Commit ef1a963e authored by Nick Thomas's avatar Nick Thomas

Frontend for selective sync by shards

parent c5de19b9
...@@ -12,14 +12,25 @@ const onPrimaryCheckboxChange = function onPrimaryCheckboxChange(e, $namespaces) ...@@ -12,14 +12,25 @@ const onPrimaryCheckboxChange = function onPrimaryCheckboxChange(e, $namespaces)
$namespaces.toggleClass('hidden', e.currentTarget.checked); $namespaces.toggleClass('hidden', e.currentTarget.checked);
}; };
const onSelectiveSyncTypeChange = function onSelectiveSyncTypeChange(e, $byNamespaces, $byShards) {
$byNamespaces.toggleClass('hidden', e.target.value !== 'namespaces');
$byShards.toggleClass('hidden', e.target.value !== 'shards');
};
export default function geoNodeForm($container) { export default function geoNodeForm($container) {
const $namespaces = $('.js-hide-if-geo-primary', $container); const $namespaces = $('.js-hide-if-geo-primary', $container);
const $primaryCheckbox = $('input[type="checkbox"]', $container); const $primaryCheckbox = $('input[type="checkbox"]', $container);
const $selectiveSyncTypeSelect = $('.js-geo-node-selective-sync-type', $container);
const $select2Dropdown = $('.js-geo-node-namespaces', $container); const $select2Dropdown = $('.js-geo-node-namespaces', $container);
const $syncByNamespaces = $('.js-sync-by-namespace', $container);
const $syncByShards = $('.js-sync-by-shard', $container);
$primaryCheckbox.on('change', e => $primaryCheckbox.on('change', e =>
onPrimaryCheckboxChange(e, $namespaces)); onPrimaryCheckboxChange(e, $namespaces));
$selectiveSyncTypeSelect.on('change', e =>
onSelectiveSyncTypeChange(e, $syncByNamespaces, $syncByShards));
$select2Dropdown.select2({ $select2Dropdown.select2({
placeholder: s__('Geo|Select groups to replicate.'), placeholder: s__('Geo|Select groups to replicate.'),
multiple: true, multiple: true,
......
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
/> />
<geo-node-sync-settings <geo-node-sync-settings
v-else-if="isCustomTypeSync" v-else-if="isCustomTypeSync"
:namespaces="itemValue.namespaces" :selective-sync-type="itemValue.selectiveSyncType"
:last-event="itemValue.lastEvent" :last-event="itemValue.lastEvent"
:cursor-last-event="itemValue.cursorLastEvent" :cursor-last-event="itemValue.cursorLastEvent"
/> />
......
...@@ -150,7 +150,7 @@ ...@@ -150,7 +150,7 @@
}, },
syncSettings() { syncSettings() {
return { return {
namespaces: this.nodeDetails.namespaces, selectiveSyncType: this.nodeDetails.selectiveSyncType,
lastEvent: this.nodeDetails.lastEvent, lastEvent: this.nodeDetails.lastEvent,
cursorLastEvent: this.nodeDetails.cursorLastEvent, cursorLastEvent: this.nodeDetails.cursorLastEvent,
}; };
......
...@@ -14,9 +14,10 @@ ...@@ -14,9 +14,10 @@
icon, icon,
}, },
props: { props: {
namespaces: { selectiveSyncType: {
type: Array, type: String,
required: true, required: false,
default: null,
}, },
lastEvent: { lastEvent: {
type: Object, type: Object,
...@@ -30,7 +31,11 @@ ...@@ -30,7 +31,11 @@
computed: { computed: {
syncType() { syncType() {
return this.namespaces.length > 0 ? s__('GeoNodes|Selective') : s__('GeoNodes|Full'); if (this.selectiveSyncType === null || this.selectiveSyncType === '') {
return s__('GeoNodes|Full');
}
return s__('GeoNodes|Selective');
}, },
eventTimestampEmpty() { eventTimestampEmpty() {
return this.lastEvent.timeStamp === 0 || this.cursorLastEvent.timeStamp === 0; return this.lastEvent.timeStamp === 0 || this.cursorLastEvent.timeStamp === 0;
......
...@@ -81,7 +81,7 @@ export default class GeoNodesStore { ...@@ -81,7 +81,7 @@ export default class GeoNodesStore {
id: rawNodeDetails.cursor_last_event_id || 0, id: rawNodeDetails.cursor_last_event_id || 0,
timeStamp: rawNodeDetails.cursor_last_event_timestamp, timeStamp: rawNodeDetails.cursor_last_event_timestamp,
}, },
namespaces: rawNodeDetails.namespaces, selectiveSyncType: rawNodeDetails.selective_sync_type,
dbReplicationLag: rawNodeDetails.db_replication_lag_seconds, dbReplicationLag: rawNodeDetails.db_replication_lag_seconds,
}; };
} }
......
...@@ -87,6 +87,8 @@ class Admin::GeoNodesController < Admin::ApplicationController ...@@ -87,6 +87,8 @@ class Admin::GeoNodesController < Admin::ApplicationController
params.require(:geo_node).permit( params.require(:geo_node).permit(
:url, :url,
:primary, :primary,
:selective_sync_type,
:selective_sync_shards,
:namespace_ids, :namespace_ids,
:repos_max_capacity, :repos_max_capacity,
:files_max_capacity :files_max_capacity
......
...@@ -19,6 +19,17 @@ module EE ...@@ -19,6 +19,17 @@ module EE
end end
end end
def selective_sync_type_options_for_select(geo_node)
options_for_select(
[
[s_('Geo|All projects'), ''],
[s_('Geo|Projects in certain groups'), 'namespaces'],
[s_('Geo|Projects in certain storage shards'), 'shards']
],
geo_node.selective_sync_type
)
end
def status_loading_icon def status_loading_icon
icon "spinner spin fw", class: 'js-geo-node-loading' icon "spinner spin fw", class: 'js-geo-node-loading'
end end
......
...@@ -11,12 +11,27 @@ ...@@ -11,12 +11,27 @@
= form.check_box :primary = form.check_box :primary
%strong This is a primary node %strong This is a primary node
.form-group.js-hide-if-geo-primary{ class: ('hidden' unless geo_node.secondary?) } .js-hide-if-geo-primary{ class: ('hidden' unless geo_node.secondary?) }
= form.label :namespace_ids, s_('Geo|Groups to replicate'), class: 'control-label' .form-group
.col-sm-10 = form.label :selective_sync_type, s_('Selective synchronization'), class: 'control-label'
= hidden_field_tag "#{form.object_name}[namespace_ids]", geo_node.namespace_ids.join(","), class: 'js-geo-node-namespaces', data: { selected: node_namespaces_options(geo_node.namespaces).to_json } .col-sm-10
.help-block = form.select :selective_sync_type, selective_sync_type_options_for_select(geo_node),
#{ s_("Choose which groups you wish to replicate to this secondary node. Leave blank to replicate all.") } {}, { class: "form-control js-geo-node-selective-sync-type" }
.form-group.js-sync-by-namespace{ class: ('hidden' unless geo_node.selective_sync_by_namespaces?) }
= form.label :namespace_ids, s_('Geo|Groups to synchronize'), class: 'control-label'
.col-sm-10
= hidden_field_tag "#{form.object_name}[namespace_ids]", geo_node.namespace_ids.join(","), class: 'js-geo-node-namespaces', data: { selected: node_namespaces_options(geo_node.namespaces).to_json }
.help-block
#{ s_("Choose which groups you wish to synchronize to this secondary node.") }
.form-group.js-sync-by-shard{ class: ('hidden' unless geo_node.selective_sync_by_shards?) }
= form.label :selective_sync_shards, s_('Geo|Shards to synchronize'), class: 'control-label'
.col-sm-10
= form.select :selective_sync_shards, repository_storages_options_for_select(geo_node.selective_sync_shards),
{ include_hidden: false }, multiple: true, class: 'form-control'
.help-block
#{ s_("Choose which shards you wish to synchronize to this secondary node.") }
.form-group.js-hide-if-geo-primary{ class: ('hidden' unless geo_node.secondary?) } .form-group.js-hide-if-geo-primary{ class: ('hidden' unless geo_node.secondary?) }
= form.label :repos_max_capacity, s_('Geo|Repository sync capacity'), class: 'control-label' = form.label :repos_max_capacity, s_('Geo|Repository sync capacity'), class: 'control-label'
......
...@@ -6,13 +6,13 @@ import { mockNodeDetails } from '../mock_data'; ...@@ -6,13 +6,13 @@ import { mockNodeDetails } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = ( const createComponent = (
namespaces = mockNodeDetails.namespaces, selectiveSyncType = mockNodeDetails.selectiveSyncType,
lastEvent = mockNodeDetails.lastEvent, lastEvent = mockNodeDetails.lastEvent,
cursorLastEvent = mockNodeDetails.cursorLastEvent) => { cursorLastEvent = mockNodeDetails.cursorLastEvent) => {
const Component = Vue.extend(geoNodeSyncSettingsComponent); const Component = Vue.extend(geoNodeSyncSettingsComponent);
return mountComponent(Component, { return mountComponent(Component, {
namespaces, selectiveSyncType,
lastEvent, lastEvent,
cursorLastEvent, cursorLastEvent,
}); });
......
...@@ -152,31 +152,6 @@ export const mockNodeDetails = { ...@@ -152,31 +152,6 @@ export const mockNodeDetails = {
id: 3, id: 3,
timeStamp: 1511255200, timeStamp: 1511255200,
}, },
namespaces: [ selectiveSyncType: 'namespaces',
{
id: 54,
name: 'platform',
path: 'platform',
kind: 'group',
full_path: 'platform',
parent_id: null,
},
{
id: 4,
name: 'Twitter',
path: 'twitter',
kind: 'group',
full_path: 'twitter',
parent_id: null,
},
{
id: 3,
name: 'Documentcloud',
path: 'documentcloud',
kind: 'group',
full_path: 'documentcloud',
parent_id: null,
},
],
dbReplicationLag: 0, dbReplicationLag: 0,
}; };
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