Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7,303 changes: 7,303 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@radix-ui/react-toggle-group": "^1.1.11",
"@radix-ui/react-tooltip": "^1.2.8",
"@tanstack/react-query": "^5.96.2",
"@testing-library/dom": "^10.4.1",
"axios": "^1.15.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
Expand Down Expand Up @@ -77,5 +78,8 @@
"typescript-eslint": "^8.58.0",
"vite": "^8.0.1",
"vitest": "^4.1.2"
},
"overrides": {
"follow-redirects": "1.16.0"
}
}
94 changes: 94 additions & 0 deletions src/application/components/rag/FileContentPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
interface FileContentPanelProps {
content: string;
metadata: { format_type: string; mime_type: string };
tables: { headers: string[]; rows: string[][] }[];
onClose: () => void;
}

export default function FileContentPanel({
content,
metadata,
tables,
onClose,
}: Readonly<FileContentPanelProps>) {
return (
<div className="fixed right-0 top-0 h-full w-[480px] bg-surface-container-lowest border-l border-outline-variant shadow-2xl z-50 flex flex-col">
<div className="flex items-center justify-between px-6 py-4 border-b border-outline-variant">
<h3 className="font-headline text-sm font-semibold text-on-surface">
File Content
</h3>
<button
type="button"
onClick={onClose}
className="flex items-center justify-center w-8 h-8 rounded-lg hover:bg-surface-container transition-colors"
aria-label="Close"
>
<span className="material-symbols-outlined text-lg text-on-surface-variant">
close
</span>
</button>
</div>

<div className="px-6 py-3 border-b border-outline-variant">
<div className="flex items-center gap-4 text-xs font-body text-on-surface-variant">
<span className="bg-surface-container px-2 py-0.5 rounded">
{metadata.format_type}
</span>
<span>{metadata.mime_type}</span>
</div>
</div>

<div className="flex-1 overflow-y-auto px-6 py-4 max-h-[calc(100vh-8rem)]">
<pre className="font-body text-sm text-on-surface whitespace-pre-wrap overflow-wrap-anywhere">
{content}
</pre>

{tables.length > 0 && (
<div className="mt-6 space-y-4">
<h4 className="font-headline text-sm font-semibold text-on-surface">
Tables ({tables.length})
</h4>
{tables.map((table, tableIdx) => (
<div
key={`table-${tableIdx}-${table.headers.join("-")}`}
className="overflow-x-auto border border-outline-variant rounded-lg"
>
<table className="min-w-full text-xs font-body">
<thead>
<tr className="bg-surface-container">
{table.headers.map((header) => (
<th
key={header}
className="px-3 py-2 text-left text-on-surface-variant font-semibold"
>
{header}
</th>
))}
</tr>
</thead>
<tbody>
{table.rows.map((row, rowIdx) => (
<tr
key={`row-${tableIdx}-${rowIdx}`}
className="border-t border-outline-variant"
>
{row.map((cell, cellIdx) => (
<td
key={`cell-${tableIdx}-${rowIdx}-${cellIdx}`}
className="px-3 py-2 text-on-surface"
>
{cell}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
))}
</div>
)}
</div>
</div>
);
}
27 changes: 19 additions & 8 deletions src/application/components/rag/FileList.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import FolderRow from "@/application/components/rag/FolderRow";
import FileRow from "@/application/components/rag/FileRow";
import type { FolderEntry } from "@/domain/entities/rag/fileEntry";
import type { FileEntry } from "@/domain/entities/rag/fileEntry";
import type { FolderEntry, FileEntry } from "@/domain/entities/rag/fileEntry";

interface FileListProps {
folders: FolderEntry[];
Expand All @@ -10,6 +9,11 @@ interface FileListProps {
error: Error | null;
onFolderClick: (prefix: string) => void;
onRetry: () => void;
onFileRead?: (objectName: string) => void;
onFileIndexLightRAG?: (objectName: string) => void;
onFileIndexClassical?: (objectName: string) => void;
onFolderIndexLightRAG?: (prefix: string) => void;
onFolderIndexClassical?: (prefix: string) => void;
}

export default function FileList({
Expand All @@ -19,6 +23,11 @@ export default function FileList({
error,
onFolderClick,
onRetry,
onFileRead,
onFileIndexLightRAG,
onFileIndexClassical,
onFolderIndexLightRAG,
onFolderIndexClassical,
}: Readonly<FileListProps>) {
if (isLoading) {
return (
Expand Down Expand Up @@ -47,13 +56,10 @@ export default function FileList({
onClick={onRetry}
className="flex items-center gap-2 text-secondary-brand font-headline text-xs font-bold uppercase tracking-widest hover:opacity-80 transition-opacity"
>
<span
className="material-symbols-outlined text-base"
aria-hidden="true"
>
<span className="material-symbols-outlined text-base" aria-hidden="true">
refresh
</span>
Retry
{"Retry"}
</button>
</div>
);
Expand Down Expand Up @@ -82,6 +88,8 @@ export default function FileList({
key={folder.prefix}
name={folder.name}
onClick={() => onFolderClick(folder.prefix)}
onIndexLightRAG={onFolderIndexLightRAG ? () => onFolderIndexLightRAG(folder.prefix) : undefined}
onIndexClassical={onFolderIndexClassical ? () => onFolderIndexClassical(folder.prefix) : undefined}
/>
))}
{files.map((file) => (
Expand All @@ -90,8 +98,11 @@ export default function FileList({
filename={file.filename}
size={file.size}
lastModified={file.lastModified}
onRead={onFileRead ? () => onFileRead(file.objectName) : undefined}
onIndexLightRAG={onFileIndexLightRAG ? () => onFileIndexLightRAG(file.objectName) : undefined}
onIndexClassical={onFileIndexClassical ? () => onFileIndexClassical(file.objectName) : undefined}
/>
))}
</div>
);
}
}
46 changes: 41 additions & 5 deletions src/application/components/rag/FileRow.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { formatFileSize } from "@/application/lib/formatFileSize";
import IndexActionMenu from "@/application/components/rag/IndexActionMenu";

interface FileRowProps {
filename: string;
size: number;
lastModified: string | null;
isIndexing?: boolean;
onRead?: () => void;
onIndexLightRAG?: () => void;
onIndexClassical?: () => void;
}

function formatDate(dateStr: string | null): string {
if (!dateStr) return "\u2014";
const date = new Date(dateStr);
if (isNaN(date.getTime())) return "\u2014";
if (Number.isNaN(date.getTime())) return "\u2014";
return date.toLocaleDateString(undefined, {
year: "numeric",
month: "short",
Expand Down Expand Up @@ -45,27 +50,58 @@ export default function FileRow({
filename,
size,
lastModified,
isIndexing,
onRead,
onIndexLightRAG,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Le menu d'indexation est dupliqué ici alors que IndexActionMenu.tsx existe. Considérer la réutilisation du composant.

onIndexClassical,
}: Readonly<FileRowProps>) {
const hasIndexOptions = onIndexLightRAG || onIndexClassical;

return (
<div
role="row"
className="w-full flex items-center gap-4 px-6 py-4 rounded-xl text-left"
className={`w-full flex items-center gap-4 px-6 py-4 rounded-xl text-left ${isIndexing ? "opacity-60" : ""}`}
>
<span
className="material-symbols-outlined text-2xl text-on-surface-variant"
aria-hidden="true"
>
{getFileIcon(filename)}
{isIndexing ? "progress_activity" : getFileIcon(filename)}
</span>
<span className="font-body text-sm text-on-surface flex-1">
{filename}
</span>
{isIndexing && (
<span className="material-symbols-outlined text-lg animate-spin text-secondary-brand" aria-hidden="true">
progress_activity
</span>
)}
<span className="font-body text-sm text-on-surface-variant w-24 text-right">
{formatFileSize(size)}
</span>
<span className="font-body text-sm text-on-surface-variant w-32 text-right">
{formatDate(lastModified)}
</span>
<div className="flex items-center gap-1">
{onRead && (
<button
type="button"
onClick={onRead}
disabled={isIndexing}
className="flex items-center justify-center w-8 h-8 rounded-lg hover:bg-surface-container transition-colors disabled:opacity-50"
aria-label={`Read ${filename}`}
>
<span className="material-symbols-outlined text-lg text-on-surface-variant">
visibility
</span>
</button>
)}
{hasIndexOptions && (
<IndexActionMenu
onIndexLightRAG={onIndexLightRAG!}
onIndexClassical={onIndexClassical!}
/>
)}
</div>
</div>
);
}
}
71 changes: 47 additions & 24 deletions src/application/components/rag/FolderRow.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,55 @@
import IndexActionMenu from "@/application/components/rag/IndexActionMenu";

interface FolderRowProps {
name: string;
onClick: () => void;
isIndexing?: boolean;
onIndexLightRAG?: () => void;
onIndexClassical?: () => void;
}

export default function FolderRow({ name, onClick }: Readonly<FolderRowProps>) {
export default function FolderRow({ name, onClick, isIndexing, onIndexLightRAG, onIndexClassical }: Readonly<FolderRowProps>) {
const hasIndexOptions = onIndexLightRAG || onIndexClassical;

return (
<button
type="button"
tabIndex={0}
onClick={onClick}
aria-label={name}
className="w-full flex items-center gap-4 px-6 py-4 rounded-xl hover:bg-surface-container transition-colors text-left"
>
<span
className="material-symbols-outlined text-2xl text-secondary-brand"
aria-label="folder icon"
<div className={`w-full flex items-center ${isIndexing ? "opacity-60" : ""}`}>
<button
type="button"
tabIndex={0}
onClick={onClick}
disabled={isIndexing}
aria-label={name}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Même duplication du menu d'indexation. IndexActionMenu devrait être utilisé ici aussi.

className="flex-1 flex items-center gap-4 px-6 py-4 rounded-xl hover:bg-surface-container transition-colors text-left"
>
folder
</span>
<span className="font-headline text-sm font-semibold text-on-surface flex-1">
{name}
</span>
<span
className="material-symbols-outlined text-lg text-outline"
aria-hidden="true"
>
chevron_right
</span>
</button>
<span
className="material-symbols-outlined text-2xl text-secondary-brand"
aria-label="folder icon"
>
{isIndexing ? "progress_activity" : "folder"}
</span>
<span className="font-headline text-sm font-semibold text-on-surface flex-1">
{name}
</span>
{isIndexing && (
<span className="material-symbols-outlined text-lg animate-spin text-secondary-brand" aria-hidden="true">
progress_activity
</span>
)}
<span
className="material-symbols-outlined text-lg text-outline"
aria-hidden="true"
>
chevron_right
</span>
</button>
{hasIndexOptions && (
<div className="mr-4">
<IndexActionMenu
onIndexLightRAG={onIndexLightRAG!}
onIndexClassical={onIndexClassical!}
/>
</div>
)}
</div>
);
}
}
Loading
Loading