ux: admin: avoid disabling the save button when changes are yet to be detected, so that the user doesn't falsely perceive that it's not possible to save yet
Massimo Melina committed
Mar 16, 2022 at 16:14 UTC
2f9f807e1cef06fff45e3df35ea8f88d586ff89f
4 files changed
+10
-6
admin/src/AccountsPage.ts
+2
-2
@@ -6,7 +6,7 @@ import { Box, Button, Card, CardContent, Grid, List, ListItem, ListItemText, Typ
6
import { Delete, Group, MilitaryTech, Person, PersonAdd, Refresh } from '@mui/icons-material'
7
import { BoolField, Form, MultiSelectField, StringField } from './Form'
8
import { alertDialog, confirmDialog } from './dialog'
9
-import { iconTooltip, isEqualLax, onlyTruthy } from './misc'
9
+import { iconTooltip, isEqualLax, modifiedSx, onlyTruthy } from './misc'
10
import { TreeItem, TreeView } from '@mui/lab'
11
import { makeStyles } from '@mui/styles'
12
import { createVerifierAndSalt, SRPParameters, SRPRoutines } from 'tssrp6a'
@@ -189,7 +189,7 @@ function AccountForm({ account, done, groups }: { account: Account, groups: stri
189
],
190
onError: alertDialog,
191
save: {
192
- disabled: isEqualLax(values, account),
192
+ sx: modifiedSx( !isEqualLax(values, account)),
193
async onClick() {
194
const { password='', password2, ...withoutPassword } = values
195
const { username } = values
admin/src/ConfigPage.ts
+2
-2
@@ -5,7 +5,7 @@ import { createElement as h, isValidElement, useEffect, useRef } from 'react';
5
import { apiCall, useApi, useApiComp } from './api'
6
import { state, useSnapState } from './state'
7
import { Refresh } from '@mui/icons-material'
8
-import { Dict } from './misc'
8
+import { Dict, modifiedSx } from './misc'
9
import { subscribeKey } from 'valtio/utils'
10
import { Form, BoolField, NumberField, StringField, SelectField, FieldProps, Field } from './Form';
11
import StringStringField from './StringStringField'
@@ -41,7 +41,7 @@ export default function ConfigPage() {
41
onError: alertDialog,
42
save: {
43
onClick: save,
44
- disabled: !Object.keys(changes).length,
44
+ sx: modifiedSx( Object.keys(changes).length>0),
45
},
46
barSx: { gap: 2 },
47
addToBar: [h(Button, {
admin/src/FileCard.ts
+2
-2
@@ -5,7 +5,7 @@ import { createElement as h, useEffect, useMemo, useState } from 'react'
5
import { Card, CardContent, List, ListItem, ListItemText } from '@mui/material'
6
import { BoolField, DisplayField, Field, FieldProps, Form, MultiSelectField, SelectField } from './Form'
7
import { apiCall, useApi } from './api'
8
-import { formatBytes, isEqualLax, onlyTruthy } from './misc'
8
+import { formatBytes, isEqualLax, modifiedSx, onlyTruthy } from './misc'
9
import { reloadVfs, Who } from './VfsPage'
10
import md from './md'
11
import _ from 'lodash'
@@ -62,7 +62,7 @@ function FileForm({ file }: { file: ReturnType<typeof useSnapState>['selectedFil
62
setValues({ ...values, [k]: v })
63
},
64
save: {
65
- disabled: isEqualLax(values, file),
65
+ sx: modifiedSx(!isEqualLax(values, file)),
66
async onClick() {
67
const props = _.pickBy(values, (v,k) =>
68
v !== file[k as keyof typeof values])
admin/src/misc.ts
+4
@@ -24,6 +24,10 @@ export function isEqualLax(a: any,b: any): boolean {
24
&& Object.entries(a).every(([k,v]) => isEqualLax(v, b[k])) )
25
}
26
27
+export function modifiedSx(is: boolean) {
28
+ return is ? { outline: '2px solid' } : undefined
29
+}
30
+
31
export function IconBtn({ title, icon, onClick, ...rest }: { title?: string, icon: SvgIconComponent, [rest:string]:any }) {
32
const [loading, setLoading] = useStateMounted(false)
33
const ret = h(IconButton, {