Commit 951572f1 authored by Zack Cuddy's avatar Zack Cuddy Committed by Mark Florian

Geo Node Status 2.0 - Core Details

This change adds the core node details
for both primary and secondary nodes.

This change uses placeholders for the
primary and secondary node data.
parent 754fc168
<script>
import { GlLink, GlIcon } from '@gitlab/ui';
import { mapState } from 'vuex';
import { __, s__ } from '~/locale';
export default {
name: 'GeoNodeCoreDetails',
i18n: {
url: __('URL'),
internalUrl: s__('Geo|Internal URL'),
gitlabVersion: __('GitLab version'),
},
components: {
GlLink,
GlIcon,
},
props: {
node: {
type: Object,
required: true,
},
},
computed: {
...mapState(['primaryVersion', 'primaryRevision']),
nodeVersion() {
if (!this.node.version || !this.node.revision) {
return __('Unknown');
}
return `${this.node.version} (${this.node.revision})`;
},
versionMismatch() {
return (
this.node.version !== this.primaryVersion || this.node.revision !== this.primaryRevision
);
},
},
};
</script>
<template>
<div class="gl-display-grid gl-lg-display-block! geo-node-core-details-grid-columns">
<div class="gl-display-flex gl-flex-direction-column gl-lg-mb-5">
<span>{{ $options.i18n.url }}</span>
<gl-link
class="gl-text-gray-900 gl-font-weight-bold gl-text-decoration-underline"
:href="node.url"
>{{ node.url }} <gl-icon name="external-link" class="gl-ml-1"
/></gl-link>
</div>
<div v-if="node.primary" class="gl-display-flex gl-flex-direction-column gl-lg-my-5">
<span>{{ $options.i18n.internalUrl }}</span>
<span class="gl-font-weight-bold" data-testid="node-internal-url">{{
node.internalUrl
}}</span>
</div>
<div class="gl-display-flex gl-flex-direction-column gl-lg-mt-5">
<span>{{ $options.i18n.gitlabVersion }}</span>
<span
:class="{ 'gl-text-red-500': versionMismatch }"
class="gl-font-weight-bold"
data-testid="node-version"
>
{{ nodeVersion }}
</span>
</div>
</div>
</template>
<script>
import { s__ } from '~/locale';
import GeoNodeCoreDetails from './geo_node_core_details.vue';
export default {
name: 'GeoNodeDetails',
i18n: {
primaryDetails: s__('Geo|Primary Details'),
secondaryDetails: s__('Geo|Secondary Details'),
},
components: {
GeoNodeCoreDetails,
},
props: {
node: {
type: Object,
required: true,
},
},
};
</script>
<template>
<div class="gl-display-grid geo-node-details-grid-columns gl-p-5">
<geo-node-core-details :node="node" />
<div
v-if="node.primary"
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>
</div>
<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>
</div>
</div>
</template>
<script> <script>
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import GeoNodeDetails from './details/geo_node_details.vue';
import GeoNodeHeader from './header/geo_node_header.vue'; import GeoNodeHeader from './header/geo_node_header.vue';
export default { export default {
name: 'GeoNodes', name: 'GeoNodes',
components: { components: {
GeoNodeHeader, GeoNodeHeader,
GeoNodeDetails,
}, },
props: { props: {
node: { node: {
...@@ -37,6 +39,6 @@ export default { ...@@ -37,6 +39,6 @@ export default {
<div> <div>
<h4 class="gl-font-lg gl-my-5">{{ siteTitle }}</h4> <h4 class="gl-font-lg gl-my-5">{{ siteTitle }}</h4>
<geo-node-header :node="node" :collapsed="collapsed" @collapse="toggleCollapse" /> <geo-node-header :node="node" :collapsed="collapsed" @collapse="toggleCollapse" />
<p v-if="!collapsed">{{ s__('Geo|Node Details') }}</p> <geo-node-details v-if="!collapsed" :node="node" />
</div> </div>
</template> </template>
...@@ -31,9 +31,22 @@ ...@@ -31,9 +31,22 @@
.geo-node-header-grid-columns { .geo-node-header-grid-columns {
grid-template-columns: 1fr auto; grid-template-columns: 1fr auto;
grid-gap: 1rem; grid-gap: $gl-spacing-scale-5;
@include media-breakpoint-up(md) { @include media-breakpoint-up(md) {
grid-template-columns: 3fr 1fr; grid-template-columns: 3fr 1fr;
} }
} }
.geo-node-details-grid-columns {
grid-gap: $gl-spacing-scale-5;
@include media-breakpoint-up(lg) {
grid-template-columns: 1fr 3fr;
}
}
.geo-node-core-details-grid-columns {
grid-template-columns: 1fr 1fr;
grid-gap: $gl-spacing-scale-5;
}
import { GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
import GeoNodeCoreDetails from 'ee/geo_nodes_beta/components/details/geo_node_core_details.vue';
import {
MOCK_PRIMARY_VERSION,
MOCK_REPLICABLE_TYPES,
MOCK_NODES,
} from 'ee_jest/geo_nodes_beta/mock_data';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
Vue.use(Vuex);
describe('GeoNodeCoreDetails', () => {
let wrapper;
const defaultProps = {
node: MOCK_NODES[0],
};
const createComponent = (initialState, props) => {
const store = new Vuex.Store({
state: {
primaryVersion: MOCK_PRIMARY_VERSION.version,
primaryRevision: MOCK_PRIMARY_VERSION.revision,
replicableTypes: MOCK_REPLICABLE_TYPES,
...initialState,
},
});
wrapper = extendedWrapper(
shallowMount(GeoNodeCoreDetails, {
store,
propsData: {
...defaultProps,
...props,
},
}),
);
};
afterEach(() => {
wrapper.destroy();
});
const findNodeUrl = () => wrapper.findComponent(GlLink);
const findNodeInternalUrl = () => wrapper.findByTestId('node-internal-url');
const findNodeVersion = () => wrapper.findByTestId('node-version');
describe('template', () => {
describe('always', () => {
beforeEach(() => {
createComponent();
});
it('renders the Node Url correctly', () => {
expect(findNodeUrl().exists()).toBe(true);
expect(findNodeUrl().attributes('href')).toBe(MOCK_NODES[0].url);
expect(findNodeUrl().text()).toBe(MOCK_NODES[0].url);
});
it('renders the node version', () => {
expect(findNodeVersion().exists()).toBe(true);
});
});
describe.each`
node | showInternalUrl
${MOCK_NODES[0]} | ${true}
${MOCK_NODES[1]} | ${false}
`(`conditionally`, ({ node, showInternalUrl }) => {
beforeEach(() => {
createComponent(null, { node });
});
describe(`when primary is ${node.primary}`, () => {
it(`does ${showInternalUrl ? '' : 'not '}render node internal url`, () => {
expect(findNodeInternalUrl().exists()).toBe(showInternalUrl);
});
});
});
describe('node version', () => {
describe.each`
currentNode | versionText | versionMismatch
${{ version: MOCK_PRIMARY_VERSION.version, revision: MOCK_PRIMARY_VERSION.revision }} | ${`${MOCK_PRIMARY_VERSION.version} (${MOCK_PRIMARY_VERSION.revision})`} | ${false}
${{ version: 'asdf', revision: MOCK_PRIMARY_VERSION.revision }} | ${`asdf (${MOCK_PRIMARY_VERSION.revision})`} | ${true}
${{ version: MOCK_PRIMARY_VERSION.version, revision: 'asdf' }} | ${`${MOCK_PRIMARY_VERSION.version} (asdf)`} | ${true}
${{ version: null, revision: null }} | ${'Unknown'} | ${true}
`(`conditionally`, ({ currentNode, versionText, versionMismatch }) => {
beforeEach(() => {
createComponent(null, { node: { ...MOCK_NODES[0], ...currentNode } });
});
describe(`when version mismatch is ${versionMismatch} and current node version is ${versionText}`, () => {
it(`does ${versionMismatch ? '' : 'not '}render version with error color`, () => {
expect(findNodeVersion().classes('gl-text-red-500')).toBe(versionMismatch);
});
it('does render version text correctly', () => {
expect(findNodeVersion().text()).toBe(versionText);
});
});
});
});
});
});
import { shallowMount } from '@vue/test-utils';
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 { MOCK_NODES } from 'ee_jest/geo_nodes_beta/mock_data';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
describe('GeoNodeDetails', () => {
let wrapper;
const defaultProps = {
node: MOCK_NODES[0],
};
const createComponent = (props) => {
wrapper = extendedWrapper(
shallowMount(GeoNodeDetails, {
propsData: {
...defaultProps,
...props,
},
}),
);
};
afterEach(() => {
wrapper.destroy();
});
const findGeoNodeCoreDetails = () => wrapper.findComponent(GeoNodeCoreDetails);
const findGeoNodePrimaryDetails = () => wrapper.findByTestId('primary-node-details');
const findGeoNodeSecondaryDetails = () => wrapper.findByTestId('secondary-node-details');
describe('template', () => {
describe('always', () => {
beforeEach(() => {
createComponent();
});
it('renders the Geo Nodes Core Details', () => {
expect(findGeoNodeCoreDetails().exists()).toBe(true);
});
});
describe.each`
node | showPrimaryDetails | showSecondaryDetails
${MOCK_NODES[0]} | ${true} | ${false}
${MOCK_NODES[1]} | ${false} | ${true}
`(`conditionally`, ({ node, showPrimaryDetails, 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`, () => {
expect(findGeoNodeSecondaryDetails().exists()).toBe(showSecondaryDetails);
});
});
});
});
});
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import Vuex from 'vuex'; import GeoNodeDetails from 'ee/geo_nodes_beta/components/details/geo_node_details.vue';
import GeoNodes from 'ee/geo_nodes_beta/components/geo_nodes.vue'; import GeoNodes from 'ee/geo_nodes_beta/components/geo_nodes.vue';
import GeoNodeHeader from 'ee/geo_nodes_beta/components/header/geo_node_header.vue'; import GeoNodeHeader from 'ee/geo_nodes_beta/components/header/geo_node_header.vue';
import { MOCK_PRIMARY_VERSION, MOCK_REPLICABLE_TYPES, MOCK_NODES } from '../mock_data'; import { MOCK_NODES } from '../mock_data';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('GeoNodes', () => { describe('GeoNodes', () => {
let wrapper; let wrapper;
...@@ -14,19 +11,8 @@ describe('GeoNodes', () => { ...@@ -14,19 +11,8 @@ describe('GeoNodes', () => {
node: MOCK_NODES[0], node: MOCK_NODES[0],
}; };
const createComponent = (initialState, props) => { const createComponent = (props) => {
const store = new Vuex.Store({
state: {
primaryVersion: MOCK_PRIMARY_VERSION.version,
primaryRevision: MOCK_PRIMARY_VERSION.revision,
replicableTypes: MOCK_REPLICABLE_TYPES,
...initialState,
},
});
wrapper = shallowMount(GeoNodes, { wrapper = shallowMount(GeoNodes, {
localVue,
store,
propsData: { propsData: {
...defaultProps, ...defaultProps,
...props, ...props,
...@@ -41,8 +27,8 @@ describe('GeoNodes', () => { ...@@ -41,8 +27,8 @@ describe('GeoNodes', () => {
const findGeoNodesContainer = () => wrapper.find('div'); const findGeoNodesContainer = () => wrapper.find('div');
const findGeoSiteTitle = () => wrapper.find('h4'); const findGeoSiteTitle = () => wrapper.find('h4');
const findGeoNodeHeader = () => wrapper.find(GeoNodeHeader); const findGeoNodeHeader = () => wrapper.findComponent(GeoNodeHeader);
const findGeoNodeDetails = () => wrapper.find('p'); const findGeoNodeDetails = () => wrapper.findComponent(GeoNodeDetails);
describe('template', () => { describe('template', () => {
beforeEach(() => { beforeEach(() => {
...@@ -78,7 +64,7 @@ describe('GeoNodes', () => { ...@@ -78,7 +64,7 @@ describe('GeoNodes', () => {
${MOCK_NODES[1]} | ${'Secondary site'} ${MOCK_NODES[1]} | ${'Secondary site'}
`(`Site Title`, ({ node, siteTitle }) => { `(`Site Title`, ({ node, siteTitle }) => {
beforeEach(() => { beforeEach(() => {
createComponent(null, { node }); createComponent({ node });
}); });
it(`is ${siteTitle} when primary is ${node.primary}`, () => { it(`is ${siteTitle} when primary is ${node.primary}`, () => {
......
...@@ -13875,6 +13875,9 @@ msgstr "" ...@@ -13875,6 +13875,9 @@ msgstr ""
msgid "Geo|In sync" msgid "Geo|In sync"
msgstr "" msgstr ""
msgid "Geo|Internal URL"
msgstr ""
msgid "Geo|Last repository check run" msgid "Geo|Last repository check run"
msgstr "" msgstr ""
...@@ -13899,9 +13902,6 @@ msgstr "" ...@@ -13899,9 +13902,6 @@ msgstr ""
msgid "Geo|Next sync scheduled at" msgid "Geo|Next sync scheduled at"
msgstr "" msgstr ""
msgid "Geo|Node Details"
msgstr ""
msgid "Geo|Node name can't be blank" msgid "Geo|Node name can't be blank"
msgstr "" msgstr ""
...@@ -13920,6 +13920,9 @@ msgstr "" ...@@ -13920,6 +13920,9 @@ 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 ""
...@@ -13968,6 +13971,9 @@ msgstr "" ...@@ -13968,6 +13971,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node." msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr "" msgstr ""
msgid "Geo|Secondary Details"
msgstr ""
msgid "Geo|Secondary node" msgid "Geo|Secondary node"
msgstr "" msgstr ""
...@@ -14196,6 +14202,9 @@ msgstr "" ...@@ -14196,6 +14202,9 @@ msgstr ""
msgid "GitLab uses %{jaeger_link} to monitor distributed systems." msgid "GitLab uses %{jaeger_link} to monitor distributed systems."
msgstr "" msgstr ""
msgid "GitLab version"
msgstr ""
msgid "GitLab will run a background job that will produce pseudonymized CSVs of the GitLab database that will be uploaded to your configured object storage directory." msgid "GitLab will run a background job that will produce pseudonymized CSVs of the GitLab database that will be uploaded to your configured object storage directory."
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