feat(webui): add bounded file quick access
This commit is contained in:
@@ -578,6 +578,8 @@ manifest = ModuleManifest(
|
|||||||
required_any=("files:file:read",),
|
required_any=("files:file:read",),
|
||||||
order=10,
|
order=10,
|
||||||
modes=("browse", "select", "upload"),
|
modes=("browse", "select", "upload"),
|
||||||
|
returned_reference_kinds=("files.file-version",),
|
||||||
|
help_context_id="files.quick_access.files",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -684,8 +686,10 @@ manifest = ModuleManifest(
|
|||||||
summary="Use managed files in the Records and documents area and keep a compact file surface beside current work.",
|
summary="Use managed files in the Records and documents area and keep a compact file surface beside current work.",
|
||||||
body=(
|
body=(
|
||||||
"Files contributes its authorized workspace to Records and documents. When Quick Access is enabled, the owner-rendered "
|
"Files contributes its authorized workspace to Records and documents. When Quick Access is enabled, the owner-rendered "
|
||||||
"file-space summary appears in Files on the right rail and links back to the complete workspace. View and rail settings "
|
"recent-file selector appears in Files on the right rail and can return one exact file-version reference to the current task. "
|
||||||
"do not bypass file ownership, shares, connector policy, integrity gates, or purpose-aware access."
|
"Opening the selector causes Files to re-run its own authorization; completion and cancellation are explicit, and the full Files "
|
||||||
|
"workspace remains available as a deep-link fallback. View and rail settings may recommend or focus this tool, but do not bypass "
|
||||||
|
"file ownership, shares, connector policy, integrity gates, or purpose-aware access."
|
||||||
),
|
),
|
||||||
layer="configured",
|
layer="configured",
|
||||||
documentation_types=("user", "admin"),
|
documentation_types=("user", "admin"),
|
||||||
@@ -711,8 +715,11 @@ manifest = ModuleManifest(
|
|||||||
"summary": "Verwaltete Dateien im Produktbereich Akten und Dokumente und optional neben der aktuellen Arbeit verwenden.",
|
"summary": "Verwaltete Dateien im Produktbereich Akten und Dokumente und optional neben der aktuellen Arbeit verwenden.",
|
||||||
"body": (
|
"body": (
|
||||||
"Files ordnet seinen berechtigten Arbeitsbereich Akten und Dokumente zu. Ist der Schnellzugriff aktiviert, erscheint "
|
"Files ordnet seinen berechtigten Arbeitsbereich Akten und Dokumente zu. Ist der Schnellzugriff aktiviert, erscheint "
|
||||||
"die vom Modul gerenderte Übersicht der Dateibereiche rechts neben der aktuellen Seite. Ansichts- und Leistenkonfiguration "
|
"die vom Modul gerenderte Auswahl zuletzt berechtigter Dateien rechts neben der aktuellen Seite und kann einen exakten "
|
||||||
"umgehen weder Eigentum, Freigaben, Connector-Richtlinien, Integritätsprüfungen noch zweckgebundenen Zugriff."
|
"Dateiversionsverweis an die aktuelle Aufgabe zurückgeben. Files prüft die Berechtigung beim Öffnen erneut; Abschluss und "
|
||||||
|
"Abbruch sind ausdrücklich, und der vollständige Files-Arbeitsbereich bleibt als Ausweichziel erreichbar. Ansichts- und "
|
||||||
|
"Leistenkonfiguration dürfen das Werkzeug empfehlen oder fokussieren, umgehen aber weder Eigentum, Freigaben, Connector-"
|
||||||
|
"Richtlinien, Integritätsprüfungen noch zweckgebundenen Zugriff."
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import { FileText, X } from "lucide-react";
|
||||||
|
import { useCallback } from "react";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
DismissibleAlert,
|
||||||
|
LoadingFrame,
|
||||||
|
SelectionList,
|
||||||
|
SelectionListItem,
|
||||||
|
SelectionListItemContent,
|
||||||
|
useDashboardWidgetData,
|
||||||
|
type QuickAccessToolRenderContext
|
||||||
|
} from "@govoplan/core-webui";
|
||||||
|
import { listFiles } from "../../api/files";
|
||||||
|
|
||||||
|
type Props = Pick<
|
||||||
|
QuickAccessToolRenderContext,
|
||||||
|
"settings" | "launchContext" | "complete" | "cancel"
|
||||||
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bounded file selection. listFiles remains the owner-side authorization
|
||||||
|
* check; the host receives only a versioned reference after explicit choice.
|
||||||
|
*/
|
||||||
|
export default function FileQuickAccess({
|
||||||
|
settings,
|
||||||
|
launchContext,
|
||||||
|
complete,
|
||||||
|
cancel
|
||||||
|
}: Props) {
|
||||||
|
const load = useCallback(
|
||||||
|
async () => (await listFiles(settings, { page_size: 7 })).files,
|
||||||
|
[settings]
|
||||||
|
);
|
||||||
|
const { data: files, loading, error } = useDashboardWidgetData(load, 0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LoadingFrame loading={loading} label="Loading recent files">
|
||||||
|
{launchContext.activeObject ? (
|
||||||
|
<p className="muted small-note">
|
||||||
|
Select a file for {launchContext.activeObject.label}. Files checks
|
||||||
|
your current access again before showing this list.
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
{error ? <DismissibleAlert tone="warning" resetKey={error}>{error}</DismissibleAlert> : null}
|
||||||
|
<SelectionList variant="navigation" label="Recent authorized files">
|
||||||
|
{(files ?? []).map((file) => (
|
||||||
|
<SelectionListItem
|
||||||
|
key={file.version_id}
|
||||||
|
selected={false}
|
||||||
|
onClick={() => complete({
|
||||||
|
contractVersion: "1",
|
||||||
|
outcome: "completed",
|
||||||
|
action: "selected",
|
||||||
|
reference: {
|
||||||
|
ownerModule: "files",
|
||||||
|
kind: "file-version",
|
||||||
|
objectId: file.version_id,
|
||||||
|
tenantId: file.tenant_id,
|
||||||
|
label: file.filename,
|
||||||
|
version: file.version_id,
|
||||||
|
path: `/files?fileId=${encodeURIComponent(file.id)}&versionId=${encodeURIComponent(file.version_id)}`
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<SelectionListItemContent
|
||||||
|
leading={<FileText size={16} aria-hidden="true" />}
|
||||||
|
title={file.filename}
|
||||||
|
description={file.display_path}
|
||||||
|
/>
|
||||||
|
</SelectionListItem>
|
||||||
|
))}
|
||||||
|
</SelectionList>
|
||||||
|
{!loading && !error && !(files ?? []).length ? (
|
||||||
|
<p className="muted">No authorized files are available.</p>
|
||||||
|
) : null}
|
||||||
|
<div className="button-row compact-actions">
|
||||||
|
<Button onClick={() => cancel("user")}><X size={15} aria-hidden="true" /> Cancel selection</Button>
|
||||||
|
</div>
|
||||||
|
</LoadingFrame>
|
||||||
|
);
|
||||||
|
}
|
||||||
+2
-8
@@ -12,6 +12,7 @@ import { FolderTree } from "./features/files/components/FileManagerComponents";
|
|||||||
import FileConnectorSettingsPanel from "./features/files/FileConnectorSettingsPanel";
|
import FileConnectorSettingsPanel from "./features/files/FileConnectorSettingsPanel";
|
||||||
import ManagedFileChooser from "./features/files/components/ManagedFileChooser";
|
import ManagedFileChooser from "./features/files/components/ManagedFileChooser";
|
||||||
import FileSpacesWidget from "./features/files/FileSpacesWidget";
|
import FileSpacesWidget from "./features/files/FileSpacesWidget";
|
||||||
|
import FileQuickAccess from "./features/files/FileQuickAccess";
|
||||||
import { listFileSpaces, listFiles, listFilesDelta, listFolders, resolveFilePatterns, shareFilesWithTarget } from "./api/files";
|
import { listFileSpaces, listFiles, listFilesDelta, listFolders, resolveFilePatterns, shareFilesWithTarget } from "./api/files";
|
||||||
import { generatedTranslations } from "./i18n/generatedTranslations";
|
import { generatedTranslations } from "./i18n/generatedTranslations";
|
||||||
import "./styles/file-manager.css";
|
import "./styles/file-manager.css";
|
||||||
@@ -72,14 +73,7 @@ const fileQuickAccessTools: QuickAccessToolsUiCapability = {
|
|||||||
tools: [
|
tools: [
|
||||||
{
|
{
|
||||||
id: "files.recent",
|
id: "files.recent",
|
||||||
render: ({ settings }) => createElement(FileSpacesWidget, {
|
render: (context) => createElement(FileQuickAccess, context)
|
||||||
settings,
|
|
||||||
refreshKey: 0,
|
|
||||||
configuration: {
|
|
||||||
maxItems: 7,
|
|
||||||
includeConnectors: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user