98 lines
3.2 KiB
TypeScript
98 lines
3.2 KiB
TypeScript
import { FileText, UploadCloud, X } from "lucide-react";
|
|
import { useCallback } from "react";
|
|
import { Link } from "react-router";
|
|
import {
|
|
Button,
|
|
DismissibleAlert,
|
|
LoadingFrame,
|
|
SelectionList,
|
|
SelectionListItem,
|
|
SelectionListItemContent,
|
|
hasScope,
|
|
quickAccessLaunchState,
|
|
useDashboardWidgetData,
|
|
type QuickAccessToolRenderContext
|
|
} from "@govoplan/core-webui";
|
|
import { listFiles } from "../../api/files";
|
|
|
|
type Props = Pick<
|
|
QuickAccessToolRenderContext,
|
|
"settings" | "auth" | "launchContext" | "complete" | "cancel" | "close"
|
|
>;
|
|
|
|
/**
|
|
* 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,
|
|
auth,
|
|
launchContext,
|
|
complete,
|
|
cancel,
|
|
close
|
|
}: Props) {
|
|
const load = useCallback(
|
|
async () => (await listFiles(settings, { sort: "recent", page_size: 7 })).files,
|
|
[settings]
|
|
);
|
|
const { data: files, loading, error } = useDashboardWidgetData(load, 0);
|
|
const canUpload = hasScope(auth, "files:upload");
|
|
|
|
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">
|
|
{canUpload ? (
|
|
<Link
|
|
className="btn btn-secondary"
|
|
to="/files?quickAction=upload"
|
|
state={quickAccessLaunchState(launchContext)}
|
|
onClick={close}
|
|
>
|
|
<UploadCloud size={15} aria-hidden="true" /> i18n:govoplan-files.upload.8bdf057f
|
|
</Link>
|
|
) : null}
|
|
<Button onClick={() => cancel("user")}><X size={15} aria-hidden="true" /> i18n:govoplan-files.cancel.77dfd213</Button>
|
|
</div>
|
|
</LoadingFrame>
|
|
);
|
|
}
|