From f296d85d6ac3048c7359941bc18b5df6a8ba1ec1 Mon Sep 17 00:00:00 2001 From: Matthias Fechner Date: Wed, 16 Oct 2024 15:33:07 +0300 Subject: [PATCH] WIP --- ui/package.json | 59 +- ui/src/CurrentUser.ts | 62 +- ui/src/application/AddApplicationDialog.tsx | 4 +- ui/src/application/Applications.tsx | 34 +- .../application/UpdateApplicationDialog.tsx | 4 +- ui/src/client/AddClientDialog.tsx | 2 +- ui/src/client/ClientStore.ts | 4 +- ui/src/client/Clients.tsx | 34 +- ui/src/client/UpdateClientDialog.tsx | 2 +- ui/src/common/BaseStore.ts | 6 +- ui/src/common/Container.tsx | 2 +- ui/src/common/SettingsDialog.tsx | 22 +- ui/src/index.tsx | 45 +- ui/src/inject.tsx | 2 +- ui/src/layout/Header.tsx | 5 - ui/src/layout/Layout.tsx | 67 +- ui/src/layout/Navigation.tsx | 6 - ui/src/message/Messages.tsx | 23 +- ui/src/message/MessagesStore.ts | 15 +- ui/src/plugin/Plugins.tsx | 6 - ui/src/snack/SnackBarHandler.tsx | 24 +- ui/src/snack/SnackManager.ts | 6 +- ui/src/user/AddEditUserDialog.tsx | 4 +- ui/src/user/Login.tsx | 38 +- ui/src/user/Register.tsx | 4 +- ui/tsconfig.json | 2 +- ui/vite.config.ts | 2 +- ui/yarn.lock | 1799 +++++++++++------ 28 files changed, 1309 insertions(+), 974 deletions(-) diff --git a/ui/package.json b/ui/package.json index 012686d67..c72bc3823 100644 --- a/ui/package.json +++ b/ui/package.json @@ -5,27 +5,27 @@ "homepage": ".", "proxy": "http://localhost:80", "dependencies": { - "@material-ui/core": "^4.11.4", - "@material-ui/icons": "^4.9.1", - "axios": "^0.21.1", - "codemirror": "^5.61.1", + "@material-ui/core": "4.12.3", + "@material-ui/icons": "4.11.2", + "axios": "1.7.4", + "codemirror": "5.64.0", "detect-browser": "^5.2.0", "js-base64": "^3.6.1", - "mobx": "^6.13.3", - "mobx-react": "^9.1.1", - "mobx-utils": "^6.1.0", - "notifyjs": "^3.0.0", - "prop-types": "^15.6.2", - "react": "^16.8.6", - "react-codemirror2": "^7.2.1", - "react-dom": "^16.8.6", - "react-infinite": "^0.13.0", - "react-markdown": "^6.0.2", - "react-router": "^5.2.0", - "react-router-dom": "^5.2.0", - "react-timeago": "^6.2.1", - "remark-gfm": "^1.0.0", - "remove-markdown": "^0.3.0", + "mobx": "6.13.4", + "mobx-react": "9.1.1", + "mobx-utils": "6.1.0", + "notifyjs": "3.0.0", + "prop-types": "15.8.1", + "react": "17.0.2", + "react-codemirror2": "7.2.1", + "react-dom": "17.0.2", + "react-infinite": "0.13.0", + "react-markdown": "9.0.1", + "react-router": "6.27.0", + "react-router-dom": "6.27.0", + "react-timeago": "7.2.0", + "remark-gfm": "4.0.0", + "remove-markdown": "0.5.5", "typeface-roboto": "1.1.13" }, "scripts": { @@ -40,18 +40,15 @@ "devDependencies": { "@types/codemirror": "5.60.0", "@types/detect-browser": "^4.0.0", - "@types/get-port": "^4.0.0", - "@types/jest": "^26.0.23", "@types/js-base64": "^3.3.1", - "@types/node": "^15.12.2", + "@types/node": "20.16.11", "@types/notifyjs": "^3.0.2", "@types/puppeteer": "^5.4.6", - "@types/react": "^16.9.49", - "@types/react-dom": "^16.9.8", + "@types/react": "17.0.83", + "@types/react-dom": "17.0.25", "@types/react-infinite": "0.0.35", - "@types/react-router-dom": "^5.1.7", + "@types/react-router-dom": "5.3.0", "@types/remove-markdown": "^0.3.0", - "@types/rimraf": "^3.0.0", "@typescript-eslint/eslint-plugin": "^4.1.0", "@typescript-eslint/parser": "^4.1.0", "@vitejs/plugin-react": "^4.3.2", @@ -61,15 +58,15 @@ "eslint-plugin-prefer-arrow": "^1.2.2", "eslint-plugin-react": "^7.20.6", "eslint-plugin-unicorn": "^21.0.0", - "get-port": "^5.1.1", + "get-port": "7.1.0", "prettier": "^2.3.1", "puppeteer": "^17.1.3", - "rimraf": "^3.0.2", + "rimraf": "6.0.1", "tree-kill": "^1.2.0", "typescript": "4.0.2", - "vite": "^5.4.8", - "vitest": "^2.1.3", - "wait-on": "^5.3.0" + "vite": "5.4.9", + "vitest": "2.1.3", + "wait-on": "8.0.1" }, "eslintConfig": { "extends": "react-app" diff --git a/ui/src/CurrentUser.ts b/ui/src/CurrentUser.ts index e93f1e110..95f737b4d 100644 --- a/ui/src/CurrentUser.ts +++ b/ui/src/CurrentUser.ts @@ -3,7 +3,7 @@ import * as config from './config'; import {Base64} from 'js-base64'; import {detect} from 'detect-browser'; import {SnackReporter} from './snack/SnackManager'; -import { makeObservable, observable, action } from 'mobx'; +import { observable, action, runInAction } from 'mobx'; import {IClient, IUser} from './types'; const tokenKey = 'gotify-login-key'; @@ -21,19 +21,7 @@ export class CurrentUser { @observable public connectionErrorMessage: string | null = null; - public constructor(private readonly snack: SnackReporter) { - makeObservable(this); - } - - @action - private setLoggedIn = (value: boolean) => { - this.loggedIn = value; - }; - - @action - private setConnectionErrorMessage = (message: string | null): void => { - this.connectionErrorMessage = message; - }; + public constructor(private readonly snack: SnackReporter) {} public token = (): string => { if (this.tokenCache !== null) { @@ -75,9 +63,8 @@ export class CurrentUser { return false; }); - @action public login = async (username: string, password: string) => { - this.setLoggedIn(false); + this.loggedIn = false; this.authenticating = true; const browser = detect(); const name = (browser && browser.name + ' ' + browser.version) || 'unknown browser'; @@ -91,19 +78,23 @@ export class CurrentUser { headers: {Authorization: 'Basic ' + Base64.encode(username + ':' + password)}, }) .then((resp: AxiosResponse) => { - this.snack(`A client named '${name}' was created for your session.`); - this.setToken(resp.data.token); - this.tryAuthenticate() - .then(() => { - this.authenticating = false; - this.setLoggedIn(true); - }) - .catch(() => { - this.authenticating = false; - console.log( - 'create client succeeded, but authenticated with given token failed' - ); - }); + runInAction(() => { + this.snack(`A client named '${name}' was created for your session.`); + this.setToken(resp.data.token); + this.tryAuthenticate() + .then(() => { + runInAction(() => { + this.authenticating = false; + this.loggedIn = true; + }) + }) + .catch(() => { + this.authenticating = false; + console.log( + 'create client succeeded, but authenticated with given token failed' + ); + }); + }) }) .catch(() => { this.authenticating = false; @@ -111,7 +102,6 @@ export class CurrentUser { }); }; - @action public tryAuthenticate = async (): Promise> => { if (this.token() === '') { return Promise.reject(); @@ -122,10 +112,10 @@ export class CurrentUser { .create() // eslint-disable-next-line @typescript-eslint/naming-convention .get(config.get('url') + 'current/user', {headers: {'X-Gotify-Key': this.token()}}) - .then((passThrough) => { + .then((passThrough: { data: IUser; }) => { this.user = passThrough.data; - this.setLoggedIn(true); - this.setConnectionErrorMessage(null); + this.loggedIn = true; + this.connectionErrorMessage = null; this.reconnectTime = 7500; return passThrough; }) @@ -142,7 +132,7 @@ export class CurrentUser { return Promise.reject(error); } - this.setConnectionErrorMessage(null); + this.connectionErrorMessage = null; if (error.response.status >= 400 && error.response.status < 500) { this.logout(); @@ -152,7 +142,6 @@ export class CurrentUser { ); }; - @action public logout = async () => { await axios .get(config.get('url') + 'client') @@ -164,7 +153,7 @@ export class CurrentUser { .catch(() => Promise.resolve()); window.localStorage.removeItem(tokenKey); this.tokenCache = null; - this.setLoggedIn(false); + this.loggedIn = false; }; public changePassword = (pass: string) => { @@ -181,7 +170,6 @@ export class CurrentUser { }); }; - @action private readonly connectionError = (message: string) => { this.connectionErrorMessage = message; if (this.reconnectTimeoutId !== null) { diff --git a/ui/src/application/AddApplicationDialog.tsx b/ui/src/application/AddApplicationDialog.tsx index dce6b9299..8bdf1d738 100644 --- a/ui/src/application/AddApplicationDialog.tsx +++ b/ui/src/application/AddApplicationDialog.tsx @@ -48,7 +48,7 @@ export default class AddDialog extends Component { className="name" label="Name *" type="text" - value={name} + defaultValue={name} onChange={this.handleChange.bind(this, 'name')} fullWidth /> @@ -56,7 +56,7 @@ export default class AddDialog extends Component { margin="dense" className="description" label="Short Description" - value={description} + defaultValue={description} onChange={this.handleChange.bind(this, 'description')} fullWidth multiline diff --git a/ui/src/application/Applications.tsx b/ui/src/application/Applications.tsx index 0eaec6ed6..f87ca5166 100644 --- a/ui/src/application/Applications.tsx +++ b/ui/src/application/Applications.tsx @@ -16,7 +16,7 @@ import Button from '@material-ui/core/Button'; import CopyableSecret from '../common/CopyableSecret'; import AddApplicationDialog from './AddApplicationDialog'; import {observer} from 'mobx-react'; -import { action, makeObservable, observable } from 'mobx'; +import { action, observable } from 'mobx'; import {inject, Stores} from '../inject'; import * as config from '../config'; import UpdateDialog from './UpdateApplicationDialog'; @@ -35,26 +35,6 @@ class Applications extends Component> { private uploadId = -1; private upload: HTMLInputElement | null = null; - constructor(props: any) { - super(props); - makeObservable(this); - } - - @action - private setDeleteId = (id: number | false) => { - this.deleteId = id; - }; - - @action - private setUpdateId = (id: number | false) => { - this.updateId = id; - }; - - @action - private setCreateDialog = (dialog: boolean) => { - this.createDialog = dialog; - }; - public componentDidMount = () => this.props.appStore.refresh(); public render() { @@ -73,7 +53,7 @@ class Applications extends Component> { id="create-app" variant="contained" color="primary" - onClick={() => (this.setCreateDialog(true))}> + onClick={() => (this.createDialog = true)}> Create Application } @@ -104,8 +84,8 @@ class Applications extends Component> { value={app.token} lastUsed={app.lastUsed} fUpload={() => this.uploadImage(app.id)} - fDelete={() => (this.setDeleteId(app.id))} - fEdit={() => (this.setUpdateId(app.id))} + fDelete={() => (this.deleteId = app.id)} + fEdit={() => (this.updateId = app.id)} noDelete={app.internal} /> ))} @@ -121,13 +101,13 @@ class Applications extends Component> { {createDialog && ( (this.setCreateDialog(false))} + fClose={() => (this.createDialog = false)} fOnSubmit={appStore.create} /> )} {updateId !== false && ( (this.setUpdateId(false))} + fClose={() => (this.updateId = false)} fOnSubmit={(name, description, defaultPriority) => appStore.update(updateId, name, description, defaultPriority) } @@ -140,7 +120,7 @@ class Applications extends Component> { (this.setDeleteId(false))} + fClose={() => (this.deleteId = false)} fOnSubmit={() => appStore.remove(deleteId)} /> )} diff --git a/ui/src/application/UpdateApplicationDialog.tsx b/ui/src/application/UpdateApplicationDialog.tsx index ed0402243..5f0b0eb73 100644 --- a/ui/src/application/UpdateApplicationDialog.tsx +++ b/ui/src/application/UpdateApplicationDialog.tsx @@ -60,7 +60,7 @@ export default class UpdateDialog extends Component { className="name" label="Name *" type="text" - value={name} + defaultValue={name} onChange={this.handleChange.bind(this, 'name')} fullWidth /> @@ -68,7 +68,7 @@ export default class UpdateDialog extends Component { margin="dense" className="description" label="Short Description" - value={description} + defaultValue={description} onChange={this.handleChange.bind(this, 'description')} fullWidth multiline diff --git a/ui/src/client/AddClientDialog.tsx b/ui/src/client/AddClientDialog.tsx index 3249b6062..c9d0df0da 100644 --- a/ui/src/client/AddClientDialog.tsx +++ b/ui/src/client/AddClientDialog.tsx @@ -37,7 +37,7 @@ export default class AddDialog extends Component { className="name" label="Name *" type="email" - value={name} + defaultValue={name} onChange={this.handleChange.bind(this, 'name')} fullWidth /> diff --git a/ui/src/client/ClientStore.ts b/ui/src/client/ClientStore.ts index e6bb37e6c..1695585c4 100644 --- a/ui/src/client/ClientStore.ts +++ b/ui/src/client/ClientStore.ts @@ -1,17 +1,15 @@ import {BaseStore} from '../common/BaseStore'; import axios from 'axios'; import * as config from '../config'; -import { action, makeObservable } from 'mobx'; +import { action } from 'mobx'; import {SnackReporter} from '../snack/SnackManager'; import {IClient} from '../types'; export class ClientStore extends BaseStore { public constructor(private readonly snack: SnackReporter) { super(); - makeObservable(this); } - @action protected requestItems = (): Promise => axios.get(`${config.get('url')}client`).then((response) => response.data); diff --git a/ui/src/client/Clients.tsx b/ui/src/client/Clients.tsx index 1a3664e1f..6a4cd8a75 100644 --- a/ui/src/client/Clients.tsx +++ b/ui/src/client/Clients.tsx @@ -15,7 +15,7 @@ import Button from '@material-ui/core/Button'; import AddClientDialog from './AddClientDialog'; import UpdateDialog from './UpdateClientDialog'; import {observer} from 'mobx-react'; -import { action, makeObservable, observable } from 'mobx'; +import { action, observable } from 'mobx'; import {inject, Stores} from '../inject'; import {IClient} from '../types'; import CopyableSecret from '../common/CopyableSecret'; @@ -30,26 +30,6 @@ class Clients extends Component> { @observable private updateId: false | number = false; - constructor(props: any) { - super(props); - makeObservable(this); - } - - @action - private setShowDialog = (show: boolean) => { - this.showDialog = show; - } - - @action - private setDeleteId = (id: false | number) => { - this.deleteId = id; - } - - @action - private setUpdateId = (id: false | number) => { - this.updateId = id; - } - public componentDidMount = () => this.props.clientStore.refresh(); public render() { @@ -69,7 +49,7 @@ class Clients extends Component> { id="create-client" variant="contained" color="primary" - onClick={() => (this.setShowDialog(true))}> + onClick={() => (this.showDialog = true)}> Create Client }> @@ -92,8 +72,8 @@ class Clients extends Component> { name={client.name} value={client.token} lastUsed={client.lastUsed} - fEdit={() => (this.setUpdateId(client.id))} - fDelete={() => (this.setDeleteId(client.id))} + fEdit={() => (this.updateId = client.id)} + fDelete={() => (this.deleteId = client.id)} /> ))} @@ -102,13 +82,13 @@ class Clients extends Component> { {showDialog && ( (this.setShowDialog(false))} + fClose={() => (this.showDialog = false)} fOnSubmit={clientStore.create} /> )} {updateId !== false && ( (this.setUpdateId(false))} + fClose={() => (this.updateId = false)} fOnSubmit={(name) => clientStore.update(updateId, name)} initialName={clientStore.getByID(updateId).name} /> @@ -117,7 +97,7 @@ class Clients extends Component> { (this.setDeleteId(false))} + fClose={() => (this.deleteId = false)} fOnSubmit={() => clientStore.remove(deleteId)} /> )} diff --git a/ui/src/client/UpdateClientDialog.tsx b/ui/src/client/UpdateClientDialog.tsx index 214a7c22b..d5ce77a7e 100644 --- a/ui/src/client/UpdateClientDialog.tsx +++ b/ui/src/client/UpdateClientDialog.tsx @@ -54,7 +54,7 @@ export default class UpdateDialog extends Component { className="name" label="Name *" type="text" - value={name} + defaultValue={name} onChange={this.handleChange.bind(this, 'name')} fullWidth /> diff --git a/ui/src/common/BaseStore.ts b/ui/src/common/BaseStore.ts index fa4f0a2f7..2b38d2fd6 100644 --- a/ui/src/common/BaseStore.ts +++ b/ui/src/common/BaseStore.ts @@ -1,4 +1,4 @@ -import { action, makeObservable, observable } from 'mobx'; +import { action, observable } from 'mobx'; interface HasID { id: number; @@ -19,10 +19,6 @@ export abstract class BaseStore implements IClearable { protected abstract requestDelete(id: number): Promise; - constructor() { - makeObservable(this); - } - @action public remove = async (id: number): Promise => { await this.requestDelete(id); diff --git a/ui/src/common/Container.tsx b/ui/src/common/Container.tsx index c891b013c..6f849845c 100644 --- a/ui/src/common/Container.tsx +++ b/ui/src/common/Container.tsx @@ -1,6 +1,6 @@ import Paper from '@material-ui/core/Paper'; import {withStyles, WithStyles} from '@material-ui/core/styles'; -import * as React from 'react'; +import React from 'react'; const styles = () => ({ paper: { diff --git a/ui/src/common/SettingsDialog.tsx b/ui/src/common/SettingsDialog.tsx index 6933a8b2c..3f5aabd66 100644 --- a/ui/src/common/SettingsDialog.tsx +++ b/ui/src/common/SettingsDialog.tsx @@ -6,7 +6,7 @@ import DialogTitle from '@material-ui/core/DialogTitle'; import TextField from '@material-ui/core/TextField'; import Tooltip from '@material-ui/core/Tooltip'; import React, {Component} from 'react'; -import { action, makeObservable, observable } from 'mobx'; +import { action, observable } from 'mobx'; import {observer} from 'mobx-react'; import {inject, Stores} from '../inject'; @@ -19,18 +19,8 @@ class SettingsDialog extends Component> { @observable private pass = ''; - constructor(props: any) { - super(props); - makeObservable(this); - } - - @action - private setPass = (value: string) => { - this.pass = value; - } - public render() { - this.setPass(this.pass); + const {pass} = this; const {fClose, currentUser} = this.props; const submitAndClose = () => { currentUser.changePassword(this.pass); @@ -50,18 +40,18 @@ class SettingsDialog extends Component> { margin="dense" type="password" label="New Password *" - value={this.pass} - onChange={(e) => (this.setPass(e.target.value))} + defaultValue={pass} + onChange={(e) => (this.pass = e.target.value)} fullWidth /> - +
{showSettings && ( - (this.setShowSettings(false))} /> + (this.showSettings = false)} /> )} @@ -174,7 +152,6 @@ class Layout extends React.Component< ); } - @action private toggleTheme() { this.currentTheme = this.currentTheme === 'dark' ? 'light' : 'dark'; localStorage.setItem(localStorageThemeKey, this.currentTheme); diff --git a/ui/src/layout/Navigation.tsx b/ui/src/layout/Navigation.tsx index 30fcd6dfb..4b3b9fbc8 100644 --- a/ui/src/layout/Navigation.tsx +++ b/ui/src/layout/Navigation.tsx @@ -1,7 +1,6 @@ import Divider from '@material-ui/core/Divider'; import Drawer from '@material-ui/core/Drawer'; import {StyleRules, Theme, WithStyles, withStyles} from '@material-ui/core/styles'; -import { makeObservable } from 'mobx'; import React, {Component} from 'react'; import {Link} from 'react-router-dom'; import {observer} from 'mobx-react'; @@ -52,11 +51,6 @@ class Navigation extends Component< > { public state = { showRequestNotification: mayAllowPermission() }; - constructor(props: any) { - super(props); - makeObservable(this); - } - public render() { const {classes, loggedIn, appStore, navOpen, setNavOpen} = this.props; const {showRequestNotification} = this.state; diff --git a/ui/src/message/Messages.tsx b/ui/src/message/Messages.tsx index 149eaab5d..ceabfc63e 100644 --- a/ui/src/message/Messages.tsx +++ b/ui/src/message/Messages.tsx @@ -7,7 +7,7 @@ import Button from '@material-ui/core/Button'; import Message from './Message'; import {observer} from 'mobx-react'; import {inject, Stores } from '../inject'; -import { action, makeObservable, observable } from 'mobx'; +import { action, observable } from 'mobx'; import ReactInfinite from 'react-infinite'; import { IMessage } from '../types'; import ConfirmDialog from '../common/ConfirmDialog'; @@ -26,21 +26,6 @@ class Messages extends Component, @observable private deleteAll = false; - constructor(props: any) { - super(props); - makeObservable(this); - } - - @action - private setHeight(id: string, height: number) { - this.heights[id] = height; - } - - @action - private setDeleteAll(deleteAll: boolean) { - this.deleteAll = deleteAll; - } - private static appId(props: IProps) { if (props === undefined) { return -1; @@ -96,7 +81,7 @@ class Messages extends Component, disabled={!hasMessages} color="primary" onClick={() => { - this.setDeleteAll(true); + this.deleteAll = true; }}> Delete All @@ -124,7 +109,7 @@ class Messages extends Component, (this.setDeleteAll(false))} + fClose={() => (this.deleteAll = false)} fOnSubmit={() => messagesStore.removeByApp(appId)} /> )} @@ -150,7 +135,7 @@ class Messages extends Component, key={message.id} height={(height: number) => { if (!this.heights[message.id]) { - this.setHeight(message.id, height); + this.heights[message.id] = height; } }} fDelete={this.deleteMessage(message)} diff --git a/ui/src/message/MessagesStore.ts b/ui/src/message/MessagesStore.ts index d1a85ef69..19d4bc3eb 100644 --- a/ui/src/message/MessagesStore.ts +++ b/ui/src/message/MessagesStore.ts @@ -1,5 +1,5 @@ import {BaseStore} from '../common/BaseStore'; -import { action, IObservableArray, makeObservable, observable, reaction } from 'mobx'; +import { action, IObservableArray, observable, reaction, runInAction } from 'mobx'; import axios, {AxiosResponse} from 'axios'; import * as config from '../config'; import {createTransformer} from 'mobx-utils'; @@ -25,11 +25,9 @@ export class MessagesStore { private readonly appStore: BaseStore, private readonly snack: SnackReporter ) { - makeObservable(this); reaction(() => appStore.getItems(), this.createEmptyStatesForApps); } - @action private stateOf = (appId: number, create = true) => { if (!this.state[appId] && create) { this.state[appId] = this.emptyState(); @@ -53,10 +51,12 @@ export class MessagesStore { (resp) => resp.data ); - state.messages.replace([...state.messages, ...pagedResult.messages]); - state.nextSince = pagedResult.paging.since ?? 0; - state.hasMore = 'next' in pagedResult.paging; - state.loaded = true; + runInAction(() => { + state.messages.replace([...state.messages, ...pagedResult.messages]); + state.nextSince = pagedResult.paging.since ?? 0; + state.hasMore = 'next' in pagedResult.paging; + state.loaded = true; + }); this.loading = false; return Promise.resolve(); }; @@ -158,7 +158,6 @@ export class MessagesStore { this.clearCache(); }; - @action private emptyState = (): MessagesState => ({ messages: observable.array(), hasMore: true, diff --git a/ui/src/plugin/Plugins.tsx b/ui/src/plugin/Plugins.tsx index 82c62427e..0bbdc8db4 100644 --- a/ui/src/plugin/Plugins.tsx +++ b/ui/src/plugin/Plugins.tsx @@ -1,4 +1,3 @@ -import { makeObservable } from 'mobx'; import React, {Component, SFC} from 'react'; import {Link} from 'react-router-dom'; import Grid from '@material-ui/core/Grid'; @@ -20,11 +19,6 @@ import { IPlugin } from '../types'; class Plugins extends Component> { public componentDidMount = () => this.props.pluginStore.refresh(); - constructor(props: any) { - super(props); - makeObservable(this); - } - public render() { const { props: {pluginStore}, diff --git a/ui/src/snack/SnackBarHandler.tsx b/ui/src/snack/SnackBarHandler.tsx index 331f72ee2..91ae1d65a 100644 --- a/ui/src/snack/SnackBarHandler.tsx +++ b/ui/src/snack/SnackBarHandler.tsx @@ -15,27 +15,16 @@ class SnackBarHandler extends Component> { private open = false; @observable private openWhen = 0; - @observable - private snackManager: any = null; private dispose: () => void = () => {}; - @action - public componentDidMount = () => { - this.snackManager = this.props.snackManager; - - this.dispose = reaction( - () => toJS(this.snackManager.counter), - this.onNewSnack - ); - } + public componentDidMount = () => + (this.dispose = reaction(() => this.props.snackManager.counter, this.onNewSnack)); public componentWillUnmount = () => this.dispose(); public render() { - if (!this.snackManager) return null; - - const {message: current, hasNext} = this.snackManager; + const {message: current, hasNext} = this.props.snackManager; const duration = hasNext() ? SnackBarHandler.MIN_VISIBLE_SNACK_TIME_IN_MS : SnackBarHandler.MAX_VISIBLE_SNACK_TIME_IN_MS; @@ -61,7 +50,6 @@ class SnackBarHandler extends Component> { ); } - @action private onNewSnack = () => { const {open, openWhen} = this; @@ -81,16 +69,14 @@ class SnackBarHandler extends Component> { } }; - @action private openNextSnack = () => { - if (this.snackManager?.hasNext()) { + if (this.props.snackManager.hasNext()) { this.open = true; this.openWhen = Date.now(); - this.snackManager.next(); + this.props.snackManager.next(); } }; - @action private closeCurrentSnack = () => (this.open = false); } diff --git a/ui/src/snack/SnackManager.ts b/ui/src/snack/SnackManager.ts index dcaf2170b..33fd53648 100644 --- a/ui/src/snack/SnackManager.ts +++ b/ui/src/snack/SnackManager.ts @@ -1,4 +1,4 @@ -import { action, makeObservable, observable } from 'mobx'; +import { action, observable } from 'mobx'; export interface SnackReporter { (message: string): void; @@ -12,10 +12,6 @@ export class SnackManager { @observable public counter = 0; - constructor() { - makeObservable(this); - } - @action public next = (): void => { if (!this.hasNext()) { diff --git a/ui/src/user/AddEditUserDialog.tsx b/ui/src/user/AddEditUserDialog.tsx index cad98ce8e..d2b316b07 100644 --- a/ui/src/user/AddEditUserDialog.tsx +++ b/ui/src/user/AddEditUserDialog.tsx @@ -55,7 +55,7 @@ export default class AddEditDialog extends Component { className="name" label="Name *" type="email" - value={name} + defaultValue={name} onChange={this.handleChange.bind(this, 'name')} fullWidth /> @@ -63,7 +63,7 @@ export default class AddEditDialog extends Component { margin="dense" className="password" type="password" - value={pass} + defaultValue={pass} fullWidth label={isEdit ? 'Pass (empty if no change)' : 'Pass *'} onChange={this.handleChange.bind(this, 'pass')} diff --git a/ui/src/user/Login.tsx b/ui/src/user/Login.tsx index 7cfb29a44..1a5543b42 100644 --- a/ui/src/user/Login.tsx +++ b/ui/src/user/Login.tsx @@ -4,7 +4,7 @@ import TextField from '@material-ui/core/TextField'; import React, {Component, FormEvent} from 'react'; import Container from '../common/Container'; import DefaultPage from '../common/DefaultPage'; -import { action, makeObservable, observable } from 'mobx'; +import { action, observable } from 'mobx'; import {observer} from 'mobx-react'; import {inject, Stores } from '../inject'; import * as config from '../config'; @@ -19,26 +19,6 @@ class Login extends Component> { @observable private registerDialog = false; - constructor(props: any) { - super(props); - makeObservable(this); - } - - @action - private setUsername = (value: string) => { - this.username = value; - }; - - @action - private setPassword = (value: string) => { - this.password = value; - }; - - @action - private setRegisterDialog = (open: boolean) => { - this.registerDialog = open; - }; - public render() { const {username, password, registerDialog} = this; return ( @@ -53,8 +33,9 @@ class Login extends Component> { label="Username" margin="dense" autoComplete="username" - value={username} - onChange={(e) => this.setUsername(e.target.value)} /> + defaultValue={username} + onChange={(e) => (this.username = e.target.value)} + /> > { label="Password" margin="normal" autoComplete="current-password" - value={password} - onChange={(e) => this.setPassword(e.target.value)} /> + defaultValue={password} + onChange={(e) => (this.password = e.target.value)} + />