Commit dbb5bc16 authored by Filipa Lacerda's avatar Filipa Lacerda

Removes extra call to fetch deploy boards

Reads 3 states from API response
Removes error state
Set all deploy boards to be opened by default
Updates tests to match new behavior
Adds a changelog entry
parent fc4d3a57
......@@ -8,6 +8,7 @@
* - Button Actions.
* [Mockup](https://gitlab.com/gitlab-org/gitlab-ce/uploads/2f655655c0eadf655d0ae7467b53002a/environments__deploy-graphic.png)
*/
import _ from 'underscore';
import deployBoardSvg from 'empty_states/icons/_deploy_board.svg';
import instanceComponent from './deploy_board_instance_component.vue';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
......@@ -26,40 +27,27 @@
type: Boolean,
required: true,
},
hasError: {
isEmpty: {
type: Boolean,
required: true,
},
},
data() {
return {
deployBoardSvg,
};
},
computed: {
canRenderDeployBoard() {
return !this.isLoading && !this.hasError && this.deployBoardData.valid;
return !this.isLoading && !this.isEmpty && !_.isEmpty(this.deployBoardData);
},
canRenderEmptyState() {
return !this.isLoading && !this.hasError && !this.deployBoardData.valid;
},
canRenderErrorState() {
return !this.isLoading && this.hasError;
return !this.isLoading && this.isEmpty;
},
instanceTitle() {
let title;
if (this.deployBoardData.instances.length === 1) {
title = 'Instance';
} else {
title = 'Instances';
}
return title;
return gl.text.pluralize('Instance', this.deployBoardData.instances);
},
projectName() {
return '<projectname>';
},
deployBoardSvg() {
return deployBoardSvg;
},
},
};
</script>
......@@ -128,11 +116,5 @@
</span>
</section>
</div>
<div
v-if="canRenderErrorState"
class="deploy-board-error-message">
We can't fetch the data right now. Please try again later.
</div>
</div>
</script>
......@@ -127,16 +127,10 @@ export default {
/**
* Toggles the visibility of the deploy boards of the clicked environment.
*
* @param {Object} model
* @return {Object}
* @param {Object} model
*/
toggleDeployBoard(model) {
this.store.toggleDeployBoard(model.id);
if (!model.isDeployboardVisible) {
this.fetchDeployBoard(model, true);
}
},
toggleFolder(folder) {
......@@ -203,11 +197,6 @@ export default {
if (openFolders.length) {
openFolders.forEach(folder => this.fetchChildEnvironments(folder));
}
const openDeployBoards = this.store.getOpenDeployBoards();
if (openDeployBoards.length) {
openDeployBoards.forEach(env => this.fetchDeployBoard(env));
}
},
errorCallback() {
......@@ -215,23 +204,6 @@ export default {
// eslint-disable-next-line no-new
new Flash('An error occurred while fetching the environments.');
},
fetchDeployBoard(environment, showLoader = false) {
this.store.updateEnvironmentProp(environment, 'isLoadingDeployBoard', showLoader);
this.service.getDeployBoard(environment.rollout_status_path)
.then(resp => resp.json())
.then((data) => {
this.store.storeDeployBoard(environment.id, data);
this.store.updateEnvironmentProp(environment, 'isLoadingDeployBoard', false);
})
.catch(() => {
this.store.updateEnvironmentProp(environment, 'isLoadingDeployBoard', false);
this.store.updateEnvironmentProp(environment, 'hasErrorDeployBoard', true);
// eslint-disable-next-line no-new
new Flash('An error occurred while fetching the deploy board.');
});
},
},
};
</script>
......
......@@ -74,7 +74,7 @@ export default {
<deploy-board
:deploy-board-data="model.deployBoardData"
:is-loading="model.isLoadingDeployBoard"
:has-error="model.hasErrorDeployBoard"
:is-empty="model.isEmptyDeployBoard"
/>
</div>
</div>
......
......@@ -30,7 +30,7 @@ export default class EnvironmentsStore {
* If the `size` is bigger than 1, it means it should be rendered as a folder.
* In those cases we add `isFolder` key in order to render it properly.
*
* Top level environments - when the size is 1 - with `rollout_status_path`
* Top level environments - when the size is 1 - with `rollout_status`
* can render a deploy board. We add `isDeployBoardVisible` and `deployBoardData`
* keys to those environments.
* The first key will let's us know if we should or not render the deploy board.
......@@ -65,13 +65,15 @@ export default class EnvironmentsStore {
filtered = Object.assign(filtered, env);
}
if (filtered.size === 1 && filtered.rollout_status_path) {
if (filtered.size === 1 && filtered.rollout_status) {
filtered = Object.assign({}, filtered, {
hasDeployBoard: true,
isDeployBoardVisible: oldEnvironmentState.isDeployBoardVisible || false,
deployBoardData: oldEnvironmentState.deployBoardData || {},
isLoadingDeployBoard: oldEnvironmentState.isLoadingDeployBoard || false,
hasErrorDeployBoard: oldEnvironmentState.hasErrorDeployBoard || false,
isDeployBoardVisible: oldEnvironmentState.isDeployBoardVisible === false ?
oldEnvironmentState.isDeployBoardVisible :
true,
deployBoardData: filtered.rollout_status.status === 'found' ? filtered.rollout_status : {},
isLoadingDeployBoard: filtered.rollout_status.status === 'loading',
isEmptyDeployBoard: filtered.rollout_status.status === 'not_found',
});
}
return filtered;
......
---
title: Improves visibility of deploy boards
merge_request:
author:
type: changed
import Vue from 'vue';
import DeployBoard from '~/environments/components/deploy_board_component.vue';
import { deployBoardMockData, invalidDeployBoardMockData } from './mock_data';
import { deployBoardMockData } from './mock_data';
describe('Deploy Board', () => {
let DeployBoardComponent;
......@@ -17,7 +17,7 @@ describe('Deploy Board', () => {
propsData: {
deployBoardData: deployBoardMockData,
isLoading: false,
hasError: false,
isEmpty: false,
},
}).$mount();
});
......@@ -46,15 +46,15 @@ describe('Deploy Board', () => {
});
});
describe('without valid data', () => {
describe('with empty state', () => {
let component;
beforeEach(() => {
component = new DeployBoardComponent({
propsData: {
deployBoardData: invalidDeployBoardMockData,
deployBoardData: {},
isLoading: false,
hasError: false,
isEmpty: true,
},
}).$mount();
});
......@@ -65,21 +65,21 @@ describe('Deploy Board', () => {
});
});
describe('with error', () => {
describe('with loading state', () => {
let component;
beforeEach(() => {
component = new DeployBoardComponent({
propsData: {
deployBoardData: {},
isLoading: false,
hasError: true,
isLoading: true,
isEmpty: false,
},
}).$mount();
});
it('should render empty state', () => {
expect(component.$el.children.length).toEqual(1);
it('should render loading spinner', () => {
expect(component.$el.querySelector('.fa-spin')).toBeDefined();
});
});
});
......@@ -37,12 +37,11 @@ describe('Environment item', () => {
size: 1,
environment_path: 'url',
id: 1,
rollout_status_path: 'url',
hasDeployBoard: true,
deployBoardData: deployBoardMockData,
isDeployBoardVisible: true,
isLoadingDeployBoard: false,
hasErrorDeployBoard: false,
isEmptyDeployBoard: false,
};
const component = new EnvironmentTable({
......@@ -66,7 +65,6 @@ describe('Environment item', () => {
size: 1,
environment_path: 'url',
id: 1,
rollout_status_path: 'url',
hasDeployBoard: true,
deployBoardData: {
instances: [
......
......@@ -29,12 +29,12 @@ describe('Store', () => {
stop_path: '/root/review-app/environments/7/stop',
created_at: '2017-01-31T10:53:46.894Z',
updated_at: '2017-01-31T10:53:46.894Z',
rollout_status_path: '/path',
rollout_status: {},
hasDeployBoard: true,
isDeployBoardVisible: false,
isDeployBoardVisible: true,
deployBoardData: {},
isLoadingDeployBoard: false,
hasErrorDeployBoard: false,
isEmptyDeployBoard: false,
};
store.storeEnvironments(serverData);
......@@ -58,20 +58,20 @@ describe('Store', () => {
expect(store.state.environments.length).toEqual(serverData.length);
});
it('should store a non folder environment with deploy board if rollout_status_path key is provided', () => {
it('should store a non folder environment with deploy board if rollout_status key is provided', () => {
const environment = {
name: 'foo',
size: 1,
latest: {
id: 1,
rollout_status_path: 'url',
rollout_status: deployBoardMockData,
},
};
store.storeEnvironments([environment]);
expect(store.state.environments[0].hasDeployBoard).toEqual(true);
expect(store.state.environments[0].isDeployBoardVisible).toEqual(false);
expect(store.state.environments[0].deployBoardData).toEqual({});
expect(store.state.environments[0].isDeployBoardVisible).toEqual(true);
expect(store.state.environments[0].deployBoardData).toEqual(deployBoardMockData);
});
it('should add folder keys when environment is a folder', () => {
......@@ -192,7 +192,7 @@ describe('Store', () => {
latest: {
id: 1,
},
rollout_status_path: 'path',
rollout_status: deployBoardMockData,
};
store.storeEnvironments([environment]);
......@@ -201,16 +201,10 @@ describe('Store', () => {
it('should toggle deploy board property for given environment id', () => {
store.toggleDeployBoard(1);
expect(store.state.environments[0].isDeployBoardVisible).toEqual(true);
});
it('should store deploy board data for given environment id', () => {
store.storeDeployBoard(1, deployBoardMockData);
expect(store.state.environments[0].deployBoardData).toEqual(deployBoardMockData);
expect(store.state.environments[0].isDeployBoardVisible).toEqual(false);
});
it('should keep deploy board data when updating environments', () => {
store.storeDeployBoard(1, deployBoardMockData);
expect(store.state.environments[0].deployBoardData).toEqual(deployBoardMockData);
const environment = {
......@@ -219,7 +213,7 @@ describe('Store', () => {
latest: {
id: 1,
},
rollout_status_path: 'path',
rollout_status: deployBoardMockData,
};
store.storeEnvironments([environment]);
expect(store.state.environments[0].deployBoardData).toEqual(deployBoardMockData);
......@@ -243,12 +237,12 @@ describe('Store', () => {
latest: {
id: 1,
},
rollout_status_path: 'path',
rollout_status: deployBoardMockData,
};
store.storeEnvironments([environment]);
expect(store.getOpenDeployBoards().length).toEqual(0);
expect(store.getOpenDeployBoards().length).toEqual(1);
});
});
});
......@@ -12,7 +12,7 @@ export const environmentsList = [
stop_path: '/root/review-app/environments/7/stop',
created_at: '2017-01-31T10:53:46.894Z',
updated_at: '2017-01-31T10:53:46.894Z',
rollout_status_path: '/path',
rollout_status: {},
},
{
folderName: 'build',
......@@ -28,7 +28,7 @@ export const environmentsList = [
stop_path: '/root/review-app/environments/12/stop',
created_at: '2017-02-01T19:42:18.400Z',
updated_at: '2017-02-01T19:42:18.400Z',
rollout_status_path: '/path',
rollout_status: {},
},
];
......@@ -48,7 +48,7 @@ export const serverData = [
stop_path: '/root/review-app/environments/7/stop',
created_at: '2017-01-31T10:53:46.894Z',
updated_at: '2017-01-31T10:53:46.894Z',
rollout_status_path: '/path',
rollout_status: {},
},
},
{
......@@ -100,7 +100,7 @@ export const environment = {
stop_path: '/root/review-app/environments/7/stop',
created_at: '2017-01-31T10:53:46.894Z',
updated_at: '2017-01-31T10:53:46.894Z',
rollout_status_path: '/path',
rollout_status: {},
};
export const deployBoardMockData = {
......@@ -136,15 +136,7 @@ export const deployBoardMockData = {
abort_url: 'url',
rollback_url: 'url',
completion: 100,
valid: true,
};
export const invalidDeployBoardMockData = {
instances: [],
abort_url: 'url',
rollback_url: 'url',
completion: 100,
valid: false,
status: 'found',
};
export const folder = {
......
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