@postgres.ai/shared 4.0.2-pr-1148 → 4.0.2-pr-1149
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/package.json +1 -1
- package/pages/Instance/Configuration/configOptions.d.ts +0 -6
- package/pages/Instance/Configuration/configOptions.js +0 -48
- package/pages/Instance/Configuration/index.d.ts +2 -1
- package/pages/Instance/Configuration/index.js +86 -115
- package/pages/Instance/Configuration/useForm.d.ts +0 -20
- package/pages/Instance/Configuration/useForm.js +5 -126
- package/pages/Instance/Configuration/utils/index.js +17 -1
- package/pages/Instance/index.js +3 -1
- package/pages/Instance/stores/Main.d.ts +0 -20
- package/pages/Instance/stores/Main.js +0 -9
- package/types/api/entities/config.d.ts +0 -32
- package/types/api/entities/config.js +18 -45
- package/pages/Instance/Configuration/PhysicalMode/EnvsEditor/index.d.ts +0 -11
- package/pages/Instance/Configuration/PhysicalMode/EnvsEditor/index.js +0 -24
- package/pages/Instance/Configuration/PhysicalMode/PgBackRest/index.d.ts +0 -10
- package/pages/Instance/Configuration/PhysicalMode/PgBackRest/index.js +0 -29
- package/pages/Instance/Configuration/PhysicalMode/Sync/index.d.ts +0 -9
- package/pages/Instance/Configuration/PhysicalMode/Sync/index.js +0 -14
- package/pages/Instance/Configuration/PhysicalMode/Walg/index.d.ts +0 -10
- package/pages/Instance/Configuration/PhysicalMode/Walg/index.js +0 -21
- package/pages/Instance/Configuration/PhysicalMode/index.d.ts +0 -10
- package/pages/Instance/Configuration/PhysicalMode/index.js +0 -17
- package/pages/Instance/Configuration/SimpleMode/PreviewCard.d.ts +0 -11
- package/pages/Instance/Configuration/SimpleMode/PreviewCard.js +0 -14
- package/pages/Instance/Configuration/SimpleMode/index.d.ts +0 -14
- package/pages/Instance/Configuration/SimpleMode/index.js +0 -107
- package/pages/Instance/Configuration/configMode.d.ts +0 -2
- package/pages/Instance/Configuration/configMode.js +0 -7
- package/pages/Instance/Configuration/connectionString.d.ts +0 -20
- package/pages/Instance/Configuration/connectionString.js +0 -129
- package/pages/Instance/Configuration/dockerCatalog.d.ts +0 -2
- package/pages/Instance/Configuration/dockerCatalog.js +0 -19
- package/types/api/endpoints/probeSource.d.ts +0 -32
- package/types/api/endpoints/probeSource.js +0 -1
package/package.json
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
export declare type ProviderImageMapping = {
|
|
2
|
-
imageType: string;
|
|
3
|
-
defaultTag?: string;
|
|
4
|
-
fallback: boolean;
|
|
5
|
-
};
|
|
6
|
-
export declare const providerKeyToImage: (providerKey: string, pgMajorVersion: number) => ProviderImageMapping;
|
|
7
1
|
export declare const dockerImageOptions: {
|
|
8
2
|
name: string;
|
|
9
3
|
type: string;
|
|
@@ -1,51 +1,3 @@
|
|
|
1
|
-
import { dockerImagesConfig } from './dockerCatalog';
|
|
2
|
-
// Mapping from the engine probe's provider key (probe.Provider) to a
|
|
3
|
-
// dockerImageOptions.type value the form already understands. Keys must
|
|
4
|
-
// match the values defined in engine/internal/retrieval/probe/provider.go
|
|
5
|
-
// (ProviderRDS, ProviderAurora, etc.) — see Task 18 in the plan.
|
|
6
|
-
const providerKeyToImageType = {
|
|
7
|
-
generic: 'Generic Postgres',
|
|
8
|
-
rds: 'rds',
|
|
9
|
-
aurora: 'aurora',
|
|
10
|
-
cloudsql: 'google-cloud-sql',
|
|
11
|
-
supabase: 'supabase',
|
|
12
|
-
heroku: 'heroku',
|
|
13
|
-
timescale: 'timescale-cloud',
|
|
14
|
-
};
|
|
15
|
-
// Reads the most recent tag for a given PG major from the shared catalog.
|
|
16
|
-
// SE images (rds, aurora, etc.) require the platform-only getSeImages call
|
|
17
|
-
// and have no entry here — they return defaultTag: undefined.
|
|
18
|
-
const genericDefaultTag = (pgMajorVersion) => {
|
|
19
|
-
if (!pgMajorVersion)
|
|
20
|
-
return undefined;
|
|
21
|
-
const version = String(pgMajorVersion);
|
|
22
|
-
const tags = dockerImagesConfig[version];
|
|
23
|
-
if (!tags || tags.length === 0)
|
|
24
|
-
return undefined;
|
|
25
|
-
return `${version}-${tags[0]}`;
|
|
26
|
-
};
|
|
27
|
-
// Resolves a probe provider key to a concrete docker image type the
|
|
28
|
-
// Configuration form can write into the projection. Unknown keys (including
|
|
29
|
-
// "azure", which has no matching SE image today) fall back to the generic
|
|
30
|
-
// Postgres image and set fallback=true so the UI can warn.
|
|
31
|
-
export const providerKeyToImage = (providerKey, pgMajorVersion) => {
|
|
32
|
-
const known = providerKeyToImageType[providerKey];
|
|
33
|
-
if (!known) {
|
|
34
|
-
return {
|
|
35
|
-
imageType: 'Generic Postgres',
|
|
36
|
-
defaultTag: genericDefaultTag(pgMajorVersion),
|
|
37
|
-
fallback: true,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
if (known === 'Generic Postgres') {
|
|
41
|
-
return {
|
|
42
|
-
imageType: 'Generic Postgres',
|
|
43
|
-
defaultTag: genericDefaultTag(pgMajorVersion),
|
|
44
|
-
fallback: false,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
return { imageType: known, defaultTag: undefined, fallback: false };
|
|
48
|
-
};
|
|
49
1
|
export const dockerImageOptions = [
|
|
50
2
|
{
|
|
51
3
|
name: 'Generic PostgreSQL (postgresai/extended-postgres)',
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
export declare const Configuration: (({ instanceId, switchActiveTab, reload, disableConfigModification, }: {
|
|
2
|
+
export declare const Configuration: (({ instanceId, switchActiveTab, reload, isConfigurationActive, disableConfigModification, }: {
|
|
3
3
|
instanceId: string;
|
|
4
4
|
switchActiveTab: (_: null, activeTab: number) => void;
|
|
5
5
|
reload: () => void;
|
|
6
|
+
isConfigurationActive: boolean;
|
|
6
7
|
disableConfigModification?: boolean | undefined;
|
|
7
8
|
}) => JSX.Element) & {
|
|
8
9
|
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
|
|
8
|
+
import { useState, useEffect, useMemo } 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,
|
|
11
|
+
import { Checkbox, FormControlLabel, Typography, Snackbar, makeStyles, Button, } 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,11 +22,9 @@ 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';
|
|
28
25
|
import styles from './styles.module.scss';
|
|
29
26
|
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';
|
|
30
28
|
const PREVENT_MODIFYING_MESSAGE = 'Editing is disabled by admin';
|
|
31
29
|
const useStyles = makeStyles({
|
|
32
30
|
checkboxRoot: {
|
|
@@ -37,31 +35,17 @@ const useStyles = makeStyles({
|
|
|
37
35
|
fontSize: '12px',
|
|
38
36
|
},
|
|
39
37
|
}, { index: 1 });
|
|
40
|
-
export const Configuration = observer(({ instanceId, switchActiveTab, reload, disableConfigModification, }) => {
|
|
41
|
-
var _a, _b;
|
|
38
|
+
export const Configuration = observer(({ instanceId, switchActiveTab, reload, isConfigurationActive, disableConfigModification, }) => {
|
|
42
39
|
const classes = useStyles();
|
|
43
40
|
const stores = useStores();
|
|
44
41
|
const { config, isConfigurationLoading, updateConfig, getSeImages, fullConfig, testDbSource, configError, getFullConfig, getFullConfigError, getEngine, } = stores.main;
|
|
45
42
|
const configData = config && JSON.parse(JSON.stringify(config));
|
|
46
|
-
const isConfigurationDisabled = disableConfigModification;
|
|
43
|
+
const isConfigurationDisabled = !isConfigurationActive || disableConfigModification;
|
|
47
44
|
const [dleEdition, setDledition] = useState('');
|
|
48
45
|
const isCeEdition = dleEdition === 'community';
|
|
49
46
|
const filteredDockerImageOptions = isCeEdition
|
|
50
47
|
? dockerImageOptions.filter((option) => option.type === 'custom' || option.type === 'Generic Postgres')
|
|
51
48
|
: 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);
|
|
65
49
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
66
50
|
const [submitState, setSubmitState] = useState({
|
|
67
51
|
status: '',
|
|
@@ -113,8 +97,6 @@ export const Configuration = observer(({ instanceId, switchActiveTab, reload, di
|
|
|
113
97
|
});
|
|
114
98
|
await updateConfig({
|
|
115
99
|
...values,
|
|
116
|
-
// Preserve configs that originally had no port: key.
|
|
117
|
-
...(omitPortOnSubmit && { port: '' }),
|
|
118
100
|
tuningParams: formatTuningParamsToObj(values.tuningParams),
|
|
119
101
|
}, instanceId).then((response) => {
|
|
120
102
|
if (response === null || response === void 0 ? void 0 : response.ok) {
|
|
@@ -125,7 +107,7 @@ export const Configuration = observer(({ instanceId, switchActiveTab, reload, di
|
|
|
125
107
|
}
|
|
126
108
|
});
|
|
127
109
|
};
|
|
128
|
-
const [{ formik, connectionData, isConnectionDataValid
|
|
110
|
+
const [{ formik, connectionData, isConnectionDataValid }] = useForm(onSubmit);
|
|
129
111
|
// Memoized enhanced Docker images to avoid recreation on every render
|
|
130
112
|
// This combines predefined images with any custom image from configuration
|
|
131
113
|
const enhancedDockerImages = useMemo(() => {
|
|
@@ -431,10 +413,6 @@ export const Configuration = observer(({ instanceId, switchActiveTab, reload, di
|
|
|
431
413
|
// Set initial data, empty string for password
|
|
432
414
|
useEffect(() => {
|
|
433
415
|
if (configData) {
|
|
434
|
-
if (!portInitFromConfig.current) {
|
|
435
|
-
markPortInitialState(configData.port == null || configData.port === '');
|
|
436
|
-
portInitFromConfig.current = true;
|
|
437
|
-
}
|
|
438
416
|
for (const [key, value] of Object.entries(configData)) {
|
|
439
417
|
if (key !== 'password') {
|
|
440
418
|
formik.setFieldValue(key, value);
|
|
@@ -516,98 +494,91 @@ export const Configuration = observer(({ instanceId, switchActiveTab, reload, di
|
|
|
516
494
|
}, anchorOrigin: { vertical: 'bottom', horizontal: 'right' }, open: (isConfigurationDisabled || Boolean(dockerState.error)) &&
|
|
517
495
|
!isModalOpen, message: Boolean(dockerState.error)
|
|
518
496
|
? dockerState.error
|
|
519
|
-
:
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
},
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
497
|
+
: disableConfigModification
|
|
498
|
+
? PREVENT_MODIFYING_MESSAGE
|
|
499
|
+
: NON_LOGICAL_RETRIEVAL_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: "logical", setOpen: handleModalClick }), _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: {
|
|
500
|
+
root: classes.checkboxRoot,
|
|
501
|
+
} }), label: 'Debug mode' }) }), _jsxs(Box, { mb: 1, mt: 1, children: [_jsx(ConfigSectionTitle, { tag: "retrieval" }), _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: "source.connection.host *", value: formik.values.host, error: formik.errors.host, tooltipText: tooltipText.host, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('host', e.target.value) }), _jsx(InputWithTooltip, { label: "source.connection.port *", value: formik.values.port, error: formik.errors.port, tooltipText: tooltipText.port, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('port', e.target.value) }), _jsx(InputWithTooltip, { label: "source.connection.username *", value: formik.values.username, error: formik.errors.username, tooltipText: tooltipText.username, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('username', e.target.value) }), _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(InputWithTooltip, { label: "source.connection.dbname *", value: formik.values.dbname, error: formik.errors.dbname, tooltipText: tooltipText.dbname, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('dbname', 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: () => {
|
|
502
|
+
onTestConnectionClick({
|
|
503
|
+
type: 'default',
|
|
504
|
+
});
|
|
505
|
+
}, disabled: testConnectionState.default.loading ||
|
|
506
|
+
isConfigurationDisabled, children: ["Test connection", testConnectionState.default.loading && (_jsx(Spinner, { size: "sm", className: styles.spinner }))] }), testConnectionState.default.message.status ||
|
|
507
|
+
testConnectionState.default.error ? (_jsx(ResponseMessage, { type: testConnectionState.default.error
|
|
508
|
+
? 'error'
|
|
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: () => {
|
|
531
536
|
onTestConnectionClick({
|
|
532
|
-
type: '
|
|
537
|
+
type: 'dockerImage',
|
|
533
538
|
});
|
|
534
|
-
}, disabled: testConnectionState.
|
|
535
|
-
isConfigurationDisabled, children: ["
|
|
536
|
-
testConnectionState.
|
|
539
|
+
}, disabled: testConnectionState.dockerImage.loading ||
|
|
540
|
+
isConfigurationDisabled, children: ["Get version from source", testConnectionState.dockerImage.loading && (_jsx(Spinner, { size: "sm", className: styles.spinner }))] }), testConnectionState.dockerImage.message.status ===
|
|
541
|
+
'error' || testConnectionState.dockerImage.error ? (_jsx(ResponseMessage, { type: testConnectionState.dockerImage.error ||
|
|
542
|
+
testConnectionState.dockerImage.message
|
|
537
543
|
? 'error'
|
|
538
|
-
: testConnectionState.
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
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) => {
|
|
544
|
+
: '', message: testConnectionState.dockerImage.error ||
|
|
545
|
+
testConnectionState.dockerImage.message.message })) : null] }), _jsx(SelectWithTooltip, { label: "dockerImage - tag *", value: formik.values.dockerTag, error: Boolean(formik.errors.dockerTag), tooltipText: tooltipText.dockerTag, disabled: isConfigurationDisabled ||
|
|
546
|
+
dockerState.loading ||
|
|
547
|
+
!dockerState.tags.length, loading: dockerState.loading, onChange: (e) => {
|
|
548
|
+
var _a;
|
|
549
|
+
const currentLocation = (_a = dockerState.data.find((image) => image.tag === e.target.value)) === null || _a === void 0 ? void 0 : _a.location;
|
|
549
550
|
formik.setValues({
|
|
550
551
|
...formik.values,
|
|
551
|
-
|
|
552
|
-
dockerPath:
|
|
552
|
+
dockerTag: e.target.value,
|
|
553
|
+
dockerPath: currentLocation,
|
|
553
554
|
});
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
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();
|
|
555
|
+
}, items: dockerState.tags.map((image) => {
|
|
556
|
+
return {
|
|
557
|
+
value: image,
|
|
558
|
+
children: image,
|
|
559
|
+
};
|
|
560
|
+
}) })] })), _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'
|
|
561
|
+
? Object.entries(formik.values.tuningParams)
|
|
562
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
563
|
+
.join('\n')
|
|
564
|
+
: formik.values.tuningParams, tooltipText: tooltipText.tuningParams, disabled: isConfigurationDisabled, onChange: (e) => formik.setFieldValue('tuningParams', e.target.value) }), _jsxs(Button, { variant: "outlined", color: "secondary", onClick: () => {
|
|
565
|
+
onTestConnectionClick({
|
|
566
|
+
type: 'fetchTuning',
|
|
611
567
|
});
|
|
612
|
-
}, disabled:
|
|
568
|
+
}, disabled: testConnectionState.fetchTuning.loading ||
|
|
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 } }) })] }));
|
|
613
584
|
});
|
|
@@ -1,10 +1,4 @@
|
|
|
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
|
-
};
|
|
8
2
|
export declare type FormValues = {
|
|
9
3
|
debug: boolean;
|
|
10
4
|
dockerImage: string;
|
|
@@ -28,14 +22,6 @@ export declare type FormValues = {
|
|
|
28
22
|
restoreConfigs: string;
|
|
29
23
|
pgDumpCustomOptions: string;
|
|
30
24
|
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[];
|
|
39
25
|
};
|
|
40
26
|
export declare const useForm: (onSubmit: (values: FormValues) => void) => {
|
|
41
27
|
formik: {
|
|
@@ -94,10 +80,4 @@ export declare const useForm: (onSubmit: (values: FormValues) => void) => {
|
|
|
94
80
|
dbname: string;
|
|
95
81
|
};
|
|
96
82
|
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;
|
|
103
83
|
}[];
|
|
@@ -4,64 +4,14 @@
|
|
|
4
4
|
* Unauthorized copying of this file, via any medium is strictly prohibited
|
|
5
5
|
*--------------------------------------------------------------------------
|
|
6
6
|
*/
|
|
7
|
-
import { useMemo, useState } from 'react';
|
|
8
7
|
import { useFormik } from 'formik';
|
|
9
8
|
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.
|
|
14
9
|
const Schema = Yup.object().shape({
|
|
15
10
|
dockerImage: Yup.string().required('Docker image is required'),
|
|
16
|
-
dbname: Yup.string().
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
}),
|
|
11
|
+
dbname: Yup.string().required('Dbname is required'),
|
|
12
|
+
host: Yup.string().required('Host is required'),
|
|
13
|
+
port: Yup.string().required('Port is required'),
|
|
14
|
+
username: Yup.string().required('Username is required'),
|
|
65
15
|
});
|
|
66
16
|
export const useForm = (onSubmit) => {
|
|
67
17
|
const formik = useFormik({
|
|
@@ -88,71 +38,12 @@ export const useForm = (onSubmit) => {
|
|
|
88
38
|
pgRestoreCustomOptions: '',
|
|
89
39
|
dumpIgnoreErrors: false,
|
|
90
40
|
restoreIgnoreErrors: false,
|
|
91
|
-
retrievalMode: 'logical',
|
|
92
|
-
physicalTool: '',
|
|
93
|
-
physicalDockerImage: '',
|
|
94
|
-
physicalSyncEnabled: false,
|
|
95
|
-
physicalWalgBackupName: '',
|
|
96
|
-
physicalPgbackrestStanza: '',
|
|
97
|
-
physicalPgbackrestDelta: false,
|
|
98
|
-
physicalEnvs: [],
|
|
99
41
|
},
|
|
100
42
|
validationSchema: Schema,
|
|
101
43
|
onSubmit,
|
|
102
44
|
validateOnBlur: false,
|
|
103
45
|
validateOnChange: false,
|
|
104
46
|
});
|
|
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;
|
|
156
47
|
const formatDatabaseArray = (database) => {
|
|
157
48
|
let databases = [];
|
|
158
49
|
const splitDatabaseArray = database.split(/[,(\s)(\n)(\r)(\t)(\r\n)]/);
|
|
@@ -180,17 +71,5 @@ export const useForm = (onSubmit) => {
|
|
|
180
71
|
formik.values.port &&
|
|
181
72
|
formik.values.username &&
|
|
182
73
|
formik.values.dbname;
|
|
183
|
-
return [
|
|
184
|
-
{
|
|
185
|
-
formik,
|
|
186
|
-
connectionData,
|
|
187
|
-
isConnectionDataValid,
|
|
188
|
-
connectionString,
|
|
189
|
-
connectionStringError,
|
|
190
|
-
onConnectionStringChange,
|
|
191
|
-
markPortInitialState,
|
|
192
|
-
markPortDirty,
|
|
193
|
-
omitPortOnSubmit,
|
|
194
|
-
},
|
|
195
|
-
];
|
|
74
|
+
return [{ formik, connectionData, isConnectionDataValid }];
|
|
196
75
|
};
|
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { dockerImageOptions } from '../configOptions';
|
|
2
|
-
import { dockerImagesConfig, genericImagePrefix } from '../dockerCatalog';
|
|
3
2
|
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
|
+
};
|
|
4
20
|
export const uniqueChipValue = (values) => {
|
|
5
21
|
const splitChipArray = values.split(/[,(\s)(\n)(\r)(\t)(\r\n)]/);
|
|
6
22
|
let databaseArray = [];
|