feat: add file selection to Google Drive connector

- Add structured request body with folders and files arrays
- Support individual file indexing alongside folder indexing
- Remove deprecated folder_ids/folder_names query params
- Update UI to allow selecting both folders and files
This commit is contained in:
CREDO23 2025-12-31 14:15:07 +02:00
parent 476c764611
commit 9c78726b6b
12 changed files with 366 additions and 97 deletions

View file

@ -47,6 +47,8 @@ interface GoogleDriveFolderTreeProps {
connectorId: number;
selectedFolders: SelectedFolder[];
onSelectFolders: (folders: SelectedFolder[]) => void;
selectedFiles?: SelectedFolder[];
onSelectFiles?: (files: SelectedFolder[]) => void;
}
// Helper to get appropriate icon for file type
@ -70,6 +72,8 @@ export function GoogleDriveFolderTree({
connectorId,
selectedFolders,
onSelectFolders,
selectedFiles = [],
onSelectFiles = () => {},
}: GoogleDriveFolderTreeProps) {
const [itemStates, setItemStates] = useState<Map<string, ItemTreeNode>>(new Map());
@ -83,6 +87,10 @@ export function GoogleDriveFolderTree({
return selectedFolders.some((f) => f.id === folderId);
};
const isFileSelected = (fileId: string): boolean => {
return selectedFiles.some((f) => f.id === fileId);
};
const toggleFolderSelection = (folderId: string, folderName: string) => {
if (isFolderSelected(folderId)) {
onSelectFolders(selectedFolders.filter((f) => f.id !== folderId));
@ -91,6 +99,14 @@ export function GoogleDriveFolderTree({
}
};
const toggleFileSelection = (fileId: string, fileName: string) => {
if (isFileSelected(fileId)) {
onSelectFiles(selectedFiles.filter((f) => f.id !== fileId));
} else {
onSelectFiles([...selectedFiles, { id: fileId, name: fileName }]);
}
};
/**
* Find an item by ID across all loaded items (root and nested).
*/
@ -201,8 +217,8 @@ export function GoogleDriveFolderTree({
const isExpanded = state?.isExpanded || false;
const isLoading = state?.isLoading || false;
const children = state?.children;
const isSelected = isFolderSelected(item.id);
const isFolder = item.isFolder;
const isSelected = isFolder ? isFolderSelected(item.id) : isFileSelected(item.id);
const childFolders = children?.filter((c) => c.isFolder) || [];
const childFiles = children?.filter((c) => !c.isFolder) || [];
@ -211,10 +227,8 @@ export function GoogleDriveFolderTree({
<div key={item.id} className="w-full" style={{ marginLeft: `${level * 1.25}rem` }}>
<div
className={cn(
"flex items-center gap-2 h-auto py-2 px-2 rounded-md",
isFolder && "hover:bg-accent cursor-pointer",
!isFolder && "cursor-default opacity-60",
isSelected && isFolder && "bg-accent/50"
"flex items-center group gap-2 h-auto py-2 px-2 rounded-md hover:bg-accent cursor-pointer",
isSelected && "bg-accent/50"
)}
>
{isFolder ? (
@ -237,16 +251,20 @@ export function GoogleDriveFolderTree({
<span className="w-4 h-4 shrink-0" />
)}
{isFolder && (
<Checkbox
checked={isSelected}
onCheckedChange={() => toggleFolderSelection(item.id, item.name)}
className="shrink-0"
onClick={(e) => e.stopPropagation()}
/>
)}
<Checkbox
checked={isSelected}
onCheckedChange={() => {
if (isFolder) {
toggleFolderSelection(item.id, item.name);
} else {
toggleFileSelection(item.id, item.name);
}
}}
className="shrink-0 z-20 group-hover:border-white group-hover:border"
onClick={(e) => e.stopPropagation()}
/>
<div className="shrink-0" style={{ marginLeft: isFolder ? "0" : "1.25rem" }}>
<div className="shrink-0">
{isFolder ? (
isExpanded ? (
<FolderOpen className="h-4 w-4 text-blue-500" />