@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.
Files changed (186) hide show
  1. package/components/DestroyCloneModal/index.js +3 -3
  2. package/components/DestroyCloneRestrictionModal/index.js +1 -1
  3. package/components/MenuButton/index.d.ts +2 -0
  4. package/components/MenuButton/index.js +1 -1
  5. package/components/ResetCloneModal/index.js +5 -3
  6. package/icons/ArrowDropDown/index.d.ts +1 -0
  7. package/icons/ArrowDropDown/index.js +1 -1
  8. package/icons/PostgresSQL/index.d.ts +2 -0
  9. package/icons/PostgresSQL/index.js +40 -0
  10. package/package.json +1 -1
  11. package/pages/Branches/Branch/context.d.ts +22 -0
  12. package/pages/Branches/Branch/context.js +3 -0
  13. package/pages/Branches/Branch/index.d.ts +9 -0
  14. package/pages/Branches/Branch/index.js +172 -0
  15. package/pages/Branches/Branch/stores/Main.d.ts +37 -0
  16. package/pages/Branches/Branch/stores/Main.js +90 -0
  17. package/pages/Branches/Branch/useCreatedStores.d.ts +6 -0
  18. package/pages/Branches/Branch/useCreatedStores.js +5 -0
  19. package/pages/Branches/components/BranchesTable/index.d.ts +10 -0
  20. package/pages/Branches/components/BranchesTable/index.js +107 -0
  21. package/pages/Branches/components/Modals/DeleteBranchModal/index.d.ts +11 -0
  22. package/pages/Branches/components/Modals/DeleteBranchModal/index.js +49 -0
  23. package/pages/Branches/components/Modals/types.d.ts +4 -0
  24. package/pages/Branches/components/Modals/types.js +1 -0
  25. package/pages/Branches/index.d.ts +6 -0
  26. package/pages/Branches/index.js +60 -0
  27. package/pages/Clone/context.d.ts +2 -0
  28. package/pages/Clone/index.d.ts +3 -1
  29. package/pages/Clone/index.js +54 -23
  30. package/pages/Clone/stores/Main.d.ts +4 -2
  31. package/pages/Clone/utils/index.d.ts +4 -0
  32. package/pages/Clone/utils/index.js +12 -0
  33. package/pages/CreateBranch/index.d.ts +17 -0
  34. package/pages/CreateBranch/index.js +135 -0
  35. package/pages/CreateBranch/stores/Main.d.ts +43 -0
  36. package/pages/CreateBranch/stores/Main.js +59 -0
  37. package/pages/CreateBranch/useCreatedStores.d.ts +6 -0
  38. package/pages/CreateBranch/useCreatedStores.js +5 -0
  39. package/pages/CreateBranch/useForm.d.ts +51 -0
  40. package/pages/CreateBranch/useForm.js +30 -0
  41. package/pages/CreateBranch/utils/index.d.ts +2 -0
  42. package/pages/CreateBranch/utils/index.js +10 -0
  43. package/pages/CreateClone/index.d.ts +4 -2
  44. package/pages/CreateClone/index.js +92 -40
  45. package/pages/CreateClone/stores/Main.d.ts +25 -2
  46. package/pages/CreateClone/stores/Main.js +26 -2
  47. package/pages/CreateClone/styles.module.scss +47 -4
  48. package/pages/CreateClone/useForm.d.ts +1 -0
  49. package/pages/CreateClone/useForm.js +1 -0
  50. package/pages/CreateClone/utils/index.d.ts +3 -0
  51. package/pages/CreateClone/utils/index.js +17 -0
  52. package/pages/CreateSnapshot/index.d.ts +17 -0
  53. package/pages/CreateSnapshot/index.js +117 -0
  54. package/pages/CreateSnapshot/stores/Main.d.ts +21 -0
  55. package/pages/CreateSnapshot/stores/Main.js +31 -0
  56. package/pages/CreateSnapshot/useCreatedStores.d.ts +6 -0
  57. package/pages/CreateSnapshot/useCreatedStores.js +5 -0
  58. package/pages/CreateSnapshot/useForm.d.ts +53 -0
  59. package/pages/CreateSnapshot/useForm.js +25 -0
  60. package/pages/CreateSnapshot/utils/index.d.ts +1 -0
  61. package/pages/CreateSnapshot/utils/index.js +3 -0
  62. package/pages/Instance/{components → Clones}/ClonesList/MenuCell/index.js +1 -1
  63. package/pages/Instance/{components → Clones}/ClonesList/MenuCell/utils.js +2 -2
  64. package/pages/Instance/Clones/ClonesList/index.js +96 -0
  65. package/pages/Instance/{components → Clones}/ClonesList/styles.module.scss +10 -0
  66. package/pages/Instance/{ClonesModal → Clones/ClonesModal}/index.js +5 -5
  67. package/pages/Instance/Clones/Header/styles.module.scss +4 -1
  68. package/pages/Instance/Clones/index.d.ts +5 -1
  69. package/pages/Instance/Clones/index.js +6 -8
  70. package/pages/{Configuration → Instance/Configuration}/InputWithTooltip/index.js +15 -11
  71. package/pages/{Configuration → Instance/Configuration}/index.d.ts +2 -1
  72. package/pages/{Configuration → Instance/Configuration}/index.js +9 -6
  73. package/pages/{Configuration → Instance/Configuration}/tooltipText.js +1 -1
  74. package/pages/Instance/Info/Disks/Disk/index.js +6 -4
  75. package/pages/Instance/Info/Retrieval/RetrievalModal/index.js +0 -4
  76. package/pages/Instance/Info/Retrieval/index.js +1 -3
  77. package/pages/Instance/Info/Snapshots/Calendar/utils.d.ts +4 -0
  78. package/pages/Instance/Info/Snapshots/index.js +10 -5
  79. package/pages/Instance/Info/Snapshots/utils.d.ts +13 -2
  80. package/pages/Instance/Info/Snapshots/utils.js +16 -6
  81. package/pages/Instance/Info/Status/index.js +2 -2
  82. package/pages/Instance/Info/index.js +2 -1
  83. package/pages/Instance/Snapshots/components/SnapshotHeader/index.d.ts +11 -0
  84. package/pages/Instance/Snapshots/components/SnapshotHeader/index.js +36 -0
  85. package/pages/Instance/Snapshots/components/SnapshotsList/index.d.ts +11 -0
  86. package/pages/Instance/Snapshots/components/SnapshotsList/index.js +157 -0
  87. package/pages/Instance/Snapshots/components/SnapshotsTable/index.d.ts +6 -0
  88. package/pages/Instance/Snapshots/components/SnapshotsTable/index.js +125 -0
  89. package/pages/Instance/Snapshots/index.d.ts +6 -0
  90. package/pages/Instance/Snapshots/index.js +92 -0
  91. package/pages/Instance/Snapshots/utils/index.d.ts +16 -0
  92. package/pages/Instance/Snapshots/utils/index.js +30 -0
  93. package/pages/Instance/SnapshotsModal/index.js +1 -1
  94. package/pages/Instance/Tabs/PlatformTabs.d.ts +10 -0
  95. package/pages/Instance/Tabs/PlatformTabs.js +51 -0
  96. package/pages/Instance/Tabs/index.d.ts +19 -2
  97. package/pages/Instance/Tabs/index.js +71 -36
  98. package/pages/Instance/Tabs/styles.d.ts +1 -0
  99. package/pages/Instance/Tabs/styles.js +62 -0
  100. package/pages/Instance/components/ModalReloadButton/index.js +1 -1
  101. package/pages/Instance/context.d.ts +7 -0
  102. package/pages/Instance/index.js +14 -13
  103. package/pages/Instance/stores/Main.d.ts +36 -10
  104. package/pages/Instance/stores/Main.js +83 -24
  105. package/pages/Instance/styles.scss +1 -4
  106. package/pages/Logs/hooks/useWsScroll.js +6 -8
  107. package/pages/Logs/index.d.ts +2 -1
  108. package/pages/Logs/index.js +42 -31
  109. package/pages/Logs/wsLogs.d.ts +3 -2
  110. package/pages/Logs/wsLogs.js +24 -8
  111. package/pages/Logs/wsSnackbar.js +7 -7
  112. package/pages/Snapshots/Snapshot/DestorySnapshotModal/index.d.ts +12 -0
  113. package/pages/Snapshots/Snapshot/DestorySnapshotModal/index.js +69 -0
  114. package/pages/Snapshots/Snapshot/context.d.ts +23 -0
  115. package/pages/Snapshots/Snapshot/context.js +3 -0
  116. package/pages/Snapshots/Snapshot/index.d.ts +9 -0
  117. package/pages/Snapshots/Snapshot/index.js +171 -0
  118. package/pages/Snapshots/Snapshot/stores/Main.d.ts +33 -0
  119. package/pages/Snapshots/Snapshot/stores/Main.js +71 -0
  120. package/pages/Snapshots/Snapshot/useCreatedStores.d.ts +6 -0
  121. package/pages/Snapshots/Snapshot/useCreatedStores.js +5 -0
  122. package/stores/Snapshots.d.ts +12 -3
  123. package/stores/Snapshots.js +27 -3
  124. package/types/api/endpoints/createBranch.d.ts +12 -0
  125. package/types/api/endpoints/createBranch.js +1 -0
  126. package/types/api/endpoints/createClone.d.ts +1 -0
  127. package/types/api/endpoints/createSnapshot.d.ts +5 -0
  128. package/types/api/endpoints/createSnapshot.js +1 -0
  129. package/types/api/endpoints/deleteBranch.d.ts +4 -0
  130. package/types/api/endpoints/deleteBranch.js +1 -0
  131. package/types/api/endpoints/destroySnapshot.d.ts +4 -0
  132. package/types/api/endpoints/destroySnapshot.js +1 -0
  133. package/types/api/endpoints/getBranchSnapshot.d.ts +5 -0
  134. package/types/api/endpoints/getBranchSnapshot.js +1 -0
  135. package/types/api/endpoints/getBranches.d.ts +18 -0
  136. package/types/api/endpoints/getBranches.js +5 -0
  137. package/types/api/endpoints/getConfig.d.ts +2 -2
  138. package/types/api/endpoints/getEngine.d.ts +1 -1
  139. package/types/api/endpoints/getFullConfig.d.ts +1 -1
  140. package/types/api/endpoints/getSnapshotList.d.ts +10 -0
  141. package/types/api/endpoints/getSnapshotList.js +1 -0
  142. package/types/api/endpoints/getSnapshots.d.ts +1 -0
  143. package/types/api/endpoints/updateConfig.d.ts +1 -1
  144. package/types/api/entities/branchSnapshot.d.ts +6 -0
  145. package/types/api/entities/branchSnapshot.js +1 -0
  146. package/types/api/entities/branchSnapshots.d.ts +15 -0
  147. package/types/api/entities/branchSnapshots.js +7 -0
  148. package/types/api/entities/clone.d.ts +6 -0
  149. package/types/api/entities/config.js +1 -1
  150. package/types/api/entities/createBranch.d.ts +5 -0
  151. package/types/api/entities/createBranch.js +1 -0
  152. package/types/api/entities/createSnapshot.d.ts +5 -0
  153. package/types/api/entities/createSnapshot.js +1 -0
  154. package/types/api/entities/dbSource.d.ts +1 -0
  155. package/types/api/entities/instance.d.ts +5 -0
  156. package/types/api/entities/instanceState.d.ts +5 -0
  157. package/types/api/entities/snapshot.d.ts +8 -0
  158. package/types/api/entities/snapshot.js +1 -1
  159. package/utils/date.d.ts +2 -0
  160. package/utils/date.js +7 -0
  161. package/utils/snapshot.d.ts +5 -2
  162. package/utils/snapshot.js +6 -1
  163. package/pages/Instance/components/ClonesList/index.js +0 -52
  164. /package/pages/Instance/{components → Clones}/ClonesList/ConnectionModal/index.d.ts +0 -0
  165. /package/pages/Instance/{components → Clones}/ClonesList/ConnectionModal/index.js +0 -0
  166. /package/pages/Instance/{components → Clones}/ClonesList/MenuCell/index.d.ts +0 -0
  167. /package/pages/Instance/{components → Clones}/ClonesList/MenuCell/utils.d.ts +0 -0
  168. /package/pages/Instance/{components → Clones}/ClonesList/index.d.ts +0 -0
  169. /package/pages/Instance/{ClonesModal → Clones/ClonesModal}/index.d.ts +0 -0
  170. /package/pages/Instance/{ClonesModal → Clones/ClonesModal}/utils.d.ts +0 -0
  171. /package/pages/Instance/{ClonesModal → Clones/ClonesModal}/utils.js +0 -0
  172. /package/pages/{Configuration → Instance/Configuration}/Header/index.d.ts +0 -0
  173. /package/pages/{Configuration → Instance/Configuration}/Header/index.js +0 -0
  174. /package/pages/{Configuration → Instance/Configuration}/InputWithTooltip/index.d.ts +0 -0
  175. /package/pages/{Configuration → Instance/Configuration}/ResponseMessage/index.d.ts +0 -0
  176. /package/pages/{Configuration → Instance/Configuration}/ResponseMessage/index.js +0 -0
  177. /package/pages/{Configuration → Instance/Configuration}/configOptions.d.ts +0 -0
  178. /package/pages/{Configuration → Instance/Configuration}/configOptions.js +0 -0
  179. /package/pages/{Configuration → Instance/Configuration}/styles.module.scss +0 -0
  180. /package/pages/{Configuration → Instance/Configuration}/tooltipText.d.ts +0 -0
  181. /package/pages/{Configuration → Instance/Configuration}/useForm.d.ts +0 -0
  182. /package/pages/{Configuration → Instance/Configuration}/useForm.js +0 -0
  183. /package/pages/{Configuration → Instance/Configuration}/utils/index.d.ts +0 -0
  184. /package/pages/{Configuration → Instance/Configuration}/utils/index.js +0 -0
  185. /package/pages/Instance/{SnapshotsModal → Snapshots/components/SnapshotsModal}/utils.d.ts +0 -0
  186. /package/pages/Instance/{SnapshotsModal → Snapshots/components/SnapshotsModal}/utils.js +0 -0
