Commit 88e5f4e9 authored by Tim Zallmann's avatar Tim Zallmann

Merge branch '5146-help-text-for-verification-info' into 'master'

Update item titles and add help text in Geo nodes admin dashboard

Closes #5146

See merge request gitlab-org/gitlab-ee!5306
parents 7032fc65 6d65793c
<script>
import { s__ } from '~/locale';
import stackedProgressBar from '~/vue_shared/components/stacked_progress_bar.vue';
import popover from '~/vue_shared/directives/popover';
import Icon from '~/vue_shared/components/icon.vue';
import StackedProgressBar from '~/vue_shared/components/stacked_progress_bar.vue';
import { VALUE_TYPE, CUSTOM_TYPE } from '../constants';
import geoNodeSyncSettings from './geo_node_sync_settings.vue';
import geoNodeEventStatus from './geo_node_event_status.vue';
import GeoNodeSyncSettings from './geo_node_sync_settings.vue';
import GeoNodeEventStatus from './geo_node_event_status.vue';
export default {
components: {
stackedProgressBar,
geoNodeSyncSettings,
geoNodeEventStatus,
Icon,
StackedProgressBar,
GeoNodeSyncSettings,
GeoNodeEventStatus,
},
directives: {
popover,
},
props: {
itemTitle: {
......@@ -56,8 +62,16 @@
required: false,
default: false,
},
helpInfo: {
type: [Boolean, Object],
required: false,
default: false,
},
},
computed: {
hasHelpInfo() {
return typeof this.helpInfo === 'object';
},
isValueTypePlain() {
return this.itemValueType === VALUE_TYPE.PLAIN;
},
......@@ -70,6 +84,26 @@
isCustomTypeSync() {
return this.customType === CUSTOM_TYPE.SYNC;
},
popoverConfig() {
return {
html: true,
trigger: 'click',
placement: 'top',
template: `
<div class="popover geo-node-detail-popover" role="tooltip">
<div class="arrow"></div>
<p class="popover-title"></p>
<div class="popover-content"></div>
</div>
`,
title: this.helpInfo.title,
content: `
<a href="${this.helpInfo.url}">
${this.helpInfo.urlText}
</a>
`,
};
},
},
};
</script>
......@@ -77,7 +111,16 @@
<template>
<div class="node-detail-item prepend-top-15 prepend-left-10">
<div class="node-detail-title">
<span>
{{ itemTitle }}
</span>
<icon
v-popover="popoverConfig"
v-if="hasHelpInfo"
css-classes="node-detail-help-text prepend-left-5"
name="question"
:size="12"
/>
</div>
<div
v-if="isValueTypePlain"
......
......@@ -26,7 +26,7 @@
<template>
<div class="prepend-top-15 detail-section-item">
<div class="node-detail-title">
{{ s__('GeoNodes|Health status:') }}
{{ s__('GeoNodes|Health status') }}
</div>
<div
class="node-detail-value node-health-status"
......
......@@ -51,7 +51,7 @@
<div class="col-md-8">
<div class="detail-section-item node-version">
<div class="node-detail-title">
{{ s__('GeoNodes|GitLab version:') }}
{{ s__('GeoNodes|GitLab version') }}
</div>
<div
class="node-detail-value node-detail-value-bold"
......
......@@ -56,7 +56,7 @@
class="col-md-6 prepend-left-15 prepend-top-10 section-items-container"
>
<geo-node-detail-item
:item-title="s__('GeoNodes|Storage config:')"
:item-title="s__('GeoNodes|Storage config')"
:item-value="storageShardsStatus"
:item-value-type="$options.valueType.PLAIN"
:css-class="storageShardsCssClass"
......
......@@ -23,49 +23,49 @@
showSectionItems: false,
nodeDetailItems: [
{
itemTitle: s__('GeoNodes|Sync settings:'),
itemTitle: s__('GeoNodes|Sync settings'),
itemValue: this.syncSettings(),
itemValueType: VALUE_TYPE.CUSTOM,
customType: CUSTOM_TYPE.SYNC,
},
{
itemTitle: s__('GeoNodes|Repositories:'),
itemTitle: s__('GeoNodes|Repositories'),
itemValue: this.nodeDetails.repositories,
itemValueType: VALUE_TYPE.GRAPH,
},
{
itemTitle: s__('GeoNodes|Wikis:'),
itemTitle: s__('GeoNodes|Wikis'),
itemValue: this.nodeDetails.wikis,
itemValueType: VALUE_TYPE.GRAPH,
},
{
itemTitle: s__('GeoNodes|Local LFS objects:'),
itemTitle: s__('GeoNodes|Local LFS objects'),
itemValue: this.nodeDetails.lfs,
itemValueType: VALUE_TYPE.GRAPH,
},
{
itemTitle: s__('GeoNodes|Local attachments:'),
itemTitle: s__('GeoNodes|Local attachments'),
itemValue: this.nodeDetails.attachments,
itemValueType: VALUE_TYPE.GRAPH,
},
{
itemTitle: s__('GeoNodes|Local job artifacts:'),
itemTitle: s__('GeoNodes|Local job artifacts'),
itemValue: this.nodeDetails.jobArtifacts,
itemValueType: VALUE_TYPE.GRAPH,
},
{
itemTitle: s__('GeoNodes|Data replication lag:'),
itemTitle: s__('GeoNodes|Data replication lag'),
itemValue: this.dbReplicationLag(),
itemValueType: VALUE_TYPE.PLAIN,
},
{
itemTitle: s__('GeoNodes|Last event ID seen from primary:'),
itemTitle: s__('GeoNodes|Last event ID seen from primary'),
itemValue: this.lastEventStatus(),
itemValueType: VALUE_TYPE.CUSTOM,
customType: CUSTOM_TYPE.EVENT,
},
{
itemTitle: s__('GeoNodes|Latest event log status:'),
itemTitle: s__('GeoNodes|Latest event log status'),
itemValue: this.cursorLastEventStatus(),
itemValueType: VALUE_TYPE.CUSTOM,
customType: CUSTOM_TYPE.EVENT,
......
......@@ -2,7 +2,7 @@
import { s__ } from '~/locale';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import { VALUE_TYPE } from '../../constants';
import { VALUE_TYPE, HELP_INFO_URL } from '../../constants';
import GeoNodeDetailItem from '../geo_node_detail_item.vue';
import SectionRevealButton from './section_reveal_button.vue';
......@@ -49,27 +49,37 @@
if (this.nodeDetails.repositoryVerificationEnabled) {
primaryNodeDetailItems.push(
{
itemTitle: s__('GeoNodes|Repository verification progress:'),
itemTitle: s__('GeoNodes|Repository checksum progress'),
itemValue: this.nodeDetails.verifiedRepositories,
itemValueType: VALUE_TYPE.GRAPH,
successLabel: s__('GeoNodes|Checksummed'),
neutraLabel: s__('GeoNodes|Not checksummed'),
failureLabel: s__('GeoNodes|Failed'),
helpInfo: {
title: s__('GeoNodes|Repositories checksummed for verification with their counterparts on Secondary nodes'),
url: HELP_INFO_URL,
urlText: s__('GeoNodes|Learn more about Repository checksum progress'),
},
},
{
itemTitle: s__('GeoNodes|Wikis checksums calculated verifies:'),
itemTitle: s__('GeoNodes|Wiki checksum progress'),
itemValue: this.nodeDetails.verifiedWikis,
itemValueType: VALUE_TYPE.GRAPH,
successLabel: s__('GeoNodes|Checksummed'),
neutraLabel: s__('GeoNodes|Not checksummed'),
failureLabel: s__('GeoNodes|Failed'),
helpInfo: {
title: s__('GeoNodes|Wikis checksummed for verification with their counterparts on Secondary nodes'),
url: HELP_INFO_URL,
urlText: s__('GeoNodes|Learn more about Wiki checksum progress'),
},
},
);
}
primaryNodeDetailItems.push(
{
itemTitle: s__('GeoNodes|Replication slots:'),
itemTitle: s__('GeoNodes|Replication slots'),
itemValue: this.nodeDetails.replicationSlots,
itemValueType: VALUE_TYPE.GRAPH,
successLabel: s__('GeoNodes|Used slots'),
......@@ -80,7 +90,7 @@
if (this.nodeDetails.replicationSlots.totalCount) {
primaryNodeDetailItems.push(
{
itemTitle: s__('GeoNodes|Replication slot WAL:'),
itemTitle: s__('GeoNodes|Replication slot WAL'),
itemValue: numberToHumanSize(this.nodeDetails.replicationSlotWAL),
itemValueType: VALUE_TYPE.PLAIN,
cssClass: 'node-detail-value-bold',
......@@ -93,20 +103,30 @@
getSecondaryNodeDetailItems() {
const secondaryNodeDetailItems = [
{
itemTitle: s__('GeoNodes|Repository checksums verified:'),
itemTitle: s__('GeoNodes|Repository verification progress'),
itemValue: this.nodeDetails.verifiedRepositories,
itemValueType: VALUE_TYPE.GRAPH,
successLabel: s__('GeoNodes|Verified'),
neutraLabel: s__('GeoNodes|Unverified'),
failureLabel: s__('GeoNodes|Failed'),
helpInfo: {
title: s__('GeoNodes|Repositories verified with their counterparts on the Primary node'),
url: HELP_INFO_URL,
urlText: s__('GeoNodes|Learn more about Repository verification'),
},
},
{
itemTitle: s__('GeoNodes|Wiki checksums verified:'),
itemTitle: s__('GeoNodes|Wiki verification progress'),
itemValue: this.nodeDetails.verifiedWikis,
itemValueType: VALUE_TYPE.GRAPH,
successLabel: s__('GeoNodes|Verified'),
neutraLabel: s__('GeoNodes|Unverified'),
failureLabel: s__('GeoNodes|Failed'),
helpInfo: {
title: s__('GeoNodes|Wikis verified with their counterparts on the Primary node'),
url: HELP_INFO_URL,
urlText: s__('GeoNodes|Learn more about Wiki verification'),
},
},
];
......@@ -145,6 +165,7 @@
:neutral-label="nodeDetailItem.neutraLabel"
:failure-label="nodeDetailItem.failureLabel"
:custom-type="nodeDetailItem.customType"
:help-info="nodeDetailItem.helpInfo"
/>
</div>
</template>
......
......@@ -27,3 +27,5 @@ export const TIME_DIFF = {
FIVE_MINS: 300,
HOUR: 3600,
};
export const HELP_INFO_URL = 'https://docs.gitlab.com/ee/administration/geo/disaster_recovery/background_verification.html#repository-verification';
......@@ -101,6 +101,14 @@
.section-items-container {
.node-detail-title {
color: $theme-gray-700;
.node-detail-help-text {
color: $blue-600;
}
.tooltip .tooltip-inner {
text-align: left;
}
}
.node-detail-value {
......@@ -125,6 +133,7 @@
}
}
.node-detail-title,
.node-health-status,
.node-sync-settings,
.node-detail-section .btn-show-section {
......
---
title: Update item titles and add help text in Geo nodes admin dashboard
merge_request: 5306
author:
type: changed
......@@ -8,7 +8,7 @@ import { rawMockNodeDetails } from '../mock_data';
const createComponent = (config) => {
const Component = Vue.extend(geoNodeDetailItemComponent);
const defaultConfig = Object.assign({
itemTitle: 'GitLab version:',
itemTitle: 'GitLab version',
cssClass: 'node-version',
itemValue: '10.4.0-pre',
successLabel: 'Synced',
......@@ -26,7 +26,7 @@ describe('GeoNodeDetailItemComponent', () => {
const vm = createComponent();
expect(vm.$el.classList.contains('node-detail-item')).toBeTruthy();
expect(vm.$el.querySelectorAll('.node-detail-title').length).not.toBe(0);
expect(vm.$el.querySelector('.node-detail-title').innerText.trim()).toBe('GitLab version:');
expect(vm.$el.querySelector('.node-detail-title').innerText.trim()).toBe('GitLab version');
vm.$destroy();
});
......@@ -37,6 +37,16 @@ describe('GeoNodeDetailItemComponent', () => {
vm.$destroy();
});
it('renders item title help info icon and popover with help info', () => {
const helpInfo = { title: 'Foo title tooltip', url: 'https://docs.gitlab.com', urlText: 'Help' };
const vm = createComponent({ helpInfo });
const helpTextIconEl = vm.$el.querySelector('.node-detail-help-text');
expect(helpTextIconEl).not.toBeNull();
expect(helpTextIconEl.querySelector('use').getAttribute('xlink:href')).toContain('question');
vm.$destroy();
});
it('renders graph item value', () => {
const vm = createComponent({
itemValueType: VALUE_TYPE.GRAPH,
......
......@@ -51,7 +51,7 @@ describe('GeoNodeHealthStatusComponent', () => {
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:');
expect(vm.$el.querySelector('.node-detail-title').innerText.trim()).toBe('Health status');
const iconContainerEl = vm.$el.querySelector('.node-detail-value.node-health-status');
expect(iconContainerEl).not.toBeNull();
......
......@@ -75,7 +75,7 @@ describe('NodeDetailsSectionMain', () => {
});
it('renders node version element', () => {
expect(vm.$el.querySelector('.node-detail-title').innerText.trim()).toBe('GitLab version:');
expect(vm.$el.querySelector('.node-detail-title').innerText.trim()).toBe('GitLab version');
expect(vm.$el.querySelector('.node-detail-value').innerText.trim()).toBe('10.4.0-pre (b93c51849b)');
});
});
......
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