openrag/frontend/components/cloud-picker/unified-cloud-picker.tsx
Cole Goldsmith d47038e097
Reorganize folders within frontend (#407)
* reorganize folder structure

* move folders from merge

* fix import issue

* run format

* update configs
2025-11-17 08:23:23 -06:00

200 lines
5.2 KiB
TypeScript

"use client";
import { useState, useEffect } from "react";
import {
UnifiedCloudPickerProps,
CloudFile,
IngestSettings as IngestSettingsType,
} from "./types";
import { PickerHeader } from "./picker-header";
import { FileList } from "./file-list";
import { IngestSettings } from "./ingest-settings";
import { createProviderHandler } from "./provider-handlers";
export const UnifiedCloudPicker = ({
provider,
onFileSelected,
selectedFiles = [],
isAuthenticated,
isIngesting,
accessToken,
onPickerStateChange,
clientId,
baseUrl,
onSettingsChange,
}: UnifiedCloudPickerProps) => {
const [isPickerLoaded, setIsPickerLoaded] = useState(false);
const [isPickerOpen, setIsPickerOpen] = useState(false);
const [isIngestSettingsOpen, setIsIngestSettingsOpen] = useState(false);
const [isLoadingBaseUrl, setIsLoadingBaseUrl] = useState(false);
const [autoBaseUrl, setAutoBaseUrl] = useState<string | undefined>(undefined);
// Settings state with defaults
const [ingestSettings, setIngestSettings] = useState<IngestSettingsType>({
chunkSize: 1000,
chunkOverlap: 200,
ocr: false,
pictureDescriptions: false,
embeddingModel: "text-embedding-3-small",
});
// Handle settings changes and notify parent
const handleSettingsChange = (newSettings: IngestSettingsType) => {
setIngestSettings(newSettings);
onSettingsChange?.(newSettings);
};
const effectiveBaseUrl = baseUrl || autoBaseUrl;
// Auto-detect base URL for OneDrive personal accounts
useEffect(() => {
if (
(provider === "onedrive" || provider === "sharepoint") &&
!baseUrl &&
accessToken &&
!autoBaseUrl
) {
const getBaseUrl = async () => {
setIsLoadingBaseUrl(true);
try {
setAutoBaseUrl("https://onedrive.live.com/picker");
} catch (error) {
console.error("Auto-detect baseUrl failed:", error);
} finally {
setIsLoadingBaseUrl(false);
}
};
getBaseUrl();
}
}, [accessToken, baseUrl, autoBaseUrl, provider]);
// Load picker API
useEffect(() => {
if (!accessToken || !isAuthenticated) return;
const loadApi = async () => {
try {
const handler = createProviderHandler(
provider,
accessToken,
onPickerStateChange,
clientId,
effectiveBaseUrl,
);
const loaded = await handler.loadPickerApi();
setIsPickerLoaded(loaded);
} catch (error) {
console.error("Failed to create provider handler:", error);
setIsPickerLoaded(false);
}
};
loadApi();
}, [
accessToken,
isAuthenticated,
provider,
clientId,
effectiveBaseUrl,
onPickerStateChange,
]);
const handleAddFiles = () => {
if (!isPickerLoaded || !accessToken) {
return;
}
if ((provider === "onedrive" || provider === "sharepoint") && !clientId) {
console.error("Client ID required for OneDrive/SharePoint");
return;
}
try {
setIsPickerOpen(true);
onPickerStateChange?.(true);
const handler = createProviderHandler(
provider,
accessToken,
(isOpen) => {
setIsPickerOpen(isOpen);
onPickerStateChange?.(isOpen);
},
clientId,
effectiveBaseUrl,
);
handler.openPicker((files: CloudFile[]) => {
// Merge new files with existing ones, avoiding duplicates
const existingIds = new Set(selectedFiles.map((f) => f.id));
const newFiles = files.filter((f) => !existingIds.has(f.id));
onFileSelected([...selectedFiles, ...newFiles]);
});
} catch (error) {
console.error("Error opening picker:", error);
setIsPickerOpen(false);
onPickerStateChange?.(false);
}
};
const handleRemoveFile = (fileId: string) => {
const updatedFiles = selectedFiles.filter((file) => file.id !== fileId);
onFileSelected(updatedFiles);
};
const handleClearAll = () => {
onFileSelected([]);
};
if (isLoadingBaseUrl) {
return (
<div className="text-sm text-muted-foreground p-4 bg-muted/20 rounded-md">
Loading...
</div>
);
}
if (
(provider === "onedrive" || provider === "sharepoint") &&
!clientId &&
isAuthenticated
) {
return (
<div className="text-sm text-muted-foreground p-4 bg-muted/20 rounded-md">
Configuration required: Client ID missing for{" "}
{provider === "sharepoint" ? "SharePoint" : "OneDrive"}.
</div>
);
}
return (
<div>
<div className="mb-6">
<PickerHeader
provider={provider}
onAddFiles={handleAddFiles}
isPickerLoaded={isPickerLoaded}
isPickerOpen={isPickerOpen}
accessToken={accessToken}
isAuthenticated={isAuthenticated}
/>
</div>
<FileList
provider={provider}
files={selectedFiles}
onClearAll={handleClearAll}
onRemoveFile={handleRemoveFile}
shouldDisableActions={isIngesting}
/>
<IngestSettings
isOpen={isIngestSettingsOpen}
onOpenChange={setIsIngestSettingsOpen}
settings={ingestSettings}
onSettingsChange={handleSettingsChange}
/>
</div>
);
};