@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.
Files changed (202) hide show
  1. package/.gitlab-ci.yml +60 -0
  2. package/components/AlertSnackbar/index.tsx +23 -0
  3. package/components/AlertSnackbar/useAlertSnackbar.tsx +65 -0
  4. package/components/Button/index.tsx +79 -0
  5. package/components/Button2/index.tsx +43 -0
  6. package/components/Button2/styles.module.scss +82 -0
  7. package/components/DestroyCloneModal/index.tsx +56 -0
  8. package/components/DestroyCloneRestrictionModal/index.tsx +50 -0
  9. package/components/ErrorStub/index.tsx +83 -0
  10. package/components/FormattedText/index.tsx +44 -0
  11. package/components/FormattedText/styles.module.scss +34 -0
  12. package/components/GatewayLink/index.tsx +33 -0
  13. package/components/HorizontalScrollContainer/index.tsx +131 -0
  14. package/components/HorizontalScrollContainer/types.ts +12 -0
  15. package/components/HorizontalScrollContainer/utils.ts +16 -0
  16. package/components/ImportantText/index.tsx +29 -0
  17. package/components/Link2/index.tsx +31 -0
  18. package/components/Link2/styles.module.scss +12 -0
  19. package/components/MenuButton/index.tsx +80 -0
  20. package/components/MenuButton/styles.module.scss +42 -0
  21. package/components/Modal/index.tsx +93 -0
  22. package/components/PageSpinner/index.tsx +18 -0
  23. package/components/PageSpinner/styles.module.scss +13 -0
  24. package/components/ResetCloneModal/index.tsx +154 -0
  25. package/components/SectionTitle/index.tsx +74 -0
  26. package/components/Select/index.tsx +42 -0
  27. package/components/SimpleModalControls/index.tsx +56 -0
  28. package/components/Spinner/icon.tsx +29 -0
  29. package/components/Spinner/index.tsx +16 -0
  30. package/components/Spinner/styles.module.scss +33 -0
  31. package/components/Status/index.tsx +61 -0
  32. package/components/Status/styles.module.scss +45 -0
  33. package/components/StubContainer/index.tsx +41 -0
  34. package/components/StubSpinner/index.tsx +49 -0
  35. package/components/StubSpinnerFlex/index.tsx +20 -0
  36. package/components/StubSpinnerFlex/styles.module.scss +20 -0
  37. package/components/SyntaxHighlight/index.tsx +107 -0
  38. package/components/Table/RowMenu/index.tsx +111 -0
  39. package/components/Table/index.tsx +140 -0
  40. package/components/Text/index.tsx +28 -0
  41. package/components/TextField/index.tsx +117 -0
  42. package/components/Tooltip/index.tsx +52 -0
  43. package/config/index.ts +32 -0
  44. package/config/links.ts +6 -0
  45. package/craco.config.js +80 -0
  46. package/helpers/getEntropy.ts +232 -0
  47. package/helpers/localStorage.ts +15 -0
  48. package/helpers/request.ts +47 -0
  49. package/hooks/useWindowDimensions.ts +16 -0
  50. package/icons/ArrowDropDown/index.tsx +29 -0
  51. package/icons/Circle/index.tsx +27 -0
  52. package/icons/External/index.tsx +14 -0
  53. package/icons/Info/index.tsx +12 -0
  54. package/icons/Renewable/index.tsx +65 -0
  55. package/icons/Shield/index.tsx +33 -0
  56. package/icons/Warning/index.tsx +29 -0
  57. package/meta.json +1 -0
  58. package/package.json +55 -0
  59. package/pages/Clone/Status/index.tsx +73 -0
  60. package/pages/Clone/context.ts +22 -0
  61. package/pages/Clone/index.tsx +634 -0
  62. package/pages/Clone/stores/Main.ts +206 -0
  63. package/pages/Clone/useCreatedStores.ts +11 -0
  64. package/pages/Configuration/Header/index.tsx +84 -0
  65. package/pages/Configuration/InputWithTooltip/index.tsx +240 -0
  66. package/pages/Configuration/ResponseMessage/index.tsx +71 -0
  67. package/pages/Configuration/configOptions.ts +60 -0
  68. package/pages/Configuration/index.tsx +1184 -0
  69. package/pages/Configuration/styles.module.scss +122 -0
  70. package/pages/Configuration/tooltipText.tsx +157 -0
  71. package/pages/Configuration/useForm.ts +108 -0
  72. package/pages/Configuration/utils/index.ts +153 -0
  73. package/pages/CreateClone/index.tsx +311 -0
  74. package/pages/CreateClone/stores/Main.ts +107 -0
  75. package/pages/CreateClone/styles.module.scss +71 -0
  76. package/pages/CreateClone/useCreatedStores.ts +11 -0
  77. package/pages/CreateClone/useForm.ts +36 -0
  78. package/pages/Instance/Clones/Header/Item/index.tsx +15 -0
  79. package/pages/Instance/Clones/Header/Item/styles.module.scss +17 -0
  80. package/pages/Instance/Clones/Header/index.tsx +74 -0
  81. package/pages/Instance/Clones/Header/styles.module.scss +11 -0
  82. package/pages/Instance/Clones/index.tsx +135 -0
  83. package/pages/Instance/ClonesModal/index.tsx +71 -0
  84. package/pages/Instance/ClonesModal/utils.ts +21 -0
  85. package/pages/Instance/InactiveInstance/index.tsx +165 -0
  86. package/pages/Instance/InactiveInstance/utils.ts +9 -0
  87. package/pages/Instance/Info/Connection/ConnectModal/Content/index.tsx +176 -0
  88. package/pages/Instance/Info/Connection/ConnectModal/Content/utils.ts +24 -0
  89. package/pages/Instance/Info/Connection/ConnectModal/index.tsx +36 -0
  90. package/pages/Instance/Info/Connection/index.tsx +81 -0
  91. package/pages/Instance/Info/Details/index.tsx +20 -0
  92. package/pages/Instance/Info/Disks/Disk/ActionsMenu/index.tsx +100 -0
  93. package/pages/Instance/Info/Disks/Disk/Marker/index.tsx +26 -0
  94. package/pages/Instance/Info/Disks/Disk/ProgressBar/PointerIcon.tsx +20 -0
  95. package/pages/Instance/Info/Disks/Disk/ProgressBar/index.tsx +73 -0
  96. package/pages/Instance/Info/Disks/Disk/Status/index.tsx +75 -0
  97. package/pages/Instance/Info/Disks/Disk/index.tsx +168 -0
  98. package/pages/Instance/Info/Disks/index.tsx +65 -0
  99. package/pages/Instance/Info/Icons/index.tsx +39 -0
  100. package/pages/Instance/Info/Retrieval/RefreshFailedAlert/index.tsx +32 -0
  101. package/pages/Instance/Info/Retrieval/RefreshFailedAlert/styles.module.scss +33 -0
  102. package/pages/Instance/Info/Retrieval/RetrievalModal/index.tsx +49 -0
  103. package/pages/Instance/Info/Retrieval/RetrievalModal/styles.module.scss +6 -0
  104. package/pages/Instance/Info/Retrieval/RetrievalTable/index.tsx +53 -0
  105. package/pages/Instance/Info/Retrieval/RetrievalTable/styles.module.scss +29 -0
  106. package/pages/Instance/Info/Retrieval/index.tsx +95 -0
  107. package/pages/Instance/Info/Retrieval/utils.ts +10 -0
  108. package/pages/Instance/Info/Snapshots/Calendar/Day/index.tsx +125 -0
  109. package/pages/Instance/Info/Snapshots/Calendar/index.tsx +133 -0
  110. package/pages/Instance/Info/Snapshots/Calendar/utils.ts +74 -0
  111. package/pages/Instance/Info/Snapshots/TimeLine/Day/index.tsx +79 -0
  112. package/pages/Instance/Info/Snapshots/TimeLine/index.tsx +57 -0
  113. package/pages/Instance/Info/Snapshots/index.tsx +97 -0
  114. package/pages/Instance/Info/Snapshots/utils.ts +18 -0
  115. package/pages/Instance/Info/Status/InstanceResponseModal/index.tsx +32 -0
  116. package/pages/Instance/Info/Status/InstanceResponseModal/styles.module.scss +3 -0
  117. package/pages/Instance/Info/Status/index.tsx +85 -0
  118. package/pages/Instance/Info/Status/styles.module.scss +12 -0
  119. package/pages/Instance/Info/Status/utils.ts +24 -0
  120. package/pages/Instance/Info/components/Property/index.tsx +32 -0
  121. package/pages/Instance/Info/components/Property/styles.module.scss +21 -0
  122. package/pages/Instance/Info/components/Section/index.tsx +50 -0
  123. package/pages/Instance/Info/components/ValueStatus/index.tsx +51 -0
  124. package/pages/Instance/Info/index.tsx +129 -0
  125. package/pages/Instance/SnapshotsModal/index.tsx +169 -0
  126. package/pages/Instance/SnapshotsModal/utils.ts +17 -0
  127. package/pages/Instance/Tabs/index.tsx +98 -0
  128. package/pages/Instance/components/ClonesList/ConnectionModal/index.tsx +196 -0
  129. package/pages/Instance/components/ClonesList/MenuCell/index.tsx +98 -0
  130. package/pages/Instance/components/ClonesList/MenuCell/utils.ts +21 -0
  131. package/pages/Instance/components/ClonesList/index.tsx +189 -0
  132. package/pages/Instance/components/ClonesList/styles.module.scss +32 -0
  133. package/pages/Instance/components/ErrorStub/index.tsx +77 -0
  134. package/pages/Instance/components/ModalReloadButton/index.tsx +43 -0
  135. package/pages/Instance/components/Tags/Tag/index.tsx +60 -0
  136. package/pages/Instance/components/Tags/index.tsx +42 -0
  137. package/pages/Instance/context.ts +39 -0
  138. package/pages/Instance/index.tsx +235 -0
  139. package/pages/Instance/stores/ClonesModal.ts +35 -0
  140. package/pages/Instance/stores/Main.ts +335 -0
  141. package/pages/Instance/stores/SnapshotsModal.ts +35 -0
  142. package/pages/Instance/styles.scss +40 -0
  143. package/pages/Instance/useCreatedStores.ts +14 -0
  144. package/pages/Logs/Icons/PlusIcon.tsx +8 -0
  145. package/pages/Logs/constants/index.ts +7 -0
  146. package/pages/Logs/hooks/useWsScroll.tsx +44 -0
  147. package/pages/Logs/index.tsx +267 -0
  148. package/pages/Logs/utils/index.ts +20 -0
  149. package/pages/Logs/wsLogs.ts +110 -0
  150. package/pages/Logs/wsSnackbar.ts +27 -0
  151. package/postgres.ai-shared-3.5.0.tgz +0 -0
  152. package/react-app-env.d.ts +71 -0
  153. package/scripts/copy-assets.js +30 -0
  154. package/scripts/pack.js +70 -0
  155. package/stores/Snapshots.ts +54 -0
  156. package/styles/colors.ts +67 -0
  157. package/styles/global.scss +29 -0
  158. package/styles/icons.tsx +1917 -0
  159. package/styles/mixins.scss +30 -0
  160. package/styles/styles.ts +87 -0
  161. package/styles/theme.ts +53 -0
  162. package/styles/vars.scss +43 -0
  163. package/styles/vars.ts +40 -0
  164. package/tsconfig.build.json +37 -0
  165. package/tsconfig.json +30 -0
  166. package/types/api/endpoints/createClone.ts +10 -0
  167. package/types/api/endpoints/destroyClone.ts +7 -0
  168. package/types/api/endpoints/getClone.ts +6 -0
  169. package/types/api/endpoints/getConfig.ts +6 -0
  170. package/types/api/endpoints/getEngine.ts +13 -0
  171. package/types/api/endpoints/getFullConfig.ts +4 -0
  172. package/types/api/endpoints/getInstance.ts +6 -0
  173. package/types/api/endpoints/getInstanceRetrieval.ts +6 -0
  174. package/types/api/endpoints/getSeImages.ts +22 -0
  175. package/types/api/endpoints/getSnapshots.ts +6 -0
  176. package/types/api/endpoints/getWSToken.ts +6 -0
  177. package/types/api/endpoints/initWS.ts +1 -0
  178. package/types/api/endpoints/refreshInstance.ts +4 -0
  179. package/types/api/endpoints/resetClone.ts +8 -0
  180. package/types/api/endpoints/testDbSource.ts +48 -0
  181. package/types/api/endpoints/updateClone.ts +10 -0
  182. package/types/api/endpoints/updateConfig.ts +6 -0
  183. package/types/api/entities/clone.ts +42 -0
  184. package/types/api/entities/config.ts +114 -0
  185. package/types/api/entities/dbSource.ts +13 -0
  186. package/types/api/entities/instance.ts +67 -0
  187. package/types/api/entities/instanceRetrieval.ts +46 -0
  188. package/types/api/entities/instanceState.ts +102 -0
  189. package/types/api/entities/pool.ts +27 -0
  190. package/types/api/entities/snapshot.ts +18 -0
  191. package/types/api/entities/wsToken.ts +7 -0
  192. package/types/byte-size/index.d.ts +22 -0
  193. package/utils/api.ts +30 -0
  194. package/utils/clone.ts +31 -0
  195. package/utils/connection.ts +38 -0
  196. package/utils/date.ts +87 -0
  197. package/utils/instance.ts +10 -0
  198. package/utils/numbers.ts +11 -0
  199. package/utils/react.ts +10 -0
  200. package/utils/snapshot.ts +4 -0
  201. package/utils/strings.ts +11 -0
  202. 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
+ &nbsp; (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,9 @@
1
+ import moment from 'moment'
2
+
3
+ export const formatTimestampUtc = (timestamp: moment.MomentInput) => {
4
+ if (!timestamp) {
5
+ return null
6
+ }
7
+
8
+ return moment(timestamp).utc().format('YYYY-MM-DD HH:mm:ss UTC')
9
+ }
@@ -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&nbsp;
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&nbsp;
169
+ <GatewayLink href="https://postgres.ai/docs/database-lab/cli-reference#getting-started">
170
+ the docs
171
+ </GatewayLink>
172
+ &nbsp;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
+ }