@@ -0,0 +1,59 @@
1
+ /*--------------------------------------------------------------------------
2
+ * Copyright (c) 2019-2021, Postgres.ai, Nikolay Samokhvalov nik@postgres.ai
3
+ * All Rights Reserved. Proprietary and confidential.
4
+ * Unauthorized copying of this file, via any medium is strictly prohibited
5
+ *--------------------------------------------------------------------------
6
+ */
7
+ import { makeAutoObservable } from 'mobx';
8
+ export class MainStore {
9
+ constructor(api) {
10
+ this.snapshotsError = null;
11
+ this.getBranchesError = null;
12
+ this.createBranchError = null;
13
+ this.isBranchesLoading = false;
14
+ this.isCreatingBranch = false;
15
+ this.branchesList = [];
16
+ this.load = async (instanceId) => {
17
+ await this.getBranches(instanceId).then((response) => {
18
+ if (response) {
19
+ this.branchesList = response;
20
+ }
21
+ });
22
+ };
23
+ this.createBranch = async (values) => {
24
+ if (!this.api.createBranch)
25
+ return;
26
+ this.isCreatingBranch = true;
27
+ this.createBranchError = null;
28
+ const { response, error } = await this.api.createBranch(values);
29
+ this.isCreatingBranch = false;
30
+ if (error)
31
+ this.createBranchError = await error.json().then((err) => err.details);
32
+ return response;
33
+ };
34
+ this.getBranches = async (instanceId) => {
35
+ if (!this.api.getBranches)
36
+ return;
37
+ this.isBranchesLoading = true;
38
+ const { response, error } = await this.api.getBranches(instanceId);
39
+ this.isBranchesLoading = false;
40
+ if (error)
41
+ this.getBranchesError = await error.json().then((err) => err);
42
+ return response;
43
+ };
44
+ this.getSnapshots = async (instanceId, branchName) => {
45
+ if (!this.api.getSnapshots)
46
+ return;
47
+ const { response, error } = await this.api.getSnapshots({
48
+ instanceId,
49
+ branchName,
50
+ });
51
+ if (error) {
52
+ this.snapshotsError = await error.json().then((err) => err);
53
+ }
54
+ return response;
55
+ };
56
+ this.api = api;
57
+ makeAutoObservable(this);
58
+ }
59
+ }
@@ -0,0 +1,6 @@
1
+ import { MainStore, MainStoreApi } from './stores/Main';
2
+ export declare const useCreatedStores: (api: MainStoreApi) => {
3
+ main: MainStore;
4
+ };
5
+ export declare type Stores = ReturnType<typeof useCreatedStores>;
6
+ export type { MainStoreApi };
@@ -0,0 +1,5 @@
1
+ import { useMemo } from 'react';
2
+ import { MainStore } from './stores/Main';
3
+ export const useCreatedStores = (api) => ({
4
+ main: useMemo(() => new MainStore(api), []),
5
+ });
@@ -0,0 +1,51 @@
1
+ /// <reference types="react" />
2
+ import { CreateBranchFormValues } from '@postgres.ai/shared/types/api/endpoints/createBranch';
3
+ export declare const useForm: (onSubmit: (values: CreateBranchFormValues) => void) => {
4
+ formik: {
5
+ initialValues: CreateBranchFormValues;
6
+ initialErrors: import("formik").FormikErrors<unknown>;
7
+ initialTouched: import("formik").FormikTouched<unknown>;
8
+ initialStatus: any;
9
+ handleBlur: {
10
+ (e: import("react").FocusEvent<any, Element>): void;
11
+ <T = any>(fieldOrEvent: T): T extends string ? (e: any) => void : void;
12
+ };
13
+ handleChange: {
14
+ (e: import("react").ChangeEvent<any>): void;
15
+ <T_1 = string | import("react").ChangeEvent<any>>(field: T_1): T_1 extends import("react").ChangeEvent<any> ? void : (e: string | import("react").ChangeEvent<any>) => void;
16
+ };
17
+ handleReset: (e: any) => void;
18
+ handleSubmit: (e?: import("react").FormEvent<HTMLFormElement> | undefined) => void;
19
+ resetForm: (nextState?: Partial<import("formik").FormikState<CreateBranchFormValues>> | undefined) => void;
20
+ setErrors: (errors: import("formik").FormikErrors<CreateBranchFormValues>) => void;
21
+ setFormikState: (stateOrCb: import("formik").FormikState<CreateBranchFormValues> | ((state: import("formik").FormikState<CreateBranchFormValues>) => import("formik").FormikState<CreateBranchFormValues>)) => void;
22
+ setFieldTouched: (field: string, touched?: boolean | undefined, shouldValidate?: boolean | undefined) => Promise<void> | Promise<import("formik").FormikErrors<CreateBranchFormValues>>;
23
+ setFieldValue: (field: string, value: any, shouldValidate?: boolean | undefined) => Promise<void> | Promise<import("formik").FormikErrors<CreateBranchFormValues>>;
24
+ setFieldError: (field: string, value: string | undefined) => void;
25
+ setStatus: (status: any) => void;
26
+ setSubmitting: (isSubmitting: boolean) => void;
27
+ setTouched: (touched: import("formik").FormikTouched<CreateBranchFormValues>, shouldValidate?: boolean | undefined) => Promise<void> | Promise<import("formik").FormikErrors<CreateBranchFormValues>>;
28
+ setValues: (values: import("react").SetStateAction<CreateBranchFormValues>, shouldValidate?: boolean | undefined) => Promise<void> | Promise<import("formik").FormikErrors<CreateBranchFormValues>>;
29
+ submitForm: () => Promise<any>;
30
+ validateForm: (values?: CreateBranchFormValues | undefined) => Promise<import("formik").FormikErrors<CreateBranchFormValues>>;
31
+ validateField: (name: string) => Promise<void> | Promise<string | undefined>;
32
+ isValid: boolean;
33
+ dirty: boolean;
34
+ unregisterField: (name: string) => void;
35
+ registerField: (name: string, { validate }: any) => void;
36
+ getFieldProps: (nameOrOptions: any) => import("formik").FieldInputProps<any>;
37
+ getFieldMeta: (name: string) => import("formik").FieldMetaProps<any>;
38
+ getFieldHelpers: (name: string) => import("formik").FieldHelperProps<any>;
39
+ validateOnBlur: boolean;
40
+ validateOnChange: boolean;
41
+ validateOnMount: boolean;
42
+ values: CreateBranchFormValues;
43
+ errors: import("formik").FormikErrors<CreateBranchFormValues>;
44
+ touched: import("formik").FormikTouched<CreateBranchFormValues>;
45
+ isSubmitting: boolean;
46
+ isValidating: boolean;
47
+ status?: any;
48
+ submitCount: number;
49
+ };
50
+ isFormDisabled: boolean;
51
+ }[];
@@ -0,0 +1,30 @@
1
+ /*--------------------------------------------------------------------------
2
+ * Copyright (c) 2019-2021, Postgres.ai, Nikolay Samokhvalov nik@postgres.ai
3
+ * All Rights Reserved. Proprietary and confidential.
4
+ * Unauthorized copying of this file, via any medium is strictly prohibited
5
+ *--------------------------------------------------------------------------
6
+ */
7
+ import { useFormik } from 'formik';
8
+ import * as Yup from 'yup';
9
+ const Schema = Yup.object().shape({
10
+ branchName: Yup.string().required('Branch name is required'),
11
+ });
12
+ export const useForm = (onSubmit) => {
13
+ const formik = useFormik({
14
+ initialValues: {
15
+ instanceId: '',
16
+ branchName: '',
17
+ baseBranch: 'main',
18
+ snapshotID: '',
19
+ creationType: 'branch',
20
+ },
21
+ validationSchema: Schema,
22
+ onSubmit,
23
+ validateOnBlur: false,
24
+ validateOnChange: false,
25
+ });
26
+ const isFormDisabled = formik.isSubmitting ||
27
+ !formik.values.branchName ||
28
+ (!formik.values.snapshotID && !formik.values.baseBranch);
29
+ return [{ formik, isFormDisabled }];
30
+ };
@@ -0,0 +1,2 @@
1
+ export declare const getCliCreateBranchCommand: (branchName: string, parentBranchName: string) => string;
2
+ export declare const getCliBranchListCommand: () => string;
@@ -0,0 +1,10 @@
1
+ export const getCliCreateBranchCommand = (branchName, parentBranchName) => {
2
+ const branchArg = branchName || `<BRANCH_NAME>`;
3
+ const parentBranchArg = parentBranchName && parentBranchName !== `main`
4
+ ? `--parent-branch ${parentBranchName}`
5
+ : ``;
6
+ return `dblab branch ${branchArg} ${parentBranchArg}`.trim();
7
+ };
8
+ export const getCliBranchListCommand = () => {
9
+ return `dblab branch`;
10
+ };
@@ -1,4 +1,4 @@
1
- /// <reference types="react" />
1
+ import React from 'react';
2
2
  import { MainStoreApi } from './useCreatedStores';
