customizable "unauthorized" page
Massimo Melina committed
Nov 11, 2023 at 00:09 UTC
b7cbb6f2152b3d49464408ca46ff5ce5e50ff71d
5 files changed
+19
-14
frontend/src/BrowseFiles.ts
+10
-4
@@ -1,6 +1,6 @@
1
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3
-import { Link } from 'react-router-dom'
3
+import { Link, useNavigate } from 'react-router-dom'
4
import { createElement as h, Fragment, memo, MouseEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react'
5
import { useWindowSize } from 'usehooks-ts'
6
import { domOn, formatBytes, ErrorMsg, hIcon, onlyTruthy } from './misc'
@@ -9,7 +9,7 @@ import { Head } from './Head'
9
import { DirEntry, state, useSnapState } from './state'
10
import { alertDialog } from './dialog'
11
import useFetchList from './useFetchList'
12
-import { useAuthorized } from './login'
12
+import { loginDialog, useAuthorized } from './login'
13
import { acceptDropFiles, enqueue } from './upload'
14
import _ from 'lodash'
15
import { t, useI18N } from './i18n'
@@ -20,13 +20,19 @@ export const MISSING_PERM = "Missing permission"
20
export function BrowseFiles() {
21
useFetchList()
22
const { error } = useSnapState()
23
- return useAuthorized() && h(Fragment, {},
23
+ const navigate = useNavigate()
24
+ return useAuthorized() ? h(Fragment, {},
25
h(CustomCode, { name: 'beforeHeader' }),
26
h(Head),
27
h(CustomCode, { name: 'afterHeader' }),
28
error ? h(ErrorMsg, { err: error }) : h(FilesList),
29
h(CustomCode, { name: 'afterList' }),
29
- )
30
+ ) : h(CustomCode, { name: 'unauthorized',
31
+ ifEmpty: () => h('h1', {
32
+ className: 'unauthorized',
33
+ onClick: () => loginDialog(navigate)
34
+ }, t`Unauthorized`)
35
+ })
36
}
37
38
function FilesList() {
frontend/src/components.ts
+1
-1
@@ -82,7 +82,7 @@ export function CustomCode({ name, props, ifEmpty }: { name: string, props?: any
82
if (html?.trim?.())
83
ret.push(h(Html, { key: 'x', code: html }))
84
return ret
85
- }, props ? Object.values(props) : [])
85
+ }, [name, ...props ? Object.values(props) : []])
86
return children.length || !ifEmpty ? h(Fragment, {}, children) : h(ifEmpty)
87
}
88
frontend/src/index.scss
+2
@@ -496,6 +496,8 @@ button label {
496
}
497
}
498
499
+.unauthorized { text-align: center }
500
+
501
#root>.tiles-mode {
502
max-width: none;
503
margin: 0 1em;
frontend/src/login.ts
+5
-8
@@ -109,7 +109,7 @@ export async function loginDialog(navigate: ReturnType<typeof useNavigate>) {
109
going = true
110
try {
111
const res = await login(usr, pwd)
112
- close()
112
+ close(true)
113
if (res?.redirect)
114
navigate(getPrefixUrl() + res.redirect)
115
} catch (err: any) {
@@ -132,13 +132,10 @@ export function useAuthorized() {
132
state.loginRequired = true
133
const navigate = useNavigate()
134
useEffect(() => {
135
- (async () => {
136
- if (!loginRequired)
137
- return closeLoginDialog?.()
138
- if (closeLoginDialog) return
139
- while (state.loginRequired)
140
- await loginDialog(navigate)
141
- })()
135
+ if (!loginRequired)
136
+ return closeLoginDialog?.()
137
+ if (!closeLoginDialog)
138
+ loginDialog(navigate).then()
139
}, [loginRequired, navigate])
140
return loginRequired ? null : true
141
}
src/customHtml.ts
+1
-1
@@ -8,7 +8,7 @@ import { mapPlugins } from './plugins'
8
const FILE = 'custom.html'
9
10
export const customHtmlSections: ReadonlyArray<string> = ['beforeHeader', 'afterHeader', 'afterMenuBar', 'afterList',
11
- 'top', 'bottom', 'afterEntryName', 'beforeLogin']
11
+ 'top', 'bottom', 'afterEntryName', 'beforeLogin', 'unauthorized']
12
13
export const customHtmlState = proxy({
14
sections: watchLoadCustomHtml().state