@postgres.ai/shared 4.0.2-pr-1149.1 → 4.0.2-pr-1200
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/components/UpgradeCloneModal/index.d.ts +11 -0
- package/components/UpgradeCloneModal/index.js +75 -0
- package/package.json +1 -1
- package/pages/Branches/Branch/index.js +27 -2
- package/pages/Branches/Branch/stores/Main.d.ts +5 -0
- package/pages/Branches/Branch/stores/Main.js +29 -0
- package/pages/Branches/components/BranchesTable/index.js +2 -2
- package/pages/Branches/index.js +10 -1
- package/pages/Clone/Status/index.js +3 -0
- package/pages/Clone/index.js +12 -4
- package/pages/Clone/stores/Main.d.ts +9 -1
- package/pages/Clone/stores/Main.js +40 -3
- package/pages/CreateBranch/stores/Main.d.ts +3 -0
- package/pages/CreateClone/index.js +2 -0
- package/pages/CreateClone/stores/Main.d.ts +5 -1
- package/pages/CreateClone/stores/Main.js +8 -3
- package/pages/Instance/Configuration/PhysicalMode/EnvsEditor/index.d.ts +13 -0
- package/pages/Instance/Configuration/PhysicalMode/EnvsEditor/index.js +31 -0
- package/pages/Instance/Configuration/PhysicalMode/PgBackRest/index.d.ts +10 -0
- package/pages/Instance/Configuration/PhysicalMode/PgBackRest/index.js +29 -0
- package/pages/Instance/Configuration/PhysicalMode/Sync/index.d.ts +9 -0
- package/pages/Instance/Configuration/PhysicalMode/Sync/index.js +14 -0
- package/pages/Instance/Configuration/PhysicalMode/Walg/index.d.ts +10 -0
- package/pages/Instance/Configuration/PhysicalMode/Walg/index.js +21 -0
- package/pages/Instance/Configuration/PhysicalMode/index.d.ts +10 -0
- package/pages/Instance/Configuration/PhysicalMode/index.js +17 -0
- package/pages/Instance/Configuration/SimpleMode/PreviewCard.d.ts +13 -0
- package/pages/Instance/Configuration/SimpleMode/PreviewCard.js +14 -0
- package/pages/Instance/Configuration/SimpleMode/index.d.ts +19 -0
- package/pages/Instance/Configuration/SimpleMode/index.js +166 -0
- package/pages/Instance/Configuration/configMode.d.ts +2 -0
- package/pages/Instance/Configuration/configMode.js +7 -0
- package/pages/Instance/Configuration/configOptions.d.ts +16 -0
- package/pages/Instance/Configuration/configOptions.js +71 -0
- package/pages/Instance/Configuration/connectionString.d.ts +20 -0
- package/pages/Instance/Configuration/connectionString.js +129 -0
- package/pages/Instance/Configuration/dockerCatalog.d.ts +2 -0
- package/pages/Instance/Configuration/dockerCatalog.js +19 -0
- package/pages/Instance/Configuration/index.d.ts +1 -2
- package/pages/Instance/Configuration/index.js +115 -86
- package/pages/Instance/Configuration/useForm.d.ts +20 -0
- package/pages/Instance/Configuration/useForm.js +126 -5
- package/pages/Instance/Configuration/utils/index.js +1 -17
- package/pages/Instance/Info/Snapshots/Calendar/Day/index.js +3 -3
- package/pages/Instance/Info/Snapshots/Calendar/utils.d.ts +3 -0
- package/pages/Instance/Info/Snapshots/utils.d.ts +6 -0
- package/pages/Instance/Snapshots/components/SnapshotsList/index.js +11 -1
- package/pages/Instance/Snapshots/index.js +11 -3
- package/pages/Instance/Snapshots/utils/index.d.ts +3 -0
- package/pages/Instance/Tabs/styles.js +6 -6
- package/pages/Instance/index.js +1 -3
- package/pages/Instance/stores/Main.d.ts +22 -2
- package/pages/Instance/stores/Main.js +26 -9
- package/pages/Snapshots/Snapshot/index.js +28 -2
- package/pages/Snapshots/Snapshot/stores/Main.d.ts +5 -0
- package/pages/Snapshots/Snapshot/stores/Main.js +29 -0
- package/stores/Snapshots.d.ts +1 -1
- package/stores/Snapshots.js +12 -6
- package/types/api/endpoints/getBranches.d.ts +6 -0
- package/types/api/endpoints/probeSource.d.ts +32 -0
- package/types/api/endpoints/probeSource.js +1 -0
- package/types/api/endpoints/testDbSource.d.ts +3 -1
- package/types/api/endpoints/testDbSource.js +6 -0
- package/types/api/endpoints/updateBranch.d.ts +11 -0
- package/types/api/endpoints/updateBranch.js +1 -0
- package/types/api/endpoints/updateSnapshot.d.ts +11 -0
- package/types/api/endpoints/updateSnapshot.js +1 -0
- package/types/api/endpoints/upgradeClone.d.ts +8 -0
- package/types/api/endpoints/upgradeClone.js +1 -0
- package/types/api/entities/branchSnapshots.d.ts +3 -0
- package/types/api/entities/clone.d.ts +9 -2
- package/types/api/entities/config.d.ts +32 -0
- package/types/api/entities/config.js +45 -18
- package/types/api/entities/instance.d.ts +11 -1
- package/types/api/entities/instanceState.d.ts +16 -1
- package/types/api/entities/snapshot.d.ts +6 -0
- package/utils/api.d.ts +1 -1
- package/utils/api.js +6 -0
- package/utils/clone.d.ts +3 -1
- package/utils/clone.js +7 -1
- package/utils/clonePoller.d.ts +12 -0
- package/utils/clonePoller.js +41 -0
- package/utils/date.js +12 -12
- package/utils/protection.d.ts +5 -0
- package/utils/protection.js +23 -0
|
@@ -4,14 +4,64 @@
|
|
|
4
4
|
* Unauthorized copying of this file, via any medium is strictly prohibited
|
|
5
5
|
*--------------------------------------------------------------------------
|
|
6
6
|
*/
|
|
7
|
+
import { useMemo, useState } from 'react';
|
|
7
8
|
import { useFormik } from 'formik';
|
|
8
9
|
import * as Yup from 'yup';
|
|
10
|
+
import { ConnectionStringError, connectionStringFromFields, connectionStringToFields, } from './connectionString';
|
|
11
|
+
// Logical-mode required fields. Validation skips the source-connection block
|
|
12
|
+
// when retrievalMode is "physical" — that branch uses tool-specific inputs
|
|
13
|
+
// instead of a connection URL.
|
|
9
14
|
const Schema = Yup.object().shape({
|
|
10
15
|
dockerImage: Yup.string().required('Docker image is required'),
|
|
11
|
-
dbname: Yup.string().
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
dbname: Yup.string().when('retrievalMode', {
|
|
17
|
+
is: 'logical',
|
|
18
|
+
then: (s) => s.required('Dbname is required'),
|
|
19
|
+
}),
|
|
20
|
+
host: Yup.string().when('retrievalMode', {
|
|
21
|
+
is: 'logical',
|
|
22
|
+
then: (s) => s.required('Host is required'),
|
|
23
|
+
}),
|
|
24
|
+
port: Yup.string().when('retrievalMode', {
|
|
25
|
+
is: 'logical',
|
|
26
|
+
then: (s) => s.required('Port is required'),
|
|
27
|
+
}),
|
|
28
|
+
username: Yup.string().when('retrievalMode', {
|
|
29
|
+
is: 'logical',
|
|
30
|
+
then: (s) => s.required('Username is required'),
|
|
31
|
+
}),
|
|
32
|
+
physicalEnvs: Yup.array()
|
|
33
|
+
.of(Yup.object().shape({
|
|
34
|
+
key: Yup.string(),
|
|
35
|
+
value: Yup.string(),
|
|
36
|
+
}))
|
|
37
|
+
.test('unique-keys', '', function (envs) {
|
|
38
|
+
if (!envs)
|
|
39
|
+
return true;
|
|
40
|
+
const positions = new Map();
|
|
41
|
+
envs.forEach((row, i) => {
|
|
42
|
+
var _a, _b;
|
|
43
|
+
const trimmed = ((_a = row === null || row === void 0 ? void 0 : row.key) !== null && _a !== void 0 ? _a : '').trim();
|
|
44
|
+
if (!trimmed)
|
|
45
|
+
return;
|
|
46
|
+
const list = (_b = positions.get(trimmed)) !== null && _b !== void 0 ? _b : [];
|
|
47
|
+
list.push(i);
|
|
48
|
+
positions.set(trimmed, list);
|
|
49
|
+
});
|
|
50
|
+
const dupes = [];
|
|
51
|
+
for (const indices of positions.values()) {
|
|
52
|
+
if (indices.length < 2)
|
|
53
|
+
continue;
|
|
54
|
+
for (const i of indices) {
|
|
55
|
+
dupes.push(this.createError({
|
|
56
|
+
path: `${this.path}[${i}].key`,
|
|
57
|
+
message: 'Duplicate key',
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (dupes.length === 0)
|
|
62
|
+
return true;
|
|
63
|
+
return new Yup.ValidationError(dupes);
|
|
64
|
+
}),
|
|
15
65
|
});
|
|
16
66
|
export const useForm = (onSubmit) => {
|
|
17
67
|
const formik = useFormik({
|
|
@@ -38,12 +88,71 @@ export const useForm = (onSubmit) => {
|
|
|
38
88
|
pgRestoreCustomOptions: '',
|
|
39
89
|
dumpIgnoreErrors: false,
|
|
40
90
|
restoreIgnoreErrors: false,
|
|
91
|
+
retrievalMode: 'logical',
|
|
92
|
+
physicalTool: '',
|
|
93
|
+
physicalDockerImage: '',
|
|
94
|
+
physicalSyncEnabled: false,
|
|
95
|
+
physicalWalgBackupName: '',
|
|
96
|
+
physicalPgbackrestStanza: '',
|
|
97
|
+
physicalPgbackrestDelta: false,
|
|
98
|
+
physicalEnvs: [],
|
|
41
99
|
},
|
|
42
100
|
validationSchema: Schema,
|
|
43
101
|
onSubmit,
|
|
44
102
|
validateOnBlur: false,
|
|
45
103
|
validateOnChange: false,
|
|
46
104
|
});
|
|
105
|
+
const [originalPortWasUnset, setOriginalPortWasUnset] = useState(false);
|
|
106
|
+
const [portDirty, setPortDirty] = useState(false);
|
|
107
|
+
const [connectionStringError, setConnectionStringError] = useState(null);
|
|
108
|
+
const connectionString = useMemo(() => connectionStringFromFields({
|
|
109
|
+
host: formik.values.host,
|
|
110
|
+
port: formik.values.port || '5432',
|
|
111
|
+
username: formik.values.username,
|
|
112
|
+
dbname: formik.values.dbname,
|
|
113
|
+
}, { omitDefaultPort: originalPortWasUnset && !portDirty }), [
|
|
114
|
+
formik.values.host,
|
|
115
|
+
formik.values.port,
|
|
116
|
+
formik.values.username,
|
|
117
|
+
formik.values.dbname,
|
|
118
|
+
originalPortWasUnset,
|
|
119
|
+
portDirty,
|
|
120
|
+
]);
|
|
121
|
+
const onConnectionStringChange = (s) => {
|
|
122
|
+
if (!s.trim()) {
|
|
123
|
+
setConnectionStringError(null);
|
|
124
|
+
formik.setValues({
|
|
125
|
+
...formik.values,
|
|
126
|
+
host: '',
|
|
127
|
+
port: '',
|
|
128
|
+
username: '',
|
|
129
|
+
dbname: '',
|
|
130
|
+
});
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
const parsed = connectionStringToFields(s);
|
|
135
|
+
setConnectionStringError(null);
|
|
136
|
+
if (parsed.portWasExplicit)
|
|
137
|
+
setPortDirty(true);
|
|
138
|
+
formik.setValues({
|
|
139
|
+
...formik.values,
|
|
140
|
+
host: parsed.fields.host,
|
|
141
|
+
port: parsed.fields.port,
|
|
142
|
+
username: parsed.fields.username,
|
|
143
|
+
dbname: parsed.fields.dbname,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
if (err instanceof ConnectionStringError)
|
|
148
|
+
setConnectionStringError(err.message);
|
|
149
|
+
else
|
|
150
|
+
throw err;
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
const markPortInitialState = (wasUnset) => setOriginalPortWasUnset(wasUnset);
|
|
154
|
+
const markPortDirty = () => setPortDirty(true);
|
|
155
|
+
const omitPortOnSubmit = originalPortWasUnset && !portDirty;
|
|
47
156
|
const formatDatabaseArray = (database) => {
|
|
48
157
|
let databases = [];
|
|
49
158
|
const splitDatabaseArray = database.split(/[,(\s)(\n)(\r)(\t)(\r\n)]/);
|
|
@@ -71,5 +180,17 @@ export const useForm = (onSubmit) => {
|
|
|
71
180
|
formik.values.port &&
|
|
72
181
|
formik.values.username &&
|
|
73
182
|
formik.values.dbname;
|
|
74
|
-
return [
|
|
183
|
+
return [
|
|
184
|
+
{
|
|
185
|
+
formik,
|
|
186
|
+
connectionData,
|
|
187
|
+
isConnectionDataValid,
|
|
188
|
+
connectionString,
|
|
189
|
+
connectionStringError,
|
|
190
|
+
onConnectionStringChange,
|
|
191
|
+
markPortInitialState,
|
|
192
|
+
markPortDirty,
|
|
193
|
+
omitPortOnSubmit,
|
|
194
|
+
},
|
|
195
|
+
];
|
|
75
196
|
};
|
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
import { dockerImageOptions } from '../configOptions';
|
|
2
|
+
import { dockerImagesConfig, genericImagePrefix } from '../dockerCatalog';
|
|
2
3
|
const seContainerRegistry = 'se-images';
|
|
3
|
-
const genericImagePrefix = 'postgresai/extended-postgres';
|
|
4
|
-
// Predefined list of Docker images for UI display
|
|
5
|
-
// This list is shown to users for convenient selection
|
|
6
|
-
// IMPORTANT: if user specified an image in config that's not in this list,
|
|
7
|
-
// it will be automatically added via createEnhancedDockerImages()
|
|
8
|
-
const dockerImagesConfig = {
|
|
9
|
-
'9.6': ['0.5.3', '0.5.2', '0.5.1'],
|
|
10
|
-
'10': ['0.5.3', '0.5.2', '0.5.1'],
|
|
11
|
-
'11': ['0.5.3', '0.5.2', '0.5.1'],
|
|
12
|
-
'12': ['0.5.3', '0.5.2', '0.5.1'],
|
|
13
|
-
'13': ['0.5.3', '0.5.2', '0.5.1'],
|
|
14
|
-
'14': ['0.5.3', '0.5.2', '0.5.1'],
|
|
15
|
-
'15': ['0.5.3', '0.5.2', '0.5.1'],
|
|
16
|
-
'16': ['0.5.3', '0.5.2', '0.5.1'],
|
|
17
|
-
'17': ['0.5.3', '0.5.2', '0.5.1'],
|
|
18
|
-
'18': ['0.6.1'],
|
|
19
|
-
};
|
|
20
4
|
export const uniqueChipValue = (values) => {
|
|
21
5
|
const splitChipArray = values.split(/[,(\s)(\n)(\r)(\t)(\r\n)]/);
|
|
22
6
|
let databaseArray = [];
|
|
@@ -16,7 +16,7 @@ const useStyles = makeStyles({
|
|
|
16
16
|
position: 'relative',
|
|
17
17
|
cursor: 'default',
|
|
18
18
|
flex: `0 0 ${CELL_SIZE}px`,
|
|
19
|
-
background: '
|
|
19
|
+
background: 'rgba(128, 128, 128, 0.1)',
|
|
20
20
|
height: `${CELL_SIZE}px`,
|
|
21
21
|
display: 'flex',
|
|
22
22
|
borderRadius: `${CELL_SIZE / 2}px`,
|
|
@@ -26,7 +26,7 @@ const useStyles = makeStyles({
|
|
|
26
26
|
fontSize: '12px',
|
|
27
27
|
},
|
|
28
28
|
rootHasSnapshots: {
|
|
29
|
-
background:
|
|
29
|
+
background: 'rgba(15, 135, 157, 0.32)',
|
|
30
30
|
cursor: 'pointer',
|
|
31
31
|
},
|
|
32
32
|
rootCurrent: {
|
|
@@ -41,7 +41,7 @@ const useStyles = makeStyles({
|
|
|
41
41
|
right: '-6px',
|
|
42
42
|
position: 'absolute',
|
|
43
43
|
fontSize: '8px',
|
|
44
|
-
backgroundColor:
|
|
44
|
+
backgroundColor: 'inherit',
|
|
45
45
|
border: `1px solid ${colors.secondary2.lightLight}`,
|
|
46
46
|
borderRadius: '8px',
|
|
47
47
|
height: '16px',
|
|
@@ -17,6 +17,9 @@ export declare const getCalendar: (monthStartDate: Date, snapshots: Snapshot[])
|
|
|
17
17
|
logicalSize: number;
|
|
18
18
|
message: string;
|
|
19
19
|
branch: string;
|
|
20
|
+
protected: boolean;
|
|
21
|
+
protectedTill?: string | undefined;
|
|
22
|
+
deleteAt?: string | undefined;
|
|
20
23
|
}[];
|
|
21
24
|
isBreak: boolean;
|
|
22
25
|
isDisabled: boolean;
|
|
@@ -16,6 +16,9 @@ export declare const getEdgeSnapshots: (snapshots: Snapshot[]) => {
|
|
|
16
16
|
logicalSize: number;
|
|
17
17
|
message: string;
|
|
18
18
|
branch: string;
|
|
19
|
+
protected: boolean;
|
|
20
|
+
protectedTill?: string | undefined;
|
|
21
|
+
deleteAt?: string | undefined;
|
|
19
22
|
};
|
|
20
23
|
lastSnapshot: {
|
|
21
24
|
createdAtDate: Date;
|
|
@@ -30,5 +33,8 @@ export declare const getEdgeSnapshots: (snapshots: Snapshot[]) => {
|
|
|
30
33
|
logicalSize: number;
|
|
31
34
|
message: string;
|
|
32
35
|
branch: string;
|
|
36
|
+
protected: boolean;
|
|
37
|
+
protectedTill?: string | undefined;
|
|
38
|
+
deleteAt?: string | undefined;
|
|
33
39
|
};
|
|
34
40
|
};
|
|
@@ -41,6 +41,16 @@ const useStyles = makeStyles({
|
|
|
41
41
|
header: {
|
|
42
42
|
fontWeight: 500,
|
|
43
43
|
},
|
|
44
|
+
protectedBadge: {
|
|
45
|
+
marginLeft: '8px',
|
|
46
|
+
padding: '1px 6px',
|
|
47
|
+
fontSize: '11px',
|
|
48
|
+
fontWeight: 400,
|
|
49
|
+
color: '#1a7f37',
|
|
50
|
+
border: '1px solid #1a7f37',
|
|
51
|
+
borderRadius: '4px',
|
|
52
|
+
whiteSpace: 'nowrap',
|
|
53
|
+
},
|
|
44
54
|
infoContent: {
|
|
45
55
|
fontSize: '12px',
|
|
46
56
|
color: '#808080',
|
|
@@ -113,7 +123,7 @@ const SnapshotListItem = ({ snapshot, setSnapshotModal, openClonesModal, }) => {
|
|
|
113
123
|
const timeAgo = formatDistanceSafe(snapshot.createdAtDate);
|
|
114
124
|
const history = useHistory();
|
|
115
125
|
const host = useHost();
|
|
116
|
-
return (_jsx("div", { className: classes.commitItem, children: _jsxs("div", { className: classes.gridContainer, children: [_jsxs("div", { className: classes.infoBlock, children: [
|
|
126
|
+
return (_jsx("div", { className: classes.commitItem, children: _jsxs("div", { className: classes.gridContainer, children: [_jsxs("div", { className: classes.infoBlock, children: [_jsxs("div", { className: classes.header, children: [snapshot.message || '-', snapshot.protected && (_jsx("span", { className: classes.protectedBadge, title: "Protected from deletion", children: "Protected" }))] }), _jsx("div", { className: classes.infoContent, title: snapshot.dataStateAt, children: timeAgo })] }), _jsxs("div", { className: classes.infoBlock, children: [_jsx("div", { className: classes.header, children: "Pool" }), _jsx("div", { className: classes.infoContent, children: (_a = snapshot.pool) !== null && _a !== void 0 ? _a : '-' })] }), _jsxs("div", { className: classes.infoBlock, children: [_jsx("div", { className: classes.header, children: "Number of clones" }), _jsx("div", { className: classes.infoContent, children: (_b = snapshot.numClones) !== null && _b !== void 0 ? _b : '-' })] }), _jsxs("div", { className: classes.infoBlock, children: [_jsx("div", { className: classes.header, children: "Logical Size" }), _jsx("div", { className: classes.infoContent, children: snapshot.logicalSize ? formatBytesIEC(snapshot.logicalSize) : '-' })] }), _jsxs("div", { className: classes.infoBlock, children: [_jsx("div", { className: classes.header, children: "Physical Size" }), _jsx("div", { className: classes.infoContent, children: snapshot.physicalSize
|
|
117
127
|
? formatBytesIEC(snapshot.physicalSize)
|
|
118
128
|
: '-' })] }), _jsxs("div", { className: classes.actionsContainer, onClick: (e) => e.stopPropagation(), children: [_jsx("div", { className: classes.snapshotId, children: snapshot.id }), _jsx("div", { className: classes.copyButtonContainer, title: "Copy snapshot ID", children: _jsx(IconButton, { className: classes.copyButton, onClick: (e) => {
|
|
119
129
|
e.stopPropagation();
|
|
@@ -37,6 +37,9 @@ const useStyles = makeStyles({
|
|
|
37
37
|
transform: 'translate(-50%, -50%)',
|
|
38
38
|
},
|
|
39
39
|
}, { index: 1 });
|
|
40
|
+
// listRefreshIntervalMs is how often the snapshot list is silently refreshed so background
|
|
41
|
+
// auto-deletion does not leave stale rows in the list.
|
|
42
|
+
const listRefreshIntervalMs = 30000;
|
|
40
43
|
export const Snapshots = observer(({ instanceId }) => {
|
|
41
44
|
var _a;
|
|
42
45
|
const host = useHost();
|
|
@@ -80,9 +83,14 @@ export const Snapshots = observer(({ instanceId }) => {
|
|
|
80
83
|
fetchInitialData();
|
|
81
84
|
}, []);
|
|
82
85
|
useEffect(() => {
|
|
83
|
-
if (selectedBranch)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
if (!selectedBranch)
|
|
87
|
+
return;
|
|
88
|
+
const branchName = selectedBranch === 'All branches' ? '' : selectedBranch;
|
|
89
|
+
stores.main.reloadSnapshots(branchName);
|
|
90
|
+
const intervalId = setInterval(() => {
|
|
91
|
+
stores.main.reloadSnapshots(branchName, true);
|
|
92
|
+
}, listRefreshIntervalMs);
|
|
93
|
+
return () => clearInterval(intervalId);
|
|
86
94
|
}, [selectedBranch]);
|
|
87
95
|
if (!instance && !snapshots.isLoading)
|
|
88
96
|
return _jsx(_Fragment, {});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { makeStyles } from '@material-ui/core';
|
|
2
|
-
|
|
3
|
-
export const useTabsStyles = makeStyles({
|
|
2
|
+
export const useTabsStyles = makeStyles((theme) => ({
|
|
4
3
|
tabsRoot: {
|
|
5
4
|
minHeight: 0,
|
|
6
5
|
marginTop: '-8px',
|
|
@@ -21,7 +20,7 @@ export const useTabsStyles = makeStyles({
|
|
|
21
20
|
height: '18px',
|
|
22
21
|
},
|
|
23
22
|
'& a': {
|
|
24
|
-
color:
|
|
23
|
+
color: theme.palette.text.primary,
|
|
25
24
|
textDecoration: 'none',
|
|
26
25
|
'@media (max-width: 700px)': {
|
|
27
26
|
display: 'flex',
|
|
@@ -39,18 +38,19 @@ export const useTabsStyles = makeStyles({
|
|
|
39
38
|
height: '3px',
|
|
40
39
|
},
|
|
41
40
|
tabRoot: {
|
|
41
|
+
color: theme.palette.text.primary,
|
|
42
42
|
fontWeight: 400,
|
|
43
43
|
minWidth: 0,
|
|
44
44
|
minHeight: 0,
|
|
45
45
|
width: '100%',
|
|
46
46
|
padding: '6px 16px',
|
|
47
|
-
borderBottom: `3px solid ${
|
|
47
|
+
borderBottom: `3px solid ${theme.palette.divider}`,
|
|
48
48
|
'& + $tabRoot': {
|
|
49
49
|
marginLeft: '10px',
|
|
50
50
|
},
|
|
51
51
|
'&.Mui-disabled': {
|
|
52
52
|
opacity: 1,
|
|
53
|
-
color:
|
|
53
|
+
color: theme.palette.text.disabled,
|
|
54
54
|
},
|
|
55
55
|
'@media (max-width: 700px)': {
|
|
56
56
|
width: 'max-content',
|
|
@@ -59,4 +59,4 @@ export const useTabsStyles = makeStyles({
|
|
|
59
59
|
tabHidden: {
|
|
60
60
|
display: 'none',
|
|
61
61
|
},
|
|
62
|
-
}, { index: 1 });
|
|
62
|
+
}), { index: 1 });
|
package/pages/Instance/index.js
CHANGED
|
@@ -67,7 +67,6 @@ export const Instance = observer((props) => {
|
|
|
67
67
|
};
|
|
68
68
|
const isInstanceIntegrated = instanceRetrieval ||
|
|
69
69
|
(!isLoadingInstance && !isLoadingInstanceRetrieval && instance && (instance === null || instance === void 0 ? void 0 : instance.url) && !instanceError);
|
|
70
|
-
const isConfigurationActive = (instanceRetrieval === null || instanceRetrieval === void 0 ? void 0 : instanceRetrieval.mode) !== 'physical';
|
|
71
70
|
useEffect(() => {
|
|
72
71
|
load(instanceId, isPlatform);
|
|
73
72
|
}, [instanceId]);
|
|
@@ -79,14 +78,13 @@ export const Instance = observer((props) => {
|
|
|
79
78
|
var _a, _b;
|
|
80
79
|
if (instance &&
|
|
81
80
|
((_b = (_a = instance.state) === null || _a === void 0 ? void 0 : _a.retrieving) === null || _b === void 0 ? void 0 : _b.status) === 'pending' &&
|
|
82
|
-
isConfigurationActive &&
|
|
83
81
|
!hasBeenRedirected) {
|
|
84
82
|
setActiveTab(TABS_INDEX.CONFIGURATION);
|
|
85
83
|
setHasBeenRedirected(true);
|
|
86
84
|
}
|
|
87
85
|
}, [instance, hasBeenRedirected]);
|
|
88
86
|
return (_jsx(HostProvider, { value: props, children: _jsxs(StoresProvider, { value: stores, children: [props.elements.breadcrumbs, _jsx(SectionTitle, { text: props.title, level: 1, tag: "h1", className: classes.title, rightContent: _jsx(Button, { onClick: () => load(props.instanceId, isPlatform), isDisabled: !instance && !instanceError, className: classes.reloadButton, children: "Reload info" }), children: isInstanceIntegrated && (_jsx(InstanceTabs, { instanceId: props.instanceId, tab: activeTab, onTabChange: (tabID) => setActiveTab(tabID), isPlatform: isPlatform, hasLogs: api.initWS !== undefined, hideInstanceTabs: props.hideBranchingFeatures })) }), instanceError && (_jsx(ErrorStub, { ...instanceError, className: classes.errorStub })), isInstanceIntegrated ? (_jsxs(_Fragment, { children: [_jsxs(TabPanel, { value: activeTab, index: TABS_INDEX.OVERVIEW, children: [!instanceError && (_jsx("div", { className: classes.content, children: instance && ((_b = (_a = instance.state) === null || _a === void 0 ? void 0 : _a.retrieving) === null || _b === void 0 ? void 0 : _b.status) ? (_jsxs(_Fragment, { children: [_jsx(Clones, {}), _jsx(Info, { hideBranchingFeatures: props.hideBranchingFeatures })] })) : (_jsx(StubSpinner, {})) })), _jsx(ClonesModal, {}), _jsx(SnapshotsModal, {})] }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.CLONES, children: activeTab === TABS_INDEX.CLONES && (_jsx("div", { className: classes.content, children: !instanceError &&
|
|
89
|
-
(instance ? _jsx(Clones, { onlyRenderList: true }) : _jsx(StubSpinner, {})) })) }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.LOGS, children: activeTab === TABS_INDEX.LOGS && (_jsx(Logs, { api: api, instanceId: props.instanceId })) }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.CONFIGURATION, children: activeTab === TABS_INDEX.CONFIGURATION && (_jsx(Configuration, { instanceId: instanceId, switchActiveTab: switchTab,
|
|
87
|
+
(instance ? _jsx(Clones, { onlyRenderList: true }) : _jsx(StubSpinner, {})) })) }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.LOGS, children: activeTab === TABS_INDEX.LOGS && (_jsx(Logs, { api: api, instanceId: props.instanceId })) }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.CONFIGURATION, children: activeTab === TABS_INDEX.CONFIGURATION && (_jsx(Configuration, { instanceId: instanceId, switchActiveTab: switchTab, reload: () => load(props.instanceId), disableConfigModification: (_c = instance === null || instance === void 0 ? void 0 : instance.state) === null || _c === void 0 ? void 0 : _c.engine.disableConfigModification })) }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.SNAPSHOTS, children: activeTab === TABS_INDEX.SNAPSHOTS && (_jsx(Snapshots, { instanceId: instanceId })) }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.BRANCHES, children: activeTab === TABS_INDEX.BRANCHES && (_jsx(Branches, { instanceId: instanceId })) })] })) : !isLoadingInstance && !isLoadingInstanceRetrieval && !instanceError ? (_jsx(TabPanel, { value: activeTab, index: activeTab, children: _jsx(InactiveInstance, { instance: instance, org: (_d = props.elements.breadcrumbs) === null || _d === void 0 ? void 0 : _d.props.org }) })) : (!instanceError && (_jsx(TabPanel, { value: activeTab, index: activeTab, children: _jsx("div", { className: classes.content, children: _jsx(StubSpinner, {}) }) })))] }) }));
|
|
90
88
|
});
|
|
91
89
|
function TabPanel(props) {
|
|
92
90
|
const { children, value, index, ...other } = props;
|
|
@@ -5,6 +5,7 @@ import { Config } from '@postgres.ai/shared/types/api/entities/config';
|
|
|
5
5
|
import { GetConfig } from '@postgres.ai/shared/types/api/endpoints/getConfig';
|
|
6
6
|
import { UpdateConfig } from '@postgres.ai/shared/types/api/endpoints/updateConfig';
|
|
7
7
|
import { TestDbSource } from '@postgres.ai/shared/types/api/endpoints/testDbSource';
|
|
8
|
+
import { ProbeSource } from '@postgres.ai/shared/types/api/endpoints/probeSource';
|
|
8
9
|
import { RefreshInstance } from '@postgres.ai/shared/types/api/endpoints/refreshInstance';
|
|
9
10
|
import { DestroyClone } from '@postgres.ai/shared/types/api/endpoints/destroyClone';
|
|
10
11
|
import { ResetClone } from '@postgres.ai/shared/types/api/endpoints/resetClone';
|
|
@@ -35,6 +36,7 @@ export declare type Api = {
|
|
|
35
36
|
getConfig?: GetConfig;
|
|
36
37
|
updateConfig?: UpdateConfig;
|
|
37
38
|
testDbSource?: TestDbSource;
|
|
39
|
+
probeSource?: ProbeSource;
|
|
38
40
|
getFullConfig?: GetFullConfig;
|
|
39
41
|
getSeImages?: GetSeImages;
|
|
40
42
|
getEngine?: GetEngine;
|
|
@@ -78,7 +80,7 @@ export declare class MainStore {
|
|
|
78
80
|
get isDisabledInstance(): boolean;
|
|
79
81
|
load: (instanceId: string, isPlatform?: boolean) => void;
|
|
80
82
|
reload: (instanceId: string) => void;
|
|
81
|
-
reloadSnapshots: (branchName?: string) => Promise<void>;
|
|
83
|
+
reloadSnapshots: (branchName?: string, silent?: boolean) => Promise<void>;
|
|
82
84
|
reloadInstanceRetrieval: () => Promise<void>;
|
|
83
85
|
private loadInstanceRetrieval;
|
|
84
86
|
private loadInstance;
|
|
@@ -104,6 +106,17 @@ export declare class MainStore {
|
|
|
104
106
|
dockerTag?: string | undefined;
|
|
105
107
|
dockerImageType?: string | undefined;
|
|
106
108
|
debug: boolean | undefined;
|
|
109
|
+
retrievalMode: import("@postgres.ai/shared/types/api/entities/config").RetrievalMode;
|
|
110
|
+
physicalTool: string;
|
|
111
|
+
physicalDockerImage: string;
|
|
112
|
+
physicalSyncEnabled: boolean;
|
|
113
|
+
physicalWalgBackupName: string;
|
|
114
|
+
physicalPgbackrestStanza: string;
|
|
115
|
+
physicalPgbackrestDelta: boolean;
|
|
116
|
+
physicalEnvs: {
|
|
117
|
+
key: string;
|
|
118
|
+
value: string;
|
|
119
|
+
}[];
|
|
107
120
|
dockerImage: string | undefined;
|
|
108
121
|
} | null | undefined>;
|
|
109
122
|
updateConfig: (values: Config, instanceId: string) => Promise<Response | null | undefined>;
|
|
@@ -127,11 +140,18 @@ export declare class MainStore {
|
|
|
127
140
|
message: string;
|
|
128
141
|
};
|
|
129
142
|
} | undefined>;
|
|
143
|
+
probeSource: (values: {
|
|
144
|
+
url: string;
|
|
145
|
+
password: string;
|
|
146
|
+
}) => Promise<{
|
|
147
|
+
response: import("@postgres.ai/shared/types/api/endpoints/probeSource").ProposedConfig | null;
|
|
148
|
+
error: import("@postgres.ai/shared/types/api/endpoints/probeSource").ProbeSourceError | null;
|
|
149
|
+
} | undefined>;
|
|
130
150
|
resetClone: (cloneId: string, snapshotId: string) => Promise<boolean | undefined>;
|
|
131
151
|
destroyClone: (cloneId: string) => Promise<boolean | undefined>;
|
|
132
152
|
private liveUpdateInstance;
|
|
133
153
|
reloadClones: () => Promise<void>;
|
|
134
|
-
getBranches: (instanceId: string) => Promise<import("@postgres.ai/shared/types/api/endpoints/getBranches").Branch[] | null | undefined>;
|
|
154
|
+
getBranches: (instanceId: string, silent?: boolean) => Promise<import("@postgres.ai/shared/types/api/endpoints/getBranches").Branch[] | null | undefined>;
|
|
135
155
|
deleteBranch: (branchName: string, instanceId: string) => Promise<{
|
|
136
156
|
response: Response | null;
|
|
137
157
|
error: globalThis.Error | null;
|
|
@@ -80,10 +80,10 @@ export class MainStore {
|
|
|
80
80
|
}
|
|
81
81
|
});
|
|
82
82
|
};
|
|
83
|
-
this.reloadSnapshots = async (branchName) => {
|
|
83
|
+
this.reloadSnapshots = async (branchName, silent) => {
|
|
84
84
|
if (!this.instance)
|
|
85
85
|
return;
|
|
86
|
-
await this.snapshots.reload(this.instance.id, branchName);
|
|
86
|
+
await this.snapshots.reload(this.instance.id, branchName, silent);
|
|
87
87
|
};
|
|
88
88
|
this.reloadInstanceRetrieval = async () => {
|
|
89
89
|
if (!this.instance)
|
|
@@ -164,15 +164,17 @@ export class MainStore {
|
|
|
164
164
|
return response;
|
|
165
165
|
};
|
|
166
166
|
this.getFullConfig = async (instanceId) => {
|
|
167
|
-
var _a, _b, _c, _d, _e;
|
|
167
|
+
var _a, _b, _c, _d, _e, _f;
|
|
168
168
|
if (!this.api.getFullConfig)
|
|
169
169
|
return;
|
|
170
170
|
const { response, error } = await this.api.getFullConfig(instanceId);
|
|
171
171
|
if (response) {
|
|
172
172
|
this.fullConfig = response;
|
|
173
173
|
const splitYML = this.fullConfig.split('---');
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
const platformSection = (_b = (_a = splitYML[0]) === null || _a === void 0 ? void 0 : _a.split('\nplatform:')[1]) !== null && _b !== void 0 ? _b : '';
|
|
175
|
+
const rawPlatformUrl = (_c = platformSection.split('url: ')[1]) === null || _c === void 0 ? void 0 : _c.split('\n')[0];
|
|
176
|
+
this.platformUrl = rawPlatformUrl === null || rawPlatformUrl === void 0 ? void 0 : rawPlatformUrl.replace(/['"]+/g, '').trim().split(/\s+/)[0];
|
|
177
|
+
this.uiVersion = (_f = (_e = (_d = splitYML[0]) === null || _d === void 0 ? void 0 : _d.split('dockerImage: "postgresai/ce-ui:')[2]) === null || _e === void 0 ? void 0 : _e.split('\n')[0]) === null || _f === void 0 ? void 0 : _f.replace(/['"]+/g, '');
|
|
176
178
|
}
|
|
177
179
|
if (error)
|
|
178
180
|
this.getFullConfigError = await error
|
|
@@ -216,6 +218,15 @@ export class MainStore {
|
|
|
216
218
|
error,
|
|
217
219
|
};
|
|
218
220
|
};
|
|
221
|
+
this.probeSource = async (values) => {
|
|
222
|
+
if (!this.api.probeSource)
|
|
223
|
+
return;
|
|
224
|
+
const { response, error } = await this.api.probeSource(values);
|
|
225
|
+
return {
|
|
226
|
+
response,
|
|
227
|
+
error,
|
|
228
|
+
};
|
|
229
|
+
};
|
|
219
230
|
this.resetClone = async (cloneId, snapshotId) => {
|
|
220
231
|
if (!this.instance || !this.api.resetClone)
|
|
221
232
|
return;
|
|
@@ -263,13 +274,19 @@ export class MainStore {
|
|
|
263
274
|
await this.loadInstanceRetrieval(this.instance.id);
|
|
264
275
|
this.isReloadingClones = false;
|
|
265
276
|
};
|
|
266
|
-
this.getBranches = async (instanceId) => {
|
|
277
|
+
this.getBranches = async (instanceId, silent) => {
|
|
267
278
|
if (!this.api.getBranches)
|
|
268
279
|
return;
|
|
269
|
-
|
|
280
|
+
if (!silent)
|
|
281
|
+
this.isBranchesLoading = true;
|
|
270
282
|
const { response, error } = await this.api.getBranches(instanceId);
|
|
271
|
-
|
|
272
|
-
|
|
283
|
+
if (!silent)
|
|
284
|
+
this.isBranchesLoading = false;
|
|
285
|
+
if (response)
|
|
286
|
+
this.getBranchesError = null;
|
|
287
|
+
// a silent background refresh must not replace the rendered list with an error stub on a
|
|
288
|
+
// transient failure; errors surface only on a foreground load.
|
|
289
|
+
if (error && !silent)
|
|
273
290
|
this.getBranchesError = await error.json().then((err) => err);
|
|
274
291
|
return response;
|
|
275
292
|
};
|
|
@@ -13,11 +13,15 @@ import { makeStyles, Button, TextField, IconButton, Table, TableHead, TableRow,
|
|
|
13
13
|
import { ErrorStub } from '@postgres.ai/shared/components/ErrorStub';
|
|
14
14
|
import { PageSpinner } from '@postgres.ai/shared/components/PageSpinner';
|
|
15
15
|
import { SectionTitle } from '@postgres.ai/shared/components/SectionTitle';
|
|
16
|
+
import { Select } from '@postgres.ai/shared/components/Select';
|
|
17
|
+
import { Spinner } from '@postgres.ai/shared/components/Spinner';
|
|
16
18
|
import { DestroySnapshotModal } from '@postgres.ai/shared/pages/Snapshots/Snapshot/DestorySnapshotModal';
|
|
17
19
|
import { HorizontalScrollContainer } from '@postgres.ai/shared/components/HorizontalScrollContainer';
|
|
18
20
|
import { Tooltip } from '@postgres.ai/shared/components/Tooltip';
|
|
19
21
|
import { icons } from '@postgres.ai/shared/styles/icons';
|
|
20
22
|
import { formatBytesIEC } from '@postgres.ai/shared/utils/units';
|
|
23
|
+
import { parseDate } from '@postgres.ai/shared/utils/date';
|
|
24
|
+
import { protectionOptions, getProtectionSelectValue, } from '@postgres.ai/shared/utils/protection';
|
|
21
25
|
import { styles } from '@postgres.ai/shared/styles/styles';
|
|
22
26
|
import { SyntaxHighlight } from '@postgres.ai/shared/components/SyntaxHighlight';
|
|
23
27
|
import { TableBodyCell, TableBodyCellMenu, TableHeaderCell, } from '@postgres.ai/shared/components/Table';
|
|
@@ -71,6 +75,13 @@ const useStyles = makeStyles(() => ({
|
|
|
71
75
|
summary: {
|
|
72
76
|
marginTop: 20,
|
|
73
77
|
},
|
|
78
|
+
protectionControl: {
|
|
79
|
+
display: 'flex',
|
|
80
|
+
alignItems: 'center',
|
|
81
|
+
marginTop: '8px',
|
|
82
|
+
marginBottom: '8px',
|
|
83
|
+
maxWidth: 525,
|
|
84
|
+
},
|
|
74
85
|
text: {
|
|
75
86
|
marginTop: '4px',
|
|
76
87
|
},
|
|
@@ -129,11 +140,18 @@ export const SnapshotPage = observer((props) => {
|
|
|
129
140
|
const history = useHistory();
|
|
130
141
|
const stores = useCreatedStores(props.api);
|
|
131
142
|
const [isOpenDestroyModal, setIsOpenDestroyModal] = useState(false);
|
|
132
|
-
const { snapshot, branchSnapshot, isSnapshotsLoading, snapshotError, branchSnapshotError, load, } = stores.main;
|
|
143
|
+
const { snapshot, branchSnapshot, isSnapshotsLoading, isUpdatingSnapshot, updateSnapshotProtection, updateSnapshotError, snapshotError, branchSnapshotError, load, } = stores.main;
|
|
133
144
|
const afterSubmitClick = () => {
|
|
134
145
|
history.push(props.routes.snapshots());
|
|
135
146
|
load(props.snapshotId, props.instanceId);
|
|
136
147
|
};
|
|
148
|
+
const protectedTillDate = (snapshot === null || snapshot === void 0 ? void 0 : snapshot.protectedTill)
|
|
149
|
+
? parseDate(snapshot.protectedTill)
|
|
150
|
+
: null;
|
|
151
|
+
const handleProtectionChange = (e) => {
|
|
152
|
+
const value = e.target.value;
|
|
153
|
+
updateSnapshotProtection(props.snapshotId, props.instanceId, value === 'none' ? null : parseInt(value, 10));
|
|
154
|
+
};
|
|
137
155
|
const headRendered = (_jsxs(_Fragment, { children: [_jsx("style", { children: 'p { margin: 0;}' }), props.elements.breadcrumbs, _jsx(SectionTitle, { className: classes.title, tag: "h1", level: 1, text: `Snapshot ${props.snapshotId}`, children: _jsx(InstanceTabs, { tab: TABS_INDEX.SNAPSHOTS, isPlatform: props.isPlatform, instanceId: props.instanceId, hasLogs: props.api.initWS !== undefined, hideInstanceTabs: props.hideBranchingFeatures }) })] }));
|
|
138
156
|
useEffect(() => {
|
|
139
157
|
load(props.snapshotId, props.instanceId);
|
|
@@ -147,7 +165,15 @@ export const SnapshotPage = observer((props) => {
|
|
|
147
165
|
? formatBytesIEC(snapshot.logicalSize)
|
|
148
166
|
: '-'] }), _jsxs("p", { className: classes.text, children: [_jsx("span", { className: classes.paramTitle, children: "Physical data diff size:" }), (snapshot === null || snapshot === void 0 ? void 0 : snapshot.physicalSize)
|
|
149
167
|
? formatBytesIEC(snapshot.physicalSize)
|
|
150
|
-
: '-'] }), (branchSnapshot === null || branchSnapshot === void 0 ? void 0 : branchSnapshot.message) && (_jsxs("p", { className: classes.text, children: [_jsx("span", { className: classes.paramTitle, children: "Message:" }), branchSnapshot.message] }))] }),
|
|
168
|
+
: '-'] }), (branchSnapshot === null || branchSnapshot === void 0 ? void 0 : branchSnapshot.message) && (_jsxs("p", { className: classes.text, children: [_jsx("span", { className: classes.paramTitle, children: "Message:" }), branchSnapshot.message] }))] }), _jsxs("div", { className: classes.summary, children: [_jsx("p", { children: _jsx("strong", { children: "Deletion protection" }) }), _jsxs("div", { className: classes.protectionControl, children: [_jsx(Select, { label: "Deletion protection", items: (snapshot === null || snapshot === void 0 ? void 0 : snapshot.protected) && protectedTillDate
|
|
169
|
+
? [
|
|
170
|
+
{
|
|
171
|
+
value: 'current',
|
|
172
|
+
children: `Protected until ${protectedTillDate.toLocaleString()}`,
|
|
173
|
+
},
|
|
174
|
+
...protectionOptions,
|
|
175
|
+
]
|
|
176
|
+
: protectionOptions, value: getProtectionSelectValue(Boolean(snapshot === null || snapshot === void 0 ? void 0 : snapshot.protected), protectedTillDate), onChange: handleProtectionChange, disabled: isUpdatingSnapshot, fullWidth: true }), isUpdatingSnapshot && (_jsx(Spinner, { size: "sm", className: classes.spinner }))] }), _jsx("p", { className: classes.text, children: "Protected snapshots cannot be deleted manually or automatically." }), updateSnapshotError && (_jsx(ErrorStub, { title: "Update error", message: updateSnapshotError, className: classes.marginTop }))] }), _jsx("br", {}), _jsx("p", { children: _jsx("strong", { children: "Snapshot info" }) }), (snapshot === null || snapshot === void 0 ? void 0 : snapshot.pool) && (_jsxs("div", { className: classes.copyFieldContainer, children: [_jsx(TextField, { variant: "outlined", label: "snapshot pool", value: snapshot.pool, className: classes.textField, margin: "normal", fullWidth: true, InputLabelProps: {
|
|
151
177
|
shrink: true,
|
|
152
178
|
style: styles.inputFieldLabel,
|
|
153
179
|
}, FormHelperTextProps: {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SnapshotsStore, SnapshotsApi } from '@postgres.ai/shared/stores/Snapshots';
|
|
2
2
|
import { DestroySnapshot } from '@postgres.ai/shared/types/api/endpoints/destroySnapshot';
|
|
3
|
+
import { UpdateSnapshot } from '@postgres.ai/shared/types/api/endpoints/updateSnapshot';
|
|
3
4
|
import { SnapshotDto } from '@postgres.ai/shared/types/api/entities/snapshot';
|
|
4
5
|
import { GetBranchSnapshot } from '@postgres.ai/shared/types/api/endpoints/getBranchSnapshot';
|
|
5
6
|
import { BranchSnapshotDto } from '@postgres.ai/shared/types/api/entities/branchSnapshot';
|
|
@@ -10,6 +11,7 @@ declare type Error = {
|
|
|
10
11
|
};
|
|
11
12
|
export declare type Api = SnapshotsApi & {
|
|
12
13
|
destroySnapshot: DestroySnapshot;
|
|
14
|
+
updateSnapshot?: UpdateSnapshot;
|
|
13
15
|
getBranchSnapshot?: GetBranchSnapshot;
|
|
14
16
|
initWS?: InitWS;
|
|
15
17
|
};
|
|
@@ -19,12 +21,15 @@ export declare class MainStore {
|
|
|
19
21
|
snapshotError: Error | null;
|
|
20
22
|
branchSnapshotError: Error | null;
|
|
21
23
|
isSnapshotsLoading: boolean;
|
|
24
|
+
isUpdatingSnapshot: boolean;
|
|
25
|
+
updateSnapshotError: string | null;
|
|
22
26
|
private readonly api;
|
|
23
27
|
readonly snapshots: SnapshotsStore;
|
|
24
28
|
constructor(api: Api);
|
|
25
29
|
load: (snapshotId: string, instanceId: string) => Promise<void>;
|
|
26
30
|
getSnapshot: (snapshotId: string, instanceId: string) => Promise<boolean | undefined>;
|
|
27
31
|
getBranchSnapshot: (snapshotId: string, instanceId: string) => Promise<import("@postgres.ai/shared/types/api/entities/branchSnapshot").BranchSnapshotDTO | null | undefined>;
|
|
32
|
+
updateSnapshotProtection: (snapshotId: string, instanceId: string, durationMinutes: number | null) => Promise<void>;
|
|
28
33
|
destroySnapshot: (snapshotId: string, forceDelete: boolean, instanceId: string) => Promise<{
|
|
29
34
|
response: boolean | null;
|
|
30
35
|
error: any;
|