@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
@@ -15,6 +15,7 @@ import IntervalField from '../../common/form/IntervalField/IntervalField';
15
15
  import PlanFormNav from './PlanFormNav';
16
16
  import { useGetDevice } from '../../../services/devices';
17
17
  import PlanPruneSettings from '../PlanSettings/PlanPruneSettings';
18
+ import PlanReplicationSettings from '../PlanSettings/PlanReplicationSettings';
18
19
 
19
20
  type PlanFormProps = {
20
21
  title: string;
@@ -26,9 +27,21 @@ type PlanFormProps = {
26
27
  close: () => void;
27
28
  storagePath?: string;
28
29
  storageId?: string;
30
+ planId?: string;
29
31
  };
30
32
 
31
- const PlanForm = ({ title, planSettings, type, onPlanSettingsChange, onSubmit, isSubmitting, close, storagePath, storageId }: PlanFormProps) => {
33
+ const PlanForm = ({
34
+ title,
35
+ planSettings,
36
+ type,
37
+ onPlanSettingsChange,
38
+ onSubmit,
39
+ isSubmitting,
40
+ close,
41
+ storagePath,
42
+ storageId,
43
+ planId,
44
+ }: PlanFormProps) => {
32
45
  const [step, setStep] = useState<number>(1);
33
46
 
34
47
  const { data: settingsData } = useGetSettings();
@@ -177,20 +190,20 @@ const PlanForm = ({ title, planSettings, type, onPlanSettingsChange, onSubmit, i
177
190
  label: 'Incremental Backup',
178
191
  description: 'Periodically create Incremental backup snapshots of source',
179
192
  },
180
- {
181
- value: 'sync',
182
- icon: 'reload',
183
- label: 'Real-time Sync',
184
- description: 'Maintain identical source (with revisions)',
185
- disabled: true,
186
- },
187
- {
188
- value: 'rescue',
189
- icon: 'rescue',
190
- label: 'Linux Server Backup',
191
- description: 'Full Linux system backups with bootable ISO image',
192
- disabled: true,
193
- },
193
+ // {
194
+ // value: 'sync',
195
+ // icon: 'reload',
196
+ // label: 'Real-time Sync',
197
+ // description: 'Maintain identical source (with revisions)',
198
+ // disabled: true,
199
+ // },
200
+ // {
201
+ // value: 'rescue',
202
+ // icon: 'rescue',
203
+ // label: 'Linux Server Backup',
204
+ // description: 'Full Linux system backups with bootable ISO image',
205
+ // disabled: true,
206
+ // },
194
207
  ]}
195
208
  />
196
209
  )}
