@postgres.ai/shared 3.5.0-pr-1027.1 → 4.0.0-pr-1028.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/DestroyCloneModal/index.js +3 -3
- package/components/DestroyCloneRestrictionModal/index.js +1 -1
- package/components/MenuButton/index.d.ts +2 -0
- package/components/MenuButton/index.js +1 -1
- package/components/ResetCloneModal/index.js +5 -3
- package/icons/ArrowDropDown/index.d.ts +1 -0
- package/icons/ArrowDropDown/index.js +1 -1
- package/icons/PostgresSQL/index.d.ts +2 -0
- package/icons/PostgresSQL/index.js +40 -0
- package/package.json +1 -1
- package/pages/Branches/Branch/context.d.ts +22 -0
- package/pages/Branches/Branch/context.js +3 -0
- package/pages/Branches/Branch/index.d.ts +9 -0
- package/pages/Branches/Branch/index.js +172 -0
- package/pages/Branches/Branch/stores/Main.d.ts +37 -0
- package/pages/Branches/Branch/stores/Main.js +90 -0
- package/pages/Branches/Branch/useCreatedStores.d.ts +6 -0
- package/pages/Branches/Branch/useCreatedStores.js +5 -0
- package/pages/Branches/components/BranchesTable/index.d.ts +10 -0
- package/pages/Branches/components/BranchesTable/index.js +107 -0
- package/pages/Branches/components/Modals/DeleteBranchModal/index.d.ts +11 -0
- package/pages/Branches/components/Modals/DeleteBranchModal/index.js +49 -0
- package/pages/Branches/components/Modals/types.d.ts +4 -0
- package/pages/Branches/components/Modals/types.js +1 -0
- package/pages/Branches/index.d.ts +6 -0
- package/pages/Branches/index.js +60 -0
- package/pages/Clone/context.d.ts +2 -0
- package/pages/Clone/index.d.ts +3 -1
- package/pages/Clone/index.js +54 -23
- package/pages/Clone/stores/Main.d.ts +4 -2
- package/pages/Clone/utils/index.d.ts +4 -0
- package/pages/Clone/utils/index.js +12 -0
- package/pages/CreateBranch/index.d.ts +17 -0
- package/pages/CreateBranch/index.js +135 -0
- package/pages/CreateBranch/stores/Main.d.ts +43 -0
- package/pages/CreateBranch/stores/Main.js +59 -0
- package/pages/CreateBranch/useCreatedStores.d.ts +6 -0
- package/pages/CreateBranch/useCreatedStores.js +5 -0
- package/pages/CreateBranch/useForm.d.ts +51 -0
- package/pages/CreateBranch/useForm.js +30 -0
- package/pages/CreateBranch/utils/index.d.ts +2 -0
- package/pages/CreateBranch/utils/index.js +10 -0
- package/pages/CreateClone/index.d.ts +4 -2
- package/pages/CreateClone/index.js +92 -40
- package/pages/CreateClone/stores/Main.d.ts +25 -2
- package/pages/CreateClone/stores/Main.js +26 -2
- package/pages/CreateClone/styles.module.scss +47 -4
- package/pages/CreateClone/useForm.d.ts +1 -0
- package/pages/CreateClone/useForm.js +1 -0
- package/pages/CreateClone/utils/index.d.ts +3 -0
- package/pages/CreateClone/utils/index.js +17 -0
- package/pages/CreateSnapshot/index.d.ts +17 -0
- package/pages/CreateSnapshot/index.js +117 -0
- package/pages/CreateSnapshot/stores/Main.d.ts +21 -0
- package/pages/CreateSnapshot/stores/Main.js +31 -0
- package/pages/CreateSnapshot/useCreatedStores.d.ts +6 -0
- package/pages/CreateSnapshot/useCreatedStores.js +5 -0
- package/pages/CreateSnapshot/useForm.d.ts +53 -0
- package/pages/CreateSnapshot/useForm.js +25 -0
- package/pages/CreateSnapshot/utils/index.d.ts +1 -0
- package/pages/CreateSnapshot/utils/index.js +3 -0
- package/pages/Instance/{components → Clones}/ClonesList/MenuCell/index.js +1 -1
- package/pages/Instance/{components → Clones}/ClonesList/MenuCell/utils.js +2 -2
- package/pages/Instance/Clones/ClonesList/index.js +96 -0
- package/pages/Instance/{components → Clones}/ClonesList/styles.module.scss +10 -0
- package/pages/Instance/{ClonesModal → Clones/ClonesModal}/index.js +5 -5
- package/pages/Instance/Clones/Header/styles.module.scss +4 -1
- package/pages/Instance/Clones/index.d.ts +5 -1
- package/pages/Instance/Clones/index.js +6 -8
- package/pages/{Configuration → Instance/Configuration}/InputWithTooltip/index.js +15 -11
- package/pages/{Configuration → Instance/Configuration}/index.d.ts +2 -1
- package/pages/{Configuration → Instance/Configuration}/index.js +9 -6
- package/pages/{Configuration → Instance/Configuration}/tooltipText.js +1 -1
- package/pages/Instance/Info/Disks/Disk/index.js +6 -4
- package/pages/Instance/Info/Retrieval/RetrievalModal/index.js +0 -4
- package/pages/Instance/Info/Retrieval/index.js +1 -3
- package/pages/Instance/Info/Snapshots/Calendar/utils.d.ts +4 -0
- package/pages/Instance/Info/Snapshots/index.js +10 -5
- package/pages/Instance/Info/Snapshots/utils.d.ts +13 -2
- package/pages/Instance/Info/Snapshots/utils.js +16 -6
- package/pages/Instance/Info/Status/index.js +2 -2
- package/pages/Instance/Info/index.js +2 -1
- package/pages/Instance/Snapshots/components/SnapshotHeader/index.d.ts +11 -0
- package/pages/Instance/Snapshots/components/SnapshotHeader/index.js +36 -0
- package/pages/Instance/Snapshots/components/SnapshotsList/index.d.ts +11 -0
- package/pages/Instance/Snapshots/components/SnapshotsList/index.js +157 -0
- package/pages/Instance/Snapshots/components/SnapshotsTable/index.d.ts +6 -0
- package/pages/Instance/Snapshots/components/SnapshotsTable/index.js +125 -0
- package/pages/Instance/Snapshots/index.d.ts +6 -0
- package/pages/Instance/Snapshots/index.js +92 -0
- package/pages/Instance/Snapshots/utils/index.d.ts +16 -0
- package/pages/Instance/Snapshots/utils/index.js +30 -0
- package/pages/Instance/SnapshotsModal/index.js +1 -1
- package/pages/Instance/Tabs/PlatformTabs.d.ts +10 -0
- package/pages/Instance/Tabs/PlatformTabs.js +51 -0
- package/pages/Instance/Tabs/index.d.ts +19 -2
- package/pages/Instance/Tabs/index.js +71 -36
- package/pages/Instance/Tabs/styles.d.ts +1 -0
- package/pages/Instance/Tabs/styles.js +62 -0
- package/pages/Instance/components/ModalReloadButton/index.js +1 -1
- package/pages/Instance/context.d.ts +7 -0
- package/pages/Instance/index.js +14 -13
- package/pages/Instance/stores/Main.d.ts +36 -10
- package/pages/Instance/stores/Main.js +83 -24
- package/pages/Instance/styles.scss +1 -4
- package/pages/Logs/hooks/useWsScroll.js +6 -8
- package/pages/Logs/index.d.ts +2 -1
- package/pages/Logs/index.js +42 -31
- package/pages/Logs/wsLogs.d.ts +3 -2
- package/pages/Logs/wsLogs.js +24 -8
- package/pages/Logs/wsSnackbar.js +7 -7
- package/pages/Snapshots/Snapshot/DestorySnapshotModal/index.d.ts +12 -0
- package/pages/Snapshots/Snapshot/DestorySnapshotModal/index.js +69 -0
- package/pages/Snapshots/Snapshot/context.d.ts +23 -0
- package/pages/Snapshots/Snapshot/context.js +3 -0
- package/pages/Snapshots/Snapshot/index.d.ts +9 -0
- package/pages/Snapshots/Snapshot/index.js +171 -0
- package/pages/Snapshots/Snapshot/stores/Main.d.ts +33 -0
- package/pages/Snapshots/Snapshot/stores/Main.js +71 -0
- package/pages/Snapshots/Snapshot/useCreatedStores.d.ts +6 -0
- package/pages/Snapshots/Snapshot/useCreatedStores.js +5 -0
- package/stores/Snapshots.d.ts +12 -3
- package/stores/Snapshots.js +27 -3
- package/types/api/endpoints/createBranch.d.ts +12 -0
- package/types/api/endpoints/createBranch.js +1 -0
- package/types/api/endpoints/createClone.d.ts +1 -0
- package/types/api/endpoints/createSnapshot.d.ts +5 -0
- package/types/api/endpoints/createSnapshot.js +1 -0
- package/types/api/endpoints/deleteBranch.d.ts +4 -0
- package/types/api/endpoints/deleteBranch.js +1 -0
- package/types/api/endpoints/destroySnapshot.d.ts +4 -0
- package/types/api/endpoints/destroySnapshot.js +1 -0
- package/types/api/endpoints/getBranchSnapshot.d.ts +5 -0
- package/types/api/endpoints/getBranchSnapshot.js +1 -0
- package/types/api/endpoints/getBranches.d.ts +18 -0
- package/types/api/endpoints/getBranches.js +5 -0
- package/types/api/endpoints/getConfig.d.ts +2 -2
- package/types/api/endpoints/getEngine.d.ts +1 -1
- package/types/api/endpoints/getFullConfig.d.ts +1 -1
- package/types/api/endpoints/getSnapshotList.d.ts +10 -0
- package/types/api/endpoints/getSnapshotList.js +1 -0
- package/types/api/endpoints/getSnapshots.d.ts +1 -0
- package/types/api/endpoints/updateConfig.d.ts +1 -1
- package/types/api/entities/branchSnapshot.d.ts +6 -0
- package/types/api/entities/branchSnapshot.js +1 -0
- package/types/api/entities/branchSnapshots.d.ts +15 -0
- package/types/api/entities/branchSnapshots.js +7 -0
- package/types/api/entities/clone.d.ts +6 -0
- package/types/api/entities/config.js +1 -1
- package/types/api/entities/createBranch.d.ts +5 -0
- package/types/api/entities/createBranch.js +1 -0
- package/types/api/entities/createSnapshot.d.ts +5 -0
- package/types/api/entities/createSnapshot.js +1 -0
- package/types/api/entities/dbSource.d.ts +1 -0
- package/types/api/entities/instance.d.ts +5 -0
- package/types/api/entities/instanceState.d.ts +5 -0
- package/types/api/entities/snapshot.d.ts +8 -0
- package/types/api/entities/snapshot.js +1 -1
- package/utils/date.d.ts +2 -0
- package/utils/date.js +7 -0
- package/utils/snapshot.d.ts +5 -2
- package/utils/snapshot.js +6 -1
- package/pages/Instance/components/ClonesList/index.js +0 -52
- /package/pages/Instance/{components → Clones}/ClonesList/ConnectionModal/index.d.ts +0 -0
- /package/pages/Instance/{components → Clones}/ClonesList/ConnectionModal/index.js +0 -0
- /package/pages/Instance/{components → Clones}/ClonesList/MenuCell/index.d.ts +0 -0
- /package/pages/Instance/{components → Clones}/ClonesList/MenuCell/utils.d.ts +0 -0
- /package/pages/Instance/{components → Clones}/ClonesList/index.d.ts +0 -0
- /package/pages/Instance/{ClonesModal → Clones/ClonesModal}/index.d.ts +0 -0
- /package/pages/Instance/{ClonesModal → Clones/ClonesModal}/utils.d.ts +0 -0
- /package/pages/Instance/{ClonesModal → Clones/ClonesModal}/utils.js +0 -0
- /package/pages/{Configuration → Instance/Configuration}/Header/index.d.ts +0 -0
- /package/pages/{Configuration → Instance/Configuration}/Header/index.js +0 -0
- /package/pages/{Configuration → Instance/Configuration}/InputWithTooltip/index.d.ts +0 -0
- /package/pages/{Configuration → Instance/Configuration}/ResponseMessage/index.d.ts +0 -0
- /package/pages/{Configuration → Instance/Configuration}/ResponseMessage/index.js +0 -0
- /package/pages/{Configuration → Instance/Configuration}/configOptions.d.ts +0 -0
- /package/pages/{Configuration → Instance/Configuration}/configOptions.js +0 -0
- /package/pages/{Configuration → Instance/Configuration}/styles.module.scss +0 -0
- /package/pages/{Configuration → Instance/Configuration}/tooltipText.d.ts +0 -0
- /package/pages/{Configuration → Instance/Configuration}/useForm.d.ts +0 -0
- /package/pages/{Configuration → Instance/Configuration}/useForm.js +0 -0
- /package/pages/{Configuration → Instance/Configuration}/utils/index.d.ts +0 -0
- /package/pages/{Configuration → Instance/Configuration}/utils/index.js +0 -0
- /package/pages/Instance/{SnapshotsModal → Snapshots/components/SnapshotsModal}/utils.d.ts +0 -0
- /package/pages/Instance/{SnapshotsModal → Snapshots/components/SnapshotsModal}/utils.js +0 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { ModalProps } from '@postgres.ai/shared/pages/Branches/components/Modals/types';
|
|
3
|
+
import { DeleteBranch } from '@postgres.ai/shared/types/api/endpoints/deleteBranch';
|
|
4
|
+
interface DeleteBranchModalProps extends ModalProps {
|
|
5
|
+
deleteBranch: DeleteBranch;
|
|
6
|
+
branchName: string;
|
|
7
|
+
instanceId: string;
|
|
8
|
+
afterSubmitClick: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare const DeleteBranchModal: ({ isOpen, onClose, deleteBranch, branchName, instanceId, afterSubmitClick, }: DeleteBranchModalProps) => JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*--------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) 2019-2021, Postgres.ai, Nikolay Samokhvalov nik@postgres.ai
|
|
4
|
+
* All Rights Reserved. Proprietary and confidential.
|
|
5
|
+
* Unauthorized copying of this file, via any medium is strictly prohibited
|
|
6
|
+
*--------------------------------------------------------------------------
|
|
7
|
+
*/
|
|
8
|
+
import { useState } from 'react';
|
|
9
|
+
import { makeStyles } from '@material-ui/core';
|
|
10
|
+
import { Modal } from '@postgres.ai/shared/components/Modal';
|
|
11
|
+
import { SimpleModalControls } from '@postgres.ai/shared/components/SimpleModalControls';
|
|
12
|
+
import { ImportantText } from '@postgres.ai/shared/components/ImportantText';
|
|
13
|
+
import { Text } from '@postgres.ai/shared/components/Text';
|
|
14
|
+
const useStyles = makeStyles({
|
|
15
|
+
errorMessage: {
|
|
16
|
+
color: 'red',
|
|
17
|
+
marginTop: '10px',
|
|
18
|
+
},
|
|
19
|
+
}, { index: 1 });
|
|
20
|
+
export const DeleteBranchModal = ({ isOpen, onClose, deleteBranch, branchName, instanceId, afterSubmitClick, }) => {
|
|
21
|
+
const classes = useStyles();
|
|
22
|
+
const [deleteError, setDeleteError] = useState(null);
|
|
23
|
+
const handleDelete = async () => {
|
|
24
|
+
var _a;
|
|
25
|
+
const deleteRes = await deleteBranch(branchName, instanceId);
|
|
26
|
+
if (deleteRes === null || deleteRes === void 0 ? void 0 : deleteRes.error) {
|
|
27
|
+
setDeleteError((_a = deleteRes.error) === null || _a === void 0 ? void 0 : _a.message);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
afterSubmitClick();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const handleClose = () => {
|
|
34
|
+
setDeleteError(null);
|
|
35
|
+
onClose();
|
|
36
|
+
};
|
|
37
|
+
return (_jsxs(Modal, { title: "Confirmation", onClose: handleClose, isOpen: isOpen, size: "xs", children: [_jsxs(Text, { children: ["Are you sure you want to delete branch", ' ', _jsx(ImportantText, { children: branchName }), "? This action cannot be undone."] }), deleteError && _jsx("p", { className: classes.errorMessage, children: deleteError }), _jsx(SimpleModalControls, { items: [
|
|
38
|
+
{
|
|
39
|
+
text: 'Cancel',
|
|
40
|
+
onClick: handleClose,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
text: 'Delete branch',
|
|
44
|
+
variant: 'primary',
|
|
45
|
+
onClick: handleDelete,
|
|
46
|
+
isDisabled: branchName === 'main',
|
|
47
|
+
},
|
|
48
|
+
] })] }));
|
|
49
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*--------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) 2019-2021, Postgres.ai, Nikolay Samokhvalov nik@postgres.ai
|
|
4
|
+
* All Rights Reserved. Proprietary and confidential.
|
|
5
|
+
* Unauthorized copying of this file, via any medium is strictly prohibited
|
|
6
|
+
*--------------------------------------------------------------------------
|
|
7
|
+
*/
|
|
8
|
+
import { observer } from 'mobx-react-lite';
|
|
9
|
+
import { useHistory } from 'react-router';
|
|
10
|
+
import { makeStyles } from '@material-ui/core';
|
|
11
|
+
import { useEffect, useState } from 'react';
|
|
12
|
+
import { useStores, useHost } from '@postgres.ai/shared/pages/Instance/context';
|
|
13
|
+
import { Button } from '@postgres.ai/shared/components/Button2';
|
|
14
|
+
import { Spinner } from '@postgres.ai/shared/components/Spinner';
|
|
15
|
+
import { ErrorStub } from '@postgres.ai/shared/components/ErrorStub';
|
|
16
|
+
import { BranchesTable } from '@postgres.ai/shared/pages/Branches/components/BranchesTable';
|
|
17
|
+
import { SectionTitle } from '@postgres.ai/shared/components/SectionTitle';
|
|
18
|
+
import { Tooltip } from '@postgres.ai/shared/components/Tooltip';
|
|
19
|
+
import { InfoIcon } from '@postgres.ai/shared/icons/Info';
|
|
20
|
+
const useStyles = makeStyles({
|
|
21
|
+
container: {
|
|
22
|
+
marginTop: '16px',
|
|
23
|
+
},
|
|
24
|
+
infoIcon: {
|
|
25
|
+
height: '12px',
|
|
26
|
+
width: '12px',
|
|
27
|
+
marginLeft: '8px',
|
|
28
|
+
color: '#808080',
|
|
29
|
+
},
|
|
30
|
+
spinner: {
|
|
31
|
+
position: 'absolute',
|
|
32
|
+
right: '50%',
|
|
33
|
+
transform: 'translate(-50%, -50%)',
|
|
34
|
+
},
|
|
35
|
+
}, { index: 1 });
|
|
36
|
+
export const Branches = observer(({ instanceId }) => {
|
|
37
|
+
const host = useHost();
|
|
38
|
+
const stores = useStores();
|
|
39
|
+
const classes = useStyles();
|
|
40
|
+
const history = useHistory();
|
|
41
|
+
const [branches, setBranches] = useState([]);
|
|
42
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
43
|
+
const { instance, getBranches, isBranchesLoading, getBranchesError, deleteBranch, } = stores.main;
|
|
44
|
+
const goToBranchAddPage = () => history.push(host.routes.createBranch());
|
|
45
|
+
const loadBranches = () => {
|
|
46
|
+
getBranches(instanceId)
|
|
47
|
+
.then((response) => {
|
|
48
|
+
response && setBranches(response);
|
|
49
|
+
})
|
|
50
|
+
.finally(() => setIsLoading(false));
|
|
51
|
+
};
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
loadBranches();
|
|
54
|
+
}, []);
|
|
55
|
+
if (!instance && !isBranchesLoading)
|
|
56
|
+
return _jsx(_Fragment, {});
|
|
57
|
+
if (getBranchesError)
|
|
58
|
+
return (_jsx(ErrorStub, { title: getBranchesError === null || getBranchesError === void 0 ? void 0 : getBranchesError.title, message: getBranchesError === null || getBranchesError === void 0 ? void 0 : getBranchesError.message }));
|
|
59
|
+
return (_jsx("div", { className: classes.container, children: isBranchesLoading || isLoading ? (_jsx(Spinner, { size: "lg", className: classes.spinner })) : (_jsxs(_Fragment, { children: [_jsx(SectionTitle, { level: 2, tag: "h2", text: `Branches (${(branches === null || branches === void 0 ? void 0 : branches.length) || 0})`, rightContent: _jsxs(_Fragment, { children: [_jsx(Button, { theme: "primary", isDisabled: !branches.length, onClick: goToBranchAddPage, children: "Create branch" }), !branches.length && (_jsx(Tooltip, { content: "No existing branch", children: _jsx("div", { style: { display: 'flex' }, children: _jsx(InfoIcon, { className: classes.infoIcon }) }) }))] }) }), _jsx(BranchesTable, { branches: branches, branchesRoute: host.routes.branches(), reloadBranches: loadBranches, deleteBranch: deleteBranch, emptyTableText: "This instance has no active branches." })] })) }));
|
|
60
|
+
});
|
package/pages/Clone/context.d.ts
CHANGED
package/pages/Clone/index.d.ts
CHANGED
package/pages/Clone/index.js
CHANGED
|
@@ -6,10 +6,10 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
6
6
|
*--------------------------------------------------------------------------
|
|
7
7
|
*/
|
|
8
8
|
import { useEffect, useState } from 'react';
|
|
9
|
-
import copyToClipboard from 'copy-to-clipboard';
|
|
10
9
|
import { observer } from 'mobx-react-lite';
|
|
11
10
|
import { useHistory } from 'react-router-dom';
|
|
12
|
-
import
|
|
11
|
+
import copyToClipboard from 'copy-to-clipboard';
|
|
12
|
+
import { makeStyles, Button, FormControlLabel, Checkbox, TextField, IconButton, } from '@material-ui/core';
|
|
13
13
|
import { getSshPortForwardingCommand, getPsqlConnectionStr, getJdbcConnectionStr, } from '@postgres.ai/shared/utils/connection';
|
|
14
14
|
import { formatBytesIEC } from '@postgres.ai/shared/utils/units';
|
|
15
15
|
import { ErrorStub } from '@postgres.ai/shared/components/ErrorStub';
|
|
@@ -23,28 +23,55 @@ import { Tooltip } from '@postgres.ai/shared/components/Tooltip';
|
|
|
23
23
|
import { SectionTitle } from '@postgres.ai/shared/components/SectionTitle';
|
|
24
24
|
import { icons } from '@postgres.ai/shared/styles/icons';
|
|
25
25
|
import { styles } from '@postgres.ai/shared/styles/styles';
|
|
26
|
+
import { SyntaxHighlight } from '@postgres.ai/shared/components/SyntaxHighlight';
|
|
26
27
|
import { Status } from './Status';
|
|
27
28
|
import { useCreatedStores } from './useCreatedStores';
|
|
28
|
-
|
|
29
|
+
import { getCliDestroyCloneCommand, getCliProtectedCloneCommand, getCliResetCloneCommand, getCreateSnapshotCommand, } from './utils';
|
|
30
|
+
import { InstanceTabs, TABS_INDEX } from "../Instance/Tabs";
|
|
31
|
+
const textFieldWidth = 525;
|
|
29
32
|
const useStyles = makeStyles((theme) => ({
|
|
33
|
+
wrapper: {
|
|
34
|
+
display: 'flex',
|
|
35
|
+
gap: '40px',
|
|
36
|
+
maxWidth: '1200px',
|
|
37
|
+
fontSize: '14px !important',
|
|
38
|
+
marginTop: '20px',
|
|
39
|
+
'@media (max-width: 1300px)': {
|
|
40
|
+
flexDirection: 'column',
|
|
41
|
+
gap: '20px',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
30
44
|
title: {
|
|
31
|
-
marginTop: '
|
|
45
|
+
marginTop: '8px',
|
|
46
|
+
lineHeight: '26px'
|
|
47
|
+
},
|
|
48
|
+
tooltip: {
|
|
49
|
+
marginTop: '8px',
|
|
32
50
|
},
|
|
33
51
|
container: {
|
|
34
|
-
maxWidth:
|
|
52
|
+
maxWidth: textFieldWidth + 25,
|
|
35
53
|
marginTop: '16px',
|
|
36
54
|
},
|
|
37
55
|
text: {
|
|
38
56
|
marginTop: '4px',
|
|
39
57
|
},
|
|
40
58
|
errorStub: {
|
|
41
|
-
|
|
59
|
+
margin: '24px 0',
|
|
42
60
|
},
|
|
43
61
|
spinner: {
|
|
44
62
|
marginLeft: '8px',
|
|
45
63
|
},
|
|
46
64
|
summary: {
|
|
47
|
-
|
|
65
|
+
flex: '1.5 1 0',
|
|
66
|
+
minWidth: 0,
|
|
67
|
+
},
|
|
68
|
+
snippetContainer: {
|
|
69
|
+
flex: '1 1 0',
|
|
70
|
+
minWidth: 0,
|
|
71
|
+
boxShadow: 'rgba(0, 0, 0, 0.1) 0px 4px 12px',
|
|
72
|
+
padding: '10px 20px 10px 20px',
|
|
73
|
+
height: 'max-content',
|
|
74
|
+
borderRadius: '4px',
|
|
48
75
|
},
|
|
49
76
|
paramTitle: {
|
|
50
77
|
display: 'inline-block',
|
|
@@ -71,10 +98,12 @@ const useStyles = makeStyles((theme) => ({
|
|
|
71
98
|
},
|
|
72
99
|
actions: {
|
|
73
100
|
display: 'flex',
|
|
74
|
-
|
|
101
|
+
flexWrap: 'wrap',
|
|
102
|
+
rowGap: '16px',
|
|
103
|
+
marginBottom: '20px',
|
|
75
104
|
},
|
|
76
105
|
actionButton: {
|
|
77
|
-
marginRight: '
|
|
106
|
+
marginRight: '10px',
|
|
78
107
|
},
|
|
79
108
|
remark: {
|
|
80
109
|
fontSize: '12px',
|
|
@@ -120,6 +149,9 @@ const useStyles = makeStyles((theme) => ({
|
|
|
120
149
|
maxWidth: textFieldWidth,
|
|
121
150
|
width: '100%',
|
|
122
151
|
},
|
|
152
|
+
status: {
|
|
153
|
+
maxWidth: `${textFieldWidth}px`,
|
|
154
|
+
},
|
|
123
155
|
copyButton: {
|
|
124
156
|
position: 'absolute',
|
|
125
157
|
top: 16,
|
|
@@ -129,12 +161,9 @@ const useStyles = makeStyles((theme) => ({
|
|
|
129
161
|
height: 32,
|
|
130
162
|
padding: 8,
|
|
131
163
|
},
|
|
132
|
-
status: {
|
|
133
|
-
maxWidth: `${textFieldWidth}px`,
|
|
134
|
-
},
|
|
135
164
|
}), { index: 1 });
|
|
136
165
|
export const Clone = observer((props) => {
|
|
137
|
-
var _a, _b, _c;
|
|
166
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
138
167
|
const classes = useStyles();
|
|
139
168
|
const history = useHistory();
|
|
140
169
|
const stores = useCreatedStores(props);
|
|
@@ -146,14 +175,12 @@ export const Clone = observer((props) => {
|
|
|
146
175
|
useEffect(() => {
|
|
147
176
|
stores.main.load(props.instanceId, props.cloneId);
|
|
148
177
|
}, []);
|
|
149
|
-
const { instance, clone, isResettingClone, isDestroyingClone, isReloading, isUpdatingClone, isCloneStable, } = stores.main;
|
|
150
|
-
const headRendered = (_jsxs(_Fragment, { children: [_jsx("style", { children: 'p { margin: 0;}' }), props.elements.breadcrumbs, _jsx(SectionTitle, { className: classes.title, tag: "h1", level: 1, text: `Clone ${props.cloneId}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (stores.main.cloneError)
|
|
156
|
-
return (_jsxs(_Fragment, { children: [headRendered, _jsx(ErrorStub, { ...stores.main.cloneError })] }));
|
|
178
|
+
const { instance, snapshots, clone, isResettingClone, isDestroyingClone, isReloading, isUpdatingClone, isCloneStable, } = stores.main;
|
|
179
|
+
const headRendered = (_jsxs(_Fragment, { children: [_jsx("style", { children: 'p { margin: 0;}' }), props.elements.breadcrumbs, _jsx(SectionTitle, { className: classes.title, tag: "h1", level: 1, text: `Clone ${props.cloneId}`, children: _jsx(InstanceTabs, { tab: TABS_INDEX.CLONES, isPlatform: props.isPlatform, instanceId: props.instanceId, hasLogs: props.api.initWS !== undefined }) })] }));
|
|
180
|
+
const cloneErrorMessage = ((_a = stores.main.instanceError) === null || _a === void 0 ? void 0 : _a.message) || ((_b = stores.main.cloneError) === null || _b === void 0 ? void 0 : _b.message);
|
|
181
|
+
const cloneErrorTitle = ((_c = stores.main.instanceError) === null || _c === void 0 ? void 0 : _c.title) || ((_d = stores.main.cloneError) === null || _d === void 0 ? void 0 : _d.title);
|
|
182
|
+
if (cloneErrorMessage && cloneErrorTitle)
|
|
183
|
+
return (_jsxs(_Fragment, { children: [headRendered, _jsx(ErrorStub, { title: cloneErrorTitle, message: cloneErrorMessage })] }));
|
|
157
184
|
// Initial getting data spinner.
|
|
158
185
|
if (!instance || !clone) {
|
|
159
186
|
return (_jsxs(_Fragment, { children: [headRendered, _jsx(PageSpinner, {})] }));
|
|
@@ -175,6 +202,9 @@ export const Clone = observer((props) => {
|
|
|
175
202
|
if (isSuccess)
|
|
176
203
|
history.push(props.routes.instance());
|
|
177
204
|
};
|
|
205
|
+
const createSnapshot = async () => {
|
|
206
|
+
history.push(props.routes.createSnapshot(props.cloneId));
|
|
207
|
+
};
|
|
178
208
|
// Clone reload.
|
|
179
209
|
const reloadClone = () => stores.main.reload();
|
|
180
210
|
// Data protection.
|
|
@@ -190,7 +220,8 @@ export const Clone = observer((props) => {
|
|
|
190
220
|
isReloading ||
|
|
191
221
|
isUpdatingClone ||
|
|
192
222
|
!isCloneStable;
|
|
193
|
-
return (_jsxs(_Fragment, { children: [headRendered, _jsxs("div", { className: classes.
|
|
223
|
+
return (_jsxs(_Fragment, { children: [headRendered, _jsxs("div", { className: classes.wrapper, children: [_jsxs("div", { className: classes.summary, children: [_jsxs("div", { className: classes.actions, children: [_jsxs(Button, { variant: "contained", color: "primary", onClick: requestResetClone, disabled: isDisabledControls, title: 'Reset clone', className: classes.actionButton, children: ["Reset clone", isResettingClone && (_jsx(Spinner, { size: "sm", className: classes.spinner }))] }), _jsxs(Button, { variant: "contained", color: "primary", onClick: requestDestroyClone, disabled: isDisabledControls, title: 'Delete this clone', className: classes.actionButton, children: ["Delete clone", isDestroyingClone && (_jsx(Spinner, { size: "sm", className: classes.spinner }))] }), _jsxs(Button, { variant: "contained", color: "primary", onClick: createSnapshot, disabled: isDisabledControls, title: 'Delete this clone', className: classes.actionButton, children: ["Create snapshot", snapshots.snapshotDataLoading && (_jsx(Spinner, { size: "sm", className: classes.spinner }))] }), _jsxs(Button, { variant: "outlined", color: "secondary", onClick: reloadClone, disabled: isDisabledControls, title: 'Refresh clone information', className: classes.actionButton, children: ["Reload info", isReloading && _jsx(Spinner, { size: "sm", className: classes.spinner })] })] }), stores.main.destroyCloneError ||
|
|
224
|
+
(stores.main.resetCloneError && (_jsx(ErrorStub, { title: 'Resetting error', message: stores.main.resetCloneError, className: classes.errorStub }))), _jsxs("div", { children: [_jsx("p", { children: _jsx("strong", { children: "Branch" }) }), _jsx("p", { className: classes.text, children: clone.branch })] }), _jsxs("div", { className: classes.title, children: [_jsx("p", { children: _jsx("strong", { children: "Created" }) }), _jsx("p", { className: classes.text, children: clone.createdAt })] }), _jsx("br", {}), _jsxs("div", { children: [_jsxs("p", { children: [_jsx("strong", { children: "Data state at" }), "\u00A0", _jsx(Tooltip, { content: _jsxs(_Fragment, { children: [_jsx("strong", { children: "Data state time" }), " is a time at which data is\u00A0 recovered for this clone."] }), children: icons.infoIcon })] }), _jsx("p", { className: classes.text, children: (_e = clone.snapshot) === null || _e === void 0 ? void 0 : _e.dataStateAt })] }), _jsx("br", {}), _jsxs("div", { children: [_jsx("p", { children: _jsx("strong", { children: "Status" }) }), _jsx(Status, { rawClone: clone, className: classes.status })] }), _jsx("br", {}), _jsxs("div", { children: [_jsxs("p", { children: [_jsx("strong", { children: "Summary" }), "\u00A0", _jsx(Tooltip, { content: _jsxs(_Fragment, { children: [_jsx("strong", { children: "Logical data size" }), " is a logical size of files in PGDATA which is being thin-cloned.", _jsx("br", {}), _jsx("br", {}), _jsx("strong", { children: "Physical data diff size" }), " is an actual size of a\u00A0 thin clone. On creation there is no diff between clone\u2019s\u00A0 and initial data state, all data blocks match. During work\u00A0 with the clone data diverges and data diff size increases.", _jsx("br", {}), _jsx("br", {}), _jsx("strong", { children: "Clone creation time" }), " is time which was\u00A0 spent to provision the clone."] }), children: icons.infoIcon })] }), _jsxs("p", { className: classes.text, children: [_jsx("span", { className: classes.paramTitle, children: "Logical data size:" }), ((_f = instance.state) === null || _f === void 0 ? void 0 : _f.dataSize)
|
|
194
225
|
? formatBytesIEC(instance.state.dataSize)
|
|
195
226
|
: '-'] }), _jsxs("p", { className: classes.text, children: [_jsx("span", { className: classes.paramTitle, children: "Physical data diff size:" }), clone.metadata.cloneDiffSize
|
|
196
227
|
? formatBytesIEC(clone.metadata.cloneDiffSize)
|
|
@@ -217,5 +248,5 @@ export const Clone = observer((props) => {
|
|
|
217
248
|
style: styles.inputFieldLabel,
|
|
218
249
|
}, FormHelperTextProps: {
|
|
219
250
|
style: styles.inputFieldHelper,
|
|
220
|
-
} }), _jsx(IconButton, { className: classes.copyButton, "aria-label": "Copy", onClick: () => copyToClipboard(jdbcConnectionStr), children: icons.copyIcon })] }), "\u00A0", _jsx(Tooltip, { content: _jsx(_Fragment, { children: "Used to connect to Postgres using JDBC. Change DBNAME to\u00A0 name of the database you want to connect, change DBPASSWORD\u00A0 to the password you\u2019ve used on clone creation." }), children: _jsx("span", { className: classes.textFieldInfo, children: icons.infoIcon }) })] }))] })), _jsx("br", {}), _jsx("div", { className: classes.fieldBlock, children: _jsxs("span", { className: classes.remark, children: ["Password was set during clone creation. It\u2019s not being stored.", _jsx("br", {}), "You would need to recreate a clone if the password is lost."] }) }), _jsx("br", {}), _jsx("p", { children: _jsx("strong", { children: "Protection" }) }), _jsxs("p", { children: [_jsx(FormControlLabel, { className: classes.checkboxLabel, control: _jsx(Checkbox, { checked: clone.protected, onChange: toggleDataProtection, name: "protected", disabled: isDisabledControls }), label: "Enable deletion protection" }), _jsx("br", {}), _jsxs("span", { className: classes.remark, children: ["When enabled no one can delete this clone and automated deletion is also disabled.", _jsx("br", {}), "Please be careful: abandoned clones with this checkbox enabled may cause out-of-disk-space events. Check disk space on daily basis and delete this clone once the work is done."] })] }), stores.main.updateCloneError && (_jsx(ErrorStub, { title: "Updating error", message: stores.main.updateCloneError, className: classes.errorStub }))] }), _jsxs(_Fragment, { children: [_jsx(DestroyCloneRestrictionModal, { isOpen: isOpenRestrictionModal, onClose: () => setIsOpenRestrictionModal(false), cloneId: clone.id }), _jsx(DestroyCloneModal, { isOpen: isOpenDestroyModal, onClose: () => setIsOpenDestroyModal(false), cloneId: clone.id, onDestroyClone: destroyClone }), _jsx(ResetCloneModal, { isOpen: isOpenResetModal, onClose: () => setIsOpenResetModal(false), clone: clone, snapshots:
|
|
251
|
+
} }), _jsx(IconButton, { className: classes.copyButton, "aria-label": "Copy", onClick: () => copyToClipboard(jdbcConnectionStr), children: icons.copyIcon })] }), "\u00A0", _jsx(Tooltip, { content: _jsx(_Fragment, { children: "Used to connect to Postgres using JDBC. Change DBNAME to\u00A0 name of the database you want to connect, change DBPASSWORD\u00A0 to the password you\u2019ve used on clone creation." }), children: _jsx("span", { className: classes.textFieldInfo, children: icons.infoIcon }) })] }))] })), _jsx("br", {}), _jsx("div", { className: classes.fieldBlock, children: _jsxs("span", { className: classes.remark, children: ["Password was set during clone creation. It\u2019s not being stored.", _jsx("br", {}), "You would need to recreate a clone if the password is lost."] }) }), _jsx("br", {}), _jsx("p", { children: _jsx("strong", { children: "Protection" }) }), _jsxs("p", { children: [_jsx(FormControlLabel, { className: classes.checkboxLabel, control: _jsx(Checkbox, { checked: clone.protected, onChange: toggleDataProtection, name: "protected", disabled: isDisabledControls }), label: "Enable deletion protection" }), _jsx("br", {}), _jsxs("span", { className: classes.remark, children: ["When enabled, no one can delete this clone and automated deletion is also disabled.", _jsx("br", {}), "Please be careful: abandoned clones with this checkbox enabled may cause out-of-disk-space events. Check disk space on daily basis and delete this clone once the work is done."] })] }), stores.main.updateCloneError && (_jsx(ErrorStub, { title: "Updating error", message: stores.main.updateCloneError, className: classes.errorStub }))] }), _jsxs("div", { className: classes.snippetContainer, children: [_jsx(SectionTitle, { tag: "h2", level: 2, text: 'Reset clone using CLI' }), _jsx("p", { className: classes.tooltip, children: "You can reset the clone using CLI using the following command:" }), _jsx(SyntaxHighlight, { content: getCliResetCloneCommand(props.cloneId) }), _jsx(SectionTitle, { className: classes.title, tag: "h2", level: 2, text: 'Delete clone using CLI' }), _jsx("p", { className: classes.tooltip, children: "You can delete the clone using CLI using the following command:" }), _jsx(SyntaxHighlight, { content: getCliDestroyCloneCommand(props.cloneId) }), _jsx(SectionTitle, { className: classes.title, tag: "h2", level: 2, text: 'Toggle deletion protection using CLI' }), _jsx("p", { className: classes.tooltip, children: "You can toggle deletion protection using CLI for this clone using the following command:" }), _jsx(SyntaxHighlight, { content: getCliProtectedCloneCommand(true) }), _jsx(SyntaxHighlight, { content: getCliProtectedCloneCommand(false) }), _jsx(SectionTitle, { className: classes.title, tag: "h2", level: 2, text: 'Create snapshot for this clone using CLI' }), _jsx("p", { className: classes.tooltip, children: "You can create a snapshot for this clone using CLI using the following command:" }), _jsx(SyntaxHighlight, { content: getCreateSnapshotCommand(props.cloneId) })] }), _jsxs(_Fragment, { children: [_jsx(DestroyCloneRestrictionModal, { isOpen: isOpenRestrictionModal, onClose: () => setIsOpenRestrictionModal(false), cloneId: clone.id }), _jsx(DestroyCloneModal, { isOpen: isOpenDestroyModal, onClose: () => setIsOpenDestroyModal(false), cloneId: clone.id, onDestroyClone: destroyClone }), _jsx(ResetCloneModal, { isOpen: isOpenResetModal, onClose: () => setIsOpenResetModal(false), clone: clone, snapshots: snapshots.data, onResetClone: resetClone, version: (_g = instance.state) === null || _g === void 0 ? void 0 : _g.engine.version })] })] })] }));
|
|
221
252
|
});
|
|
@@ -6,12 +6,14 @@ import { UpdateClone } from '@postgres.ai/shared/types/api/endpoints/updateClone
|
|
|
6
6
|
import { SnapshotsStore, SnapshotsApi } from '@postgres.ai/shared/stores/Snapshots';
|
|
7
7
|
import { Clone } from '@postgres.ai/shared/types/api/entities/clone';
|
|
8
8
|
import { Instance } from '@postgres.ai/shared/types/api/entities/instance';
|
|
9
|
+
import { InitWS } from '@postgres.ai/shared/types/api/endpoints/initWS';
|
|
9
10
|
export declare type Api = SnapshotsApi & {
|
|
10
11
|
getInstance: GetInstance;
|
|
11
12
|
getClone: GetClone;
|
|
12
13
|
resetClone: ResetClone;
|
|
13
14
|
destroyClone: DestroyClone;
|
|
14
15
|
updateClone: UpdateClone;
|
|
16
|
+
initWS: InitWS;
|
|
15
17
|
};
|
|
16
18
|
declare type Error = {
|
|
17
19
|
title?: string;
|
|
@@ -34,8 +36,8 @@ export declare class MainStore {
|
|
|
34
36
|
private readonly api;
|
|
35
37
|
constructor(api: Api);
|
|
36
38
|
get isCloneStable(): boolean;
|
|
37
|
-
load: (instanceId: string, cloneId: string) => Promise<boolean>;
|
|
38
|
-
reload: () => Promise<boolean>;
|
|
39
|
+
load: (instanceId: string, cloneId: string) => Promise<boolean | undefined>;
|
|
40
|
+
reload: () => Promise<boolean | undefined>;
|
|
39
41
|
private loadInstance;
|
|
40
42
|
private loadClone;
|
|
41
43
|
resetClone: (snapshotId: string) => Promise<boolean>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const getCliResetCloneCommand: (cloneId: string) => string;
|
|
2
|
+
export declare const getCliDestroyCloneCommand: (cloneId: string) => string;
|
|
3
|
+
export declare const getCliProtectedCloneCommand: (enabled: boolean) => string;
|
|
4
|
+
export declare const getCreateSnapshotCommand: (cloneId: string) => string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const getCliResetCloneCommand = (cloneId) => {
|
|
2
|
+
return `dblab clone reset ${cloneId ? cloneId : `<CLONE_ID>`}`;
|
|
3
|
+
};
|
|
4
|
+
export const getCliDestroyCloneCommand = (cloneId) => {
|
|
5
|
+
return `dblab clone destroy ${cloneId ? cloneId : `<CLONE_ID>`}`;
|
|
6
|
+
};
|
|
7
|
+
export const getCliProtectedCloneCommand = (enabled) => {
|
|
8
|
+
return `dblab clone update --protected ${enabled ? '' : 'false'}`;
|
|
9
|
+
};
|
|
10
|
+
export const getCreateSnapshotCommand = (cloneId) => {
|
|
11
|
+
return `dblab branch snapshot --clone-id ${cloneId}`;
|
|
12
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { MainStoreApi } from './stores/Main';
|
|
3
|
+
interface CreateBranchProps {
|
|
4
|
+
instanceId: string;
|
|
5
|
+
api: MainStoreApi;
|
|
6
|
+
routes: {
|
|
7
|
+
branch: (branchName: string) => string;
|
|
8
|
+
};
|
|
9
|
+
elements: {
|
|
10
|
+
breadcrumbs: React.ReactNode;
|
|
11
|
+
};
|
|
12
|
+
isPlatform?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare const CreateBranchPage: (({ instanceId, api, elements, routes, isPlatform }: CreateBranchProps) => JSX.Element) & {
|
|
15
|
+
displayName: string;
|
|
16
|
+
};
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/*--------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) 2019-2021, Postgres.ai, Nikolay Samokhvalov nik@postgres.ai
|
|
4
|
+
* All Rights Reserved. Proprietary and confidential.
|
|
5
|
+
* Unauthorized copying of this file, via any medium is strictly prohibited
|
|
6
|
+
*--------------------------------------------------------------------------
|
|
7
|
+
*/
|
|
8
|
+
import cn from 'classnames';
|
|
9
|
+
import { useHistory } from 'react-router';
|
|
10
|
+
import { observer } from 'mobx-react-lite';
|
|
11
|
+
import { useEffect, useState } from 'react';
|
|
12
|
+
import { TextField, makeStyles } from '@material-ui/core';
|
|
13
|
+
import { Button } from '@postgres.ai/shared/components/Button';
|
|
14
|
+
import { ResponseMessage } from '@postgres.ai/shared/pages/Instance/Configuration/ResponseMessage';
|
|
15
|
+
import { Select } from '@postgres.ai/shared/components/Select';
|
|
16
|
+
import { SectionTitle } from '@postgres.ai/shared/components/SectionTitle';
|
|
17
|
+
import { ErrorStub } from '@postgres.ai/shared/components/ErrorStub';
|
|
18
|
+
import { SyntaxHighlight } from '@postgres.ai/shared/components/SyntaxHighlight';
|
|
19
|
+
import { StubSpinner } from '@postgres.ai/shared/components/StubSpinnerFlex';
|
|
20
|
+
import { Spinner } from '@postgres.ai/shared/components/Spinner';
|
|
21
|
+
import { useForm } from './useForm';
|
|
22
|
+
import { useCreatedStores } from './useCreatedStores';
|
|
23
|
+
import { getCliBranchListCommand, getCliCreateBranchCommand } from './utils';
|
|
24
|
+
import { InstanceTabs, TABS_INDEX } from "../Instance/Tabs";
|
|
25
|
+
const useStyles = makeStyles({
|
|
26
|
+
wrapper: {
|
|
27
|
+
display: 'flex',
|
|
28
|
+
gap: '60px',
|
|
29
|
+
maxWidth: '1200px',
|
|
30
|
+
fontSize: '14px',
|
|
31
|
+
marginTop: '20px',
|
|
32
|
+
'@media (max-width: 1300px)': {
|
|
33
|
+
flexDirection: 'column',
|
|
34
|
+
gap: '20px',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
container: {
|
|
38
|
+
maxWidth: '100%',
|
|
39
|
+
flex: '1 1 0',
|
|
40
|
+
minWidth: 0,
|
|
41
|
+
'& p,span': {
|
|
42
|
+
fontSize: 14,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
snippetContainer: {
|
|
46
|
+
flex: '1 1 0',
|
|
47
|
+
minWidth: 0,
|
|
48
|
+
boxShadow: 'rgba(0, 0, 0, 0.1) 0px 4px 12px',
|
|
49
|
+
padding: '10px 20px 10px 20px',
|
|
50
|
+
height: 'max-content',
|
|
51
|
+
borderRadius: '4px',
|
|
52
|
+
},
|
|
53
|
+
marginBottom: {
|
|
54
|
+
marginBottom: '8px',
|
|
55
|
+
},
|
|
56
|
+
marginBottom2x: {
|
|
57
|
+
marginBottom: '16px',
|
|
58
|
+
},
|
|
59
|
+
marginTop: {
|
|
60
|
+
marginTop: '8px',
|
|
61
|
+
},
|
|
62
|
+
title: {
|
|
63
|
+
marginTop: '8px',
|
|
64
|
+
lineHeight: '26px'
|
|
65
|
+
},
|
|
66
|
+
form: {
|
|
67
|
+
marginTop: '16px',
|
|
68
|
+
},
|
|
69
|
+
spinner: {
|
|
70
|
+
marginLeft: '8px',
|
|
71
|
+
color: '#fff',
|
|
72
|
+
},
|
|
73
|
+
snapshotOverflow: {
|
|
74
|
+
width: '100%',
|
|
75
|
+
wordWrap: 'break-word',
|
|
76
|
+
whiteSpace: 'initial',
|
|
77
|
+
},
|
|
78
|
+
}, { index: 1 });
|
|
79
|
+
export const CreateBranchPage = observer(({ instanceId, api, elements, routes, isPlatform }) => {
|
|
80
|
+
const stores = useCreatedStores(api);
|
|
81
|
+
const classes = useStyles();
|
|
82
|
+
const history = useHistory();
|
|
83
|
+
const [branchSnapshots, setBranchSnapshots] = useState([]);
|
|
84
|
+
const { load, branchesList, getBranchesError, createBranch, createBranchError, isBranchesLoading, isCreatingBranch, getSnapshots, snapshotsError, } = stores.main;
|
|
85
|
+
const handleSubmit = async (values) => {
|
|
86
|
+
await createBranch({
|
|
87
|
+
...values,
|
|
88
|
+
instanceId,
|
|
89
|
+
}).then((branch) => {
|
|
90
|
+
if (branch && (branch === null || branch === void 0 ? void 0 : branch.name)) {
|
|
91
|
+
history.push(routes.branch(branch.name));
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
const fetchSnapshots = async (branchName) => {
|
|
96
|
+
await getSnapshots(instanceId, branchName).then((response) => {
|
|
97
|
+
var _a;
|
|
98
|
+
if (response) {
|
|
99
|
+
setBranchSnapshots(response);
|
|
100
|
+
formik.setFieldValue('snapshotID', (_a = response[0]) === null || _a === void 0 ? void 0 : _a.id);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
const handleParentBranchChange = async (e) => {
|
|
105
|
+
const branchName = e.target.value;
|
|
106
|
+
formik.setFieldValue('baseBranch', branchName);
|
|
107
|
+
await fetchSnapshots(branchName);
|
|
108
|
+
};
|
|
109
|
+
const [{ formik }] = useForm(handleSubmit);
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
load(instanceId);
|
|
112
|
+
fetchSnapshots(formik.values.baseBranch);
|
|
113
|
+
}, [formik.values.baseBranch]);
|
|
114
|
+
if (isBranchesLoading) {
|
|
115
|
+
return _jsx(StubSpinner, {});
|
|
116
|
+
}
|
|
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 }) }), _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
|
+
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
|
|
120
|
+
? branchesList.map((branch) => {
|
|
121
|
+
return {
|
|
122
|
+
value: branch.name,
|
|
123
|
+
children: branch.name,
|
|
124
|
+
};
|
|
125
|
+
})
|
|
126
|
+
: [] }), _jsx("strong", { children: "Snapshot ID" }), _jsx("p", { className: cn(classes.marginTop, classes.marginBottom), children: "Choose an existing snapshot. This snapshot will be memorized as a forking point for the new branch; it cannot be deleted while the branch exists." }), _jsx(Select, { fullWidth: true, className: classes.marginBottom2x, label: "Snapshot ID", value: formik.values.snapshotID, disabled: !branchesList || formik.isSubmitting, onChange: (e) => formik.setFieldValue('snapshotID', e.target.value), error: Boolean(formik.errors.baseBranch), items: branchSnapshots
|
|
127
|
+
? branchSnapshots.map((snapshot, i) => {
|
|
128
|
+
const isLatest = i === 0;
|
|
129
|
+
return {
|
|
130
|
+
value: snapshot.id,
|
|
131
|
+
children: (_jsxs("div", { children: [_jsxs("strong", { className: classes.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] }))] })),
|
|
132
|
+
};
|
|
133
|
+
})
|
|
134
|
+
: [] }), _jsxs(Button, { variant: "primary", size: "medium", className: classes.marginTop, onClick: formik.submitForm, children: ["Create branch", isCreatingBranch && (_jsx(Spinner, { size: "sm", className: classes.spinner }))] }), createBranchError && (_jsx(ResponseMessage, { type: 'error', message: createBranchError }))] })] }), ' ', _jsxs("div", { className: classes.snippetContainer, children: [_jsx(SectionTitle, { tag: "h1", level: 1, text: "The same using CLI" }), _jsx("p", { className: classes.marginTop, children: "Alternatively, you can create a new branch using CLI. Fill the form, copy the command below and paste it into your terminal." }), _jsx(SyntaxHighlight, { content: getCliCreateBranchCommand(formik.values.branchName, formik.values.baseBranch) }), _jsx(SectionTitle, { className: classes.marginTop, tag: "h2", level: 2, text: 'Get branches using CLI' }), _jsx("p", { className: classes.marginTop, children: "You can get a list of all branches using CLI. Copy the command below and paste it into your terminal." }), _jsx(SyntaxHighlight, { content: getCliBranchListCommand() })] })] })] }));
|
|
135
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { GetBranches } from '@postgres.ai/shared/types/api/endpoints/getBranches';
|
|
2
|
+
import { CreateBranch, CreateBranchFormValues } from '@postgres.ai/shared/types/api/endpoints/createBranch';
|
|
3
|
+
import { Branch } from '@postgres.ai/shared/types/api/endpoints/getBranches';
|
|
4
|
+
import { GetSnapshots } from '@postgres.ai/shared/types/api/endpoints/getSnapshots';
|
|
5
|
+
import { InitWS } from '@postgres.ai/shared/types/api/endpoints/initWS';
|
|
6
|
+
declare type Error = {
|
|
7
|
+
title?: string;
|
|
8
|
+
message: string;
|
|
9
|
+
};
|
|
10
|
+
export declare type MainStoreApi = {
|
|
11
|
+
getBranches: GetBranches;
|
|
12
|
+
createBranch: CreateBranch;
|
|
13
|
+
getSnapshots: GetSnapshots;
|
|
14
|
+
initWS: InitWS;
|
|
15
|
+
};
|
|
16
|
+
export declare class MainStore {
|
|
17
|
+
snapshotsError: Error | null;
|
|
18
|
+
getBranchesError: Error | null;
|
|
19
|
+
createBranchError: string | null;
|
|
20
|
+
isBranchesLoading: boolean;
|
|
21
|
+
isCreatingBranch: boolean;
|
|
22
|
+
branchesList: Branch[];
|
|
23
|
+
private readonly api;
|
|
24
|
+
constructor(api: MainStoreApi);
|
|
25
|
+
load: (instanceId: string) => Promise<void>;
|
|
26
|
+
createBranch: (values: CreateBranchFormValues) => Promise<import("../../../types/api/entities/createBranch").CreateBranchDTO | null | undefined>;
|
|
27
|
+
getBranches: (instanceId: string) => Promise<Branch[] | null | undefined>;
|
|
28
|
+
getSnapshots: (instanceId: string, branchName?: string) => Promise<{
|
|
29
|
+
createdAtDate: Date;
|
|
30
|
+
dataStateAtDate: Date;
|
|
31
|
+
numClones: string | number;
|
|
32
|
+
clones: string[];
|
|
33
|
+
createdAt: string;
|
|
34
|
+
dataStateAt: string;
|
|
35
|
+
id: string;
|
|
36
|
+
pool: string;
|
|
37
|
+
physicalSize: number;
|
|
38
|
+
logicalSize: number;
|
|
39
|
+
message: string;
|
|
40
|
+
branch: string;
|
|
41
|
+
}[] | null | undefined>;
|
|
42
|
+
}
|
|
43
|
+
export {};
|