filebrowser ole :)
This commit is contained in:
parent
ed368d1f71
commit
fa3304fe0b
@ -167,11 +167,6 @@ export const FileBrowserWidgetSchema = z.object({
|
||||
viewMode: z.enum(['list', 'thumbs']).default('list'),
|
||||
sortBy: z.enum(['name', 'ext', 'date', 'type']).default('name'),
|
||||
showToolbar: z.boolean().default(true),
|
||||
canChangeMount: z.boolean().default(true),
|
||||
allowFileViewer: z.boolean().default(true),
|
||||
allowLightbox: z.boolean().default(true),
|
||||
allowDownload: z.boolean().default(true),
|
||||
jail: z.boolean().default(false),
|
||||
variables: WidgetVariablesSchema,
|
||||
});
|
||||
|
||||
|
||||
@ -67,9 +67,11 @@ export const WidgetPropertiesForm: React.FC<WidgetPropertiesFormProps> = ({
|
||||
}, [currentProps]);
|
||||
|
||||
const updateSetting = (key: string, value: any) => {
|
||||
const newSettings = { ...settings, [key]: value };
|
||||
setSettings(newSettings);
|
||||
onSettingsChange(newSettings);
|
||||
setSettings(prev => {
|
||||
const newSettings = { ...prev, [key]: value };
|
||||
onSettingsChange(newSettings);
|
||||
return newSettings;
|
||||
});
|
||||
};
|
||||
|
||||
const renderField = (key: string, config: any) => {
|
||||
@ -422,6 +424,8 @@ export const WidgetPropertiesForm: React.FC<WidgetPropertiesFormProps> = ({
|
||||
setVfsPickerField(key);
|
||||
setVfsPickerMountKey(mountKey);
|
||||
setVfsPickerPathKey(pathKey);
|
||||
setVfsBrowseMount(settings[mountKey] || config.defaultMount || 'home');
|
||||
setVfsBrowsePath(settings[pathKey] || '/');
|
||||
setVfsPickerOpen(true);
|
||||
}}
|
||||
>
|
||||
@ -624,10 +628,6 @@ export const WidgetPropertiesForm: React.FC<WidgetPropertiesFormProps> = ({
|
||||
{/* VFS Browse Dialog */}
|
||||
<Dialog open={vfsPickerOpen} onOpenChange={(open) => {
|
||||
if (!open) setVfsPickerOpen(false);
|
||||
else {
|
||||
setVfsBrowseMount(settings[vfsPickerMountKey] || 'home');
|
||||
setVfsBrowsePath(settings[vfsPickerPathKey] || '/');
|
||||
}
|
||||
}}>
|
||||
<DialogContent className="sm:max-w-2xl max-w-[95vw] p-0 gap-0">
|
||||
<DialogHeader className="p-4 pb-2">
|
||||
@ -638,12 +638,10 @@ export const WidgetPropertiesForm: React.FC<WidgetPropertiesFormProps> = ({
|
||||
</DialogHeader>
|
||||
<div style={{ height: 350, overflow: 'hidden' }}>
|
||||
<FileBrowserWidget
|
||||
key={vfsBrowseMount}
|
||||
mount={vfsBrowseMount}
|
||||
path={vfsBrowsePath}
|
||||
onMountChange={(m: string) => {
|
||||
setVfsBrowseMount(m);
|
||||
setVfsBrowsePath('/');
|
||||
}}
|
||||
onMountChange={(m: string) => setVfsBrowseMount(m)}
|
||||
onPathChange={(p: string) => setVfsBrowsePath(p)}
|
||||
viewMode="list"
|
||||
mode="simple"
|
||||
|
||||
@ -504,6 +504,7 @@ export function registerAllWidgets() {
|
||||
allowFileViewer: true,
|
||||
allowLightbox: true,
|
||||
allowDownload: true,
|
||||
jail: false,
|
||||
variables: {}
|
||||
},
|
||||
configSchema: {
|
||||
@ -588,6 +589,12 @@ export function registerAllWidgets() {
|
||||
label: 'Allow Download',
|
||||
description: 'Show download button for files',
|
||||
default: true
|
||||
},
|
||||
jail: {
|
||||
type: 'boolean',
|
||||
label: 'Jail Mode',
|
||||
description: 'Prevent navigating above the configured mount and path',
|
||||
default: false
|
||||
}
|
||||
},
|
||||
minSize: { width: 300, height: 300 },
|
||||
|
||||
@ -27,6 +27,7 @@ const FileBrowserWidget: React.FC<FileBrowserWidgetExtendedProps> = (props) => {
|
||||
allowFileViewer = true,
|
||||
allowLightbox = true,
|
||||
allowDownload = true,
|
||||
jail = false,
|
||||
onPathChange,
|
||||
onMountChange,
|
||||
onSelect,
|
||||
@ -43,10 +44,19 @@ const FileBrowserWidget: React.FC<FileBrowserWidgetExtendedProps> = (props) => {
|
||||
const mount = onMountChange ? mountProp : internalMount;
|
||||
const currentPath = isControlled ? pathProp : internalPath;
|
||||
|
||||
// Jail: normalize the root path for comparison
|
||||
const jailRoot = pathProp.replace(/\/+$/, '') || '/';
|
||||
|
||||
const updatePath = useCallback((newPath: string) => {
|
||||
// Jail guard: prevent navigating above the jail root
|
||||
if (jail) {
|
||||
const norm = newPath.replace(/\/+$/, '') || '/';
|
||||
const root = pathProp.replace(/\/+$/, '') || '/';
|
||||
if (root !== '/' && !norm.startsWith(root) && norm !== root) return;
|
||||
}
|
||||
if (isControlled) onPathChange!(newPath);
|
||||
else setInternalPath(newPath);
|
||||
}, [isControlled, onPathChange]);
|
||||
}, [isControlled, onPathChange, jail, pathProp]);
|
||||
|
||||
const updateMount = useCallback((newMount: string) => {
|
||||
if (onMountChange) onMountChange(newMount);
|
||||
@ -140,7 +150,14 @@ const FileBrowserWidget: React.FC<FileBrowserWidgetExtendedProps> = (props) => {
|
||||
|
||||
// ── Sorted items ─────────────────────────────────────────────
|
||||
|
||||
const canGoUp = currentPath !== '/' && currentPath !== '';
|
||||
const canGoUp = (() => {
|
||||
if (currentPath === '/' || currentPath === '') return false;
|
||||
if (jail) {
|
||||
const normalized = currentPath.replace(/\/+$/, '') || '/';
|
||||
return normalized !== jailRoot && normalized !== jailRoot.replace(/\/+$/, '');
|
||||
}
|
||||
return true;
|
||||
})();
|
||||
const sorted = useMemo(() => sortNodes(nodes, sortBy, sortAsc), [nodes, sortBy, sortAsc]);
|
||||
const itemCount = sorted.length + (canGoUp ? 1 : 0);
|
||||
const getNode = (idx: number): INode | null => {
|
||||
@ -189,8 +206,14 @@ const FileBrowserWidget: React.FC<FileBrowserWidgetExtendedProps> = (props) => {
|
||||
const crumbs = [{ label: '/', path: '/' }];
|
||||
let acc = '';
|
||||
for (const p of parts) { acc += (acc ? '/' : '') + p; crumbs.push({ label: p, path: acc }); }
|
||||
// In jail mode, only show crumbs at or below the jail root
|
||||
if (jail) {
|
||||
const root = jailRoot === '/' ? '/' : jailRoot;
|
||||
const rootParts = root === '/' ? 0 : root.split('/').filter(Boolean).length;
|
||||
return crumbs.slice(rootParts);
|
||||
}
|
||||
return crumbs;
|
||||
}, [currentPath, mount]);
|
||||
}, [currentPath, mount, jail, jailRoot]);
|
||||
|
||||
// Return-to-sender focus
|
||||
useEffect(() => {
|
||||
@ -369,7 +392,7 @@ const FileBrowserWidget: React.FC<FileBrowserWidgetExtendedProps> = (props) => {
|
||||
<FileBrowserToolbar
|
||||
canGoUp={canGoUp}
|
||||
goUp={goUp}
|
||||
canChangeMount={canChangeMount}
|
||||
canChangeMount={!jail && canChangeMount}
|
||||
availableMounts={availableMounts}
|
||||
mount={mount}
|
||||
updateMount={updateMount}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user