Skip to content

Commit ff1c91f

Browse files
committed
Merge branch '456-snackbar-display-logic' into 'master'
fix: Snackbar display logic for Logs tab (#456) Closes #456 See merge request postgres-ai/database-lab!640
2 parents 3bc839b + 712aaf5 commit ff1c91f

File tree

10 files changed

+59
-53
lines changed

10 files changed

+59
-53
lines changed

ui/packages/shared/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"mobx": "^6.3.5",
3131
"mobx-react-lite": "^3.2.1",
3232
"moment": "^2.24.0",
33+
"prop-types": "^15.7.2",
3334
"react": "^17.0.2",
3435
"react-countdown-hook": "^1.1.0",
3536
"react-scripts": "^5.0.0",

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

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import { useStores } from '@postgres.ai/shared/pages/Instance/context'
2424
import { FormValues, useForm } from './useForm'
2525
import { Spinner } from '@postgres.ai/shared/components/Spinner'
2626
import styles from './styles.module.scss'
27-
import { SimpleModalControls } from '@postgres.ai/shared/components/SimpleModalControls'
2827
import { ResponseMessage } from './ResponseMessage'
2928
import { uniqueDatabases } from './utils'
3029
import { ExternalIcon } from '@postgres.ai/shared/icons/External'
@@ -448,14 +447,6 @@ export const Configuration = observer(
448447
theme="vs-light"
449448
options={{ domReadOnly: true, readOnly: true }}
450449
/>
451-
<SimpleModalControls
452-
items={[
453-
{
454-
text: 'Close',
455-
onClick: () => setIsOpen(false),
456-
},
457-
]}
458-
/>
459450
</Modal>
460451
</div>
461452
)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const useStyles = makeStyles(
3030
width: 0,
3131
flex: '1 1 100%',
3232
marginRight: '40px',
33+
height: "100%",
3334

3435
[theme.breakpoints.down('sm')]: {
3536
width: '100%',

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const useStyles = makeStyles(
5050
marginTop: '16px',
5151
position: 'relative',
5252
flex: '1 1 100%',
53-
height: '100%',
53+
height: "100%",
5454

5555
[theme.breakpoints.down('sm')]: {
5656
flexDirection: 'column',
@@ -160,7 +160,9 @@ export const Instance = observer((props: Props) => {
160160
<TabPanel value={activeTab} index={2}>
161161
<Configuration
162162
isConfigurationActive={isConfigurationActive}
163-
disableConfigModification={instance?.state.engine.disableConfigModification}
163+
disableConfigModification={
164+
instance?.state.engine.disableConfigModification
165+
}
164166
switchActiveTab={switchTab}
165167
activeTab={activeTab}
166168
reload={() => stores.main.load(props.instanceId)}
@@ -181,7 +183,6 @@ function TabPanel(props: PropTypes.InferProps<any>) {
181183
hidden={value !== index}
182184
id={`scrollable-auto-tabpanel-${index}`}
183185
aria-labelledby={`scrollable-auto-tab-${index}`}
184-
style={{ height: '100%' }}
185186
{...other}
186187
>
187188
<Box p={3} sx={{ height: '100%' }}>

ui/packages/shared/pages/Instance/stores/Main.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,9 @@ export class MainStore {
197197
}
198198

199199
if (error)
200-
this.getFullConfigError = await error.json().then((err) => err.message)
200+
this.getFullConfigError = await error
201+
.json()
202+
.then((err: Error) => err.message)
201203

202204
return response
203205
}
Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,45 @@
1-
import { useEffect } from 'react'
1+
import { useState, useEffect } from 'react'
22
import { wsSnackbar } from '@postgres.ai/shared/pages/Logs/wsSnackbar'
33

4-
export const useWsScroll = () => {
5-
const snackbarTag = document.createElement('div')
6-
const contentElement = document.getElementById(
7-
'content-container',
8-
) as HTMLElement
4+
export const useWsScroll = (isLoading: boolean) => {
5+
const [isNewData, setIsNewData] = useState(false)
6+
const [isAtBottom, setIsAtBottom] = useState(true)
97

108
useEffect(() => {
11-
const targetNode = document.getElementById('logs-container') as HTMLElement
12-
contentElement?.addEventListener(
13-
'scroll',
14-
() => {
15-
wsSnackbar(contentElement, targetNode, snackbarTag)
16-
},
17-
false,
18-
)
19-
20-
return () =>
9+
!isLoading && wsSnackbar(isAtBottom, isNewData)
10+
11+
const contentElement = document.getElementById('content-container')
12+
const targetNode = document.getElementById('logs-container')
13+
14+
const clientAtBottom = (element: HTMLElement) =>
15+
element.scrollHeight - element.scrollTop - 50 < element.clientHeight
16+
17+
const handleScroll = (e: Event) => {
18+
if (clientAtBottom(e.target as HTMLElement)) {
19+
setIsAtBottom(true)
20+
setIsNewData(false)
21+
} else {
22+
setIsAtBottom(false)
23+
}
24+
}
25+
26+
const handleInsert = (e: Event | any) => {
27+
if (e.srcElement?.tagName !== 'DIV') {
28+
isAtBottom && targetNode?.scrollIntoView(false)
29+
setIsNewData(true)
30+
}
31+
}
32+
33+
contentElement?.addEventListener('scroll', handleScroll, false)
34+
contentElement?.addEventListener('DOMNodeInserted', handleInsert, false)
35+
36+
return () => {
37+
contentElement?.removeEventListener('scroll', handleScroll, false)
2138
contentElement?.removeEventListener(
22-
'scroll',
23-
() => {
24-
wsSnackbar(contentElement, targetNode, snackbarTag)
25-
},
39+
'DOMNodeInserted',
40+
handleInsert,
2641
false,
2742
)
28-
}, [])
43+
}
44+
}, [isAtBottom, isNewData, isLoading])
2945
}

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ const useStyles = makeStyles(
2020
)
2121

2222
export const Logs = ({ api }: { api: Api }) => {
23-
useWsScroll()
2423
const classes = useStyles()
2524
const [isLoading, setIsLoading] = React.useState(true)
25+
useWsScroll(isLoading)
2626

2727
useEffect(() => {
2828
if (api.initWS != undefined) {
@@ -39,15 +39,11 @@ export const Logs = ({ api }: { api: Api }) => {
3939
}
4040

4141
const callback = (mutationList: MutationRecord[]) => {
42-
const isScrolling = !targetNode?.querySelector('.snackbar-tag')
4342
for (const mutation of mutationList) {
4443
if (mutation.type === 'childList') {
4544
setIsLoading(false)
4645
}
4746
}
48-
if (isScrolling) {
49-
targetNode?.scrollIntoView(false)
50-
}
5147
}
5248

5349
const observer = new MutationObserver(callback)
Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,26 @@
11
const LOGS_NEW_DATA_MESSAGE =
22
'New data arrived below - scroll down to see it 👇🏻'
33

4-
export const wsSnackbar = (
5-
contentElement: HTMLElement,
6-
targetNode: HTMLElement,
7-
snackbarTag: HTMLElement,
8-
) => {
9-
if (
10-
contentElement.scrollHeight - contentElement.scrollTop - 50 >
11-
contentElement.clientHeight
12-
) {
13-
if (!targetNode.querySelector('.snackbar-tag')) {
14-
targetNode.appendChild(snackbarTag)
4+
export const wsSnackbar = (clientAtBottom: boolean, isNewData: boolean) => {
5+
const targetNode = document.getElementById('logs-container')
6+
const snackbarTag = document.createElement('div')
7+
8+
if (!clientAtBottom && isNewData) {
9+
if (!targetNode?.querySelector('.snackbar-tag')) {
10+
targetNode?.appendChild(snackbarTag)
1511
snackbarTag.classList.add('snackbar-tag')
1612
if (snackbarTag.childNodes.length === 0) {
1713
snackbarTag.appendChild(document.createTextNode(LOGS_NEW_DATA_MESSAGE))
1814
}
1915
snackbarTag.onclick = () => {
20-
targetNode.scrollIntoView({
16+
targetNode?.scrollIntoView({
2117
behavior: 'smooth',
2218
block: 'end',
2319
inline: 'end',
2420
})
2521
}
2622
}
2723
} else {
28-
snackbarTag.remove()
24+
targetNode?.querySelector('.snackbar-tag')?.remove()
2925
}
3026
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export type GetFullConfig = () => Promise<{
22
response: string | null
3-
error: Response | null
3+
error: Response | any | null
44
}>

ui/pnpm-lock.yaml

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)