@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
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// connectionString.ts — Expert-mode helper that converts between the
|
|
2
|
+
// (host, port, username, dbname) shape stored in `server.yml` and the
|
|
3
|
+
// single URL field the form exposes. The engine remains the source of
|
|
4
|
+
// truth for actual probing (see engine/internal/retrieval/probe/parser.go);
|
|
5
|
+
// this parser only powers the form's load/save round-trip.
|
|
6
|
+
//
|
|
7
|
+
// Accepts both URI form (postgres://user@host:5432/dbname) and DSN form
|
|
8
|
+
// (host=db port=5432 user=app dbname=shop). Rejects any input that carries
|
|
9
|
+
// a password — passwords belong in the masked field, never the URL field.
|
|
10
|
+
export class ConnectionStringError extends Error {
|
|
11
|
+
}
|
|
12
|
+
export const ErrPasswordInConnectionString = 'Password must be entered in the Password field, not the connection string.';
|
|
13
|
+
export const ErrMultiHost = 'Multi-host connection strings are not supported.';
|
|
14
|
+
export const ErrInvalidConnectionString = 'Could not parse the connection string.';
|
|
15
|
+
const URI_SCHEMES = ['postgres:', 'postgresql:'];
|
|
16
|
+
const isUri = (s) => URI_SCHEMES.some((p) => s.toLowerCase().startsWith(p));
|
|
17
|
+
const stripBrackets = (h) => (h.startsWith('[') && h.endsWith(']') ? h.slice(1, -1) : h);
|
|
18
|
+
const parseUri = (s) => {
|
|
19
|
+
let url;
|
|
20
|
+
try {
|
|
21
|
+
url = new URL(s);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
throw new ConnectionStringError(ErrInvalidConnectionString);
|
|
25
|
+
}
|
|
26
|
+
if (url.password)
|
|
27
|
+
throw new ConnectionStringError(ErrPasswordInConnectionString);
|
|
28
|
+
if (!url.hostname)
|
|
29
|
+
throw new ConnectionStringError(ErrInvalidConnectionString);
|
|
30
|
+
if (url.hostname.includes(','))
|
|
31
|
+
throw new ConnectionStringError(ErrMultiHost);
|
|
32
|
+
const portWasExplicit = url.port !== '';
|
|
33
|
+
const path = url.pathname.startsWith('/') ? url.pathname.slice(1) : url.pathname;
|
|
34
|
+
const dbname = path.includes(',') ? '' : decodeURIComponent(path);
|
|
35
|
+
return {
|
|
36
|
+
fields: {
|
|
37
|
+
host: stripBrackets(url.hostname),
|
|
38
|
+
port: portWasExplicit ? url.port : '5432',
|
|
39
|
+
username: url.username ? decodeURIComponent(url.username) : '',
|
|
40
|
+
dbname,
|
|
41
|
+
},
|
|
42
|
+
portWasExplicit,
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
// Tokenizer for libpq DSN form: key=value pairs, values may be single-quoted
|
|
46
|
+
// when they contain spaces (libpq spec). Throws on malformed input.
|
|
47
|
+
const tokenizeDsn = (s) => {
|
|
48
|
+
const out = {};
|
|
49
|
+
let i = 0;
|
|
50
|
+
while (i < s.length) {
|
|
51
|
+
// skip leading whitespace
|
|
52
|
+
while (i < s.length && /\s/.test(s[i]))
|
|
53
|
+
i++;
|
|
54
|
+
if (i >= s.length)
|
|
55
|
+
break;
|
|
56
|
+
// read key
|
|
57
|
+
const keyStart = i;
|
|
58
|
+
while (i < s.length && s[i] !== '=' && !/\s/.test(s[i]))
|
|
59
|
+
i++;
|
|
60
|
+
if (i >= s.length || s[i] !== '=')
|
|
61
|
+
throw new ConnectionStringError(ErrInvalidConnectionString);
|
|
62
|
+
const key = s.slice(keyStart, i);
|
|
63
|
+
i++; // skip '='
|
|
64
|
+
// read value (possibly quoted)
|
|
65
|
+
let value = '';
|
|
66
|
+
if (s[i] === "'") {
|
|
67
|
+
i++;
|
|
68
|
+
while (i < s.length && s[i] !== "'") {
|
|
69
|
+
if (s[i] === '\\' && i + 1 < s.length) {
|
|
70
|
+
value += s[i + 1];
|
|
71
|
+
i += 2;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
value += s[i];
|
|
75
|
+
i++;
|
|
76
|
+
}
|
|
77
|
+
if (i >= s.length)
|
|
78
|
+
throw new ConnectionStringError(ErrInvalidConnectionString);
|
|
79
|
+
i++; // skip closing quote
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
while (i < s.length && !/\s/.test(s[i])) {
|
|
83
|
+
value += s[i];
|
|
84
|
+
i++;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
out[key.toLowerCase()] = value;
|
|
88
|
+
}
|
|
89
|
+
return out;
|
|
90
|
+
};
|
|
91
|
+
const parseDsn = (s) => {
|
|
92
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
93
|
+
const tokens = tokenizeDsn(s);
|
|
94
|
+
if (tokens.password)
|
|
95
|
+
throw new ConnectionStringError(ErrPasswordInConnectionString);
|
|
96
|
+
const host = (_b = (_a = tokens.host) !== null && _a !== void 0 ? _a : tokens.hostaddr) !== null && _b !== void 0 ? _b : '';
|
|
97
|
+
if (host.includes(','))
|
|
98
|
+
throw new ConnectionStringError(ErrMultiHost);
|
|
99
|
+
const portRaw = (_c = tokens.port) !== null && _c !== void 0 ? _c : '';
|
|
100
|
+
const portWasExplicit = portRaw !== '';
|
|
101
|
+
return {
|
|
102
|
+
fields: {
|
|
103
|
+
host,
|
|
104
|
+
port: portWasExplicit ? portRaw : '5432',
|
|
105
|
+
username: (_e = (_d = tokens.user) !== null && _d !== void 0 ? _d : tokens.username) !== null && _e !== void 0 ? _e : '',
|
|
106
|
+
dbname: (_g = (_f = tokens.dbname) !== null && _f !== void 0 ? _f : tokens.database) !== null && _g !== void 0 ? _g : '',
|
|
107
|
+
},
|
|
108
|
+
portWasExplicit,
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
export const connectionStringToFields = (s) => {
|
|
112
|
+
const trimmed = s.trim();
|
|
113
|
+
if (!trimmed)
|
|
114
|
+
throw new ConnectionStringError(ErrInvalidConnectionString);
|
|
115
|
+
if (isUri(trimmed))
|
|
116
|
+
return parseUri(trimmed);
|
|
117
|
+
if (trimmed.includes('='))
|
|
118
|
+
return parseDsn(trimmed);
|
|
119
|
+
throw new ConnectionStringError(ErrInvalidConnectionString);
|
|
120
|
+
};
|
|
121
|
+
// formatHost wraps IPv6 literals in brackets so the resulting URI parses cleanly.
|
|
122
|
+
const formatHost = (host) => (host.includes(':') ? `[${host}]` : host);
|
|
123
|
+
export const connectionStringFromFields = (fields, opts = {}) => {
|
|
124
|
+
const userPart = fields.username ? `${encodeURIComponent(fields.username)}@` : '';
|
|
125
|
+
const showPort = fields.port && !(opts.omitDefaultPort && fields.port === '5432');
|
|
126
|
+
const portPart = showPort ? `:${fields.port}` : '';
|
|
127
|
+
const dbPart = fields.dbname ? `/${encodeURIComponent(fields.dbname)}` : '';
|
|
128
|
+
return `postgres://${userPart}${formatHost(fields.host)}${portPart}${dbPart}`;
|
|
129
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Shared image-catalog constants. Kept in its own module so both
|
|
2
|
+
// `configOptions.ts` and `utils/index.ts` can read them without creating
|
|
3
|
+
// an import cycle (utils → configOptions today).
|
|
4
|
+
export const genericImagePrefix = 'postgresai/extended-postgres';
|
|
5
|
+
// Predefined Docker image catalog for the Generic Postgres image. If a
|
|
6
|
+
// user's config references a tag not listed here, createEnhancedDockerImages
|
|
7
|
+
// in utils/index.ts appends it at runtime.
|
|
8
|
+
export 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
|
+
};
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
export declare const Configuration: (({ instanceId, switchActiveTab, reload,
|
|
2
|
+
export declare const Configuration: (({ instanceId, switchActiveTab, reload, disableConfigModification, }: {
|
|
3
3
|
instanceId: string;
|
|
4
4
|
switchActiveTab: (_: null, activeTab: number) => void;
|
|
5
5
|
reload: () => void;
|
|
6
|
-
isConfigurationActive: boolean;
|
|
7
6
|
disableConfigModification?: boolean | undefined;
|
|
8
7
|
}) => JSX.Element) & {
|
|
9
8
|
displayName: string;
|
|
@@ -5,10 +5,10 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
5
5
|
* Unauthorized copying of this file, via any small is strictly prohibited
|
|
6
6
|
*--------------------------------------------------------------------------
|
|
7
7
|
*/
|
|
8
|
-
import { useState, useEffect, useMemo } from 'react';
|
|
8
|
+
import { useState, useEffect, useMemo, useRef } from 'react';
|
|
9
9
|
import { observer } from 'mobx-react-lite';
|
|
10
10
|
import Editor from '@monaco-editor/react';
|
|
11
|
-
import { Checkbox, FormControlLabel, Typography, Snackbar, makeStyles, Button, } from '@material-ui/core';
|
|
11
|
+
import { Checkbox, FormControlLabel, Typography, Snackbar, makeStyles, Button, Tab, Tabs, Radio, RadioGroup, } from '@material-ui/core';
|
|
12
12
|
import Box from '@mui/material/Box';
|
|
13
13
|
import { Modal } from '@postgres.ai/shared/components/Modal';
|
|
14
14
|
import { StubSpinner } from '@postgres.ai/shared/components/StubSpinner';
|
|
@@ -22,9 +22,11 @@ import { ConfigSectionTitle, Header, ModalTitle } from './Header';
|
|
|
22
22
|
import { dockerImageOptions, imagePgOptions } from './configOptions';
|
|
23
23
|
import { uniqueChipValue, customOrGenericImage, createEnhancedDockerImages, } from './utils';
|
|
24
24
|
import { SelectWithTooltip, InputWithChip, InputWithTooltip, } from './InputWithTooltip';
|
|
25
|
+
import { SimpleMode, buildProjectionFromProposed } from './SimpleMode';
|
|
26
|
+
import { getInitialConfigMode } from './configMode';
|
|
27
|
+
import { PhysicalMode } from './PhysicalMode';
|
|
25
28
|
import styles from './styles.module.scss';
|
|
26
29
|
import { formatTuningParams, formatTuningParamsToObj, } from '@postgres.ai/shared/types/api/endpoints/testDbSource';
|
|
27
|
-
const NON_LOGICAL_RETRIEVAL_MESSAGE = 'Configuration editing is only available in logical mode';
|
|
28
30
|
const PREVENT_MODIFYING_MESSAGE = 'Editing is disabled by admin';
|
|
29
31
|
const useStyles = makeStyles({
|
|
30
32
|
checkboxRoot: {
|
|
@@ -35,17 +37,31 @@ const useStyles = makeStyles({
|
|
|
35
37
|
fontSize: '12px',
|
|
36
38
|
},
|
|
37
39
|
}, { index: 1 });
|
|
38
|
-
export const Configuration = observer(({ instanceId, switchActiveTab, reload,
|
|
40
|
+
export const Configuration = observer(({ instanceId, switchActiveTab, reload, disableConfigModification, }) => {
|
|
41
|
+
var _a, _b;
|
|
39
42
|
const classes = useStyles();
|
|
40
43
|
const stores = useStores();
|
|
41
44
|
const { config, isConfigurationLoading, updateConfig, getSeImages, fullConfig, testDbSource, configError, getFullConfig, getFullConfigError, getEngine, } = stores.main;
|
|
42
45
|
const configData = config && JSON.parse(JSON.stringify(config));
|
|
43
|
-
const isConfigurationDisabled =
|
|
46
|
+
const isConfigurationDisabled = disableConfigModification;
|
|
44
47
|
const [dleEdition, setDledition] = useState('');
|
|
45
48
|
const isCeEdition = dleEdition === 'community';
|
|
46
49
|
const filteredDockerImageOptions = isCeEdition
|
|
47
50
|
? dockerImageOptions.filter((option) => option.type === 'custom' || option.type === 'Generic Postgres')
|
|
48
51
|
: dockerImageOptions;
|
|
52
|
+
const [userPickedMode, setUserPickedMode] = useState(null);
|
|
53
|
+
// Seeded lazily — only once configData transitions from null to non-null.
|
|
54
|
+
// Prevents the Simple/Expert default from flipping mid-session when an
|
|
55
|
+
// Apply triggers a refetch and the recomputed default would differ.
|
|
56
|
+
const [initialMode, setInitialMode] = useState(null);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (initialMode === null && configData) {
|
|
59
|
+
setInitialMode(getInitialConfigMode(configData.host, configData.retrievalMode));
|
|
60
|
+
}
|
|
61
|
+
}, [configData, initialMode]);
|
|
62
|
+
const configMode = (_a = userPickedMode !== null && userPickedMode !== void 0 ? userPickedMode : initialMode) !== null && _a !== void 0 ? _a : 'simple';
|
|
63
|
+
const setConfigMode = setUserPickedMode;
|
|
64
|
+
const portInitFromConfig = useRef(false);
|
|
49
65
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
50
66
|
const [submitState, setSubmitState] = useState({
|
|
51
67
|
status: '',
|
|
@@ -97,6 +113,8 @@ export const Configuration = observer(({ instanceId, switchActiveTab, reload, is
|
|
|
97
113
|
});
|
|
98
114
|
await updateConfig({
|
|
99
115
|
...values,
|
|
116
|
+
// Preserve configs that originally had no port: key.
|
|
117
|
+
...(omitPortOnSubmit && { port: '' }),
|
|
100
118
|
tuningParams: formatTuningParamsToObj(values.tuningParams),
|
|
101
119
|
}, instanceId).then((response) => {
|
|
102
120
|
if (response === null || response === void 0 ? void 0 : response.ok) {
|
|
@@ -107,7 +125,7 @@ export const Configuration = observer(({ instanceId, switchActiveTab, reload, is
|
|
|
107
125
|
}
|
|
108
126
|
});
|
|
109
127
|
};
|
|
110
|
-
const [{ formik, connectionData, isConnectionDataValid }] = useForm(onSubmit);
|
|
128
|
+
const [{ formik, connectionData, isConnectionDataValid, connectionString, connectionStringError, onConnectionStringChange, markPortInitialState, omitPortOnSubmit, },] = useForm(onSubmit);
|
|
111
129
|
// Memoized enhanced Docker images to avoid recreation on every render
|
|
112
130
|
// This combines predefined images with any custom image from configuration
|
|
113
131
|
const enhancedDockerImages = useMemo(() => {
|
|
@@ -413,6 +431,10 @@ export const Configuration = observer(({ instanceId, switchActiveTab, reload, is
|
|
|
413
431
|
// Set initial data, empty string for password
|
|
414
432
|
useEffect(() => {
|
|
415
433
|
if (configData) {
|
|
434
|
+
if (!portInitFromConfig.current) {
|
|
435
|
+
markPortInitialState(configData.port == null || configData.port === '');
|
|
436
|
+
portInitFromConfig.current = true;
|
|
437
|
+
}
|
|
416
438
|
for (const [key, value] of Object.entries(configData)) {
|
|
417
439
|
if (key !== 'password') {
|
|
418
440
|
formik.setFieldValue(key, value);
|
|
@@ -494,91 +516,98 @@ export const Configuration = observer(({ instanceId, switchActiveTab, reload, is
|
|
|
494
516
|
}, anchorOrigin: { vertical: 'bottom', horizontal: 'right' }, open: (isConfigurationDisabled || Boolean(dockerState.error)) &&
|
|
495
517
|
!isModalOpen, message: Boolean(dockerState.error)
|
|
496
518
|
? dockerState.error
|
|
497
|
-
:
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
}, disabled:
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
: testConnectionState.default.message.status
|
|
510
|
-
? testConnectionState.default.message.status
|
|
511
|
-
: '', message: testConnectionState.default.error ||
|
|
512
|
-
testConnectionState.default.message.message })) : null] }), _jsx(InputWithTooltip, { label: "pg_dump jobs", value: formik.values.dumpParallelJobs, tooltipText: tooltipText.dumpParallelJobs, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('dumpParallelJobs', e.target.value) }), _jsx(InputWithChip, { value: formik.values.pgDumpCustomOptions, label: "pg_dump customOptions", id: "pgDumpCustomOptions", tooltipText: tooltipText.pgDumpCustomOptions, handleDeleteChip: handleDeleteChip, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('pgDumpCustomOptions', e.target.value) }), _jsx(FormControlLabel, { style: { maxWidth: 'max-content' }, control: _jsx(Checkbox, { name: "dumpIgnoreErrors", checked: formik.values.dumpIgnoreErrors, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('dumpIgnoreErrors', e.target.checked), classes: {
|
|
513
|
-
root: classes.checkboxRoot,
|
|
514
|
-
} }), label: 'Ignore errors during logical data dump' })] })] }), _jsxs(Box, { mb: 2, mt: 1, children: [_jsx(ConfigSectionTitle, { tag: "databaseContainer" }), _jsx("span", { className: classes.grayText, style: { margin: '0.5rem 0 1rem 0', display: 'block' }, children: "DBLab manages various database containers, such as clones. This section defines default container settings." }), _jsxs("div", { children: [_jsx(SelectWithTooltip, { label: "dockerImage - choose from the list *", value: formik.values.dockerImageType, error: Boolean(formik.errors.dockerImageType), tooltipText: tooltipText.dockerImageType, disabled: isConfigurationDisabled || dockerState.loading, items: filteredDockerImageOptions.map((image) => {
|
|
515
|
-
return {
|
|
516
|
-
value: image.type,
|
|
517
|
-
children: image.name,
|
|
518
|
-
};
|
|
519
|
-
}), onChange: handleDockerImageSelect }), formik.values.dockerImageType === 'custom' ? (_jsx(InputWithTooltip, { label: "dockerImage *", value: formik.values.dockerImage, error: formik.errors.dockerImage, tooltipText: tooltipText.dockerImage, disabled: isConfigurationDisabled, onChange: (e) => {
|
|
520
|
-
formik.setValues({
|
|
521
|
-
...formik.values,
|
|
522
|
-
dockerImage: e.target.value,
|
|
523
|
-
dockerPath: e.target.value,
|
|
524
|
-
});
|
|
525
|
-
} })) : (_jsxs(_Fragment, { children: [_jsx(SelectWithTooltip, { label: "dockerImage - Postgres major version *", value: formik.values.dockerImage, error: Boolean(formik.errors.dockerImage), tooltipText: tooltipText.dockerImage, disabled: isConfigurationDisabled ||
|
|
526
|
-
dockerState.loading ||
|
|
527
|
-
!dockerState.images.length, loading: dockerState.loading, items: dockerState.images
|
|
528
|
-
.slice()
|
|
529
|
-
.reverse()
|
|
530
|
-
.map((image) => {
|
|
531
|
-
return {
|
|
532
|
-
value: image,
|
|
533
|
-
children: image,
|
|
534
|
-
};
|
|
535
|
-
}), onChange: handleDockerVersionSelect }), _jsxs(Box, { mt: 0.5, mb: 2, children: [_jsxs(Button, { variant: "outlined", color: "secondary", onClick: () => {
|
|
519
|
+
: PREVENT_MODIFYING_MESSAGE, className: styles.snackbar }), !config && isConfigurationLoading ? (_jsx("div", { className: styles.spinnerContainer, children: _jsx(Spinner, { size: "lg", className: styles.spinner }) })) : (_jsxs(Box, { children: [_jsx(Header, { retrievalMode: formik.values.retrievalMode, setOpen: handleModalClick }), _jsxs(Tabs, { value: configMode, onChange: (_, value) => setConfigMode(value), indicatorColor: "primary", textColor: "primary", "aria-label": "Configuration mode", children: [_jsx(Tab, { value: "simple", label: "Simple" }), _jsx(Tab, { value: "expert", label: "Expert" })] }), configMode === 'simple' ? (_jsx(SimpleMode, { instanceId: instanceId, disabled: isConfigurationDisabled, onApplied: switchTab, onEdit: (proposed, password) => {
|
|
520
|
+
const projection = buildProjectionFromProposed(proposed, password);
|
|
521
|
+
formik.setValues({ ...formik.values, ...projection });
|
|
522
|
+
setConfigMode('expert');
|
|
523
|
+
} })) : null, configMode === 'expert' ? (_jsxs(_Fragment, { children: [_jsxs(Box, { children: [_jsx(Box, { children: _jsx(FormControlLabel, { control: _jsx(Checkbox, { name: "debug", checked: formik.values.debug, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('debug', e.target.checked), classes: {
|
|
524
|
+
root: classes.checkboxRoot,
|
|
525
|
+
} }), label: 'Debug mode' }) }), _jsxs(Box, { mb: 1, mt: 1, children: [_jsx(ConfigSectionTitle, { tag: "retrieval" }), _jsxs(Box, { mt: 1, mb: 1, children: [_jsx(Typography, { className: styles.subsection, children: "Retrieval mode" }), _jsxs(RadioGroup, { row: true, "aria-label": "retrieval mode", value: formik.values.retrievalMode, onChange: (_, value) => {
|
|
526
|
+
formik.setFieldValue('retrievalMode', value);
|
|
527
|
+
}, children: [_jsx(FormControlLabel, { value: "logical", control: _jsx(Radio, { disabled: isConfigurationDisabled }), label: "Logical (dump/restore)" }), _jsx(FormControlLabel, { value: "physical", control: _jsx(Radio, { disabled: isConfigurationDisabled }), label: "Physical (WAL-G / pgBackRest)" })] })] }), formik.values.retrievalMode === 'physical' && (_jsx(PhysicalMode, { values: formik.values, onChange: (key, value) => formik.setFieldValue(key, value, key === 'physicalEnvs'), disabled: isConfigurationDisabled, envsKeyErrors: (_b = formik.errors.physicalEnvs) === null || _b === void 0 ? void 0 : _b.map((row) => row === null || row === void 0 ? void 0 : row.key) })), formik.values.retrievalMode === 'logical' && (_jsxs(Box, { mt: 1, children: [_jsx(Typography, { className: styles.subsection, children: "Subsection \"retrieval.spec.logicalDump\"" }), _jsx("span", { className: classes.grayText, children: "Source database credentials and dumping options." }), _jsx(InputWithTooltip, { label: "Connection string *", value: connectionString, error: connectionStringError ||
|
|
528
|
+
formik.errors.host ||
|
|
529
|
+
formik.errors.username ||
|
|
530
|
+
formik.errors.dbname, tooltipText: () => (_jsxs(_Fragment, { children: ["URI form: ", _jsx("code", { children: "postgres://user@host:5432/dbname" }), ". DSN form is also accepted. Do not include the password here \u2014 use the Password field below."] })), disabled: isConfigurationDisabled, onChange: (e) => onConnectionStringChange(e.target.value) }), _jsx(Box, { mt: 0.5, mb: 1, children: _jsxs("span", { className: classes.grayText, "data-testid": "connection-string-parsed", children: ["host: ", formik.values.host || '—', " | port:", ' ', formik.values.port || '5432 (default)', " | user:", ' ', formik.values.username || '—', " | dbname:", ' ', formik.values.dbname || '—'] }) }), _jsx(InputWithTooltip, { type: "password", value: formik.values.password, label: "source.connection.password", tooltipText: tooltipText.password, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('password', e.target.value) }), _jsx(InputWithChip, { id: "databases", value: formik.values.databases, label: "Databases to copy", tooltipText: tooltipText.databases, handleDeleteChip: handleDeleteChip, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('databases', e.target.value) }), _jsxs(Box, { mt: 3, mb: 3, children: [_jsxs(Button, { variant: "outlined", color: "secondary", onClick: () => {
|
|
536
531
|
onTestConnectionClick({
|
|
537
|
-
type: '
|
|
532
|
+
type: 'default',
|
|
538
533
|
});
|
|
539
|
-
}, disabled: testConnectionState.
|
|
540
|
-
isConfigurationDisabled, children: ["
|
|
541
|
-
|
|
542
|
-
testConnectionState.dockerImage.message
|
|
534
|
+
}, disabled: testConnectionState.default.loading ||
|
|
535
|
+
isConfigurationDisabled, children: ["Test connection", testConnectionState.default.loading && (_jsx(Spinner, { size: "sm", className: styles.spinner }))] }), testConnectionState.default.message.status ||
|
|
536
|
+
testConnectionState.default.error ? (_jsx(ResponseMessage, { type: testConnectionState.default.error
|
|
543
537
|
? 'error'
|
|
544
|
-
:
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
538
|
+
: testConnectionState.default.message.status
|
|
539
|
+
? testConnectionState.default.message.status
|
|
540
|
+
: '', message: testConnectionState.default.error ||
|
|
541
|
+
testConnectionState.default.message.message })) : null] }), _jsx(InputWithTooltip, { label: "pg_dump jobs", value: formik.values.dumpParallelJobs, tooltipText: tooltipText.dumpParallelJobs, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('dumpParallelJobs', e.target.value) }), _jsx(InputWithChip, { value: formik.values.pgDumpCustomOptions, label: "pg_dump customOptions", id: "pgDumpCustomOptions", tooltipText: tooltipText.pgDumpCustomOptions, handleDeleteChip: handleDeleteChip, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('pgDumpCustomOptions', e.target.value) }), _jsx(FormControlLabel, { style: { maxWidth: 'max-content' }, control: _jsx(Checkbox, { name: "dumpIgnoreErrors", checked: formik.values.dumpIgnoreErrors, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('dumpIgnoreErrors', e.target.checked), classes: {
|
|
542
|
+
root: classes.checkboxRoot,
|
|
543
|
+
} }), label: 'Ignore errors during logical data dump' })] }))] }), _jsxs(Box, { mb: 2, mt: 1, children: [_jsx(ConfigSectionTitle, { tag: "databaseContainer" }), _jsx("span", { className: classes.grayText, style: { margin: '0.5rem 0 1rem 0', display: 'block' }, children: "DBLab manages various database containers, such as clones. This section defines default container settings." }), _jsxs("div", { children: [_jsx(SelectWithTooltip, { label: "dockerImage - choose from the list *", value: formik.values.dockerImageType, error: Boolean(formik.errors.dockerImageType), tooltipText: tooltipText.dockerImageType, disabled: isConfigurationDisabled || dockerState.loading, items: filteredDockerImageOptions.map((image) => {
|
|
544
|
+
return {
|
|
545
|
+
value: image.type,
|
|
546
|
+
children: image.name,
|
|
547
|
+
};
|
|
548
|
+
}), onChange: handleDockerImageSelect }), formik.values.dockerImageType === 'custom' ? (_jsx(InputWithTooltip, { label: "dockerImage *", value: formik.values.dockerImage, error: formik.errors.dockerImage, tooltipText: tooltipText.dockerImage, disabled: isConfigurationDisabled, onChange: (e) => {
|
|
550
549
|
formik.setValues({
|
|
551
550
|
...formik.values,
|
|
552
|
-
|
|
553
|
-
dockerPath:
|
|
551
|
+
dockerImage: e.target.value,
|
|
552
|
+
dockerPath: e.target.value,
|
|
554
553
|
});
|
|
555
|
-
},
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
554
|
+
} })) : (_jsxs(_Fragment, { children: [_jsx(SelectWithTooltip, { label: "dockerImage - Postgres major version *", value: formik.values.dockerImage, error: Boolean(formik.errors.dockerImage), tooltipText: tooltipText.dockerImage, disabled: isConfigurationDisabled ||
|
|
555
|
+
dockerState.loading ||
|
|
556
|
+
!dockerState.images.length, loading: dockerState.loading, items: dockerState.images
|
|
557
|
+
.slice()
|
|
558
|
+
.reverse()
|
|
559
|
+
.map((image) => {
|
|
560
|
+
return {
|
|
561
|
+
value: image,
|
|
562
|
+
children: image,
|
|
563
|
+
};
|
|
564
|
+
}), onChange: handleDockerVersionSelect }), _jsxs(Box, { mt: 0.5, mb: 2, children: [_jsxs(Button, { variant: "outlined", color: "secondary", onClick: () => {
|
|
565
|
+
onTestConnectionClick({
|
|
566
|
+
type: 'dockerImage',
|
|
567
|
+
});
|
|
568
|
+
}, disabled: testConnectionState.dockerImage.loading ||
|
|
569
|
+
isConfigurationDisabled, children: ["Get version from source", testConnectionState.dockerImage.loading && (_jsx(Spinner, { size: "sm", className: styles.spinner }))] }), testConnectionState.dockerImage.message.status ===
|
|
570
|
+
'error' || testConnectionState.dockerImage.error ? (_jsx(ResponseMessage, { type: testConnectionState.dockerImage.error ||
|
|
571
|
+
testConnectionState.dockerImage.message
|
|
572
|
+
? 'error'
|
|
573
|
+
: '', message: testConnectionState.dockerImage.error ||
|
|
574
|
+
testConnectionState.dockerImage.message.message })) : null] }), _jsx(SelectWithTooltip, { label: "dockerImage - tag *", value: formik.values.dockerTag, error: Boolean(formik.errors.dockerTag), tooltipText: tooltipText.dockerTag, disabled: isConfigurationDisabled ||
|
|
575
|
+
dockerState.loading ||
|
|
576
|
+
!dockerState.tags.length, loading: dockerState.loading, onChange: (e) => {
|
|
577
|
+
var _a;
|
|
578
|
+
const currentLocation = (_a = dockerState.data.find((image) => image.tag === e.target.value)) === null || _a === void 0 ? void 0 : _a.location;
|
|
579
|
+
formik.setValues({
|
|
580
|
+
...formik.values,
|
|
581
|
+
dockerTag: e.target.value,
|
|
582
|
+
dockerPath: currentLocation,
|
|
583
|
+
});
|
|
584
|
+
}, items: dockerState.tags.map((image) => {
|
|
585
|
+
return {
|
|
586
|
+
value: image,
|
|
587
|
+
children: image,
|
|
588
|
+
};
|
|
589
|
+
}) })] })), _jsxs(Typography, { paragraph: true, children: ["Cannot find your image? Reach out to support:", ' ', _jsxs("a", { href: 'https://postgres.ai/contact', target: "_blank", className: styles.externalLink, children: ["https://postgres.ai/contact", _jsx(ExternalIcon, { className: styles.externalIcon })] })] })] })] }), _jsxs(Box, { mb: 3, children: [_jsx(ConfigSectionTitle, { tag: "databaseConfigs" }), _jsx("span", { className: classes.grayText, style: { marginTop: '0.5rem', display: 'block' }, children: "Default PostgreSQL configuration used for all PostgreSQL instances running in containers managed by DBLab." }), _jsx(InputWithTooltip, { type: "textarea", label: "shared_buffers parameter", value: formik.values.sharedBuffers, tooltipText: tooltipText.sharedBuffers, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('sharedBuffers', e.target.value) }), _jsx(InputWithTooltip, { type: "textarea", label: "shared_preload_libraries", value: formik.values.sharedPreloadLibraries, tooltipText: tooltipText.sharedPreloadLibraries, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('sharedPreloadLibraries', e.target.value) }), _jsx(InputWithTooltip, { type: "textarea", label: "Query tuning parameters", value: typeof formik.values.tuningParams === 'object'
|
|
590
|
+
? Object.entries(formik.values.tuningParams)
|
|
591
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
592
|
+
.join('\n')
|
|
593
|
+
: formik.values.tuningParams, tooltipText: tooltipText.tuningParams, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('tuningParams', e.target.value) }), _jsxs(Button, { variant: "outlined", color: "secondary", onClick: () => {
|
|
594
|
+
onTestConnectionClick({
|
|
595
|
+
type: 'fetchTuning',
|
|
596
|
+
});
|
|
597
|
+
}, disabled: testConnectionState.fetchTuning.loading ||
|
|
598
|
+
isConfigurationDisabled, children: ["Get from source database", testConnectionState.fetchTuning.loading && (_jsx(Spinner, { size: "sm", className: styles.spinner }))] }), testConnectionState.fetchTuning.message.status === 'error' ||
|
|
599
|
+
testConnectionState.fetchTuning.error ? (_jsx(ResponseMessage, { type: testConnectionState.fetchTuning.error ||
|
|
600
|
+
testConnectionState.fetchTuning.message
|
|
601
|
+
? 'error'
|
|
602
|
+
: '', message: testConnectionState.fetchTuning.error ||
|
|
603
|
+
testConnectionState.fetchTuning.message.message })) : null] }), formik.values.retrievalMode === 'logical' && (_jsxs(Box, { children: [_jsxs(Box, { children: [_jsx(Typography, { className: styles.subsection, children: "Subsection \"retrieval.spec.logicalRestore\"" }), _jsx("span", { className: classes.grayText, children: "Restoring options." })] }), _jsx(InputWithTooltip, { label: "pg_restore jobs", value: formik.values.restoreParallelJobs, tooltipText: tooltipText.restoreParallelJobs, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('restoreParallelJobs', e.target.value) }), _jsx(InputWithChip, { value: formik.values.pgRestoreCustomOptions, label: "pg_restore customOptions", id: "pgRestoreCustomOptions", tooltipText: tooltipText.pgRestoreCustomOptions, handleDeleteChip: handleDeleteChip, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('pgRestoreCustomOptions', e.target.value) }), _jsx(InputWithTooltip, { type: "textarea", label: "Restore PostgreSQL configs", value: formik.values.restoreConfigs, tooltipText: tooltipText.restoreConfigs, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('restoreConfigs', e.target.value) }), _jsx(FormControlLabel, { style: { maxWidth: 'max-content' }, control: _jsx(Checkbox, { name: "restoreIgnoreErrors", checked: formik.values.restoreIgnoreErrors, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('restoreIgnoreErrors', e.target.checked), classes: {
|
|
604
|
+
root: classes.checkboxRoot,
|
|
605
|
+
} }), label: 'Ignore errors during logical data restore' })] })), _jsx(Box, { mt: 1, children: _jsx(Typography, { className: styles.subsection, children: "Subsection \"retrieval.refresh\"" }) }), _jsxs("span", { className: classes.grayText, children: ["Define full data refresh on schedule. The process requires at least one additional filesystem mount point. The schedule is to be specified using", ' ', _jsxs("a", { href: "https://en.wikipedia.org/wiki/Cron#Overview", target: "_blank", className: styles.externalLink, children: ["crontab format", _jsx(ExternalIcon, { className: styles.externalIcon })] }), "."] }), _jsx(InputWithTooltip, { label: "timetable", value: formik.values.timetable, tooltipText: tooltipText.timetable, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('timetable', e.target.value) })] }), _jsxs(Box, { mt: 2, mb: 2, sx: {
|
|
606
|
+
display: 'flex',
|
|
607
|
+
alignItems: 'center',
|
|
608
|
+
}, children: [_jsxs(Button, { variant: "contained", color: "secondary", onClick: () => {
|
|
609
|
+
formik.submitForm().then(() => {
|
|
610
|
+
scrollToField();
|
|
567
611
|
});
|
|
568
|
-
}, disabled:
|
|
569
|
-
isConfigurationDisabled, children: ["Get from source database", testConnectionState.fetchTuning.loading && (_jsx(Spinner, { size: "sm", className: styles.spinner }))] }), testConnectionState.fetchTuning.message.status === 'error' ||
|
|
570
|
-
testConnectionState.fetchTuning.error ? (_jsx(ResponseMessage, { type: testConnectionState.fetchTuning.error ||
|
|
571
|
-
testConnectionState.fetchTuning.message
|
|
572
|
-
? 'error'
|
|
573
|
-
: '', message: testConnectionState.fetchTuning.error ||
|
|
574
|
-
testConnectionState.fetchTuning.message.message })) : null] }), _jsxs(Box, { children: [_jsxs(Box, { children: [_jsx(Typography, { className: styles.subsection, children: "Subsection \"retrieval.spec.logicalRestore\"" }), _jsx("span", { className: classes.grayText, children: "Restoring options." })] }), _jsx(InputWithTooltip, { label: "pg_restore jobs", value: formik.values.restoreParallelJobs, tooltipText: tooltipText.restoreParallelJobs, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('restoreParallelJobs', e.target.value) }), _jsx(InputWithChip, { value: formik.values.pgRestoreCustomOptions, label: "pg_restore customOptions", id: "pgRestoreCustomOptions", tooltipText: tooltipText.pgRestoreCustomOptions, handleDeleteChip: handleDeleteChip, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('pgRestoreCustomOptions', e.target.value) }), _jsx(InputWithTooltip, { type: "textarea", label: "Restore PostgreSQL configs", value: formik.values.restoreConfigs, tooltipText: tooltipText.restoreConfigs, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('restoreConfigs', e.target.value) }), _jsx(FormControlLabel, { style: { maxWidth: 'max-content' }, control: _jsx(Checkbox, { name: "restoreIgnoreErrors", checked: formik.values.restoreIgnoreErrors, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('restoreIgnoreErrors', e.target.checked), classes: {
|
|
575
|
-
root: classes.checkboxRoot,
|
|
576
|
-
} }), label: 'Ignore errors during logical data restore' })] }), _jsx(Box, { mt: 1, children: _jsx(Typography, { className: styles.subsection, children: "Subsection \"retrieval.refresh\"" }) }), _jsxs("span", { className: classes.grayText, children: ["Define full data refresh on schedule. The process requires at least one additional filesystem mount point. The schedule is to be specified using", ' ', _jsxs("a", { href: "https://en.wikipedia.org/wiki/Cron#Overview", target: "_blank", className: styles.externalLink, children: ["crontab format", _jsx(ExternalIcon, { className: styles.externalIcon })] }), "."] }), _jsx(InputWithTooltip, { label: "timetable", value: formik.values.timetable, tooltipText: tooltipText.timetable, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('timetable', e.target.value) })] }), _jsxs(Box, { mt: 2, mb: 2, sx: {
|
|
577
|
-
display: 'flex',
|
|
578
|
-
alignItems: 'center',
|
|
579
|
-
}, children: [_jsxs(Button, { variant: "contained", color: "secondary", onClick: () => {
|
|
580
|
-
formik.submitForm().then(() => {
|
|
581
|
-
scrollToField();
|
|
582
|
-
});
|
|
583
|
-
}, disabled: formik.isSubmitting || isConfigurationDisabled, children: ["Apply changes", formik.isSubmitting && (_jsx(Spinner, { size: "sm", className: styles.spinner }))] }), _jsx(Box, { sx: { px: 2 }, children: _jsx(Button, { variant: "outlined", color: "secondary", onClick: switchTab, children: "Cancel" }) })] }), (submitState.status && submitState.response) || configError ? (_jsx(ResponseMessage, { type: configError ? 'error' : submitState.status, message: configError || submitState.response })) : null] })), _jsx(Modal, { title: _jsx(ModalTitle, {}), onClose: () => setIsModalOpen(false), isOpen: isModalOpen, size: "xl", children: _jsx(Editor, { height: "70vh", width: "100%", defaultLanguage: "yaml", value: getFullConfigError ? getFullConfigError : fullConfig, loading: _jsx(StubSpinner, {}), theme: "vs-light", options: { domReadOnly: true, readOnly: true } }) })] }));
|
|
612
|
+
}, disabled: formik.isSubmitting || isConfigurationDisabled, children: ["Apply changes", formik.isSubmitting && (_jsx(Spinner, { size: "sm", className: styles.spinner }))] }), _jsx(Box, { sx: { px: 2 }, children: _jsx(Button, { variant: "outlined", color: "secondary", onClick: switchTab, children: "Cancel" }) })] }), (submitState.status && submitState.response) || configError ? (_jsx(ResponseMessage, { type: configError ? 'error' : submitState.status, message: configError || submitState.response })) : null] })) : null] })), _jsx(Modal, { title: _jsx(ModalTitle, {}), onClose: () => setIsModalOpen(false), isOpen: isModalOpen, size: "xl", children: _jsx(Editor, { height: "70vh", width: "100%", defaultLanguage: "yaml", value: getFullConfigError ? getFullConfigError : fullConfig, loading: _jsx(StubSpinner, {}), theme: "vs-light", options: { domReadOnly: true, readOnly: true } }) })] }));
|
|
584
613
|
});
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
+
export declare type RetrievalMode = 'logical' | 'physical';
|
|
3
|
+
export declare type PhysicalTool = 'walg' | 'pgbackrest' | 'customTool' | '';
|
|
4
|
+
export declare type PhysicalEnv = {
|
|
5
|
+
key: string;
|
|
6
|
+
value: string;
|
|
7
|
+
};
|
|
2
8
|
export declare type FormValues = {
|
|
3
9
|
debug: boolean;
|
|
4
10
|
dockerImage: string;
|
|
@@ -22,6 +28,14 @@ export declare type FormValues = {
|
|
|
22
28
|
restoreConfigs: string;
|
|
23
29
|
pgDumpCustomOptions: string;
|
|
24
30
|
pgRestoreCustomOptions: string;
|
|
31
|
+
retrievalMode: RetrievalMode;
|
|
32
|
+
physicalTool: PhysicalTool;
|
|
33
|
+
physicalDockerImage: string;
|
|
34
|
+
physicalSyncEnabled: boolean;
|
|
35
|
+
physicalWalgBackupName: string;
|
|
36
|
+
physicalPgbackrestStanza: string;
|
|
37
|
+
physicalPgbackrestDelta: boolean;
|
|
38
|
+
physicalEnvs: PhysicalEnv[];
|
|
25
39
|
};
|
|
26
40
|
export declare const useForm: (onSubmit: (values: FormValues) => void) => {
|
|
27
41
|
formik: {
|
|
@@ -80,4 +94,10 @@ export declare const useForm: (onSubmit: (values: FormValues) => void) => {
|
|
|
80
94
|
dbname: string;
|
|
81
95
|
};
|
|
82
96
|
isConnectionDataValid: string;
|
|
97
|
+
connectionString: string;
|
|
98
|
+
connectionStringError: string | null;
|
|
99
|
+
onConnectionStringChange: (s: string) => void;
|
|
100
|
+
markPortInitialState: (wasUnset: boolean) => void;
|
|
101
|
+
markPortDirty: () => void;
|
|
102
|
+
omitPortOnSubmit: boolean;
|
|
83
103
|
}[];
|