From 12a72b2cd98ec56b800301cfe81c400464ea2c77 Mon Sep 17 00:00:00 2001
From: Brent O'Neill
Date: Thu, 2 Oct 2025 16:30:22 -0600
Subject: [PATCH 01/12] remove unused fields
---
frontend/src/app/knowledge/chunks/page.tsx | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/frontend/src/app/knowledge/chunks/page.tsx b/frontend/src/app/knowledge/chunks/page.tsx
index cb96eddc..267d0afc 100644
--- a/frontend/src/app/knowledge/chunks/page.tsx
+++ b/frontend/src/app/knowledge/chunks/page.tsx
@@ -298,12 +298,12 @@ function ChunksPageContent() {
Original document
-
+ {/*
- Name
-
{fileData?.filename}
-
+
*/}
- Type
-
@@ -318,23 +318,23 @@ function ChunksPageContent() {
: "Unknown"}
- */}
{/* TODO: Uncomment after data is available */}
{/*
- Source
*/}
- */}
From 042ffb421fc55c9500530646182887f85834c073 Mon Sep 17 00:00:00 2001
From: Brent O'Neill
Date: Thu, 2 Oct 2025 16:41:59 -0600
Subject: [PATCH 02/12] fix search
---
frontend/src/app/knowledge/chunks/page.tsx | 47 +++++++++++++++-------
1 file changed, 33 insertions(+), 14 deletions(-)
diff --git a/frontend/src/app/knowledge/chunks/page.tsx b/frontend/src/app/knowledge/chunks/page.tsx
index 267d0afc..bc00f886 100644
--- a/frontend/src/app/knowledge/chunks/page.tsx
+++ b/frontend/src/app/knowledge/chunks/page.tsx
@@ -1,6 +1,6 @@
"use client";
-import { ArrowLeft, Check, Copy, Loader2, Search } from "lucide-react";
+import { ArrowLeft, Check, Copy, Loader2, Search, X } from "lucide-react";
import { Suspense, useCallback, useEffect, useMemo, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { ProtectedRoute } from "@/components/protected-route";
@@ -14,7 +14,7 @@ import {
} from "../../api/queries/useGetSearchQuery";
import { Label } from "@/components/ui/label";
import { Checkbox } from "@/components/ui/checkbox";
-import { Input } from "@/components/ui/input";
+import { filterAccentClasses } from "@/components/knowledge-filter-panel";
const getFileTypeLabel = (mimetype: string) => {
if (mimetype === "application/pdf") return "PDF";
@@ -26,8 +26,9 @@ const getFileTypeLabel = (mimetype: string) => {
function ChunksPageContent() {
const router = useRouter();
const searchParams = useSearchParams();
+ const { selectedFilter, setSelectedFilter, parsedFilterData, isPanelOpen } =
+ useKnowledgeFilter();
const { isMenuOpen } = useTask();
- const { parsedFilterData, isPanelOpen } = useKnowledgeFilter();
const filename = searchParams.get("filename");
const [chunks, setChunks] = useState([]);
@@ -158,17 +159,35 @@ function ChunksPageContent() {
-
-
: null}
- id="search-query"
- type="text"
- defaultValue={parsedFilterData?.query}
- value={queryInputText}
- onChange={(e) => setQueryInputText(e.target.value)}
- placeholder="Search chunks..."
- />
+
+
+ {selectedFilter?.name && (
+
+ {selectedFilter?.name}
+ setSelectedFilter(null)}
+ />
+
+ )}
+
+
setQueryInputText(e.target.value)}
+ />
+
Date: Fri, 3 Oct 2025 09:08:33 -0600
Subject: [PATCH 03/12] fix frontend ID
---
frontend/src/app/api/queries/useGetSearchQuery.ts | 5 +++--
frontend/src/app/knowledge/chunks/page.tsx | 6 ++++--
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/frontend/src/app/api/queries/useGetSearchQuery.ts b/frontend/src/app/api/queries/useGetSearchQuery.ts
index 5383178d..d0c1a3a9 100644
--- a/frontend/src/app/api/queries/useGetSearchQuery.ts
+++ b/frontend/src/app/api/queries/useGetSearchQuery.ts
@@ -29,6 +29,7 @@ export interface ChunkResult {
owner_email?: string;
file_size?: number;
connector_type?: string;
+ index?: number;
}
export interface File {
@@ -55,7 +56,7 @@ export interface File {
export const useGetSearchQuery = (
query: string,
queryData?: ParsedQueryData | null,
- options?: Omit,
+ options?: Omit
) => {
const queryClient = useQueryClient();
@@ -184,7 +185,7 @@ export const useGetSearchQuery = (
queryFn: getFiles,
...options,
},
- queryClient,
+ queryClient
);
return queryResult;
diff --git a/frontend/src/app/knowledge/chunks/page.tsx b/frontend/src/app/knowledge/chunks/page.tsx
index bc00f886..9b02506b 100644
--- a/frontend/src/app/knowledge/chunks/page.tsx
+++ b/frontend/src/app/knowledge/chunks/page.tsx
@@ -86,7 +86,9 @@ function ChunksPageContent() {
return;
}
- setChunks(fileData?.chunks || []);
+ setChunks(
+ fileData?.chunks?.map((chunk, i) => ({ ...chunk, index: i + 1 })) || []
+ );
}, [data, filename]);
// Set selected state for all checkboxes when selectAll changes
@@ -246,7 +248,7 @@ function ChunksPageContent() {
/>
- Chunk {chunk.page}
+ Chunk {chunk.index}
{chunk.text.length} chars
From ac333b99d7317b8b3400e280d836454ffae64676 Mon Sep 17 00:00:00 2001
From: Brent O'Neill
Date: Fri, 3 Oct 2025 09:12:35 -0600
Subject: [PATCH 04/12] added value
---
frontend/src/app/knowledge/chunks/page.tsx | 1 +
1 file changed, 1 insertion(+)
diff --git a/frontend/src/app/knowledge/chunks/page.tsx b/frontend/src/app/knowledge/chunks/page.tsx
index 9b02506b..bbb7f019 100644
--- a/frontend/src/app/knowledge/chunks/page.tsx
+++ b/frontend/src/app/knowledge/chunks/page.tsx
@@ -188,6 +188,7 @@ function ChunksPageContent() {
type="text"
placeholder="Search your documents..."
onChange={(e) => setQueryInputText(e.target.value)}
+ value={queryInputText}
/>
From 11a6f0e8d415ce989929c49e566da75d474b11bf Mon Sep 17 00:00:00 2001
From: Brent O'Neill
Date: Fri, 3 Oct 2025 10:47:31 -0600
Subject: [PATCH 05/12] updated header and cloud picker header
---
frontend/src/app/upload/[provider]/page.tsx | 659 +++++++++---------
.../components/cloud-picker/picker-header.tsx | 8 +-
2 files changed, 332 insertions(+), 335 deletions(-)
diff --git a/frontend/src/app/upload/[provider]/page.tsx b/frontend/src/app/upload/[provider]/page.tsx
index 7c72ec3d..8e0a306c 100644
--- a/frontend/src/app/upload/[provider]/page.tsx
+++ b/frontend/src/app/upload/[provider]/page.tsx
@@ -12,367 +12,370 @@ import { useTask } from "@/contexts/task-context";
// CloudFile interface is now imported from the unified cloud picker
interface CloudConnector {
- id: string;
- name: string;
- description: string;
- status: "not_connected" | "connecting" | "connected" | "error";
- type: string;
- connectionId?: string;
- clientId: string;
- hasAccessToken: boolean;
- accessTokenError?: string;
+ id: string;
+ name: string;
+ description: string;
+ status: "not_connected" | "connecting" | "connected" | "error";
+ type: string;
+ connectionId?: string;
+ clientId: string;
+ hasAccessToken: boolean;
+ accessTokenError?: string;
}
export default function UploadProviderPage() {
- const params = useParams();
- const router = useRouter();
- const provider = params.provider as string;
- const { addTask, tasks } = useTask();
+ const params = useParams();
+ const router = useRouter();
+ const provider = params.provider as string;
+ const { addTask, tasks } = useTask();
- const [connector, setConnector] = useState(null);
- const [isLoading, setIsLoading] = useState(true);
- const [error, setError] = useState(null);
- const [accessToken, setAccessToken] = useState(null);
- const [selectedFiles, setSelectedFiles] = useState([]);
- const [isIngesting, setIsIngesting] = useState(false);
- const [currentSyncTaskId, setCurrentSyncTaskId] = useState(
- null,
- );
- const [ingestSettings, setIngestSettings] = useState({
- chunkSize: 1000,
- chunkOverlap: 200,
- ocr: false,
- pictureDescriptions: false,
- embeddingModel: "text-embedding-3-small",
- });
+ const [connector, setConnector] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [accessToken, setAccessToken] = useState(null);
+ const [selectedFiles, setSelectedFiles] = useState([]);
+ const [isIngesting, setIsIngesting] = useState(false);
+ const [currentSyncTaskId, setCurrentSyncTaskId] = useState(
+ null
+ );
+ const [ingestSettings, setIngestSettings] = useState({
+ chunkSize: 1000,
+ chunkOverlap: 200,
+ ocr: false,
+ pictureDescriptions: false,
+ embeddingModel: "text-embedding-3-small",
+ });
- useEffect(() => {
- const fetchConnectorInfo = async () => {
- setIsLoading(true);
- setError(null);
+ useEffect(() => {
+ const fetchConnectorInfo = async () => {
+ setIsLoading(true);
+ setError(null);
- try {
- // Fetch available connectors to validate the provider
- const connectorsResponse = await fetch("/api/connectors");
- if (!connectorsResponse.ok) {
- throw new Error("Failed to load connectors");
- }
+ try {
+ // Fetch available connectors to validate the provider
+ const connectorsResponse = await fetch("/api/connectors");
+ if (!connectorsResponse.ok) {
+ throw new Error("Failed to load connectors");
+ }
- const connectorsResult = await connectorsResponse.json();
- const providerInfo = connectorsResult.connectors[provider];
+ const connectorsResult = await connectorsResponse.json();
+ const providerInfo = connectorsResult.connectors[provider];
- if (!providerInfo || !providerInfo.available) {
- setError(
- `Cloud provider "${provider}" is not available or configured.`,
- );
- return;
- }
+ if (!providerInfo || !providerInfo.available) {
+ setError(
+ `Cloud provider "${provider}" is not available or configured.`
+ );
+ return;
+ }
- // Check connector status
- const statusResponse = await fetch(
- `/api/connectors/${provider}/status`,
- );
- if (!statusResponse.ok) {
- throw new Error(`Failed to check ${provider} status`);
- }
+ // Check connector status
+ const statusResponse = await fetch(
+ `/api/connectors/${provider}/status`
+ );
+ if (!statusResponse.ok) {
+ throw new Error(`Failed to check ${provider} status`);
+ }
- const statusData = await statusResponse.json();
- const connections = statusData.connections || [];
- const activeConnection = connections.find(
- (conn: { is_active: boolean; connection_id: string }) =>
- conn.is_active,
- );
- const isConnected = activeConnection !== undefined;
+ const statusData = await statusResponse.json();
+ const connections = statusData.connections || [];
+ const activeConnection = connections.find(
+ (conn: { is_active: boolean; connection_id: string }) =>
+ conn.is_active
+ );
+ const isConnected = activeConnection !== undefined;
- let hasAccessToken = false;
- let accessTokenError: string | undefined;
+ let hasAccessToken = false;
+ let accessTokenError: string | undefined;
- // Try to get access token for connected connectors
- if (isConnected && activeConnection) {
- try {
- const tokenResponse = await fetch(
- `/api/connectors/${provider}/token?connection_id=${activeConnection.connection_id}`,
- );
- if (tokenResponse.ok) {
- const tokenData = await tokenResponse.json();
- if (tokenData.access_token) {
- hasAccessToken = true;
- setAccessToken(tokenData.access_token);
- }
- } else {
- const errorData = await tokenResponse
- .json()
- .catch(() => ({ error: "Token unavailable" }));
- accessTokenError = errorData.error || "Access token unavailable";
- }
- } catch {
- accessTokenError = "Failed to fetch access token";
- }
- }
+ // Try to get access token for connected connectors
+ if (isConnected && activeConnection) {
+ try {
+ const tokenResponse = await fetch(
+ `/api/connectors/${provider}/token?connection_id=${activeConnection.connection_id}`
+ );
+ if (tokenResponse.ok) {
+ const tokenData = await tokenResponse.json();
+ if (tokenData.access_token) {
+ hasAccessToken = true;
+ setAccessToken(tokenData.access_token);
+ }
+ } else {
+ const errorData = await tokenResponse
+ .json()
+ .catch(() => ({ error: "Token unavailable" }));
+ accessTokenError = errorData.error || "Access token unavailable";
+ }
+ } catch {
+ accessTokenError = "Failed to fetch access token";
+ }
+ }
- setConnector({
- id: provider,
- name: providerInfo.name,
- description: providerInfo.description,
- status: isConnected ? "connected" : "not_connected",
- type: provider,
- connectionId: activeConnection?.connection_id,
- clientId: activeConnection?.client_id,
- hasAccessToken,
- accessTokenError,
- });
- } catch (error) {
- console.error("Failed to load connector info:", error);
- setError(
- error instanceof Error
- ? error.message
- : "Failed to load connector information",
- );
- } finally {
- setIsLoading(false);
- }
- };
+ setConnector({
+ id: provider,
+ name: providerInfo.name,
+ description: providerInfo.description,
+ status: isConnected ? "connected" : "not_connected",
+ type: provider,
+ connectionId: activeConnection?.connection_id,
+ clientId: activeConnection?.client_id,
+ hasAccessToken,
+ accessTokenError,
+ });
+ } catch (error) {
+ console.error("Failed to load connector info:", error);
+ setError(
+ error instanceof Error
+ ? error.message
+ : "Failed to load connector information"
+ );
+ } finally {
+ setIsLoading(false);
+ }
+ };
- if (provider) {
- fetchConnectorInfo();
- }
- }, [provider]);
+ if (provider) {
+ fetchConnectorInfo();
+ }
+ }, [provider]);
- // Watch for sync task completion and redirect
- useEffect(() => {
- if (!currentSyncTaskId) return;
+ // Watch for sync task completion and redirect
+ useEffect(() => {
+ if (!currentSyncTaskId) return;
- const currentTask = tasks.find(
- (task) => task.task_id === currentSyncTaskId,
- );
+ const currentTask = tasks.find(
+ (task) => task.task_id === currentSyncTaskId
+ );
- if (currentTask && currentTask.status === "completed") {
- // Task completed successfully, show toast and redirect
- setIsIngesting(false);
- setTimeout(() => {
- router.push("/knowledge");
- }, 2000); // 2 second delay to let user see toast
- } else if (currentTask && currentTask.status === "failed") {
- // Task failed, clear the tracking but don't redirect
- setIsIngesting(false);
- setCurrentSyncTaskId(null);
- }
- }, [tasks, currentSyncTaskId, router]);
+ if (currentTask && currentTask.status === "completed") {
+ // Task completed successfully, show toast and redirect
+ setIsIngesting(false);
+ setTimeout(() => {
+ router.push("/knowledge");
+ }, 2000); // 2 second delay to let user see toast
+ } else if (currentTask && currentTask.status === "failed") {
+ // Task failed, clear the tracking but don't redirect
+ setIsIngesting(false);
+ setCurrentSyncTaskId(null);
+ }
+ }, [tasks, currentSyncTaskId, router]);
- const handleFileSelected = (files: CloudFile[]) => {
- setSelectedFiles(files);
- console.log(`Selected ${files.length} files from ${provider}:`, files);
- // You can add additional handling here like triggering sync, etc.
- };
+ const handleFileSelected = (files: CloudFile[]) => {
+ setSelectedFiles(files);
+ console.log(`Selected ${files.length} files from ${provider}:`, files);
+ // You can add additional handling here like triggering sync, etc.
+ };
- const handleSync = async (connector: CloudConnector) => {
- if (!connector.connectionId || selectedFiles.length === 0) return;
+ const handleSync = async (connector: CloudConnector) => {
+ if (!connector.connectionId || selectedFiles.length === 0) return;
- setIsIngesting(true);
+ setIsIngesting(true);
- try {
- const syncBody: {
- connection_id: string;
- max_files?: number;
- selected_files?: string[];
- settings?: IngestSettings;
- } = {
- connection_id: connector.connectionId,
- selected_files: selectedFiles.map((file) => file.id),
- settings: ingestSettings,
- };
+ try {
+ const syncBody: {
+ connection_id: string;
+ max_files?: number;
+ selected_files?: string[];
+ settings?: IngestSettings;
+ } = {
+ connection_id: connector.connectionId,
+ selected_files: selectedFiles.map((file) => file.id),
+ settings: ingestSettings,
+ };
- const response = await fetch(`/api/connectors/${connector.type}/sync`, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify(syncBody),
- });
+ const response = await fetch(`/api/connectors/${connector.type}/sync`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(syncBody),
+ });
- const result = await response.json();
+ const result = await response.json();
- if (response.status === 201) {
- const taskIds = result.task_ids;
- if (taskIds && taskIds.length > 0) {
- const taskId = taskIds[0]; // Use the first task ID
- addTask(taskId);
- setCurrentSyncTaskId(taskId);
- }
- } else {
- console.error("Sync failed:", result.error);
- }
- } catch (error) {
- console.error("Sync error:", error);
- setIsIngesting(false);
- }
- };
+ if (response.status === 201) {
+ const taskIds = result.task_ids;
+ if (taskIds && taskIds.length > 0) {
+ const taskId = taskIds[0]; // Use the first task ID
+ addTask(taskId);
+ setCurrentSyncTaskId(taskId);
+ }
+ } else {
+ console.error("Sync failed:", result.error);
+ }
+ } catch (error) {
+ console.error("Sync error:", error);
+ setIsIngesting(false);
+ }
+ };
- const getProviderDisplayName = () => {
- const nameMap: { [key: string]: string } = {
- google_drive: "Google Drive",
- onedrive: "OneDrive",
- sharepoint: "SharePoint",
- };
- return nameMap[provider] || provider;
- };
+ const getProviderDisplayName = () => {
+ const nameMap: { [key: string]: string } = {
+ google_drive: "Google Drive",
+ onedrive: "OneDrive",
+ sharepoint: "SharePoint",
+ };
+ return nameMap[provider] || provider;
+ };
- if (isLoading) {
- return (
-
-
-
-
-
Loading {getProviderDisplayName()} connector...
-
-
-
- );
- }
+ if (isLoading) {
+ return (
+
+
+
+
+
Loading {getProviderDisplayName()} connector...
+
+
+
+ );
+ }
- if (error || !connector) {
- return (
-
-
-
-
+ if (error || !connector) {
+ return (
+
+
+
+
-
-
-
-
- Provider Not Available
-
-
{error}
-
-
-
-
- );
- }
+
+
+
+
+ Provider Not Available
+
+
{error}
+
+
+
+
+ );
+ }
- if (connector.status !== "connected") {
- return (
-
-
-
-
+ if (connector.status !== "connected") {
+ return (
+
+
+
+
-
-
-
-
- {connector.name} Not Connected
-
-
- You need to connect your {connector.name} account before you can
- select files.
-
-
-
-
-
- );
- }
+
+
+
+
+ {connector.name} Not Connected
+
+
+ You need to connect your {connector.name} account before you can
+ select files.
+
+
+
+
+
+ );
+ }
- if (!connector.hasAccessToken) {
- return (
-
-
-
-
+ if (!connector.hasAccessToken) {
+ return (
+
+
+
+
-
-
-
-
- Access Token Required
-
-
- {connector.accessTokenError ||
- `Unable to get access token for ${connector.name}. Try reconnecting your account.`}
-
-
-
-
-
- );
- }
+
+
+
+
+ Access Token Required
+
+
+ {connector.accessTokenError ||
+ `Unable to get access token for ${connector.name}. Try reconnecting your account.`}
+
+
+
+
+
+ );
+ }
- return (
-
-
-
-
- Add from {getProviderDisplayName()}
-
-
+ return (
+
+
+
+
+ Add from {getProviderDisplayName()}
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
- );
+
+
+
+
+
+
+
+ );
}
diff --git a/frontend/src/components/cloud-picker/picker-header.tsx b/frontend/src/components/cloud-picker/picker-header.tsx
index 05dcaebd..e0d9cfa4 100644
--- a/frontend/src/components/cloud-picker/picker-header.tsx
+++ b/frontend/src/components/cloud-picker/picker-header.tsx
@@ -51,19 +51,13 @@ export const PickerHeader = ({
Select files from {getProviderName(provider)} to ingest.
-
- csv, json, pdf,{" "}
-
+16 more{" "}
-
150 MB max
-
);
From 088ed2697b5eadf5802cf8b39e2e8c71c93c03e1 Mon Sep 17 00:00:00 2001
From: Brent O'Neill
Date: Fri, 3 Oct 2025 12:00:13 -0600
Subject: [PATCH 06/12] updates from sync
---
frontend/src/app/knowledge/chunks/page.tsx | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/frontend/src/app/knowledge/chunks/page.tsx b/frontend/src/app/knowledge/chunks/page.tsx
index bbb7f019..85a4e3f2 100644
--- a/frontend/src/app/knowledge/chunks/page.tsx
+++ b/frontend/src/app/knowledge/chunks/page.tsx
@@ -161,7 +161,7 @@ function ChunksPageContent() {
-
+
{selectedFilter?.name && (
setQueryInputText(e.target.value)}
value={queryInputText}
/>
-
*/}
@@ -269,6 +269,10 @@ function ChunksPageContent() {
+
+ {chunk.score.toFixed(2)} score
+
+
{/* TODO: Update to use active toggle */}
{/*
Date: Fri, 3 Oct 2025 12:12:47 -0600
Subject: [PATCH 07/12] remove checkboxes
---
frontend/src/app/knowledge/chunks/page.tsx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/frontend/src/app/knowledge/chunks/page.tsx b/frontend/src/app/knowledge/chunks/page.tsx
index 85a4e3f2..cde2c3e8 100644
--- a/frontend/src/app/knowledge/chunks/page.tsx
+++ b/frontend/src/app/knowledge/chunks/page.tsx
@@ -240,14 +240,14 @@ function ChunksPageContent() {
>
-
+ {/*
handleChunkCardCheckboxChange(index)
}
/>
-
+
*/}
Chunk {chunk.index}
@@ -282,7 +282,7 @@ function ChunksPageContent() {
Active
*/}
-
+
{chunk.text}
From 99cc806a559f526e9e4a837c41096eef19fd3116 Mon Sep 17 00:00:00 2001
From: Brent O'Neill
Date: Fri, 3 Oct 2025 13:53:39 -0600
Subject: [PATCH 08/12] fix empty state
---
frontend/src/app/knowledge/chunks/page.tsx | 103 +++++++++++----------
1 file changed, 55 insertions(+), 48 deletions(-)
diff --git a/frontend/src/app/knowledge/chunks/page.tsx b/frontend/src/app/knowledge/chunks/page.tsx
index cde2c3e8..31b741a4 100644
--- a/frontend/src/app/knowledge/chunks/page.tsx
+++ b/frontend/src/app/knowledge/chunks/page.tsx
@@ -224,10 +224,9 @@ function ChunksPageContent() {
) : chunks.length === 0 ? (
-
-
No chunks found
-
- This file may not have been indexed yet
+
No knowledge
+
+ Clear the knowledge filter or return to the knowledge page
@@ -292,24 +291,29 @@ function ChunksPageContent() {
{/* Right panel - Summary (TODO), Technical details, */}
-
-
-
Technical details
-
-
-
- Total chunks
- -
- {chunks.length}
-
-
-
-
- Avg length
- -
- {averageChunkLength.toFixed(0)} chars
-
-
- {/* TODO: Uncomment after data is available */}
- {/*
+ {chunks.length > 0 && (
+
+
+
+ Technical details
+
+
+
+
-
+ Total chunks
+
+ -
+ {chunks.length}
+
+
+
+
- Avg length
+ -
+ {averageChunkLength.toFixed(0)} chars
+
+
+ {/* TODO: Uncomment after data is available */}
+ {/*
- Process time
-
@@ -319,51 +323,54 @@ function ChunksPageContent() {
-
*/}
-
-
-
-
Original document
-
- {/*
+
+
+
+
+ Original document
+
+
+ {/*
- Name
-
{fileData?.filename}
*/}
-
-
- Type
- -
- {fileData ? getFileTypeLabel(fileData.mimetype) : "Unknown"}
-
-
-
-
- Size
- -
- {fileData?.size
- ? `${Math.round(fileData.size / 1024)} KB`
- : "Unknown"}
-
-
- {/*
+
+
- Type
+ -
+ {fileData ? getFileTypeLabel(fileData.mimetype) : "Unknown"}
+
+
+
+
- Size
+ -
+ {fileData?.size
+ ? `${Math.round(fileData.size / 1024)} KB`
+ : "Unknown"}
+
+
+ {/*
- Uploaded
-
N/A
*/}
- {/* TODO: Uncomment after data is available */}
- {/*
+ {/* TODO: Uncomment after data is available */}
+ {/*
- Source
*/}
- {/*
+ {/*
- Updated
-
N/A
*/}
-
+
+
-
+ )}
);
}
From 8213f0f6136242e160df49597064d050b30db5e3 Mon Sep 17 00:00:00 2001
From: Brent O'Neill
Date: Mon, 6 Oct 2025 08:53:09 -0600
Subject: [PATCH 09/12] revert
---
frontend/src/components/cloud-picker/picker-header.tsx | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/frontend/src/components/cloud-picker/picker-header.tsx b/frontend/src/components/cloud-picker/picker-header.tsx
index e0d9cfa4..54407aa7 100644
--- a/frontend/src/components/cloud-picker/picker-header.tsx
+++ b/frontend/src/components/cloud-picker/picker-header.tsx
@@ -51,13 +51,19 @@ export const PickerHeader = ({
Select files from {getProviderName(provider)} to ingest.
+
+ csv, json, pdf,{" "}
+
+16 more{" "}
+
150 MB max
+
);
From c2f50fe139563453b8edd5cf311095d0ab71a9e3 Mon Sep 17 00:00:00 2001
From: Brent O'Neill
Date: Mon, 6 Oct 2025 08:53:39 -0600
Subject: [PATCH 10/12] revert
---
frontend/src/components/cloud-picker/picker-header.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frontend/src/components/cloud-picker/picker-header.tsx b/frontend/src/components/cloud-picker/picker-header.tsx
index 54407aa7..05dcaebd 100644
--- a/frontend/src/components/cloud-picker/picker-header.tsx
+++ b/frontend/src/components/cloud-picker/picker-header.tsx
@@ -57,7 +57,7 @@ export const PickerHeader = ({
className="bg-foreground text-background hover:bg-foreground/90 font-semibold"
>
- Add Files
+ {isPickerOpen ? "Opening Picker..." : "Add Files"}
csv, json, pdf,{" "}
From 47b84a3d8a2e74d7db88ae578a328a6e60d10214 Mon Sep 17 00:00:00 2001
From: Brent O'Neill
Date: Mon, 6 Oct 2025 08:55:12 -0600
Subject: [PATCH 11/12] revert
---
frontend/src/app/upload/[provider]/page.tsx | 659 ++++++++++----------
1 file changed, 328 insertions(+), 331 deletions(-)
diff --git a/frontend/src/app/upload/[provider]/page.tsx b/frontend/src/app/upload/[provider]/page.tsx
index 8e0a306c..7c72ec3d 100644
--- a/frontend/src/app/upload/[provider]/page.tsx
+++ b/frontend/src/app/upload/[provider]/page.tsx
@@ -12,370 +12,367 @@ import { useTask } from "@/contexts/task-context";
// CloudFile interface is now imported from the unified cloud picker
interface CloudConnector {
- id: string;
- name: string;
- description: string;
- status: "not_connected" | "connecting" | "connected" | "error";
- type: string;
- connectionId?: string;
- clientId: string;
- hasAccessToken: boolean;
- accessTokenError?: string;
+ id: string;
+ name: string;
+ description: string;
+ status: "not_connected" | "connecting" | "connected" | "error";
+ type: string;
+ connectionId?: string;
+ clientId: string;
+ hasAccessToken: boolean;
+ accessTokenError?: string;
}
export default function UploadProviderPage() {
- const params = useParams();
- const router = useRouter();
- const provider = params.provider as string;
- const { addTask, tasks } = useTask();
+ const params = useParams();
+ const router = useRouter();
+ const provider = params.provider as string;
+ const { addTask, tasks } = useTask();
- const [connector, setConnector] = useState(null);
- const [isLoading, setIsLoading] = useState(true);
- const [error, setError] = useState(null);
- const [accessToken, setAccessToken] = useState(null);
- const [selectedFiles, setSelectedFiles] = useState([]);
- const [isIngesting, setIsIngesting] = useState(false);
- const [currentSyncTaskId, setCurrentSyncTaskId] = useState(
- null
- );
- const [ingestSettings, setIngestSettings] = useState({
- chunkSize: 1000,
- chunkOverlap: 200,
- ocr: false,
- pictureDescriptions: false,
- embeddingModel: "text-embedding-3-small",
- });
+ const [connector, setConnector] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [accessToken, setAccessToken] = useState(null);
+ const [selectedFiles, setSelectedFiles] = useState([]);
+ const [isIngesting, setIsIngesting] = useState(false);
+ const [currentSyncTaskId, setCurrentSyncTaskId] = useState(
+ null,
+ );
+ const [ingestSettings, setIngestSettings] = useState({
+ chunkSize: 1000,
+ chunkOverlap: 200,
+ ocr: false,
+ pictureDescriptions: false,
+ embeddingModel: "text-embedding-3-small",
+ });
- useEffect(() => {
- const fetchConnectorInfo = async () => {
- setIsLoading(true);
- setError(null);
+ useEffect(() => {
+ const fetchConnectorInfo = async () => {
+ setIsLoading(true);
+ setError(null);
- try {
- // Fetch available connectors to validate the provider
- const connectorsResponse = await fetch("/api/connectors");
- if (!connectorsResponse.ok) {
- throw new Error("Failed to load connectors");
- }
+ try {
+ // Fetch available connectors to validate the provider
+ const connectorsResponse = await fetch("/api/connectors");
+ if (!connectorsResponse.ok) {
+ throw new Error("Failed to load connectors");
+ }
- const connectorsResult = await connectorsResponse.json();
- const providerInfo = connectorsResult.connectors[provider];
+ const connectorsResult = await connectorsResponse.json();
+ const providerInfo = connectorsResult.connectors[provider];
- if (!providerInfo || !providerInfo.available) {
- setError(
- `Cloud provider "${provider}" is not available or configured.`
- );
- return;
- }
+ if (!providerInfo || !providerInfo.available) {
+ setError(
+ `Cloud provider "${provider}" is not available or configured.`,
+ );
+ return;
+ }
- // Check connector status
- const statusResponse = await fetch(
- `/api/connectors/${provider}/status`
- );
- if (!statusResponse.ok) {
- throw new Error(`Failed to check ${provider} status`);
- }
+ // Check connector status
+ const statusResponse = await fetch(
+ `/api/connectors/${provider}/status`,
+ );
+ if (!statusResponse.ok) {
+ throw new Error(`Failed to check ${provider} status`);
+ }
- const statusData = await statusResponse.json();
- const connections = statusData.connections || [];
- const activeConnection = connections.find(
- (conn: { is_active: boolean; connection_id: string }) =>
- conn.is_active
- );
- const isConnected = activeConnection !== undefined;
+ const statusData = await statusResponse.json();
+ const connections = statusData.connections || [];
+ const activeConnection = connections.find(
+ (conn: { is_active: boolean; connection_id: string }) =>
+ conn.is_active,
+ );
+ const isConnected = activeConnection !== undefined;
- let hasAccessToken = false;
- let accessTokenError: string | undefined;
+ let hasAccessToken = false;
+ let accessTokenError: string | undefined;
- // Try to get access token for connected connectors
- if (isConnected && activeConnection) {
- try {
- const tokenResponse = await fetch(
- `/api/connectors/${provider}/token?connection_id=${activeConnection.connection_id}`
- );
- if (tokenResponse.ok) {
- const tokenData = await tokenResponse.json();
- if (tokenData.access_token) {
- hasAccessToken = true;
- setAccessToken(tokenData.access_token);
- }
- } else {
- const errorData = await tokenResponse
- .json()
- .catch(() => ({ error: "Token unavailable" }));
- accessTokenError = errorData.error || "Access token unavailable";
- }
- } catch {
- accessTokenError = "Failed to fetch access token";
- }
- }
+ // Try to get access token for connected connectors
+ if (isConnected && activeConnection) {
+ try {
+ const tokenResponse = await fetch(
+ `/api/connectors/${provider}/token?connection_id=${activeConnection.connection_id}`,
+ );
+ if (tokenResponse.ok) {
+ const tokenData = await tokenResponse.json();
+ if (tokenData.access_token) {
+ hasAccessToken = true;
+ setAccessToken(tokenData.access_token);
+ }
+ } else {
+ const errorData = await tokenResponse
+ .json()
+ .catch(() => ({ error: "Token unavailable" }));
+ accessTokenError = errorData.error || "Access token unavailable";
+ }
+ } catch {
+ accessTokenError = "Failed to fetch access token";
+ }
+ }
- setConnector({
- id: provider,
- name: providerInfo.name,
- description: providerInfo.description,
- status: isConnected ? "connected" : "not_connected",
- type: provider,
- connectionId: activeConnection?.connection_id,
- clientId: activeConnection?.client_id,
- hasAccessToken,
- accessTokenError,
- });
- } catch (error) {
- console.error("Failed to load connector info:", error);
- setError(
- error instanceof Error
- ? error.message
- : "Failed to load connector information"
- );
- } finally {
- setIsLoading(false);
- }
- };
+ setConnector({
+ id: provider,
+ name: providerInfo.name,
+ description: providerInfo.description,
+ status: isConnected ? "connected" : "not_connected",
+ type: provider,
+ connectionId: activeConnection?.connection_id,
+ clientId: activeConnection?.client_id,
+ hasAccessToken,
+ accessTokenError,
+ });
+ } catch (error) {
+ console.error("Failed to load connector info:", error);
+ setError(
+ error instanceof Error
+ ? error.message
+ : "Failed to load connector information",
+ );
+ } finally {
+ setIsLoading(false);
+ }
+ };
- if (provider) {
- fetchConnectorInfo();
- }
- }, [provider]);
+ if (provider) {
+ fetchConnectorInfo();
+ }
+ }, [provider]);
- // Watch for sync task completion and redirect
- useEffect(() => {
- if (!currentSyncTaskId) return;
+ // Watch for sync task completion and redirect
+ useEffect(() => {
+ if (!currentSyncTaskId) return;
- const currentTask = tasks.find(
- (task) => task.task_id === currentSyncTaskId
- );
+ const currentTask = tasks.find(
+ (task) => task.task_id === currentSyncTaskId,
+ );
- if (currentTask && currentTask.status === "completed") {
- // Task completed successfully, show toast and redirect
- setIsIngesting(false);
- setTimeout(() => {
- router.push("/knowledge");
- }, 2000); // 2 second delay to let user see toast
- } else if (currentTask && currentTask.status === "failed") {
- // Task failed, clear the tracking but don't redirect
- setIsIngesting(false);
- setCurrentSyncTaskId(null);
- }
- }, [tasks, currentSyncTaskId, router]);
+ if (currentTask && currentTask.status === "completed") {
+ // Task completed successfully, show toast and redirect
+ setIsIngesting(false);
+ setTimeout(() => {
+ router.push("/knowledge");
+ }, 2000); // 2 second delay to let user see toast
+ } else if (currentTask && currentTask.status === "failed") {
+ // Task failed, clear the tracking but don't redirect
+ setIsIngesting(false);
+ setCurrentSyncTaskId(null);
+ }
+ }, [tasks, currentSyncTaskId, router]);
- const handleFileSelected = (files: CloudFile[]) => {
- setSelectedFiles(files);
- console.log(`Selected ${files.length} files from ${provider}:`, files);
- // You can add additional handling here like triggering sync, etc.
- };
+ const handleFileSelected = (files: CloudFile[]) => {
+ setSelectedFiles(files);
+ console.log(`Selected ${files.length} files from ${provider}:`, files);
+ // You can add additional handling here like triggering sync, etc.
+ };
- const handleSync = async (connector: CloudConnector) => {
- if (!connector.connectionId || selectedFiles.length === 0) return;
+ const handleSync = async (connector: CloudConnector) => {
+ if (!connector.connectionId || selectedFiles.length === 0) return;
- setIsIngesting(true);
+ setIsIngesting(true);
- try {
- const syncBody: {
- connection_id: string;
- max_files?: number;
- selected_files?: string[];
- settings?: IngestSettings;
- } = {
- connection_id: connector.connectionId,
- selected_files: selectedFiles.map((file) => file.id),
- settings: ingestSettings,
- };
+ try {
+ const syncBody: {
+ connection_id: string;
+ max_files?: number;
+ selected_files?: string[];
+ settings?: IngestSettings;
+ } = {
+ connection_id: connector.connectionId,
+ selected_files: selectedFiles.map((file) => file.id),
+ settings: ingestSettings,
+ };
- const response = await fetch(`/api/connectors/${connector.type}/sync`, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify(syncBody),
- });
+ const response = await fetch(`/api/connectors/${connector.type}/sync`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(syncBody),
+ });
- const result = await response.json();
+ const result = await response.json();
- if (response.status === 201) {
- const taskIds = result.task_ids;
- if (taskIds && taskIds.length > 0) {
- const taskId = taskIds[0]; // Use the first task ID
- addTask(taskId);
- setCurrentSyncTaskId(taskId);
- }
- } else {
- console.error("Sync failed:", result.error);
- }
- } catch (error) {
- console.error("Sync error:", error);
- setIsIngesting(false);
- }
- };
+ if (response.status === 201) {
+ const taskIds = result.task_ids;
+ if (taskIds && taskIds.length > 0) {
+ const taskId = taskIds[0]; // Use the first task ID
+ addTask(taskId);
+ setCurrentSyncTaskId(taskId);
+ }
+ } else {
+ console.error("Sync failed:", result.error);
+ }
+ } catch (error) {
+ console.error("Sync error:", error);
+ setIsIngesting(false);
+ }
+ };
- const getProviderDisplayName = () => {
- const nameMap: { [key: string]: string } = {
- google_drive: "Google Drive",
- onedrive: "OneDrive",
- sharepoint: "SharePoint",
- };
- return nameMap[provider] || provider;
- };
+ const getProviderDisplayName = () => {
+ const nameMap: { [key: string]: string } = {
+ google_drive: "Google Drive",
+ onedrive: "OneDrive",
+ sharepoint: "SharePoint",
+ };
+ return nameMap[provider] || provider;
+ };
- if (isLoading) {
- return (
-
-
-
-
-
Loading {getProviderDisplayName()} connector...
-
-
-
- );
- }
+ if (isLoading) {
+ return (
+
+
+
+
+
Loading {getProviderDisplayName()} connector...
+
+
+
+ );
+ }
- if (error || !connector) {
- return (
-
-
-
-
+ if (error || !connector) {
+ return (
+
+
+
+
-
-
-
-
- Provider Not Available
-
-
{error}
-
-
-
-
- );
- }
+
+
+
+
+ Provider Not Available
+
+
{error}
+
+
+
+
+ );
+ }
- if (connector.status !== "connected") {
- return (
-
-
-
-
+ if (connector.status !== "connected") {
+ return (
+
+
+
+
-
-
-
-
- {connector.name} Not Connected
-
-
- You need to connect your {connector.name} account before you can
- select files.
-
-
-
-
-
- );
- }
+
+
+
+
+ {connector.name} Not Connected
+
+
+ You need to connect your {connector.name} account before you can
+ select files.
+
+
+
+
+
+ );
+ }
- if (!connector.hasAccessToken) {
- return (
-
-
-
-
+ if (!connector.hasAccessToken) {
+ return (
+
+
+
+
-
-
-
-
- Access Token Required
-
-
- {connector.accessTokenError ||
- `Unable to get access token for ${connector.name}. Try reconnecting your account.`}
-
-
-
-
-
- );
- }
+
+
+
+
+ Access Token Required
+
+
+ {connector.accessTokenError ||
+ `Unable to get access token for ${connector.name}. Try reconnecting your account.`}
+
+
+
+
+
+ );
+ }
- return (
-
-
-
-
- Add from {getProviderDisplayName()}
-
-
+ return (
+
+
+
+
+ Add from {getProviderDisplayName()}
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
- );
+
+
+
+
+
+
+
+ );
}
From 1643e10d5f215443c9039c1e07d8024613f96546 Mon Sep 17 00:00:00 2001
From: Brent O'Neill
Date: Mon, 6 Oct 2025 09:53:14 -0600
Subject: [PATCH 12/12] Cleanup commented code
---
frontend/src/app/knowledge/chunks/page.tsx | 32 +++++++++++-----------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/frontend/src/app/knowledge/chunks/page.tsx b/frontend/src/app/knowledge/chunks/page.tsx
index 9ae3619c..6288bcfc 100644
--- a/frontend/src/app/knowledge/chunks/page.tsx
+++ b/frontend/src/app/knowledge/chunks/page.tsx
@@ -13,8 +13,8 @@ import {
type File,
useGetSearchQuery,
} from "../../api/queries/useGetSearchQuery";
-import { Label } from "@/components/ui/label";
-import { Checkbox } from "@/components/ui/checkbox";
+// import { Label } from "@/components/ui/label";
+// import { Checkbox } from "@/components/ui/checkbox";
import { filterAccentClasses } from "@/components/knowledge-filter-panel";
const getFileTypeLabel = (mimetype: string) => {
@@ -106,20 +106,20 @@ function ChunksPageContent() {
router.push("/knowledge");
}, [router]);
- const handleChunkCardCheckboxChange = useCallback(
- (index: number) => {
- setSelectedChunks((prevSelected) => {
- const newSelected = new Set(prevSelected);
- if (newSelected.has(index)) {
- newSelected.delete(index);
- } else {
- newSelected.add(index);
- }
- return newSelected;
- });
- },
- [setSelectedChunks]
- );
+ // const handleChunkCardCheckboxChange = useCallback(
+ // (index: number) => {
+ // setSelectedChunks((prevSelected) => {
+ // const newSelected = new Set(prevSelected);
+ // if (newSelected.has(index)) {
+ // newSelected.delete(index);
+ // } else {
+ // newSelected.add(index);
+ // }
+ // return newSelected;
+ // });
+ // },
+ // [setSelectedChunks]
+ // );
if (!filename) {
return (