@plutonhq/core-frontend 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/@types/backups.d.ts +26 -0
- package/dist-lib/@types/backups.d.ts.map +1 -1
- package/dist-lib/@types/devices.d.ts +7 -0
- package/dist-lib/@types/devices.d.ts.map +1 -1
- package/dist-lib/@types/plans.d.ts +21 -1
- package/dist-lib/@types/plans.d.ts.map +1 -1
- package/dist-lib/@types/restores.d.ts +2 -0
- package/dist-lib/@types/restores.d.ts.map +1 -1
- package/dist-lib/components/Device/DeviceBackups/DeviceBackups.d.ts +3 -2
- package/dist-lib/components/Device/DeviceBackups/DeviceBackups.d.ts.map +1 -1
- package/dist-lib/components/Device/DeviceBackups/DeviceBackups.js +73 -85
- package/dist-lib/components/Device/DeviceBackups/DeviceBackups.js.map +1 -1
- package/dist-lib/components/Plan/BackupEvents/BackupEvents.d.ts.map +1 -1
- package/dist-lib/components/Plan/BackupEvents/BackupEvents.js +88 -50
- package/dist-lib/components/Plan/BackupEvents/BackupEvents.js.map +1 -1
- package/dist-lib/components/Plan/BackupEvents/BackupEvents.module.scss.js +70 -38
- package/dist-lib/components/Plan/BackupEvents/BackupEvents.module.scss.js.map +1 -1
- package/dist-lib/components/Plan/BackupProgress/BackupProgress.d.ts.map +1 -1
- package/dist-lib/components/Plan/BackupProgress/BackupProgress.js +166 -123
- package/dist-lib/components/Plan/BackupProgress/BackupProgress.js.map +1 -1
- package/dist-lib/components/Plan/BackupProgress/BackupProgress.module.scss.js +64 -30
- package/dist-lib/components/Plan/BackupProgress/BackupProgress.module.scss.js.map +1 -1
- package/dist-lib/components/Plan/Backups/Backups.d.ts +8 -1
- package/dist-lib/components/Plan/Backups/Backups.d.ts.map +1 -1
- package/dist-lib/components/Plan/Backups/Backups.js +154 -125
- package/dist-lib/components/Plan/Backups/Backups.js.map +1 -1
- package/dist-lib/components/Plan/EditPlan/EditPlan.d.ts.map +1 -1
- package/dist-lib/components/Plan/EditPlan/EditPlan.js +11 -10
- package/dist-lib/components/Plan/EditPlan/EditPlan.js.map +1 -1
- package/dist-lib/components/Plan/Mirrors/MirrorDetails.d.ts +12 -0
- package/dist-lib/components/Plan/Mirrors/MirrorDetails.d.ts.map +1 -0
- package/dist-lib/components/Plan/Mirrors/MirrorDetails.js +68 -0
- package/dist-lib/components/Plan/Mirrors/MirrorDetails.js.map +1 -0
- package/dist-lib/components/Plan/Mirrors/MirrorDetails.module.scss.js +26 -0
- package/dist-lib/components/Plan/Mirrors/MirrorDetails.module.scss.js.map +1 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStatusBadge.d.ts +11 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStatusBadge.d.ts.map +1 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStatusBadge.js +38 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStatusBadge.js.map +1 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStatusBadge.module.scss.js +16 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStatusBadge.module.scss.js.map +1 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStorageSelector.d.ts +14 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStorageSelector.d.ts.map +1 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStorageSelector.js +54 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStorageSelector.js.map +1 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStorageSelector.module.scss.js +26 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStorageSelector.module.scss.js.map +1 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStorageSelectorModal.d.ts +15 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStorageSelectorModal.d.ts.map +1 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStorageSelectorModal.js +34 -0
- package/dist-lib/components/Plan/Mirrors/MirrorStorageSelectorModal.js.map +1 -0
- package/dist-lib/components/Plan/PlanBackups/PlanBackups.d.ts.map +1 -1
- package/dist-lib/components/Plan/PlanBackups/PlanBackups.js +20 -17
- package/dist-lib/components/Plan/PlanBackups/PlanBackups.js.map +1 -1
- package/dist-lib/components/Plan/PlanForm/PlanForm.d.ts +2 -1
- package/dist-lib/components/Plan/PlanForm/PlanForm.d.ts.map +1 -1
- package/dist-lib/components/Plan/PlanForm/PlanForm.js +121 -94
- package/dist-lib/components/Plan/PlanForm/PlanForm.js.map +1 -1
- package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.d.ts +16 -0
- package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.d.ts.map +1 -0
- package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.js +115 -0
- package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.js.map +1 -0
- package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.module.scss.js +26 -0
- package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.module.scss.js.map +1 -0
- package/dist-lib/components/Plan/PlanItems/PlanItem.d.ts.map +1 -1
- package/dist-lib/components/Plan/PlanItems/PlanItem.js +58 -59
- package/dist-lib/components/Plan/PlanItems/PlanItem.js.map +1 -1
- package/dist-lib/components/Plan/PlanPendingBackup/PlanPendingBackup.d.ts +2 -2
- package/dist-lib/components/Plan/PlanPendingBackup/PlanPendingBackup.d.ts.map +1 -1
- package/dist-lib/components/Plan/PlanPendingBackup/PlanPendingBackup.js.map +1 -1
- package/dist-lib/components/Plan/PlanRemoveModal/PlanRemoveModal.js +8 -8
- package/dist-lib/components/Plan/PlanRemoveModal/PlanRemoveModal.js.map +1 -1
- package/dist-lib/components/Plan/PlanSettings/PlanReplicationSettings.d.ts +14 -0
- package/dist-lib/components/Plan/PlanSettings/PlanReplicationSettings.d.ts.map +1 -0
- package/dist-lib/components/Plan/PlanSettings/PlanReplicationSettings.js +290 -0
- package/dist-lib/components/Plan/PlanSettings/PlanReplicationSettings.js.map +1 -0
- package/dist-lib/components/Plan/PlanSettings/PlanReplicationSettings.module.scss.js +26 -0
- package/dist-lib/components/Plan/PlanSettings/PlanReplicationSettings.module.scss.js.map +1 -0
- package/dist-lib/components/Plan/PlanStats/PlanStats.d.ts.map +1 -1
- package/dist-lib/components/Plan/PlanStats/PlanStats.js +41 -42
- package/dist-lib/components/Plan/PlanStats/PlanStats.js.map +1 -1
- package/dist-lib/components/Plan/PlanStats/PlanStats.module.scss.js +5 -5
- package/dist-lib/components/Plan/PlanStorageInfo/PlanStorageInfo.d.ts +15 -0
- package/dist-lib/components/Plan/PlanStorageInfo/PlanStorageInfo.d.ts.map +1 -0
- package/dist-lib/components/Plan/PlanStorageInfo/PlanStorageInfo.js +69 -0
- package/dist-lib/components/Plan/PlanStorageInfo/PlanStorageInfo.js.map +1 -0
- package/dist-lib/components/Plan/PlanStorageInfo/PlanStorageInfo.module.scss.js +16 -0
- package/dist-lib/components/Plan/PlanStorageInfo/PlanStorageInfo.module.scss.js.map +1 -0
- package/dist-lib/components/Restore/RestoreWizard/RestoreConfirmStep.d.ts.map +1 -1
- package/dist-lib/components/Restore/RestoreWizard/RestoreConfirmStep.js +36 -34
- package/dist-lib/components/Restore/RestoreWizard/RestoreConfirmStep.js.map +1 -1
- package/dist-lib/components/Restore/RestoreWizard/RestorePreviewStep.d.ts.map +1 -1
- package/dist-lib/components/Restore/RestoreWizard/RestorePreviewStep.js +7 -5
- package/dist-lib/components/Restore/RestoreWizard/RestorePreviewStep.js.map +1 -1
- package/dist-lib/components/Restore/RestoreWizard/RestoreSettingsStep.d.ts +12 -4
- package/dist-lib/components/Restore/RestoreWizard/RestoreSettingsStep.d.ts.map +1 -1
- package/dist-lib/components/Restore/RestoreWizard/RestoreSettingsStep.js +44 -32
- package/dist-lib/components/Restore/RestoreWizard/RestoreSettingsStep.js.map +1 -1
- package/dist-lib/components/Restore/RestoreWizard/RestoreWizard.d.ts +5 -1
- package/dist-lib/components/Restore/RestoreWizard/RestoreWizard.d.ts.map +1 -1
- package/dist-lib/components/Restore/RestoreWizard/RestoreWizard.js +48 -44
- package/dist-lib/components/Restore/RestoreWizard/RestoreWizard.js.map +1 -1
- package/dist-lib/components/Restore/RestoreWizard/RestoreWizard.module.scss.js +32 -32
- package/dist-lib/components/Settings/GeneralSettings/GeneralSettings.d.ts +1 -1
- package/dist-lib/components/Settings/GeneralSettings/GeneralSettings.d.ts.map +1 -1
- package/dist-lib/components/Settings/GeneralSettings/GeneralSettings.js +52 -24
- package/dist-lib/components/Settings/GeneralSettings/GeneralSettings.js.map +1 -1
- package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.d.ts.map +1 -1
- package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.js +28 -19
- package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.js.map +1 -1
- package/dist-lib/components/Settings/TwoFactorSetup/TwoFactorSetup.d.ts +7 -0
- package/dist-lib/components/Settings/TwoFactorSetup/TwoFactorSetup.d.ts.map +1 -0
- package/dist-lib/components/Settings/TwoFactorSetup/TwoFactorSetup.js +79 -0
- package/dist-lib/components/Settings/TwoFactorSetup/TwoFactorSetup.js.map +1 -0
- package/dist-lib/components/Settings/TwoFactorSetup/TwoFactorSetup.module.scss.js +24 -0
- package/dist-lib/components/Settings/TwoFactorSetup/TwoFactorSetup.module.scss.js.map +1 -0
- package/dist-lib/components/common/Icon/Icon.d.ts.map +1 -1
- package/dist-lib/components/common/Icon/Icon.js +11 -0
- package/dist-lib/components/common/Icon/Icon.js.map +1 -1
- package/dist-lib/components/common/PageHeader/PageHeader.module.scss.js +6 -6
- package/dist-lib/components/index.d.ts +6 -0
- package/dist-lib/components/index.d.ts.map +1 -1
- package/dist-lib/components.js +102 -90
- package/dist-lib/components.js.map +1 -1
- package/dist-lib/hooks/usePwaAutoUpdate.d.ts +11 -2
- package/dist-lib/hooks/usePwaAutoUpdate.d.ts.map +1 -1
- package/dist-lib/hooks/usePwaAutoUpdate.js +32 -10
- package/dist-lib/hooks/usePwaAutoUpdate.js.map +1 -1
- package/dist-lib/router.d.ts.map +1 -1
- package/dist-lib/router.js +46 -35
- package/dist-lib/router.js.map +1 -1
- package/dist-lib/routes/DeviceSingle/DeviceSingle.d.ts.map +1 -1
- package/dist-lib/routes/DeviceSingle/DeviceSingle.js +40 -40
- package/dist-lib/routes/DeviceSingle/DeviceSingle.js.map +1 -1
- package/dist-lib/routes/PlanSingle/PlanSingle.d.ts.map +1 -1
- package/dist-lib/routes/PlanSingle/PlanSingle.js +123 -98
- package/dist-lib/routes/PlanSingle/PlanSingle.js.map +1 -1
- package/dist-lib/services/backups.d.ts +15 -2
- package/dist-lib/services/backups.d.ts.map +1 -1
- package/dist-lib/services/backups.js +119 -100
- package/dist-lib/services/backups.js.map +1 -1
- package/dist-lib/services/plans.d.ts +20 -0
- package/dist-lib/services/plans.d.ts.map +1 -1
- package/dist-lib/services/plans.js +227 -172
- package/dist-lib/services/plans.js.map +1 -1
- package/dist-lib/services/restores.d.ts +10 -2
- package/dist-lib/services/restores.d.ts.map +1 -1
- package/dist-lib/services/restores.js +61 -57
- package/dist-lib/services/restores.js.map +1 -1
- package/dist-lib/services/settings.d.ts +16 -0
- package/dist-lib/services/settings.d.ts.map +1 -1
- package/dist-lib/services/settings.js +147 -68
- package/dist-lib/services/settings.js.map +1 -1
- package/dist-lib/services/users.d.ts.map +1 -1
- package/dist-lib/services/users.js +32 -32
- package/dist-lib/services/users.js.map +1 -1
- package/dist-lib/services.js +113 -101
- package/dist-lib/styles/core-frontend.css +1 -1
- package/dist-lib/utils/progressHelpers.d.ts +12 -1
- package/dist-lib/utils/progressHelpers.d.ts.map +1 -1
- package/dist-lib/utils/progressHelpers.js +121 -63
- package/dist-lib/utils/progressHelpers.js.map +1 -1
- package/dist-lib/utils.js +29 -28
- package/package.json +1 -1
- package/src/@types/backups.ts +28 -0
- package/src/@types/devices.ts +8 -0
- package/src/@types/plans.ts +23 -1
- package/src/@types/restores.ts +2 -0
- package/src/components/Device/DeviceBackups/DeviceBackups.tsx +11 -36
- package/src/components/Plan/BackupEvents/BackupEvents.module.scss +65 -0
- package/src/components/Plan/BackupEvents/BackupEvents.tsx +65 -4
- package/src/components/Plan/BackupProgress/BackupProgress.module.scss +121 -3
- package/src/components/Plan/BackupProgress/BackupProgress.tsx +149 -71
- package/src/components/Plan/Backups/Backups.tsx +52 -4
- package/src/components/Plan/EditPlan/EditPlan.tsx +1 -0
- package/src/components/Plan/Mirrors/MirrorDetails.module.scss +76 -0
- package/src/components/Plan/Mirrors/MirrorDetails.tsx +100 -0
- package/src/components/Plan/Mirrors/MirrorStatusBadge.module.scss +25 -0
- package/src/components/Plan/Mirrors/MirrorStatusBadge.tsx +65 -0
- package/src/components/Plan/Mirrors/MirrorStorageSelector.module.scss +97 -0
- package/src/components/Plan/Mirrors/MirrorStorageSelector.tsx +70 -0
- package/src/components/Plan/Mirrors/MirrorStorageSelectorModal.tsx +40 -0
- package/src/components/Plan/PlanBackups/PlanBackups.tsx +4 -1
- package/src/components/Plan/PlanForm/PlanForm.tsx +44 -17
- package/src/components/Plan/PlanIntegrity/PlanIntegrity.module.scss +110 -0
- package/src/components/Plan/PlanIntegrity/PlanIntegrity.tsx +187 -0
- package/src/components/Plan/PlanItems/PlanItem.tsx +3 -3
- package/src/components/Plan/PlanPendingBackup/PlanPendingBackup.tsx +2 -2
- package/src/components/Plan/PlanRemoveModal/PlanRemoveModal.tsx +1 -1
- package/src/components/Plan/PlanSettings/PlanReplicationSettings.module.scss +105 -0
- package/src/components/Plan/PlanSettings/PlanReplicationSettings.tsx +334 -0
- package/src/components/Plan/PlanStats/PlanStats.module.scss +1 -1
- package/src/components/Plan/PlanStats/PlanStats.tsx +8 -8
- package/src/components/Plan/PlanStorageInfo/PlanStorageInfo.module.scss +43 -0
- package/src/components/Plan/PlanStorageInfo/PlanStorageInfo.tsx +83 -0
- package/src/components/Restore/RestoreWizard/RestoreConfirmStep.tsx +2 -0
- package/src/components/Restore/RestoreWizard/RestorePreviewStep.tsx +2 -0
- package/src/components/Restore/RestoreWizard/RestoreSettingsStep.tsx +36 -13
- package/src/components/Restore/RestoreWizard/RestoreWizard.module.scss +4 -0
- package/src/components/Restore/RestoreWizard/RestoreWizard.tsx +9 -1
- package/src/components/Settings/GeneralSettings/GeneralSettings.tsx +38 -2
- package/src/components/Settings/IntegrationSettings/IntegrationSettings.tsx +9 -2
- package/src/components/Settings/TwoFactorSetup/TwoFactorSetup.module.scss +62 -0
- package/src/components/Settings/TwoFactorSetup/TwoFactorSetup.tsx +102 -0
- package/src/components/common/Icon/Icon.tsx +10 -1
- package/src/components/common/PageHeader/PageHeader.module.scss +3 -0
- package/src/components/index.ts +8 -0
- package/src/hooks/usePwaAutoUpdate.ts +51 -11
- package/src/router.tsx +26 -17
- package/src/routes/DeviceSingle/DeviceSingle.tsx +3 -3
- package/src/routes/PlanSingle/PlanSingle.tsx +21 -0
- package/src/services/backups.ts +32 -9
- package/src/services/plans.ts +75 -0
- package/src/services/restores.ts +10 -2
- package/src/services/settings.ts +90 -0
- package/src/services/users.ts +14 -5
- package/src/utils/progressHelpers.ts +85 -1
package/src/services/plans.ts
CHANGED
|
@@ -392,3 +392,78 @@ export function useCheckActiveBackupsOrRestore() {
|
|
|
392
392
|
// refetchOnMount: true,
|
|
393
393
|
});
|
|
394
394
|
}
|
|
395
|
+
|
|
396
|
+
// Remove Replication Storage
|
|
397
|
+
export async function deleteReplicationStorage({
|
|
398
|
+
planID,
|
|
399
|
+
storageID,
|
|
400
|
+
storagePath,
|
|
401
|
+
removeData,
|
|
402
|
+
replicationId,
|
|
403
|
+
}: {
|
|
404
|
+
planID: string;
|
|
405
|
+
storageID: string;
|
|
406
|
+
storagePath: string;
|
|
407
|
+
removeData: boolean;
|
|
408
|
+
replicationId?: string;
|
|
409
|
+
}) {
|
|
410
|
+
const header = new Headers({ 'Content-Type': 'application/json', Accept: 'application/json' });
|
|
411
|
+
const res = await fetch(`${API_URL}/plans/${planID}/action/delete-replication-storage`, {
|
|
412
|
+
method: 'POST',
|
|
413
|
+
credentials: 'include',
|
|
414
|
+
headers: header,
|
|
415
|
+
body: JSON.stringify({ storageID, storagePath, removeData, replicationId }),
|
|
416
|
+
});
|
|
417
|
+
const data = await res.json();
|
|
418
|
+
if (!data.success) {
|
|
419
|
+
throw new Error(data.error);
|
|
420
|
+
}
|
|
421
|
+
return data;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export function useDeleteReplicationStorage() {
|
|
425
|
+
const queryClient = useQueryClient();
|
|
426
|
+
return useMutation({
|
|
427
|
+
mutationFn: deleteReplicationStorage,
|
|
428
|
+
onError: (error: Error) => {
|
|
429
|
+
console.log('error :', error?.message);
|
|
430
|
+
toast.error(error.message || `Error removing replication storage.`);
|
|
431
|
+
},
|
|
432
|
+
onSuccess: (res, variables) => {
|
|
433
|
+
console.log('# Replication Storage Removed! :', res, variables);
|
|
434
|
+
queryClient.invalidateQueries({ queryKey: ['plan', variables.planID] });
|
|
435
|
+
queryClient.invalidateQueries({ queryKey: ['plans'] });
|
|
436
|
+
toast.success(res?.message || `Replication storage removed successfully!`, { autoClose: 5000 });
|
|
437
|
+
},
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
export async function checkPlanIntegrity({ planId }: { planId: string }) {
|
|
442
|
+
// const header = new Headers({ 'Content-Type': 'application/json', Accept: 'application/json' });
|
|
443
|
+
const res = await fetch(`${API_URL}/plans/${planId}/action/checkintegrity`, {
|
|
444
|
+
method: 'POST',
|
|
445
|
+
credentials: 'include',
|
|
446
|
+
// headers: header,
|
|
447
|
+
});
|
|
448
|
+
// Check if response is ok
|
|
449
|
+
const data = await res.json();
|
|
450
|
+
if (!data.success) {
|
|
451
|
+
throw new Error(data.error);
|
|
452
|
+
}
|
|
453
|
+
return data;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
export function useCheckPlanIntegrity() {
|
|
457
|
+
const queryClient = useQueryClient();
|
|
458
|
+
return useMutation({
|
|
459
|
+
mutationFn: checkPlanIntegrity,
|
|
460
|
+
onSuccess: (res, payload) => {
|
|
461
|
+
queryClient.invalidateQueries({ queryKey: ['plan', payload.planId] });
|
|
462
|
+
console.log('res :', payload, res);
|
|
463
|
+
},
|
|
464
|
+
onError: (error, payload) => {
|
|
465
|
+
console.error('Error checking plan integrity for planId:', payload.planId, error);
|
|
466
|
+
toast.error(`Error checking plan integrity. ${error instanceof Error ? error.message : 'Unknown error'}`, { autoClose: false });
|
|
467
|
+
},
|
|
468
|
+
});
|
|
469
|
+
}
|
package/src/services/restores.ts
CHANGED
|
@@ -89,6 +89,8 @@ export async function restoreBackup({
|
|
|
89
89
|
includes,
|
|
90
90
|
excludes,
|
|
91
91
|
deleteOption,
|
|
92
|
+
storageId,
|
|
93
|
+
replicationId,
|
|
92
94
|
}: {
|
|
93
95
|
backupId: string;
|
|
94
96
|
planId: string;
|
|
@@ -97,13 +99,15 @@ export async function restoreBackup({
|
|
|
97
99
|
includes?: string[];
|
|
98
100
|
excludes?: string[];
|
|
99
101
|
deleteOption: boolean;
|
|
102
|
+
storageId?: string;
|
|
103
|
+
replicationId?: string;
|
|
100
104
|
}) {
|
|
101
105
|
const header = new Headers({ 'Content-Type': 'application/json', Accept: 'application/json' });
|
|
102
106
|
const res = await fetch(`${API_URL}/restores/action/restore`, {
|
|
103
107
|
method: 'POST',
|
|
104
108
|
credentials: 'include',
|
|
105
109
|
headers: header,
|
|
106
|
-
body: JSON.stringify({ backupId, planId, target, overwrite, includes, excludes, delete: deleteOption }),
|
|
110
|
+
body: JSON.stringify({ backupId, planId, target, overwrite, includes, excludes, delete: deleteOption, storageId, replicationId }),
|
|
107
111
|
});
|
|
108
112
|
const data = await res.json();
|
|
109
113
|
if (!data.success) {
|
|
@@ -132,6 +136,8 @@ export async function getDryRestoreStats({
|
|
|
132
136
|
includes,
|
|
133
137
|
excludes,
|
|
134
138
|
deleteOption,
|
|
139
|
+
storageId,
|
|
140
|
+
replicationId,
|
|
135
141
|
}: {
|
|
136
142
|
backupId: string;
|
|
137
143
|
planId: string;
|
|
@@ -140,13 +146,15 @@ export async function getDryRestoreStats({
|
|
|
140
146
|
includes?: string[];
|
|
141
147
|
excludes?: string[];
|
|
142
148
|
deleteOption?: boolean;
|
|
149
|
+
storageId?: string;
|
|
150
|
+
replicationId?: string;
|
|
143
151
|
}) {
|
|
144
152
|
const header = new Headers({ 'Content-Type': 'application/json', Accept: 'application/json' });
|
|
145
153
|
const res = await fetch(`${API_URL}/restores/action/dryrestore`, {
|
|
146
154
|
method: 'POST',
|
|
147
155
|
credentials: 'include',
|
|
148
156
|
headers: header,
|
|
149
|
-
body: JSON.stringify({ backupId, planId, target, overwrite, includes, excludes, delete: deleteOption }),
|
|
157
|
+
body: JSON.stringify({ backupId, planId, target, overwrite, includes, excludes, delete: deleteOption, storageId, replicationId }),
|
|
150
158
|
});
|
|
151
159
|
const data = await res.json();
|
|
152
160
|
if (!data.success) {
|
package/src/services/settings.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
2
2
|
import { API_URL } from '../utils/constants';
|
|
3
|
+
import { useNavigate } from 'react-router';
|
|
3
4
|
|
|
4
5
|
// ============== Settings API ==============
|
|
5
6
|
|
|
@@ -211,3 +212,92 @@ export function useCompleteSetup() {
|
|
|
211
212
|
mutationFn: completeSetup,
|
|
212
213
|
});
|
|
213
214
|
}
|
|
215
|
+
|
|
216
|
+
// Two-Factor Authentication (2FA) Setup and Verification
|
|
217
|
+
|
|
218
|
+
export async function setupTwoFactorAuth(id: number) {
|
|
219
|
+
const headers = new Headers({ 'Content-Type': 'application/json', Accept: 'application/json' });
|
|
220
|
+
const res = await fetch(`${API_URL}/settings/${id}/2fa/setup`, {
|
|
221
|
+
method: 'POST',
|
|
222
|
+
headers,
|
|
223
|
+
credentials: 'include',
|
|
224
|
+
});
|
|
225
|
+
// Check if response is ok
|
|
226
|
+
if (!res.ok) {
|
|
227
|
+
const data = await res.json();
|
|
228
|
+
throw new Error(data.error);
|
|
229
|
+
}
|
|
230
|
+
const data = await res.json();
|
|
231
|
+
return data;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function useSetupTwoFactorAuth() {
|
|
235
|
+
return useMutation({
|
|
236
|
+
mutationFn: setupTwoFactorAuth,
|
|
237
|
+
onSuccess: (res) => {
|
|
238
|
+
console.log('# 2FA setup data fetched successfully! :', res);
|
|
239
|
+
},
|
|
240
|
+
onError: (res) => {
|
|
241
|
+
console.log('# 2FA setup data fetch failed! :', res);
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
export async function verifyTwoFactorAuth({ code, id }: { code: string; id: number }) {
|
|
246
|
+
const headers = new Headers({ 'Content-Type': 'application/json', Accept: 'application/json' });
|
|
247
|
+
const res = await fetch(`${API_URL}/settings/${id}/2fa/finalize`, {
|
|
248
|
+
method: 'POST',
|
|
249
|
+
headers,
|
|
250
|
+
credentials: 'include',
|
|
251
|
+
body: JSON.stringify({ code }),
|
|
252
|
+
});
|
|
253
|
+
// Check if response is ok
|
|
254
|
+
if (!res.ok) {
|
|
255
|
+
const data = await res.json();
|
|
256
|
+
throw new Error(data.error);
|
|
257
|
+
}
|
|
258
|
+
const data = await res.json();
|
|
259
|
+
return data;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export function useVerifyTwoFactorAuth() {
|
|
263
|
+
return useMutation({
|
|
264
|
+
mutationFn: verifyTwoFactorAuth,
|
|
265
|
+
onSuccess: (res) => {
|
|
266
|
+
console.log('# 2FA verification successful! :', res);
|
|
267
|
+
},
|
|
268
|
+
onError: (res) => {
|
|
269
|
+
console.log('# 2FA verification failed! :', res);
|
|
270
|
+
},
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export async function verifyTwoFactorOTP({ code }: { code: string }) {
|
|
275
|
+
const headers = new Headers({ 'Content-Type': 'application/json', Accept: 'application/json' });
|
|
276
|
+
const res = await fetch(`${API_URL}/user/verify-otp`, {
|
|
277
|
+
method: 'POST',
|
|
278
|
+
headers,
|
|
279
|
+
credentials: 'include',
|
|
280
|
+
body: JSON.stringify({ code }),
|
|
281
|
+
});
|
|
282
|
+
// Check if response is ok
|
|
283
|
+
if (!res.ok) {
|
|
284
|
+
const data = await res.json();
|
|
285
|
+
throw new Error(data.error);
|
|
286
|
+
}
|
|
287
|
+
const data = await res.json();
|
|
288
|
+
return data;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export function useVerifyTwoFactorOTP() {
|
|
292
|
+
const navigate = useNavigate();
|
|
293
|
+
return useMutation({
|
|
294
|
+
mutationFn: verifyTwoFactorOTP,
|
|
295
|
+
onSuccess: (res) => {
|
|
296
|
+
console.log('# 2FA verification successful! :', res);
|
|
297
|
+
navigate('/');
|
|
298
|
+
},
|
|
299
|
+
onError: (res) => {
|
|
300
|
+
console.log('# 2FA verification failed! :', res);
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
}
|
package/src/services/users.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { API_URL } from '../utils/constants';
|
|
2
|
-
import { useQuery, useMutation } from '@tanstack/react-query';
|
|
2
|
+
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
3
3
|
import { useNavigate } from 'react-router';
|
|
4
4
|
|
|
5
5
|
interface LoginCredentials {
|
|
@@ -12,22 +12,28 @@ export type InstallType = 'docker' | 'binary' | 'dev';
|
|
|
12
12
|
//VALIDATE USER
|
|
13
13
|
export async function validateAuth() {
|
|
14
14
|
const res = await fetch(`${API_URL}/user/validate`, { method: 'GET', credentials: 'include' });
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
15
|
+
|
|
16
|
+
// Read headers before checking status - middleware sets these on all responses
|
|
18
17
|
const appVersion = res.headers.get('x-app-version');
|
|
19
18
|
const serverOS = res.headers.get('x-server-os');
|
|
20
19
|
const installType = (res.headers.get('x-install-type') || 'dev') as InstallType;
|
|
20
|
+
const setupPending = res.headers.get('x-setup-pending') === '1';
|
|
21
21
|
|
|
22
22
|
(window as any).plutonVersion = appVersion || 'unknown';
|
|
23
23
|
(window as any).plutonServerOS = serverOS || 'unknown';
|
|
24
24
|
(window as any).plutonInstallType = installType;
|
|
25
|
+
(window as any).plutonSetupPending = setupPending;
|
|
26
|
+
|
|
27
|
+
if (!res.ok) {
|
|
28
|
+
throw new Error('Invalid authentication');
|
|
29
|
+
}
|
|
25
30
|
|
|
26
31
|
const data = await res.json();
|
|
27
32
|
return {
|
|
28
33
|
...data,
|
|
29
34
|
appVersion,
|
|
30
35
|
installType,
|
|
36
|
+
setupPending,
|
|
31
37
|
};
|
|
32
38
|
}
|
|
33
39
|
|
|
@@ -59,10 +65,11 @@ export async function loginUser(credentials: LoginCredentials) {
|
|
|
59
65
|
// Add this new hook
|
|
60
66
|
export function useLogin() {
|
|
61
67
|
const navigate = useNavigate();
|
|
68
|
+
const queryClient = useQueryClient();
|
|
62
69
|
return useMutation({
|
|
63
70
|
mutationFn: loginUser,
|
|
64
71
|
onSuccess: (res) => {
|
|
65
|
-
|
|
72
|
+
queryClient.removeQueries({ queryKey: ['auth'] });
|
|
66
73
|
if (res.totpRequired) {
|
|
67
74
|
navigate('/login/verify-otp');
|
|
68
75
|
} else {
|
|
@@ -87,9 +94,11 @@ export async function logoutUser() {
|
|
|
87
94
|
|
|
88
95
|
export function useLogout() {
|
|
89
96
|
const navigate = useNavigate();
|
|
97
|
+
const queryClient = useQueryClient();
|
|
90
98
|
return useMutation({
|
|
91
99
|
mutationFn: logoutUser,
|
|
92
100
|
onSuccess: () => {
|
|
101
|
+
queryClient.removeQueries({ queryKey: ['auth'] });
|
|
93
102
|
navigate('/login');
|
|
94
103
|
},
|
|
95
104
|
});
|
|
@@ -25,6 +25,7 @@ export function generateBackupProgressMessage(progressData: BackupProgressData |
|
|
|
25
25
|
'pre-backup': 'Pre-Backup',
|
|
26
26
|
backup: 'Backup',
|
|
27
27
|
'post-backup': 'Post-Backup',
|
|
28
|
+
replicating: 'Replicating',
|
|
28
29
|
finished: 'Complete',
|
|
29
30
|
};
|
|
30
31
|
|
|
@@ -72,7 +73,7 @@ const handleScriptAction = (action: string): string | null => {
|
|
|
72
73
|
};
|
|
73
74
|
|
|
74
75
|
// Function to extract numbers from action strings and create meaningful messages
|
|
75
|
-
export const getBackupEventActionMessage = (action: string): string => {
|
|
76
|
+
export const getBackupEventActionMessage = (action: string, storageName?: string): string => {
|
|
76
77
|
// Handle script actions first
|
|
77
78
|
const scriptMessage = handleScriptAction(action);
|
|
78
79
|
if (scriptMessage) {
|
|
@@ -93,6 +94,20 @@ export const getBackupEventActionMessage = (action: string): string => {
|
|
|
93
94
|
return `Scheduling Retry (${parseInt(current)}/${total})...`;
|
|
94
95
|
}
|
|
95
96
|
|
|
97
|
+
// Handle replication retry scheduling
|
|
98
|
+
const replicationRetryScheduledMatch = action.match(/REPLICATION_RETRY_(\d+)_OF_(\d+)_SCHEDULED/);
|
|
99
|
+
if (replicationRetryScheduledMatch) {
|
|
100
|
+
const [, current, total] = replicationRetryScheduledMatch;
|
|
101
|
+
return `Retrying (${current}/${total})...`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Handle replication retry start
|
|
105
|
+
const replicationRetryStartMatch = action.match(/REPLICATION_RETRY_(\d+)_OF_(\d+)_START/);
|
|
106
|
+
if (replicationRetryStartMatch) {
|
|
107
|
+
const [, current, total] = replicationRetryStartMatch;
|
|
108
|
+
return `Retrying (${current}/${total})...`;
|
|
109
|
+
}
|
|
110
|
+
|
|
96
111
|
// Static action mappings
|
|
97
112
|
const staticMessages: Record<string, string> = {
|
|
98
113
|
INITIALIZE: 'Starting Backup...',
|
|
@@ -134,8 +149,53 @@ export const getBackupEventActionMessage = (action: string): string => {
|
|
|
134
149
|
ISO_UPLOAD_COMPLETE: 'ISO Upload Complete',
|
|
135
150
|
ISO_UPLOAD_FAILED: 'ISO Upload Failed',
|
|
136
151
|
BACKUP_WARNING: 'Hiccup Detected During Backup',
|
|
152
|
+
// Replication actions
|
|
153
|
+
REPLICATION_START: 'Replicating Snapshots...',
|
|
154
|
+
REPLICATION_INIT_START: 'Initializing Replication Repository...',
|
|
155
|
+
REPLICATION_INIT_COMPLETE: 'Replication Repository Initialized',
|
|
156
|
+
REPLICATION_INIT_FAILED: 'Replication Repository Init Failed',
|
|
157
|
+
REPLICATION_UNLOCK_START: 'Unlocking Replication Repository...',
|
|
158
|
+
REPLICATION_UNLOCK_COMPLETE: 'Replication Repository Unlocked',
|
|
159
|
+
REPLICATION_COPY_START: 'Copying Snapshot to Replication...',
|
|
160
|
+
REPLICATION_COPY_COMPLETE: 'Snapshot Copied to Replication',
|
|
161
|
+
REPLICATION_COPY_FAILED: 'Replication Copy Failed',
|
|
162
|
+
REPLICATION_PRUNE_START: 'Pruning Replication Repository...',
|
|
163
|
+
REPLICATION_PRUNE_COMPLETE: 'Replication Prune Complete',
|
|
164
|
+
REPLICATION_PRUNE_FAILED: 'Replication Prune Failed',
|
|
165
|
+
REPLICATION_STATS_START: 'Updating Replication Stats...',
|
|
166
|
+
REPLICATION_STATS_COMPLETE: 'Replication Stats Updated',
|
|
167
|
+
REPLICATION_COMPLETE: 'Replication Complete',
|
|
168
|
+
REPLICATION_FAILED: 'Replication Failed',
|
|
169
|
+
REPLICATION_PARTIAL_FAILURE: 'Some Replications Failed',
|
|
170
|
+
REPLICATION_MANUAL_RETRY_START: 'Retrying Failed Replications...',
|
|
171
|
+
REPLICATION_MANUAL_RETRY_COMPLETE: 'Replication Retry Complete',
|
|
172
|
+
REPLICATION_MANUAL_RETRY_PARTIAL_FAILURE: 'Some Replication Retries Still Failed',
|
|
137
173
|
};
|
|
138
174
|
|
|
175
|
+
// Storage-name-aware replication action mappings
|
|
176
|
+
const replicationMessagesWithStorage: Record<string, (name: string) => string> = {
|
|
177
|
+
REPLICATION_START: (name) => `Replicating Snapshot to ${name}...`,
|
|
178
|
+
REPLICATION_INIT_START: (name) => `Initializing Replication Repository in ${name}...`,
|
|
179
|
+
REPLICATION_INIT_COMPLETE: (name) => `Replication Repository Initialized in ${name}`,
|
|
180
|
+
REPLICATION_INIT_FAILED: (name) => `Replication Repository Init Failed in ${name}`,
|
|
181
|
+
REPLICATION_UNLOCK_START: (name) => `Unlocking Replication Repository in ${name}...`,
|
|
182
|
+
REPLICATION_UNLOCK_COMPLETE: (name) => `Replication Repository Unlocked in ${name}`,
|
|
183
|
+
REPLICATION_COPY_START: (name) => `Copying Snapshot to ${name}...`,
|
|
184
|
+
REPLICATION_COPY_COMPLETE: (name) => `Snapshot Copied to ${name}`,
|
|
185
|
+
REPLICATION_COPY_FAILED: (name) => `Replication Copy Failed for ${name}`,
|
|
186
|
+
REPLICATION_PRUNE_START: (name) => `Pruning Replication Repository in ${name}...`,
|
|
187
|
+
REPLICATION_PRUNE_COMPLETE: (name) => `Replication Prune Complete for ${name}`,
|
|
188
|
+
REPLICATION_PRUNE_FAILED: (name) => `Replication Prune Failed for ${name}`,
|
|
189
|
+
REPLICATION_STATS_START: (name) => `Updating Replication Stats for ${name}...`,
|
|
190
|
+
REPLICATION_STATS_COMPLETE: (name) => `Replication Stats Updated for ${name}`,
|
|
191
|
+
REPLICATION_COMPLETE: (name) => `Replication Complete for ${name}`,
|
|
192
|
+
REPLICATION_FAILED: (name) => `Replication Failed for ${name}`,
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
if (storageName && replicationMessagesWithStorage[action]) {
|
|
196
|
+
return replicationMessagesWithStorage[action](storageName);
|
|
197
|
+
}
|
|
198
|
+
|
|
139
199
|
return staticMessages[action] || action;
|
|
140
200
|
};
|
|
141
201
|
|
|
@@ -242,3 +302,27 @@ export function extractResticData(progressData: BackupProgressData | null) {
|
|
|
242
302
|
|
|
243
303
|
return eventWithResticData?.resticData || null;
|
|
244
304
|
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Generates a human-readable progress message for a specific replication mirror.
|
|
308
|
+
* Uses the mirror's latest event action and includes the storage name.
|
|
309
|
+
*/
|
|
310
|
+
export function generateMirrorProgressMessage(mirror: { storageName: string; events?: { action: string; completed: boolean }[] }): string {
|
|
311
|
+
if (!mirror.events?.length) {
|
|
312
|
+
return 'Pending...';
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Find the last incomplete event or the most recent event
|
|
316
|
+
const lastIncompleteEvent = mirror.events
|
|
317
|
+
.slice()
|
|
318
|
+
.reverse()
|
|
319
|
+
.find((event) => !event.completed);
|
|
320
|
+
|
|
321
|
+
const currentEvent = lastIncompleteEvent || mirror.events[mirror.events.length - 1];
|
|
322
|
+
|
|
323
|
+
if (!currentEvent) {
|
|
324
|
+
return 'Pending...';
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return getBackupEventActionMessage(currentEvent.action, mirror.storageName);
|
|
328
|
+
}
|