@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.
Files changed (35) hide show
  1. package/package.json +1 -1
  2. package/pages/Instance/Configuration/configOptions.d.ts +0 -6
  3. package/pages/Instance/Configuration/configOptions.js +0 -48
  4. package/pages/Instance/Configuration/index.d.ts +2 -1
  5. package/pages/Instance/Configuration/index.js +86 -115
  6. package/pages/Instance/Configuration/useForm.d.ts +0 -20
  7. package/pages/Instance/Configuration/useForm.js +5 -126
  8. package/pages/Instance/Configuration/utils/index.js +17 -1
  9. package/pages/Instance/index.js +3 -1
  10. package/pages/Instance/stores/Main.d.ts +0 -20
  11. package/pages/Instance/stores/Main.js +0 -9
  12. package/types/api/entities/config.d.ts +0 -32
  13. package/types/api/entities/config.js +18 -45
  14. package/pages/Instance/Configuration/PhysicalMode/EnvsEditor/index.d.ts +0 -11
  15. package/pages/Instance/Configuration/PhysicalMode/EnvsEditor/index.js +0 -24
  16. package/pages/Instance/Configuration/PhysicalMode/PgBackRest/index.d.ts +0 -10
  17. package/pages/Instance/Configuration/PhysicalMode/PgBackRest/index.js +0 -29
  18. package/pages/Instance/Configuration/PhysicalMode/Sync/index.d.ts +0 -9
  19. package/pages/Instance/Configuration/PhysicalMode/Sync/index.js +0 -14
  20. package/pages/Instance/Configuration/PhysicalMode/Walg/index.d.ts +0 -10
  21. package/pages/Instance/Configuration/PhysicalMode/Walg/index.js +0 -21
  22. package/pages/Instance/Configuration/PhysicalMode/index.d.ts +0 -10
  23. package/pages/Instance/Configuration/PhysicalMode/index.js +0 -17
  24. package/pages/Instance/Configuration/SimpleMode/PreviewCard.d.ts +0 -11
  25. package/pages/Instance/Configuration/SimpleMode/PreviewCard.js +0 -14
  26. package/pages/Instance/Configuration/SimpleMode/index.d.ts +0 -14
  27. package/pages/Instance/Configuration/SimpleMode/index.js +0 -107
  28. package/pages/Instance/Configuration/configMode.d.ts +0 -2
  29. package/pages/Instance/Configuration/configMode.js +0 -7
  30. package/pages/Instance/Configuration/connectionString.d.ts +0 -20
  31. package/pages/Instance/Configuration/connectionString.js +0 -129
  32. package/pages/Instance/Configuration/dockerCatalog.d.ts +0 -2
  33. package/pages/Instance/Configuration/dockerCatalog.js +0 -19
  34. package/types/api/endpoints/probeSource.d.ts +0 -32
  35. package/types/api/endpoints/probeSource.js +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postgres.ai/shared",
3
- "version": "4.0.2-pr-1148",
3
+ "version": "4.0.2-pr-1149",
4
4
  "main": "index.js",
5
5
  "types": "index.d.ts",
6
6
  "peerDependencies": {
@@ -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, useRef } from 'react';
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, Tab, Tabs, Radio, RadioGroup, } from '@material-ui/core';
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, connectionString, connectionStringError, onConnectionStringChange, markPortInitialState, omitPortOnSubmit, },] = useForm(onSubmit);
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
- : 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: () => {
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: 'default',
537
+ type: 'dockerImage',
533
538
  });
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
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.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) => {
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
- dockerImage: e.target.value,
552
- dockerPath: e.target.value,
552
+ dockerTag: e.target.value,
553
+ dockerPath: currentLocation,
553
554
  });
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();
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: 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 } }) })] }));
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().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
- }),
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 = [];