Commit 38da8c01 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '11165-selective-sync-ui' into 'master'

Make Geo Selective Sync More Clear

Closes #11165

See merge request gitlab-org/gitlab!29596
parents 03160606 2dd8d142
<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,
};
......@@ -9605,7 +9605,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"
......@@ -10634,6 +10637,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 ""
......@@ -18804,6 +18810,9 @@ msgstr ""
msgid "Severity: %{severity}"
msgstr ""
msgid "Shards (%{shards})"
msgstr ""
msgid "Shards to synchronize"
msgstr ""
......@@ -24848,6 +24857,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