fix: admin/fs: "different permission..." not working correctly
Massimo Melina committed
Nov 2, 2023 at 14:32 UTC
ab299d14bc4acbcc4916ba22e6893bfc57647704
3 files changed
+23
-23
admin/src/FileForm.ts
+14
-18
@@ -13,7 +13,7 @@ import {
13
SelectField,
14
StringField
15
} from '@hfs/mui-grid-form'
16
-import { apiCall, useApiEx } from './api'
16
+import { apiCall, UseApi, useApiEx } from './api'
17
import {
18
basename, Btn, defaultPerms, formatBytes, formatTimestamp, IconBtn, isEqualLax, isWhoObject, LinkBtn, modifiedSx,
19
newDialog, objSameKeys, onlyTruthy, prefix, useBreakpoint, VfsPerms, Who, WhoObject, wikiLink
@@ -33,7 +33,7 @@ interface FileFormProps {
33
file: VfsNode
34
anyMask?: boolean
35
addToBar?: ReactNode
36
- statusApi: any
36
+ statusApi: UseApi
37
}
38
39
const ACCEPT_LINK = "https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept"
@@ -186,13 +186,10 @@ interface WhoFieldProps extends FieldProps<Who | undefined> {
186
contentText?: string
187
}
188
function WhoField({ value, onChange, parent, inherit, accounts, helperText, showInherited, otherPerms, byMasks,
189
- isChildren, isDir, contentText="folder content", setApi, ...rest }: WhoFieldProps): ReactElement {
189
+ hideValues, isChildren, isDir, contentText="folder content", setApi, ...rest }: WhoFieldProps): ReactElement {
190
const defaultLabel = (byMasks !== undefined ? "As per mask: " : parent !== undefined ? "As parent: " : "Default: " )
191
+ who2desc(byMasks ?? inherit)
192
const objectMode = isWhoObject(value)
193
- const [forceObject, setForceObject] = useState(objectMode)
194
- const showObjectMode = objectMode || forceObject
195
- const childrenValue = objectMode ? value.children : undefined
193
const thisValue = objectMode ? value.this : value
194
195
const options = useMemo(() =>
@@ -204,19 +201,19 @@ function WhoField({ value, onChange, parent, inherit, accounts, helperText, show
201
...otherPerms,
202
{ value: [], label: "Select accounts" },
203
// don't offer inherited value twice, unless it was already selected, or it is forced
207
- ].map(x => (x.value === thisValue || showInherited || x.value !== inherit)
204
+ ].map(x => !hideValues?.includes(x.value) && (x.value === thisValue || showInherited || x.value !== inherit)
205
&& { label: _.capitalize(who2desc(x.value)), ...x })), // default label
206
[inherit, parent, thisValue])
207
208
const timeout = 500
209
const arrayMode = Array.isArray(thisValue)
210
// a large side band will convey union across the fields
214
- return h(Box, { sx: { borderRight: showObjectMode ? '8px solid #8884' : undefined, transition: `all ${timeout}ms` } },
211
+ return h(Box, { sx: { borderRight: objectMode ? '8px solid #8884' : undefined, transition: `all ${timeout}ms` } },
212
h(SelectField as typeof SelectField<typeof thisValue | null>, {
213
...rest,
214
value: arrayMode ? [] : thisValue ?? null,
215
onChange(v, { event }) {
219
- onChange(showObjectMode ? simplify({ this: v ?? undefined, children: childrenValue }) : v ?? undefined, { was: value, event })
216
+ onChange(objectMode ? simplify({ ...value, this: v ?? undefined }) : v ?? undefined, { was: value, event })
217
},
218
options,
219
}),
@@ -232,21 +229,20 @@ function WhoField({ value, onChange, parent, inherit, accounts, helperText, show
229
!isChildren && isDir && h(LinkBtn, {
230
sx: { display: 'block', mt: -.5 },
231
onClick(event) {
235
- if (thisValue === undefined) return
236
- setForceObject(!showObjectMode)
237
- if (objectMode)
238
- onChange(thisValue, { was: value, event })
232
+ onChange(objectMode ? thisValue : { this: thisValue, children: thisValue == null ? !inherit : undefined } , { was: value, event })
233
}
240
- }, showObjectMode ? "Different permission for " : "Same permission for ", contentText)
234
+ }, objectMode ? "Different permission for " : "Same permission for ", contentText)
235
),
242
- !isChildren && h(Collapse, { in: showObjectMode, timeout },
236
+ !isChildren && h(Collapse, { in: objectMode, timeout },
237
h(WhoField, {
238
label: "Permission for " + contentText,
239
parent, inherit, accounts, showInherited, otherPerms, isDir,
240
+ value: objectMode && value?.children,
241
isChildren: true,
247
- value: childrenValue ?? undefined,
242
+ hideValues: [thisValue ?? inherit, thisValue],
243
onChange(v, { event }) {
249
- onChange(simplify({ this: thisValue ?? undefined, children: v }), { was: value, event })
244
+ if (objectMode) // shut up ts
245
+ onChange(simplify({ ...value, children: v }), { was: value, event })
246
}
247
})
248
),
@@ -267,7 +263,7 @@ function who2desc(who: any) {
263
}
264
265
interface LinkFieldProps extends FieldProps<string> {
270
- statusApi: any // receive status from parent, to avoid asking server at each click on a file
266
+ statusApi: UseApi<any> // receive status from parent, to avoid asking server at each click on a file
267
}
268
function LinkField({ value, statusApi }: LinkFieldProps) {
269
const { data, reload, error } = statusApi
admin/src/VfsPage.ts
+8
-5
@@ -21,11 +21,14 @@ export default function VfsPage() {
21
const { vfs, selectedFiles, movingFile } = useSnapState()
22
const { data, reload, element } = useApiEx('get_vfs')
23
useMemo(() => vfs || reload(), [vfs, reload])
24
- const anyMask = useMemo(() =>
25
- (function someMask(node: typeof vfs) {
26
- return !_.isEmpty(node?.masks) || node?.children?.some(someMask)
27
- })(vfs),
28
- [vfs])
24
+ const anyMask = useMemo(() => {
25
+ let f = selectedFiles[0]
26
+ while (f)
27
+ if (_.isEmpty(f.masks))
28
+ f = f.parent as any
29
+ else
30
+ return true
31
+ }, [selectedFiles])
32
const sideBreakpoint = 'md'
33
const isSideBreakpoint = useBreakpoint(sideBreakpoint)
34
const statusApi = useApiEx('get_status')
shared/api.ts
+1
@@ -73,6 +73,7 @@ export class ApiError extends Error {
73
}
74
}
75
76
+export type UseApi<T=unknown> = ReturnType<typeof useApi<T>>
77
export function useApi<T=any>(cmd: string | Falsy, params?: object, options: ApiCallOptions={}) {
78
const [data, setData] = useStateMounted<T | undefined>(undefined)
79
const [error, setError] = useStateMounted<Error | undefined>(undefined)