Commit 1285d629 authored by Filipa Lacerda's avatar Filipa Lacerda

Move change page param to utility function

Add tests

Adds folder name in the top of the table
parent 73accafe
...@@ -50,15 +50,15 @@ module.exports = Vue.component('environment-component', { ...@@ -50,15 +50,15 @@ module.exports = Vue.component('environment-component', {
}, },
canReadEnvironmentParsed() { canReadEnvironmentParsed() {
return this.$options.convertPermissionToBoolean(this.canReadEnvironment); return gl.utils.convertPermissionToBoolean(this.canReadEnvironment);
}, },
canCreateDeploymentParsed() { canCreateDeploymentParsed() {
return this.$options.convertPermissionToBoolean(this.canCreateDeployment); return gl.utils.convertPermissionToBoolean(this.canCreateDeployment);
}, },
canCreateEnvironmentParsed() { canCreateEnvironmentParsed() {
return this.$options.convertPermissionToBoolean(this.canCreateEnvironment); return gl.utils.convertPermissionToBoolean(this.canCreateEnvironment);
}, },
}, },
...@@ -97,15 +97,6 @@ module.exports = Vue.component('environment-component', { ...@@ -97,15 +97,6 @@ module.exports = Vue.component('environment-component', {
}); });
}, },
/**
* Converts permission provided as strings to booleans.
* @param {String} string
* @returns {Boolean}
*/
convertPermissionToBoolean(string) {
return string === 'true';
},
methods: { methods: {
toggleRow(model) { toggleRow(model) {
return this.store.toggleFolder(model.name); return this.store.toggleFolder(model.name);
...@@ -114,26 +105,11 @@ module.exports = Vue.component('environment-component', { ...@@ -114,26 +105,11 @@ module.exports = Vue.component('environment-component', {
/** /**
* Will change the page number and update the URL. * Will change the page number and update the URL.
* *
* If no search params are present, we'll add param for page
* If param for page is already present, we'll update it
* If there are params but none for page, we'll add it at the end.
*
* @param {Number} pageNumber desired page to go to. * @param {Number} pageNumber desired page to go to.
* @return {String}
*/ */
changePage(pageNumber) { changePage(pageNumber) {
let param; const param = gl.utils.setParamInURL('page', pageNumber);
if (window.location.search.length === 0) {
param = `?page=${pageNumber}`;
}
if (window.location.search.indexOf('page') !== -1) {
param = window.location.search.replace(/page=\d/g, `page=${pageNumber}`);
}
if (window.location.search.length &&
window.location.search.indexOf('page') === -1) {
param = `${window.location.search}&page=${pageNumber}`;
}
gl.utils.visitUrl(param); gl.utils.visitUrl(param);
return param; return param;
......
...@@ -99,7 +99,7 @@ module.exports = Vue.component('environment-item', { ...@@ -99,7 +99,7 @@ module.exports = Vue.component('environment-item', {
* @returns {Boolean} * @returns {Boolean}
*/ */
hasStopAction() { hasStopAction() {
return this.model.latest['stop_action?']; return this.model.latest && this.model.latest['stop_action?'];
}, },
/** /**
...@@ -414,7 +414,7 @@ module.exports = Vue.component('environment-item', { ...@@ -414,7 +414,7 @@ module.exports = Vue.component('environment-item', {
* @return {String} * @return {String}
*/ */
folderUrl() { folderUrl() {
return `${window.location.pathname}/folders/${this.model.latest.id}`; return `${window.location.pathname}/folders/${this.model.name}`;
}, },
}, },
......
const EnvironmentsFolderComponent = require('./environments_folder_view'); const EnvironmentsFolderComponent = require('./environments_folder_view');
require('../../vue_shared/vue_resource_interceptor');
$(() => { $(() => {
window.gl = window.gl || {}; window.gl = window.gl || {};
......
...@@ -6,6 +6,7 @@ Vue.use(require('vue-resource')); ...@@ -6,6 +6,7 @@ Vue.use(require('vue-resource'));
const EnvironmentsService = require('../services/environments_service'); const EnvironmentsService = require('../services/environments_service');
const EnvironmentTable = require('../components/environments_table'); const EnvironmentTable = require('../components/environments_table');
const Store = require('../stores/environments_store'); const Store = require('../stores/environments_store');
require('../../vue_shared/components/table_pagination');
require('../../lib/utils/common_utils'); require('../../lib/utils/common_utils');
module.exports = Vue.component('environment-folder-view', { module.exports = Vue.component('environment-folder-view', {
...@@ -19,9 +20,11 @@ module.exports = Vue.component('environment-folder-view', { ...@@ -19,9 +20,11 @@ module.exports = Vue.component('environment-folder-view', {
const environmentsData = document.querySelector('#environments-folder-list-view').dataset; const environmentsData = document.querySelector('#environments-folder-list-view').dataset;
const store = new Store(); const store = new Store();
const endpoint = `${window.location.pathname}.json`; const endpoint = `${window.location.pathname}.json`;
const folderName = window.location.pathname.substr(window.location.pathname.lastIndexOf('/') + 1);
return { return {
store, store,
folderName,
endpoint, endpoint,
state: store.state, state: store.state,
visibility: 'available', visibility: 'available',
...@@ -47,21 +50,30 @@ module.exports = Vue.component('environment-folder-view', { ...@@ -47,21 +50,30 @@ module.exports = Vue.component('environment-folder-view', {
}, },
canReadEnvironmentParsed() { canReadEnvironmentParsed() {
return this.$options.convertPermissionToBoolean(this.canReadEnvironment); return gl.utils.convertPermissionToBoolean(this.canReadEnvironment);
}, },
canCreateDeploymentParsed() { canCreateDeploymentParsed() {
return this.$options.convertPermissionToBoolean(this.canCreateDeployment); return gl.utils.convertPermissionToBoolean(this.canCreateDeployment);
}, },
/**
* URL to link in the stopped tab.
*
* @return {String}
*/
stoppedPath() { stoppedPath() {
return `${window.location.pathname}?scope=stopped`; return `${window.location.pathname}?scope=stopped`;
}, },
/**
* URL to link in the available tab.
*
* @return {String}
*/
availablePath() { availablePath() {
return window.location.pathname; return window.location.pathname;
}, },
}, },
/** /**
...@@ -84,6 +96,8 @@ module.exports = Vue.component('environment-folder-view', { ...@@ -84,6 +96,8 @@ module.exports = Vue.component('environment-folder-view', {
body: resp.json(), body: resp.json(),
})) }))
.then((response) => { .then((response) => {
this.store.storeAvailableCount(response.body.available_count);
this.store.storeStoppedCount(response.body.stopped_count);
this.store.storeEnvironments(response.body.environments); this.store.storeEnvironments(response.body.environments);
this.store.storePagination(response.headers); this.store.storePagination(response.headers);
}) })
...@@ -96,45 +110,14 @@ module.exports = Vue.component('environment-folder-view', { ...@@ -96,45 +110,14 @@ module.exports = Vue.component('environment-folder-view', {
}); });
}, },
/**
* Transforms the url parameter into an object and
* returns the one requested.
*
* @param {String} param
* @returns {String} The value of the requested parameter.
*/
getQueryParameter(parameter) {
return window.location.search.substring(1).split('&').reduce((acc, param) => {
const paramSplited = param.split('=');
acc[paramSplited[0]] = paramSplited[1];
return acc;
}, {})[parameter];
},
methods: { methods: {
/** /**
* Will change the page number and update the URL. * Will change the page number and update the URL.
* *
* If no search params are present, we'll add param for page
* If param for page is already present, we'll update it
* If there are params but none for page, we'll add it at the end.
*
* @param {Number} pageNumber desired page to go to. * @param {Number} pageNumber desired page to go to.
*/ */
changePage(pageNumber) { changePage(pageNumber) {
let param; const param = gl.utils.setParamInURL('page', pageNumber);
if (window.location.search.length === 0) {
param = `?page=${pageNumber}`;
}
if (window.location.search.indexOf('page') !== -1) {
param = window.location.search.replace(/page=\d/g, `page=${pageNumber}`);
}
if (window.location.search.length &&
window.location.search.indexOf('page') === -1) {
param = `${window.location.search}&page=${pageNumber}`;
}
gl.utils.visitUrl(param); gl.utils.visitUrl(param);
return param; return param;
...@@ -143,13 +126,15 @@ module.exports = Vue.component('environment-folder-view', { ...@@ -143,13 +126,15 @@ module.exports = Vue.component('environment-folder-view', {
template: ` template: `
<div :class="cssContainerClass"> <div :class="cssContainerClass">
<div class="top-area"> <div class="top-area" v-if="!isLoading">
<h3>FOLDER NAME</h3> <h4 class="js-folder-name environments-folder-name">
Environments / <b>{{folderName}}</b>
</h4>
<ul v-if="!isLoading" class="nav-links"> <ul class="nav-links">
<li v-bind:class="{ 'active': scope === undefined || scope === 'available' }"> <li v-bind:class="{ 'active': scope === null || scope === 'available' }">
<a :href="availablePath"> <a :href="availablePath" class="js-available-environments-folder-tab">
Available Available
<span class="badge js-available-environments-count"> <span class="badge js-available-environments-count">
{{state.availableCounter}} {{state.availableCounter}}
...@@ -157,7 +142,7 @@ module.exports = Vue.component('environment-folder-view', { ...@@ -157,7 +142,7 @@ module.exports = Vue.component('environment-folder-view', {
</a> </a>
</li> </li>
<li v-bind:class="{ 'active' : scope === 'stopped' }"> <li v-bind:class="{ 'active' : scope === 'stopped' }">
<a :href="stoppedPath"> <a :href="stoppedPath" class="js-stopped-environments-folder-tab">
Stopped Stopped
<span class="badge js-stopped-environments-count"> <span class="badge js-stopped-environments-count">
{{state.stoppedCounter}} {{state.stoppedCounter}}
......
...@@ -241,5 +241,45 @@ ...@@ -241,5 +241,45 @@
acc[element] = DOMStringMapObject[element]; acc[element] = DOMStringMapObject[element];
return acc; return acc;
}, {}); }, {});
/**
* Updates the search parameter of a URL given the parameter and values provided.
*
* If no search params are present we'll add it.
* If param for page is already present, we'll update it
* If there are params but not for the given one, we'll add it at the end.
* Returns the new search parameters.
*
* @param {String} param
* @param {Number|String|Undefined|Null} value
* @return {String}
*/
w.gl.utils.setParamInURL = (param, value) => {
let search;
if (window.location.search.length === 0) {
search = `?${param}=${value}`;
}
if (window.location.search.indexOf(param) !== -1) {
const regex = new RegExp(param + '=\\d');
search = window.location.search.replace(regex, `${param}=${value}`);
}
if (window.location.search.length &&
window.location.search.indexOf(param) === -1) {
search = `${window.location.search}&${param}=${value}`;
}
return search;
};
/**
* Converts permission provided as strings to booleans.
*
* @param {String} string
* @returns {Boolean}
*/
w.gl.utils.convertPermissionToBoolean = permission => permission === 'true';
})(window); })(window);
}).call(this); }).call(this);
...@@ -10,6 +10,11 @@ ...@@ -10,6 +10,11 @@
font-size: 34px; font-size: 34px;
} }
.environments-folder-name {
font-weight: normal;
padding-top: 20px;
}
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
.environments-container { .environments-container {
width: 100%; width: 100%;
......
const EnvironmentTable = require('~/environments/components/environments_table');
describe('Environment item', () => {
preloadFixtures('static/environments/element.html.raw');
beforeEach(() => {
loadFixtures('static/environments/element.html.raw');
});
it('Should render a table', () => {
const mockItem = {
name: 'review',
size: 3,
isFolder: true,
latest: {
environment_path: 'url',
},
};
const component = new EnvironmentTable({
el: document.querySelector('.test-dom-element'),
propsData: {
environments: [{ mockItem }],
canCreateDeployment: false,
canReadEnvironment: true,
},
});
expect(component.$el.tagName).toEqual('TABLE');
});
});
const Vue = require('vue');
require('~/flash');
const EnvironmentsFolderViewComponent = require('~/environments/folder/environments_folder_view');
const { environmentsList } = require('../mock_data');
describe('Environments Folder View', () => {
preloadFixtures('static/environments/environments_folder_view.html.raw');
beforeEach(() => {
loadFixtures('static/environments/environments_folder_view.html.raw');
window.history.pushState({}, null, 'environments/folders/51');
});
let component;
describe('successfull request', () => {
const environmentsResponseInterceptor = (request, next) => {
next(request.respondWith(JSON.stringify({
environments: environmentsList,
stopped_count: 1,
available_count: 0,
}), {
status: 200,
headers: {
'X-nExt-pAge': '2',
'x-page': '1',
'X-Per-Page': '1',
'X-Prev-Page': '',
'X-TOTAL': '37',
'X-Total-Pages': '2',
},
}));
};
beforeEach(() => {
Vue.http.interceptors.push(environmentsResponseInterceptor);
component = new EnvironmentsFolderViewComponent({
el: document.querySelector('#environments-folder-list-view'),
});
});
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, environmentsResponseInterceptor,
);
});
it('should render a table with environments', (done) => {
setTimeout(() => {
expect(
component.$el.querySelectorAll('table tbody tr').length,
).toEqual(2);
done();
}, 0);
});
it('should render available tab with count', (done) => {
setTimeout(() => {
expect(
component.$el.querySelector('.js-available-environments-folder-tab').textContent,
).toContain('Available');
expect(
component.$el.querySelector('.js-available-environments-folder-tab .js-available-environments-count').textContent,
).toContain('0');
done();
}, 0);
});
it('should render stopped tab with count', (done) => {
setTimeout(() => {
expect(
component.$el.querySelector('.js-stopped-environments-folder-tab').textContent,
).toContain('Stopped');
expect(
component.$el.querySelector('.js-stopped-environments-folder-tab .js-stopped-environments-count').textContent,
).toContain('1');
done();
}, 0);
});
// FIX ME:
it('should render parent folder name', (done) => {
setTimeout(() => {
expect(
component.$el.querySelector('.js-folder-name'),
).toBe(null);
done();
}, 0);
});
describe('pagination', () => {
it('should render pagination', (done) => {
setTimeout(() => {
expect(
component.$el.querySelectorAll('.gl-pagination li').length,
).toEqual(5);
done();
}, 0);
});
it('should update url when no search params are present', (done) => {
spyOn(gl.utils, 'visitUrl');
setTimeout(() => {
component.$el.querySelector('.gl-pagination li:nth-child(5) a').click();
expect(gl.utils.visitUrl).toHaveBeenCalledWith('?page=2');
done();
}, 0);
});
it('should update url when page is already present', (done) => {
spyOn(gl.utils, 'visitUrl');
window.history.pushState({}, null, '?page=1');
setTimeout(() => {
component.$el.querySelector('.gl-pagination li:nth-child(5) a').click();
expect(gl.utils.visitUrl).toHaveBeenCalledWith('?page=2');
done();
}, 0);
});
it('should update url when page and scope are already present', (done) => {
spyOn(gl.utils, 'visitUrl');
window.history.pushState({}, null, '?scope=all&page=1');
setTimeout(() => {
component.$el.querySelector('.gl-pagination li:nth-child(5) a').click();
expect(gl.utils.visitUrl).toHaveBeenCalledWith('?scope=all&page=2');
done();
}, 0);
});
it('should update url when page and scope are already present and page is first param', (done) => {
spyOn(gl.utils, 'visitUrl');
window.history.pushState({}, null, '?page=1&scope=all');
setTimeout(() => {
component.$el.querySelector('.gl-pagination li:nth-child(5) a').click();
expect(gl.utils.visitUrl).toHaveBeenCalledWith('?page=2&scope=all');
done();
}, 0);
});
});
});
describe('unsuccessfull request', () => {
const environmentsErrorResponseInterceptor = (request, next) => {
next(request.respondWith(JSON.stringify([]), {
status: 500,
}));
};
beforeEach(() => {
Vue.http.interceptors.push(environmentsErrorResponseInterceptor);
});
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, environmentsErrorResponseInterceptor,
);
});
it('should not render a table', (done) => {
component = new EnvironmentsFolderViewComponent({
el: document.querySelector('#environments-folder-list-view'),
});
setTimeout(() => {
expect(
component.$el.querySelector('table'),
).toBe(null);
done();
}, 0);
});
it('should render available tab with count 0', (done) => {
setTimeout(() => {
expect(
component.$el.querySelector('.js-available-environments-folder-tab').textContent,
).toContain('Available');
expect(
component.$el.querySelector('.js-available-environments-folder-tab .js-available-environments-count').textContent,
).toContain('0');
done();
}, 0);
});
it('should render stopped tab with count 0', (done) => {
setTimeout(() => {
expect(
component.$el.querySelector('.js-stopped-environments-folder-tab').textContent,
).toContain('Stopped');
expect(
component.$el.querySelector('.js-stopped-environments-folder-tab .js-stopped-environments-count').textContent,
).toContain('0');
done();
}, 0);
});
it('should not render parent folder name', (done) => {
setTimeout(() => {
expect(
component.$el.querySelector('.js-folder-name'),
).toBe(null);
done();
}, 0);
});
});
});
%div
#environments-folder-list-view{ data: { "can-create-deployment" => "true",
"can-read-environment" => "true",
"css-class" => "",
"commit-icon-svg" => custom_icon("icon_commit"),
"terminal-icon-svg" => custom_icon("icon_terminal"),
"play-icon-svg" => custom_icon("icon_play") } }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment