diff --git a/frontend/src/lib/components/ResourceList.svelte b/frontend/src/lib/components/ResourceList.svelte index df705c7e..c190eb0b 100644 --- a/frontend/src/lib/components/ResourceList.svelte +++ b/frontend/src/lib/components/ResourceList.svelte @@ -53,13 +53,22 @@ /** * Optional per-item visibility gate. Called at menu-open time * with the target item + context; return `false` to hide the - * entry for that row. Synchronous by contract — pages that need - * an async check (e.g. "does the caller have Read on the parent - * folder?") should pre-warm a cache when items load so the - * answer is already resolved by the time this runs. See - * `$lib/utils/folderAccess.ts` for the reference pattern. + * entry entirely for that row (e.g. `open_parent` on a drive- + * root folder that has no parent to open). Prefer `disabled?` + * over hiding when the action *could* apply but the caller + * lacks the required permission — a greyed entry answers + * "this option exists" for the user instead of leaving a hole + * that reads as a forgotten feature. */ visible?: (item: FileItem | FolderItem, ctx?: ItemContext) => boolean; + /** + * Optional per-item disabled gate. Called at menu-open time; + * `true` renders the entry non-interactive (dimmed, no click). + * Kept sync by the same contract as `visible?` — use the + * `menuPrepare` prop to prime any cache the predicate depends + * on before the menu renders. + */ + disabled?: (item: FileItem | FolderItem, ctx?: ItemContext) => boolean; run: (item: FileItem | FolderItem, ctx?: ItemContext) => void; } @@ -1352,12 +1361,17 @@ data-testid="resource-list-context-menu" > {#each visibleActions as action (action.key)} + {@const dis = action.disabled?.(ctxItem!, ctxOf(ctxItem!.id)) === true} {t('files.share', 'Share')}