@postgres.ai/shared 3.5.1-pr-1027.0
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/.gitlab-ci.yml +60 -0
- package/components/AlertSnackbar/index.tsx +23 -0
- package/components/AlertSnackbar/useAlertSnackbar.tsx +65 -0
- package/components/Button/index.tsx +79 -0
- package/components/Button2/index.tsx +43 -0
- package/components/Button2/styles.module.scss +82 -0
- package/components/DestroyCloneModal/index.tsx +56 -0
- package/components/DestroyCloneRestrictionModal/index.tsx +50 -0
- package/components/ErrorStub/index.tsx +83 -0
- package/components/FormattedText/index.tsx +44 -0
- package/components/FormattedText/styles.module.scss +34 -0
- package/components/GatewayLink/index.tsx +33 -0
- package/components/HorizontalScrollContainer/index.tsx +131 -0
- package/components/HorizontalScrollContainer/types.ts +12 -0
- package/components/HorizontalScrollContainer/utils.ts +16 -0
- package/components/ImportantText/index.tsx +29 -0
- package/components/Link2/index.tsx +31 -0
- package/components/Link2/styles.module.scss +12 -0
- package/components/MenuButton/index.tsx +80 -0
- package/components/MenuButton/styles.module.scss +42 -0
- package/components/Modal/index.tsx +93 -0
- package/components/PageSpinner/index.tsx +18 -0
- package/components/PageSpinner/styles.module.scss +13 -0
- package/components/ResetCloneModal/index.tsx +154 -0
- package/components/SectionTitle/index.tsx +74 -0
- package/components/Select/index.tsx +42 -0
- package/components/SimpleModalControls/index.tsx +56 -0
- package/components/Spinner/icon.tsx +29 -0
- package/components/Spinner/index.tsx +16 -0
- package/components/Spinner/styles.module.scss +33 -0
- package/components/Status/index.tsx +61 -0
- package/components/Status/styles.module.scss +45 -0
- package/components/StubContainer/index.tsx +41 -0
- package/components/StubSpinner/index.tsx +49 -0
- package/components/StubSpinnerFlex/index.tsx +20 -0
- package/components/StubSpinnerFlex/styles.module.scss +20 -0
- package/components/SyntaxHighlight/index.tsx +107 -0
- package/components/Table/RowMenu/index.tsx +111 -0
- package/components/Table/index.tsx +140 -0
- package/components/Text/index.tsx +28 -0
- package/components/TextField/index.tsx +117 -0
- package/components/Tooltip/index.tsx +52 -0
- package/config/index.ts +32 -0
- package/config/links.ts +6 -0
- package/craco.config.js +80 -0
- package/helpers/getEntropy.ts +232 -0
- package/helpers/localStorage.ts +15 -0
- package/helpers/request.ts +47 -0
- package/hooks/useWindowDimensions.ts +16 -0
- package/icons/ArrowDropDown/index.tsx +29 -0
- package/icons/Circle/index.tsx +27 -0
- package/icons/External/index.tsx +14 -0
- package/icons/Info/index.tsx +12 -0
- package/icons/Renewable/index.tsx +65 -0
- package/icons/Shield/index.tsx +33 -0
- package/icons/Warning/index.tsx +29 -0
- package/meta.json +1 -0
- package/package.json +55 -0
- package/pages/Clone/Status/index.tsx +73 -0
- package/pages/Clone/context.ts +22 -0
- package/pages/Clone/index.tsx +634 -0
- package/pages/Clone/stores/Main.ts +206 -0
- package/pages/Clone/useCreatedStores.ts +11 -0
- package/pages/Configuration/Header/index.tsx +84 -0
- package/pages/Configuration/InputWithTooltip/index.tsx +240 -0
- package/pages/Configuration/ResponseMessage/index.tsx +71 -0
- package/pages/Configuration/configOptions.ts +60 -0
- package/pages/Configuration/index.tsx +1184 -0
- package/pages/Configuration/styles.module.scss +122 -0
- package/pages/Configuration/tooltipText.tsx +157 -0
- package/pages/Configuration/useForm.ts +108 -0
- package/pages/Configuration/utils/index.ts +153 -0
- package/pages/CreateClone/index.tsx +311 -0
- package/pages/CreateClone/stores/Main.ts +107 -0
- package/pages/CreateClone/styles.module.scss +71 -0
- package/pages/CreateClone/useCreatedStores.ts +11 -0
- package/pages/CreateClone/useForm.ts +36 -0
- package/pages/Instance/Clones/Header/Item/index.tsx +15 -0
- package/pages/Instance/Clones/Header/Item/styles.module.scss +17 -0
- package/pages/Instance/Clones/Header/index.tsx +74 -0
- package/pages/Instance/Clones/Header/styles.module.scss +11 -0
- package/pages/Instance/Clones/index.tsx +135 -0
- package/pages/Instance/ClonesModal/index.tsx +71 -0
- package/pages/Instance/ClonesModal/utils.ts +21 -0
- package/pages/Instance/InactiveInstance/index.tsx +165 -0
- package/pages/Instance/InactiveInstance/utils.ts +9 -0
- package/pages/Instance/Info/Connection/ConnectModal/Content/index.tsx +176 -0
- package/pages/Instance/Info/Connection/ConnectModal/Content/utils.ts +24 -0
- package/pages/Instance/Info/Connection/ConnectModal/index.tsx +36 -0
- package/pages/Instance/Info/Connection/index.tsx +81 -0
- package/pages/Instance/Info/Details/index.tsx +20 -0
- package/pages/Instance/Info/Disks/Disk/ActionsMenu/index.tsx +100 -0
- package/pages/Instance/Info/Disks/Disk/Marker/index.tsx +26 -0
- package/pages/Instance/Info/Disks/Disk/ProgressBar/PointerIcon.tsx +20 -0
- package/pages/Instance/Info/Disks/Disk/ProgressBar/index.tsx +73 -0
- package/pages/Instance/Info/Disks/Disk/Status/index.tsx +75 -0
- package/pages/Instance/Info/Disks/Disk/index.tsx +168 -0
- package/pages/Instance/Info/Disks/index.tsx +65 -0
- package/pages/Instance/Info/Icons/index.tsx +39 -0
- package/pages/Instance/Info/Retrieval/RefreshFailedAlert/index.tsx +32 -0
- package/pages/Instance/Info/Retrieval/RefreshFailedAlert/styles.module.scss +33 -0
- package/pages/Instance/Info/Retrieval/RetrievalModal/index.tsx +49 -0
- package/pages/Instance/Info/Retrieval/RetrievalModal/styles.module.scss +6 -0
- package/pages/Instance/Info/Retrieval/RetrievalTable/index.tsx +53 -0
- package/pages/Instance/Info/Retrieval/RetrievalTable/styles.module.scss +29 -0
- package/pages/Instance/Info/Retrieval/index.tsx +95 -0
- package/pages/Instance/Info/Retrieval/utils.ts +10 -0
- package/pages/Instance/Info/Snapshots/Calendar/Day/index.tsx +125 -0
- package/pages/Instance/Info/Snapshots/Calendar/index.tsx +133 -0
- package/pages/Instance/Info/Snapshots/Calendar/utils.ts +74 -0
- package/pages/Instance/Info/Snapshots/TimeLine/Day/index.tsx +79 -0
- package/pages/Instance/Info/Snapshots/TimeLine/index.tsx +57 -0
- package/pages/Instance/Info/Snapshots/index.tsx +97 -0
- package/pages/Instance/Info/Snapshots/utils.ts +18 -0
- package/pages/Instance/Info/Status/InstanceResponseModal/index.tsx +32 -0
- package/pages/Instance/Info/Status/InstanceResponseModal/styles.module.scss +3 -0
- package/pages/Instance/Info/Status/index.tsx +85 -0
- package/pages/Instance/Info/Status/styles.module.scss +12 -0
- package/pages/Instance/Info/Status/utils.ts +24 -0
- package/pages/Instance/Info/components/Property/index.tsx +32 -0
- package/pages/Instance/Info/components/Property/styles.module.scss +21 -0
- package/pages/Instance/Info/components/Section/index.tsx +50 -0
- package/pages/Instance/Info/components/ValueStatus/index.tsx +51 -0
- package/pages/Instance/Info/index.tsx +129 -0
- package/pages/Instance/SnapshotsModal/index.tsx +169 -0
- package/pages/Instance/SnapshotsModal/utils.ts +17 -0
- package/pages/Instance/Tabs/index.tsx +98 -0
- package/pages/Instance/components/ClonesList/ConnectionModal/index.tsx +196 -0
- package/pages/Instance/components/ClonesList/MenuCell/index.tsx +98 -0
- package/pages/Instance/components/ClonesList/MenuCell/utils.ts +21 -0
- package/pages/Instance/components/ClonesList/index.tsx +189 -0
- package/pages/Instance/components/ClonesList/styles.module.scss +32 -0
- package/pages/Instance/components/ErrorStub/index.tsx +77 -0
- package/pages/Instance/components/ModalReloadButton/index.tsx +43 -0
- package/pages/Instance/components/Tags/Tag/index.tsx +60 -0
- package/pages/Instance/components/Tags/index.tsx +42 -0
- package/pages/Instance/context.ts +39 -0
- package/pages/Instance/index.tsx +235 -0
- package/pages/Instance/stores/ClonesModal.ts +35 -0
- package/pages/Instance/stores/Main.ts +335 -0
- package/pages/Instance/stores/SnapshotsModal.ts +35 -0
- package/pages/Instance/styles.scss +40 -0
- package/pages/Instance/useCreatedStores.ts +14 -0
- package/pages/Logs/Icons/PlusIcon.tsx +8 -0
- package/pages/Logs/constants/index.ts +7 -0
- package/pages/Logs/hooks/useWsScroll.tsx +44 -0
- package/pages/Logs/index.tsx +267 -0
- package/pages/Logs/utils/index.ts +20 -0
- package/pages/Logs/wsLogs.ts +110 -0
- package/pages/Logs/wsSnackbar.ts +27 -0
- package/postgres.ai-shared-3.5.0.tgz +0 -0
- package/react-app-env.d.ts +71 -0
- package/scripts/copy-assets.js +30 -0
- package/scripts/pack.js +70 -0
- package/stores/Snapshots.ts +54 -0
- package/styles/colors.ts +67 -0
- package/styles/global.scss +29 -0
- package/styles/icons.tsx +1917 -0
- package/styles/mixins.scss +30 -0
- package/styles/styles.ts +87 -0
- package/styles/theme.ts +53 -0
- package/styles/vars.scss +43 -0
- package/styles/vars.ts +40 -0
- package/tsconfig.build.json +37 -0
- package/tsconfig.json +30 -0
- package/types/api/endpoints/createClone.ts +10 -0
- package/types/api/endpoints/destroyClone.ts +7 -0
- package/types/api/endpoints/getClone.ts +6 -0
- package/types/api/endpoints/getConfig.ts +6 -0
- package/types/api/endpoints/getEngine.ts +13 -0
- package/types/api/endpoints/getFullConfig.ts +4 -0
- package/types/api/endpoints/getInstance.ts +6 -0
- package/types/api/endpoints/getInstanceRetrieval.ts +6 -0
- package/types/api/endpoints/getSeImages.ts +22 -0
- package/types/api/endpoints/getSnapshots.ts +6 -0
- package/types/api/endpoints/getWSToken.ts +6 -0
- package/types/api/endpoints/initWS.ts +1 -0
- package/types/api/endpoints/refreshInstance.ts +4 -0
- package/types/api/endpoints/resetClone.ts +8 -0
- package/types/api/endpoints/testDbSource.ts +48 -0
- package/types/api/endpoints/updateClone.ts +10 -0
- package/types/api/endpoints/updateConfig.ts +6 -0
- package/types/api/entities/clone.ts +42 -0
- package/types/api/entities/config.ts +114 -0
- package/types/api/entities/dbSource.ts +13 -0
- package/types/api/entities/instance.ts +67 -0
- package/types/api/entities/instanceRetrieval.ts +46 -0
- package/types/api/entities/instanceState.ts +102 -0
- package/types/api/entities/pool.ts +27 -0
- package/types/api/entities/snapshot.ts +18 -0
- package/types/api/entities/wsToken.ts +7 -0
- package/types/byte-size/index.d.ts +22 -0
- package/utils/api.ts +30 -0
- package/utils/clone.ts +31 -0
- package/utils/connection.ts +38 -0
- package/utils/date.ts +87 -0
- package/utils/instance.ts +10 -0
- package/utils/numbers.ts +11 -0
- package/utils/react.ts +10 -0
- package/utils/snapshot.ts +4 -0
- package/utils/strings.ts +11 -0
- package/utils/units.ts +23 -0
|
@@ -0,0 +1,135 @@
|
|
|
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
|
+
|
|
8
|
+
import { useState } from 'react'
|
|
9
|
+
import { makeStyles, Theme, useMediaQuery } from '@material-ui/core'
|
|
10
|
+
import { useHistory } from 'react-router-dom'
|
|
11
|
+
import { observer } from 'mobx-react-lite'
|
|
12
|
+
|
|
13
|
+
import { SectionTitle } from '@postgres.ai/shared/components/SectionTitle'
|
|
14
|
+
import { Button } from '@postgres.ai/shared/components/Button2'
|
|
15
|
+
import { round } from '@postgres.ai/shared/utils/numbers'
|
|
16
|
+
import { Tooltip } from '@postgres.ai/shared/components/Tooltip'
|
|
17
|
+
import { InfoIcon } from '@postgres.ai/shared/icons/Info'
|
|
18
|
+
|
|
19
|
+
import { useStores, useHost } from '@postgres.ai/shared/pages/Instance/context'
|
|
20
|
+
|
|
21
|
+
import { ClonesList } from '../components/ClonesList'
|
|
22
|
+
|
|
23
|
+
import { Header } from './Header'
|
|
24
|
+
|
|
25
|
+
const SHORT_LIST_SIZE = 3
|
|
26
|
+
|
|
27
|
+
const useStyles = makeStyles(
|
|
28
|
+
(theme) => ({
|
|
29
|
+
root: {
|
|
30
|
+
width: 0,
|
|
31
|
+
flex: '1 1 100%',
|
|
32
|
+
marginRight: '40px',
|
|
33
|
+
height: '100%',
|
|
34
|
+
|
|
35
|
+
[theme.breakpoints.down('sm')]: {
|
|
36
|
+
width: '100%',
|
|
37
|
+
marginRight: 0,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
tableTitle: {
|
|
41
|
+
marginTop: '5px',
|
|
42
|
+
},
|
|
43
|
+
listSizeButton: {
|
|
44
|
+
marginTop: '12px',
|
|
45
|
+
},
|
|
46
|
+
infoIcon: {
|
|
47
|
+
height: '12px',
|
|
48
|
+
width: '12px',
|
|
49
|
+
marginLeft: '8px',
|
|
50
|
+
color: '#808080',
|
|
51
|
+
},
|
|
52
|
+
}),
|
|
53
|
+
{ index: 1 },
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
export const Clones = observer(() => {
|
|
57
|
+
const classes = useStyles()
|
|
58
|
+
const history = useHistory()
|
|
59
|
+
const isMobile = useMediaQuery<Theme>((theme) => theme.breakpoints.down('sm'))
|
|
60
|
+
const [isShortListForMobile, setIsShortListForMobile] = useState(true)
|
|
61
|
+
|
|
62
|
+
const stores = useStores()
|
|
63
|
+
const host = useHost()
|
|
64
|
+
|
|
65
|
+
const { instance } = stores.main
|
|
66
|
+
if (!instance || !instance.state) return null
|
|
67
|
+
|
|
68
|
+
const isShortList = isMobile && isShortListForMobile
|
|
69
|
+
const toggleListSize = () => setIsShortListForMobile(!isShortListForMobile)
|
|
70
|
+
|
|
71
|
+
const goToCloneAddPage = () => history.push(host.routes.createClone())
|
|
72
|
+
|
|
73
|
+
const showListSizeButton =
|
|
74
|
+
instance.state?.cloning.clones?.length > SHORT_LIST_SIZE && isMobile
|
|
75
|
+
|
|
76
|
+
const isLoadingSnapshots = stores.main.snapshots.isLoading
|
|
77
|
+
const hasSnapshots = Boolean(stores.main.snapshots.data?.length)
|
|
78
|
+
const canCreateClone = hasSnapshots && !stores.main.isDisabledInstance
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<div className={classes.root}>
|
|
82
|
+
<SectionTitle level={2} tag="h2" text="Cloning summary" />
|
|
83
|
+
|
|
84
|
+
<Header
|
|
85
|
+
expectedCloningTimeS={round(
|
|
86
|
+
instance.state.cloning.expectedCloningTime,
|
|
87
|
+
2,
|
|
88
|
+
)}
|
|
89
|
+
logicalSize={instance.state.dataSize}
|
|
90
|
+
clonesCount={instance.state.cloning.clones.length}
|
|
91
|
+
/>
|
|
92
|
+
|
|
93
|
+
<SectionTitle
|
|
94
|
+
className={classes.tableTitle}
|
|
95
|
+
level={2}
|
|
96
|
+
tag="h3"
|
|
97
|
+
text={`Clones (${instance.state.cloning.clones.length})`}
|
|
98
|
+
rightContent={
|
|
99
|
+
<>
|
|
100
|
+
<Button
|
|
101
|
+
theme="primary"
|
|
102
|
+
onClick={goToCloneAddPage}
|
|
103
|
+
isDisabled={!canCreateClone}
|
|
104
|
+
isLoading={isLoadingSnapshots}
|
|
105
|
+
>
|
|
106
|
+
Create clone
|
|
107
|
+
</Button>
|
|
108
|
+
|
|
109
|
+
{!hasSnapshots && (
|
|
110
|
+
<Tooltip content="No snapshots">
|
|
111
|
+
<InfoIcon className={classes.infoIcon} />
|
|
112
|
+
</Tooltip>
|
|
113
|
+
)}
|
|
114
|
+
</>
|
|
115
|
+
}
|
|
116
|
+
/>
|
|
117
|
+
|
|
118
|
+
<ClonesList
|
|
119
|
+
clones={
|
|
120
|
+
isShortList
|
|
121
|
+
? instance.state.cloning.clones.slice(0, SHORT_LIST_SIZE)
|
|
122
|
+
: instance.state.cloning.clones
|
|
123
|
+
}
|
|
124
|
+
isDisabled={stores.main.isDisabledInstance}
|
|
125
|
+
emptyStubText="This instance has no active clones"
|
|
126
|
+
/>
|
|
127
|
+
|
|
128
|
+
{showListSizeButton && (
|
|
129
|
+
<Button className={classes.listSizeButton} onClick={toggleListSize}>
|
|
130
|
+
{isShortList ? 'Show more' : 'Show less'}
|
|
131
|
+
</Button>
|
|
132
|
+
)}
|
|
133
|
+
</div>
|
|
134
|
+
)
|
|
135
|
+
})
|
|
@@ -0,0 +1,71 @@
|
|
|
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
|
+
|
|
8
|
+
import { makeStyles } from '@material-ui/core'
|
|
9
|
+
import { observer } from 'mobx-react-lite'
|
|
10
|
+
|
|
11
|
+
import { useStores } from '@postgres.ai/shared/pages/Instance/context'
|
|
12
|
+
import { Modal } from '@postgres.ai/shared/components/Modal'
|
|
13
|
+
import { ClonesList } from '@postgres.ai/shared/pages/Instance/components/ClonesList'
|
|
14
|
+
import { Tags } from '@postgres.ai/shared/pages/Instance/components/Tags'
|
|
15
|
+
import { ModalReloadButton } from '@postgres.ai/shared/pages/Instance/components/ModalReloadButton'
|
|
16
|
+
|
|
17
|
+
import { getTags } from './utils'
|
|
18
|
+
|
|
19
|
+
const useStyles = makeStyles(
|
|
20
|
+
{
|
|
21
|
+
root: {
|
|
22
|
+
marginTop: 0,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
{ index: 1 },
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
export const ClonesModal = observer(() => {
|
|
29
|
+
const classes = useStyles()
|
|
30
|
+
const stores = useStores()
|
|
31
|
+
|
|
32
|
+
const { instance } = stores.main
|
|
33
|
+
if (!instance) return null
|
|
34
|
+
|
|
35
|
+
const { pool, snapshotId, isOpenModal, closeModal } = stores.clonesModal
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Modal
|
|
39
|
+
title={`Clones (${instance.state?.cloning.clones.length})`}
|
|
40
|
+
isOpen={isOpenModal}
|
|
41
|
+
onClose={closeModal}
|
|
42
|
+
size="md"
|
|
43
|
+
titleRightContent={
|
|
44
|
+
<ModalReloadButton
|
|
45
|
+
isReloading={stores.main.isReloadingClones}
|
|
46
|
+
onReload={stores.main.reloadClones}
|
|
47
|
+
/>
|
|
48
|
+
}
|
|
49
|
+
headerContent={
|
|
50
|
+
<Tags
|
|
51
|
+
data={getTags({
|
|
52
|
+
pool,
|
|
53
|
+
snapshotId,
|
|
54
|
+
})}
|
|
55
|
+
/>
|
|
56
|
+
}
|
|
57
|
+
classes={{ content: classes.root }}
|
|
58
|
+
>
|
|
59
|
+
<ClonesList
|
|
60
|
+
isDisabled={false}
|
|
61
|
+
clones={instance.state?.cloning.clones.filter((clone) => {
|
|
62
|
+
const isMatchedByPool = !pool || pool === clone.snapshot?.pool
|
|
63
|
+
const isMatchedBySnapshot =
|
|
64
|
+
!snapshotId || snapshotId === clone.snapshot?.id
|
|
65
|
+
return isMatchedByPool && isMatchedBySnapshot
|
|
66
|
+
})}
|
|
67
|
+
emptyStubText="No clones found"
|
|
68
|
+
/>
|
|
69
|
+
</Modal>
|
|
70
|
+
)
|
|
71
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
|
|
8
|
+
export const getTags = ({
|
|
9
|
+
pool,
|
|
10
|
+
snapshotId,
|
|
11
|
+
}: {
|
|
12
|
+
pool: string | null
|
|
13
|
+
snapshotId: string | null
|
|
14
|
+
}) => {
|
|
15
|
+
const tags = []
|
|
16
|
+
|
|
17
|
+
if (pool) tags.push({ name: 'Disk', value: pool })
|
|
18
|
+
if (snapshotId) tags.push({ name: 'Snapshot', value: snapshotId })
|
|
19
|
+
|
|
20
|
+
return tags
|
|
21
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { Tooltip } from '@material-ui/core'
|
|
2
|
+
import { makeStyles } from '@material-ui/core'
|
|
3
|
+
import { formatDistanceToNowStrict } from 'date-fns'
|
|
4
|
+
|
|
5
|
+
import { Link } from '@postgres.ai/shared/components/Link2'
|
|
6
|
+
import { Instance } from '@postgres.ai/shared/types/api/entities/instance'
|
|
7
|
+
|
|
8
|
+
import { formatTimestampUtc } from './utils'
|
|
9
|
+
|
|
10
|
+
const useStyles = makeStyles(
|
|
11
|
+
{
|
|
12
|
+
container: {
|
|
13
|
+
maxWidth: '650px',
|
|
14
|
+
width: '100%',
|
|
15
|
+
},
|
|
16
|
+
timeLabel: {
|
|
17
|
+
lineHeight: '16px',
|
|
18
|
+
fontSize: 14,
|
|
19
|
+
cursor: 'pointer',
|
|
20
|
+
flex: '2 1 0',
|
|
21
|
+
|
|
22
|
+
'& span': {
|
|
23
|
+
fontWeight: 'normal !important',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
toolTip: {
|
|
27
|
+
fontSize: '10px !important',
|
|
28
|
+
maxWidth: '100%',
|
|
29
|
+
},
|
|
30
|
+
content: {
|
|
31
|
+
margin: '25px 0',
|
|
32
|
+
},
|
|
33
|
+
flexContainer: {
|
|
34
|
+
display: 'flex',
|
|
35
|
+
alignItems: 'center',
|
|
36
|
+
flexDirection: 'row',
|
|
37
|
+
padding: '10px 0',
|
|
38
|
+
borderBottom: '1px solid rgba(224, 224, 224, 1)',
|
|
39
|
+
|
|
40
|
+
'& span:first-child': {
|
|
41
|
+
flex: '1 1 0',
|
|
42
|
+
fontWeight: '500',
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
'& span': {
|
|
46
|
+
flex: '2 1 0',
|
|
47
|
+
margin: '0',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{ index: 1 },
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
export const InactiveInstance = ({
|
|
55
|
+
org,
|
|
56
|
+
instance,
|
|
57
|
+
}: {
|
|
58
|
+
org: string
|
|
59
|
+
instance: Instance | null
|
|
60
|
+
}) => {
|
|
61
|
+
const classes = useStyles()
|
|
62
|
+
|
|
63
|
+
const getVersionDigits = (str: string | undefined | null) => {
|
|
64
|
+
if (!str) {
|
|
65
|
+
return 'N/A'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const digits = str.match(/\d+/g)
|
|
69
|
+
|
|
70
|
+
if (digits && digits.length > 0) {
|
|
71
|
+
return `${digits[0]}.${digits[1]}.${digits[2]}`
|
|
72
|
+
}
|
|
73
|
+
return ''
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<div className={classes.container}>
|
|
78
|
+
<div className={classes.flexContainer}>
|
|
79
|
+
<span>Plan</span>
|
|
80
|
+
<span>{instance?.dto.plan || '---'}</span>
|
|
81
|
+
</div>
|
|
82
|
+
<div className={classes.flexContainer}>
|
|
83
|
+
<span>Version</span>
|
|
84
|
+
<span>
|
|
85
|
+
{getVersionDigits(
|
|
86
|
+
instance?.state && (instance?.state?.engine?.version as string),
|
|
87
|
+
)}
|
|
88
|
+
</span>
|
|
89
|
+
</div>
|
|
90
|
+
<div className={classes.flexContainer}>
|
|
91
|
+
<span>Registered</span>
|
|
92
|
+
<span className={classes.timeLabel}>
|
|
93
|
+
<Tooltip
|
|
94
|
+
title={formatTimestampUtc(instance?.createdAt) ?? ''}
|
|
95
|
+
classes={{ tooltip: classes.toolTip }}
|
|
96
|
+
>
|
|
97
|
+
<span>
|
|
98
|
+
{instance?.createdAt &&
|
|
99
|
+
formatDistanceToNowStrict(new Date(instance?.createdAt), {
|
|
100
|
+
addSuffix: true,
|
|
101
|
+
})}
|
|
102
|
+
</span>
|
|
103
|
+
</Tooltip>
|
|
104
|
+
</span>
|
|
105
|
+
</div>
|
|
106
|
+
{instance?.telemetryLastReportedAt && (
|
|
107
|
+
<div className={classes.flexContainer}>
|
|
108
|
+
<span>Telemetry last reported</span>
|
|
109
|
+
<span className={classes.timeLabel}>
|
|
110
|
+
<Tooltip
|
|
111
|
+
title={
|
|
112
|
+
formatTimestampUtc(instance?.telemetryLastReportedAt) ?? ''
|
|
113
|
+
}
|
|
114
|
+
classes={{ tooltip: classes.toolTip }}
|
|
115
|
+
>
|
|
116
|
+
<span>
|
|
117
|
+
{formatDistanceToNowStrict(
|
|
118
|
+
new Date(instance?.telemetryLastReportedAt),
|
|
119
|
+
{
|
|
120
|
+
addSuffix: true,
|
|
121
|
+
},
|
|
122
|
+
)}
|
|
123
|
+
</span>
|
|
124
|
+
</Tooltip>
|
|
125
|
+
</span>
|
|
126
|
+
</div>
|
|
127
|
+
)}
|
|
128
|
+
<div className={classes.flexContainer}>
|
|
129
|
+
<span>Instance ID</span>
|
|
130
|
+
<span>
|
|
131
|
+
<span
|
|
132
|
+
style={{
|
|
133
|
+
fontWeight: 'normal',
|
|
134
|
+
}}
|
|
135
|
+
>
|
|
136
|
+
<Link to={`/${org}/instances/${instance?.id}`}>{instance?.id}</Link>
|
|
137
|
+
(self-assigned:{' '}
|
|
138
|
+
{instance?.dto?.selfassigned_instance_id || 'N/A'})
|
|
139
|
+
</span>
|
|
140
|
+
</span>
|
|
141
|
+
</div>
|
|
142
|
+
{instance?.dto.plan !== 'CE' && (
|
|
143
|
+
<div className={classes.flexContainer}>
|
|
144
|
+
<span>Billing data</span>
|
|
145
|
+
<span>
|
|
146
|
+
<Link to={`/${org}/billing`}>Billing data</Link>
|
|
147
|
+
</span>
|
|
148
|
+
</div>
|
|
149
|
+
)}
|
|
150
|
+
<p className={classes.content}>
|
|
151
|
+
To work with this instance, access its UI or API directly. Full
|
|
152
|
+
integration of UI to the Platform is currently available only to the EE
|
|
153
|
+
users. If you have any questions, reach out to{' '}
|
|
154
|
+
<a
|
|
155
|
+
href="https://postgres.ai/contact"
|
|
156
|
+
target="_blank"
|
|
157
|
+
rel="noopener noreferrer"
|
|
158
|
+
>
|
|
159
|
+
the Postgres.ai team
|
|
160
|
+
</a>
|
|
161
|
+
.
|
|
162
|
+
</p>
|
|
163
|
+
</div>
|
|
164
|
+
)
|
|
165
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
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
|
+
|
|
8
|
+
import { makeStyles, IconButton } from '@material-ui/core'
|
|
9
|
+
import { observer } from 'mobx-react-lite'
|
|
10
|
+
import copy from 'copy-to-clipboard'
|
|
11
|
+
|
|
12
|
+
import { GatewayLink } from '@postgres.ai/shared/components/GatewayLink'
|
|
13
|
+
import { icons } from '@postgres.ai/shared/styles/icons'
|
|
14
|
+
import { Link } from '@postgres.ai/shared/components/Link2'
|
|
15
|
+
import { TextField } from '@postgres.ai/shared/components/TextField'
|
|
16
|
+
import { Tooltip } from '@postgres.ai/shared/components/Tooltip'
|
|
17
|
+
import { useStores } from '@postgres.ai/shared/pages/Instance/context'
|
|
18
|
+
|
|
19
|
+
import { getCliInitCommand, getSshPortForwardingCommand } from './utils'
|
|
20
|
+
|
|
21
|
+
const useStyles = makeStyles(
|
|
22
|
+
{
|
|
23
|
+
root: {
|
|
24
|
+
fontSize: '14px',
|
|
25
|
+
},
|
|
26
|
+
list: {
|
|
27
|
+
listStyle: 'decimal inside none',
|
|
28
|
+
margin: 0,
|
|
29
|
+
padding: 0,
|
|
30
|
+
},
|
|
31
|
+
item: {
|
|
32
|
+
'& + $item': {
|
|
33
|
+
marginTop: '16px',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
textField: {
|
|
37
|
+
width: 'calc(100% - 24px)',
|
|
38
|
+
margin: '16px 0 0 0',
|
|
39
|
+
},
|
|
40
|
+
textFieldWrapper: {
|
|
41
|
+
display: 'flex',
|
|
42
|
+
alignItems: 'flex-end',
|
|
43
|
+
},
|
|
44
|
+
textFieldInfo: {
|
|
45
|
+
display: 'flex',
|
|
46
|
+
alignItems: 'center',
|
|
47
|
+
height: '32px',
|
|
48
|
+
marginLeft: '12px',
|
|
49
|
+
},
|
|
50
|
+
copyButton: {
|
|
51
|
+
width: '32px',
|
|
52
|
+
height: '32px',
|
|
53
|
+
padding: '8px',
|
|
54
|
+
},
|
|
55
|
+
note: {
|
|
56
|
+
margin: '24px 0 0 0',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{ index: 1 },
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
export const Content = observer(() => {
|
|
63
|
+
const classes = useStyles()
|
|
64
|
+
const stores = useStores()
|
|
65
|
+
|
|
66
|
+
const { instance } = stores.main
|
|
67
|
+
if (!instance) return null
|
|
68
|
+
|
|
69
|
+
const cliInitCommand = getCliInitCommand(instance)
|
|
70
|
+
const sshPortForwardingCommand = getSshPortForwardingCommand(instance)
|
|
71
|
+
const dblabStatusCommand = 'dblab instance status'
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<div className={classes.root}>
|
|
75
|
+
<ol className={classes.list}>
|
|
76
|
+
<li className={classes.item}>
|
|
77
|
+
Generate a personal token on
|
|
78
|
+
<Link
|
|
79
|
+
to={
|
|
80
|
+
// ROUTES.ORG.TOKENS.createPath({ org: context.org })
|
|
81
|
+
'/'
|
|
82
|
+
}
|
|
83
|
+
>
|
|
84
|
+
Access token page
|
|
85
|
+
</Link>
|
|
86
|
+
.
|
|
87
|
+
</li>
|
|
88
|
+
|
|
89
|
+
<li className={classes.item}>
|
|
90
|
+
Use personal token to initialize a connection to the Database Lab
|
|
91
|
+
instance:
|
|
92
|
+
<div className={classes.textFieldWrapper}>
|
|
93
|
+
<TextField
|
|
94
|
+
label="CLI init command"
|
|
95
|
+
value={cliInitCommand}
|
|
96
|
+
className={classes.textField}
|
|
97
|
+
InputProps={{
|
|
98
|
+
endAdornment: (
|
|
99
|
+
<IconButton
|
|
100
|
+
className={classes.copyButton}
|
|
101
|
+
onClick={() => copy(cliInitCommand)}
|
|
102
|
+
>
|
|
103
|
+
{icons.copyIcon}
|
|
104
|
+
</IconButton>
|
|
105
|
+
),
|
|
106
|
+
}}
|
|
107
|
+
/>
|
|
108
|
+
<Tooltip
|
|
109
|
+
content={
|
|
110
|
+
<>
|
|
111
|
+
Use this oneliner to initialize Database Lab CLI on your
|
|
112
|
+
machine.
|
|
113
|
+
<br />
|
|
114
|
+
All UPPERCASED variables (if any) are to be substituted
|
|
115
|
+
<br />
|
|
116
|
+
by real values.
|
|
117
|
+
</>
|
|
118
|
+
}
|
|
119
|
+
>
|
|
120
|
+
<span className={classes.textFieldInfo}>{icons.infoIcon}</span>
|
|
121
|
+
</Tooltip>
|
|
122
|
+
</div>
|
|
123
|
+
</li>
|
|
124
|
+
|
|
125
|
+
{sshPortForwardingCommand && (
|
|
126
|
+
<li className={classes.item}>
|
|
127
|
+
In a separate console, set up SSH port forwarding (and keep it
|
|
128
|
+
running):
|
|
129
|
+
<TextField
|
|
130
|
+
label="SSH port forwarding"
|
|
131
|
+
value={sshPortForwardingCommand}
|
|
132
|
+
className={classes.textField}
|
|
133
|
+
InputProps={{
|
|
134
|
+
endAdornment: (
|
|
135
|
+
<IconButton
|
|
136
|
+
className={classes.copyButton}
|
|
137
|
+
onClick={() => copy(sshPortForwardingCommand)}
|
|
138
|
+
>
|
|
139
|
+
{icons.copyIcon}
|
|
140
|
+
</IconButton>
|
|
141
|
+
),
|
|
142
|
+
}}
|
|
143
|
+
/>
|
|
144
|
+
</li>
|
|
145
|
+
)}
|
|
146
|
+
|
|
147
|
+
<li className={classes.item}>
|
|
148
|
+
Test it:
|
|
149
|
+
<TextField
|
|
150
|
+
label="CLI status command"
|
|
151
|
+
value={dblabStatusCommand}
|
|
152
|
+
className={classes.textField}
|
|
153
|
+
InputProps={{
|
|
154
|
+
endAdornment: (
|
|
155
|
+
<IconButton
|
|
156
|
+
className={classes.copyButton}
|
|
157
|
+
onClick={() => copy(dblabStatusCommand)}
|
|
158
|
+
>
|
|
159
|
+
{icons.copyIcon}
|
|
160
|
+
</IconButton>
|
|
161
|
+
),
|
|
162
|
+
}}
|
|
163
|
+
/>
|
|
164
|
+
</li>
|
|
165
|
+
</ol>
|
|
166
|
+
|
|
167
|
+
<p className={classes.note}>
|
|
168
|
+
Read
|
|
169
|
+
<GatewayLink href="https://postgres.ai/docs/database-lab/cli-reference#getting-started">
|
|
170
|
+
the docs
|
|
171
|
+
</GatewayLink>
|
|
172
|
+
to get started with CLI.
|
|
173
|
+
</p>
|
|
174
|
+
</div>
|
|
175
|
+
)
|
|
176
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
|
|
8
|
+
import { Instance } from '@postgres.ai/shared/types/api/entities/instance'
|
|
9
|
+
|
|
10
|
+
export const getCliInitCommand = (instance: Instance) =>
|
|
11
|
+
`dblab init --url ${instance.url} --token TOKEN --environment-id ${instance.projectName}`
|
|
12
|
+
|
|
13
|
+
export const getSshPortForwardingCommand = (instance: Instance) => {
|
|
14
|
+
if (instance.sshServerUrl) {
|
|
15
|
+
// Parse the URL to get the port
|
|
16
|
+
const url = new URL(instance.url as string)
|
|
17
|
+
const port = url.port || '2345'
|
|
18
|
+
// Here we hard-code the API port on the server (2345)- this is a requirement now
|
|
19
|
+
// for all DBLab instances working via tunnel, per decision made (NIkolayS 2024-05-22)
|
|
20
|
+
return `ssh -NTML ${port}:localhost:2345 ${instance.sshServerUrl} -i ~/.ssh/id_rsa`
|
|
21
|
+
} else {
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
|
|
8
|
+
import { useState } from 'react'
|
|
9
|
+
|
|
10
|
+
import { Button } from '@postgres.ai/shared/components/Button2'
|
|
11
|
+
import { Modal } from '@postgres.ai/shared/components/Modal'
|
|
12
|
+
|
|
13
|
+
import { Content } from './Content'
|
|
14
|
+
|
|
15
|
+
type Props = {
|
|
16
|
+
className?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const ConnectModal = (props: Props) => {
|
|
20
|
+
const [isOpen, setIsOpen] = useState(false)
|
|
21
|
+
|
|
22
|
+
const handleClickOpen = () => setIsOpen(true)
|
|
23
|
+
|
|
24
|
+
const handleClose = () => setIsOpen(false)
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<>
|
|
28
|
+
<Button onClick={handleClickOpen} className={props.className}>
|
|
29
|
+
Connect
|
|
30
|
+
</Button>
|
|
31
|
+
<Modal isOpen={isOpen} onClose={handleClose} title="Connection info">
|
|
32
|
+
<Content />
|
|
33
|
+
</Modal>
|
|
34
|
+
</>
|
|
35
|
+
)
|
|
36
|
+
}
|