3
3
  declare type Host = {
4
4
  instanceId: string;
@@ -10,7 +10,9 @@ declare type Host = {
10
10
  breadcrumbs: React.ReactNode;
11
11
  };
12
12
  };
13
- declare type Props = Host;
13
+ declare type Props = Host & {
14
+ isPlatform?: boolean;
15
+ };
14
16
  export declare const CreateClone: ((props: Props) => JSX.Element) & {
15
17
  displayName: string;
16
18
  };
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import cn from 'classnames';
3
- import { useEffect } from 'react';
3
+ import { useEffect, useState } from 'react';
4
4
  import { useHistory } from 'react-router-dom';
5
5
  import { observer } from 'mobx-react-lite';
6
6
  import { useTimer } from 'use-timer';
@@ -12,20 +12,25 @@ import { Select } from '@postgres.ai/shared/components/Select';
12
12
  import { Button } from '@postgres.ai/shared/components/Button';
13
13
  import { Spinner } from '@postgres.ai/shared/components/Spinner';
14
14
  import { ErrorStub } from '@postgres.ai/shared/components/ErrorStub';
15
- import { compareSnapshotsDesc } from '@postgres.ai/shared/utils/snapshot';
16
15
  import { round } from '@postgres.ai/shared/utils/numbers';
17
16
  import { formatBytesIEC } from '@postgres.ai/shared/utils/units';
