diff --git a/kolibri/core/assets/src/views/sync/ConfirmationRegisterModal.vue b/kolibri/core/assets/src/views/sync/ConfirmationRegisterModal.vue
index 753252df6bb..8017003c5ad 100644
--- a/kolibri/core/assets/src/views/sync/ConfirmationRegisterModal.vue
+++ b/kolibri/core/assets/src/views/sync/ConfirmationRegisterModal.vue
@@ -5,7 +5,7 @@
:submitText="registerText"
:cancelText="cancelText"
@submit="registerFacility"
- @cancel="$emit('cancel')"
+ @cancel="cancel"
>
{{ $tr('registerWith', { name: projectName }) }}
@@ -44,6 +44,15 @@
type: String,
required: true,
},
+ /**
+ * Whether or not the modal should emit a success event
+ * after the facility has been discovered to be already registered.
+ */
+ successOnAlreadyRegistered: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -90,6 +99,13 @@
}
});
},
+ cancel() {
+ if (this.alreadyRegistered && this.successOnAlreadyRegistered) {
+ this.$emit('success', this.targetFacility);
+ } else {
+ this.$emit('cancel');
+ }
+ },
},
$trs: {
registerFacility: {
diff --git a/kolibri/core/assets/src/views/sync/FacilityNameAndSyncStatus/index.vue b/kolibri/core/assets/src/views/sync/FacilityNameAndSyncStatus/index.vue
index b47c1cdd676..b2988839477 100644
--- a/kolibri/core/assets/src/views/sync/FacilityNameAndSyncStatus/index.vue
+++ b/kolibri/core/assets/src/views/sync/FacilityNameAndSyncStatus/index.vue
@@ -63,6 +63,7 @@
diff --git a/kolibri/core/assets/src/views/sync/SyncFacilityModalGroup.vue b/kolibri/core/assets/src/views/sync/SyncFacilityModalGroup.vue
index b75514d5ee0..727c4c0bcdf 100644
--- a/kolibri/core/assets/src/views/sync/SyncFacilityModalGroup.vue
+++ b/kolibri/core/assets/src/views/sync/SyncFacilityModalGroup.vue
@@ -15,6 +15,23 @@
@submit="handleAddressSubmit"
@cancel="closeModal()"
/>
+
+
+
@@ -26,15 +43,21 @@
import commonSyncElements from 'kolibri.coreVue.mixins.commonSyncElements';
import SelectDeviceModalGroup from './SelectDeviceModalGroup';
import SelectSyncSourceModal from './SelectSyncSourceModal';
+ import RegisterFacilityModal from './RegisterFacilityModal';
+ import ConfirmationRegisterModal from './ConfirmationRegisterModal';
const Steps = Object.freeze({
SELECT_SOURCE: 'SELECT_SOURCE',
SELECT_ADDRESS: 'SELECT_ADDRESS',
+ REGISTER_FACILITY: 'REGISTER_FACILITY',
+ CONFIRMATION_REGISTER: 'CONFIRMATION_REGISTER',
});
export default {
name: 'SyncFacilityModalGroup',
components: {
+ ConfirmationRegisterModal,
+ RegisterFacilityModal,
SelectSyncSourceModal,
SelectDeviceModalGroup,
},
@@ -49,18 +72,24 @@
},
data() {
return {
- step: null,
+ step: Steps.SELECT_SOURCE,
syncSubmitDisabled: false,
- displaySkipOption: true,
+ kdpProject: null, // { name, token }
};
},
computed: {
atSelectSource() {
- return !this.step;
+ return this.step === Steps.SELECT_SOURCE;
},
atSelectAddress() {
return this.step === Steps.SELECT_ADDRESS;
},
+ atRegister() {
+ return this.step === Steps.REGISTER_FACILITY;
+ },
+ atConfirmation() {
+ return this.step === Steps.CONFIRMATION_REGISTER;
+ },
},
methods: {
handleSourceSubmit(data) {
@@ -68,9 +97,9 @@
this.step = Steps.SELECT_ADDRESS;
} else {
if (this.facilityForSync.dataset.registered) {
- this.$emit('syncKDP', this.facilityForSync);
+ this.emitKdpSync();
} else {
- this.$emit('register', this.displaySkipOption, this.facilityForSync);
+ this.step = Steps.REGISTER_FACILITY;
}
}
},
@@ -80,9 +109,16 @@
}
this.$emit('syncPeer', data, this.facilityForSync);
},
+ handleValidateSuccess({ name, token }) {
+ this.kdpProject = { name, token };
+ this.step = Steps.CONFIRMATION_REGISTER;
+ },
closeModal() {
this.$emit('close');
},
+ emitKdpSync() {
+ this.$emit('syncKDP', this.facilityForSync);
+ },
},
};
diff --git a/kolibri/plugins/device/assets/src/views/FacilitiesPage/FacilitiesTasksPage.vue b/kolibri/plugins/device/assets/src/views/FacilitiesPage/FacilitiesTasksPage.vue
index fddbe2a9f36..ffca0caee51 100644
--- a/kolibri/plugins/device/assets/src/views/FacilitiesPage/FacilitiesTasksPage.vue
+++ b/kolibri/plugins/device/assets/src/views/FacilitiesPage/FacilitiesTasksPage.vue
@@ -22,7 +22,7 @@
task.clearable));
+ return Boolean(this.activeFacilityTasks.find(task => task.clearable));
},
},
methods: {
diff --git a/kolibri/plugins/device/assets/src/views/FacilitiesPage/facilityTasksQueue.js b/kolibri/plugins/device/assets/src/views/FacilitiesPage/facilityTasksQueue.js
index 85b35acbb3b..52c29817de8 100644
--- a/kolibri/plugins/device/assets/src/views/FacilitiesPage/facilityTasksQueue.js
+++ b/kolibri/plugins/device/assets/src/views/FacilitiesPage/facilityTasksQueue.js
@@ -1,7 +1,7 @@
// Mixin that can be used for a component to view and manage
// the task queue
import { TaskResource } from 'kolibri.resources';
-import { TaskTypes } from 'kolibri.utils.syncTaskUtils';
+import { TaskStatuses, TaskTypes } from 'kolibri.utils.syncTaskUtils';
function isSyncTask(task) {
return task.type === TaskTypes.SYNCDATAPORTAL || task.type === TaskTypes.SYNCPEERFULL;
@@ -11,6 +11,13 @@ function taskFacilityMatch(task, facility) {
return task.facility_id === facility.id;
}
+function isActiveTask(task) {
+ // Helper function filter tasks by whether they are 'active'
+ // i.e. has a user just queued a non-repeating task, or is a repeating task
+ // that is currently running.
+ return task.repeat !== null || task.status === TaskStatuses.RUNNING;
+}
+
export default {
data() {
return {
@@ -41,10 +48,15 @@ export default {
this.isPolling = false;
},
computed: {
+ activeFacilityTasks() {
+ return this.facilityTasks.filter(isActiveTask);
+ },
facilityIsSyncing() {
return function isSyncing(facility) {
- const syncTasks = this.facilityTasks.filter(t => isSyncTask(t) && !t.clearable);
- return Boolean(syncTasks.find(task => taskFacilityMatch(task, facility)));
+ const inProcessSyncTasks = this.activeFacilityTasks.filter(
+ t => isSyncTask(t) && !t.clearable
+ );
+ return Boolean(inProcessSyncTasks.find(task => taskFacilityMatch(task, facility)));
};
},
facilityIsDeleting() {
diff --git a/kolibri/plugins/device/assets/src/views/FacilitiesPage/index.vue b/kolibri/plugins/device/assets/src/views/FacilitiesPage/index.vue
index ec932c4c157..be425f654aa 100644
--- a/kolibri/plugins/device/assets/src/views/FacilitiesPage/index.vue
+++ b/kolibri/plugins/device/assets/src/views/FacilitiesPage/index.vue
@@ -27,8 +27,8 @@
@@ -153,7 +153,7 @@
@@ -246,8 +245,6 @@
facilityForRegister: null,
kdpProject: null, // { name, token }
taskIdsToWatch: [],
- displaySkipOption: false,
- // (facilityTaskQueue) facilityTasks
};
},
computed: {
@@ -306,7 +303,6 @@
if (option === Options.REMOVE) {
this.facilityForRemoval = facility;
} else if (option === Options.REGISTER) {
- this.displaySkipOption = false;
this.facilityForRegister = facility;
} else if (option === Options.MANAGESYNC) {
const route = this.manageSync(facility.id);
@@ -367,11 +363,6 @@
this.taskIdsToWatch.push(taskId);
this.facilityForRemoval = null;
},
- handleRegister(displaySkipOption, facility) {
- this.displaySkipOption = displaySkipOption;
- this.facilityForRegister = facility;
- this.facilityForSync = null;
- },
handleKDPSync(facility) {
this.facilityForSync = null;
this.facilityForRegister = null;
diff --git a/kolibri/plugins/facility/assets/src/routes.js b/kolibri/plugins/facility/assets/src/routes.js
index 50103aaa6ca..b0e5ce96892 100644
--- a/kolibri/plugins/facility/assets/src/routes.js
+++ b/kolibri/plugins/facility/assets/src/routes.js
@@ -157,7 +157,10 @@ export default [
const facilityId = route.params.facility_id || store.getters.currentFacilityId;
return {
facilityId,
- goBackRoute: { name: PageNames.DATA_EXPORT_PAGE },
+ goBackRoute: {
+ name: PageNames.DATA_EXPORT_PAGE,
+ params: { facility_id: route.params.facility_id },
+ },
editSyncRoute: function(deviceId) {
return {
name: SyncPageNames.EDIT_SYNC_SCHEDULE,
@@ -180,7 +183,10 @@ export default [
return {
facilityId: route.params.facility_id || store.getters.currentFacilityId,
deviceId: route.params.deviceId,
- goBackRoute: { name: SyncPageNames.MANAGE_SYNC_SCHEDULE },
+ goBackRoute: {
+ name: SyncPageNames.MANAGE_SYNC_SCHEDULE,
+ params: { facility_id: route.params.facility_id },
+ },
};
},
},
diff --git a/kolibri/plugins/facility/assets/src/views/DataPage/SyncInterface/index.vue b/kolibri/plugins/facility/assets/src/views/DataPage/SyncInterface/index.vue
index cc94ff516f0..85cf7ccced1 100644
--- a/kolibri/plugins/facility/assets/src/views/DataPage/SyncInterface/index.vue
+++ b/kolibri/plugins/facility/assets/src/views/DataPage/SyncInterface/index.vue
@@ -84,7 +84,7 @@
@@ -169,7 +168,6 @@
syncHasFailed: false,
Modals,
isMenuOpen: false,
- displaySkipOption: false,
};
},
computed: {
@@ -265,9 +263,8 @@
handleSyncFacilityFailure() {
this.syncHasFailed = true;
},
- handleRegister(displaySkipOption) {
+ handleRegister() {
this.closeMenu();
- this.displaySkipOption = Boolean(displaySkipOption);
this.displayModal(Modals.REGISTER_FACILITY);
},
handleKDPSync() {
diff --git a/packages/kolibri-common/components/SyncSchedule/EditDeviceSyncSchedule.vue b/packages/kolibri-common/components/SyncSchedule/EditDeviceSyncSchedule.vue
index 6c4363283d2..78a7ff366d5 100644
--- a/packages/kolibri-common/components/SyncSchedule/EditDeviceSyncSchedule.vue
+++ b/packages/kolibri-common/components/SyncSchedule/EditDeviceSyncSchedule.vue
@@ -28,6 +28,7 @@
-
+
{{ $tr('serverTime') }}
- {{ now }}
+ {{
+ $formatTime(now, {
+ year: "numeric",
+ month: "numeric",
+ day: "numeric",
+ hour: "numeric",
+ minute: "numeric",
+ second: "numeric",
+ })
+ }}
-
+
{{ $tr('checkboxLabel') }}
@@ -134,10 +148,7 @@
:layout12="{ span: 12 }"
>
{{ $tr('removeDeviceWarning') }}
-
-
-
-
+
{{ $tr('deviceNotConnected') }}
@@ -152,10 +163,38 @@
import ImmersivePage from 'kolibri.coreVue.components.ImmersivePage';
import BottomAppBar from 'kolibri.coreVue.components.BottomAppBar';
- import { NetworkLocationResource, FacilityResource, TaskResource } from 'kolibri.resources';
+ import { NetworkLocationResource, TaskResource } from 'kolibri.resources';
import { now } from 'kolibri.utils.serverClock';
import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings';
- import { TaskTypes } from 'kolibri.utils.syncTaskUtils';
+ import { TaskStatuses, TaskTypes } from 'kolibri.utils.syncTaskUtils';
+ import { KDP_ID, oneHour, oneDay, oneWeek, twoWeeks, oneMonth } from './constants';
+ import { kdpNameTranslator } from './i18n';
+
+ const today = new Date();
+ const daysOfWeek = [];
+ const date = new Date(
+ today.getFullYear(),
+ today.getMonth(),
+ today.getDate() + (7 - today.getDay())
+ );
+ for (let i = 0; i < 7; i++) {
+ daysOfWeek.push({ value: i, date: new Date(date) });
+ date.setDate(date.getDate() + 1);
+ }
+
+ const endTime = new Date();
+ endTime.setHours(24, 0, 0, 0);
+ const interval = 30;
+
+ const times = [];
+ var i = 0;
+ const time = new Date();
+ time.setHours(0, 0, 0, 0);
+
+ while (time < endTime) {
+ times.push({ value: i++, time: new Date(time) });
+ time.setMinutes(time.getMinutes() + interval);
+ }
export default {
name: 'EditDeviceSyncSchedule',
@@ -185,16 +224,13 @@
data() {
return {
removeDeviceModal: false,
- deviceName: null,
- device: [],
- now: now(),
+ retryFlag: false,
+ device: null,
+ now: null,
selectedItem: {},
tasks: [],
selectedDay: {},
selectedTime: {},
- removeBtn: false,
- serverTime: null,
- baseurl: null,
};
},
computed: {
@@ -217,55 +253,79 @@
},
selectArray() {
return [
- { label: this.$tr('everyHour'), value: 3600 },
- { label: this.$tr('everyDay'), value: 86400 },
- { label: this.$tr('everyWeek'), value: 604800 },
- { label: this.$tr('everyTwoWeeks'), value: 1209600 },
- { label: this.$tr('everyMonth'), value: 2592000 },
+ { label: this.$tr('everyHour'), value: oneHour },
+ { label: this.$tr('everyDay'), value: oneDay },
+ { label: this.$tr('everyWeek'), value: oneWeek },
+ { label: this.$tr('everyTwoWeeks'), value: twoWeeks },
+ { label: this.$tr('everyMonth'), value: oneMonth },
];
},
getDays() {
- const today = new Date();
- const daysOfWeek = [];
- const date = new Date(
- today.getFullYear(),
- today.getMonth(),
- today.getDate() + (7 - today.getDay())
- );
- for (let i = 0; i < 7; i++) {
- daysOfWeek.push({ label: this.$formatDate(date, { weekday: 'long' }), value: i });
- date.setDate(date.getDate() + 1);
- }
- return daysOfWeek;
+ return daysOfWeek.map(day => {
+ return {
+ label: this.$formatDate(day.date, { weekday: 'long' }),
+ value: day.value,
+ };
+ });
},
SyncTime() {
- const endTime = new Date();
- endTime.setHours(24, 0, 0, 0);
- const interval = 30;
-
- const times = [];
- var i = 0;
- const time = new Date();
- time.setHours(0, 0, 0, 0);
-
- while (time < endTime) {
- times.push({ label: this.$formatTime(time), value: i++ });
- time.setMinutes(time.getMinutes() + interval);
- }
- return times;
+ return times.map(time => {
+ return {
+ label: this.$formatTime(time.time),
+ value: time.value,
+ hours: time.time.getHours(),
+ minutes: time.time.getMinutes(),
+ };
+ });
+ },
+ deviceName() {
+ return this.device && this.device.nickname && this.device.nickname.length
+ ? this.device.nickname
+ : this.device.device_name;
+ },
+ currentTask() {
+ return this.tasks && this.tasks.length ? this.tasks[0] : null;
+ },
+ currentTaskRunning() {
+ return this.currentTask && this.currentTask.status === TaskStatuses.RUNNING;
+ },
+ timeRequired() {
+ return this.selectedItem.value > oneHour;
+ },
+ timeIsSet() {
+ return this.selectedTime && times[this.selectedTime.value];
+ },
+ dayRequired() {
+ return this.selectedItem.value > oneDay;
+ },
+ dayIsSet() {
+ return this.selectedDay && daysOfWeek[this.selectedDay.value];
+ },
+ isKdp() {
+ return this.deviceId === KDP_ID;
+ },
+ taskType() {
+ return this.isKdp ? TaskTypes.SYNCDATAPORTAL : TaskTypes.SYNCPEERFULL;
+ },
+ saveDisabled() {
+ return (
+ this.currentTaskRunning ||
+ (!this.timeIsSet && this.timeRequired) ||
+ (!this.dayIsSet && this.dayRequired) ||
+ !this.selectedItem.value
+ );
},
},
- beforeMount() {
+ created() {
this.fetchDevice();
- },
- mounted() {
- this.serverTime = setInterval(() => {
+ this.now = now();
+ this.serverTimeInterval = setInterval(() => {
this.now = now();
}, 10000);
},
beforeDestroy() {
- clearInterval(this.serverTime);
+ clearInterval(this.serverTimeInterval);
},
methods: {
closeModal() {
@@ -273,57 +333,154 @@
},
handleDeleteDevice() {
this.removeDeviceModal = false;
- NetworkLocationResource.deleteModel({ id: this.deviceId })
+ TaskResource.deleteModel({ id: this.currentTask.id })
.then(() => {
this.showSnackbarNotification('deviceRemove');
- history.back();
+ this.goBack();
})
.catch(() => {
this.showSnackbarNotification('deviceNotRemove');
});
},
+ computeNextSync() {
+ const date = new Date(this.now);
+ if (this.timeRequired) {
+ if (!this.timeIsSet) {
+ throw new ReferenceError('Time is not set and is required');
+ }
+ const hours = this.selectedTime.hours;
+ const minutes = this.selectedTime.minutes;
+ if (
+ hours < date.getHours() ||
+ (hours === date.getHours() && minutes < date.getMinutes())
+ ) {
+ date.setDate(date.getDate() + 1);
+ }
+ date.setHours(hours);
+ date.setMinutes(minutes);
+ }
+ if (this.dayRequired) {
+ if (!this.dayIsSet) {
+ throw new ReferenceError('Day is not set and is required');
+ }
+ const diff = this.selectedDay.value - date.getDay();
+ if (date.getDay() > this.selectedDay.value) {
+ date.setDate(date.getDate() + 7 - Math.abs(diff));
+ } else if (date.getDay() < this.selectedDay.value) {
+ date.setDate(date.getDate() + Math.abs(diff));
+ }
+ }
+ return date;
+ },
handleSaveSchedule() {
- FacilityResource.fetchModel({ id: this.facilityId, force: true }).then(facility => {
- this.facility = { ...facility };
- const date = new Date(this.serverTime);
- const equeue_param = date.toISOString();
- TaskResource.startTask({
- type: TaskTypes.SYNCPEERFULL,
- facility: this.facility.id,
- device_id: this.deviceId,
- baseurl: this.baseurl,
- enqueue_args: {
- enqueue_at: equeue_param,
- repeat_interval: this.selectedItem.value,
- repeat: 2,
- },
+ const enqueue_param = this.computeNextSync().toISOString();
+ const enqueue_args = {
+ enqueue_at: enqueue_param,
+ repeat_interval: this.selectedItem.value,
+ repeat: null,
+ retry_interval: this.retryFlag ? 60 * 5 : null,
+ };
+ let promise;
+ if (this.currentTask) {
+ promise = TaskResource.saveModel({
+ id: this.currentTask.id,
+ data: { enqueue_args },
+ exists: true,
+ });
+ } else {
+ const taskParams = {
+ type: this.taskType,
+ facility: this.facilityId,
+ enqueue_args,
+ };
+ if (!this.isKdp) {
+ taskParams.device_id = this.deviceId;
+ taskParams.baseurl = this.device.base_url;
+ }
+ promise = TaskResource.startTask(taskParams);
+ }
+ promise
+ .then(() => {
+ this.goBack();
+ this.showSnackbarNotification('syncAdded');
})
- .then(() => {
- history.back();
- this.showSnackbarNotification('syncAdded');
- })
- .catch(() => {
- this.createTaskFailedSnackbar();
- });
- });
+ .catch(() => {
+ this.createTaskFailedSnackbar();
+ if (this.currentTask) {
+ this.fetchSyncTasks();
+ }
+ });
},
- cancelBtn() {
+ goBack() {
this.$router.push(this.goBackRoute);
},
+ pollFetchSyncTasks() {
+ this.pollInterval = setInterval(() => {
+ this.fetchSyncTasks();
+ }, 10000);
+ },
+ fetchSyncTasks() {
+ TaskResource.list({ queue: 'facility_task' }).then(tasks => {
+ this.tasks = tasks.filter(
+ task =>
+ (this.isKdp || task.extra_metadata.device_id === this.device.id) &&
+ task.facility_id === this.facilityId &&
+ task.type === this.taskType &&
+ // Only show tasks that are repeating indefinitely
+ task.repeat === null
+ );
+ this.$nextTick(() => {
+ if (this.currentTask) {
+ const enqueueAt = new Date(Date.parse(this.currentTask.scheduled_datetime));
+ const day = enqueueAt.getDay();
+ const hours = enqueueAt.getHours();
+ const minutes = enqueueAt.getMinutes();
+ this.selectedItem =
+ this.selectArray.find(item => item.value === this.currentTask.repeat_interval) ||
+ {};
+ this.selectedDay = this.getDays.find(item => item.value === day) || {};
+ for (const time of this.SyncTime) {
+ // Because there can be some drift in the task scheduling process,
+ // we round the 'scheduled' time to the nearest 30 minutes
+ if (
+ time.minutes === 0 &&
+ ((time.hours === hours && minutes < 15) ||
+ (time.hours === hours + 1 && minutes >= 45))
+ ) {
+ this.selectedTime = time;
+ break;
+ }
+ if (time.minutes === 30 && time.hours === hours && minutes >= 15 && minutes < 45) {
+ this.selectedTime = time;
+ break;
+ }
+ }
+ this.retryFlag = Boolean(this.currentTask.retry_interval);
+ if (this.currentTaskRunning) {
+ this.pollFetchSyncTasks();
+ } else {
+ clearInterval(this.pollInterval);
+ this.pollInterval = null;
+ }
+ }
+ });
+ });
+ },
fetchDevice() {
+ if (this.isKdp) {
+ this.device = {
+ id: KDP_ID,
+ // eslint-disable-next-line kolibri/vue-no-undefined-string-uses
+ device_name: kdpNameTranslator.$tr('syncToKDP'),
+ base_url: '',
+ };
+ this.fetchSyncTasks();
+ return;
+ }
NetworkLocationResource.fetchModel({ id: this.deviceId }).then(device => {
this.device = device;
- this.baseurl = device.base_url;
- TaskResource.list({ queue: 'facility_task' }).then(tasks => {
- this.tasks = tasks.filter(
- task =>
- task.extra_metadata.device_id === device.id && task.facility_id === this.facilityId
- );
- if (this.tasks && this.tasks.length) {
- this.removeBtn = true;
- }
- });
+ this.fetchSyncTasks();
});
},
},
diff --git a/packages/kolibri-common/components/SyncSchedule/ManageSyncSchedule.vue b/packages/kolibri-common/components/SyncSchedule/ManageSyncSchedule.vue
index 7b6973c3958..fed92e47c70 100644
--- a/packages/kolibri-common/components/SyncSchedule/ManageSyncSchedule.vue
+++ b/packages/kolibri-common/components/SyncSchedule/ManageSyncSchedule.vue
@@ -40,7 +40,7 @@
-
+
{{ coreString('deviceNameLabel') }} |
{{ $tr('Schedule') }} |
@@ -48,45 +48,35 @@
|
- {{ device.extra_metadata.device_name }}
- {{ device.extra_metadata.baseurl }}
+ {{ task.deviceName }}
+ {{ task.extra_metadata.baseurl }}
|
- {{ scheduleTime(device.repeat_interval, device.scheduled_datetime ) }}
+ {{ scheduleTime(task.repeat_interval, task.scheduled_datetime ) }}
|
-
-
-
-
-
- {{ $tr('connected') }}
-
-
-
- {{ $tr('disconnected') }}
-
-
-
- |
-
-
- {{ $tr('disconnected') }}
+ |
+
+
+ {{ $tr('connected') }}
+
+
+
+ {{ $tr('disconnected') }}
+
+
|
{{ coreString('editAction') }}
@@ -113,77 +103,13 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ btn.base_url }}
-
-
-
-
-
-
-
-
-
-
-
-
-
+ :facilityForSync="facility"
+ @close="closeModal"
+ @syncKDP="handleKDPSync"
+ @syncPeer="handlePeerSync"
+ />
@@ -192,22 +118,52 @@
|