better code: future-proof api for newDialog
Massimo Melina committed
Jul 13, 2023 at 23:39 UTC
7239345fd56a08f8a9abcffe71f13de78f7d502a
15 files changed
+33
-27
admin/src/AccountsPage.ts
+5
-4
@@ -56,7 +56,7 @@ export default function AccountsPage() {
56
addToBar: isSideBreakpoint && h(IconBtn, { // not really useful, but users misled in thinking it's a dialog will find satisfaction in dismissing the form
57
icon: Close,
58
title: "Close",
59
- onClick: close
59
+ onClick: selectNone
60
}),
61
reload,
62
done(username) {
@@ -66,14 +66,15 @@ export default function AccountsPage() {
66
})
67
useEffect(() => {
68
if (isSideBreakpoint || !sideContent || !sel.length) return
69
- return newDialog({
69
+ const { close } = newDialog({
70
title: _.isString(sel) ? _.startCase(sel)
71
: sel.length > 1 ? "Multiple selection"
72
: selectedAccount ? (selectedAccount.hasPassword ? "User: " : "Group: ") + selectedAccount.username
73
: '?', // never
74
Content: () => sideContent,
75
- onClose: close,
75
+ onClose: selectNone,
76
})
77
+ return close
78
}, [isSideBreakpoint, sel, selectedAccount])
79
80
return element || h(Grid, { container: true, maxWidth: '80em' },
@@ -140,7 +141,7 @@ export default function AccountsPage() {
141
h(Card, {}, h(CardContent, {}, sideContent) )),
142
)
143
143
- function close() {
144
+ function selectNone() {
145
setSel([])
146
}
147
admin/src/FileField.ts
+1
-1
@@ -22,7 +22,7 @@ export default function FileField({ value, onChange, files=true, folders=false,
22
title: "Browse files...",
23
edge: 'end',
24
onClick() {
25
- const close = newDialog({
25
+ const { close } = newDialog({
26
title: title ?? (files ? "Pick a file" : "Pick a folder"),
27
dialogProps: {
28
fullScreen: !large,
admin/src/FileForm.ts
+1
-1
@@ -245,7 +245,7 @@ function LinkField({ value, statusApi }: LinkFieldProps) {
245
)
246
247
function edit() {
248
- const close = newDialog({
248
+ const { close } = newDialog({
249
title: "Change link",
250
Content() {
251
const [v, setV] = useState(base || '')
admin/src/OptionsPage.ts
+1
-1
@@ -312,7 +312,7 @@ function suggestMakingCert() {
312
export async function makeCertAndSave() {
313
if (!window.crypto.subtle)
314
return alertDialog("Retry this procedure on localhost", 'warning')
315
- const close = newDialog({
315
+ const { close } = newDialog({
316
title: "Get a certificate",
317
Content: () => h(Flex, { flexDirection: 'column' },
318
h('p', {}, "HTTPS needs a certificate to work."),
admin/src/VfsPage.ts
+5
-4
@@ -47,7 +47,7 @@ export default function VfsPage() {
47
return b && !ret.includes(b) ? [b, ...ret] : ret
48
}, [status])
49
50
- function close() {
50
+ function selectNone() {
51
state.selectedFiles = []
52
}
53
@@ -56,7 +56,7 @@ export default function VfsPage() {
56
addToBar: isSideBreakpoint && h(IconBtn, { // not really useful, but users misled in thinking it's a dialog will find satisfaction in dismissing the form
57
icon: Close,
58
title: "Close",
59
- onClick: close
59
+ onClick: selectNone
60
}),
61
defaultPerms: data?.defaultPerms as VfsPerms,
62
anyMask,
@@ -76,11 +76,12 @@ export default function VfsPage() {
76
77
useEffect(() => {
78
if (isSideBreakpoint || !sideContent) return
79
- return newDialog({
79
+ const { close } = newDialog({
80
title: selectedFiles.length > 1 ? "Multiple selection" : selectedFiles[0].name,
81
Content: () => sideContent,
82
- onClose: close,
82
+ onClose: selectNone,
83
})
84
+ return close
85
},[isSideBreakpoint, selectedFiles])
86
87
useEffect(() => {
admin/src/addFiles.ts
+1
-1
@@ -10,7 +10,7 @@ import FilePicker from './FilePicker'
10
import { onlyTruthy } from './misc'
11
12
export default function addFiles() {
13
- const close = newDialog({
13
+ const { close } = newDialog({
14
title: "Add files or folders",
15
dialogProps: { sx:{ minWidth: 'min(90vw, 40em)', minHeight: 'calc(100vh - 9em)' } },
16
Content() {
admin/src/dialog.ts
+3
-3
@@ -94,7 +94,7 @@ export async function alertDialog(msg: ReactElement | string | Error, options?:
94
msg = msg.message || String(msg)
95
type = 'error'
96
}
97
- const close = newDialog({
97
+ const { close } = newDialog({
98
className: 'dialog-alert-' + type,
99
icon: '!',
100
onClose: resolve,
@@ -208,12 +208,12 @@ export async function promptDialog(msg: string, props:any={}) : Promise<string |
208
}
209
210
export function waitDialog() {
211
- return newDialog({ Content: CircularProgress, closable: false })
211
+ return newDialog({ Content: CircularProgress, closable: false }).close
212
}
213
214
export function toast(msg: string | ReactElement, type: AlertType | ReactElement='info') {
215
const ms = 3000
216
- const close = newDialog({
216
+ const { close } = newDialog({
217
Content,
218
dialogProps: {
219
PaperProps: {
admin/src/importAccountsCsv.ts
+1
-1
@@ -57,7 +57,7 @@ export async function importAccountsCsv(cb?: () => void) {
57
},
58
})
59
if (!cfg) return
60
- const close = newDialog({
60
+ const { close } = newDialog({
61
title: "Importing...",
62
Content() {
63
const [progress, setProgress] = useState(0)
frontend/src/dialog.ts
+2
-2
@@ -72,7 +72,7 @@ export async function alertDialog(msg: ReactElement | string | Error, type:Alert
72
icon: '!',
73
onClose: resolve,
74
Content
75
- })))
75
+ }).close))
76
77
function Content(){
78
if (msg instanceof Error)
@@ -102,7 +102,7 @@ export async function confirmDialog(msg: ReactElement | string, options: Confirm
102
onClose: resolve,
103
...rest,
104
Content
105
- })) )
105
+ }).close) )
106
107
function Content() {
108
const [sec,setSec] = useState(Math.ceil(timeout||0))
frontend/src/fileMenu.ts
+1
-1
@@ -56,7 +56,7 @@ export function openFileMenu(entry: DirEntry, ev: MouseEvent, addToMenu: (FileMe
56
if (res)
57
menu.push(...res.flat())
58
const ico = getEntryIcon(entry)
59
- const close = newDialog({
59
+ const { close } = newDialog({
60
title: isFolder ? t`Folder menu` : t`File menu`,
61
className: 'file-dialog',
62
icon: () => ico,
frontend/src/login.ts
+4
-3
@@ -45,7 +45,7 @@ export async function loginDialog(navigate: ReturnType<typeof useNavigate>) {
45
return lastPromise = new Promise(resolve => {
46
if (closeLoginDialog)
47
return lastPromise
48
- const closeDialog = closeLoginDialog = newDialog({
48
+ const { close } = newDialog({
49
className: 'login-dialog dialog-login',
50
icon: () => hIcon('login'),
51
onClose(v) {
@@ -95,7 +95,7 @@ export async function loginDialog(navigate: ReturnType<typeof useNavigate>) {
95
function onKeyDown(ev: KeyboardEvent) {
96
const { key } = ev
97
if (key === 'Escape')
98
- return closeDialog(null)
98
+ return close(null)
99
if (key === 'Enter')
100
return go()
101
}
@@ -107,7 +107,7 @@ export async function loginDialog(navigate: ReturnType<typeof useNavigate>) {
107
if (!usr || !pwd) return
108
try {
109
const res = await login(usr, pwd)
110
- closeDialog()
110
+ close()
111
if (res?.redirect)
112
navigate(getPrefixUrl() + res.redirect)
113
} catch (err: any) {
@@ -118,6 +118,7 @@ export async function loginDialog(navigate: ReturnType<typeof useNavigate>) {
118
119
}
120
})
121
+ closeLoginDialog = close
122
})
123
}
124
frontend/src/misc.ts
+2
-1
@@ -42,7 +42,7 @@ export function working() {
42
if (isWorking)
43
return ()=>{} // noop
44
isWorking = true
45
- return newDialog({
45
+ const { close } = newDialog({
46
closable: false,
47
noFrame: true,
48
Content: Spinner,
@@ -52,6 +52,7 @@ export function working() {
52
isWorking = false
53
}
54
})
55
+ return close
56
}
57
58
export function hfsEvent(name: string, params?:Dict) {
frontend/src/show.ts
+1
-1
@@ -8,7 +8,7 @@ import { openFileMenu } from './fileMenu'
8
import { useI18N } from './i18n'
9
10
export function fileShow(entry: DirEntry) {
11
- const close = newDialog({
11
+ const { close } = newDialog({
12
noFrame: true,
13
className: 'file-show',
14
Content() {
frontend/src/upload.ts
+1
-1
@@ -82,7 +82,7 @@ export function showUpload() {
82
if (!uploadState.qs.length)
83
resetCounters()
84
uploadDialogIsOpen = true
85
- const close = newDialog({
85
+ const { close } = newDialog({
86
dialogProps: { id: 'upload-dialog', style: { minHeight: '6em', minWidth: 'min(20em, 100vw - 1em)' } },
87
title: t`Upload`,
88
icon: () => hIcon('upload'),
shared/dialogs.ts
+4
-2
@@ -22,7 +22,7 @@ export interface DialogOptions {
22
}
23
24
const dialogs = proxy<DialogOptions[]>([])
25
-export type DialogCloser = ReturnType<typeof newDialog>
25
+export type DialogCloser = ReturnType<typeof newDialog>['close']
26
27
export const dialogsDefaults: Partial<DialogOptions> = {
28
closableContent: 'x',
@@ -103,7 +103,9 @@ export function newDialog(options: DialogOptions) {
103
const $id = Math.random()
104
options.$id = $id // object identity is not working because of the proxy. This is a possible workaround
105
dialogs.push(options)
106
- return (v?:any) => {
106
+ return { close }
107
+
108
+ function close(v?:any) {
109
const i = dialogs.findIndex(x => (x as any).$id === $id)
110
if (i < 0) return
111
dialogs.splice(i,1)