dashboard-nanobot/frontend/src/shared/workspace/WorkspaceEntriesList.tsx

101 lines
3.5 KiB
TypeScript

import { FileText, FolderOpen } from 'lucide-react';
import type { WorkspaceNode } from './types';
import { isPreviewableWorkspaceFile, workspaceFileAction } from './utils';
interface WorkspaceEntriesLabels {
download: string;
fileNotPreviewable: string;
folder: string;
goUp: string;
goUpTitle: string;
openFolderTitle: string;
previewTitle: string;
}
interface WorkspaceEntriesListProps {
nodes: WorkspaceNode[];
workspaceParentPath: string | null;
selectedBotId: string;
workspaceFileLoading: boolean;
workspaceDownloadExtensionSet: ReadonlySet<string>;
labels: WorkspaceEntriesLabels;
onLoadWorkspaceTree: (botId: string, path?: string) => Promise<void> | void;
onOpenWorkspaceFilePreview: (path: string) => Promise<void> | void;
onShowWorkspaceHoverCard: (node: WorkspaceNode, anchor: HTMLElement) => void;
onHideWorkspaceHoverCard: () => void;
}
export function WorkspaceEntriesList({
nodes,
workspaceParentPath,
selectedBotId,
workspaceFileLoading,
workspaceDownloadExtensionSet,
labels,
onLoadWorkspaceTree,
onOpenWorkspaceFilePreview,
onShowWorkspaceHoverCard,
onHideWorkspaceHoverCard,
}: WorkspaceEntriesListProps) {
return (
<>
{workspaceParentPath !== null ? (
<button
key="dir:.."
className="workspace-entry dir nav-up"
onClick={() => void onLoadWorkspaceTree(selectedBotId, workspaceParentPath || '')}
title={labels.goUpTitle}
>
<FolderOpen size={14} />
<span className="workspace-entry-name">..</span>
<span className="workspace-entry-meta">{labels.goUp}</span>
</button>
) : null}
{nodes.map((node) => {
const key = `${node.type}:${node.path}`;
if (node.type === 'dir') {
return (
<button
key={key}
className="workspace-entry dir"
onClick={() => void onLoadWorkspaceTree(selectedBotId, node.path)}
title={labels.openFolderTitle}
>
<FolderOpen size={14} />
<span className="workspace-entry-name" title={node.name}>{node.name}</span>
<span className="workspace-entry-meta">{labels.folder}</span>
</button>
);
}
const previewable = isPreviewableWorkspaceFile(node, workspaceDownloadExtensionSet);
const downloadOnlyFile = workspaceFileAction(node.path, workspaceDownloadExtensionSet) === 'download';
return (
<button
key={key}
className={`workspace-entry file ${previewable ? '' : 'disabled'}`}
disabled={workspaceFileLoading}
aria-disabled={!previewable || workspaceFileLoading}
onClick={() => {
if (workspaceFileLoading || !previewable) return;
void onOpenWorkspaceFilePreview(node.path);
}}
onMouseEnter={(event) => onShowWorkspaceHoverCard(node, event.currentTarget)}
onMouseLeave={onHideWorkspaceHoverCard}
onFocus={(event) => onShowWorkspaceHoverCard(node, event.currentTarget)}
onBlur={onHideWorkspaceHoverCard}
title={previewable ? (downloadOnlyFile ? labels.download : labels.previewTitle) : labels.fileNotPreviewable}
>
<FileText size={14} />
<span className="workspace-entry-name" title={node.name}>{node.name}</span>
<span className="workspace-entry-meta mono">{node.ext || '-'}</span>
</button>
);
})}
</>
);
}