18
17
  import { SectionTitle } from '@postgres.ai/shared/components/SectionTitle';
18
+ import { SyntaxHighlight } from '@postgres.ai/shared/components/SyntaxHighlight';
19
19
  import { MIN_ENTROPY, getEntropy, validatePassword, } from '@postgres.ai/shared/helpers/getEntropy';
20
20
  import { useCreatedStores } from './useCreatedStores';
21
21
  import { useForm } from './useForm';
22
+ import { getCliCloneStatus, getCliCreateCloneCommand } from './utils';
23
+ import { compareSnapshotsDesc } from '@postgres.ai/shared/utils/snapshot';
22
24
  import styles from './styles.module.scss';
25
+ import { InstanceTabs, TABS_INDEX } from "../Instance/Tabs";
23
26
  export const CreateClone = observer((props) => {
24
- var _a, _b, _c, _d;
27
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
25
28
  const history = useHistory();
26
29
  const stores = useCreatedStores(props.api);
27
- const cloneError = stores.main.cloneError;
28
30
  const timer = useTimer();
31
+ const [branchesList, setBranchesList] = useState([]);
32
+ const [snapshots, setSnapshots] = useState([]);
33
+ const [isLoadingSnapshots, setIsLoadingSnapshots] = useState(false);
29
34
  // Form.
30
35
  const onSubmit = async (values) => {
31
36
  if (!values.dbPassword || getEntropy(values.dbPassword) < MIN_ENTROPY) {
@@ -35,56 +40,103 @@ export const CreateClone = observer((props) => {
35
40
  timer.start();
36
41
  const isSuccess = await stores.main.createClone(values);
37
42
  formik.setFieldError('dbPassword', '');
38
- if (!isSuccess || cloneError) {
43
+ if (!isSuccess || stores.main.cloneError) {
39
44
  timer.pause();
40
45
  timer.reset();
41
46
  }
42
47
  };
48
+ const fetchBranchSnapshotsData = async (branchName, initialSnapshotId) => {
49
+ var _a;
50
+ const snapshotsRes = (_a = (await stores.main.getSnapshots(props.instanceId, branchName))) !== null && _a !== void 0 ? _a : [];
51
+ setSnapshots(snapshotsRes);
52
+ const selectedSnapshot = snapshotsRes.find(s => s.id === initialSnapshotId) || snapshotsRes[0];
53
+ formik.setFieldValue('snapshotId', selectedSnapshot === null || selectedSnapshot === void 0 ? void 0 : selectedSnapshot.id);
54
+ };
55
+ const handleSelectBranch = async (e) => {
56
+ const selectedBranch = e.target.value;
57
+ formik.setFieldValue('branch', selectedBranch);
58
+ if (props.api.getSnapshots) {
59
+ await fetchBranchSnapshotsData(selectedBranch);
60
+ }
61
+ };
43
62
  const formik = useForm(onSubmit);
63
+ const fetchData = async (initialBranch, initialSnapshotId) => {
64
+ var _a, _b, _c, _d, _e;
65
+ try {
66
+ setIsLoadingSnapshots(true);
67
+ await stores.main.load(props.instanceId);
68
+ const branches = (_a = (await stores.main.getBranches(props.instanceId))) !== null && _a !== void 0 ? _a : [];
69
+ let initiallySelectedBranch = (_b = branches[0]) === null || _b === void 0 ? void 0 : _b.name;
70
+ if (initialBranch && branches.find((branch) => branch.name === initialBranch)) {
71
+ initiallySelectedBranch = initialBranch;
72
+ }
73
+ setBranchesList(branches.map((branch) => branch.name));
74
+ formik.setFieldValue('branch', initiallySelectedBranch);
75
+ if (props.api.getSnapshots) {
76
+ await fetchBranchSnapshotsData(initiallySelectedBranch, initialSnapshotId);
77
+ }
78
+ else {
79
+ const allSnapshots = (_e = (_d = (_c = stores.main) === null || _c === void 0 ? void 0 : _c.snapshots) === null || _d === void 0 ? void 0 : _d.data) !== null && _e !== void 0 ? _e : [];
80
+ const sortedSnapshots = allSnapshots.slice().sort(compareSnapshotsDesc);
81
+ setSnapshots(sortedSnapshots);
82
+ let selectedSnapshot = allSnapshots.find(s => s.id === initialSnapshotId) || allSnapshots[0];
83
+ formik.setFieldValue('snapshotId', selectedSnapshot === null || selectedSnapshot === void 0 ? void 0 : selectedSnapshot.id);
84
+ }
85
+ }
86
+ catch (error) {
87
+ console.error('Error fetching data:', error);
88
+ }
89
+ finally {
90
+ setIsLoadingSnapshots(false);
91
+ }
92
+ };
44
93
  // Initial loading data.
45
94
  useEffect(() => {
46
- stores.main.load(props.instanceId);
47
- }, []);
95
+ var _a, _b;
96
+ const queryString = history.location.search.split('?')[1];
97
+ const params = new URLSearchParams(queryString);
98
+ const branchId = (_a = params.get('branch_id')) !== null && _a !== void 0 ? _a : undefined;
99
+ const snapshotId = (_b = params.get('snapshot_id')) !== null && _b !== void 0 ? _b : undefined;
100
+ fetchData(branchId, snapshotId);
101
+ }, [history.location.search, formik.initialValues]);
48
102
  // Redirect when clone is created and stable.
49
103
  useEffect(() => {
50
- if (!stores.main.clone)
51
- return;
52
- if (!stores.main.isCloneStable)
104
+ if (!stores.main.clone || !stores.main.isCloneStable)
53
105
  return;
54
106
  history.push(props.routes.clone(stores.main.clone.id));
55
107
  }, [stores.main.clone, stores.main.isCloneStable]);
56
- // Snapshots.
57
- const sortedSnapshots = (_a = stores.main.snapshots.data) === null || _a === void 0 ? void 0 : _a.slice().sort(compareSnapshotsDesc);
58
- useEffect(() => {
59
- const [firstSnapshot] = sortedSnapshots !== null && sortedSnapshots !== void 0 ? sortedSnapshots : [];
60
- if (!firstSnapshot)
61
- return;
62
- formik.setFieldValue('snapshotId', firstSnapshot.id);
63
- }, [Boolean(sortedSnapshots)]);
64
- const headRendered = (_jsxs(_Fragment, { children: [_jsx("style", { children: 'p { margin: 0; }' }), props.elements.breadcrumbs, _jsx(SectionTitle, { className: styles.title, tag: "h1", level: 1, text: "Create clone" })] }));
108
+ const headRendered = (_jsxs(_Fragment, { children: [_jsx("style", { children: 'p { margin: 0; }' }), props.elements.breadcrumbs, _jsx(SectionTitle, { tag: "h1", level: 1, text: "Create clone", className: styles.pageTitle, children: _jsx(InstanceTabs, { tab: TABS_INDEX.CLONES, isPlatform: props.isPlatform, instanceId: props.instanceId, hasLogs: props.api.initWS !== undefined }) })] }));
65
109
  // Initial loading spinner.
66
- if (!stores.main.instance || !stores.main.snapshots.data)
110
+ if (!stores.main.instance || isLoadingSnapshots)
67
111
  return (_jsxs(_Fragment, { children: [headRendered, _jsx(StubSpinner, {})] }));
68
- // Instance getting error.
69
- if (stores.main.instanceError)
70
- return (_jsxs(_Fragment, { children: [headRendered, _jsx(ErrorStub, { message: stores.main.instanceError })] }));
71
- // Snapshots getting error.
72
- if (stores.main.snapshots.error)
73
- return _jsx(ErrorStub, { message: stores.main.snapshots.error });
112
+ // Instance/branches getting error.
113
+ if (stores.main.instanceError ||
114
+ stores.main.getBranchesError ||
115
+ stores.main.getSnapshotsError ||
116
+ ((_b = (_a = stores.main) === null || _a === void 0 ? void 0 : _a.snapshots) === null || _b === void 0 ? void 0 : _b.error))
117
+ return (_jsxs(_Fragment, { children: [headRendered, _jsx(ErrorStub, { message: stores.main.instanceError ||
118
+ ((_c = stores.main.getBranchesError) === null || _c === void 0 ? void 0 : _c.message) ||
119
+ ((_d = stores.main.getSnapshotsError) === null || _d === void 0 ? void 0 : _d.message) ||
120
+ ((_f = (_e = stores.main) === null || _e === void 0 ? void 0 : _e.snapshots) === null || _f === void 0 ? void 0 : _f.error) })] }));
74
121
  const isCloneUnstable = Boolean(stores.main.clone && !stores.main.isCloneStable);
75
122
  const isCreatingClone = formik.isSubmitting || isCloneUnstable;
76
- return (_jsxs(_Fragment, { children: [headRendered, _jsxs("div", { className: styles.form, children: [stores.main.cloneError && (_jsx("div", { className: styles.section, children: _jsx(ErrorStub, { message: stores.main.cloneError }) })), _jsxs("div", { className: styles.section, children: [_jsx(TextField, { fullWidth: true, label: "Clone ID", value: formik.values.cloneId, onChange: (e) => formik.setFieldValue('cloneId', e.target.value), error: Boolean(formik.errors.cloneId), disabled: isCreatingClone }), _jsx(Select, { fullWidth: true, label: "Data state time *", value: formik.values.snapshotId, disabled: !sortedSnapshots || isCreatingClone, onChange: (e) => formik.setFieldValue('snapshotId', e.target.value), error: Boolean(formik.errors.snapshotId), items: (_b = sortedSnapshots === null || sortedSnapshots === void 0 ? void 0 : sortedSnapshots.map((snapshot, i) => {
77
- const isLatest = i === 0;
78
- return {
79
- value: snapshot.id,
80
- children: (_jsxs(_Fragment, { children: [snapshot.dataStateAt, isLatest && (_jsx("span", { className: styles.snapshotTag, children: "Latest" }))] })),
81
- };
82
- })) !== null && _b !== void 0 ? _b : [] }), _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\u2019t 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) => {
83
- formik.setFieldValue('dbPassword', e.target.value);
84
- if (formik.errors.dbPassword) {
85
- formik.setFieldError('dbPassword', '');
86
- }
87
- }, error: Boolean(formik.errors.dbPassword), disabled: isCreatingClone }), _jsx("p", { className: cn(formik.errors.dbPassword && styles.error, styles.remark), children: formik.errors.dbPassword })] }), _jsx("div", { className: styles.section, children: _jsxs(Paper, { className: styles.summary, children: [_jsx(InfoIcon, { className: styles.summaryIcon }), _jsxs("div", { className: styles.params, children: [_jsxs("p", { className: styles.param, children: [_jsx("span", { children: "Data size:" }), _jsx("strong", { children: ((_c = stores.main.instance.state) === null || _c === void 0 ? void 0 : _c.dataSize)
88
- ? formatBytesIEC(stores.main.instance.state.dataSize)
89
- : '-' })] }), _jsxs("p", { className: styles.param, children: [_jsx("span", { children: "Expected cloning time:" }), _jsxs("strong", { children: [round((_d = stores.main.instance.state) === null || _d === void 0 ? void 0 : _d.cloning.expectedCloningTime, 2), ' ', "s"] })] })] })] }) }), _jsxs("div", { className: styles.section, children: [_jsx(FormControlLabel, { label: "Enable deletion protection", control: _jsx(Checkbox, { checked: formik.values.isProtected, onChange: (e) => formik.setFieldValue('isProtected', e.target.checked), name: "protected", disabled: isCreatingClone }) }), _jsxs("p", { className: styles.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."] })] }), _jsx("div", { className: styles.section, children: _jsxs("div", { className: styles.controls, children: [_jsxs(Button, { onClick: formik.submitForm, variant: "primary", size: "medium", isDisabled: isCreatingClone, children: ["Create clone", isCreatingClone && (_jsx(Spinner, { size: "sm", className: styles.spinner }))] }), isCreatingClone && (_jsxs("p", { className: styles.elapsedTime, children: ["Elapsed time: ", timer.time, " s"] }))] }) })] })] }));
123
+ return (_jsxs(_Fragment, { children: [headRendered, _jsxs("div", { className: styles.container, children: [_jsxs("div", { className: styles.form, children: [_jsxs("div", { className: styles.section, children: [branchesList && branchesList.length > 0 && (_jsx(Select, { fullWidth: true, label: "Branch", value: formik.values.branch, disabled: !branchesList || isCreatingClone, onChange: handleSelectBranch, error: Boolean(formik.errors.branch), items: (_g = branchesList === null || branchesList === void 0 ? void 0 : branchesList.map((snapshot) => {
124
+ return {
125
+ value: snapshot,
126
+ children: snapshot,
127
+ };
128
+ })) !== null && _g !== void 0 ? _g : [] })), _jsx(TextField, { fullWidth: true, label: "Clone ID", value: formik.values.cloneId, onChange: (e) => formik.setFieldValue('cloneId', e.target.value), 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) => {
129
+ const isLatest = i === 0;
130
+ return {
131
+ value: snapshot.id,
132
+ 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] }))] })),
133
+ };
134
+ })) !== 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\u2019t 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) => {
135
+ formik.setFieldValue('dbPassword', e.target.value);
136
+ if (formik.errors.dbPassword) {
137
+ formik.setFieldError('dbPassword', '');
138
+ }
139
+ }, error: Boolean(formik.errors.dbPassword), disabled: isCreatingClone }), _jsx("p", { className: cn(formik.errors.dbPassword && styles.error, styles.remark), children: formik.errors.dbPassword })] }), _jsxs("div", { className: styles.form, children: [_jsx(FormControlLabel, { label: "Enable deletion protection", control: _jsx(Checkbox, { checked: formik.values.isProtected, onChange: (e) => formik.setFieldValue('isProtected', e.target.checked), name: "protected", disabled: isCreatingClone }) }), _jsxs("p", { className: styles.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 a daily basis and delete this clone once the work is done."] })] }), _jsxs("div", { className: cn(styles.marginBottom, styles.section), children: [_jsxs(Paper, { className: styles.summary, children: [_jsx(InfoIcon, { className: styles.summaryIcon }), _jsxs("div", { className: styles.params, children: [_jsxs("p", { className: styles.param, children: [_jsx("span", { children: "Data size:" }), _jsx("strong", { children: ((_j = stores.main.instance.state) === null || _j === void 0 ? void 0 : _j.dataSize)
140
+ ? formatBytesIEC(stores.main.instance.state.dataSize)
141
+ : '-' })] }), _jsxs("p", { className: styles.param, children: [_jsx("span", { children: "Expected cloning time:" }), _jsxs("strong", { children: [round((_k = stores.main.instance.state) === null || _k === void 0 ? void 0 : _k.cloning.expectedCloningTime, 2), ' ', "s"] })] })] })] }), stores.main.cloneError && (_jsx("div", { className: cn(styles.marginBottom, styles.section), children: _jsx(ErrorStub, { message: stores.main.cloneError }) })), _jsx("div", { className: styles.controls, children: _jsxs(Button, { onClick: formik.submitForm, variant: "primary", size: "medium", isDisabled: isCreatingClone, children: ["Create clone", isCreatingClone && (_jsx(Spinner, { size: "sm", className: styles.spinner }))] }) })] })] }), _jsx("div", { className: styles.form, children: _jsxs("div", { className: styles.snippetContainer, children: [_jsx(SectionTitle, { className: styles.title, tag: "h1", level: 1, text: "The same using CLI" }), _jsx("p", { className: styles.text, children: "Alternatively, you can create a new clone using CLI. Fill the form, copy the command below and paste it into your terminal." }), _jsx(SyntaxHighlight, { wrapLines: true, content: getCliCreateCloneCommand(formik.values) }), _jsx(SectionTitle, { className: styles.title, tag: "h2", level: 2, text: "Check clone status" }), _jsx("p", { className: styles.text, children: "To check the status of your newly created clone, use the command below." }), _jsx(SyntaxHighlight, { content: getCliCloneStatus(formik.values.cloneId) })] }) })] })] }));
90
142
  });
