@postgres.ai/shared 4.0.0-pr-695.12 → 4.0.0-pr-1042
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/CreateBranch/index.js +1 -1
- package/pages/CreateBranch/useForm.js +17 -1
- package/pages/CreateClone/index.js +2 -2
- package/pages/CreateClone/useForm.js +9 -1
- package/pages/Instance/index.js +3 -3
- package/pages/Instance/stores/Main.d.ts +1 -0
- package/pages/Instance/stores/Main.js +10 -1
package/package.json
CHANGED
|
@@ -116,7 +116,7 @@ export const CreateBranchPage = observer(({ instanceId, api, elements, routes, i
|
|
|
116
116
|
}
|
|
117
117
|
return (_jsxs(_Fragment, { children: [elements.breadcrumbs, _jsx(SectionTitle, { tag: "h1", level: 1, text: "Create branch", className: classes.title, children: _jsx(InstanceTabs, { tab: TABS_INDEX.BRANCHES, isPlatform: isPlatform, instanceId: instanceId, hasLogs: api.initWS !== undefined, hideInstanceTabs: hideBranchingFeatures }) }), _jsxs("div", { className: classes.wrapper, children: [_jsxs("div", { className: classes.container, children: [(snapshotsError || getBranchesError) && (_jsx("div", { className: classes.marginTop, children: _jsx(ErrorStub, { message: (snapshotsError === null || snapshotsError === void 0 ? void 0 : snapshotsError.message) || (getBranchesError === null || getBranchesError === void 0 ? void 0 : getBranchesError.message) }) })), _jsxs("div", { className: classes.form, children: [_jsx(TextField, { label: "Branch name", variant: "outlined", required: true, fullWidth: true, size: "small", InputLabelProps: {
|
|
118
118
|
shrink: true,
|
|
119
|
-
}, value: formik.values.branchName, error: Boolean(formik.errors.branchName), className: classes.marginBottom, onChange: (e) => formik.setFieldValue('branchName', e.target.value) }), _jsx("p", { className: cn(classes.marginTop, classes.marginBottom), children: "Choose an existing branch. The new branch will initially point at the same snapshot as the parent branch but going further, their evolution paths will be independent - new snapshots can be created for both branches." }), _jsx(Select, { fullWidth: true, label: "Parent branch", value: formik.values.baseBranch, disabled: !branchesList || formik.isSubmitting, onChange: handleParentBranchChange, error: Boolean(formik.errors.baseBranch), items: branchesList
|
|
119
|
+
}, value: formik.values.branchName, error: Boolean(formik.errors.branchName), helperText: formik.errors.branchName, className: classes.marginBottom, onChange: (e) => formik.setFieldValue('branchName', e.target.value) }), _jsx("p", { className: cn(classes.marginTop, classes.marginBottom), children: "Choose an existing branch. The new branch will initially point at the same snapshot as the parent branch but going further, their evolution paths will be independent - new snapshots can be created for both branches." }), _jsx(Select, { fullWidth: true, label: "Parent branch", value: formik.values.baseBranch, disabled: !branchesList || formik.isSubmitting, onChange: handleParentBranchChange, error: Boolean(formik.errors.baseBranch), items: branchesList
|
|
120
120
|
? branchesList.map((branch) => {
|
|
121
121
|
return {
|
|
122
122
|
value: branch.name,
|
|
@@ -7,7 +7,23 @@
|
|
|
7
7
|
import { useFormik } from 'formik';
|
|
8
8
|
import * as Yup from 'yup';
|
|
9
9
|
const Schema = Yup.object().shape({
|
|
10
|
-
branchName: Yup.string()
|
|
10
|
+
branchName: Yup.string()
|
|
11
|
+
.required('Branch name is required')
|
|
12
|
+
.max(255, 'Branch name cannot exceed 255 characters')
|
|
13
|
+
.test('valid-zfs-name', 'Branch name can only contain letters, numbers, and these characters: _ -', (value) => {
|
|
14
|
+
if (!value)
|
|
15
|
+
return true;
|
|
16
|
+
// ZFS allows only alphanumeric characters and: _ -
|
|
17
|
+
const validChars = /^[a-zA-Z0-9_-]*$/;
|
|
18
|
+
return validChars.test(value);
|
|
19
|
+
})
|
|
20
|
+
.test('valid-start-char', 'Branch name must start with a letter, number, or underscore', (value) => {
|
|
21
|
+
if (!value)
|
|
22
|
+
return true;
|
|
23
|
+
// Dataset names can begin with alphanumeric character or underscore
|
|
24
|
+
const validStartChar = /^[a-zA-Z0-9_]/;
|
|
25
|
+
return validStartChar.test(value);
|
|
26
|
+
}),
|
|
11
27
|
});
|
|
12
28
|
export const useForm = (onSubmit) => {
|
|
13
29
|
const formik = useFormik({
|
|
@@ -128,13 +128,13 @@ export const CreateClone = observer((props) => {
|
|
|
128
128
|
})) !== null && _g !== void 0 ? _g : [] })), _jsx(TextField, { fullWidth: true, label: "Clone ID", value: formik.values.cloneId, onChange: (e) => {
|
|
129
129
|
const sanitizedCloneIdValue = e.target.value.replace(/\s/g, '');
|
|
130
130
|
formik.setFieldValue('cloneId', sanitizedCloneIdValue);
|
|
131
|
-
}, error: Boolean(formik.errors.cloneId), disabled: isCreatingClone }), _jsx(Select, { fullWidth: true, label: "Snapshot *", value: formik.values.snapshotId, disabled: !snapshots || isCreatingClone, onChange: (e) => formik.setFieldValue('snapshotId', e.target.value), error: Boolean(formik.errors.snapshotId), items: (_h = snapshots.map((snapshot, i) => {
|
|
131
|
+
}, error: Boolean(formik.errors.cloneId), helperText: formik.errors.cloneId, disabled: isCreatingClone }), _jsx(Select, { fullWidth: true, label: "Snapshot *", value: formik.values.snapshotId, disabled: !snapshots || isCreatingClone, onChange: (e) => formik.setFieldValue('snapshotId', e.target.value), error: Boolean(formik.errors.snapshotId), items: (_h = snapshots.map((snapshot, i) => {
|
|
132
132
|
const isLatest = i === 0;
|
|
133
133
|
return {
|
|
134
134
|
value: snapshot.id,
|
|
135
135
|
children: (_jsxs("div", { className: styles.snapshotItem, children: [_jsxs("strong", { className: styles.snapshotOverflow, children: [snapshot === null || snapshot === void 0 ? void 0 : snapshot.id, " ", isLatest && _jsx("span", { children: "Latest" })] }), (snapshot === null || snapshot === void 0 ? void 0 : snapshot.dataStateAt) && (_jsxs("p", { children: ["Data state at: ", snapshot === null || snapshot === void 0 ? void 0 : snapshot.dataStateAt] })), snapshot.message && (_jsxs("span", { children: ["Message: ", snapshot.message] }))] })),
|
|
136
136
|
};
|
|
137
|
-
})) !== null && _h !== void 0 ? _h : [] }), _jsx("p", { className: styles.remark, children: "By default latest snapshot of database is used. You can select\u00A0 different snapshots if earlier database state is needed." })] }), _jsxs("div", { className: styles.section, children: [_jsx("h2", { className: styles.title, children: "Database credentials *" }), _jsx("p", { className: styles.text, children: "Set custom credentials for the new clone. Save the password in reliable place, it can
|
|
137
|
+
})) !== null && _h !== void 0 ? _h : [] }), _jsx("p", { className: styles.remark, children: "By default latest snapshot of database is used. You can select\u00A0 different snapshots if earlier database state is needed." })] }), _jsxs("div", { className: styles.section, children: [_jsx("h2", { className: styles.title, children: "Database credentials *" }), _jsx("p", { className: styles.text, children: "Set custom credentials for the new clone. Save the password in reliable place, it can't be read later." }), _jsx(TextField, { fullWidth: true, label: "Database username *", value: formik.values.dbUser, onChange: (e) => formik.setFieldValue('dbUser', e.target.value), error: Boolean(formik.errors.dbUser), disabled: isCreatingClone }), _jsx(TextField, { fullWidth: true, label: "Database password *", type: "password", value: formik.values.dbPassword, onChange: (e) => {
|
|
138
138
|
formik.setFieldValue('dbPassword', e.target.value);
|
|
139
139
|
if (formik.errors.dbPassword) {
|
|
140
140
|
formik.setFieldError('dbPassword', '');
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { useFormik } from 'formik';
|
|
2
2
|
import * as Yup from 'yup';
|
|
3
3
|
const Schema = Yup.object().shape({
|
|
4
|
-
cloneId: Yup.string()
|
|
4
|
+
cloneId: Yup.string()
|
|
5
|
+
.max(63, 'Clone ID cannot exceed 63 characters')
|
|
6
|
+
.test('valid-docker-name', 'Clone ID must start with a letter or number and can only contain letters, numbers, underscores, periods, and hyphens', (value) => {
|
|
7
|
+
if (!value)
|
|
8
|
+
return true;
|
|
9
|
+
// Docker container name requirements: start with letter/number, contain only ASCII [a-zA-Z0-9_.-]
|
|
10
|
+
const validDockerName = /^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/;
|
|
11
|
+
return validDockerName.test(value);
|
|
12
|
+
}),
|
|
5
13
|
snapshotId: Yup.string().required('Date state time is required'),
|
|
6
14
|
dbUser: Yup.string().required('Database username is required'),
|
|
7
15
|
dbPassword: Yup.string().required('Database password is required'),
|
package/pages/Instance/index.js
CHANGED
|
@@ -56,7 +56,7 @@ export const Instance = observer((props) => {
|
|
|
56
56
|
const [activeTab, setActiveTab] = React.useState((props === null || props === void 0 ? void 0 : props.renderCurrentTab) || TABS_INDEX.OVERVIEW);
|
|
57
57
|
const [hasBeenRedirected, setHasBeenRedirected] = React.useState(false);
|
|
58
58
|
const stores = useCreatedStores(props);
|
|
59
|
-
const { instance, instanceError, instanceRetrieval, isLoadingInstance, load, } = stores.main;
|
|
59
|
+
const { instance, instanceError, instanceRetrieval, isLoadingInstance, isLoadingInstanceRetrieval, load, } = stores.main;
|
|
60
60
|
const switchTab = (_, tabID) => {
|
|
61
61
|
const contentElement = document.getElementById('content-container');
|
|
62
62
|
setActiveTab(tabID);
|
|
@@ -66,7 +66,7 @@ export const Instance = observer((props) => {
|
|
|
66
66
|
contentElement === null || contentElement === void 0 ? void 0 : contentElement.scrollTo(0, 0);
|
|
67
67
|
};
|
|
68
68
|
const isInstanceIntegrated = instanceRetrieval ||
|
|
69
|
-
(!isLoadingInstance && instance && (instance === null || instance === void 0 ? void 0 : instance.url) && !instanceError);
|
|
69
|
+
(!isLoadingInstance && !isLoadingInstanceRetrieval && instance && (instance === null || instance === void 0 ? void 0 : instance.url) && !instanceError);
|
|
70
70
|
const isConfigurationActive = (instanceRetrieval === null || instanceRetrieval === void 0 ? void 0 : instanceRetrieval.mode) !== 'physical';
|
|
71
71
|
useEffect(() => {
|
|
72
72
|
load(instanceId, isPlatform);
|
|
@@ -86,7 +86,7 @@ export const Instance = observer((props) => {
|
|
|
86
86
|
}
|
|
87
87
|
}, [instance, hasBeenRedirected]);
|
|
88
88
|
return (_jsx(HostProvider, { value: props, children: _jsxs(StoresProvider, { value: stores, children: [props.elements.breadcrumbs, _jsx(SectionTitle, { text: props.title, level: 1, tag: "h1", className: classes.title, rightContent: _jsx(Button, { onClick: () => load(props.instanceId, isPlatform), isDisabled: !instance && !instanceError, className: classes.reloadButton, children: "Reload info" }), children: isInstanceIntegrated && (_jsx(InstanceTabs, { instanceId: props.instanceId, tab: activeTab, onTabChange: (tabID) => setActiveTab(tabID), isPlatform: isPlatform, hasLogs: api.initWS !== undefined, hideInstanceTabs: props.hideBranchingFeatures })) }), instanceError && (_jsx(ErrorStub, { ...instanceError, className: classes.errorStub })), isInstanceIntegrated ? (_jsxs(_Fragment, { children: [_jsxs(TabPanel, { value: activeTab, index: TABS_INDEX.OVERVIEW, children: [!instanceError && (_jsx("div", { className: classes.content, children: instance && ((_b = (_a = instance.state) === null || _a === void 0 ? void 0 : _a.retrieving) === null || _b === void 0 ? void 0 : _b.status) ? (_jsxs(_Fragment, { children: [_jsx(Clones, {}), _jsx(Info, { hideBranchingFeatures: props.hideBranchingFeatures })] })) : (_jsx(StubSpinner, {})) })), _jsx(ClonesModal, {}), _jsx(SnapshotsModal, {})] }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.CLONES, children: activeTab === TABS_INDEX.CLONES && (_jsx("div", { className: classes.content, children: !instanceError &&
|
|
89
|
-
(instance ? _jsx(Clones, { onlyRenderList: true }) : _jsx(StubSpinner, {})) })) }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.LOGS, children: activeTab === TABS_INDEX.LOGS && (_jsx(Logs, { api: api, instanceId: props.instanceId })) }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.CONFIGURATION, children: activeTab === TABS_INDEX.CONFIGURATION && (_jsx(Configuration, { instanceId: instanceId, switchActiveTab: switchTab, isConfigurationActive: isConfigurationActive, reload: () => load(props.instanceId), disableConfigModification: (_c = instance === null || instance === void 0 ? void 0 : instance.state) === null || _c === void 0 ? void 0 : _c.engine.disableConfigModification })) }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.SNAPSHOTS, children: activeTab === TABS_INDEX.SNAPSHOTS && (_jsx(Snapshots, { instanceId: instanceId })) }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.BRANCHES, children: activeTab === TABS_INDEX.BRANCHES && (_jsx(Branches, { instanceId: instanceId })) })] })) : !isLoadingInstance && !instanceError ? (_jsx(TabPanel, { value: activeTab, index: activeTab, children: _jsx(InactiveInstance, { instance: instance, org: (_d = props.elements.breadcrumbs) === null || _d === void 0 ? void 0 : _d.props.org }) })) : (!instanceError && (_jsx(TabPanel, { value: activeTab, index: activeTab, children: _jsx("div", { className: classes.content, children: _jsx(StubSpinner, {}) }) })))] }) }));
|
|
89
|
+
(instance ? _jsx(Clones, { onlyRenderList: true }) : _jsx(StubSpinner, {})) })) }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.LOGS, children: activeTab === TABS_INDEX.LOGS && (_jsx(Logs, { api: api, instanceId: props.instanceId })) }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.CONFIGURATION, children: activeTab === TABS_INDEX.CONFIGURATION && (_jsx(Configuration, { instanceId: instanceId, switchActiveTab: switchTab, isConfigurationActive: isConfigurationActive, reload: () => load(props.instanceId), disableConfigModification: (_c = instance === null || instance === void 0 ? void 0 : instance.state) === null || _c === void 0 ? void 0 : _c.engine.disableConfigModification })) }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.SNAPSHOTS, children: activeTab === TABS_INDEX.SNAPSHOTS && (_jsx(Snapshots, { instanceId: instanceId })) }), _jsx(TabPanel, { value: activeTab, index: TABS_INDEX.BRANCHES, children: activeTab === TABS_INDEX.BRANCHES && (_jsx(Branches, { instanceId: instanceId })) })] })) : !isLoadingInstance && !isLoadingInstanceRetrieval && !instanceError ? (_jsx(TabPanel, { value: activeTab, index: activeTab, children: _jsx(InactiveInstance, { instance: instance, org: (_d = props.elements.breadcrumbs) === null || _d === void 0 ? void 0 : _d.props.org }) })) : (!instanceError && (_jsx(TabPanel, { value: activeTab, index: activeTab, children: _jsx("div", { className: classes.content, children: _jsx(StubSpinner, {}) }) })))] }) }));
|
|
90
90
|
});
|
|
91
91
|
function TabPanel(props) {
|
|
92
92
|
const { children, value, index, ...other } = props;
|
|
@@ -27,9 +27,12 @@ export class MainStore {
|
|
|
27
27
|
this.isBranchesLoading = false;
|
|
28
28
|
this.isConfigLoading = false;
|
|
29
29
|
this.isLoadingInstance = false;
|
|
30
|
+
this.isLoadingInstanceRetrieval = false;
|
|
30
31
|
this.load = (instanceId, isPlatform = false) => {
|
|
31
32
|
this.instance = null;
|
|
33
|
+
this.instanceRetrieval = null;
|
|
32
34
|
this.isReloadingInstance = true;
|
|
35
|
+
this.isLoadingInstanceRetrieval = true;
|
|
33
36
|
if (!isPlatform) {
|
|
34
37
|
this.getBranches(instanceId);
|
|
35
38
|
}
|
|
@@ -58,7 +61,9 @@ export class MainStore {
|
|
|
58
61
|
};
|
|
59
62
|
this.reload = (instanceId) => {
|
|
60
63
|
this.instance = null;
|
|
64
|
+
this.instanceRetrieval = null;
|
|
61
65
|
this.isReloadingInstance = true;
|
|
66
|
+
this.isLoadingInstanceRetrieval = true;
|
|
62
67
|
this.loadInstance(instanceId, false).then(() => {
|
|
63
68
|
var _a, _b, _c;
|
|
64
69
|
if (this.api.refreshInstance)
|
|
@@ -88,11 +93,15 @@ export class MainStore {
|
|
|
88
93
|
this.isReloadingInstanceRetrieval = false;
|
|
89
94
|
};
|
|
90
95
|
this.loadInstanceRetrieval = async (instanceId) => {
|
|
91
|
-
if (!this.api.getInstanceRetrieval)
|
|
96
|
+
if (!this.api.getInstanceRetrieval) {
|
|
97
|
+
this.isLoadingInstanceRetrieval = false;
|
|
92
98
|
return;
|
|
99
|
+
}
|
|
100
|
+
this.isLoadingInstanceRetrieval = true;
|
|
93
101
|
const { response, error } = await this.api.getInstanceRetrieval({
|
|
94
102
|
instanceId: instanceId,
|
|
95
103
|
});
|
|
104
|
+
this.isLoadingInstanceRetrieval = false;
|
|
96
105
|
if (response)
|
|
97
106
|
this.instanceRetrieval = response;
|
|
98
107
|
if (error)
|