@samitouri / QOSami-HFS / commits / ab299d14

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)