@@ -3,24 +3,47 @@ import { Clone } from '@postgres.ai/shared/types/api/entities/clone';
3
3
  import { GetInstance } from '@postgres.ai/shared/types/api/endpoints/getInstance';
4
4
  import { CreateClone } from '@postgres.ai/shared/types/api/endpoints/createClone';
5
5
  import { GetClone } from '@postgres.ai/shared/types/api/endpoints/getClone';
6
+ import { GetBranches } from '@postgres.ai/shared/types/api/endpoints/getBranches';
7
+ import { GetSnapshots } from '@postgres.ai/shared/types/api/endpoints/getSnapshots';
6
8
  import { SnapshotsStore, SnapshotsApi } from '@postgres.ai/shared/stores/Snapshots';
7
9
  import { FormValues } from '../useForm';
10
+ import { InitWS } from '@postgres.ai/shared/types/api/endpoints/initWS';
8
11
  export declare type MainStoreApi = SnapshotsApi & {
9
12
  getInstance: GetInstance;
10
13
  createClone: CreateClone;
11
14
  getClone: GetClone;
15
+ getBranches?: GetBranches;
16
+ getSnapshots?: GetSnapshots;
17
+ initWS: InitWS;
12
18
  };
13
19
  export declare class MainStore {
14
20
  instance: Instance | null;
15
21
  instanceError: string | null;
22
+ getBranchesError: Error | null;
23
+ getSnapshotsError: Error | null;
16
24
  clone: Clone | null;
17
25
  cloneError: string | null;
18
26
  private cloneUpdateTimeout?;
19
27
  private readonly api;
20
- readonly snapshots: SnapshotsStore;
28
+ readonly snapshots?: SnapshotsStore;
21
29
  constructor(api: MainStoreApi);
22
30
  get isCloneStable(): boolean | undefined;
23
- load: (instanceId: string) => Promise<boolean>;
31
+ load: (instanceId: string) => Promise<boolean | undefined>;
24
32
  createClone: (data: FormValues) => Promise<boolean>;
33
+ getBranches: (instanceId: string) => Promise<import("@postgres.ai/shared/types/api/endpoints/getBranches").Branch[] | null | undefined>;
34
+ getSnapshots: (instanceId: string, branchName?: string) => Promise<{
35
+ createdAtDate: Date;
36
+ dataStateAtDate: Date;
37
+ numClones: string | number;
38
+ clones: string[];
39
+ createdAt: string;
40
+ dataStateAt: string;
41
+ id: string;
42
+ pool: string;
43
+ physicalSize: number;
44
+ logicalSize: number;
45
+ message: string;
46
+ branch: string;
47
+ }[] | null | undefined>;
25
48
  private updateCloneUntilStable;
26
49
  }
