Skip to content

Commit d3de699

Browse files
committed
Merge branch 'refs/heads/main' into joyui-import
# Conflicts: # new-log-viewer/src/components/modals/SettingsModal/SettingsDialog.tsx
2 parents 956d026 + f402065 commit d3de699

File tree

13 files changed

+443
-86
lines changed

13 files changed

+443
-86
lines changed

new-log-viewer/src/App.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Layout from "./components/Layout";
2+
import NotificationContextProvider from "./contexts/NotificationContextProvider";
23
import StateContextProvider from "./contexts/StateContextProvider";
34
import UrlContextProvider from "./contexts/UrlContextProvider";
45

@@ -10,11 +11,13 @@ import UrlContextProvider from "./contexts/UrlContextProvider";
1011
*/
1112
const App = () => {
1213
return (
13-
<UrlContextProvider>
14-
<StateContextProvider>
15-
<Layout/>
16-
</StateContextProvider>
17-
</UrlContextProvider>
14+
<NotificationContextProvider>
15+
<UrlContextProvider>
16+
<StateContextProvider>
17+
<Layout/>
18+
</StateContextProvider>
19+
</UrlContextProvider>
20+
</NotificationContextProvider>
1821
);
1922
};
2023

new-log-viewer/src/components/Layout.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {CONFIG_KEY} from "../typings/config";
44
import {CONFIG_DEFAULT} from "../utils/config";
55
import CentralContainer from "./CentralContainer";
66
import MenuBar from "./MenuBar";
7+
import PopUps from "./PopUps";
78
import StatusBar from "./StatusBar";
89
import APP_THEME from "./theme";
910

