hfs 0.26.8 → 0.26.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/assets/index.bb5198ec.js +281 -0
- package/admin/assets/index.dcc78777.css +1 -0
- package/admin/assets/sha512.9dfe82e1.js +8 -0
- package/admin/index.html +3 -1
- package/admin/{public/logo.svg → logo.svg} +0 -0
- package/frontend/assets/index.27a78796.js +85 -0
- package/frontend/assets/index.93366732.css +1 -0
- package/frontend/assets/sha512.6af42937.js +8 -0
- package/frontend/{public/fontello.css → fontello.css} +0 -0
- package/frontend/{public/fontello.woff2 → fontello.woff2} +0 -0
- package/frontend/index.html +3 -1
- package/package.json +1 -1
- package/src/QuickZipStream.js +285 -0
- package/src/ThrottledStream.js +93 -0
- package/src/adminApis.js +169 -0
- package/src/api.accounts.js +59 -0
- package/src/api.auth.js +128 -0
- package/src/api.file_list.js +103 -0
- package/src/api.helpers.js +32 -0
- package/src/api.monitor.js +102 -0
- package/src/api.plugins.js +127 -0
- package/src/api.vfs.js +164 -0
- package/src/apiMiddleware.js +120 -0
- package/src/block.js +33 -0
- package/src/commands.js +124 -0
- package/src/config.js +168 -0
- package/src/connections.js +57 -0
- package/src/const.js +83 -0
- package/src/crypt.js +21 -0
- package/src/debounceAsync.js +48 -0
- package/src/events.js +9 -0
- package/src/frontEndApis.js +38 -0
- package/src/github.js +102 -0
- package/src/index.js +56 -0
- package/src/listen.js +235 -0
- package/src/log.js +137 -0
- package/src/middlewares.js +175 -0
- package/src/misc.js +160 -0
- package/src/pbkdf2.js +74 -0
- package/src/perm.js +181 -0
- package/src/plugins.js +343 -0
- package/src/serveFile.js +105 -0
- package/src/serveGuiFiles.js +113 -0
- package/src/sse.js +29 -0
- package/src/throttler.js +91 -0
- package/src/update.js +69 -0
- package/src/util-files.js +148 -0
- package/src/util-generators.js +30 -0
- package/src/util-http.js +30 -0
- package/src/vfs.js +230 -0
- package/src/watchLoad.js +73 -0
- package/src/zip.js +72 -0
- package/admin/.DS_Store +0 -0
- package/admin/.eslintrc +0 -8
- package/admin/.gitignore +0 -23
- package/admin/package.json +0 -67
- package/admin/src/AccountForm.ts +0 -92
- package/admin/src/AccountsPage.ts +0 -143
- package/admin/src/App.ts +0 -83
- package/admin/src/ArrayField.ts +0 -84
- package/admin/src/ConfigPage.ts +0 -279
- package/admin/src/FileField.ts +0 -52
- package/admin/src/FileForm.ts +0 -148
- package/admin/src/FilePicker.ts +0 -166
- package/admin/src/HomePage.ts +0 -96
- package/admin/src/InstalledPlugins.ts +0 -158
- package/admin/src/LoginRequired.ts +0 -75
- package/admin/src/LogoutPage.ts +0 -27
- package/admin/src/LogsPage.ts +0 -75
- package/admin/src/MainMenu.ts +0 -74
- package/admin/src/MenuButton.ts +0 -38
- package/admin/src/MonitorPage.ts +0 -200
- package/admin/src/OnlinePlugins.ts +0 -101
- package/admin/src/PermField.ts +0 -80
- package/admin/src/PluginsPage.ts +0 -27
- package/admin/src/VfsMenuBar.ts +0 -58
- package/admin/src/VfsPage.ts +0 -124
- package/admin/src/VfsTree.ts +0 -95
- package/admin/src/addFiles.ts +0 -59
- package/admin/src/api.ts +0 -246
- package/admin/src/dialog.ts +0 -203
- package/admin/src/index.css +0 -21
- package/admin/src/index.ts +0 -10
- package/admin/src/md.ts +0 -31
- package/admin/src/misc.ts +0 -141
- package/admin/src/react-app-env.d.ts +0 -1
- package/admin/src/reportWebVitals.ts +0 -15
- package/admin/src/setupTests.ts +0 -5
- package/admin/src/state.ts +0 -40
- package/admin/src/theme.ts +0 -37
- package/admin/tsconfig.json +0 -26
- package/admin/vite.config.ts +0 -32
- package/frontend/.DS_Store +0 -0
- package/frontend/.eslintrc +0 -8
- package/frontend/.gitignore +0 -23
- package/frontend/package.json +0 -51
- package/frontend/src/App.ts +0 -25
- package/frontend/src/Breadcrumbs.ts +0 -43
- package/frontend/src/BrowseFiles.ts +0 -141
- package/frontend/src/Head.ts +0 -45
- package/frontend/src/UserPanel.ts +0 -52
- package/frontend/src/api.ts +0 -78
- package/frontend/src/components.ts +0 -54
- package/frontend/src/dialog.css +0 -76
- package/frontend/src/dialog.ts +0 -105
- package/frontend/src/icons.ts +0 -46
- package/frontend/src/index.scss +0 -307
- package/frontend/src/index.ts +0 -10
- package/frontend/src/login.ts +0 -50
- package/frontend/src/menu.ts +0 -188
- package/frontend/src/misc.ts +0 -54
- package/frontend/src/options.ts +0 -52
- package/frontend/src/react-app-env.d.ts +0 -1
- package/frontend/src/reportWebVitals.ts +0 -15
- package/frontend/src/setupTests.ts +0 -5
- package/frontend/src/state.ts +0 -82
- package/frontend/src/useAuthorized.ts +0 -17
- package/frontend/src/useFetchList.ts +0 -144
- package/frontend/src/useTheme.ts +0 -23
- package/frontend/tsconfig.json +0 -26
- package/frontend/vite.config.ts +0 -21
- package/src/QuickZipStream.ts +0 -279
- package/src/ThrottledStream.ts +0 -98
- package/src/adminApis.ts +0 -161
- package/src/api.accounts.ts +0 -78
- package/src/api.auth.ts +0 -131
- package/src/api.file_list.ts +0 -102
- package/src/api.helpers.ts +0 -30
- package/src/api.monitor.ts +0 -106
- package/src/api.plugins.ts +0 -139
- package/src/api.vfs.ts +0 -182
- package/src/apiMiddleware.ts +0 -124
- package/src/block.ts +0 -35
- package/src/commands.ts +0 -122
- package/src/config.ts +0 -166
- package/src/connections.ts +0 -60
- package/src/const.ts +0 -57
- package/src/crypt.ts +0 -16
- package/src/debounceAsync.ts +0 -51
- package/src/events.ts +0 -6
- package/src/frontEndApis.ts +0 -17
- package/src/github.ts +0 -102
- package/src/index.ts +0 -53
- package/src/listen.ts +0 -220
- package/src/log.ts +0 -128
- package/src/middlewares.ts +0 -176
- package/src/misc.ts +0 -149
- package/src/pbkdf2.ts +0 -83
- package/src/perm.ts +0 -194
- package/src/plugins.ts +0 -342
- package/src/serveFile.ts +0 -104
- package/src/serveGuiFiles.ts +0 -95
- package/src/sse.ts +0 -29
- package/src/throttler.ts +0 -106
- package/src/update.ts +0 -67
- package/src/util-files.ts +0 -137
- package/src/util-generators.ts +0 -29
- package/src/util-http.ts +0 -29
- package/src/vfs.ts +0 -258
- package/src/watchLoad.ts +0 -75
- package/src/zip.ts +0 -69
package/admin/src/dialog.ts
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
// This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
Box,
|
|
5
|
-
Button,
|
|
6
|
-
CircularProgress,
|
|
7
|
-
Dialog as MuiDialog,
|
|
8
|
-
DialogContent,
|
|
9
|
-
DialogProps,
|
|
10
|
-
DialogTitle,
|
|
11
|
-
IconButton
|
|
12
|
-
} from '@mui/material'
|
|
13
|
-
import {
|
|
14
|
-
createElement as h, Fragment,
|
|
15
|
-
isValidElement,
|
|
16
|
-
ReactElement,
|
|
17
|
-
useEffect,
|
|
18
|
-
useRef,
|
|
19
|
-
useState
|
|
20
|
-
} from 'react'
|
|
21
|
-
import { Check, Close, Error as ErrorIcon, Forward, Info, Warning } from '@mui/icons-material'
|
|
22
|
-
import { newDialog, closeDialog, dialogsDefaults, DialogOptions } from '@hfs/shared'
|
|
23
|
-
import { Form, FormProps } from '@hfs/mui-grid-form'
|
|
24
|
-
import { useBreakpoint } from './misc'
|
|
25
|
-
import { Flex } from '@hfs/frontend/src/components'
|
|
26
|
-
export * from '@hfs/shared/lib/dialogs'
|
|
27
|
-
|
|
28
|
-
dialogsDefaults.Container = function Container(d:DialogOptions) {
|
|
29
|
-
useEffect(()=>{
|
|
30
|
-
ref.current?.focus()
|
|
31
|
-
}, [])
|
|
32
|
-
const ref = useRef<HTMLElement>()
|
|
33
|
-
d = { ...dialogsDefaults, ...d }
|
|
34
|
-
const { sx, root, ...rest } = d.dialogProps||{}
|
|
35
|
-
const p = d.padding ? 2 : 0
|
|
36
|
-
return h(MuiDialog, {
|
|
37
|
-
open: true,
|
|
38
|
-
maxWidth: 'lg',
|
|
39
|
-
fullScreen: !useBreakpoint('sm'),
|
|
40
|
-
...rest,
|
|
41
|
-
...root,
|
|
42
|
-
onClose: ()=> closeDialog(),
|
|
43
|
-
},
|
|
44
|
-
d.title && h(DialogTitle, {}, d.title),
|
|
45
|
-
h(DialogContent, {
|
|
46
|
-
ref,
|
|
47
|
-
sx: { ...sx, px: p, pb: p, display: 'flex', flexDirection: 'column', }
|
|
48
|
-
}, h(d.Content) )
|
|
49
|
-
)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
type AlertType = 'error' | 'warning' | 'info' | 'success'
|
|
53
|
-
|
|
54
|
-
const type2ico = {
|
|
55
|
-
error: ErrorIcon,
|
|
56
|
-
warning: Warning,
|
|
57
|
-
info: Info,
|
|
58
|
-
success: Check,
|
|
59
|
-
}
|
|
60
|
-
export async function alertDialog(msg: ReactElement | string | Error, options?: AlertType | ({ type?:AlertType, icon?: ReactElement } & Partial<DialogOptions>)) {
|
|
61
|
-
return new Promise(resolve => {
|
|
62
|
-
const opt = typeof options === 'string' ? { type: options } : (options ?? {})
|
|
63
|
-
let { type='info', ...rest } = opt
|
|
64
|
-
if (msg instanceof Error) {
|
|
65
|
-
msg = msg.message || String(msg)
|
|
66
|
-
type = 'error'
|
|
67
|
-
}
|
|
68
|
-
const close = newDialog({
|
|
69
|
-
className: 'dialog-alert-' + type,
|
|
70
|
-
icon: '!',
|
|
71
|
-
onClose: resolve,
|
|
72
|
-
...rest,
|
|
73
|
-
Content() {
|
|
74
|
-
return h(Box, { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 1 },
|
|
75
|
-
h(IconButton, {
|
|
76
|
-
onClick() {
|
|
77
|
-
close()
|
|
78
|
-
},
|
|
79
|
-
size: 'small',
|
|
80
|
-
sx: { position: 'absolute', right: 0, top: 0, opacity: .5 }
|
|
81
|
-
}, h(Close)),
|
|
82
|
-
opt.icon ?? h(type2ico[type], { color: type, fontSize: 'large' }),
|
|
83
|
-
isValidElement(msg) ? msg
|
|
84
|
-
: h(Box, { fontSize: 'large', mb: 1, lineHeight: '1.8em' }, String(msg)),
|
|
85
|
-
)
|
|
86
|
-
}
|
|
87
|
-
})
|
|
88
|
-
})
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
interface ConfirmOptions { href?: string }
|
|
92
|
-
export async function confirmDialog(msg: string | ReactElement, { href }: ConfirmOptions={}) : Promise<boolean> {
|
|
93
|
-
return new Promise(resolve => newDialog({
|
|
94
|
-
className: 'dialog-confirm',
|
|
95
|
-
icon: '?',
|
|
96
|
-
onClose: resolve,
|
|
97
|
-
Content
|
|
98
|
-
}) )
|
|
99
|
-
|
|
100
|
-
function Content() {
|
|
101
|
-
return h(Fragment, {},
|
|
102
|
-
h(Box, { mb: 2 }, msg),
|
|
103
|
-
h(Flex, {},
|
|
104
|
-
h('a', {
|
|
105
|
-
href,
|
|
106
|
-
onClick: () => closeDialog(true),
|
|
107
|
-
}, h(Button, { variant: 'contained' }, "Confirm")),
|
|
108
|
-
h(Button, { onClick: () => closeDialog(false) }, "Don't"),
|
|
109
|
-
),
|
|
110
|
-
)
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
type FormDialog<T> = Pick<DialogProps, 'fullScreen' | 'title'>
|
|
115
|
-
& Pick<DialogOptions, 'dialogProps'>
|
|
116
|
-
& Omit<FormProps<T>, 'values' | 'save' | 'set'>
|
|
117
|
-
& Partial<Pick<FormProps<T>, 'values' | 'save'>>
|
|
118
|
-
& {
|
|
119
|
-
onChange?: (values:Partial<T>, extra: { setValues: React.Dispatch<React.SetStateAction<Partial<T>>> }) => void,
|
|
120
|
-
before?: any
|
|
121
|
-
}
|
|
122
|
-
export async function formDialog<T>({ fullScreen, title, onChange, before, ...props }: FormDialog<T>) : Promise<T> {
|
|
123
|
-
return new Promise(resolve => newDialog({
|
|
124
|
-
className: 'dialog-confirm',
|
|
125
|
-
icon: '?',
|
|
126
|
-
onClose: resolve,
|
|
127
|
-
title,
|
|
128
|
-
Content
|
|
129
|
-
}) )
|
|
130
|
-
|
|
131
|
-
function Content() {
|
|
132
|
-
const [values, setValues] = useState<Partial<T>>(props.values||{})
|
|
133
|
-
return h(Fragment, {},
|
|
134
|
-
before,
|
|
135
|
-
h(Form, {
|
|
136
|
-
...props,
|
|
137
|
-
values,
|
|
138
|
-
set(v, k) {
|
|
139
|
-
const newV = { ...values, [k]: v }
|
|
140
|
-
setValues(newV)
|
|
141
|
-
onChange?.(newV, { setValues })
|
|
142
|
-
},
|
|
143
|
-
save: {
|
|
144
|
-
...props.save,
|
|
145
|
-
onClick() {
|
|
146
|
-
closeDialog(values)
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
})
|
|
150
|
-
)
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export async function promptDialog(msg: string, props:any={}) : Promise<string | undefined> {
|
|
155
|
-
return formDialog<{ text: string }>({
|
|
156
|
-
...props,
|
|
157
|
-
fields: [
|
|
158
|
-
{ k: 'text', label: null, autoFocus: true,
|
|
159
|
-
before: h(Box, { mb: 2 }, msg),
|
|
160
|
-
...props.field
|
|
161
|
-
},
|
|
162
|
-
],
|
|
163
|
-
save: {
|
|
164
|
-
children: "Continue",
|
|
165
|
-
startIcon: h(Forward),
|
|
166
|
-
...props.save,
|
|
167
|
-
},
|
|
168
|
-
saveOnEnter: true,
|
|
169
|
-
barSx: { gap: 2 },
|
|
170
|
-
addToBar: [
|
|
171
|
-
h(Button, { onClick: closeDialog }, "Cancel"),
|
|
172
|
-
...props.addToBar||[],
|
|
173
|
-
]
|
|
174
|
-
}).then(values => values?.text)
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
export function waitDialog() {
|
|
178
|
-
return newDialog({ Content: CircularProgress, closable: false })
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export function toast(msg: string | ReactElement, type: AlertType | ReactElement='info') {
|
|
182
|
-
const ms = 3000
|
|
183
|
-
const close = newDialog({
|
|
184
|
-
Content,
|
|
185
|
-
dialogProps: {
|
|
186
|
-
PaperProps: {
|
|
187
|
-
sx: { transition: `opacity ${ms}ms ease-in` },
|
|
188
|
-
ref(x: HTMLElement) { // we need to set opacity later, to trigger transition
|
|
189
|
-
if (x)
|
|
190
|
-
x.style.opacity = '0'
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
})
|
|
195
|
-
setTimeout(close, ms)
|
|
196
|
-
|
|
197
|
-
function Content(){
|
|
198
|
-
return h(Box, { display:'flex', flexDirection: 'column', alignItems: 'center', gap: 1 },
|
|
199
|
-
isValidElement(type) ? type : h(type2ico[type], { color:type }),
|
|
200
|
-
isValidElement(msg) ? msg : h('div', {}, String(msg))
|
|
201
|
-
)
|
|
202
|
-
}
|
|
203
|
-
}
|
package/admin/src/index.css
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
body {
|
|
2
|
-
margin: 0;
|
|
3
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
4
|
-
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
5
|
-
sans-serif;
|
|
6
|
-
-webkit-font-smoothing: antialiased;
|
|
7
|
-
-moz-osx-font-smoothing: grayscale;
|
|
8
|
-
height: 100vh;
|
|
9
|
-
}
|
|
10
|
-
#root { min-height: 100%; display:flex; }
|
|
11
|
-
|
|
12
|
-
code {
|
|
13
|
-
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
|
14
|
-
monospace;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.MuiTreeItem-content {
|
|
18
|
-
box-sizing: border-box; /* avoid unwanted scrolling caused by its width:100% + padding */
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
ol, ul { margin-top: .2em }
|
package/admin/src/index.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
|
|
2
|
-
|
|
3
|
-
import { createElement as h, StrictMode } from 'react'
|
|
4
|
-
import { createRoot } from 'react-dom/client'
|
|
5
|
-
import './index.css'
|
|
6
|
-
import '@hfs/shared/src/min-crypto-polyfill'
|
|
7
|
-
import App from './App'
|
|
8
|
-
|
|
9
|
-
createRoot(document.getElementById('root')!)
|
|
10
|
-
.render( h(StrictMode, {}, h(App)) )
|
package/admin/src/md.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
|
|
2
|
-
|
|
3
|
-
import { createElement as h, Fragment } from 'react'
|
|
4
|
-
|
|
5
|
-
// markdown inspired syntax to transform text into react elements: * for bold, / for italic, _ for underline, ` for code
|
|
6
|
-
export default function md(text: string | TemplateStringsArray) {
|
|
7
|
-
if (typeof text !== 'string')
|
|
8
|
-
text = text[0]
|
|
9
|
-
const re = /([`*/_])(.+)\1|(\n)/g
|
|
10
|
-
const res = []
|
|
11
|
-
let last = 0
|
|
12
|
-
let match
|
|
13
|
-
while (match = re.exec(text)) { //eslint-disable-line no-cond-assign
|
|
14
|
-
res.push( text.slice(last, match.index) )
|
|
15
|
-
if (match[3])
|
|
16
|
-
res.push(h('br'))
|
|
17
|
-
else {
|
|
18
|
-
const tag = ({
|
|
19
|
-
'`': 'code',
|
|
20
|
-
'*': 'b',
|
|
21
|
-
'/': 'i',
|
|
22
|
-
'_': 'u',
|
|
23
|
-
})[ match[1] ]
|
|
24
|
-
if (!tag)
|
|
25
|
-
throw Error("should never happen")
|
|
26
|
-
res.push( h(tag,{}, match[2]) )
|
|
27
|
-
}
|
|
28
|
-
last = match.index + match[0].length
|
|
29
|
-
}
|
|
30
|
-
return h(Fragment, {}, ...res, text.slice(last, Infinity))
|
|
31
|
-
}
|
package/admin/src/misc.ts
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
// This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
|
|
2
|
-
|
|
3
|
-
import { createElement as h, FC, ReactNode } from 'react'
|
|
4
|
-
import { Box, Breakpoint, CircularProgress, IconButton, Link, Tooltip, useMediaQuery } from '@mui/material'
|
|
5
|
-
import { Link as RouterLink } from 'react-router-dom'
|
|
6
|
-
import { SxProps } from '@mui/system'
|
|
7
|
-
import { SvgIconComponent } from '@mui/icons-material'
|
|
8
|
-
import { alertDialog, confirmDialog } from './dialog'
|
|
9
|
-
import { apiCall } from './api'
|
|
10
|
-
import { onlyTruthy, useStateMounted } from '@hfs/shared'
|
|
11
|
-
export * from '@hfs/shared'
|
|
12
|
-
|
|
13
|
-
export function spinner() {
|
|
14
|
-
return h(CircularProgress)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function isWindowsDrive(s?: string) {
|
|
18
|
-
return s && /^[a-zA-Z]:$/.test(s)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function isEqualLax(a: any,b: any): boolean {
|
|
22
|
-
return a == b //eslint-disable-line
|
|
23
|
-
|| (a && b && typeof a === 'object' && typeof b === 'object'
|
|
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
|
-
interface IconBtnProps {
|
|
32
|
-
title?: ReactNode
|
|
33
|
-
icon: SvgIconComponent
|
|
34
|
-
disabled?: boolean | string
|
|
35
|
-
progress?: boolean | number
|
|
36
|
-
link?: string
|
|
37
|
-
confirm?: string
|
|
38
|
-
[rest: string]: any
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function IconBtn({ title, icon, onClick, disabled, progress, link, tooltipProps, confirm, ...rest }: IconBtnProps) {
|
|
42
|
-
const [loading, setLoading] = useStateMounted(false)
|
|
43
|
-
if (typeof disabled === 'string')
|
|
44
|
-
title = disabled
|
|
45
|
-
if (link)
|
|
46
|
-
onClick = () => window.open(link)
|
|
47
|
-
let ret: ReturnType<FC> = h(IconButton, {
|
|
48
|
-
disabled: Boolean(loading || progress || disabled),
|
|
49
|
-
...rest,
|
|
50
|
-
async onClick() {
|
|
51
|
-
if (confirm && !await confirmDialog(confirm)) return
|
|
52
|
-
const ret = onClick?.apply(this,arguments)
|
|
53
|
-
if (ret && ret instanceof Promise) {
|
|
54
|
-
setLoading(true)
|
|
55
|
-
ret.catch(alertDialog).finally(()=> setLoading(false))
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}, h(icon))
|
|
59
|
-
if ((progress || loading) && progress !== false) // false is also useful to inhibit behavior with loading
|
|
60
|
-
ret = h(Box, { position:'relative', display: 'inline-block' },
|
|
61
|
-
h(CircularProgress, {
|
|
62
|
-
...(typeof progress === 'number' ? { value: progress*100, variant: 'determinate' } : null),
|
|
63
|
-
style: { position:'absolute', top: 4, left: 4, width: 32, height: 32 }
|
|
64
|
-
}),
|
|
65
|
-
ret
|
|
66
|
-
)
|
|
67
|
-
if (title)
|
|
68
|
-
ret = h(Tooltip, { title, ...tooltipProps, children: h('span',{},ret) })
|
|
69
|
-
return ret
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function iconTooltip(icon: SvgIconComponent, tooltip: string, sx?: SxProps) {
|
|
73
|
-
return h(Tooltip, { title: tooltip, children: h(icon, { sx }) })
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function InLink(props:any) {
|
|
77
|
-
return h(Link, { component: RouterLink, ...props })
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function Center(props: any) {
|
|
81
|
-
return h(Box, { display:'flex', height:'100%', width:'100%', justifyContent:'center', alignItems:'center', ...props })
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export async function manipulateConfig(k: string, work:(data:any) => any) {
|
|
85
|
-
const cfg = await apiCall('get_config', { only: [k] })
|
|
86
|
-
const was = cfg[k]
|
|
87
|
-
const will = await work(was)
|
|
88
|
-
if (JSON.stringify(was) !== JSON.stringify(will))
|
|
89
|
-
await apiCall('set_config', { values: { [k]: will } })
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export function typedKeys<T extends {}>(o: T) {
|
|
93
|
-
return Object.keys(o) as (keyof T)[]
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export function dirname(s: string) {
|
|
97
|
-
let i = s.lastIndexOf('/')
|
|
98
|
-
if (i < 0)
|
|
99
|
-
i = s.lastIndexOf('\\')
|
|
100
|
-
return i < 0 ? '' : s.slice(0, i)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export function isAbsolutePath(s: string) {
|
|
104
|
-
return s && (s[0] === '/' || isWindowsDrive(s.slice(0,2)))
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export function pathJoin(...args: any[]) {
|
|
108
|
-
const delimiter = findFirst(args, x => /\\|\//.exec('\\a/b')?.[0])
|
|
109
|
-
const good = onlyTruthy(args.map(x => x == null ? '' : String(x)))
|
|
110
|
-
return good.map((x, i) => i === good.length-1 || x.endsWith('\\') || x.endsWith('/') ? x : x + delimiter)
|
|
111
|
-
.join('')
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export function findFirst<I=any, O=any>(a: I[], cb:(v:I)=>O): any {
|
|
115
|
-
for (const x of a) {
|
|
116
|
-
const ret = cb(x)
|
|
117
|
-
if (ret !== undefined)
|
|
118
|
-
return ret
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export function xlate(input: any, table: Record<string, any>) {
|
|
123
|
-
return table[input] ?? input
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// return true if same size or larger
|
|
127
|
-
export function useBreakpoint(breakpoint: Breakpoint) {
|
|
128
|
-
return useMediaQuery((theme: any) => theme.breakpoints.up(breakpoint), { noSsr:true }) // without noSsr, first execution always returns false
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export function err2msg(code: string) {
|
|
132
|
-
return {
|
|
133
|
-
ENOENT: "Not found",
|
|
134
|
-
ENOTDIR: "Not a folder",
|
|
135
|
-
}[code] || code
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export function wantArray<T>(x?: void | T | T[]) {
|
|
139
|
-
return x == null ? [] : Array.isArray(x) ? x : [x]
|
|
140
|
-
}
|
|
141
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/// <reference types="react-scripts" />
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { ReportHandler } from 'web-vitals';
|
|
2
|
-
|
|
3
|
-
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
|
4
|
-
if (onPerfEntry && onPerfEntry instanceof Function) {
|
|
5
|
-
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
|
6
|
-
getCLS(onPerfEntry);
|
|
7
|
-
getFID(onPerfEntry);
|
|
8
|
-
getFCP(onPerfEntry);
|
|
9
|
-
getLCP(onPerfEntry);
|
|
10
|
-
getTTFB(onPerfEntry);
|
|
11
|
-
});
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export default reportWebVitals;
|
package/admin/src/setupTests.ts
DELETED
package/admin/src/state.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
// This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
|
|
2
|
-
|
|
3
|
-
import { proxy, useSnapshot } from 'valtio'
|
|
4
|
-
import { Dict } from './misc'
|
|
5
|
-
import { VfsNode } from './VfsPage'
|
|
6
|
-
import _ from 'lodash'
|
|
7
|
-
import { subscribeKey } from 'valtio/utils'
|
|
8
|
-
|
|
9
|
-
const STORAGE_KEY = 'admin_state'
|
|
10
|
-
export const state = proxy<{
|
|
11
|
-
title: string
|
|
12
|
-
config: Dict
|
|
13
|
-
vfs: VfsNode | undefined
|
|
14
|
-
selectedFiles: VfsNode[]
|
|
15
|
-
loginRequired: boolean
|
|
16
|
-
username: string
|
|
17
|
-
onlinePluginsColumns: Dict<boolean>
|
|
18
|
-
}>(Object.assign({
|
|
19
|
-
title: '',
|
|
20
|
-
config: {},
|
|
21
|
-
selectedFiles: [],
|
|
22
|
-
vfs: undefined,
|
|
23
|
-
loginRequired: false,
|
|
24
|
-
username: '',
|
|
25
|
-
onlinePluginsColumns: {
|
|
26
|
-
version: false,
|
|
27
|
-
pushed_at: false,
|
|
28
|
-
license: false,
|
|
29
|
-
}
|
|
30
|
-
}, JSON.parse(localStorage[STORAGE_KEY]||null)))
|
|
31
|
-
|
|
32
|
-
const SETTINGS_TO_STORE: (keyof typeof state)[] = ['onlinePluginsColumns']
|
|
33
|
-
const storeSettings = _.debounce(() =>
|
|
34
|
-
localStorage[STORAGE_KEY] = JSON.stringify(_.pick(state, SETTINGS_TO_STORE)), 500, { maxWait: 1000 })
|
|
35
|
-
for (const k of SETTINGS_TO_STORE)
|
|
36
|
-
subscribeKey(state, k, storeSettings)
|
|
37
|
-
|
|
38
|
-
export function useSnapState() {
|
|
39
|
-
return useSnapshot(state)
|
|
40
|
-
}
|
package/admin/src/theme.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
// This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
|
|
2
|
-
|
|
3
|
-
import { createTheme, useMediaQuery } from '@mui/material'
|
|
4
|
-
import { useMemo } from 'react'
|
|
5
|
-
|
|
6
|
-
const EMPTY = {}
|
|
7
|
-
export function useMyTheme() {
|
|
8
|
-
const lightMode = useMediaQuery('(prefers-color-scheme: dark)') ? null : EMPTY
|
|
9
|
-
return useMemo(() => createTheme({
|
|
10
|
-
palette: lightMode || {
|
|
11
|
-
mode: 'dark',
|
|
12
|
-
text: { primary: '#bbb' },
|
|
13
|
-
primary: { main: '#469' },
|
|
14
|
-
},
|
|
15
|
-
typography: {
|
|
16
|
-
fontFamily: 'Roboto, "Noto sans", "Segoe UI", "San Francisco", "Helvetica Neue", Arial, sans-serif'
|
|
17
|
-
},
|
|
18
|
-
components: {
|
|
19
|
-
MuiTextField: {
|
|
20
|
-
defaultProps: { variant: 'filled' },
|
|
21
|
-
styleOverrides: lightMode || {
|
|
22
|
-
root: { '& label.Mui-focused': { color: '#ccc' } } // our primary.main is too dark for mui's dark theme, and when input element is :-webkit-autofill it will make not enough contrast
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
MuiButton: {
|
|
26
|
-
defaultProps: { variant: 'outlined' },
|
|
27
|
-
styleOverrides: lightMode || {
|
|
28
|
-
root({ ownerState }) {
|
|
29
|
-
return ownerState.color === 'primary' && {
|
|
30
|
-
color: ownerState.variant === 'contained' ? '#ddd' : '#68c'
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}), [lightMode])
|
|
37
|
-
}
|
package/admin/tsconfig.json
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "es2017",
|
|
4
|
-
"lib": [
|
|
5
|
-
"dom",
|
|
6
|
-
"dom.iterable",
|
|
7
|
-
"esnext"
|
|
8
|
-
],
|
|
9
|
-
"allowJs": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"esModuleInterop": true,
|
|
12
|
-
"allowSyntheticDefaultImports": true,
|
|
13
|
-
"strict": true,
|
|
14
|
-
"forceConsistentCasingInFileNames": true,
|
|
15
|
-
"noFallthroughCasesInSwitch": true,
|
|
16
|
-
"module": "esnext",
|
|
17
|
-
"moduleResolution": "node",
|
|
18
|
-
"resolveJsonModule": true,
|
|
19
|
-
"isolatedModules": true,
|
|
20
|
-
"noEmit": true,
|
|
21
|
-
"jsx": "react-jsx"
|
|
22
|
-
},
|
|
23
|
-
"include": [
|
|
24
|
-
"src"
|
|
25
|
-
]
|
|
26
|
-
}
|
package/admin/vite.config.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vite'
|
|
2
|
-
import vitePluginImport from 'vite-plugin-babel-import';
|
|
3
|
-
|
|
4
|
-
// https://vitejs.dev/config/
|
|
5
|
-
export default defineConfig({
|
|
6
|
-
build: {
|
|
7
|
-
outDir: '../dist/admin',
|
|
8
|
-
emptyOutDir: true,
|
|
9
|
-
target: "es2015",
|
|
10
|
-
},
|
|
11
|
-
plugins: [
|
|
12
|
-
vitePluginImport([] || [
|
|
13
|
-
{ // this is (currently) speeding up build process, by bringing "modules transformed" from 11k+ down to 1.5k+
|
|
14
|
-
libraryName: '@mui/icons-material',
|
|
15
|
-
libraryDirectory: '',
|
|
16
|
-
libraryChangeCase: "camelCase",
|
|
17
|
-
ignoreStyles: [],
|
|
18
|
-
},
|
|
19
|
-
])
|
|
20
|
-
],
|
|
21
|
-
server: {
|
|
22
|
-
port: 3006,
|
|
23
|
-
proxy: {
|
|
24
|
-
'/~/': {
|
|
25
|
-
target: 'http://localhost',
|
|
26
|
-
proxyTimeout: 2000,
|
|
27
|
-
changeOrigin: true,
|
|
28
|
-
ws: true,
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
})
|
package/frontend/.DS_Store
DELETED
|
Binary file
|
package/frontend/.eslintrc
DELETED
package/frontend/.gitignore
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
2
|
-
|
|
3
|
-
# dependencies
|
|
4
|
-
/node_modules
|
|
5
|
-
/.pnp
|
|
6
|
-
.pnp.js
|
|
7
|
-
|
|
8
|
-
# testing
|
|
9
|
-
/coverage
|
|
10
|
-
|
|
11
|
-
# production
|
|
12
|
-
/build
|
|
13
|
-
|
|
14
|
-
# misc
|
|
15
|
-
.DS_Store
|
|
16
|
-
.env.local
|
|
17
|
-
.env.development.local
|
|
18
|
-
.env.test.local
|
|
19
|
-
.env.production.local
|
|
20
|
-
|
|
21
|
-
npm-debug.log*
|
|
22
|
-
yarn-debug.log*
|
|
23
|
-
yarn-error.log*
|
package/frontend/package.json
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@hfs/frontend",
|
|
3
|
-
"private": true,
|
|
4
|
-
"proxy": "http://localhost",
|
|
5
|
-
"scripts": {
|
|
6
|
-
"start": "vite",
|
|
7
|
-
"build": "tsc && vite build",
|
|
8
|
-
"preview": "vite preview",
|
|
9
|
-
"test-dep": "npm audit --production"
|
|
10
|
-
},
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"@hfs/shared": "*",
|
|
13
|
-
"js-sha512": "^0.8.0",
|
|
14
|
-
"lodash": "^4.17.21",
|
|
15
|
-
"react": "^18.2.0",
|
|
16
|
-
"react-dom": "^18.2.0",
|
|
17
|
-
"react-router-dom": "^6.1.1",
|
|
18
|
-
"tssrp6a": "^3.0.0",
|
|
19
|
-
"use-debounce": "^7.0.1",
|
|
20
|
-
"usehooks-ts": "^2.6.0",
|
|
21
|
-
"valtio": "^1.2.7",
|
|
22
|
-
"web-vitals": "^2.1.4"
|
|
23
|
-
},
|
|
24
|
-
"devDependencies": {
|
|
25
|
-
"@types/lodash": "^4.14.178",
|
|
26
|
-
"@types/node": "^16.11.21",
|
|
27
|
-
"@types/react": "^18.0.15",
|
|
28
|
-
"@types/react-dom": "^18.0.6",
|
|
29
|
-
"cross-env": "^7.0.3",
|
|
30
|
-
"sass": "^1.54.5",
|
|
31
|
-
"vite": "^3.0.0"
|
|
32
|
-
},
|
|
33
|
-
"eslintConfig": {
|
|
34
|
-
"extends": [
|
|
35
|
-
"react-app",
|
|
36
|
-
"react-app/jest"
|
|
37
|
-
]
|
|
38
|
-
},
|
|
39
|
-
"browserslist": {
|
|
40
|
-
"production": [
|
|
41
|
-
">0.2%",
|
|
42
|
-
"not dead",
|
|
43
|
-
"not op_mini all"
|
|
44
|
-
],
|
|
45
|
-
"development": [
|
|
46
|
-
"last 1 chrome version",
|
|
47
|
-
"last 1 firefox version",
|
|
48
|
-
"last 1 safari version"
|
|
49
|
-
]
|
|
50
|
-
}
|
|
51
|
-
}
|