@plutonhq/core-frontend 0.1.31 → 0.1.33
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/plans.d.ts +4 -0
- package/dist-lib/@types/plans.d.ts.map +1 -1
- package/dist-lib/components/Plan/AddPlan/AddPlan.d.ts.map +1 -1
- package/dist-lib/components/Plan/AddPlan/AddPlan.js +29 -24
- package/dist-lib/components/Plan/AddPlan/AddPlan.js.map +1 -1
- package/dist-lib/components/Plan/BackupEvents/BackupEvents.js +33 -33
- package/dist-lib/components/Plan/BackupEvents/BackupEvents.js.map +1 -1
- package/dist-lib/components/Plan/BackupEvents/BackupEvents.module.scss.js +36 -36
- package/dist-lib/components/Plan/BackupProgress/BackupProgress.d.ts.map +1 -1
- package/dist-lib/components/Plan/BackupProgress/BackupProgress.js +63 -53
- package/dist-lib/components/Plan/BackupProgress/BackupProgress.js.map +1 -1
- package/dist-lib/components/Plan/BackupProgress/BackupProgress.module.scss.js +32 -32
- package/dist-lib/components/Plan/Backups/Backups.d.ts.map +1 -1
- package/dist-lib/components/Plan/Backups/Backups.js +148 -144
- package/dist-lib/components/Plan/Backups/Backups.js.map +1 -1
- package/dist-lib/components/Plan/Backups/Backups.module.scss.js +34 -32
- package/dist-lib/components/Plan/Backups/Backups.module.scss.js.map +1 -1
- package/dist-lib/components/Plan/FilterPlans/FilterPlans.d.ts +9 -0
- package/dist-lib/components/Plan/FilterPlans/FilterPlans.d.ts.map +1 -0
- package/dist-lib/components/Plan/FilterPlans/FilterPlans.js +117 -0
- package/dist-lib/components/Plan/FilterPlans/FilterPlans.js.map +1 -0
- package/dist-lib/components/Plan/FilterPlans/FilterPlans.module.scss.js +20 -0
- package/dist-lib/components/Plan/FilterPlans/FilterPlans.module.scss.js.map +1 -0
- package/dist-lib/components/Plan/PlanForm/PlanForm.d.ts +4 -2
- package/dist-lib/components/Plan/PlanForm/PlanForm.d.ts.map +1 -1
- package/dist-lib/components/Plan/PlanForm/PlanForm.js +33 -29
- package/dist-lib/components/Plan/PlanForm/PlanForm.js.map +1 -1
- package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.d.ts +2 -1
- package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.d.ts.map +1 -1
- package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.js +85 -57
- package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.js.map +1 -1
- package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.module.scss.js +11 -9
- package/dist-lib/components/Plan/PlanIntegrity/PlanIntegrity.module.scss.js.map +1 -1
- package/dist-lib/components/Plan/PlanItems/PlanItem.js +1 -1
- package/dist-lib/components/Plan/PlanItems/PlanItem.js.map +1 -1
- package/dist-lib/components/Plan/PlanRepair/PlanRepair.d.ts +9 -0
- package/dist-lib/components/Plan/PlanRepair/PlanRepair.d.ts.map +1 -0
- package/dist-lib/components/Plan/PlanRepair/PlanRepair.js +262 -0
- package/dist-lib/components/Plan/PlanRepair/PlanRepair.js.map +1 -0
- package/dist-lib/components/Plan/PlanRepair/PlanRepair.module.scss.js +14 -0
- package/dist-lib/components/Plan/PlanRepair/PlanRepair.module.scss.js.map +1 -0
- package/dist-lib/components/Plan/PlanSettings/PlanAdvancedSettings.d.ts +4 -2
- package/dist-lib/components/Plan/PlanSettings/PlanAdvancedSettings.d.ts.map +1 -1
- package/dist-lib/components/Plan/PlanSettings/PlanAdvancedSettings.js +24 -22
- package/dist-lib/components/Plan/PlanSettings/PlanAdvancedSettings.js.map +1 -1
- package/dist-lib/components/Plan/PlanSettings/PlanGeneralSettings.d.ts +4 -2
- package/dist-lib/components/Plan/PlanSettings/PlanGeneralSettings.d.ts.map +1 -1
- package/dist-lib/components/Plan/PlanSettings/PlanGeneralSettings.js +39 -28
- package/dist-lib/components/Plan/PlanSettings/PlanGeneralSettings.js.map +1 -1
- package/dist-lib/components/Plan/PlanSettings/PlanSettings.module.scss.js +66 -64
- package/dist-lib/components/Plan/PlanSettings/PlanSettings.module.scss.js.map +1 -1
- package/dist-lib/components/Plan/PlanSizeChart/PlanSizeChart.d.ts +7 -0
- package/dist-lib/components/Plan/PlanSizeChart/PlanSizeChart.d.ts.map +1 -0
- package/dist-lib/components/Plan/PlanSizeChart/PlanSizeChart.js +116 -0
- package/dist-lib/components/Plan/PlanSizeChart/PlanSizeChart.js.map +1 -0
- package/dist-lib/components/Plan/PlanSizeChart/PlanSizeChart.module.scss.js +20 -0
- package/dist-lib/components/Plan/PlanSizeChart/PlanSizeChart.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 +29 -30
- package/dist-lib/components/Plan/PlanStats/PlanStats.js.map +1 -1
- package/dist-lib/components/Plan/PlanStats/PlanStats.module.scss.js +16 -14
- package/dist-lib/components/Plan/PlanStats/PlanStats.module.scss.js.map +1 -1
- package/dist-lib/components/common/Icon/Icon.d.ts.map +1 -1
- package/dist-lib/components/common/Icon/Icon.js +395 -378
- package/dist-lib/components/common/Icon/Icon.js.map +1 -1
- package/dist-lib/components/common/SortItems/SortItems.d.ts +2 -1
- package/dist-lib/components/common/SortItems/SortItems.d.ts.map +1 -1
- package/dist-lib/components/common/SortItems/SortItems.js +14 -14
- package/dist-lib/components/common/SortItems/SortItems.js.map +1 -1
- package/dist-lib/components/common/SortItems/SortItems.module.scss.js +1 -1
- package/dist-lib/components/common/form/MultiSelect/MultiSelect.module.scss.js +16 -16
- package/dist-lib/components/index.d.ts +2 -0
- package/dist-lib/components/index.d.ts.map +1 -1
- package/dist-lib/components.js +199 -195
- package/dist-lib/components.js.map +1 -1
- package/dist-lib/hooks/usePlanSingleActions.d.ts.map +1 -1
- package/dist-lib/hooks/usePlanSingleActions.js +22 -19
- package/dist-lib/hooks/usePlanSingleActions.js.map +1 -1
- package/dist-lib/node_modules/.pnpm/@kurkle_color@0.3.4/node_modules/@kurkle/color/dist/color.esm.js +449 -0
- package/dist-lib/node_modules/.pnpm/@kurkle_color@0.3.4/node_modules/@kurkle/color/dist/color.esm.js.map +1 -0
- package/dist-lib/node_modules/.pnpm/chart.js@4.5.1/node_modules/chart.js/dist/chart.js +5219 -0
- package/dist-lib/node_modules/.pnpm/chart.js@4.5.1/node_modules/chart.js/dist/chart.js.map +1 -0
- package/dist-lib/node_modules/.pnpm/chart.js@4.5.1/node_modules/chart.js/dist/chunks/helpers.dataset.js +1691 -0
- package/dist-lib/node_modules/.pnpm/chart.js@4.5.1/node_modules/chart.js/dist/chunks/helpers.dataset.js.map +1 -0
- package/dist-lib/node_modules/.pnpm/react-chartjs-2@5.3.1_chart.js@4.5.1_react@18.3.1/node_modules/react-chartjs-2/dist/index.js +93 -0
- package/dist-lib/node_modules/.pnpm/react-chartjs-2@5.3.1_chart.js@4.5.1_react@18.3.1/node_modules/react-chartjs-2/dist/index.js.map +1 -0
- package/dist-lib/routes/Login/Login.d.ts.map +1 -1
- package/dist-lib/routes/Login/Login.js +45 -36
- package/dist-lib/routes/Login/Login.js.map +1 -1
- package/dist-lib/routes/PlanSingle/PlanSingle.d.ts.map +1 -1
- package/dist-lib/routes/PlanSingle/PlanSingle.js +131 -118
- package/dist-lib/routes/PlanSingle/PlanSingle.js.map +1 -1
- package/dist-lib/routes/Plans/Plans.d.ts.map +1 -1
- package/dist-lib/routes/Plans/Plans.js +77 -51
- package/dist-lib/routes/Plans/Plans.js.map +1 -1
- package/dist-lib/services/plans.d.ts +33 -5
- package/dist-lib/services/plans.d.ts.map +1 -1
- package/dist-lib/services/plans.js +92 -67
- package/dist-lib/services/plans.js.map +1 -1
- package/dist-lib/services.js +93 -91
- package/dist-lib/styles/core-frontend.css +1 -1
- package/dist-lib/styles/global.scss +4 -0
- package/dist-lib/utils/helpers.d.ts +2 -0
- package/dist-lib/utils/helpers.d.ts.map +1 -1
- package/dist-lib/utils/helpers.js +68 -42
- package/dist-lib/utils/helpers.js.map +1 -1
- package/dist-lib/utils.js +36 -34
- package/package.json +3 -1
- package/src/@types/plans.ts +5 -0
- package/src/components/Plan/AddPlan/AddPlan.tsx +22 -16
- package/src/components/Plan/BackupEvents/BackupEvents.module.scss +2 -0
- package/src/components/Plan/BackupEvents/BackupEvents.tsx +2 -2
- package/src/components/Plan/BackupProgress/BackupProgress.module.scss +1 -0
- package/src/components/Plan/BackupProgress/BackupProgress.tsx +7 -2
- package/src/components/Plan/Backups/Backups.module.scss +16 -0
- package/src/components/Plan/Backups/Backups.tsx +13 -2
- package/src/components/Plan/FilterPlans/FilterPlans.module.scss +65 -0
- package/src/components/Plan/FilterPlans/FilterPlans.tsx +126 -0
- package/src/components/Plan/PlanForm/PlanForm.tsx +7 -1
- package/src/components/Plan/PlanIntegrity/PlanIntegrity.module.scss +19 -0
- package/src/components/Plan/PlanIntegrity/PlanIntegrity.tsx +40 -3
- package/src/components/Plan/PlanItems/PlanItem.tsx +1 -1
- package/src/components/Plan/PlanRepair/PlanRepair.module.scss +53 -0
- package/src/components/Plan/PlanRepair/PlanRepair.tsx +243 -0
- package/src/components/Plan/PlanSettings/PlanAdvancedSettings.tsx +6 -2
- package/src/components/Plan/PlanSettings/PlanGeneralSettings.tsx +14 -2
- package/src/components/Plan/PlanSettings/PlanSettings.module.scss +8 -0
- package/src/components/Plan/PlanSizeChart/PlanSizeChart.module.scss +76 -0
- package/src/components/Plan/PlanSizeChart/PlanSizeChart.tsx +163 -0
- package/src/components/Plan/PlanStats/PlanStats.module.scss +16 -2
- package/src/components/Plan/PlanStats/PlanStats.tsx +8 -11
- package/src/components/common/Icon/Icon.tsx +21 -0
- package/src/components/common/SortItems/SortItems.module.scss +3 -2
- package/src/components/common/SortItems/SortItems.tsx +6 -3
- package/src/components/common/form/MultiSelect/MultiSelect.module.scss +1 -0
- package/src/components/index.ts +2 -0
- package/src/hooks/usePlanSingleActions.tsx +26 -23
- package/src/routes/Login/Login.tsx +8 -2
- package/src/routes/PlanSingle/PlanSingle.tsx +17 -0
- package/src/routes/Plans/Plans.tsx +70 -35
- package/src/services/plans.ts +40 -4
- package/src/styles/global.scss +4 -0
- package/src/utils/helpers.ts +25 -0
|
@@ -233,6 +233,22 @@
|
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
+
.errorDetailsModal {
|
|
237
|
+
width: 100%;
|
|
238
|
+
max-height: 500px;
|
|
239
|
+
overflow: auto;
|
|
240
|
+
font-family: monospace;
|
|
241
|
+
box-sizing: border-box;
|
|
242
|
+
border-radius: 6px;
|
|
243
|
+
background-color: var(--primary-color-lighter);
|
|
244
|
+
p {
|
|
245
|
+
border-bottom: 1px solid;
|
|
246
|
+
padding: 12px;
|
|
247
|
+
margin: 0;
|
|
248
|
+
border-color: var(--line-color);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
236
252
|
@media only screen and (max-width: 768px) {
|
|
237
253
|
.backupsTable {
|
|
238
254
|
overflow: auto;
|
|
@@ -21,7 +21,7 @@ import BackupEvents from '../BackupEvents/BackupEvents';
|
|
|
21
21
|
import Input from '../../common/form/Input/Input';
|
|
22
22
|
import MirrorStatusBadge from '../Mirrors/MirrorStatusBadge';
|
|
23
23
|
import MirrorStorageSelectorModal from '../Mirrors/MirrorStorageSelectorModal';
|
|
24
|
-
import { SidePanel, SnapshotViewer } from '../..';
|
|
24
|
+
import { Modal, SidePanel, SnapshotViewer } from '../..';
|
|
25
25
|
|
|
26
26
|
const DownloadLabel = ({ download, downloadBackup }: { download: Backup['download']; downloadBackup: () => void }) => {
|
|
27
27
|
if (download?.status === 'started') {
|
|
@@ -101,6 +101,7 @@ const Backups = ({
|
|
|
101
101
|
const [showRestoreModal, setShowRestoreModal] = useState<Backup | false>(false);
|
|
102
102
|
const [showBackupEvents, setShowBackupEvents] = useState<false | string>(false);
|
|
103
103
|
const [showSnapshotViewer, setShowSnapshotViewer] = useState<Backup | false>(false);
|
|
104
|
+
const [showBackupError, setShowBackupError] = useState<string | false>(false);
|
|
104
105
|
const [showEditModal, setShowEditModal] = useState<Backup | false>(false);
|
|
105
106
|
const [showStorageSelector, setShowStorageSelector] = useState<Backup | false>(false);
|
|
106
107
|
const queryClient = useQueryClient();
|
|
@@ -240,8 +241,9 @@ const Backups = ({
|
|
|
240
241
|
<div
|
|
241
242
|
className={`${classes.status} ${errorMsg ? classes.statusHasError : ''}`}
|
|
242
243
|
data-tooltip-id="htmlToolTip"
|
|
243
|
-
data-tooltip-html={`<div><string>Error</string>: ${errorMsg}</div>`}
|
|
244
|
+
data-tooltip-html={`<div class="linebreak-tooltip-content"><string>Error</string>: ${errorMsg?.slice(0, 120) + (errorMsg && errorMsg.length > 120 ? '...' : '')}</div>`}
|
|
244
245
|
data-tooltip-hidden={!errorMsg}
|
|
246
|
+
onClick={() => errorMsg && errorMsg.length > 120 && setShowBackupError(errorMsg)}
|
|
245
247
|
>
|
|
246
248
|
<StatusLabel status={status} hasError={!!errorMsg} />
|
|
247
249
|
</div>
|
|
@@ -453,6 +455,15 @@ const Backups = ({
|
|
|
453
455
|
/>
|
|
454
456
|
</SidePanel>
|
|
455
457
|
)}
|
|
458
|
+
{showBackupError && (
|
|
459
|
+
<Modal title="Error Details" closeModal={() => setShowBackupError(false)} width={'600px'}>
|
|
460
|
+
<div className={`${classes.errorDetailsModal} styled__scrollbar`}>
|
|
461
|
+
{showBackupError.split('\n').map((line, index) => (
|
|
462
|
+
<p key={index}>{line}</p>
|
|
463
|
+
))}
|
|
464
|
+
</div>
|
|
465
|
+
</Modal>
|
|
466
|
+
)}
|
|
456
467
|
</div>
|
|
457
468
|
);
|
|
458
469
|
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
.filterItems {
|
|
2
|
+
position: relative;
|
|
3
|
+
.filterBtn {
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
.filterCount {
|
|
7
|
+
background-color: var(--primary-color);
|
|
8
|
+
color: var(--primary-text-color);
|
|
9
|
+
padding: 1px 6px;
|
|
10
|
+
border-radius: 12px;
|
|
11
|
+
font-size: 10px;
|
|
12
|
+
}
|
|
13
|
+
&.filterBtnActive {
|
|
14
|
+
color: var(--primary-color);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
.dropdown {
|
|
18
|
+
margin-top: -1px;
|
|
19
|
+
position: absolute;
|
|
20
|
+
z-index: 9999;
|
|
21
|
+
border: 1px solid var(--line-color);
|
|
22
|
+
background: var(--field-bg);
|
|
23
|
+
box-shadow: 0 0 15px var(--content-shadow-color);
|
|
24
|
+
width: calc(100% - 2px);
|
|
25
|
+
border-radius: 0 0 4px 4px;
|
|
26
|
+
overflow: auto;
|
|
27
|
+
font-size: 0.75rem;
|
|
28
|
+
right: 0;
|
|
29
|
+
width: max-content;
|
|
30
|
+
max-height: 320px;
|
|
31
|
+
border-radius: 6px;
|
|
32
|
+
|
|
33
|
+
.field {
|
|
34
|
+
padding: 12px 12px 0 12px;
|
|
35
|
+
label {
|
|
36
|
+
font-weight: 600;
|
|
37
|
+
margin-bottom: 4px;
|
|
38
|
+
display: block;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
.footer {
|
|
42
|
+
border-top: 1px solid var(--line-color);
|
|
43
|
+
margin-top: 12px;
|
|
44
|
+
display: flex;
|
|
45
|
+
justify-content: space-around;
|
|
46
|
+
button:nth-child(2) {
|
|
47
|
+
padding: 6px 10px;
|
|
48
|
+
background: var(--primary-color-light);
|
|
49
|
+
color: var(--primary-color);
|
|
50
|
+
line-height: 1em;
|
|
51
|
+
height: fit-content;
|
|
52
|
+
border-radius: 4px;
|
|
53
|
+
margin: 8px;
|
|
54
|
+
font-weight: 600;
|
|
55
|
+
&:hover {
|
|
56
|
+
background: var(--primary-color);
|
|
57
|
+
color: var(--primary-text-color);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
button:hover {
|
|
61
|
+
color: var(--primary-color);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { useMemo, useState } from 'react';
|
|
2
|
+
import classes from './FilterPlans.module.scss';
|
|
3
|
+
import { Plan } from '../../..';
|
|
4
|
+
import { Icon, MultiSelect } from '../..';
|
|
5
|
+
|
|
6
|
+
type FilterPlansProps = {
|
|
7
|
+
onUpdate: (s: Record<PlanFilterTypes, string[]> | null) => void;
|
|
8
|
+
plans: Plan[];
|
|
9
|
+
};
|
|
10
|
+
export type PlanFilterTypes = 'devices' | 'tags' | 'storages' | 'methods';
|
|
11
|
+
|
|
12
|
+
const defaultState = { devices: [], tags: [], storages: [], methods: [] };
|
|
13
|
+
|
|
14
|
+
const FilterPlans = ({ onUpdate, plans }: FilterPlansProps) => {
|
|
15
|
+
const [showDropDown, setShowDropDown] = useState(false);
|
|
16
|
+
const [selected, setSelected] = useState<Record<PlanFilterTypes, string[]>>(() => {
|
|
17
|
+
const storedSettingsRaw = localStorage.getItem('plans_filter');
|
|
18
|
+
const storedSettings = storedSettingsRaw ? JSON.parse(storedSettingsRaw) : null;
|
|
19
|
+
return storedSettings || defaultState;
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const hasFilters = Object.values(selected).some((arr) => arr.length > 0);
|
|
23
|
+
|
|
24
|
+
const filterableItems = useMemo(() => {
|
|
25
|
+
const items: Record<PlanFilterTypes, { label: string; value: string }[]> = { devices: [], tags: [], storages: [], methods: [] };
|
|
26
|
+
plans.forEach((plan) => {
|
|
27
|
+
plan.tags.forEach((tag) => {
|
|
28
|
+
if (!items.tags.find((t) => t.value === tag)) {
|
|
29
|
+
items.tags.push({ label: tag, value: tag });
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
if (!items.devices.find((t) => t.value === plan.device.id)) {
|
|
33
|
+
items.devices.push({ label: plan.device.name, value: plan.device.id });
|
|
34
|
+
}
|
|
35
|
+
if (!items.storages.find((t) => t.value === plan.storage.id)) {
|
|
36
|
+
items.storages.push({ label: plan.storage.name, value: plan.storage.id });
|
|
37
|
+
}
|
|
38
|
+
if (!items.methods.find((t) => t.value === plan.method)) {
|
|
39
|
+
items.methods.push({ label: plan.method, value: plan.method });
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return items;
|
|
43
|
+
}, [plans]);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<div className={classes.filterItems}>
|
|
47
|
+
<button
|
|
48
|
+
className={`${classes.filterBtn} ${showDropDown || hasFilters ? classes.filterBtnActive : ''}`}
|
|
49
|
+
onClick={() => setShowDropDown(!showDropDown)}
|
|
50
|
+
data-tooltip-id="appTooltip"
|
|
51
|
+
data-tooltip-content="Filter"
|
|
52
|
+
aria-label="Filter Plans"
|
|
53
|
+
data-tooltip-place="top"
|
|
54
|
+
data-tooltip-delay-show={500}
|
|
55
|
+
>
|
|
56
|
+
<Icon type="filter" size={18} />{' '}
|
|
57
|
+
{hasFilters && <span className={classes.filterCount}>{Object.values(selected).reduce((acc, arr) => acc + arr.length, 0)}</span>}
|
|
58
|
+
</button>
|
|
59
|
+
{showDropDown && (
|
|
60
|
+
<div className={`${classes.dropdown} styled__scrollbar`}>
|
|
61
|
+
{filterableItems.devices.length > 1 && (
|
|
62
|
+
<div className={classes.field}>
|
|
63
|
+
<label>Devices</label>
|
|
64
|
+
<MultiSelect
|
|
65
|
+
title="Devices"
|
|
66
|
+
fieldValue={selected.devices}
|
|
67
|
+
options={filterableItems.devices}
|
|
68
|
+
onUpdate={(devices) => setSelected((selected) => ({ ...selected, devices }))}
|
|
69
|
+
/>
|
|
70
|
+
</div>
|
|
71
|
+
)}
|
|
72
|
+
<div className={classes.field}>
|
|
73
|
+
<label>Backup Type</label>
|
|
74
|
+
<MultiSelect
|
|
75
|
+
title="Backup Type"
|
|
76
|
+
fieldValue={selected.methods}
|
|
77
|
+
options={filterableItems.methods}
|
|
78
|
+
onUpdate={(methods) => setSelected((selected) => ({ ...selected, methods }))}
|
|
79
|
+
/>
|
|
80
|
+
</div>
|
|
81
|
+
<div className={classes.field}>
|
|
82
|
+
<label>Storage</label>
|
|
83
|
+
<MultiSelect
|
|
84
|
+
title="Storages"
|
|
85
|
+
fieldValue={selected.storages}
|
|
86
|
+
options={filterableItems.storages}
|
|
87
|
+
onUpdate={(storages) => setSelected((selected) => ({ ...selected, storages }))}
|
|
88
|
+
/>
|
|
89
|
+
</div>
|
|
90
|
+
<div className={classes.field}>
|
|
91
|
+
<label>Tags</label>
|
|
92
|
+
<MultiSelect
|
|
93
|
+
title="Tags"
|
|
94
|
+
fieldValue={selected.tags}
|
|
95
|
+
options={filterableItems.tags}
|
|
96
|
+
onUpdate={(tags) => setSelected((selected) => ({ ...selected, tags }))}
|
|
97
|
+
/>
|
|
98
|
+
</div>
|
|
99
|
+
<div className={classes.footer}>
|
|
100
|
+
<button
|
|
101
|
+
onClick={() => {
|
|
102
|
+
localStorage.removeItem('plans_filter');
|
|
103
|
+
setSelected(defaultState);
|
|
104
|
+
onUpdate(null);
|
|
105
|
+
setShowDropDown(false);
|
|
106
|
+
}}
|
|
107
|
+
>
|
|
108
|
+
<Icon type="reload" /> Reset
|
|
109
|
+
</button>
|
|
110
|
+
<button
|
|
111
|
+
onClick={() => {
|
|
112
|
+
localStorage.setItem('plans_filter', JSON.stringify(selected));
|
|
113
|
+
onUpdate(selected);
|
|
114
|
+
setShowDropDown(false);
|
|
115
|
+
}}
|
|
116
|
+
>
|
|
117
|
+
<Icon type="check" size={12} /> Apply
|
|
118
|
+
</button>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
)}
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export default FilterPlans;
|
|
@@ -4,7 +4,7 @@ import SidePanel from '../../common/SidePanel/SidePanel';
|
|
|
4
4
|
import StoragePicker from '../../common/form/StoragePicker/StoragePicker';
|
|
5
5
|
import PlanStrategySettings from '../PlanSettings/PlanStrategySettings';
|
|
6
6
|
import PlanSourceSettings from '../PlanSettings/PlanSourceSettings';
|
|
7
|
-
import { NewPlanSettings } from '../../../@types/plans';
|
|
7
|
+
import { NewPlanSettings, PlanAddRunSettings } from '../../../@types/plans';
|
|
8
8
|
import classes from '../AddPlan/AddPlan.module.scss';
|
|
9
9
|
import PFClasses from './PlanForm.module.scss';
|
|
10
10
|
import { useGetSettings } from '../../../services/settings';
|
|
@@ -27,6 +27,8 @@ type PlanFormProps = {
|
|
|
27
27
|
storagePath?: string;
|
|
28
28
|
storageId?: string;
|
|
29
29
|
planId?: string;
|
|
30
|
+
runSettings?: PlanAddRunSettings;
|
|
31
|
+
setRunSettings?: (runSettings: PlanAddRunSettings) => void;
|
|
30
32
|
};
|
|
31
33
|
|
|
32
34
|
const PlanForm = ({
|
|
@@ -40,6 +42,8 @@ const PlanForm = ({
|
|
|
40
42
|
storagePath,
|
|
41
43
|
storageId,
|
|
42
44
|
planId,
|
|
45
|
+
runSettings,
|
|
46
|
+
setRunSettings,
|
|
43
47
|
}: PlanFormProps) => {
|
|
44
48
|
const [step, setStep] = useState<number>(1);
|
|
45
49
|
|
|
@@ -279,6 +283,8 @@ const PlanForm = ({
|
|
|
279
283
|
onUpdate={onPlanSettingsChange}
|
|
280
284
|
device={deviceInstance}
|
|
281
285
|
isEditing={type === 'edit'}
|
|
286
|
+
runSettings={runSettings}
|
|
287
|
+
setRunSettings={setRunSettings}
|
|
282
288
|
/>
|
|
283
289
|
</div>
|
|
284
290
|
)}
|
|
@@ -103,6 +103,25 @@
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
.repairBox {
|
|
107
|
+
border: 1px solid var(--line-color);
|
|
108
|
+
padding: 12px;
|
|
109
|
+
margin: 15px 5px;
|
|
110
|
+
box-sizing: border-box;
|
|
111
|
+
border-radius: 6px;
|
|
112
|
+
border-color: var(--primary-color-mid) #aaacff;
|
|
113
|
+
background: var(--background-color);
|
|
114
|
+
|
|
115
|
+
button {
|
|
116
|
+
background-color: var(--primary-color);
|
|
117
|
+
color: var(--primary-text-color);
|
|
118
|
+
padding: 6px 12px;
|
|
119
|
+
cursor: pointer;
|
|
120
|
+
border-radius: 4px;
|
|
121
|
+
margin-top: 6px;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
106
125
|
@media only screen and (max-width: 768px) {
|
|
107
126
|
.integrityLogs .integrityLogsHeader {
|
|
108
127
|
flex-direction: column;
|
|
@@ -13,9 +13,10 @@ interface PlanIntegrityProps {
|
|
|
13
13
|
storage: { name: string; type: string; id: string };
|
|
14
14
|
replicationStorages: PlanReplicationStorage[];
|
|
15
15
|
onClose: () => void;
|
|
16
|
+
onRepairOpen: (replicationId: string) => void;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
const PlanIntegrity = ({ planId, taskPending, verificationData, storage, replicationStorages = [], onClose }: PlanIntegrityProps) => {
|
|
19
|
+
const PlanIntegrity = ({ planId, taskPending, verificationData, storage, replicationStorages = [], onClose, onRepairOpen }: PlanIntegrityProps) => {
|
|
19
20
|
const [showContent, setShowContent] = useState('primary');
|
|
20
21
|
const integrityCheckMutation = useCheckPlanIntegrity();
|
|
21
22
|
|
|
@@ -67,6 +68,11 @@ const PlanIntegrity = ({ planId, taskPending, verificationData, storage, replica
|
|
|
67
68
|
.split('\n')
|
|
68
69
|
.map((line, index) => <p key={index}>{line.includes('`') ? <code>{line.replace(/`/g, '')}</code> : line}</p>)}
|
|
69
70
|
{!backupResData.fix && <p>No Suggestion for this issue.</p>}
|
|
71
|
+
{(backupResData.errorType === 'pack_file_error' || backupResData.errorType === 'index_error') && (
|
|
72
|
+
<p>
|
|
73
|
+
<button onClick={() => onRepairOpen(storageType)}>Open Repo Repair</button> Window for more options.
|
|
74
|
+
</p>
|
|
75
|
+
)}
|
|
70
76
|
<p>
|
|
71
77
|
Learn more about fixing restic repo issues{' '}
|
|
72
78
|
<a
|
|
@@ -96,6 +102,37 @@ const PlanIntegrity = ({ planId, taskPending, verificationData, storage, replica
|
|
|
96
102
|
return <div className="label error">⛔ Error Found. {backupMessage}</div>;
|
|
97
103
|
};
|
|
98
104
|
|
|
105
|
+
const renderRepairContent = (storageType: string) => {
|
|
106
|
+
const backupResData = getBackupResultByStorage(storageType);
|
|
107
|
+
return (
|
|
108
|
+
<div className={classes.repairBox}>
|
|
109
|
+
{(backupResData?.errorType === 'pack_file_error' || backupResData?.errorType === 'repairable_pack_file_error') && (
|
|
110
|
+
<div>
|
|
111
|
+
Some pack files in the repository are either damaged or missing and can be repaired.{' '}
|
|
112
|
+
<button onClick={() => onRepairOpen(storageType)}>
|
|
113
|
+
<Icon type="repair" size={13} /> Open Repo Repair Tool
|
|
114
|
+
</button>
|
|
115
|
+
</div>
|
|
116
|
+
)}
|
|
117
|
+
{backupResData?.errorType === 'index_error' && (
|
|
118
|
+
<div>
|
|
119
|
+
The index files in the repository are corrupted and can be repaired.{' '}
|
|
120
|
+
<button onClick={() => onRepairOpen(storageType)}>
|
|
121
|
+
<Icon type="repair" size={13} /> Open Repo Repair Tool
|
|
122
|
+
</button>{' '}
|
|
123
|
+
</div>
|
|
124
|
+
)}
|
|
125
|
+
</div>
|
|
126
|
+
);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const renderRepairOrFixSuggestion = (storageType: string) => {
|
|
130
|
+
const backupResData = getBackupResultByStorage(storageType);
|
|
131
|
+
const errorType = backupResData?.errorType;
|
|
132
|
+
const isRepairable = errorType === 'pack_file_error' || errorType === 'index_error' || errorType === 'repairable_pack_file_error';
|
|
133
|
+
return isRepairable ? renderRepairContent(storageType) : renderBackupFixSuggestion(storageType);
|
|
134
|
+
};
|
|
135
|
+
|
|
99
136
|
const renderResultWithReplications = () => {
|
|
100
137
|
return (
|
|
101
138
|
<div className={`${classes.integrityResult} ${classes.withReplications}`}>
|
|
@@ -130,7 +167,7 @@ const PlanIntegrity = ({ planId, taskPending, verificationData, storage, replica
|
|
|
130
167
|
<div className={classes.replicationResultContent}>
|
|
131
168
|
{renderBackupStatus(storageType)}
|
|
132
169
|
{renderLogs(storageType)}
|
|
133
|
-
{
|
|
170
|
+
{renderRepairOrFixSuggestion(storageType)}
|
|
134
171
|
</div>
|
|
135
172
|
)}
|
|
136
173
|
</div>
|
|
@@ -152,7 +189,7 @@ const PlanIntegrity = ({ planId, taskPending, verificationData, storage, replica
|
|
|
152
189
|
<div className={classes.integrityResult}>
|
|
153
190
|
{renderBackupStatus('primary')}
|
|
154
191
|
{renderLogs('primary')}
|
|
155
|
-
{
|
|
192
|
+
{renderRepairOrFixSuggestion('primary')}
|
|
156
193
|
</div>
|
|
157
194
|
) : (
|
|
158
195
|
renderResultWithReplications()
|
|
@@ -79,7 +79,7 @@ const PlanItem = ({ plan, layout = 'list' }: PlanItemProps) => {
|
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
81
81
|
toast.promise(
|
|
82
|
-
performBackupMutation.mutateAsync(id),
|
|
82
|
+
performBackupMutation.mutateAsync({ id }),
|
|
83
83
|
{
|
|
84
84
|
pending: `Starting ${isSync ? 'Sync' : 'Backup'}...`,
|
|
85
85
|
success: `${isSync ? 'Sync' : 'Backup'} initiated successfully! 🚀`,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
.repairContainer {
|
|
2
|
+
position: relative;
|
|
3
|
+
small {
|
|
4
|
+
padding: 12px 0;
|
|
5
|
+
display: block;
|
|
6
|
+
}
|
|
7
|
+
.repairContent {
|
|
8
|
+
border: 1px solid var(--line-color);
|
|
9
|
+
border-radius: 6px;
|
|
10
|
+
button {
|
|
11
|
+
background: var(--background-color);
|
|
12
|
+
border-radius: 20px;
|
|
13
|
+
line-height: 1.7em;
|
|
14
|
+
color: var(--primary-color);
|
|
15
|
+
padding: 2px 10px;
|
|
16
|
+
transition: all 0.1s linear;
|
|
17
|
+
&:hover {
|
|
18
|
+
background: var(--primary-color);
|
|
19
|
+
color: var(--primary-text-color);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
.repairTitle {
|
|
23
|
+
background: var(--background-color);
|
|
24
|
+
margin-top: 0;
|
|
25
|
+
font-weight: 600;
|
|
26
|
+
font-size: 1.1em;
|
|
27
|
+
padding: 12px;
|
|
28
|
+
}
|
|
29
|
+
p {
|
|
30
|
+
padding: 16px 8px;
|
|
31
|
+
border-bottom: 1px solid var(--line-color);
|
|
32
|
+
margin: 0;
|
|
33
|
+
}
|
|
34
|
+
p:last-child {
|
|
35
|
+
border-bottom: none;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
.overlay {
|
|
39
|
+
position: absolute;
|
|
40
|
+
width: 100%;
|
|
41
|
+
height: 100%;
|
|
42
|
+
top: 0;
|
|
43
|
+
left: 0;
|
|
44
|
+
opacity: 0.95;
|
|
45
|
+
background-color: var(--modal-bg);
|
|
46
|
+
z-index: 3;
|
|
47
|
+
justify-content: center;
|
|
48
|
+
align-items: center;
|
|
49
|
+
display: flex;
|
|
50
|
+
border: 1px solid var(--line-color);
|
|
51
|
+
border-radius: 6px;
|
|
52
|
+
}
|
|
53
|
+
}
|