@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,235 @@
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 React, { useEffect } from 'react'
9
+ import { makeStyles } from '@material-ui/core'
10
+ import { observer } from 'mobx-react-lite'
11
+
12
+ import { Button } from '@postgres.ai/shared/components/Button2'
13
+ import { StubSpinner } from '@postgres.ai/shared/components/StubSpinner'
14
+ import { SectionTitle } from '@postgres.ai/shared/components/SectionTitle'
15
+ import { ErrorStub } from '@postgres.ai/shared/components/ErrorStub'
16
+
17
+ import { Tabs } from './Tabs'
18
+ import { Logs } from '../Logs'
19
+ import { Clones } from './Clones'
20
+ import { Info } from './Info'
21
+ import { Configuration } from '../Configuration'
22
+ import { ClonesModal } from './ClonesModal'
23
+ import { SnapshotsModal } from './SnapshotsModal'
24
+ import { InactiveInstance } from './InactiveInstance'
25
+ import { Host, HostProvider, StoresProvider } from './context'
26
+
27
+ import Typography from '@material-ui/core/Typography'
28
+ import Box from '@mui/material/Box'
29
+
30
+ import { useCreatedStores } from './useCreatedStores'
31
+
32
+ import './styles.scss'
33
+
34
+ type Props = Host
35
+
36
+ const useStyles = makeStyles(
37
+ (theme) => ({
38
+ title: {
39
+ marginTop: '8px',
40
+ },
41
+ reloadButton: {
42
+ flex: '0 0 auto',
43
+ alignSelf: 'flex-start',
44
+ },
45
+ errorStub: {
46
+ marginTop: '16px',
47
+ },
48
+ content: {
49
+ display: 'flex',
50
+ marginTop: '16px',
51
+ position: 'relative',
52
+ flex: '1 1 100%',
53
+ height: '100%',
54
+
55
+ [theme.breakpoints.down('sm')]: {
56
+ flexDirection: 'column',
57
+ },
58
+ },
59
+ }),
60
+ { index: 1 },
61
+ )
62
+
63
+ export const Instance = observer((props: Props) => {
64
+ const classes = useStyles()
65
+
66
+ const { instanceId, api } = props
67
+ const [activeTab, setActiveTab] = React.useState(0)
68
+ const [hasBeenRedirected, setHasBeenRedirected] = React.useState(false);
69
+
70
+ const stores = useCreatedStores(props)
71
+ const {
72
+ instance,
73
+ instanceError,
74
+ instanceRetrieval,
75
+ isLoadingInstance,
76
+ load,
77
+ reload,
78
+ } = stores.main
79
+
80
+ const switchTab = (_: React.ChangeEvent<{}> | null, tabID: number) => {
81
+ const contentElement = document.getElementById('content-container')
82
+ setActiveTab(tabID)
83
+
84
+ if (tabID === 0) {
85
+ load(props.instanceId)
86
+ }
87
+ contentElement?.scroll(0, 0)
88
+ }
89
+
90
+ const isInstanceIntegrated =
91
+ instanceRetrieval ||
92
+ (!isLoadingInstance && instance && instance?.url && !instanceError)
93
+
94
+ const isConfigurationActive = instanceRetrieval?.mode !== 'physical'
95
+
96
+ useEffect(() => {
97
+ load(instanceId)
98
+ }, [instanceId])
99
+
100
+ useEffect(() => {
101
+ if (props.setProjectAlias) props.setProjectAlias(instance?.projectAlias || '')
102
+ }, [instance])
103
+
104
+ useEffect(() => {
105
+ if (
106
+ instance &&
107
+ instance?.state?.retrieving?.status === 'pending' &&
108
+ isConfigurationActive &&
109
+ !props.isPlatform &&
110
+ !hasBeenRedirected
111
+ ) {
112
+ setActiveTab(2)
113
+ setHasBeenRedirected(true)
114
+ }
115
+ }, [instance, hasBeenRedirected])
116
+
117
+ return (
118
+ <HostProvider value={props}>
119
+ <StoresProvider value={stores}>
120
+ {props.elements.breadcrumbs}
121
+ <SectionTitle
122
+ text={props.title}
123
+ level={1}
124
+ tag="h1"
125
+ className={classes.title}
126
+ rightContent={
127
+ <Button
128
+ onClick={() => reload(props.instanceId)}
129
+ isDisabled={!instance && !instanceError}
130
+ className={classes.reloadButton}
131
+ >
132
+ Reload info
133
+ </Button>
134
+ }
135
+ >
136
+ {isInstanceIntegrated && (
137
+ <Tabs
138
+ isPlatform={props.isPlatform}
139
+ value={activeTab}
140
+ handleChange={switchTab}
141
+ hasLogs={api.initWS != undefined}
142
+ />
143
+ )}
144
+ </SectionTitle>
145
+
146
+ {instanceError && (
147
+ <ErrorStub {...instanceError} className={classes.errorStub} />
148
+ )}
149
+
150
+ {isInstanceIntegrated ? (
151
+ <>
152
+ <TabPanel value={activeTab} index={0}>
153
+ {!instanceError && (
154
+ <div className={classes.content}>
155
+ {!instance ||
156
+ (!instance?.state?.retrieving?.status && <StubSpinner />)}
157
+
158
+ {instance ? (
159
+ <>
160
+ <Clones />
161
+ <Info />
162
+ </>
163
+ ) : (
164
+ <StubSpinner />
165
+ )}
166
+ </div>
167
+ )}
168
+
169
+ <ClonesModal />
170
+
171
+ <SnapshotsModal />
172
+ </TabPanel>
173
+
174
+ {!props.isPlatform && (
175
+ <>
176
+ <TabPanel value={activeTab} index={1}>
177
+ {activeTab === 1 && <Logs api={api} />}
178
+ </TabPanel>
179
+
180
+ <TabPanel value={activeTab} index={2}>
181
+ <Configuration
182
+ isConfigurationActive={isConfigurationActive}
183
+ disableConfigModification={
184
+ instance?.state?.engine.disableConfigModification
185
+ }
186
+ switchActiveTab={switchTab}
187
+ reload={() => load(props.instanceId)}
188
+ />
189
+ </TabPanel>
190
+ </>
191
+ )}
192
+ </>
193
+ ) : !isLoadingInstance && !instanceError ? (
194
+ <TabPanel value={activeTab} index={activeTab}>
195
+ <InactiveInstance
196
+ instance={instance}
197
+ org={(props.elements.breadcrumbs as any)?.props.org}
198
+ />
199
+ </TabPanel>
200
+ ) : (
201
+ !instanceError && (
202
+ <TabPanel value={activeTab} index={0}>
203
+ <div className={classes.content}>
204
+ <StubSpinner />
205
+ </div>
206
+ </TabPanel>
207
+ )
208
+ )}
209
+ </StoresProvider>
210
+ </HostProvider>
211
+ )
212
+ })
213
+
214
+ function TabPanel(props: {
215
+ children?: React.ReactNode
216
+ index: number
217
+ value: number
218
+ }) {
219
+ const { children, value, index, ...other } = props
220
+
221
+ return (
222
+ <Typography
223
+ component="div"
224
+ role="tabpanel"
225
+ hidden={value !== index}
226
+ id={`scrollable-auto-tabpanel-${index}`}
227
+ aria-labelledby={`scrollable-auto-tab-${index}`}
228
+ {...other}
229
+ >
230
+ <Box p={3} sx={{ height: '100%' }}>
231
+ {children}
232
+ </Box>
233
+ </Typography>
234
+ )
235
+ }
@@ -0,0 +1,35 @@
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 { makeAutoObservable } from 'mobx'
9
+
10
+ type FilterOptions = {
11
+ pool?: string | null
12
+ snapshotId?: string
13
+ }
14
+
15
+ export class ClonesModalStore {
16
+ isOpenModal = false
17
+ pool: string | null = null
18
+ snapshotId: string | null = null
19
+
20
+ constructor() {
21
+ makeAutoObservable(this)
22
+ }
23
+
24
+ openModal = (filterOptions: FilterOptions | undefined = {}) => {
25
+ const { pool = null, snapshotId = null } = filterOptions
26
+
27
+ this.pool = pool
28
+ this.snapshotId = snapshotId
29
+ this.isOpenModal = true
30
+ }
31
+
32
+ closeModal = () => {
33
+ this.isOpenModal = false
34
+ }
35
+ }
@@ -0,0 +1,335 @@
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
+
9
+ import { GetSnapshots } from '@postgres.ai/shared/types/api/endpoints/getSnapshots'
10
+ import { GetInstance } from '@postgres.ai/shared/types/api/endpoints/getInstance'
11
+ import { Config } from '@postgres.ai/shared/types/api/entities/config'
12
+ import { GetConfig } from '@postgres.ai/shared/types/api/endpoints/getConfig'
13
+ import { UpdateConfig } from '@postgres.ai/shared/types/api/endpoints/updateConfig'
14
+ import { TestDbSource } from '@postgres.ai/shared/types/api/endpoints/testDbSource'
15
+ import { RefreshInstance } from '@postgres.ai/shared/types/api/endpoints/refreshInstance'
16
+ import { DestroyClone } from '@postgres.ai/shared/types/api/endpoints/destroyClone'
17
+ import { ResetClone } from '@postgres.ai/shared/types/api/endpoints/resetClone'
18
+ import { GetWSToken } from '@postgres.ai/shared/types/api/endpoints/getWSToken'
19
+ import { InitWS } from '@postgres.ai/shared/types/api/endpoints/initWS'
20
+ import { Instance } from '@postgres.ai/shared/types/api/entities/instance'
21
+ import { SnapshotsStore } from '@postgres.ai/shared/stores/Snapshots'
22
+ import { getTextFromUnknownApiError } from '@postgres.ai/shared/utils/api'
23
+ import { dbSource } from '@postgres.ai/shared/types/api/entities/dbSource'
24
+ import { GetFullConfig } from '@postgres.ai/shared/types/api/endpoints/getFullConfig'
25
+ import { GetInstanceRetrieval } from '@postgres.ai/shared/types/api/endpoints/getInstanceRetrieval'
26
+ import { InstanceRetrievalType } from '@postgres.ai/shared/types/api/entities/instanceRetrieval'
27
+ import { GetEngine } from '@postgres.ai/shared/types/api/endpoints/getEngine'
28
+ import { GetSeImages } from '@postgres.ai/shared/types/api/endpoints/getSeImages'
29
+
30
+ const UNSTABLE_CLONE_STATUS_CODES = ['CREATING', 'RESETTING', 'DELETING']
31
+
32
+ export type Api = {
33
+ getInstance: GetInstance
34
+ getSnapshots: GetSnapshots
35
+ refreshInstance?: RefreshInstance
36
+ destroyClone: DestroyClone
37
+ resetClone: ResetClone
38
+ getWSToken: GetWSToken
39
+ initWS?: InitWS
40
+ getConfig?: GetConfig
41
+ updateConfig?: UpdateConfig
42
+ testDbSource?: TestDbSource
43
+ getFullConfig?: GetFullConfig
44
+ getSeImages?: GetSeImages
45
+ getEngine?: GetEngine
46
+ getInstanceRetrieval?: GetInstanceRetrieval
47
+ }
48
+
49
+ type Error = {
50
+ title?: string
51
+ message?: string
52
+ }
53
+
54
+ export class MainStore {
55
+ instance: Instance | null = null
56
+ instanceRetrieval: InstanceRetrievalType | null = null
57
+ config: Config | null = null
58
+ fullConfig?: string
59
+ platformUrl?: string
60
+ instanceError: Error | null = null
61
+ configError: string | null = null
62
+ getFullConfigError: string | null = null
63
+ seImagesError: string | undefined | null = null
64
+
65
+ unstableClones = new Set<string>()
66
+
67
+ readonly snapshots: SnapshotsStore
68
+
69
+ isReloadingClones = false
70
+ isConfigurationLoading = false
71
+ isReloadingInstance = false
72
+ isReloadingInstanceRetrieval = false
73
+ isLoadingInstance = false
74
+
75
+ private readonly api: Api
76
+
77
+ constructor(api: Api) {
78
+ makeAutoObservable(this)
79
+
80
+ this.api = api
81
+ this.snapshots = new SnapshotsStore(api)
82
+ }
83
+
84
+ get isDisabledInstance() {
85
+ if (!this.instance) return true
86
+ return this.instance.state?.status.code === 'NO_RESPONSE'
87
+ }
88
+
89
+ load = (instanceId: string) => {
90
+ this.instance = null
91
+ this.isReloadingInstance = true
92
+ this.loadInstance(instanceId, false).then(() => {
93
+ if (this.instance?.createdAt && this.instance?.url || !this.instance?.createdAt) {
94
+ this.snapshots.load(instanceId)
95
+ }
96
+ })
97
+ this.loadInstanceRetrieval(instanceId).then(() => {
98
+ if (this.instanceRetrieval) {
99
+ this.getConfig()
100
+ this.getFullConfig()
101
+ }
102
+ })
103
+ }
104
+
105
+ reload = (instanceId: string) => {
106
+ this.instance = null
107
+ this.isReloadingInstance = true
108
+ this.loadInstance(instanceId, false).then(() => {
109
+ if (this.api.refreshInstance)
110
+ this.api.refreshInstance({ instanceId: instanceId })
111
+
112
+ if (this.instance?.createdAt && this.instance?.url || !this.instance?.createdAt) {
113
+ this.snapshots.load(instanceId)
114
+ }
115
+ })
116
+ this.loadInstanceRetrieval(instanceId).then(() => {
117
+ if (this.instanceRetrieval) {
118
+ this.getConfig()
119
+ this.getFullConfig()
120
+ }
121
+ })
122
+ }
123
+
124
+ reloadSnapshots = async () => {
125
+ if (!this.instance) return
126
+ await this.snapshots.reload(this.instance.id)
127
+ }
128
+
129
+ reloadInstanceRetrieval = async () => {
130
+ if (!this.instance) return
131
+ this.isReloadingInstanceRetrieval = true
132
+ this.loadInstanceRetrieval(this.instance.id)
133
+ this.isReloadingInstanceRetrieval = false
134
+ }
135
+
136
+ private loadInstanceRetrieval = async (instanceId: string) => {
137
+ if (!this.api.getInstanceRetrieval) return
138
+
139
+ const { response, error } = await this.api.getInstanceRetrieval({
140
+ instanceId: instanceId,
141
+ })
142
+
143
+ if (response) this.instanceRetrieval = response
144
+
145
+ if (error)
146
+ this.instanceError = { message: await getTextFromUnknownApiError(error) }
147
+
148
+ return !!response
149
+ }
150
+
151
+ private loadInstance = async (
152
+ instanceId: string,
153
+ refresh: boolean = true,
154
+ ) => {
155
+ this.instanceError = null
156
+ this.isLoadingInstance = true
157
+
158
+ if (this.api.refreshInstance && refresh)
159
+ await this.api.refreshInstance({ instanceId: instanceId })
160
+
161
+ const { response, error } = await this.api.getInstance({
162
+ instanceId: instanceId,
163
+ })
164
+
165
+ this.isLoadingInstance = false
166
+
167
+ if (response === null) {
168
+ this.instanceError = {
169
+ title: 'Error 404',
170
+ message: 'Specified instance not found or you have no access.',
171
+ }
172
+ }
173
+
174
+ if (response) {
175
+ this.instance = response
176
+
177
+ const unstableClones = new Set<string>()
178
+
179
+ this.instance.state?.cloning.clones?.forEach((clone) => {
180
+ if (UNSTABLE_CLONE_STATUS_CODES.includes(clone.status.code)) {
181
+ unstableClones.add(clone.id)
182
+ }
183
+ })
184
+
185
+ this.unstableClones = unstableClones
186
+ }
187
+
188
+ if (error)
189
+ this.instanceError = { message: await getTextFromUnknownApiError(error) }
190
+
191
+ return !!response
192
+ }
193
+
194
+ getConfig = async () => {
195
+ if (!this.api.getConfig) return
196
+
197
+ this.isConfigurationLoading = true
198
+
199
+ const { response, error } = await this.api.getConfig()
200
+
201
+ this.isConfigurationLoading = false
202
+
203
+ if (response) {
204
+ this.config = response
205
+ this.configError = null
206
+ }
207
+
208
+ if (error) {
209
+ this.configError = await error.json().then((err) => err.message)
210
+ }
211
+
212
+ return response
213
+ }
214
+
215
+ updateConfig = async (values: Config) => {
216
+ if (!this.api.updateConfig) return
217
+
218
+ const { response, error } = await this.api.updateConfig({ ...values })
219
+
220
+ if (error) this.configError = await error.json().then((err) => err.message)
221
+
222
+ return response
223
+ }
224
+
225
+ getFullConfig = async () => {
226
+ if (!this.api.getFullConfig) return
227
+
228
+ const { response, error } = await this.api.getFullConfig()
229
+ if (response) {
230
+ this.fullConfig = response
231
+
232
+ const splitYML = this.fullConfig.split('---')
233
+ this.platformUrl = splitYML[0]?.split('url: ')[1]?.split('\n')[0]
234
+ }
235
+
236
+ if (error)
237
+ this.getFullConfigError = await error
238
+ .json()
239
+ .then((err: Error) => err.message)
240
+
241
+ return response
242
+ }
243
+
244
+ getSeImages = async (values: { packageGroup: string }) => {
245
+ if (!this.api.getSeImages || !this.platformUrl) return
246
+
247
+ const { response, error } = await this.api.getSeImages({
248
+ packageGroup: values.packageGroup,
249
+ platformUrl: this.platformUrl,
250
+ })
251
+
252
+ if (response) {
253
+ this.seImagesError = null
254
+ }
255
+
256
+ if (error) {
257
+ this.seImagesError = await error.json().then((err: Error) => err.message)
258
+ }
259
+
260
+ return response
261
+ }
262
+
263
+ getEngine = async () => {
264
+ if (!this.api.getEngine) return
265
+
266
+ this.configError = null
267
+
268
+ const { response, error } = await this.api.getEngine()
269
+
270
+ if (error) await getTextFromUnknownApiError(error)
271
+ return response
272
+ }
273
+
274
+ testDbSource = async (values: dbSource) => {
275
+ if (!this.api.testDbSource) return
276
+
277
+ const { response, error } = await this.api.testDbSource(values)
278
+
279
+ return {
280
+ response,
281
+ error,
282
+ }
283
+ }
284
+
285
+ resetClone = async (cloneId: string, snapshotId: string) => {
286
+ if (!this.instance) return
287
+
288
+ this.unstableClones.add(cloneId)
289
+
290
+ const { response, error } = await this.api.resetClone({
291
+ cloneId,
292
+ snapshotId,
293
+ instanceId: this.instance.id,
294
+ })
295
+
296
+ if (response) this.liveUpdateInstance()
297
+ if (error) await getTextFromUnknownApiError(error)
298
+
299
+ return !!response
300
+ }
301
+
302
+ destroyClone = async (cloneId: string) => {
303
+ if (!this.instance) return
304
+
305
+ this.unstableClones.add(cloneId)
306
+
307
+ const { response, error } = await this.api.destroyClone({
308
+ cloneId,
309
+ instanceId: this.instance.id,
310
+ })
311
+
312
+ if (response) this.liveUpdateInstance()
313
+ if (error) await getTextFromUnknownApiError(error)
314
+
315
+ return !!response
316
+ }
317
+
318
+ private liveUpdateInstance = async () => {
319
+ if (!this.unstableClones.size) return
320
+ if (!this.instance) return
321
+
322
+ await this.loadInstance(this.instance.id)
323
+ await this.loadInstanceRetrieval(this.instance.id)
324
+
325
+ if (!this.unstableClones.size) return
326
+ }
327
+
328
+ reloadClones = async () => {
329
+ if (!this.instance) return
330
+ this.isReloadingClones = true
331
+ await this.loadInstance(this.instance.id)
332
+ await this.loadInstanceRetrieval(this.instance.id)
333
+ this.isReloadingClones = false
334
+ }
335
+ }
@@ -0,0 +1,35 @@
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 { makeAutoObservable } from 'mobx'
9
+
10
+ type FilterOptions = {
11
+ pool?: string | null
12
+ date?: Date
13
+ }
14
+
15
+ export class SnapshotsModalStore {
16
+ isOpenModal = false
17
+ pool: string | null = null
18
+ date: Date | null = null
19
+
20
+ constructor() {
21
+ makeAutoObservable(this)
22
+ }
23
+
24
+ openModal = (filterOptions: FilterOptions | undefined = {}) => {
25
+ const { pool = null, date = null } = filterOptions
26
+
27
+ this.pool = pool
28
+ this.date = date
29
+ this.isOpenModal = true
30
+ }
31
+
32
+ closeModal = () => {
33
+ this.isOpenModal = false
34
+ }
35
+ }
@@ -0,0 +1,40 @@
1
+ /*--------------------------------------------------------------------------
2
+ * Copyright (c) 2019-2022, 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
+ #logs-container {
9
+ margin: 20px 0 0 0;
10
+ border: 1px solid #b4b4b4;
11
+ border-radius: 4px;
12
+ overflow: hidden;
13
+ padding: 0.5rem 1rem;
14
+
15
+ & > p {
16
+ font-size: small;
17
+ font-family: 'Fira Code', monospace;
18
+ padding: 1px 0;
19
+ }
20
+ }
21
+
22
+ .error-log {
23
+ color: red;
24
+ }
25
+
26
+ .snackbar-tag {
27
+ position: fixed;
28
+ bottom: 0;
29
+ left: 50%;
30
+ transform: translate(-50%, -50%);
31
+ background-color: #fff2e5;
32
+ color: #000;
33
+ font-weight: 500;
34
+ font-size: 11px;
35
+ padding: 6px 8px;
36
+ border-radius: 4px;
37
+ transition: all 40050ms ease;
38
+ cursor: pointer;
39
+ z-index: 1;
40
+ }
@@ -0,0 +1,14 @@
1
+ import { useMemo } from 'react'
2
+
3
+ import { MainStore } from './stores/Main'
4
+ import { ClonesModalStore } from './stores/ClonesModal'
5
+ import { SnapshotsModalStore } from './stores/SnapshotsModal'
6
+ import { Host } from './context'
7
+
8
+ export const useCreatedStores = (host: Host) => ({
9
+ main: useMemo(() => new MainStore(host.api), []),
10
+ clonesModal: useMemo(() => new ClonesModalStore(), []),
11
+ snapshotsModal: useMemo(() => new SnapshotsModalStore(), []),
12
+ })
13
+
14
+ export type Stores = ReturnType<typeof useCreatedStores>
@@ -0,0 +1,8 @@
1
+ export const PlusIcon = () => (
2
+ <svg viewBox="0 0 512 512" focusable="false">
3
+ <path
4
+ fill="currentColor"
5
+ d="M289.94 256l95-95A24 24 0 00351 127l-95 95-95-95a24 24 0 00-34 34l95 95-95 95a24 24 0 1034 34l95-95 95 95a24 24 0 0034-34z"
6
+ ></path>
7
+ </svg>
8
+ )