Commit b7ac0f54 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '213214-update-geo-status-design' into 'master'

Update Geo Node Status Design

Closes #213214

See merge request gitlab-org/gitlab!29067
parents 2fdb6b9c fa237c9a
......@@ -26,9 +26,12 @@ export default {
<template>
<div class="mt-2 detail-section-item">
<div class="text-secondary-700 node-detail-title">{{ s__('GeoNodes|Health status') }}</div>
<div :class="healthCssClass" class="mt-1 d-flex align-items-center node-health-status">
<div
:class="healthCssClass"
class="rounded-pill d-inline-flex align-items-center px-2 py-1 mt-1"
>
<icon :size="16" :name="statusIconName" />
<span class="status-text ml-2"> {{ status }} </span>
<span class="status-text ml-1 bold"> {{ status }} </span>
</div>
</div>
</template>
......@@ -19,16 +19,16 @@ export const HEALTH_STATUS_ICON = {
healthy: 'status_success',
unhealthy: 'status_failed',
disabled: 'status_canceled',
unknown: 'status_warning',
unknown: 'status_notfound',
offline: 'status_canceled',
};
export const HEALTH_STATUS_CLASS = {
healthy: 'text-success-500',
unhealthy: 'text-danger-500',
disabled: 'text-secondary-950',
unknown: 'cdark',
offline: 'cdark',
healthy: 'text-success-600 bg-success-100',
unhealthy: 'text-danger-600 bg-danger-100',
disabled: 'text-secondary-800 bg-secondary-100',
unknown: 'text-secondary-800 bg-secondary-100',
offline: 'text-secondary-800 bg-secondary-100',
};
export const TIME_DIFF = {
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`GeoNodeHealthStatusComponent computed properties renders Icon correctly 1`] = `"<icon-stub name=\\"status_success\\" size=\\"16\\"></icon-stub>"`;
exports[`GeoNodeHealthStatusComponent computed properties renders Icon correctly 2`] = `"<icon-stub name=\\"status_failed\\" size=\\"16\\"></icon-stub>"`;
exports[`GeoNodeHealthStatusComponent computed properties renders Icon correctly 3`] = `"<icon-stub name=\\"status_canceled\\" size=\\"16\\"></icon-stub>"`;
exports[`GeoNodeHealthStatusComponent computed properties renders Icon correctly 4`] = `"<icon-stub name=\\"status_notfound\\" size=\\"16\\"></icon-stub>"`;
exports[`GeoNodeHealthStatusComponent computed properties renders Icon correctly 5`] = `"<icon-stub name=\\"status_canceled\\" size=\\"16\\"></icon-stub>"`;
exports[`GeoNodeHealthStatusComponent computed properties renders StatusPill correctly 1`] = `
"<div class=\\"rounded-pill d-inline-flex align-items-center px-2 py-1 mt-1 text-success-600 bg-success-100\\">
<icon-stub name=\\"status_success\\" size=\\"16\\"></icon-stub> <span class=\\"status-text ml-1 bold\\"> Healthy </span>
</div>"
`;
exports[`GeoNodeHealthStatusComponent computed properties renders StatusPill correctly 2`] = `
"<div class=\\"rounded-pill d-inline-flex align-items-center px-2 py-1 mt-1 text-danger-600 bg-danger-100\\">
<icon-stub name=\\"status_failed\\" size=\\"16\\"></icon-stub> <span class=\\"status-text ml-1 bold\\"> Unhealthy </span>
</div>"
`;
exports[`GeoNodeHealthStatusComponent computed properties renders StatusPill correctly 3`] = `
"<div class=\\"rounded-pill d-inline-flex align-items-center px-2 py-1 mt-1 text-secondary-800 bg-secondary-100\\">
<icon-stub name=\\"status_canceled\\" size=\\"16\\"></icon-stub> <span class=\\"status-text ml-1 bold\\"> Disabled </span>
</div>"
`;
exports[`GeoNodeHealthStatusComponent computed properties renders StatusPill correctly 4`] = `
"<div class=\\"rounded-pill d-inline-flex align-items-center px-2 py-1 mt-1 text-secondary-800 bg-secondary-100\\">
<icon-stub name=\\"status_notfound\\" size=\\"16\\"></icon-stub> <span class=\\"status-text ml-1 bold\\"> Unknown </span>
</div>"
`;
exports[`GeoNodeHealthStatusComponent computed properties renders StatusPill correctly 5`] = `
"<div class=\\"rounded-pill d-inline-flex align-items-center px-2 py-1 mt-1 text-secondary-800 bg-secondary-100\\">
<icon-stub name=\\"status_canceled\\" size=\\"16\\"></icon-stub> <span class=\\"status-text ml-1 bold\\"> Offline </span>
</div>"
`;
import Vue from 'vue';
import { shallowMount } from '@vue/test-utils';
import Icon from '~/vue_shared/components/icon.vue';
import geoNodeHealthStatusComponent from 'ee/geo_nodes/components/geo_node_health_status.vue';
import { HEALTH_STATUS_ICON, HEALTH_STATUS_CLASS } from 'ee/geo_nodes/constants';
import mountComponent from 'helpers/vue_mount_component_helper';
import { mockNodeDetails } from '../mock_data';
const createComponent = (status = mockNodeDetails.health) => {
const Component = Vue.extend(geoNodeHealthStatusComponent);
return mountComponent(Component, {
status,
});
};
describe('GeoNodeHealthStatusComponent', () => {
describe('computed', () => {
describe('healthCssClass', () => {
it('returns CSS class representing `status` prop value', () => {
const vm = createComponent('healthy');
expect(vm.healthCssClass).toBe(HEALTH_STATUS_CLASS.healthy);
vm.$destroy();
});
});
describe('statusIconName', () => {
it('returns icon name representing `status` prop value', () => {
let vm = createComponent('healthy');
expect(vm.statusIconName).toBe(HEALTH_STATUS_ICON.healthy);
vm.$destroy();
vm = createComponent('unhealthy');
let wrapper;
expect(vm.statusIconName).toBe(HEALTH_STATUS_ICON.unhealthy);
vm.$destroy();
const defaultProps = {
status: mockNodeDetails.health,
};
vm = createComponent('disabled');
expect(vm.statusIconName).toBe(HEALTH_STATUS_ICON.disabled);
vm.$destroy();
vm = createComponent('unknown');
const createComponent = (props = {}) => {
wrapper = shallowMount(geoNodeHealthStatusComponent, {
propsData: {
...defaultProps,
...props,
},
});
};
expect(vm.statusIconName).toBe(HEALTH_STATUS_ICON.unknown);
vm.$destroy();
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
vm = createComponent('offline');
const findStatusPill = () => wrapper.find('.rounded-pill');
const findStatusIcon = () => findStatusPill().find(Icon);
expect(vm.statusIconName).toBe(HEALTH_STATUS_ICON.offline);
vm.$destroy();
});
describe.each`
status | healthCssClass | statusIconName
${'Healthy'} | ${HEALTH_STATUS_CLASS.healthy} | ${HEALTH_STATUS_ICON.healthy}
${'Unhealthy'} | ${HEALTH_STATUS_CLASS.unhealthy} | ${HEALTH_STATUS_ICON.unhealthy}
${'Disabled'} | ${HEALTH_STATUS_CLASS.disabled} | ${HEALTH_STATUS_ICON.disabled}
${'Unknown'} | ${HEALTH_STATUS_CLASS.unknown} | ${HEALTH_STATUS_ICON.unknown}
${'Offline'} | ${HEALTH_STATUS_CLASS.offline} | ${HEALTH_STATUS_ICON.offline}
`(`computed properties`, ({ status, healthCssClass, statusIconName }) => {
beforeEach(() => {
createComponent({ status });
});
});
describe('template', () => {
it('renders container elements correctly', () => {
const vm = createComponent('Healthy');
expect(vm.$el.classList.contains('detail-section-item')).toBe(true);
expect(vm.$el.querySelector('.node-detail-title').innerText.trim()).toBe('Health status');
it(`sets background of StatusPill to ${healthCssClass} when status is ${status}`, () => {
expect(
findStatusPill()
.classes()
.join(' '),
).toContain(healthCssClass);
});
const iconContainerEl = vm.$el.querySelector('.node-health-status');
it('renders StatusPill correctly', () => {
expect(findStatusPill().html()).toMatchSnapshot();
});
expect(iconContainerEl).not.toBeNull();
expect(iconContainerEl.querySelector('svg use').getAttribute('xlink:href')).toContain(
'#status_success',
);
it(`sets StatusIcon to ${statusIconName} when status is ${status}`, () => {
expect(findStatusIcon().attributes('name')).toBe(statusIconName);
});
expect(iconContainerEl.querySelector('.status-text').innerText.trim()).toBe('Healthy');
vm.$destroy();
it('renders Icon correctly', () => {
expect(findStatusIcon().html()).toMatchSnapshot();
});
});
});
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