@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.
Files changed (217) hide show
  1. package/dist-lib/@types/backups.d.ts +26 -0
  2. package/dist-lib/@types/backups.d.ts.map +1 -1
  3. package/dist-lib/@types/devices.d.ts +7 -0
  4. package/dist-lib/@types/devices.d.ts.map +1 -1
  5. package/dist-lib/@types/plans.d.ts +21 -1
  6. package/dist-lib/@types/plans.d.ts.map +1 -1
  7. package/dist-lib/@types/restores.d.ts +2 -0
  8. package/dist-lib/@types/restores.d.ts.map +1 -1
  9. package/dist-lib/components/Device/DeviceBackups/DeviceBackups.d.ts +3 -2
  10. package/dist-lib/components/Device/DeviceBackups/DeviceBackups.d.ts.map +1 -1
  11. package/dist-lib/components/Device/DeviceBackups/DeviceBackups.js +73 -85
  12. package/dist-lib/components/Device/DeviceBackups/DeviceBackups.js.map +1 -1
  13. package/dist-lib/components/Plan/BackupEvents/BackupEvents.d.ts.map +1 -1
  14. package/dist-lib/components/Plan/BackupEvents/BackupEvents.js +88 -50
  15. package/dist-lib/components/Plan/BackupEvents/BackupEvents.js.map +1 -1
  16. package/dist-lib/components/Plan/BackupEvents/BackupEvents.module.scss.js +70 -38
  17. package/dist-lib/components/Plan/BackupEvents/BackupEvents.module.scss.js.map +1 -1
  18. package/dist-lib/components/Plan/BackupProgress/BackupProgress.d.ts.map +1 -1
  19. package/dist-lib/components/Plan/BackupProgress/BackupProgress.js +166 -123
  20. package/dist-lib/components/Plan/BackupProgress/BackupProgress.js.map +1 -1
  21. package/dist-lib/components/Plan/BackupProgress/BackupProgress.module.scss.js +64 -30
  22. package/dist-lib/components/Plan/BackupProgress/BackupProgress.module.scss.js.map +1 -1
  23. package/dist-lib/components/Plan/Backups/Backups.d.ts +8 -1
  24. package/dist-lib/components/Plan/Backups/Backups.d.ts.map +1 -1
  25. package/dist-lib/components/Plan/Backups/Backups.js +154 -125
  26. package/dist-lib/components/Plan/Backups/Backups.js.map +1 -1
  27. package/dist-lib/components/Plan/EditPlan/EditPlan.d.ts.map +1 -1
  28. package/dist-lib/components/Plan/EditPlan/EditPlan.js +11 -10
  29. package/dist-lib/components/Plan/EditPlan/EditPlan.js.map +1 -1
  30. package/dist-lib/components/Plan/Mirrors/MirrorDetails.d.ts +12 -0
  31. package/dist-lib/components/Plan/Mirrors/MirrorDetails.d.ts.map +1 -0
  32. package/dist-lib/components/Plan/Mirrors/MirrorDetails.js +68 -0
  33. package/dist-lib/components/Plan/Mirrors/MirrorDetails.js.map +1 -0
  34. package/dist-lib/components/Plan/Mirrors/MirrorDetails.module.scss.js +26 -0
  35. package/dist-lib/components/Plan/Mirrors/MirrorDetails.module.scss.js.map +1 -0
  36. package/dist-lib/components/Plan/Mirrors/MirrorStatusBadge.d.ts +11 -0
  37. package/dist-lib/components/Plan/Mirrors/MirrorStatusBadge.d.ts.map +1 -0
  38. package/dist-lib/components/Plan/Mirrors/MirrorStatusBadge.js +38 -0
  39. package/dist-lib/components/Plan/Mirrors/MirrorStatusBadge.js.map +1 -0
  40. package/dist-lib/components/Plan/Mirrors/MirrorStatusBadge.module.scss.js +16 -0
  41. package/dist-lib/components/Plan/Mirrors/MirrorStatusBadge.module.scss.js.map +1 -0
  42. package/dist-lib/components/Plan/Mirrors/MirrorStorageSelector.d.ts +14 -0
  43. package/dist-lib/components/Plan/Mirrors/MirrorStorageSelector.d.ts.map +1 -0
  44. package/dist-lib/components/Plan/Mirrors/MirrorStorageSelector.js +54 -0
  45. package/dist-lib/components/Plan/Mirrors/MirrorStorageSelector.js.map +1 -0
  46. package/dist-lib/components/Plan/Mirrors/MirrorStorageSelector.module.scss.js +26 -0
  47. package/dist-lib/components/Plan/Mirrors/MirrorStorageSelector.module.scss.js.map +1 -0
  48. package/dist-lib/components/Plan/Mirrors/MirrorStorageSelectorModal.d.ts +15 -0
  49. package/dist-lib/components/Plan/Mirrors/MirrorStorageSelectorModal.d.ts.map +1 -0
  50. package/dist-lib/components/Plan/Mirrors/MirrorStorageSelectorModal.js +34 -0
  51. package/dist-lib/components/Plan/Mirrors/MirrorStorageSelectorModal.js.map +1 -0
  52. package/dist-lib/components/Plan/PlanBackups/PlanBackups.d.ts.map +1 -1
  53. package/dist-lib/components/Plan/PlanBackups/PlanBackups.js +20 -17
  54. package/dist-lib/components/Plan/PlanBackups/PlanBackups.js.map +1 -1
  55. package/dist-lib/components/Plan/PlanForm/PlanForm.d.ts +2 -1
  56. package/dist-lib/components/Plan/PlanForm/PlanForm.d.ts.map +1 -1
  57. package/dist-lib/components/Plan/PlanForm/PlanForm.js +121 -94
  58. package/dist-lib/components/Plan/PlanForm/PlanForm.js.map +1 -1
  59. package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.d.ts +16 -0
  60. package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.d.ts.map +1 -0
  61. package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.js +115 -0
  62. package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.js.map +1 -0
  63. package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.module.scss.js +26 -0
  64. package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.module.scss.js.map +1 -0
  65. package/dist-lib/components/Plan/PlanItems/PlanItem.d.ts.map +1 -1
  66. package/dist-lib/components/Plan/PlanItems/PlanItem.js +58 -59
  67. package/dist-lib/components/Plan/PlanItems/PlanItem.js.map +1 -1
  68. package/dist-lib/components/Plan/PlanPendingBackup/PlanPendingBackup.d.ts +2 -2
  69. package/dist-lib/components/Plan/PlanPendingBackup/PlanPendingBackup.d.ts.map +1 -1
  70. package/dist-lib/components/Plan/PlanPendingBackup/PlanPendingBackup.js.map +1 -1
  71. package/dist-lib/components/Plan/PlanRemoveModal/PlanRemoveModal.js +8 -8
  72. package/dist-lib/components/Plan/PlanRemoveModal/PlanRemoveModal.js.map +1 -1
  73. package/dist-lib/components/Plan/PlanSettings/PlanReplicationSettings.d.ts +14 -0
  74. package/dist-lib/components/Plan/PlanSettings/PlanReplicationSettings.d.ts.map +1 -0
  75. package/dist-lib/components/Plan/PlanSettings/PlanReplicationSettings.js +290 -0
  76. package/dist-lib/components/Plan/PlanSettings/PlanReplicationSettings.js.map +1 -0
  77. package/dist-lib/components/Plan/PlanSettings/PlanReplicationSettings.module.scss.js +26 -0
  78. package/dist-lib/components/Plan/PlanSettings/PlanReplicationSettings.module.scss.js.map +1 -0
  79. package/dist-lib/components/Plan/PlanStats/PlanStats.d.ts.map +1 -1
  80. package/dist-lib/components/Plan/PlanStats/PlanStats.js +41 -42
  81. package/dist-lib/components/Plan/PlanStats/PlanStats.js.map +1 -1
  82. package/dist-lib/components/Plan/PlanStats/PlanStats.module.scss.js +5 -5
  83. package/dist-lib/components/Plan/PlanStorageInfo/PlanStorageInfo.d.ts +15 -0
  84. package/dist-lib/components/Plan/PlanStorageInfo/PlanStorageInfo.d.ts.map +1 -0
  85. package/dist-lib/components/Plan/PlanStorageInfo/PlanStorageInfo.js +69 -0
  86. package/dist-lib/components/Plan/PlanStorageInfo/PlanStorageInfo.js.map +1 -0
  87. package/dist-lib/components/Plan/PlanStorageInfo/PlanStorageInfo.module.scss.js +16 -0
  88. package/dist-lib/components/Plan/PlanStorageInfo/PlanStorageInfo.module.scss.js.map +1 -0
  89. package/dist-lib/components/Restore/RestoreWizard/RestoreConfirmStep.d.ts.map +1 -1
  90. package/dist-lib/components/Restore/RestoreWizard/RestoreConfirmStep.js +36 -34
  91. package/dist-lib/components/Restore/RestoreWizard/RestoreConfirmStep.js.map +1 -1
  92. package/dist-lib/components/Restore/RestoreWizard/RestorePreviewStep.d.ts.map +1 -1
  93. package/dist-lib/components/Restore/RestoreWizard/RestorePreviewStep.js +7 -5
  94. package/dist-lib/components/Restore/RestoreWizard/RestorePreviewStep.js.map +1 -1
  95. package/dist-lib/components/Restore/RestoreWizard/RestoreSettingsStep.d.ts +12 -4
  96. package/dist-lib/components/Restore/RestoreWizard/RestoreSettingsStep.d.ts.map +1 -1
  97. package/dist-lib/components/Restore/RestoreWizard/RestoreSettingsStep.js +44 -32
  98. package/dist-lib/components/Restore/RestoreWizard/RestoreSettingsStep.js.map +1 -1
  99. package/dist-lib/components/Restore/RestoreWizard/RestoreWizard.d.ts +5 -1
  100. package/dist-lib/components/Restore/RestoreWizard/RestoreWizard.d.ts.map +1 -1
  101. package/dist-lib/components/Restore/RestoreWizard/RestoreWizard.js +48 -44
  102. package/dist-lib/components/Restore/RestoreWizard/RestoreWizard.js.map +1 -1
  103. package/dist-lib/components/Restore/RestoreWizard/RestoreWizard.module.scss.js +32 -32
  104. package/dist-lib/components/Settings/GeneralSettings/GeneralSettings.d.ts +1 -1
  105. package/dist-lib/components/Settings/GeneralSettings/GeneralSettings.d.ts.map +1 -1
  106. package/dist-lib/components/Settings/GeneralSettings/GeneralSettings.js +52 -24
  107. package/dist-lib/components/Settings/GeneralSettings/GeneralSettings.js.map +1 -1
  108. package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.d.ts.map +1 -1
  109. package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.js +28 -19
  110. package/dist-lib/components/Settings/IntegrationSettings/IntegrationSettings.js.map +1 -1
  111. package/dist-lib/components/Settings/TwoFactorSetup/TwoFactorSetup.d.ts +7 -0
  112. package/dist-lib/components/Settings/TwoFactorSetup/TwoFactorSetup.d.ts.map +1 -0
  113. package/dist-lib/components/Settings/TwoFactorSetup/TwoFactorSetup.js +79 -0
  114. package/dist-lib/components/Settings/TwoFactorSetup/TwoFactorSetup.js.map +1 -0
  115. package/dist-lib/components/Settings/TwoFactorSetup/TwoFactorSetup.module.scss.js +24 -0
  116. package/dist-lib/components/Settings/TwoFactorSetup/TwoFactorSetup.module.scss.js.map +1 -0
  117. package/dist-lib/components/common/Icon/Icon.d.ts.map +1 -1
  118. package/dist-lib/components/common/Icon/Icon.js +11 -0
  119. package/dist-lib/components/common/Icon/Icon.js.map +1 -1
  120. package/dist-lib/components/common/PageHeader/PageHeader.module.scss.js +6 -6
  121. package/dist-lib/components/index.d.ts +6 -0
  122. package/dist-lib/components/index.d.ts.map +1 -1
  123. package/dist-lib/components.js +102 -90
  124. package/dist-lib/components.js.map +1 -1
  125. package/dist-lib/hooks/usePwaAutoUpdate.d.ts +11 -2
  126. package/dist-lib/hooks/usePwaAutoUpdate.d.ts.map +1 -1
  127. package/dist-lib/hooks/usePwaAutoUpdate.js +32 -10
  128. package/dist-lib/hooks/usePwaAutoUpdate.js.map +1 -1
  129. package/dist-lib/router.d.ts.map +1 -1
  130. package/dist-lib/router.js +46 -35
  131. package/dist-lib/router.js.map +1 -1
  132. package/dist-lib/routes/DeviceSingle/DeviceSingle.d.ts.map +1 -1
  133. package/dist-lib/routes/DeviceSingle/DeviceSingle.js +40 -40
  134. package/dist-lib/routes/DeviceSingle/DeviceSingle.js.map +1 -1
  135. package/dist-lib/routes/PlanSingle/PlanSingle.d.ts.map +1 -1
  136. package/dist-lib/routes/PlanSingle/PlanSingle.js +123 -98
  137. package/dist-lib/routes/PlanSingle/PlanSingle.js.map +1 -1
  138. package/dist-lib/services/backups.d.ts +15 -2
  139. package/dist-lib/services/backups.d.ts.map +1 -1
  140. package/dist-lib/services/backups.js +119 -100
  141. package/dist-lib/services/backups.js.map +1 -1
  142. package/dist-lib/services/plans.d.ts +20 -0
  143. package/dist-lib/services/plans.d.ts.map +1 -1
  144. package/dist-lib/services/plans.js +227 -172
  145. package/dist-lib/services/plans.js.map +1 -1
  146. package/dist-lib/services/restores.d.ts +10 -2
  147. package/dist-lib/services/restores.d.ts.map +1 -1
  148. package/dist-lib/services/restores.js +61 -57
  149. package/dist-lib/services/restores.js.map +1 -1
  150. package/dist-lib/services/settings.d.ts +16 -0
  151. package/dist-lib/services/settings.d.ts.map +1 -1
  152. package/dist-lib/services/settings.js +147 -68
  153. package/dist-lib/services/settings.js.map +1 -1
  154. package/dist-lib/services/users.d.ts.map +1 -1
  155. package/dist-lib/services/users.js +32 -32
  156. package/dist-lib/services/users.js.map +1 -1
  157. package/dist-lib/services.js +113 -101
  158. package/dist-lib/styles/core-frontend.css +1 -1
  159. package/dist-lib/utils/progressHelpers.d.ts +12 -1
  160. package/dist-lib/utils/progressHelpers.d.ts.map +1 -1
  161. package/dist-lib/utils/progressHelpers.js +121 -63
  162. package/dist-lib/utils/progressHelpers.js.map +1 -1
  163. package/dist-lib/utils.js +29 -28
  164. package/package.json +1 -1
  165. package/src/@types/backups.ts +28 -0
  166. package/src/@types/devices.ts +8 -0
  167. package/src/@types/plans.ts +23 -1
  168. package/src/@types/restores.ts +2 -0
  169. package/src/components/Device/DeviceBackups/DeviceBackups.tsx +11 -36
  170. package/src/components/Plan/BackupEvents/BackupEvents.module.scss +65 -0
  171. package/src/components/Plan/BackupEvents/BackupEvents.tsx +65 -4
  172. package/src/components/Plan/BackupProgress/BackupProgress.module.scss +121 -3
  173. package/src/components/Plan/BackupProgress/BackupProgress.tsx +149 -71
  174. package/src/components/Plan/Backups/Backups.tsx +52 -4
  175. package/src/components/Plan/EditPlan/EditPlan.tsx +1 -0
  176. package/src/components/Plan/Mirrors/MirrorDetails.module.scss +76 -0
  177. package/src/components/Plan/Mirrors/MirrorDetails.tsx +100 -0
  178. package/src/components/Plan/Mirrors/MirrorStatusBadge.module.scss +25 -0
  179. package/src/components/Plan/Mirrors/MirrorStatusBadge.tsx +65 -0
  180. package/src/components/Plan/Mirrors/MirrorStorageSelector.module.scss +97 -0
  181. package/src/components/Plan/Mirrors/MirrorStorageSelector.tsx +70 -0
  182. package/src/components/Plan/Mirrors/MirrorStorageSelectorModal.tsx +40 -0
  183. package/src/components/Plan/PlanBackups/PlanBackups.tsx +4 -1
  184. package/src/components/Plan/PlanForm/PlanForm.tsx +44 -17
  185. package/src/components/Plan/PlanIntegrity/PlanIntegrity.module.scss +110 -0
  186. package/src/components/Plan/PlanIntegrity/PlanIntegrity.tsx +187 -0
  187. package/src/components/Plan/PlanItems/PlanItem.tsx +3 -3
  188. package/src/components/Plan/PlanPendingBackup/PlanPendingBackup.tsx +2 -2
  189. package/src/components/Plan/PlanRemoveModal/PlanRemoveModal.tsx +1 -1
  190. package/src/components/Plan/PlanSettings/PlanReplicationSettings.module.scss +105 -0
  191. package/src/components/Plan/PlanSettings/PlanReplicationSettings.tsx +334 -0
  192. package/src/components/Plan/PlanStats/PlanStats.module.scss +1 -1
  193. package/src/components/Plan/PlanStats/PlanStats.tsx +8 -8
  194. package/src/components/Plan/PlanStorageInfo/PlanStorageInfo.module.scss +43 -0
  195. package/src/components/Plan/PlanStorageInfo/PlanStorageInfo.tsx +83 -0
  196. package/src/components/Restore/RestoreWizard/RestoreConfirmStep.tsx +2 -0
  197. package/src/components/Restore/RestoreWizard/RestorePreviewStep.tsx +2 -0
  198. package/src/components/Restore/RestoreWizard/RestoreSettingsStep.tsx +36 -13
  199. package/src/components/Restore/RestoreWizard/RestoreWizard.module.scss +4 -0
  200. package/src/components/Restore/RestoreWizard/RestoreWizard.tsx +9 -1
  201. package/src/components/Settings/GeneralSettings/GeneralSettings.tsx +38 -2
  202. package/src/components/Settings/IntegrationSettings/IntegrationSettings.tsx +9 -2
  203. package/src/components/Settings/TwoFactorSetup/TwoFactorSetup.module.scss +62 -0
  204. package/src/components/Settings/TwoFactorSetup/TwoFactorSetup.tsx +102 -0
  205. package/src/components/common/Icon/Icon.tsx +10 -1
  206. package/src/components/common/PageHeader/PageHeader.module.scss +3 -0
  207. package/src/components/index.ts +8 -0
  208. package/src/hooks/usePwaAutoUpdate.ts +51 -11
  209. package/src/router.tsx +26 -17
  210. package/src/routes/DeviceSingle/DeviceSingle.tsx +3 -3
  211. package/src/routes/PlanSingle/PlanSingle.tsx +21 -0
  212. package/src/services/backups.ts +32 -9
  213. package/src/services/plans.ts +75 -0
  214. package/src/services/restores.ts +10 -2
  215. package/src/services/settings.ts +90 -0
  216. package/src/services/users.ts +14 -5
  217. package/src/utils/progressHelpers.ts +85 -1
@@ -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
+ }
@@ -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) {
@@ -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
+ }
@@ -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
- if (!res.ok) {
16
- throw new Error('Invalid authentication');
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
- console.log('res :', res);
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
+ }