Commit e36d606d authored by Zack Cuddy's avatar Zack Cuddy Committed by Mike Greiling

Geo Node Status 2.0 - Primary Details

This change replaces the placeholder text
for the Primary specific node details
with actual components.

This change still leaves placeholder text
for the progress bars for the next mr
as well as in the secondary
node details section.
parent 983a1c52
<script> <script>
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import GeoNodeCoreDetails from './geo_node_core_details.vue'; import GeoNodeCoreDetails from './geo_node_core_details.vue';
import GeoNodePrimaryOtherInfo from './primary_node/geo_node_primary_other_info.vue';
import GeoNodeVerificationInfo from './primary_node/geo_node_verification_info.vue';
export default { export default {
name: 'GeoNodeDetails', name: 'GeoNodeDetails',
i18n: { i18n: {
primaryDetails: s__('Geo|Primary Details'),
secondaryDetails: s__('Geo|Secondary Details'), secondaryDetails: s__('Geo|Secondary Details'),
}, },
components: { components: {
GeoNodeCoreDetails, GeoNodeCoreDetails,
GeoNodePrimaryOtherInfo,
GeoNodeVerificationInfo,
}, },
props: { props: {
node: { node: {
...@@ -27,7 +30,11 @@ export default { ...@@ -27,7 +30,11 @@ export default {
v-if="node.primary" v-if="node.primary"
class="gl-display-flex gl-sm-flex-direction-column gl-align-items-flex-start gl-h-full gl-w-full" class="gl-display-flex gl-sm-flex-direction-column gl-align-items-flex-start gl-h-full gl-w-full"
> >
<p data-testid="primary-node-details">{{ $options.i18n.primaryDetails }}</p> <geo-node-verification-info
class="gl-flex-fill-1 gl-mb-5 gl-md-mb-0 gl-md-mr-5 gl-h-full gl-w-full"
:node="node"
/>
<geo-node-primary-other-info class="gl-flex-fill-1 gl-h-full gl-w-full" :node="node" />
</div> </div>
<div v-else class="gl-display-flex gl-flex-direction-column gl-h-full gl-w-full"> <div v-else class="gl-display-flex gl-flex-direction-column gl-h-full gl-w-full">
<p data-testid="secondary-node-details">{{ $options.i18n.secondaryDetails }}</p> <p data-testid="secondary-node-details">{{ $options.i18n.secondaryDetails }}</p>
......
<script>
import { GlCard } from '@gitlab/ui';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import { __, s__ } from '~/locale';
export default {
name: 'GeoNodePrimaryOtherInfo',
i18n: {
otherInformation: __('Other information'),
progressBarPlaceholder: s__('Geo|Progress Bar Placeholder'),
replicationSlotWAL: s__('Geo|Replication slot WAL'),
},
components: {
GlCard,
},
props: {
node: {
type: Object,
required: true,
},
},
computed: {
replicationSlotWAL() {
return numberToHumanSize(this.node.replicationSlotsMaxRetainedWalBytes);
},
replicationSlots() {
return {
title: s__('Geo|Replication slots'),
values: {
total: this.node.replicationSlotsCount || 0,
success: this.node.replicationSlotsUsedCount || 0,
},
};
},
},
};
</script>
<template>
<gl-card>
<template #header>
<h5 class="gl-my-0">{{ $options.i18n.otherInformation }}</h5>
</template>
<div class="gl-mb-5">
<span>{{ replicationSlots.title }}</span>
<p data-testid="replication-progress-bar">{{ $options.i18n.progressBarPlaceholder }}</p>
</div>
<div
v-if="node.replicationSlotsMaxRetainedWalBytes"
class="gl-display-flex gl-flex-direction-column gl-mb-5"
>
<span>{{ $options.i18n.replicationSlotWAL }}</span>
<span class="gl-font-weight-bold gl-mt-2" data-testid="replication-slot-wal">{{
replicationSlotWAL
}}</span>
</div>
</gl-card>
</template>
<script>
import { GlCard, GlIcon, GlPopover, GlLink } from '@gitlab/ui';
import { mapGetters } from 'vuex';
import { HELP_INFO_URL } from 'ee/geo_nodes_beta/constants';
import { sprintf, s__, __ } from '~/locale';
export default {
name: 'GeoNodeVerificationInfo',
i18n: {
verificationInfo: s__('Geo|Verificaton information'),
replicationHelpText: s__(
'Geo|Replicated data is verified with the secondary node(s) using checksums.',
),
learnMore: __('Learn more'),
progressBarPlaceholder: s__('Geo|Progress Bar Placeholder'),
},
components: {
GlCard,
GlIcon,
GlPopover,
GlLink,
},
props: {
node: {
type: Object,
required: true,
},
},
computed: {
...mapGetters(['verificationInfo']),
verificationInfoBars() {
return this.verificationInfo(this.node.id);
},
},
methods: {
buildTitle(title) {
return sprintf(s__('Geo|%{title} checksum progress'), { title });
},
},
HELP_INFO_URL,
};
</script>
<template>
<gl-card header-class="gl-display-flex gl-align-items-center">
<template #header>
<h5 class="gl-my-0">{{ $options.i18n.verificationInfo }}</h5>
<gl-icon
ref="verificationInfo"
name="question"
class="gl-text-blue-500 gl-cursor-pointer gl-ml-2"
/>
<gl-popover :target="() => $refs.verificationInfo.$el" placement="top" triggers="hover focus">
<p class="gl-font-base">
{{ $options.i18n.replicationHelpText }}
</p>
<gl-link :href="$options.HELP_INFO_URL" target="_blank">{{
$options.i18n.learnMore
}}</gl-link>
</gl-popover>
</template>
<div v-for="bar in verificationInfoBars" :key="bar.title" class="gl-mb-5">
<span data-testid="verification-bar-title">{{ buildTitle(bar.title) }}</span>
<p data-testid="verification-progress-bar">{{ $options.i18n.progressBarPlaceholder }}</p>
</div>
</gl-card>
</template>
...@@ -12,6 +12,11 @@ export const GEO_TROUBLESHOOTING_URL = helpPagePath( ...@@ -12,6 +12,11 @@ export const GEO_TROUBLESHOOTING_URL = helpPagePath(
'administration/geo/replication/troubleshooting.html', 'administration/geo/replication/troubleshooting.html',
); );
export const HELP_INFO_URL = helpPagePath(
'administration/geo/disaster_recovery/background_verification.html',
{ anchor: 'repository-verification' },
);
export const HEALTH_STATUS_UI = { export const HEALTH_STATUS_UI = {
healthy: { healthy: {
icon: 'status_success', icon: 'status_success',
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import GeoNodeCoreDetails from 'ee/geo_nodes_beta/components/details/geo_node_core_details.vue'; import GeoNodeCoreDetails from 'ee/geo_nodes_beta/components/details/geo_node_core_details.vue';
import GeoNodeDetails from 'ee/geo_nodes_beta/components/details/geo_node_details.vue'; import GeoNodeDetails from 'ee/geo_nodes_beta/components/details/geo_node_details.vue';
import GeoNodePrimaryOtherInfo from 'ee/geo_nodes_beta/components/details/primary_node/geo_node_primary_other_info.vue';
import GeoNodeVerificationInfo from 'ee/geo_nodes_beta/components/details/primary_node/geo_node_verification_info.vue';
import { MOCK_NODES } from 'ee_jest/geo_nodes_beta/mock_data'; import { MOCK_NODES } from 'ee_jest/geo_nodes_beta/mock_data';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
...@@ -27,7 +29,8 @@ describe('GeoNodeDetails', () => { ...@@ -27,7 +29,8 @@ describe('GeoNodeDetails', () => {
}); });
const findGeoNodeCoreDetails = () => wrapper.findComponent(GeoNodeCoreDetails); const findGeoNodeCoreDetails = () => wrapper.findComponent(GeoNodeCoreDetails);
const findGeoNodePrimaryDetails = () => wrapper.findByTestId('primary-node-details'); const findGeoNodePrimaryOtherInfo = () => wrapper.findComponent(GeoNodePrimaryOtherInfo);
const findGeoNodeVerificationInfo = () => wrapper.findComponent(GeoNodeVerificationInfo);
const findGeoNodeSecondaryDetails = () => wrapper.findByTestId('secondary-node-details'); const findGeoNodeSecondaryDetails = () => wrapper.findByTestId('secondary-node-details');
describe('template', () => { describe('template', () => {
...@@ -42,23 +45,32 @@ describe('GeoNodeDetails', () => { ...@@ -42,23 +45,32 @@ describe('GeoNodeDetails', () => {
}); });
describe.each` describe.each`
node | showPrimaryDetails | showSecondaryDetails node | showPrimaryOtherInfo | showPrimaryVerificationInfo | showSecondaryDetails
${MOCK_NODES[0]} | ${true} | ${false} ${MOCK_NODES[0]} | ${true} | ${true} | ${false}
${MOCK_NODES[1]} | ${false} | ${true} ${MOCK_NODES[1]} | ${false} | ${false} | ${true}
`(`conditionally`, ({ node, showPrimaryDetails, showSecondaryDetails }) => { `(
beforeEach(() => { `conditionally`,
createComponent({ node }); ({ node, showPrimaryOtherInfo, showPrimaryVerificationInfo, showSecondaryDetails }) => {
}); beforeEach(() => {
createComponent({ node });
describe(`when primary is ${node.primary}`, () => {
it(`does ${showPrimaryDetails ? '' : 'not '}render GeoNodePrimaryDetails`, () => {
expect(findGeoNodePrimaryDetails().exists()).toBe(showPrimaryDetails);
}); });
it(`does ${showSecondaryDetails ? '' : 'not '}render GeoNodeSecondaryDetails`, () => { describe(`when primary is ${node.primary}`, () => {
expect(findGeoNodeSecondaryDetails().exists()).toBe(showSecondaryDetails); it(`does ${showPrimaryOtherInfo ? '' : 'not '}render GeoNodePrimaryInfo`, () => {
expect(findGeoNodePrimaryOtherInfo().exists()).toBe(showPrimaryOtherInfo);
});
it(`does ${
showPrimaryVerificationInfo ? '' : 'not '
}render GeoNodeVerificationInfo`, () => {
expect(findGeoNodeVerificationInfo().exists()).toBe(showPrimaryVerificationInfo);
});
it(`does ${showSecondaryDetails ? '' : 'not '}render GeoNodeSecondaryDetails`, () => {
expect(findGeoNodeSecondaryDetails().exists()).toBe(showSecondaryDetails);
});
}); });
}); },
}); );
}); });
}); });
import { GlCard } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import GeoNodePrimaryOtherInfo from 'ee/geo_nodes_beta/components/details/primary_node/geo_node_primary_other_info.vue';
import { MOCK_NODES } from 'ee_jest/geo_nodes_beta/mock_data';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { numberToHumanSize } from '~/lib/utils/number_utils';
describe('GeoNodePrimaryOtherInfo', () => {
let wrapper;
const defaultProps = {
node: MOCK_NODES[0],
};
const createComponent = (props) => {
wrapper = extendedWrapper(
shallowMount(GeoNodePrimaryOtherInfo, {
propsData: {
...defaultProps,
...props,
},
}),
);
};
afterEach(() => {
wrapper.destroy();
});
const findGlCard = () => wrapper.findComponent(GlCard);
const findGeoNodeProgressBar = () => wrapper.findByTestId('replication-progress-bar');
const findReplicationSlotWAL = () => wrapper.findByTestId('replication-slot-wal');
describe('template', () => {
describe('always', () => {
beforeEach(() => {
createComponent();
});
it('renders the details card', () => {
expect(findGlCard().exists()).toBe(true);
});
it('renders the replicationSlots progress bar', () => {
expect(findGeoNodeProgressBar().exists()).toBe(true);
});
});
describe('when replicationSlotWAL exists', () => {
beforeEach(() => {
createComponent({ node: MOCK_NODES[0] });
});
it('renders the replicationSlotWAL section correctly', () => {
expect(findReplicationSlotWAL().exists()).toBe(true);
expect(findReplicationSlotWAL().text()).toBe(
numberToHumanSize(MOCK_NODES[0].replicationSlotsMaxRetainedWalBytes),
);
});
});
describe('when replicationSlotWAL is null', () => {
beforeEach(() => {
createComponent({ node: MOCK_NODES[1] });
});
it('does not render the replicationSlotWAL section', () => {
expect(findReplicationSlotWAL().exists()).toBe(false);
});
});
});
});
import { GlCard, GlIcon, GlPopover, GlLink } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
import GeoNodeVerificationInfo from 'ee/geo_nodes_beta/components/details/primary_node/geo_node_verification_info.vue';
import { HELP_INFO_URL } from 'ee/geo_nodes_beta/constants';
import { MOCK_NODES, MOCK_PRIMARY_VERIFICATION_INFO } from 'ee_jest/geo_nodes_beta/mock_data';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
Vue.use(Vuex);
describe('GeoNodeVerificationInfo', () => {
let wrapper;
const defaultProps = {
node: MOCK_NODES[0],
};
const createComponent = (props) => {
const store = new Vuex.Store({
getters: {
verificationInfo: () => () => MOCK_PRIMARY_VERIFICATION_INFO,
},
});
wrapper = extendedWrapper(
mount(GeoNodeVerificationInfo, {
store,
propsData: {
...defaultProps,
...props,
},
}),
);
};
afterEach(() => {
wrapper.destroy();
});
const findGlCard = () => wrapper.findComponent(GlCard);
const findGlIcon = () => wrapper.findComponent(GlIcon);
const findGlPopover = () => wrapper.findComponent(GlPopover);
const findGlPopoverLink = () => findGlPopover().findComponent(GlLink);
const findGeoNodeProgressBarTitles = () => wrapper.findAllByTestId('verification-bar-title');
const findGeoNodeProgressBars = () => wrapper.findAllByTestId('verification-progress-bar');
describe('template', () => {
describe('always', () => {
beforeEach(() => {
createComponent();
});
it('renders the details card', () => {
expect(findGlCard().exists()).toBe(true);
});
it('renders the question icon correctly', () => {
expect(findGlIcon().exists()).toBe(true);
expect(findGlIcon().props('name')).toBe('question');
});
it('renders the GlPopover always', () => {
expect(findGlPopover().exists()).toBe(true);
});
it('renders the popover link correctly', () => {
expect(findGlPopoverLink().exists()).toBe(true);
expect(findGlPopoverLink().attributes('href')).toBe(HELP_INFO_URL);
});
it('renders a progress bar for each verification replicable', () => {
expect(findGeoNodeProgressBars()).toHaveLength(MOCK_PRIMARY_VERIFICATION_INFO.length);
});
it('renders progress bar titles correctly', () => {
expect(findGeoNodeProgressBarTitles().wrappers.map((w) => w.text())).toStrictEqual(
MOCK_PRIMARY_VERIFICATION_INFO.map((vI) => `${vI.title} checksum progress`),
);
});
});
});
});
...@@ -13833,6 +13833,9 @@ msgstr "" ...@@ -13833,6 +13833,9 @@ msgstr ""
msgid "Geo|%{name} is scheduled for re-verify" msgid "Geo|%{name} is scheduled for re-verify"
msgstr "" msgstr ""
msgid "Geo|%{title} checksum progress"
msgstr ""
msgid "Geo|Add site" msgid "Geo|Add site"
msgstr "" msgstr ""
...@@ -13947,15 +13950,15 @@ msgstr "" ...@@ -13947,15 +13950,15 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting." msgid "Geo|Please refer to Geo Troubleshooting."
msgstr "" msgstr ""
msgid "Geo|Primary Details"
msgstr ""
msgid "Geo|Primary node" msgid "Geo|Primary node"
msgstr "" msgstr ""
msgid "Geo|Primary site" msgid "Geo|Primary site"
msgstr "" msgstr ""
msgid "Geo|Progress Bar Placeholder"
msgstr ""
msgid "Geo|Project" msgid "Geo|Project"
msgstr "" msgstr ""
...@@ -13980,6 +13983,15 @@ msgstr "" ...@@ -13980,6 +13983,15 @@ msgstr ""
msgid "Geo|Remove tracking database entry" msgid "Geo|Remove tracking database entry"
msgstr "" msgstr ""
msgid "Geo|Replicated data is verified with the secondary node(s) using checksums."
msgstr ""
msgid "Geo|Replication slot WAL"
msgstr ""
msgid "Geo|Replication slots"
msgstr ""
msgid "Geo|Resync" msgid "Geo|Resync"
msgstr "" msgstr ""
...@@ -14055,6 +14067,9 @@ msgstr "" ...@@ -14055,6 +14067,9 @@ msgstr ""
msgid "Geo|Verification failed - %{error}" msgid "Geo|Verification failed - %{error}"
msgstr "" msgstr ""
msgid "Geo|Verificaton information"
msgstr ""
msgid "Geo|Waiting for scheduler" msgid "Geo|Waiting for scheduler"
msgstr "" msgstr ""
......
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