@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,81 @@
|
|
|
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/styles'
|
|
9
|
+
import { observer } from 'mobx-react-lite'
|
|
10
|
+
|
|
11
|
+
import { useStores } from '@postgres.ai/shared/pages/Instance/context'
|
|
12
|
+
import { ShieldIcon } from '@postgres.ai/shared/icons/Shield'
|
|
13
|
+
import { WarningIcon } from '@postgres.ai/shared/icons/Warning'
|
|
14
|
+
|
|
15
|
+
import { Section } from '../components/Section'
|
|
16
|
+
import { Property } from '../components/Property'
|
|
17
|
+
import { ValueStatus } from '../components/ValueStatus'
|
|
18
|
+
|
|
19
|
+
import { ConnectModal } from './ConnectModal'
|
|
20
|
+
|
|
21
|
+
const useStyles = makeStyles(
|
|
22
|
+
{
|
|
23
|
+
connectButton: {
|
|
24
|
+
marginTop: '10px',
|
|
25
|
+
},
|
|
26
|
+
url: {
|
|
27
|
+
overflowWrap: 'break-word',
|
|
28
|
+
},
|
|
29
|
+
icon: {
|
|
30
|
+
top: 0,
|
|
31
|
+
left: 0,
|
|
32
|
+
position: 'absolute',
|
|
33
|
+
height: '100%',
|
|
34
|
+
width: '100%',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{ index: 1 },
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
const checkIsSecureUrl = (urlStr: string) => {
|
|
41
|
+
const url = new URL(urlStr)
|
|
42
|
+
return url.protocol === 'https:'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const Connection = observer(() => {
|
|
46
|
+
const stores = useStores()
|
|
47
|
+
const classes = useStyles()
|
|
48
|
+
|
|
49
|
+
const { instance } = stores.main
|
|
50
|
+
if (!instance?.url) return null
|
|
51
|
+
|
|
52
|
+
const isSecureUrl = checkIsSecureUrl(instance.url) || instance.useTunnel
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<Section title="Connection">
|
|
56
|
+
<Property name="URL">
|
|
57
|
+
<span className={classes.url}>{instance.url}</span>
|
|
58
|
+
<br />
|
|
59
|
+
<ValueStatus
|
|
60
|
+
type={isSecureUrl ? 'ok' : 'warning'}
|
|
61
|
+
icon={
|
|
62
|
+
isSecureUrl ? (
|
|
63
|
+
<ShieldIcon className={classes.icon} />
|
|
64
|
+
) : (
|
|
65
|
+
<WarningIcon className={classes.icon} />
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
>
|
|
69
|
+
The connection to Database Lab API is{' '}
|
|
70
|
+
{isSecureUrl ? 'secure' : 'not secure'}
|
|
71
|
+
</ValueStatus>
|
|
72
|
+
</Property>
|
|
73
|
+
|
|
74
|
+
<Property name="WS tunnels">
|
|
75
|
+
{instance.useTunnel ? 'used' : 'not used'}
|
|
76
|
+
</Property>
|
|
77
|
+
|
|
78
|
+
<ConnectModal className={classes.connectButton} />
|
|
79
|
+
</Section>
|
|
80
|
+
)
|
|
81
|
+
})
|
|
@@ -0,0 +1,20 @@
|
|
|
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 from 'react';
|
|
9
|
+
|
|
10
|
+
import { Section } from '../components/Section';
|
|
11
|
+
import { Property } from '../components/Property';
|
|
12
|
+
|
|
13
|
+
export const Details = () => {
|
|
14
|
+
return (
|
|
15
|
+
<Section title='Details'>
|
|
16
|
+
<Property name='Database docker image'>postgres:12</Property>
|
|
17
|
+
<Property name='Version'>0.4.4</Property>
|
|
18
|
+
</Section>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
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, { useState } from 'react'
|
|
9
|
+
import { IconButton, makeStyles, Menu, MenuItem } from '@material-ui/core'
|
|
10
|
+
import { MoreVert } from '@material-ui/icons'
|
|
11
|
+
import copy from 'copy-to-clipboard'
|
|
12
|
+
|
|
13
|
+
import { colors } from '@postgres.ai/shared/styles/colors'
|
|
14
|
+
import { useStores } from '@postgres.ai/shared/pages/Instance/context'
|
|
15
|
+
|
|
16
|
+
type Props = {
|
|
17
|
+
poolId: string | null
|
|
18
|
+
poolName: string
|
|
19
|
+
isActive: boolean
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const useStyles = makeStyles(
|
|
23
|
+
{
|
|
24
|
+
root: {
|
|
25
|
+
padding: '3px 1px',
|
|
26
|
+
border: `1px solid ${colors.consoleStroke}`,
|
|
27
|
+
borderRadius: '4px',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
{ index: 1 },
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
export const ActionsMenu = (props: Props) => {
|
|
34
|
+
const classes = useStyles()
|
|
35
|
+
const stores = useStores()
|
|
36
|
+
|
|
37
|
+
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null)
|
|
38
|
+
|
|
39
|
+
const isOpen = Boolean(anchorEl)
|
|
40
|
+
|
|
41
|
+
const openMenu = (e: React.MouseEvent<HTMLButtonElement>) => {
|
|
42
|
+
e.stopPropagation()
|
|
43
|
+
setAnchorEl(e.currentTarget)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const closeMenu = () => setAnchorEl(null)
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<>
|
|
50
|
+
<IconButton className={classes.root} onClick={openMenu}>
|
|
51
|
+
<MoreVert />
|
|
52
|
+
</IconButton>
|
|
53
|
+
|
|
54
|
+
<Menu
|
|
55
|
+
anchorOrigin={{
|
|
56
|
+
vertical: 'top',
|
|
57
|
+
horizontal: 'left',
|
|
58
|
+
}}
|
|
59
|
+
transformOrigin={{
|
|
60
|
+
vertical: 'top',
|
|
61
|
+
horizontal: 'left',
|
|
62
|
+
}}
|
|
63
|
+
anchorEl={anchorEl}
|
|
64
|
+
keepMounted
|
|
65
|
+
open={isOpen}
|
|
66
|
+
onClose={closeMenu}
|
|
67
|
+
onClick={(e) => e.stopPropagation()}
|
|
68
|
+
>
|
|
69
|
+
<MenuItem
|
|
70
|
+
onClick={() => {
|
|
71
|
+
closeMenu()
|
|
72
|
+
copy(props.poolName)
|
|
73
|
+
}}
|
|
74
|
+
>
|
|
75
|
+
Copy name
|
|
76
|
+
</MenuItem>
|
|
77
|
+
{props.isActive && (
|
|
78
|
+
<div>
|
|
79
|
+
<MenuItem
|
|
80
|
+
onClick={() => {
|
|
81
|
+
closeMenu()
|
|
82
|
+
stores.clonesModal.openModal({ pool: props.poolId })
|
|
83
|
+
}}
|
|
84
|
+
>
|
|
85
|
+
List clones
|
|
86
|
+
</MenuItem>
|
|
87
|
+
<MenuItem
|
|
88
|
+
onClick={() => {
|
|
89
|
+
closeMenu()
|
|
90
|
+
stores.snapshotsModal.openModal({ pool: props.poolId })
|
|
91
|
+
}}
|
|
92
|
+
>
|
|
93
|
+
List snapshots
|
|
94
|
+
</MenuItem>
|
|
95
|
+
</div>
|
|
96
|
+
)}
|
|
97
|
+
</Menu>
|
|
98
|
+
</>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { makeStyles } from '@material-ui/core'
|
|
3
|
+
import clsx from 'clsx'
|
|
4
|
+
|
|
5
|
+
import { CircleIcon } from '@postgres.ai/shared/icons/Circle'
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
className: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const useStyles = makeStyles(
|
|
12
|
+
{
|
|
13
|
+
root: {
|
|
14
|
+
display: 'inline',
|
|
15
|
+
verticalAlign: 'middle',
|
|
16
|
+
width: '10px',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
{ index: 1 },
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
export const Marker = (props: Props) => {
|
|
23
|
+
const classes = useStyles()
|
|
24
|
+
|
|
25
|
+
return <CircleIcon className={clsx(classes.root, props.className)} />
|
|
26
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const PoinerIcon = ({
|
|
2
|
+
className,
|
|
3
|
+
style,
|
|
4
|
+
}: {
|
|
5
|
+
className?: string
|
|
6
|
+
|
|
7
|
+
style?: React.CSSProperties
|
|
8
|
+
}) => (
|
|
9
|
+
<svg
|
|
10
|
+
width="5"
|
|
11
|
+
height="14"
|
|
12
|
+
viewBox="0 0 5 14"
|
|
13
|
+
fill="none"
|
|
14
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
15
|
+
style={style}
|
|
16
|
+
className={className}
|
|
17
|
+
>
|
|
18
|
+
<path d="M2.5 14L-2.06593e-07 -4.37114e-07L5 0L2.5 14Z" fill="#EE0202" />
|
|
19
|
+
</svg>
|
|
20
|
+
)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { makeStyles } from '@material-ui/core'
|
|
2
|
+
|
|
3
|
+
import { colors } from '@postgres.ai/shared/styles/colors'
|
|
4
|
+
import { Tooltip } from '@postgres.ai/shared/components/Tooltip'
|
|
5
|
+
|
|
6
|
+
import { PoinerIcon } from './PointerIcon'
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
value: number
|
|
10
|
+
total: number
|
|
11
|
+
thresholdPercent: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const useStyles = makeStyles(
|
|
15
|
+
(theme) => ({
|
|
16
|
+
'@keyframes grow': {
|
|
17
|
+
'0%': {
|
|
18
|
+
transform: 'scaleX(0)',
|
|
19
|
+
},
|
|
20
|
+
'100%': {
|
|
21
|
+
transform: 'scaleX(1)',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
root: {
|
|
25
|
+
height: '12px',
|
|
26
|
+
position: 'relative',
|
|
27
|
+
borderRadius: '4px',
|
|
28
|
+
background: colors.gray,
|
|
29
|
+
overflow: 'hidden',
|
|
30
|
+
marginTop: '8px',
|
|
31
|
+
},
|
|
32
|
+
indicator: {
|
|
33
|
+
position: 'absolute',
|
|
34
|
+
top: 0,
|
|
35
|
+
left: 0,
|
|
36
|
+
height: '100%',
|
|
37
|
+
width: '30%',
|
|
38
|
+
background: colors.primary.light,
|
|
39
|
+
animation: `$grow 500ms ${theme.transitions.easing.easeOut}`,
|
|
40
|
+
transformOrigin: 0,
|
|
41
|
+
},
|
|
42
|
+
pointer: {
|
|
43
|
+
position: 'absolute',
|
|
44
|
+
height: '100%',
|
|
45
|
+
top: 0,
|
|
46
|
+
transform: 'translateX(-50%)',
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
{ index: 1 },
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
export const ProgressBar = (props: Props) => {
|
|
53
|
+
const classes = useStyles()
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<div className={classes.root}>
|
|
57
|
+
<div
|
|
58
|
+
className={classes.indicator}
|
|
59
|
+
style={{ width: `${(props.value / props.total) * 100}%` }}
|
|
60
|
+
/>
|
|
61
|
+
<Tooltip
|
|
62
|
+
content={`+${props.thresholdPercent}% disk usage may result in performance degradation`}
|
|
63
|
+
>
|
|
64
|
+
<PoinerIcon
|
|
65
|
+
className={classes.pointer}
|
|
66
|
+
style={{
|
|
67
|
+
left: `${props.thresholdPercent}%`,
|
|
68
|
+
}}
|
|
69
|
+
/>
|
|
70
|
+
</Tooltip>
|
|
71
|
+
</div>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { makeStyles } from '@material-ui/core'
|
|
2
|
+
|
|
3
|
+
import { WarningIcon } from '@postgres.ai/shared/icons/Warning'
|
|
4
|
+
import { Tooltip } from '@postgres.ai/shared/components/Tooltip'
|
|
5
|
+
import { colors } from '@postgres.ai/shared/styles/colors'
|
|
6
|
+
|
|
7
|
+
export type Props = {
|
|
8
|
+
value: 'refreshing' | 'active' | 'empty'
|
|
9
|
+
hasWarning: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const VALUE_TO_NAME: Record<Props['value'], string> = {
|
|
13
|
+
refreshing: 'Data refreshing',
|
|
14
|
+
active: 'Active',
|
|
15
|
+
empty: 'Empty',
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const VALUE_TO_DESC: Record<Props['value'], string> = {
|
|
19
|
+
refreshing: 'Data retrieval is in progress',
|
|
20
|
+
active: 'Disk is ready to provision clones',
|
|
21
|
+
empty: 'Disk is emptied and ready for a data retrieval',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const useStyles = makeStyles(
|
|
25
|
+
{
|
|
26
|
+
root: {
|
|
27
|
+
display: 'flex',
|
|
28
|
+
color: colors.white,
|
|
29
|
+
},
|
|
30
|
+
warning: {
|
|
31
|
+
display: 'flex',
|
|
32
|
+
flex: '0 0 16px',
|
|
33
|
+
alignItems: 'center',
|
|
34
|
+
justifyContent: 'center',
|
|
35
|
+
marginRight: '4px',
|
|
36
|
+
height: '16px',
|
|
37
|
+
background: colors.state.warning,
|
|
38
|
+
borderRadius: '3px',
|
|
39
|
+
},
|
|
40
|
+
icon: {
|
|
41
|
+
height: '10px',
|
|
42
|
+
},
|
|
43
|
+
label: {
|
|
44
|
+
fontSize: '12px',
|
|
45
|
+
padding: '1px 6px',
|
|
46
|
+
borderRadius: '3px',
|
|
47
|
+
flex: '0 0 auto',
|
|
48
|
+
background: (props: Props) => {
|
|
49
|
+
if (props.value === 'refreshing') return colors.state.notice
|
|
50
|
+
if (props.value === 'active') return colors.state.ok
|
|
51
|
+
return colors.state.unknown
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{ index: 1 },
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
export const Status = (props: Props) => {
|
|
59
|
+
const { value, hasWarning } = props
|
|
60
|
+
|
|
61
|
+
const classes = useStyles(props)
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div className={classes.root}>
|
|
65
|
+
{hasWarning && (
|
|
66
|
+
<div className={classes.warning}>
|
|
67
|
+
<WarningIcon className={classes.icon} />
|
|
68
|
+
</div>
|
|
69
|
+
)}
|
|
70
|
+
<Tooltip content={VALUE_TO_DESC[value]}>
|
|
71
|
+
<div className={classes.label}>{VALUE_TO_NAME[value]}</div>
|
|
72
|
+
</Tooltip>
|
|
73
|
+
</div>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { makeStyles } from '@material-ui/core'
|
|
2
|
+
import { formatDistanceToNowStrict } from 'date-fns'
|
|
3
|
+
|
|
4
|
+
import { colors } from '@postgres.ai/shared/styles/colors'
|
|
5
|
+
import { formatBytesIEC } from '@postgres.ai/shared/utils/units'
|
|
6
|
+
import { Status as PerformanceStatus } from '@postgres.ai/shared/components/Status'
|
|
7
|
+
import { formatUTC } from '@postgres.ai/shared/utils/date'
|
|
8
|
+
|
|
9
|
+
import { Property } from '../../components/Property'
|
|
10
|
+
import { ActionsMenu } from './ActionsMenu'
|
|
11
|
+
import { Status } from './Status'
|
|
12
|
+
import { Marker } from './Marker'
|
|
13
|
+
import { ProgressBar } from './ProgressBar'
|
|
14
|
+
|
|
15
|
+
const WARNING_THRESHOLD_PERCENT = 80
|
|
16
|
+
|
|
17
|
+
type Props = {
|
|
18
|
+
id: string | null
|
|
19
|
+
name: string
|
|
20
|
+
totalDataSize: number
|
|
21
|
+
mode: string
|
|
22
|
+
refreshingStartDate: Date | null
|
|
23
|
+
clonesCount: number
|
|
24
|
+
snapshotsCount: number
|
|
25
|
+
usedDataSize: number
|
|
26
|
+
freeDataSize: number
|
|
27
|
+
status: 'refreshing' | 'active' | 'empty'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const useStyles = makeStyles(
|
|
31
|
+
{
|
|
32
|
+
root: {
|
|
33
|
+
border: `1px solid ${colors.consoleStroke}`,
|
|
34
|
+
padding: '6px 8px 8px',
|
|
35
|
+
borderRadius: '4px',
|
|
36
|
+
|
|
37
|
+
'& + $root': {
|
|
38
|
+
marginTop: '8px',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
header: {
|
|
42
|
+
display: 'flex',
|
|
43
|
+
justifyContent: 'space-between',
|
|
44
|
+
alignItems: 'center',
|
|
45
|
+
},
|
|
46
|
+
titleWrapper: {
|
|
47
|
+
display: 'flex',
|
|
48
|
+
flex: '1 1 auto',
|
|
49
|
+
alignItems: 'center',
|
|
50
|
+
marginRight: '16px',
|
|
51
|
+
minWidth: 0,
|
|
52
|
+
},
|
|
53
|
+
title: {
|
|
54
|
+
fontWeight: 700,
|
|
55
|
+
fontSize: '14px',
|
|
56
|
+
margin: '0 4px 0 0',
|
|
57
|
+
whiteSpace: 'nowrap',
|
|
58
|
+
textOverflow: 'ellipsis',
|
|
59
|
+
overflow: 'hidden',
|
|
60
|
+
},
|
|
61
|
+
content: {
|
|
62
|
+
marginTop: '8px',
|
|
63
|
+
},
|
|
64
|
+
markerUsed: {
|
|
65
|
+
color: colors.primary.light,
|
|
66
|
+
},
|
|
67
|
+
markerFree: {
|
|
68
|
+
color: colors.gray,
|
|
69
|
+
},
|
|
70
|
+
warningMessage: {
|
|
71
|
+
fontSize: '10px',
|
|
72
|
+
marginTop: '6px',
|
|
73
|
+
},
|
|
74
|
+
uppercaseContent: {
|
|
75
|
+
textTransform: 'uppercase',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{ index: 1 },
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
const getPercent = (value: number, total: number) =>
|
|
82
|
+
Math.round((value / total) * 100)
|
|
83
|
+
|
|
84
|
+
export const Disk = (props: Props) => {
|
|
85
|
+
const classes = useStyles()
|
|
86
|
+
|
|
87
|
+
const shouldShowWarning =
|
|
88
|
+
props.status === 'active' &&
|
|
89
|
+
getPercent(props.usedDataSize, props.totalDataSize) >
|
|
90
|
+
WARNING_THRESHOLD_PERCENT
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<div className={classes.root}>
|
|
94
|
+
<div className={classes.header}>
|
|
95
|
+
<div className={classes.titleWrapper}>
|
|
96
|
+
<h6 title={props.name} className={classes.title}>
|
|
97
|
+
{props.name}
|
|
98
|
+
</h6>
|
|
99
|
+
<ActionsMenu
|
|
100
|
+
poolId={props.id}
|
|
101
|
+
poolName={props.name}
|
|
102
|
+
isActive={props.status === 'active'}
|
|
103
|
+
/>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<Status value={props.status} hasWarning={shouldShowWarning} />
|
|
107
|
+
</div>
|
|
108
|
+
<Property name="Mode" classes={{ content: classes.uppercaseContent }}>
|
|
109
|
+
{props.mode}
|
|
110
|
+
</Property>
|
|
111
|
+
|
|
112
|
+
{props.status === 'refreshing' && props.refreshingStartDate && (
|
|
113
|
+
<div className={classes.content}>
|
|
114
|
+
<Property name="Refreshing started at">
|
|
115
|
+
{formatUTC(props.refreshingStartDate, 'yyyy-MM-dd HH:mm:ss')} UTC (
|
|
116
|
+
{formatDistanceToNowStrict(props.refreshingStartDate, {
|
|
117
|
+
addSuffix: true,
|
|
118
|
+
})}
|
|
119
|
+
)
|
|
120
|
+
</Property>
|
|
121
|
+
</div>
|
|
122
|
+
)}
|
|
123
|
+
<div className={classes.content}>
|
|
124
|
+
<Property name="Clones">{props.clonesCount}</Property>
|
|
125
|
+
<Property name="Snapshots">{props.snapshotsCount}</Property>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<div className={classes.content}>
|
|
129
|
+
<Property name="Size">{formatBytesIEC(props.totalDataSize)}</Property>
|
|
130
|
+
<Property
|
|
131
|
+
name={
|
|
132
|
+
<>
|
|
133
|
+
Used
|
|
134
|
+
<Marker className={classes.markerUsed} />
|
|
135
|
+
</>
|
|
136
|
+
}
|
|
137
|
+
>
|
|
138
|
+
{formatBytesIEC(props.usedDataSize)} /{' '}
|
|
139
|
+
{getPercent(props.usedDataSize, props.totalDataSize)} %
|
|
140
|
+
</Property>
|
|
141
|
+
<Property
|
|
142
|
+
name={
|
|
143
|
+
<>
|
|
144
|
+
Free
|
|
145
|
+
<Marker className={classes.markerFree} />
|
|
146
|
+
</>
|
|
147
|
+
}
|
|
148
|
+
>
|
|
149
|
+
{formatBytesIEC(props.freeDataSize)} /{' '}
|
|
150
|
+
{getPercent(props.freeDataSize, props.totalDataSize)} %
|
|
151
|
+
</Property>
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<ProgressBar
|
|
155
|
+
value={props.usedDataSize}
|
|
156
|
+
total={props.totalDataSize}
|
|
157
|
+
thresholdPercent={WARNING_THRESHOLD_PERCENT}
|
|
158
|
+
/>
|
|
159
|
+
|
|
160
|
+
{shouldShowWarning && (
|
|
161
|
+
<PerformanceStatus type="warning" className={classes.warningMessage}>
|
|
162
|
+
+{WARNING_THRESHOLD_PERCENT}% disk usage may result in performance
|
|
163
|
+
degradation
|
|
164
|
+
</PerformanceStatus>
|
|
165
|
+
)}
|
|
166
|
+
</div>
|
|
167
|
+
)
|
|
168
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
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 { observer } from 'mobx-react-lite'
|
|
9
|
+
|
|
10
|
+
import { useStores } from '@postgres.ai/shared/pages/Instance/context'
|
|
11
|
+
|
|
12
|
+
import { Section } from '../components/Section'
|
|
13
|
+
|
|
14
|
+
import { Disk } from './Disk'
|
|
15
|
+
|
|
16
|
+
export const Disks = observer(() => {
|
|
17
|
+
const stores = useStores()
|
|
18
|
+
|
|
19
|
+
const { instance, snapshots } = stores.main
|
|
20
|
+
if (!instance) return null
|
|
21
|
+
if (!snapshots) return null
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Section title="Disks">
|
|
25
|
+
{instance.state?.pools?.map((pool) => {
|
|
26
|
+
return (
|
|
27
|
+
<Disk
|
|
28
|
+
key={pool.name}
|
|
29
|
+
status={pool.status}
|
|
30
|
+
name={pool.name}
|
|
31
|
+
id={pool.name}
|
|
32
|
+
mode={pool.mode}
|
|
33
|
+
clonesCount={pool.cloneList.length}
|
|
34
|
+
snapshotsCount={
|
|
35
|
+
snapshots.data?.filter((snapshot) => snapshot.pool === pool.name)
|
|
36
|
+
.length ?? 0
|
|
37
|
+
}
|
|
38
|
+
totalDataSize={pool.fileSystem.size}
|
|
39
|
+
usedDataSize={pool.fileSystem.used}
|
|
40
|
+
freeDataSize={pool.fileSystem.free}
|
|
41
|
+
refreshingStartDate={instance.state?.retrieving?.lastRefresh ?? null}
|
|
42
|
+
/>
|
|
43
|
+
)
|
|
44
|
+
}) ??
|
|
45
|
+
(instance.state?.fileSystem && (
|
|
46
|
+
<Disk
|
|
47
|
+
status={'active'}
|
|
48
|
+
name={'Main'}
|
|
49
|
+
id={null}
|
|
50
|
+
mode="ZFS"
|
|
51
|
+
clonesCount={instance.state?.clones?.length ?? instance.state.cloning.clones.length}
|
|
52
|
+
snapshotsCount={snapshots.data?.length ?? 0}
|
|
53
|
+
totalDataSize={instance.state.fileSystem.size}
|
|
54
|
+
usedDataSize={instance.state.fileSystem.used}
|
|
55
|
+
freeDataSize={instance.state.fileSystem.free}
|
|
56
|
+
refreshingStartDate={null}
|
|
57
|
+
/>
|
|
58
|
+
)) ?? (
|
|
59
|
+
<>
|
|
60
|
+
Disk information is <strong>unavailable</strong>.
|
|
61
|
+
</>
|
|
62
|
+
)}
|
|
63
|
+
</Section>
|
|
64
|
+
)
|
|
65
|
+
})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export const ArrowLeft = ({ className }: { className?: string }) => (
|
|
2
|
+
<svg
|
|
3
|
+
width="20"
|
|
4
|
+
height="21"
|
|
5
|
+
viewBox="0 0 20 21"
|
|
6
|
+
fill="none"
|
|
7
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
8
|
+
className={className}
|
|
9
|
+
>
|
|
10
|
+
<path
|
|
11
|
+
d="M0.307554 9.50891L9.50896 0.307513C9.91902 -0.102504 10.583 -0.102504 10.9931 0.307513C11.4031 0.7172 11.4031 1.38195 10.9931 1.79163L2.53369 10.251L10.993 18.7103C11.403 19.12 11.403 19.7847 10.993 20.1944C10.788 20.3995 10.5196 20.502 10.251 20.502C9.98229 20.502 9.71356 20.3995 9.50891 20.1944L0.307507 10.993C-0.102512 10.5833 -0.10251 9.9186 0.307554 9.50891Z"
|
|
12
|
+
fill="white"
|
|
13
|
+
/>
|
|
14
|
+
<path
|
|
15
|
+
d="M9.00696 9.50891L18.2084 0.307513C18.6181 -0.102504 19.2828 -0.102504 19.6925 0.307513C20.1025 0.7172 20.1025 1.38195 19.6925 1.79163L11.2335 10.251L19.6924 18.7103C20.1025 19.12 20.1025 19.7847 19.6924 20.1944C19.4878 20.3995 19.2191 20.502 18.9504 20.502C18.6817 20.502 18.413 20.3995 18.2083 20.1944L9.00692 10.993C8.59695 10.5833 8.59695 9.9186 9.00696 9.50891Z"
|
|
16
|
+
fill="white"
|
|
17
|
+
/>
|
|
18
|
+
</svg>
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
export const ArrowRight = ({ className }: { className?: string }) => (
|
|
22
|
+
<svg
|
|
23
|
+
width="21"
|
|
24
|
+
height="21"
|
|
25
|
+
viewBox="0 0 21 21"
|
|
26
|
+
fill="none"
|
|
27
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
28
|
+
className={className}
|
|
29
|
+
>
|
|
30
|
+
<path
|
|
31
|
+
d="M20.211 9.5089L10.8896 0.307513C10.4742 -0.102504 9.80151 -0.102504 9.38609 0.307513C8.97073 0.717199 8.97073 1.38195 9.38609 1.79163L17.9558 10.251L9.38614 18.7103C8.97078 19.12 8.97078 19.7847 9.38614 20.1944C9.59385 20.3994 9.8657 20.502 10.1379 20.502C10.4101 20.502 10.6823 20.3994 10.8896 20.1944L20.211 10.993C20.6264 10.5833 20.6264 9.91859 20.211 9.5089Z"
|
|
32
|
+
fill="white"
|
|
33
|
+
/>
|
|
34
|
+
<path
|
|
35
|
+
d="M11.3981 9.5089L2.07672 0.307513C1.66169 -0.102504 0.988271 -0.102504 0.573242 0.307513C0.157878 0.717199 0.157878 1.38195 0.573242 1.79163L9.14256 10.251L0.57329 18.7103C0.157926 19.12 0.157926 19.7847 0.57329 20.1944C0.780613 20.3994 1.05284 20.502 1.32503 20.502C1.59721 20.502 1.86944 20.3994 2.07677 20.1944L11.3982 10.993C11.8135 10.5833 11.8135 9.91859 11.3981 9.5089Z"
|
|
36
|
+
fill="white"
|
|
37
|
+
/>
|
|
38
|
+
</svg>
|
|
39
|
+
)
|