Skip to content

Commit 77bb273

Browse files
committed
Merge branch '448-fix-ui-logs-tab' into 'master'
fix: Refactor Logs tab, enable user scroll and fix loader issue (#448) Closes #448 See merge request postgres-ai/database-lab!636
2 parents 5407334 + 5170218 commit 77bb273

File tree

10 files changed

+251
-133
lines changed

10 files changed

+251
-133
lines changed

ui/packages/ce/src/App/Layout/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const Layout = (props: Props) => {
99
return (
1010
<div className={styles.root}>
1111
<div className={styles.menu}>{props.menu}</div>
12-
<div className={styles.content}>{props.children}</div>
12+
<div id="content-container" className={styles.content}>{props.children}</div>
1313
</div>
1414
)
1515
}

ui/packages/shared/pages/Configuration/InputWithTooltip/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export const InputWithChip = ({
107107
key={index}
108108
className={styles.chip}
109109
label={database}
110+
disabled={disabled}
110111
onDelete={(event) => handleDeleteDatabase(event, database)}
111112
color="primary"
112113
/>

ui/packages/shared/pages/Configuration/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export const Configuration = observer(
5656
isConfigurationActive,
5757
allowModifyingConfig,
5858
}: {
59-
switchActiveTab: (activeTab: number) => void
59+
switchActiveTab: (_: null, activeTab: number) => void
6060
activeTab: number
6161
reload: () => void
6262
isConfigurationActive: boolean
@@ -91,7 +91,7 @@ export const Configuration = observer(
9191

9292
const switchTab = async () => {
9393
reload()
94-
switchActiveTab(0)
94+
switchActiveTab(null, 0)
9595
}
9696

9797
const onSubmit = async (values: FormValues) => {
@@ -414,7 +414,7 @@ export const Configuration = observer(
414414
<Button
415415
variant="secondary"
416416
size="medium"
417-
onClick={() => switchActiveTab(0)}
417+
onClick={() => switchActiveTab(null, 0)}
418418
>
419419
Cancel
420420
</Button>

ui/packages/shared/pages/Instance/index.tsx

Lines changed: 9 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,21 @@ import { observer } from 'mobx-react-lite'
1111

1212
import { Button } from '@postgres.ai/shared/components/Button2'
1313
import { StubSpinner } from '@postgres.ai/shared/components/StubSpinner'
14-
import { Spinner } from '@postgres.ai/shared/components/Spinner';
1514
import { SectionTitle } from '@postgres.ai/shared/components/SectionTitle'
1615
import { ErrorStub } from '@postgres.ai/shared/components/ErrorStub'
1716

1817
import { Tabs } from './Tabs'
18+
import { Logs } from '../Logs'
1919
import { Clones } from './Clones'
2020
import { Info } from './Info'
21-
import { establishConnection } from './wsLogs'
2221
import { Configuration } from '../Configuration'
2322
import { ClonesModal } from './ClonesModal'
2423
import { SnapshotsModal } from './SnapshotsModal'
2524
import { Host, HostProvider, StoresProvider } from './context'
2625

27-
import PropTypes from "prop-types";
28-
import Typography from "@material-ui/core/Typography";
29-
import Box from "@material-ui/core/Box";
30-
import Alert from '@material-ui/lab/Alert';
31-
import AlertTitle from '@material-ui/lab/AlertTitle';
26+
import PropTypes from 'prop-types'
27+
import Typography from '@material-ui/core/Typography'
28+
import Box from '@material-ui/core/Box'
3229

3330
import { useCreatedStores } from './useCreatedStores'
3431

@@ -57,12 +54,6 @@ const useStyles = makeStyles((theme) => ({
5754
flexDirection: 'column',
5855
},
5956
},
60-
spinnerContainer: {
61-
display: "flex",
62-
width: "100%",
63-
alignItems: "center",
64-
justifyContent: "center"
65-
}
6657
}))
6758

6859
export const Instance = observer((props: Props) => {
@@ -97,16 +88,10 @@ export const Instance = observer((props: Props) => {
9788

9889
const [activeTab, setActiveTab] = React.useState(0);
9990

100-
const [isLogConnectionEnabled, enableLogConnection] = React.useState(false);
101-
102-
const switchTab = (_: React.ChangeEvent<{}>, tabID: number) => {
103-
if (tabID == 1 && api.initWS != undefined && !isLogConnectionEnabled) {
104-
establishConnection(api).then(() => {
105-
enableLogConnection(true)
106-
});
107-
}
108-
91+
const switchTab = (_: React.ChangeEvent<{} | null>, tabID: number) => {
92+
const contentElement = document.getElementById('content-container')
10993
setActiveTab(tabID);
94+
contentElement.scroll(0, 0)
11095
};
11196

11297
return (
@@ -160,25 +145,15 @@ export const Instance = observer((props: Props) => {
160145
</TabPanel>
161146

162147
<TabPanel value={activeTab} index={1}>
163-
<Alert severity="info">
164-
<AlertTitle>Sensitive data are masked.</AlertTitle>
165-
You can see the raw log data connecting to the machine and running the <strong>'docker logs'</strong> command.
166-
</Alert>
167-
<div id="logs-container">
168-
{!isLogConnectionEnabled && (
169-
<div className={classes.spinnerContainer}>
170-
<Spinner />
171-
</div>
172-
)}
173-
</div>
148+
{activeTab === 1 && <Logs api={api} />}
174149
</TabPanel>
175150
</>
176151

177152
<TabPanel value={activeTab} index={2}>
178153
<Configuration
179154
isConfigurationActive={isConfigurationActive}
180155
allowModifyingConfig={instance?.state.engine.allowModifyingConfig}
181-
switchActiveTab={(id: number) => setActiveTab(id)}
156+
switchActiveTab={switchTab}
182157
activeTab={activeTab}
183158
reload={() => stores.main.load(props.instanceId)}
184159
/>

ui/packages/shared/pages/Instance/styles.scss

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,32 @@
66
*/
77

88
#logs-container {
9-
margin: 1rem 0;
10-
border: 1px solid #b4b4b4;
11-
border-radius: 4px;
12-
margin-top: 20px;
13-
overflow: hidden;
14-
padding: 0.5rem 1rem;
15-
& > p {
16-
font-size: medium;
17-
font-family: 'Fira Code', monospace;
18-
padding: 4px 0;
19-
}
9+
margin: 20px 0 0 0;
10+
border: 1px solid #b4b4b4;
11+
border-radius: 4px;
12+
overflow: hidden;
13+
padding: 0.5rem 1rem;
14+
& > p {
15+
font-size: small;
16+
font-family: 'Fira Code', monospace;
17+
padding: 1px 0;
18+
}
2019
}
2120

2221
.error-log {
2322
color: red;
24-
}
23+
}
24+
25+
.snackbar-tag {
26+
position: fixed;
27+
bottom: 0;
28+
left: 50%;
29+
transform: translate(-50%, -50%);
30+
background-color: #fff2e5;
31+
color: #000;
32+
font-weight: 500;
33+
padding: 6px 8px;
34+
border-radius: 4px;
35+
transition: all 40050ms ease;
36+
cursor: pointer;
37+
}

ui/packages/shared/pages/Instance/wsLogs.ts

Lines changed: 0 additions & 83 deletions
This file was deleted.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { useEffect } from 'react'
2+
import { wsSnackbar } from '@postgres.ai/shared/pages/Logs/wsSnackbar'
3+
4+
export const useWsScroll = () => {
5+
const snackbarTag = document.createElement('div')
6+
const contentElement = document.getElementById('content-container')
7+
8+
useEffect(() => {
9+
const targetNode = document.getElementById('logs-container')
10+
contentElement.addEventListener(
11+
'scroll',
12+
() => {
13+
wsSnackbar(contentElement, targetNode, snackbarTag)
14+
},
15+
false,
16+
)
17+
18+
return () =>
19+
contentElement.removeEventListener(
20+
'scroll',
21+
() => {
22+
wsSnackbar(contentElement, targetNode, snackbarTag)
23+
},
24+
false,
25+
)
26+
}, [])
27+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import React, { useEffect } from 'react'
2+
import { Alert, AlertTitle } from '@material-ui/lab'
3+
import { makeStyles } from '@material-ui/core'
4+
import { Spinner } from '@postgres.ai/shared/components/Spinner'
5+
6+
import { Api } from 'pages/Instance/stores/Main'
7+
import { establishConnection } from '@postgres.ai/shared/pages/Logs/wsLogs'
8+
import { useWsScroll } from '@postgres.ai/shared/pages/Logs/hooks/useWsScroll'
9+
10+
const useStyles = makeStyles(() => ({
11+
spinnerContainer: {
12+
display: 'flex',
13+
width: '100%',
14+
alignItems: 'center',
15+
justifyContent: 'center',
16+
},
17+
}))
18+
19+
export const Logs = ({ api }: { api: Api }) => {
20+
useWsScroll()
21+
const classes = useStyles()
22+
const [isLoading, setIsLoading] = React.useState(true)
23+
24+
useEffect(() => {
25+
if (api.initWS != undefined) {
26+
establishConnection(api)
27+
}
28+
}, [api])
29+
30+
useEffect(() => {
31+
const config = { attributes: false, childList: true, subtree: true }
32+
const targetNode = document.getElementById('logs-container')
33+
34+
if (isLoading && targetNode.querySelectorAll('p').length === 1) {
35+
setIsLoading(false)
36+
}
37+
38+
const callback = (mutationList: MutationRecord[]) => {
39+
const isScrolling = !targetNode.querySelector('.snackbar-tag')
40+
for (const mutation of mutationList) {
41+
if (mutation.type === 'childList') {
42+
setIsLoading(false)
43+
}
44+
}
45+
if (isScrolling) {
46+
targetNode.scrollIntoView(false)
47+
}
48+
}
49+
50+
const observer = new MutationObserver(callback)
51+
observer.observe(targetNode, config)
52+
}, [isLoading])
53+
54+
return (
55+
<>
56+
<Alert severity="info">
57+
<AlertTitle>Sensitive data are masked.</AlertTitle>
58+
You can see the raw log data connecting to the machine and running the{' '}
59+
<strong>'docker logs'</strong> command.
60+
</Alert>
61+
<div id="logs-container">
62+
{isLoading && (
63+
<div className={classes.spinnerContainer}>
64+
<Spinner />
65+
</div>
66+
)}
67+
</div>
68+
</>
69+
)
70+
}

0 commit comments

Comments
 (0)