Commit 52786f4b authored by Dhiraj Bodicherla's avatar Dhiraj Bodicherla

Updated deploy instances color scheme

The definition for deploy instances in environment
page have been updated long ago but the styling is
stale. This MR updates the style with new color scheme
parent daff9851
---
title: Update deploy instances color scheme
merge_request: 20890
author:
type: changed
...@@ -110,16 +110,17 @@ export default { ...@@ -110,16 +110,17 @@ export default {
<div v-if="canRenderDeployBoard" class="deploy-board-information"> <div v-if="canRenderDeployBoard" class="deploy-board-information">
<section class="deploy-board-status"> <section class="deploy-board-status">
<span v-tooltip :title="instanceIsCompletedText"> <span v-tooltip :title="instanceIsCompletedText">
<span class="percentage text-center text-plain">{{ deployBoardData.completion }}%</span> <span ref="percentage" class="text-center text-plain gl-font-size-large"
>{{ deployBoardData.completion }}%</span
>
<span class="text text-center text-secondary">{{ __('Complete') }}</span> <span class="text text-center text-secondary">{{ __('Complete') }}</span>
</span> </span>
</section> </section>
<section class="deploy-board-instances"> <section class="deploy-board-instances">
<p class="deploy-board-instances-text text-secondary"> <span class="deploy-board-instances-text text-secondary">
<span>{{ instanceTitle }}</span> {{ instanceTitle }} ({{ instanceCount }})
<span class="total-instances">({{ instanceCount }})</span> </span>
</p>
<div class="deploy-board-instances-container d-flex flex-wrap flex-row"> <div class="deploy-board-instances-container d-flex flex-wrap flex-row">
<template v-for="(instance, i) in deployBoardData.instances"> <template v-for="(instance, i) in deployBoardData.instances">
......
...@@ -6,11 +6,11 @@ ...@@ -6,11 +6,11 @@
* Each instance has a state and a tooltip. * Each instance has a state and a tooltip.
* The state needs to be represented in different colors, * The state needs to be represented in different colors,
* see more information about this in * see more information about this in
* https://gitlab.com/gitlab-org/gitlab/uploads/5fff049fd88336d9ee0c6ef77b1ba7e3/monitoring__deployboard--key.png * https://gitlab.com/gitlab-org/gitlab/uploads/f1f00df6293d30f241dbeaa876a1e939/Screen_Shot_2019-11-26_at_3.35.43_PM.png
* *
* An instance can represent a normal deploy or a canary deploy. In the latter we need to provide * An instance can represent a normal deploy or a canary deploy. In the latter we need to provide
* this information in the tooltip and the colors. * this information in the tooltip and the colors.
* Mockup is https://gitlab.com/gitlab-org/gitlab/merge_requests/1551#note_26595150 * Mockup is https://gitlab.com/gitlab-org/gitlab/issues/35570
*/ */
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
...@@ -24,12 +24,12 @@ export default { ...@@ -24,12 +24,12 @@ export default {
* Represents the status of the pod. Each state is represented with a different * Represents the status of the pod. Each state is represented with a different
* color. * color.
* It should be one of the following: * It should be one of the following:
* finished || deploying || failed || ready || preparing || waiting * succeeded || running || failed || pending || unknown
*/ */
status: { status: {
type: String, type: String,
required: true, required: true,
default: 'finished', default: 'succeeded',
}, },
tooltipText: { tooltipText: {
...@@ -58,13 +58,10 @@ export default { ...@@ -58,13 +58,10 @@ export default {
computed: { computed: {
cssClass() { cssClass() {
let cssClassName = `deployment-instance-${this.status}`; return {
[`deployment-instance-${this.status}`]: true,
if (!this.stable) { 'deployment-instance-canary': !this.stable,
cssClassName = `${cssClassName} deployment-instance-canary`; };
}
return cssClassName;
}, },
computedLogPath() { computedLogPath() {
......
...@@ -3,32 +3,68 @@ ...@@ -3,32 +3,68 @@
height: 15px; height: 15px;
margin: 1px; margin: 1px;
border: 1px solid; border: 1px solid;
border-radius: 3px; border-radius: $border-radius-small;
position: relative;
&-running { &-succeeded {
background-color: $green-100; background-color: $green-600;
border-color: $green-400; border-color: $green-800;
&:hover { &:hover {
background-color: $green-300; background-color: $green-800;
border-color: $green-500; border-color: $green-950;
} }
} }
&-succeeded { &-running {
background-color: $green-50; background-color: $green-300;
border-color: $green-400; border-color: $green-600;
&:hover {
background-color: $green-500;
border-color: $green-800;
}
} }
&-failed, &-failed {
&-unknown { background-color: $red-600;
background-color: $red-200; border-color: $red-800;
border-color: $red-500;
&::before {
content: '';
border: 1px solid $white-light;
background: $white-light;
transform: rotate(45deg);
position: absolute;
border-radius: 1px;
top: -2px;
bottom: -2px;
}
&:hover {
background-color: $red-800;
border-color: $red-950;
}
} }
&-pending { &-pending {
background-color: $gray-300;
border-color: $gray-700;
&:hover {
background-color: $gray-500;
border-color: $gray-900;
}
}
&-unknown {
background-color: $white-light; background-color: $white-light;
border-color: $border-color; border-color: $gray-700;
&:hover {
background-color: $white-light;
border-color: $gray-900;
}
} }
&.deployment-instance-canary { &.deployment-instance-canary {
...@@ -39,6 +75,7 @@ ...@@ -39,6 +75,7 @@
background-color: $orange-300; background-color: $orange-300;
border-radius: 50%; border-radius: 50%;
content: ''; content: '';
z-index: 1;
} }
} }
} }
...@@ -30,14 +30,6 @@ ...@@ -30,14 +30,6 @@
width: 100%; width: 100%;
} }
.deploy-board-instances-text {
font-size: 12px;
}
.deploy-board-instances-container {
margin-top: -8px;
}
.deploy-board-actions { .deploy-board-actions {
order: 3; order: 3;
align-self: center; align-self: center;
......
import Vue from 'vue'; import Vue from 'vue';
import { mount } from '@vue/test-utils';
import DeployBoard from 'ee/environments/components/deploy_board_component.vue'; import DeployBoard from 'ee/environments/components/deploy_board_component.vue';
import { environment } from 'spec/environments/mock_data'; import { environment } from 'spec/environments/mock_data';
import { deployBoardMockData } from './mock_data'; import { deployBoardMockData } from './mock_data';
describe('Deploy Board', () => { describe('Deploy Board', () => {
let DeployBoardComponent; let wrapper;
beforeEach(() => { const createComponent = (props = {}) =>
DeployBoardComponent = Vue.extend(DeployBoard); mount(Vue.extend(DeployBoard), {
}); propsData: {
deployBoardData: deployBoardMockData,
isLoading: false,
isEmpty: false,
logsPath: environment.log_path,
...props,
},
sync: false,
});
describe('with valid data', () => { describe('with valid data', () => {
let component; beforeEach(done => {
wrapper = createComponent();
beforeEach(() => { wrapper.vm.$nextTick(done);
component = new DeployBoardComponent({
propsData: {
deployBoardData: deployBoardMockData,
isLoading: false,
isEmpty: false,
logsPath: environment.log_path,
},
}).$mount();
}); });
it('should render percentage with completion value provided', () => { it('should render percentage with completion value provided', () => {
expect( expect(wrapper.vm.$refs.percentage.innerText).toEqual(`${deployBoardMockData.completion}%`);
component.$el.querySelector('.deploy-board-information .percentage').textContent,
).toEqual(`${deployBoardMockData.completion}%`);
}); });
it('should render total instance count', () => { it('should render total instance count', () => {
const renderedTotal = component.$el.querySelector('.deploy-board-instances .total-instances'); const renderedTotal = wrapper.find('.deploy-board-instances-text');
const actualTotal = deployBoardMockData.instances.length; const actualTotal = deployBoardMockData.instances.length;
const output = `${actualTotal > 1 ? 'Instances' : 'Instance'} (${actualTotal})`;
expect(renderedTotal.textContent).toEqual(`(${actualTotal})`); expect(renderedTotal.text()).toEqual(output);
}); });
it('should render all instances', () => { it('should render all instances', () => {
const instances = component.$el.querySelectorAll('.deploy-board-instances-container a'); const instances = wrapper.findAll('.deploy-board-instances-container a');
expect(instances.length).toEqual(deployBoardMockData.instances.length); expect(instances.length).toEqual(deployBoardMockData.instances.length);
expect( expect(
instances[2].classList.contains( instances.at(1).classes(`deployment-instance-${deployBoardMockData.instances[2].status}`),
`deployment-instance-${deployBoardMockData.instances[2].status}`,
),
).toBe(true); ).toBe(true);
}); });
it('should render an abort and a rollback button with the provided url', () => { it('should render an abort and a rollback button with the provided url', () => {
const buttons = component.$el.querySelectorAll('.deploy-board-actions a'); const buttons = wrapper.findAll('.deploy-board-actions a');
expect(buttons[0].getAttribute('href')).toEqual(deployBoardMockData.rollback_url); expect(buttons.at(0).attributes('href')).toEqual(deployBoardMockData.rollback_url);
expect(buttons[1].getAttribute('href')).toEqual(deployBoardMockData.abort_url); expect(buttons.at(1).attributes('href')).toEqual(deployBoardMockData.abort_url);
}); });
}); });
describe('with empty state', () => { describe('with empty state', () => {
let component; beforeEach(done => {
wrapper = createComponent({
beforeEach(() => { deployBoardData: {},
component = new DeployBoardComponent({ isLoading: false,
propsData: { isEmpty: true,
deployBoardData: {}, logsPath: environment.log_path,
isLoading: false, });
isEmpty: true, wrapper.vm.$nextTick(done);
logsPath: environment.log_path,
},
}).$mount();
}); });
it('should render the empty state', () => { it('should render the empty state', () => {
expect(component.$el.querySelector('.deploy-board-empty-state-svg svg')).toBeDefined(); expect(wrapper.find('.deploy-board-empty-state-svg svg')).toBeDefined();
expect( expect(
component.$el.querySelector( wrapper.find('.deploy-board-empty-state-text .deploy-board-empty-state-title').text(),
'.deploy-board-empty-state-text .deploy-board-empty-state-title',
).textContent,
).toContain('Kubernetes deployment not found'); ).toContain('Kubernetes deployment not found');
}); });
}); });
describe('with loading state', () => { describe('with loading state', () => {
let component; beforeEach(done => {
wrapper = createComponent({
beforeEach(() => { deployBoardData: {},
component = new DeployBoardComponent({ isLoading: true,
propsData: { isEmpty: false,
deployBoardData: {}, logsPath: environment.log_path,
isLoading: true, });
isEmpty: false, wrapper.vm.$nextTick(done);
logsPath: environment.log_path,
},
}).$mount();
}); });
it('should render loading spinner', () => { it('should render loading spinner', () => {
expect(component.$el.querySelector('.fa-spin')).toBeDefined(); expect(wrapper.find('.fa-spin')).toBeDefined();
}); });
}); });
describe('with hasLegacyAppLabel equal true', () => { describe('with hasLegacyAppLabel equal true', () => {
let component; beforeEach(done => {
wrapper = createComponent({
beforeEach(() => { isLoading: false,
component = new DeployBoardComponent({ isEmpty: false,
propsData: { logsPath: environment.log_path,
isLoading: false, hasLegacyAppLabel: true,
isEmpty: false, deployBoardData: {},
logsPath: environment.log_path, });
hasLegacyAppLabel: true, wrapper.vm.$nextTick(done);
deployBoardData: {},
},
}).$mount();
}); });
it('should render legacy label warning message', () => { it('should render legacy label warning message', () => {
const warningMessage = component.$el.querySelector('.bs-callout-warning'); const warningMessage = wrapper.find('.bs-callout-warning');
expect(warningMessage).toBeTruthy(); expect(warningMessage).toBeTruthy();
expect(warningMessage.innerText).toContain( expect(warningMessage.text()).toContain(
'Matching on the app label has been removed for deploy boards.', 'Matching on the app label has been removed for deploy boards.',
); );
}); });
......
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