Commit 2dd8d142 authored by Zack Cuddy's avatar Zack Cuddy

Make Geo Selective Sync more clear

Currently, it is not very clear when a
Node is set up for selective sync.

This MR moves the selective sync data
to the header section of the Node card.

It also unifies the verbiage "Groups" to replace
the limited usage of "Namespaces" in some sections.
parent d0ccf9f2
<script>
import { sprintf, s__ } from '~/locale';
import { sprintf, s__, __ } from '~/locale';
import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
import tooltip from '~/vue_shared/directives/tooltip';
import icon from '~/vue_shared/components/icon.vue';
......@@ -40,7 +40,11 @@ export default {
return s__('GeoNodes|Full');
}
return `${s__('GeoNodes|Selective')} (${this.selectiveSyncType})`;
// Renaming namespaces to groups in the UI for Geo Selective Sync
const syncLabel =
this.selectiveSyncType === 'namespaces' ? __('groups') : this.selectiveSyncType;
return sprintf(s__('GeoNodes|Selective (%{syncLabel})'), { syncLabel });
},
eventTimestampEmpty() {
return this.lastEvent.timeStamp === 0 || this.cursorLastEvent.timeStamp === 0;
......@@ -117,7 +121,7 @@ export default {
class="d-flex align-items-center"
data-placement="bottom"
>
<strong>{{ syncType }}</strong>
<strong data-testid="syncType">{{ syncType }}</strong>
<icon name="retry" class="ml-2" />
<span v-if="!eventTimestampEmpty" class="ml-2">
{{ syncStatusEventInfo }}
......
<script>
import { __ } from '~/locale';
import { __, sprintf } from '~/locale';
import GeoNodeHealthStatus from '../geo_node_health_status.vue';
import GeoNodeActions from '../geo_node_actions.vue';
......@@ -45,6 +45,23 @@ export default {
nodeHealthStatus() {
return this.nodeDetails.healthy ? this.nodeDetails.health : this.nodeDetails.healthStatus;
},
selectiveSyncronization() {
const { selectiveSyncType } = this.nodeDetails;
if (selectiveSyncType === 'shards') {
return sprintf(__('Shards (%{shards})'), {
shards: this.node.selectiveSyncShards.join(', '),
});
}
if (selectiveSyncType === 'namespaces') {
return sprintf(__('Groups (%{groups})'), {
groups: this.nodeDetails.namespaces.map(n => n.full_path).join(', '),
});
}
return null;
},
},
};
</script>
......@@ -77,6 +94,12 @@ export default {
{{ nodeVersion }}
</span>
</div>
<div v-if="selectiveSyncronization" class="d-flex flex-column mt-2">
<span class="text-secondary-700">{{ s__('GeoNodes|Selective synchronization') }}</span>
<span data-testid="selectiveSync" class="mt-1 font-weight-bold">
{{ selectiveSyncronization }}
</span>
</div>
<geo-node-health-status :status="nodeHealthStatus" />
</div>
</div>
......
......@@ -56,6 +56,7 @@ export default class GeoNodesStore {
editPath: rawNode.web_edit_url,
geoProjectsUrl: rawNode.web_geo_projects_url,
statusPath: rawNode._links.status,
selectiveSyncShards: rawNode.selective_sync_shards,
};
}
......@@ -151,6 +152,7 @@ export default class GeoNodesStore {
timeStamp: rawNodeDetails.cursor_last_event_timestamp,
},
selectiveSyncType: rawNodeDetails.selective_sync_type,
namespaces: rawNodeDetails.namespaces,
dbReplicationLag: rawNodeDetails.db_replication_lag_seconds,
};
}
......
---
title: Make Geo Selective Sync More Clear from the Node Details view
merge_request: 29596
author:
type: changed
......@@ -23,11 +23,37 @@ const createComponent = (
describe('GeoNodeSyncSettingsComponent', () => {
describe('computed', () => {
describe('syncType', () => {
it('returns string representing sync type', () => {
const vm = createComponent();
let vm;
describe('when syncType is namespaces', () => {
beforeEach(() => {
vm = createComponent(false, 'namespaces');
});
afterEach(() => {
vm.$destroy();
});
it('renders the correct sync title', () => {
expect(vm.$el.querySelector('[data-testid="syncType"]').innerText.trim()).toBe(
'Selective (groups)',
);
});
});
expect(vm.syncType).toBe('Selective (namespaces)');
vm.$destroy();
describe('when syncType is shards', () => {
beforeEach(() => {
vm = createComponent(false, 'shards');
});
afterEach(() => {
vm.$destroy();
});
it('renders the correct sync title', () => {
expect(vm.$el.querySelector('[data-testid="syncType"]').innerText.trim()).toBe(
'Selective (shards)',
);
});
});
});
......@@ -35,7 +61,7 @@ describe('GeoNodeSyncSettingsComponent', () => {
it('returns `true` if one of the event timestamp is empty', () => {
const vmEmptyTimestamp = createComponent(
false,
mockNodeDetails.namespaces,
mockNodeDetails.selectiveSyncType,
{
id: 0,
timeStamp: 0,
......
......@@ -71,6 +71,51 @@ describe('NodeDetailsSectionMain', () => {
.catch(done.fail);
});
});
describe('selectiveSyncronization', () => {
describe('when selectiveSyncronization is not enabled', () => {
beforeEach(() => {
vm = createComponent({ nodeDetails: { ...mockNodeDetails, selectiveSyncType: null } });
});
it('does not render selective sync information', () => {
expect(vm.$el.querySelector('[data-testid="selectiveSync"]')).toBeFalsy();
});
});
describe('when selectiveSyncronization is shards', () => {
beforeEach(() => {
vm = createComponent({
node: { ...mockNode, selectiveSyncShards: ['default', 'extra'] },
nodeDetails: { ...mockNodeDetails, selectiveSyncType: 'shards' },
});
});
it('renders Shards information correctly', () => {
expect(vm.$el.querySelector('[data-testid="selectiveSync"]').innerText.trim()).toBe(
'Shards (default, extra)',
);
});
});
describe('when selectiveSyncronization is namespaces', () => {
beforeEach(() => {
vm = createComponent({
nodeDetails: {
...mockNodeDetails,
selectiveSyncType: 'namespaces',
namespaces: [{ full_path: 'gitlab-org' }, { full_path: 'gitlab-com' }],
},
});
});
it('renders Groups information correctly', () => {
expect(vm.$el.querySelector('[data-testid="selectiveSync"]').innerText.trim()).toBe(
'Groups (gitlab-org, gitlab-com)',
);
});
});
});
});
describe('template', () => {
......
......@@ -46,7 +46,6 @@ describe('NodeDetailsSectionSync', () => {
return wrapper.vm.$nextTick(() => {
const syncSettings = wrapper.vm.syncSettings();
expect(syncSettings.syncStatusUnavailable).toBe(true);
expect(syncSettings.namespaces).toBe(mockNodeDetails.namespaces);
expect(syncSettings.lastEvent).toBe(mockNodeDetails.lastEvent);
expect(syncSettings.cursorLastEvent).toBe(mockNodeDetails.cursorLastEvent);
});
......
......@@ -19,6 +19,7 @@ export const mockNodes = [
verification_max_capacity: 100,
clone_protocol: 'http',
web_edit_url: 'http://127.0.0.1:3001/admin/geo/nodes/1/edit',
selective_sync_shards: [],
_links: {
self: 'http://127.0.0.1:3001/api/v4/geo_nodes/1',
repair: 'http://127.0.0.1:3001/api/v4/geo_nodes/1/repair',
......@@ -39,6 +40,7 @@ export const mockNodes = [
sync_object_storage: true,
clone_protocol: 'http',
web_edit_url: 'http://127.0.0.1:3001/admin/geo/nodes/1/edit',
selective_sync_shards: [],
_links: {
self: 'http://127.0.0.1:3001/api/v4/geo_nodes/2',
repair: 'http://127.0.0.1:3001/api/v4/geo_nodes/2/repair',
......@@ -61,6 +63,7 @@ export const mockNode = {
repairPath: 'http://127.0.0.1:3001/api/v4/geo_nodes/1/repair',
statusPath: 'http://127.0.0.1:3001/api/v4/geo_nodes/1/status',
editPath: 'http://127.0.0.1:3001/admin/geo/nodes/1/edit',
selective_sync_shards: [],
};
export const rawMockNodeDetails = {
......@@ -239,5 +242,6 @@ export const mockNodeDetails = {
timeStamp: 1511255200,
},
selectiveSyncType: 'namespaces',
namespaces: [],
dbReplicationLag: 0,
};
......@@ -9509,7 +9509,10 @@ msgstr ""
msgid "GeoNodes|Repository verification progress"
msgstr ""
msgid "GeoNodes|Selective"
msgid "GeoNodes|Selective (%{syncLabel})"
msgstr ""
msgid "GeoNodes|Selective synchronization"
msgstr ""
msgid "GeoNodes|Something went wrong while changing node status"
......@@ -10538,6 +10541,9 @@ msgstr ""
msgid "Groups (%{count})"
msgstr ""
msgid "Groups (%{groups})"
msgstr ""
msgid "Groups can also be nested by creating %{subgroup_docs_link_start}subgroups%{subgroup_docs_link_end}."
msgstr ""
......@@ -18657,6 +18663,9 @@ msgstr ""
msgid "Severity: %{severity}"
msgstr ""
msgid "Shards (%{shards})"
msgstr ""
msgid "Shards to synchronize"
msgstr ""
......@@ -24641,6 +24650,9 @@ msgstr ""
msgid "group"
msgstr ""
msgid "groups"
msgstr ""
msgid "has already been linked to another vulnerability"
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