@@ -208,8 +221,8 @@ const PlanForm = ({ title, planSettings, type, onPlanSettingsChange, onSubmit, i
208
221
  <label className={classes.label}>Backup Destination*</label>
209
222
  {!planSettings.storage.name && <span className={classes.fieldErrorLabel}>{'Required'}</span>}
210
223
  <StoragePicker
211
- storagePath={storagePath}
212
- storageId={storageId}
224
+ storagePath={storagePath || planSettings.storagePath}
225
+ storageId={storageId || planSettings.storage?.id || ''}
213
226
  deviceId={planSettings.sourceId || 'main'}
214
227
  disabled={type === 'edit' ? true : false}
215
228
  onUpdate={(s: { storage: { name: string; id: string; type: string }; path: string }) =>
@@ -221,6 +234,20 @@ const PlanForm = ({ title, planSettings, type, onPlanSettingsChange, onSubmit, i
221
234
  }
222
235
  />
223
236
  </div>
237
+ <PlanReplicationSettings
238
+ replication={planSettings.settings.replication}
239
+ primaryStorageId={planSettings.storage.id}
240
+ primaryStoragePath={planSettings.storagePath}
241
+ deviceId={planSettings.sourceId || 'main'}
242
+ isEditing={type === 'edit' ? true : false}
243
+ planID={planId}
244
+ onUpdate={(replication) =>
245
+ onPlanSettingsChange({
246
+ ...planSettings,
247
+ settings: { ...planSettings.settings, replication: replication },
248
+ })
249
+ }
250
+ />
224
251
  </div>
225
252
  )}
226
253
  {step === 3 && (
@@ -0,0 +1,110 @@
1
+ .integrityMessage {
2
+ :global(.label) {
3
+ font-size: 0.9em;
4
+ border-radius: 6px;
5
+ padding: 10px;
6
+ }
7
+ }
8
+
9
+ .fixSuggestion {
10
+ border-radius: 6px;
11
+ border: 1px solid var(--line-color);
12
+ box-sizing: border-box;
13
+ margin: 0 5px;
14
+ margin-top: 12px;
15
+ h4 {
16
+ padding: 12px;
17
+ font-weight: 600;
18
+ margin: 0;
19
+ border-bottom: 1px solid var(--line-color);
20
+ }
21
+ .fixSuggestionContent {
22
+ padding: 0 12px;
23
+ font-size: 0.9em;
24
+ code {
25
+ background: var(--line-color);
26
+ padding: 5px;
27
+ border-radius: 4px;
28
+ display: block;
29
+ font-family: monospace;
30
+ }
31
+ }
32
+ }
33
+
34
+ .integrityLogs {
35
+ border-radius: 6px;
36
+ border: 1px solid var(--line-color);
37
+ box-sizing: border-box;
38
+ margin: 0 5px;
39
+ margin-top: 12px;
40
+
41
+ .integrityLogsHeader {
42
+ padding: 12px;
43
+ font-weight: 600;
44
+ border-bottom: 1px solid var(--line-color);
45
+ display: flex;
46
+ justify-content: space-between;
47
+ & > div:nth-child(2) {
48
+ font-weight: normal;
49
+ color: var(--content-text-color-light);
50
+ }
51
+ }
52
+ .integrityLogMessages {
53
+ font-family: monospace;
54
+ background-color: var(--background-color);
55
+ line-height: 1.3rem;
56
+ max-height: 300px;
57
+ overflow: auto;
58
+ span {
59
+ display: block;
60
+ padding: 4px 12px;
61
+ line-break: anywhere;
62
+ &:nth-child(even) {
63
+ background: rgba(0, 0, 0, 0.03);
64
+ }
65
+ }
66
+ }
67
+ }
68
+
69
+ .integrityResult {
70
+ &.withReplications {
71
+ border: 1px solid var(--line-color);
72
+ border-radius: 6px;
73
+ .replicationResult {
74
+ h4 {
75
+ margin: 0;
76
+ padding: 12px;
77
+ cursor: pointer;
78
+ display: flex;
79
+ justify-content: space-between;
80
+ border-bottom: 1px solid var(--line-color);
81
+ i {
82
+ background-color: var(--background-color);
83
+ color: var(--content-text-color-light);
84
+ padding: 1px 12px;
85
+ border-radius: 20px;
86
+ font-size: 0.7rem;
87
+ font-weight: normal;
88
+ font-style: normal;
89
+ display: inline-block;
90
+ margin-left: 6px;
91
+ }
92
+ img {
93
+ max-width: 14px;
94
+ vertical-align: middle;
95
+ margin-right: 6px;
96
+ }
97
+ }
98
+ .replicationResultContent {
99
+ padding: 12px;
100
+ border-bottom: 1px solid var(--line-color);
101
+ }
102
+ }
103
+ }
104
+ }
105
+
106
+ @media only screen and (max-width: 768px) {
107
+ .integrityLogs .integrityLogsHeader {
108
+ flex-direction: column;
109
+ }
110
+ }
@@ -0,0 +1,187 @@
1
+ import { useState } from 'react';
2
+ import classes from './PlanIntegrity.module.scss';
3
+ import { useCheckPlanIntegrity } from '../../../services';
4
+ import { Plan, PlanReplicationStorage, PlanVerifiedResult } from '../../../@types';
5
+ import { formatDateTime, timeAgo } from '../../../utils';
6
+ import Icon from '../../common/Icon/Icon';
7
+ import ActionModal from '../../common/ActionModal/ActionModal';
8
+
9
+ interface PlanIntegrityProps {
10
+ planId: string;
11
+ taskPending: boolean;
12
+ verificationData: Plan['verified'];
13
+ storage: { name: string; type: string; id: string };
14
+ replicationStorages: PlanReplicationStorage[];
15
+ onClose: () => void;
16
+ }
17
+
18
+ const PlanIntegrity = ({ planId, taskPending, verificationData, storage, replicationStorages = [], onClose }: PlanIntegrityProps) => {
19
+ const [showContent, setShowContent] = useState('primary');
20
+ const integrityCheckMutation = useCheckPlanIntegrity();
21
+
22
+ const integrityResultLoaded = verificationData && verificationData?.result;
23
+ const hasReplications = replicationStorages && replicationStorages.length > 0;
24
+
25
+ const getBackupResultByStorage = (storageType: string): PlanVerifiedResult | null => {
26
+ if (!verificationData?.result) return null;
27
+
28
+ const replicationResult = verificationData.result as Record<string, PlanVerifiedResult>;
29
+ return replicationResult[storageType] ?? null;
30
+ };
31
+
32
+ const renderLogs = (storageType: string) => {
33
+ if (integrityCheckMutation.isPending) return null;
34
+ const backupResData = getBackupResultByStorage(storageType);
35
+ const messages = backupResData?.logs;
36
+ if (!messages?.length) return null;
37
+
38
+ return (
39
+ <div className={classes.integrityLogs}>
40
+ <div className={classes.integrityLogsHeader}>
41
+ <div>Integrity Check Output Logs</div>
42
+ <div title={formatDateTime(verificationData.endedAt || verificationData.startedAt)}>
43
+ <Icon type="clock" size={14} /> {timeAgo(new Date(verificationData.endedAt || verificationData.startedAt))}
44
+ </div>
45
+ </div>
46
+ <div className={classes.integrityLogMessages}>
47
+ {messages.map((message, index) => (
48
+ <span key={index}>{message}</span>
49
+ ))}
50
+ </div>
51
+ </div>
52
+ );
53
+ };
54
+
55
+ const renderBackupFixSuggestion = (storageType: string) => {
56
+ if (!integrityResultLoaded) return null;
57
+ if (integrityCheckMutation.isPending) return null;
58
+ const backupResData = getBackupResultByStorage(storageType);
59
+ if (!backupResData?.hasError) return null;
60
+
61
+ return (
62
+ <div className={classes.fixSuggestion}>
63
+ <h4>Fix Suggestion</h4>
64
+ <div className={classes.fixSuggestionContent}>
65
+ {backupResData.fix &&
66
+ backupResData.fix
67
+ .split('\n')
68
+ .map((line, index) => <p key={index}>{line.includes('`') ? <code>{line.replace(/`/g, '')}</code> : line}</p>)}
69
+ {!backupResData.fix && <p>No Suggestion for this issue.</p>}
70
+ <p>
71
+ Learn more about fixing restic repo issues{' '}
72
+ <a
73
+ href="https://restic.readthedocs.io/en/latest/077_troubleshooting.html#find-out-what-is-damaged"
74
+ target="_blank"
75
+ rel="noreferrer"
76
+ >
77
+ here.
78
+ </a>
79
+ </p>
80
+ </div>
81
+ </div>
82
+ );
83
+ };
84
+
85
+ const renderBackupStatus = (storageType: string) => {
86
+ if (!integrityResultLoaded) return null;
87
+ if (integrityCheckMutation.isPending) return null;
88
+ const backupResData = getBackupResultByStorage(storageType);
89
+ const backupHasError = backupResData?.hasError;
90
+ const backupMessage = backupResData?.message;
91
+
92
+ if (!backupHasError && backupMessage?.includes('No Issue Detected')) {
93
+ return <div className="label success">🥳 Yoohoo! No Corruption or Bit rot found. Your backup snapshots are completely restorable.</div>;
94
+ }
95
+
96
+ return <div className="label error">⛔ Error Found. {backupMessage}</div>;
97
+ };
98
+
99
+ const renderResultWithReplications = () => {
100
+ return (
101
+ <div className={`${classes.integrityResult} ${classes.withReplications}`}>
102
+ {verificationData &&
103
+ Object.entries(verificationData.result as Record<string, PlanVerifiedResult>).map(([storageType]) => {
104
+ let theStorage = storage;
105
+ if (storageType !== 'primary') {
106
+ const mirror = replicationStorages.find((s) => s.storageId === storageType.replace('mirror_', ''));
107
+ if (mirror) {
108
+ theStorage = { name: mirror.storageName as string, type: mirror?.storageType as string, id: mirror?.storageId as string };
109
+ }
110
+ }
111
+ if (!theStorage) return null;
112
+ const backupResData = getBackupResultByStorage(storageType);
113
+ const backupHasError = backupResData?.hasError;
114
+ return (
115
+ <div key={storageType} className={classes.replicationResult}>
116
+ <h4 onClick={() => setShowContent(storageType)} className={showContent === storageType ? classes.active : ''}>
117
+ <span>
118
+ <img src={`/providers/${theStorage.type}.png`} />
119
+ {theStorage.name} <i>{storageType === 'primary' ? 'Primary' : `Mirror`}</i>
120
+ </span>
121
+ <span>
122
+ {backupHasError ? (
123
+ <Icon type="error-circle-filled" size={14} color="#ff4d4f" />
124
+ ) : (
125
+ <Icon type="check-circle-filled" size={14} color="#06ba9f" />
126
+ )}
127
+ </span>
128
+ </h4>
129
+ {showContent === storageType && (
130
+ <div className={classes.replicationResultContent}>
131
+ {renderBackupStatus(storageType)}
132
+ {renderLogs(storageType)}
133
+ {renderBackupFixSuggestion(storageType)}
134
+ </div>
135
+ )}
136
+ </div>
137
+ );
138
+ })}
139
+ </div>
140
+ );
141
+ };
142
+
143
+ return (
144
+ <ActionModal
145
+ title="Check Backup Integrity"
146
+ message={
147
+ <div className={classes.integrityMessage}>
148
+ {!integrityResultLoaded && <p>Check the integrity of the backup snapshots now to check if they are restorable?</p>}
149
+ {integrityResultLoaded && (
150
+ <div>
151
+ {!hasReplications ? (
152
+ <div className={classes.integrityResult}>
153
+ {renderBackupStatus('primary')}
154
+ {renderLogs('primary')}
155
+ {renderBackupFixSuggestion('primary')}
156
+ </div>
157
+ ) : (
158
+ renderResultWithReplications()
159
+ )}
160
+ </div>
161
+ )}
162
+ {integrityCheckMutation.isPending && (
163
+ <div className="label in_progress">
164
+ <Icon type="loading" size={14} />
165
+ Checking integrity...
166
+ </div>
167
+ )}
168
+ </div>
169
+ }
170
+ errorMessage={integrityCheckMutation.error?.message}
171
+ closeModal={() => onClose()}
172
+ width="600px"
173
+ primaryAction={{
174
+ title: integrityResultLoaded ? 'Check Again' : 'Check Now',
175
+ type: 'default',
176
+ isPending: integrityCheckMutation.isPending,
177
+ action: () => !taskPending && integrityCheckMutation.mutate({ planId }),
178
+ }}
179
+ secondaryAction={{
180
+ title: 'Close',
181
+ action: () => onClose(),
182
+ }}
183
+ />
184
+ );
185
+ };
186
+
187
+ export default PlanIntegrity;
@@ -8,6 +8,7 @@ import classes from './PlanItem.module.scss';
8
8
  import { useDeletePlan, usePausePlan, usePerformBackup, useResumePlan } from '../../../services/plans';
9
9
  import { planIntervalName } from '../../../utils/plans';
10
10
  import PlanHistory from '../PlanHistory/PlanHistory';
11
+ import PlanStorageInfo from '../PlanStorageInfo/PlanStorageInfo';
11
12
 
12
13
  interface PlanItemProps {
13
14
  plan: Plan;
@@ -156,9 +157,8 @@ const PlanItem = ({ plan, layout = 'list' }: PlanItemProps) => {
156
157
  )}
157
158
  <span className={classes.sourceCount}>{sourceConfig.includes.length}</span>
158
159
  </span>{' '}
159
- {'-->'} {storage.type && <img src={`/providers/${storage.type}.png`} />}
160
- {storage.name}
161
- {/* {storagePath && storagePath !== '/' && '/' + storagePath} */}
160
+ {'-->'}
161
+ <PlanStorageInfo replicationSettings={plan.settings.replication} storage={storage} storagePath={plan.storagePath} />
162
162
  </div>
163
163
  </NavLink>
164
164
  </div>
@@ -4,13 +4,13 @@ import { useCheckActiveBackupsOrRestore } from '../../../services/plans';
4
4
  import classes from './PlanPendingBackup.module.scss';
5
5
  import Icon from '../../common/Icon/Icon';
6
6
 
7
- interface PlanPendingBackup {
7
+ interface PlanPendingBackupProps {
8
8
  planId: string;
9
9
  type?: 'backup' | 'restore';
10
10
  onPendingDetect: () => void;
11
11
  }
12
12
 
13
- const PlanPendingBackup = ({ planId, type = 'backup', onPendingDetect }: PlanPendingBackup) => {
13
+ const PlanPendingBackup = ({ planId, type = 'backup', onPendingDetect }: PlanPendingBackupProps) => {
14
14
  const [, setSearchParams] = useSearchParams();
15
15
  const checkActivesMutation = useCheckActiveBackupsOrRestore();
16
16
 
@@ -51,7 +51,7 @@ const PlanRemoveModal = ({ planId, taskPending, actionInProgress, close }: PlanR
51
51
  <Toggle
52
52
  fieldValue={removeRemoteData}
53
53
  onUpdate={setRemoveRemoteData}
54
- description={`Remove remote backup data from the Remote Storage`}
54
+ description={`Remove backup data from the Storage`}
55
55
  customClasses={classes.removeRemoteToggle}
56
56
  />
57
57
  </div>
@@ -0,0 +1,105 @@
1
+ .mirrorSection {
2
+ margin-top: 10px;
3
+ padding: 15px 0;
4
+ border-top: 1px solid var(--line-color);
5
+ }
6
+
7
+ .mirrorSettings {
8
+ margin-top: 15px;
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: 15px;
12
+ }
13
+
14
+ .mirrorDestination {
15
+ padding: 15px;
16
+ border: 1px solid var(--field-line-color);
17
+ border-radius: 6px;
18
+ }
19
+
20
+ .mirrorHeader {
21
+ display: flex;
22
+ justify-content: space-between;
23
+ align-items: center;
24
+ margin-bottom: 10px;
25
+
26
+ label {
27
+ margin-bottom: 0 !important;
28
+ }
29
+ }
30
+
31
+ .mirrorHeaderRight {
32
+ display: flex;
33
+ gap: 6px;
34
+ .confirmBtn {
35
+ color: var(--primary-color);
36
+ background-color: var(--primary-color-light);
37
+ font-size: 0.7rem;
38
+ display: flex;
39
+ align-items: center;
40
+ gap: 4px;
41
+ padding: 4px 8px;
42
+ border-radius: 4px;
43
+ transition: all 0.12s linear;
44
+ &:hover:not(:disabled) {
45
+ background-color: var(--primary-color);
46
+ color: var(--primary-color-light);
47
+ }
48
+ &:disabled {
49
+ opacity: 0.6;
50
+ cursor: not-allowed;
51
+ }
52
+ }
53
+ .removeBtn {
54
+ color: var(--error-button-color);
55
+ font-size: 0.75rem;
56
+ display: flex;
57
+ align-items: center;
58
+ gap: 4px;
59
+ padding: 4px 8px;
60
+ border-radius: 4px;
61
+ transition: all 0.12s linear;
62
+ &:hover {
63
+ background-color: var(--error-bg-color);
64
+ }
65
+ }
66
+
67
+ .storagePositionControls {
68
+ button {
69
+ color: var(--icon-color);
70
+ &:hover {
71
+ color: var(--primary-color);
72
+ }
73
+ &:disabled {
74
+ opacity: 0.4;
75
+ color: var(--icon-color);
76
+ cursor: not-allowed;
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ .addMirrorBtn {
83
+ display: flex;
84
+ align-items: center;
85
+ gap: 6px;
86
+ padding: 10px 16px;
87
+ border: 1px dashed var(--field-line-color);
88
+ border-radius: 6px;
89
+ color: var(--content-text-color-light);
90
+ font-size: 0.75rem;
91
+ width: 100%;
92
+ justify-content: center;
93
+ transition: all 0.12s linear;
94
+ &:hover {
95
+ border-color: var(--primary-color);
96
+ color: var(--primary-color);
97
+ background-color: var(--primary-color-light);
98
+ }
99
+ }
100
+
101
+ .concurrentOption {
102
+ margin-top: 5px;
103
+ padding-top: 10px;
104
+ border-top: 1px solid var(--line-color);
105
+ }