@@ -7,12 +7,15 @@ export class MainStore {
7
7
  constructor(api) {
8
8
  this.instance = null;
9
9
  this.instanceError = null;
10
+ this.getBranchesError = null;
11
+ this.getSnapshotsError = null;
10
12
  this.clone = null;
11
13
  this.cloneError = null;
12
14
  this.load = async (instanceId) => {
15
+ var _a, _b;
13
16
  const [instance, isLoadedSnapshots] = await Promise.all([
14
17
  this.api.getInstance({ instanceId }),
15
- this.snapshots.load(instanceId),
18
+ (_b = (_a = this.snapshots) === null || _a === void 0 ? void 0 : _a.load(instanceId)) !== null && _b !== void 0 ? _b : true,
16
19
  ]);
17
20
  if (instance.response)
18
21
  this.instance = instance.response;
@@ -38,6 +41,25 @@ export class MainStore {
38
41
  this.cloneError = await error.json().then((err) => (err === null || err === void 0 ? void 0 : err.message) || err);
39
42
  return Boolean(response);
40
43
  };
44
+ this.getBranches = async (instanceId) => {
45
+ if (!this.api.getBranches)
46
+ return;
47
+ const { response, error } = await this.api.getBranches(instanceId);
48
+ if (error)
49
+ this.getBranchesError = await error.json().then((err) => err);
50
+ return response;
51
+ };
52
+ this.getSnapshots = async (instanceId, branchName) => {
53
+ if (!this.api.getSnapshots)
54
+ return;
55
+ const { response, error } = await this.api.getSnapshots({
56
+ instanceId,
57
+ branchName,
58
+ });
59
+ if (error)
60
+ this.getSnapshotsError = await error.json().then((err) => err);
61
+ return response;
62
+ };
41
63
  this.updateCloneUntilStable = async (args) => {
42
64
  window.clearTimeout(this.cloneUpdateTimeout);
43
65
  const { response, error } = await this.api.getClone(args);
@@ -51,7 +73,9 @@ export class MainStore {
51
73
  };
52
74
  makeAutoObservable(this);
53
75
  this.api = api;
54
- this.snapshots = new SnapshotsStore(api);
76
+ if (!api.getSnapshots) {
77
+ this.snapshots = new SnapshotsStore(api);
78
+ }
55
79
  }
56
80
  get isCloneStable() {
57
81
  if (!this.clone)
@@ -1,15 +1,41 @@
1
+ .container {
2
+ display: flex;
3
+ gap: 60px;
4
+ margin-top: 20px;
5
+ max-width: 1200px;
6
+
7
+ @media (max-width: 1300px) {
8
+ flex-direction: column;
9
+ gap: 20px;
10
+ }
11
+ }
12
+
1
13
  .title {
2
14
  margin-top: 16px;
3
15
  }
4
16
 
5
17
  .form {
6
- max-width: 425px;
7
- margin-top: 8px;
18
+ flex: 1 1 0;
19
+ }
20
+
21
+ .snippetContainer {
22
+ flex: 1 1 0;
23
+ min-width: 0;
24
+ box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;
25
+ padding: 0 20px 10px 20px;
26
+ height: max-content;
27
+ border-radius: 4px;
28
+ }
29
+
30
+ .snapshotItem {
31
+ display: flex;
32
+ flex-direction: column;
33
+ padding: 4px 0;
8
34
  }
9
35
 
10
36
  .section {
11
37
  & + .section {
12
- margin-top: 32px;
38
+ margin-top: 24px;
13
39
  }
14
40
  }
15
41
 
@@ -22,6 +48,10 @@
22
48
  margin-top: 8px;
23
49
  }
24
50
 
51
+ .marginBottom {
52
+ margin-bottom: 10px;
53
+ }
54
+
25
55
  .remark {
26
56
  font-size: 12px;
27
57
  }
@@ -38,8 +68,10 @@
38
68
  .summary {
39
69
  display: flex;
40
70
  align-items: center;
41
- background-color: rgba(#808080, 0.15) !important;
71
+ background-color: rgb(250, 250, 250) !important;
72
+ box-shadow: none !important;
42
73
  padding: 12px;
74
+ margin: 10px 0 15px 0;
43
75
  }
44
76
 
45
77
  .summaryIcon {
@@ -69,3 +101,14 @@
69
101
  .elapsedTime {
70
102
  margin-left: 24px;
71
103
  }
104
+
105
+ .snapshotOverflow {
106
+ width: 100%;
107
+ word-wrap: break-word;
108
+ white-space: initial;
109
+ }
110
+
111
+ .pageTitle {
112
+ margin-top: 8px;
113
+ line-height: 26px;
114
+ }
@@ -1,5 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  export declare type FormValues = {
3
+ branch: string;
3
4
  cloneId: string;
4
5
  snapshotId: string;
5
6
  dbUser: string;
@@ -10,6 +10,7 @@ const Schema = Yup.object().shape({
10
10
  export const useForm = (onSubmit) => {
11
11
  const formik = useFormik({
12
12
  initialValues: {
13
+ branch: '',
13
14
  cloneId: '',
14
15
  snapshotId: '',
15
16
  dbUser: '',
@@ -0,0 +1,3 @@
1
+ import { FormValues } from '@postgres.ai/shared/pages/CreateClone/useForm';
2
+ export declare const getCliCreateCloneCommand: (values: FormValues) => string;
3
+ export declare const getCliCloneStatus: (cloneId: string) => string;
@@ -0,0 +1,17 @@
1
+ export const getCliCreateCloneCommand = (values) => {
2
+ const { dbUser, dbPassword, branch, isProtected, cloneId } = values;
3
+ return `dblab clone create \
4
+
5
+ --username ${dbUser ? dbUser : `<USERNAME>`} \
6
+
7
+ --password ${dbPassword ? dbPassword.replace(/./g, '*') : `<PASSWORD>`} \
8
+
9
+ ${branch ? `--branch ${branch}` : ``} \
10
+
11
+ ${isProtected ? `--protected` : ''} \
12
+
13
+ --id ${cloneId ? cloneId : `<CLONE_ID>`} \ `;
14
+ };
15
+ export const getCliCloneStatus = (cloneId) => {
16
+ return `dblab clone status ${cloneId ? cloneId : `<CLONE_ID>`}`;
17
+ };
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { MainStoreApi } from './stores/Main';
3
+ interface CreateSnapshotProps {
4
+ instanceId: string;
5
+ api: MainStoreApi;
6
+ routes: {
7
+ snapshot: (snapshotId: string) => string;
8
+ };
9
+ elements: {
10
+ breadcrumbs: React.ReactNode;
11
+ };
12
+ isPlatform?: boolean;
13
+ }
14
+ export declare const CreateSnapshotPage: (({ instanceId, api, elements, routes, isPlatform }: CreateSnapshotProps) => JSX.Element) & {
15
+ displayName: string;
16
+ };
17
+ export {};