fix: use notistack

This commit is contained in:
Jannis Mattheis 2025-08-03 21:43:26 +02:00
parent 0ca5156fed
commit a7733b4f0a
5 changed files with 23 additions and 109 deletions

View File

@ -17,6 +17,7 @@
"mobx-react": "^6.3.0",
"mobx-utils": "^5.6.1",
"notifyjs": "^3.0.0",
"notistack": "^3.0.2",
"react": "^17.0.0",
"react-codemirror2": "^7.2.1",
"react-dom": "^16.4.2",

View File

@ -8,7 +8,6 @@ import LoadingSpinner from '../common/LoadingSpinner';
import Navigation from './Navigation';
import ScrollUpButton from '../common/ScrollUpButton';
import SettingsDialog from '../common/SettingsDialog';
import SnackBarHandler from '../snack/SnackBarHandler';
import * as config from '../config';
import Applications from '../application/Applications';
import Clients from '../client/Clients';
@ -20,6 +19,7 @@ import Users from '../user/Users';
import {observer} from 'mobx-react';
import {ConnectionErrorBanner} from '../common/ConnectionErrorBanner';
import {useStores} from '../stores';
import {SnackbarProvider} from 'notistack';
const useStyles = makeStyles()((theme: Theme) => ({
content: {
@ -141,7 +141,7 @@ const Layout = observer(() => {
<SettingsDialog fClose={() => setShowSettings(false)} />
)}
<ScrollUpButton />
<SnackBarHandler />
<SnackbarProvider />
</div>
</div>
</HashRouter>

View File

@ -1,86 +0,0 @@
import IconButton from '@mui/material/IconButton';
import Snackbar from '@mui/material/Snackbar';
import Close from '@mui/icons-material/Close';
import React, {Component} from 'react';
import {observable, reaction} from 'mobx';
import {observer} from 'mobx-react';
import {inject, Stores} from '../inject';
@observer
class SnackBarHandler extends Component<Stores<'snackManager'>> {
private static MAX_VISIBLE_SNACK_TIME_IN_MS = 6000;
private static MIN_VISIBLE_SNACK_TIME_IN_MS = 1000;
@observable
private open = false;
@observable
private openWhen = 0;
private dispose: () => void = () => {};
public componentDidMount = () =>
(this.dispose = reaction(() => this.props.snackManager.counter, this.onNewSnack));
public componentWillUnmount = () => this.dispose();
public render() {
const {message: current, hasNext} = this.props.snackManager;
const duration = hasNext()
? SnackBarHandler.MIN_VISIBLE_SNACK_TIME_IN_MS
: SnackBarHandler.MAX_VISIBLE_SNACK_TIME_IN_MS;
return (
<Snackbar
anchorOrigin={{vertical: 'bottom', horizontal: 'left'}}
open={this.open}
autoHideDuration={duration}
onClose={this.closeCurrentSnack}
message={<span id="message-id">{current}</span>}
action={
<IconButton
key="close"
aria-label="Close"
color="inherit"
onClick={this.closeCurrentSnack}
size="large">
<Close />
</IconButton>
}
TransitionProps={{
onExited: this.openNextSnack,
}}
/>
);
}
private onNewSnack = () => {
const {open, openWhen} = this;
if (!open) {
this.openNextSnack();
return;
}
const snackOpenSince = Date.now() - openWhen;
if (snackOpenSince > SnackBarHandler.MIN_VISIBLE_SNACK_TIME_IN_MS) {
this.closeCurrentSnack();
} else {
setTimeout(
this.closeCurrentSnack,
SnackBarHandler.MIN_VISIBLE_SNACK_TIME_IN_MS - snackOpenSince
);
}
};
private openNextSnack = () => {
if (this.props.snackManager.hasNext()) {
this.open = true;
this.openWhen = Date.now();
this.props.snackManager.next();
}
};
private closeCurrentSnack = () => (this.open = false);
}
export default inject('snackManager')(SnackBarHandler);

View File

@ -1,30 +1,11 @@
import {action, observable} from 'mobx';
import {enqueueSnackbar} from 'notistack';
export interface SnackReporter {
(message: string): void;
}
export class SnackManager {
@observable
private messages: string[] = [];
@observable
public message: string | null = null;
@observable
public counter = 0;
@action
public next = (): void => {
if (!this.hasNext()) {
throw new Error('There is nothing here :(');
}
this.message = this.messages.shift() as string;
};
public hasNext = () => this.messages.length > 0;
@action
public snack: SnackReporter = (message: string): void => {
this.messages.push(message);
this.counter++;
enqueueSnackbar({message, variant: 'info'});
};
}

View File

@ -1473,6 +1473,11 @@ chownr@^1.1.1:
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
clsx@^1.1.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
clsx@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
@ -2102,6 +2107,11 @@ globals@^14.0.0:
resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e"
integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
goober@^2.0.33:
version "2.1.16"
resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.16.tgz#7d548eb9b83ff0988d102be71f271ca8f9c82a95"
integrity sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==
graphemer@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
@ -2815,6 +2825,14 @@ notifyjs@^3.0.0:
resolved "https://registry.yarnpkg.com/notifyjs/-/notifyjs-3.0.0.tgz#7418c9d6c0533aebaa643414214af53b521d1b28"
integrity sha1-dBjJ1sBTOuuqZDQUIUr1O1IdGyg=
notistack@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/notistack/-/notistack-3.0.2.tgz#009799c3fccddeffac58565ba1657d27616dfabd"
integrity sha512-0R+/arLYbK5Hh7mEfR2adt0tyXJcCC9KkA2hc56FeWik2QN6Bm/S4uW+BjzDARsJth5u06nTjelSw/VSnB1YEA==
dependencies:
clsx "^1.1.0"
goober "^2.0.33"
object-assign@4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.0.1.tgz#99504456c3598b5cad4fc59c26e8a9bb107fe0bd"