@@ -23,6 +24,7 @@ const Layout = () => {
2324
<MenuBar/>
2425
<CentralContainer/>
2526
<StatusBar/>
27+
<PopUps/>
2628
</CssVarsProvider>
2729
);
2830
};
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import {
2+
useContext,
3+
useEffect,
4+
useRef,
5+
useState,
6+
} from "react";
7+
8+
import {
9+
Alert,
10+
Box,
11+
CircularProgress,
12+
IconButton,
13+
Typography,
14+
} from "@mui/joy";
15+
16+
import CloseIcon from "@mui/icons-material/Close";
17+
18+
import {
19+
NotificationContext,
20+
PopUpMessage,
21+
} from "../../contexts/NotificationContextProvider";
22+
import {WithId} from "../../typings/common";
23+
import {LOG_LEVEL} from "../../typings/logs";
24+
import {DO_NOT_TIMEOUT_VALUE} from "../../typings/notifications";
25+
26+
27+
const AUTO_DISMISS_PERCENT_UPDATE_INTERVAL_MILLIS = 50;
28+
29+
interface PopUpMessageProps {
30+
message: WithId<PopUpMessage>,
31+
}
32+
33+
/**
34+
* Display a pop-up message in an alert box.
35+
*
36+
* @param props
37+
* @param props.message
38+
* @return
39+
*/
40+
const PopUpMessageBox = ({message}: PopUpMessageProps) => {
41+
const {id, level, message: messageStr, title, timeoutMillis} = message;
42+
43+
const {handlePopUpMessageClose} = useContext(NotificationContext);
44+
const [percentRemaining, setPercentRemaining] = useState<number>(100);
45+
const intervalCountRef = useRef<number>(0);
46+
47+
const handleCloseButtonClick = () => {
48+
handlePopUpMessageClose(id);
49+
};
50+
51+
useEffect(() => {
52+
if (DO_NOT_TIMEOUT_VALUE === timeoutMillis) {
53+
return () => {};
54+
}
55+
56+
const totalIntervals = Math.ceil(
57+
timeoutMillis / AUTO_DISMISS_PERCENT_UPDATE_INTERVAL_MILLIS
58+
);
59+
const intervalId = setInterval(() => {
60+
intervalCountRef.current++;
61+
const newPercentRemaining = 100 - (100 * (intervalCountRef.current / totalIntervals));
62+
if (0 >= newPercentRemaining) {
63+
handlePopUpMessageClose(id);
64+
}
65+
setPercentRemaining(newPercentRemaining);
66+
}, AUTO_DISMISS_PERCENT_UPDATE_INTERVAL_MILLIS);
67+
68+
return () => {
69+
clearInterval(intervalId);
70+
};
71+
}, [
72+
timeoutMillis,
73+
handlePopUpMessageClose,
74+
id,
75+
]);
76+
77+
const color = level >= LOG_LEVEL.ERROR ?
78+
"danger" :
79+
"primary";
80+
81+
return (
82+
<Alert
83+
className={"pop-up-message-box-alert"}
84+
color={color}
85+
variant={"outlined"}
86+
>
87+
<div className={"pop-up-message-box-alert-layout"}>
88+
<Box className={"pop-up-message-box-title-container"}>
89+
<Typography
90+
className={"pop-up-message-box-title-text"}
91+
color={color}
92+
level={"title-md"}
93+
>
94+
{title}
95+
</Typography>
96+
<CircularProgress
97+
color={color}
98+
determinate={true}
99+
size={"sm"}
100+
thickness={3}
101+
value={percentRemaining}
102+
>
103+
<IconButton
104+
className={"pop-up-message-box-close-button"}
105+
color={color}
106+
size={"sm"}
107+
onClick={handleCloseButtonClick}
108+
>
109+
<CloseIcon/>
110+
</IconButton>
111+
</CircularProgress>
112+
</Box>
113+
<Typography level={"body-sm"}>
114+
{messageStr}
115+
</Typography>
116+
</div>
117+
</Alert>
118+
);
119+
};
120+
121+
export default PopUpMessageBox;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
.pop-up-messages-container-snackbar {
2+
/* Disable pointer events on the transparent container to allow components underneath to be
3+
accessed. */
4+
pointer-events: none;
5+
6+
right: 14px !important;
7+
bottom: var(--ylv-status-bar-height) !important;
8+
9+
padding: 0 !important;
10+
11+
background: transparent !important;
12+
border: none !important;
13+
box-shadow: none !important;
14+
}
15+
16+
.pop-up-messages-container-stack {
17+
scrollbar-width: none;
18+
overflow-y: auto;
19+
height: calc(100vh - var(--ylv-status-bar-height) - var(--ylv-menu-bar-height));
20+
}
21+
22+
.pop-up-message-box-alert {
23+
/* Restore pointer events on the pop-up messages. See above `pointer-events: none` in
24+
`.pop-up-messages-container-snackbar`. */
25+
pointer-events: initial;
26+
padding-inline: 18px !important;
27+
}
28+
29+
.pop-up-message-box-alert-layout {
30+
width: 300px;
31+
}
32+
33+
.pop-up-message-box-title-container {
34+
display: flex;
35+
align-items: center;
36+
}
37+
38+
.pop-up-message-box-title-text {
39+
flex-grow: 1;
40+
}
41+
42+
.pop-up-message-box-close-button {
43+
/* stylelint-disable-next-line custom-property-pattern */
44+
--IconButton-size: 18px !important;
45+
46+
border-radius: 18px !important;
47+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import {useContext} from "react";
2+
3+
import {
4+
Snackbar,
5+
Stack,
6+
} from "@mui/joy";
7+
8+
import {NotificationContext} from "../../contexts/NotificationContextProvider";
9+
import PopUpMessageBox from "./PopUpMessageBox";
10+
11+
import "./index.css";
12+
13+
14+
/**
15+
* Displays pop-ups in a transparent container positioned on the right side of the viewport.
16+
*
17+
* @return
18+
*/
19+
const PopUps = () => {
20+
const {popUpMessages} = useContext(NotificationContext);
21+
22+
return (
23+
<Snackbar
24+
className={"pop-up-messages-container-snackbar"}
25+
open={0 < popUpMessages.length}
26+
>
27+
<Stack
28+
className={"pop-up-messages-container-stack"}
29+
direction={"column-reverse"}
30+
gap={1}
31+
>
32+
{popUpMessages.map((message) => (
33+
<PopUpMessageBox
34+
key={message.id}
35+
message={message}/>
36+
))}
37+
</Stack>
38+
</Snackbar>
39+
);
40+
};
41+
42+
export default PopUps;

new-log-viewer/src/components/StatusBar/index.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,4 @@
1515

1616
.status-message {
1717
flex-grow: 1;
18-
padding-left: 8px;
1918
}

new-log-viewer/src/components/StatusBar/index.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,8 @@ const StatusBar = () => {
3434

3535
return (
3636
<Sheet className={"status-bar"}>
37-
<Typography
38-
className={"status-message"}
39-
level={"body-sm"}
40-
>
41-
Status message
37+
<Typography className={"status-message"}>
38+
{/* This is left blank intentionally until status messages are implemented. */}
4239
</Typography>
4340
<Button
4441
color={"primary"}

0 commit comments

Comments
 (0)