Files

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>
);
}