Merge pull request #190 from langflow-ai/page-style-alignment
Page style alignment
This commit is contained in:
commit
f1bb5a5ad3
8 changed files with 1904 additions and 1907 deletions
|
|
@ -103,7 +103,7 @@ export function KnowledgeDropdown() {
|
||||||
const connections = statusData.connections || [];
|
const connections = statusData.connections || [];
|
||||||
const activeConnection = connections.find(
|
const activeConnection = connections.find(
|
||||||
(conn: { is_active: boolean; connection_id: string }) =>
|
(conn: { is_active: boolean; connection_id: string }) =>
|
||||||
conn.is_active,
|
conn.is_active
|
||||||
);
|
);
|
||||||
const isConnected = activeConnection !== undefined;
|
const isConnected = activeConnection !== undefined;
|
||||||
|
|
||||||
|
|
@ -113,7 +113,7 @@ export function KnowledgeDropdown() {
|
||||||
// Check token availability
|
// Check token availability
|
||||||
try {
|
try {
|
||||||
const tokenRes = await fetch(
|
const tokenRes = await fetch(
|
||||||
`/api/connectors/${type}/token?connection_id=${activeConnection.connection_id}`,
|
`/api/connectors/${type}/token?connection_id=${activeConnection.connection_id}`
|
||||||
);
|
);
|
||||||
if (tokenRes.ok) {
|
if (tokenRes.ok) {
|
||||||
const tokenData = await tokenRes.json();
|
const tokenData = await tokenRes.json();
|
||||||
|
|
@ -175,7 +175,9 @@ export function KnowledgeDropdown() {
|
||||||
// Check if filename already exists (using ORIGINAL filename)
|
// Check if filename already exists (using ORIGINAL filename)
|
||||||
console.log("[Duplicate Check] Checking file:", file.name);
|
console.log("[Duplicate Check] Checking file:", file.name);
|
||||||
const checkResponse = await fetch(
|
const checkResponse = await fetch(
|
||||||
`/api/documents/check-filename?filename=${encodeURIComponent(file.name)}`,
|
`/api/documents/check-filename?filename=${encodeURIComponent(
|
||||||
|
file.name
|
||||||
|
)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("[Duplicate Check] Response status:", checkResponse.status);
|
console.log("[Duplicate Check] Response status:", checkResponse.status);
|
||||||
|
|
@ -184,7 +186,7 @@ export function KnowledgeDropdown() {
|
||||||
const errorText = await checkResponse.text();
|
const errorText = await checkResponse.text();
|
||||||
console.error("[Duplicate Check] Error response:", errorText);
|
console.error("[Duplicate Check] Error response:", errorText);
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Failed to check duplicates: ${checkResponse.statusText}`,
|
`Failed to check duplicates: ${checkResponse.statusText}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,7 +230,7 @@ export function KnowledgeDropdown() {
|
||||||
window.dispatchEvent(
|
window.dispatchEvent(
|
||||||
new CustomEvent("fileUploadStart", {
|
new CustomEvent("fileUploadStart", {
|
||||||
detail: { filename: file.name },
|
detail: { filename: file.name },
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -269,7 +271,7 @@ export function KnowledgeDropdown() {
|
||||||
) {
|
) {
|
||||||
const errorMsg = runJson.error || "Ingestion pipeline failed";
|
const errorMsg = runJson.error || "Ingestion pipeline failed";
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Ingestion failed: ${errorMsg}. Try setting DISABLE_INGEST_WITH_LANGFLOW=true if you're experiencing Langflow component issues.`,
|
`Ingestion failed: ${errorMsg}. Try setting DISABLE_INGEST_WITH_LANGFLOW=true if you're experiencing Langflow component issues.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Log deletion status if provided
|
// Log deletion status if provided
|
||||||
|
|
@ -277,12 +279,12 @@ export function KnowledgeDropdown() {
|
||||||
if (deleteResult.status === "deleted") {
|
if (deleteResult.status === "deleted") {
|
||||||
console.log(
|
console.log(
|
||||||
"File successfully cleaned up from Langflow:",
|
"File successfully cleaned up from Langflow:",
|
||||||
deleteResult.file_id,
|
deleteResult.file_id
|
||||||
);
|
);
|
||||||
} else if (deleteResult.status === "delete_failed") {
|
} else if (deleteResult.status === "delete_failed") {
|
||||||
console.warn(
|
console.warn(
|
||||||
"Failed to cleanup file from Langflow:",
|
"Failed to cleanup file from Langflow:",
|
||||||
deleteResult.error,
|
deleteResult.error
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -299,7 +301,7 @@ export function KnowledgeDropdown() {
|
||||||
unified: true,
|
unified: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
refetchTasks();
|
refetchTasks();
|
||||||
|
|
@ -310,7 +312,7 @@ export function KnowledgeDropdown() {
|
||||||
filename: file.name,
|
filename: file.name,
|
||||||
error: error instanceof Error ? error.message : "Upload failed",
|
error: error instanceof Error ? error.message : "Upload failed",
|
||||||
},
|
},
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
window.dispatchEvent(new CustomEvent("fileUploadComplete"));
|
window.dispatchEvent(new CustomEvent("fileUploadComplete"));
|
||||||
|
|
@ -325,7 +327,7 @@ export function KnowledgeDropdown() {
|
||||||
if (!oldData) return oldData;
|
if (!oldData) return oldData;
|
||||||
// Filter out the file that's being overwritten
|
// Filter out the file that's being overwritten
|
||||||
return oldData.filter(
|
return oldData.filter(
|
||||||
(file: SearchFile) => file.filename !== pendingFile.name,
|
(file: SearchFile) => file.filename !== pendingFile.name
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -494,11 +496,8 @@ export function KnowledgeDropdown() {
|
||||||
onClick={() => !isLoading && setIsOpen(!isOpen)}
|
onClick={() => !isLoading && setIsOpen(!isOpen)}
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
>
|
>
|
||||||
|
|
||||||
<>
|
<>
|
||||||
{isLoading &&
|
{isLoading && <Loader2 className="h-4 w-4 animate-spin" />}
|
||||||
<Loader2 className="h-4 w-4 animate-spin" />
|
|
||||||
}
|
|
||||||
<span>
|
<span>
|
||||||
{isLoading
|
{isLoading
|
||||||
? fileUploading
|
? fileUploading
|
||||||
|
|
@ -516,7 +515,7 @@ export function KnowledgeDropdown() {
|
||||||
<ChevronDown
|
<ChevronDown
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-4 w-4 transition-transform",
|
"h-4 w-4 transition-transform",
|
||||||
isOpen && "rotate-180",
|
isOpen && "rotate-180"
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
@ -537,7 +536,7 @@ export function KnowledgeDropdown() {
|
||||||
"w-full px-3 py-2 text-left text-sm hover:bg-accent hover:text-accent-foreground",
|
"w-full px-3 py-2 text-left text-sm hover:bg-accent hover:text-accent-foreground",
|
||||||
"disabled" in item &&
|
"disabled" in item &&
|
||||||
item.disabled &&
|
item.disabled &&
|
||||||
"opacity-50 cursor-not-allowed hover:bg-transparent hover:text-current",
|
"opacity-50 cursor-not-allowed hover:bg-transparent hover:text-current"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{item.label}
|
{item.label}
|
||||||
|
|
@ -576,7 +575,7 @@ export function KnowledgeDropdown() {
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="/path/to/documents"
|
placeholder="/path/to/documents"
|
||||||
value={folderPath}
|
value={folderPath}
|
||||||
onChange={(e) => setFolderPath(e.target.value)}
|
onChange={e => setFolderPath(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-end gap-2">
|
<div className="flex justify-end gap-2">
|
||||||
|
|
@ -618,7 +617,7 @@ export function KnowledgeDropdown() {
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="s3://bucket/path"
|
placeholder="s3://bucket/path"
|
||||||
value={bucketUrl}
|
value={bucketUrl}
|
||||||
onChange={(e) => setBucketUrl(e.target.value)}
|
onChange={e => setBucketUrl(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-end gap-2">
|
<div className="flex justify-end gap-2">
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ export function KnowledgeFilterList({
|
||||||
<div className="flex-1 min-h-0 flex flex-col">
|
<div className="flex-1 min-h-0 flex flex-col">
|
||||||
<div className="px-3 flex-1 min-h-0 flex flex-col">
|
<div className="px-3 flex-1 min-h-0 flex flex-col">
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<div className="flex items-center justify-between mb-3 ml-3 mr-2">
|
<div className="flex items-center justify-between mb-3 mr-2 ml-4">
|
||||||
<h3 className="text-xs font-medium text-muted-foreground">
|
<h3 className="text-xs font-medium text-muted-foreground">
|
||||||
Knowledge Filters
|
Knowledge Filters
|
||||||
</h3>
|
</h3>
|
||||||
|
|
@ -82,11 +82,11 @@ export function KnowledgeFilterList({
|
||||||
</div>
|
</div>
|
||||||
<div className="overflow-y-auto scrollbar-hide space-y-1">
|
<div className="overflow-y-auto scrollbar-hide space-y-1">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="text-[13px] text-muted-foreground p-2 ml-1">
|
<div className="text-[13px] text-muted-foreground p-2 ml-2">
|
||||||
Loading...
|
Loading...
|
||||||
</div>
|
</div>
|
||||||
) : filters.length === 0 ? (
|
) : filters.length === 0 ? (
|
||||||
<div className="text-[13px] text-muted-foreground p-2 ml-1">
|
<div className="text-[13px] text-muted-foreground pb-2 pt-3 ml-4">
|
||||||
{searchQuery ? "No filters found" : "No saved filters"}
|
{searchQuery ? "No filters found" : "No saved filters"}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ export function KnowledgeFilterPanel() {
|
||||||
// Load available facets using search aggregations hook
|
// Load available facets using search aggregations hook
|
||||||
const { data: aggregations } = useGetSearchAggregations("*", 1, 0, {
|
const { data: aggregations } = useGetSearchAggregations("*", 1, 0, {
|
||||||
enabled: isPanelOpen,
|
enabled: isPanelOpen,
|
||||||
placeholderData: (prev) => prev,
|
placeholderData: prev => prev,
|
||||||
staleTime: 60_000,
|
staleTime: 60_000,
|
||||||
gcTime: 5 * 60_000,
|
gcTime: 5 * 60_000,
|
||||||
});
|
});
|
||||||
|
|
@ -214,7 +214,7 @@ export function KnowledgeFilterPanel() {
|
||||||
facetType: keyof typeof selectedFilters,
|
facetType: keyof typeof selectedFilters,
|
||||||
newValues: string[]
|
newValues: string[]
|
||||||
) => {
|
) => {
|
||||||
setSelectedFilters((prev) => ({
|
setSelectedFilters(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[facetType]: newValues,
|
[facetType]: newValues,
|
||||||
}));
|
}));
|
||||||
|
|
@ -234,7 +234,7 @@ export function KnowledgeFilterPanel() {
|
||||||
return (
|
return (
|
||||||
<div className="h-full bg-background border-l">
|
<div className="h-full bg-background border-l">
|
||||||
<Card className="h-full rounded-none border-0 flex flex-col">
|
<Card className="h-full rounded-none border-0 flex flex-col">
|
||||||
<CardHeader className="pb-3">
|
<CardHeader className="pb-3 pt-3">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<CardTitle className="text-lg flex items-center gap-2">
|
<CardTitle className="text-lg flex items-center gap-2">
|
||||||
Knowledge Filter
|
Knowledge Filter
|
||||||
|
|
@ -271,7 +271,7 @@ export function KnowledgeFilterPanel() {
|
||||||
<Input
|
<Input
|
||||||
id="filter-name"
|
id="filter-name"
|
||||||
value={name}
|
value={name}
|
||||||
onChange={(e) => {
|
onChange={e => {
|
||||||
const v = e.target.value;
|
const v = e.target.value;
|
||||||
setName(v);
|
setName(v);
|
||||||
if (nameError && v.trim()) {
|
if (nameError && v.trim()) {
|
||||||
|
|
@ -302,7 +302,7 @@ export function KnowledgeFilterPanel() {
|
||||||
<Textarea
|
<Textarea
|
||||||
id="filter-description"
|
id="filter-description"
|
||||||
value={description}
|
value={description}
|
||||||
onChange={(e) => setDescription(e.target.value)}
|
onChange={e => setDescription(e.target.value)}
|
||||||
placeholder="Provide a brief description of your knowledge filter..."
|
placeholder="Provide a brief description of your knowledge filter..."
|
||||||
rows={3}
|
rows={3}
|
||||||
/>
|
/>
|
||||||
|
|
@ -319,7 +319,7 @@ export function KnowledgeFilterPanel() {
|
||||||
placeholder="Enter your search query..."
|
placeholder="Enter your search query..."
|
||||||
value={query}
|
value={query}
|
||||||
className="font-mono placeholder:font-mono"
|
className="font-mono placeholder:font-mono"
|
||||||
onChange={(e) => setQuery(e.target.value)}
|
onChange={e => setQuery(e.target.value)}
|
||||||
rows={2}
|
rows={2}
|
||||||
disabled={!!queryOverride && !createMode}
|
disabled={!!queryOverride && !createMode}
|
||||||
/>
|
/>
|
||||||
|
|
@ -329,13 +329,13 @@ export function KnowledgeFilterPanel() {
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<MultiSelect
|
<MultiSelect
|
||||||
options={(availableFacets.data_sources || []).map((bucket) => ({
|
options={(availableFacets.data_sources || []).map(bucket => ({
|
||||||
value: bucket.key,
|
value: bucket.key,
|
||||||
label: bucket.key,
|
label: bucket.key,
|
||||||
count: bucket.count,
|
count: bucket.count,
|
||||||
}))}
|
}))}
|
||||||
value={selectedFilters.data_sources}
|
value={selectedFilters.data_sources}
|
||||||
onValueChange={(values) =>
|
onValueChange={values =>
|
||||||
handleFilterChange("data_sources", values)
|
handleFilterChange("data_sources", values)
|
||||||
}
|
}
|
||||||
placeholder="Select sources..."
|
placeholder="Select sources..."
|
||||||
|
|
@ -345,15 +345,13 @@ export function KnowledgeFilterPanel() {
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<MultiSelect
|
<MultiSelect
|
||||||
options={(availableFacets.document_types || []).map(
|
options={(availableFacets.document_types || []).map(bucket => ({
|
||||||
(bucket) => ({
|
|
||||||
value: bucket.key,
|
value: bucket.key,
|
||||||
label: bucket.key,
|
label: bucket.key,
|
||||||
count: bucket.count,
|
count: bucket.count,
|
||||||
})
|
}))}
|
||||||
)}
|
|
||||||
value={selectedFilters.document_types}
|
value={selectedFilters.document_types}
|
||||||
onValueChange={(values) =>
|
onValueChange={values =>
|
||||||
handleFilterChange("document_types", values)
|
handleFilterChange("document_types", values)
|
||||||
}
|
}
|
||||||
placeholder="Select types..."
|
placeholder="Select types..."
|
||||||
|
|
@ -363,13 +361,13 @@ export function KnowledgeFilterPanel() {
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<MultiSelect
|
<MultiSelect
|
||||||
options={(availableFacets.owners || []).map((bucket) => ({
|
options={(availableFacets.owners || []).map(bucket => ({
|
||||||
value: bucket.key,
|
value: bucket.key,
|
||||||
label: bucket.key,
|
label: bucket.key,
|
||||||
count: bucket.count,
|
count: bucket.count,
|
||||||
}))}
|
}))}
|
||||||
value={selectedFilters.owners}
|
value={selectedFilters.owners}
|
||||||
onValueChange={(values) => handleFilterChange("owners", values)}
|
onValueChange={values => handleFilterChange("owners", values)}
|
||||||
placeholder="Select owners..."
|
placeholder="Select owners..."
|
||||||
allOptionLabel="All Owners"
|
allOptionLabel="All Owners"
|
||||||
/>
|
/>
|
||||||
|
|
@ -378,14 +376,14 @@ export function KnowledgeFilterPanel() {
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<MultiSelect
|
<MultiSelect
|
||||||
options={(availableFacets.connector_types || []).map(
|
options={(availableFacets.connector_types || []).map(
|
||||||
(bucket) => ({
|
bucket => ({
|
||||||
value: bucket.key,
|
value: bucket.key,
|
||||||
label: bucket.key,
|
label: bucket.key,
|
||||||
count: bucket.count,
|
count: bucket.count,
|
||||||
})
|
})
|
||||||
)}
|
)}
|
||||||
value={selectedFilters.connector_types}
|
value={selectedFilters.connector_types}
|
||||||
onValueChange={(values) =>
|
onValueChange={values =>
|
||||||
handleFilterChange("connector_types", values)
|
handleFilterChange("connector_types", values)
|
||||||
}
|
}
|
||||||
placeholder="Select connectors..."
|
placeholder="Select connectors..."
|
||||||
|
|
@ -405,7 +403,7 @@ export function KnowledgeFilterPanel() {
|
||||||
min="1"
|
min="1"
|
||||||
max="1000"
|
max="1000"
|
||||||
value={resultLimit}
|
value={resultLimit}
|
||||||
onChange={(e) => {
|
onChange={e => {
|
||||||
const newLimit = Math.max(
|
const newLimit = Math.max(
|
||||||
1,
|
1,
|
||||||
Math.min(1000, parseInt(e.target.value) || 1)
|
Math.min(1000, parseInt(e.target.value) || 1)
|
||||||
|
|
@ -418,7 +416,7 @@ export function KnowledgeFilterPanel() {
|
||||||
</div>
|
</div>
|
||||||
<Slider
|
<Slider
|
||||||
value={[resultLimit]}
|
value={[resultLimit]}
|
||||||
onValueChange={(values) => setResultLimit(values[0])}
|
onValueChange={values => setResultLimit(values[0])}
|
||||||
max={1000}
|
max={1000}
|
||||||
min={1}
|
min={1}
|
||||||
step={1}
|
step={1}
|
||||||
|
|
@ -438,7 +436,7 @@ export function KnowledgeFilterPanel() {
|
||||||
max="5"
|
max="5"
|
||||||
step="0.1"
|
step="0.1"
|
||||||
value={scoreThreshold}
|
value={scoreThreshold}
|
||||||
onChange={(e) =>
|
onChange={e =>
|
||||||
setScoreThreshold(parseFloat(e.target.value) || 0)
|
setScoreThreshold(parseFloat(e.target.value) || 0)
|
||||||
}
|
}
|
||||||
className="h-6 text-xs text-right px-2 bg-muted/30 !border-0 rounded ml-auto focus:ring-0 focus:outline-none"
|
className="h-6 text-xs text-right px-2 bg-muted/30 !border-0 rounded ml-auto focus:ring-0 focus:outline-none"
|
||||||
|
|
@ -447,7 +445,7 @@ export function KnowledgeFilterPanel() {
|
||||||
</div>
|
</div>
|
||||||
<Slider
|
<Slider
|
||||||
value={[scoreThreshold]}
|
value={[scoreThreshold]}
|
||||||
onValueChange={(values) => setScoreThreshold(values[0])}
|
onValueChange={values => setScoreThreshold(values[0])}
|
||||||
max={5}
|
max={5}
|
||||||
min={0}
|
min={0}
|
||||||
step={0.1}
|
step={0.1}
|
||||||
|
|
|
||||||
|
|
@ -230,7 +230,7 @@ function ChatPage() {
|
||||||
content: `🔄 Starting upload of **${file.name}**...`,
|
content: `🔄 Starting upload of **${file.name}**...`,
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
};
|
};
|
||||||
setMessages((prev) => [...prev, uploadStartMessage]);
|
setMessages(prev => [...prev, uploadStartMessage]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
@ -282,7 +282,7 @@ function ChatPage() {
|
||||||
content: `⏳ Upload initiated for **${file.name}**. Processing in background... (Task ID: ${taskId})`,
|
content: `⏳ Upload initiated for **${file.name}**. Processing in background... (Task ID: ${taskId})`,
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
};
|
};
|
||||||
setMessages((prev) => [...prev.slice(0, -1), pollingMessage]);
|
setMessages(prev => [...prev.slice(0, -1), pollingMessage]);
|
||||||
} else if (response.ok) {
|
} else if (response.ok) {
|
||||||
// Original flow: Direct response
|
// Original flow: Direct response
|
||||||
|
|
||||||
|
|
@ -296,7 +296,7 @@ function ChatPage() {
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
};
|
};
|
||||||
|
|
||||||
setMessages((prev) => [...prev.slice(0, -1), uploadMessage]);
|
setMessages(prev => [...prev.slice(0, -1), uploadMessage]);
|
||||||
|
|
||||||
// Add file to conversation docs
|
// Add file to conversation docs
|
||||||
if (result.filename) {
|
if (result.filename) {
|
||||||
|
|
@ -305,7 +305,7 @@ function ChatPage() {
|
||||||
|
|
||||||
// Update the response ID for this endpoint
|
// Update the response ID for this endpoint
|
||||||
if (result.response_id) {
|
if (result.response_id) {
|
||||||
setPreviousResponseIds((prev) => ({
|
setPreviousResponseIds(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[endpoint]: result.response_id,
|
[endpoint]: result.response_id,
|
||||||
}));
|
}));
|
||||||
|
|
@ -329,7 +329,7 @@ function ChatPage() {
|
||||||
content: `❌ Failed to process document. Please try again.`,
|
content: `❌ Failed to process document. Please try again.`,
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
};
|
};
|
||||||
setMessages((prev) => [...prev.slice(0, -1), errorMessage]);
|
setMessages(prev => [...prev.slice(0, -1), errorMessage]);
|
||||||
} finally {
|
} finally {
|
||||||
setIsUploading(false);
|
setIsUploading(false);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
@ -620,7 +620,7 @@ function ChatPage() {
|
||||||
lastLoadedConversationRef.current = conversationData.response_id;
|
lastLoadedConversationRef.current = conversationData.response_id;
|
||||||
|
|
||||||
// Set the previous response ID for this conversation
|
// Set the previous response ID for this conversation
|
||||||
setPreviousResponseIds((prev) => ({
|
setPreviousResponseIds(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[conversationData.endpoint]: conversationData.response_id,
|
[conversationData.endpoint]: conversationData.response_id,
|
||||||
}));
|
}));
|
||||||
|
|
@ -662,7 +662,7 @@ function ChatPage() {
|
||||||
content: `🔄 Starting upload of **${filename}**...`,
|
content: `🔄 Starting upload of **${filename}**...`,
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
};
|
};
|
||||||
setMessages((prev) => [...prev, uploadStartMessage]);
|
setMessages(prev => [...prev, uploadStartMessage]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFileUploaded = (event: CustomEvent) => {
|
const handleFileUploaded = (event: CustomEvent) => {
|
||||||
|
|
@ -680,11 +680,11 @@ function ChatPage() {
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
};
|
};
|
||||||
|
|
||||||
setMessages((prev) => [...prev.slice(0, -1), uploadMessage]);
|
setMessages(prev => [...prev.slice(0, -1), uploadMessage]);
|
||||||
|
|
||||||
// Update the response ID for this endpoint
|
// Update the response ID for this endpoint
|
||||||
if (result.response_id) {
|
if (result.response_id) {
|
||||||
setPreviousResponseIds((prev) => ({
|
setPreviousResponseIds(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[endpoint]: result.response_id,
|
[endpoint]: result.response_id,
|
||||||
}));
|
}));
|
||||||
|
|
@ -711,7 +711,7 @@ function ChatPage() {
|
||||||
content: `❌ Upload failed for **${filename}**: ${error}`,
|
content: `❌ Upload failed for **${filename}**: ${error}`,
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
};
|
};
|
||||||
setMessages((prev) => [...prev.slice(0, -1), errorMessage]);
|
setMessages(prev => [...prev.slice(0, -1), errorMessage]);
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener(
|
window.addEventListener(
|
||||||
|
|
@ -1007,7 +1007,7 @@ function ChatPage() {
|
||||||
if (chunk.delta.finish_reason) {
|
if (chunk.delta.finish_reason) {
|
||||||
console.log("Finish reason:", chunk.delta.finish_reason);
|
console.log("Finish reason:", chunk.delta.finish_reason);
|
||||||
// Mark any pending function calls as completed
|
// Mark any pending function calls as completed
|
||||||
currentFunctionCalls.forEach((fc) => {
|
currentFunctionCalls.forEach(fc => {
|
||||||
if (fc.status === "pending" && fc.argumentsString) {
|
if (fc.status === "pending" && fc.argumentsString) {
|
||||||
try {
|
try {
|
||||||
fc.arguments = JSON.parse(fc.argumentsString);
|
fc.arguments = JSON.parse(fc.argumentsString);
|
||||||
|
|
@ -1040,13 +1040,13 @@ function ChatPage() {
|
||||||
|
|
||||||
// Try to find an existing pending call to update (created by earlier deltas)
|
// Try to find an existing pending call to update (created by earlier deltas)
|
||||||
let existing = currentFunctionCalls.find(
|
let existing = currentFunctionCalls.find(
|
||||||
(fc) => fc.id === chunk.item.id
|
fc => fc.id === chunk.item.id
|
||||||
);
|
);
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
existing = [...currentFunctionCalls]
|
existing = [...currentFunctionCalls]
|
||||||
.reverse()
|
.reverse()
|
||||||
.find(
|
.find(
|
||||||
(fc) =>
|
fc =>
|
||||||
fc.status === "pending" &&
|
fc.status === "pending" &&
|
||||||
!fc.id &&
|
!fc.id &&
|
||||||
fc.name === (chunk.item.tool_name || chunk.item.name)
|
fc.name === (chunk.item.tool_name || chunk.item.name)
|
||||||
|
|
@ -1077,7 +1077,7 @@ function ChatPage() {
|
||||||
currentFunctionCalls.push(functionCall);
|
currentFunctionCalls.push(functionCall);
|
||||||
console.log(
|
console.log(
|
||||||
"🟢 Function calls now:",
|
"🟢 Function calls now:",
|
||||||
currentFunctionCalls.map((fc) => ({
|
currentFunctionCalls.map(fc => ({
|
||||||
id: fc.id,
|
id: fc.id,
|
||||||
name: fc.name,
|
name: fc.name,
|
||||||
}))
|
}))
|
||||||
|
|
@ -1150,7 +1150,7 @@ function ChatPage() {
|
||||||
);
|
);
|
||||||
console.log(
|
console.log(
|
||||||
"🔵 Looking for existing function calls:",
|
"🔵 Looking for existing function calls:",
|
||||||
currentFunctionCalls.map((fc) => ({
|
currentFunctionCalls.map(fc => ({
|
||||||
id: fc.id,
|
id: fc.id,
|
||||||
name: fc.name,
|
name: fc.name,
|
||||||
}))
|
}))
|
||||||
|
|
@ -1158,7 +1158,7 @@ function ChatPage() {
|
||||||
|
|
||||||
// Find existing function call by ID or name
|
// Find existing function call by ID or name
|
||||||
const functionCall = currentFunctionCalls.find(
|
const functionCall = currentFunctionCalls.find(
|
||||||
(fc) =>
|
fc =>
|
||||||
fc.id === chunk.item.id ||
|
fc.id === chunk.item.id ||
|
||||||
fc.name === chunk.item.tool_name ||
|
fc.name === chunk.item.tool_name ||
|
||||||
fc.name === chunk.item.name
|
fc.name === chunk.item.name
|
||||||
|
|
@ -1206,7 +1206,7 @@ function ChatPage() {
|
||||||
|
|
||||||
// Find existing function call by ID, or by name/type if ID not available
|
// Find existing function call by ID, or by name/type if ID not available
|
||||||
const functionCall = currentFunctionCalls.find(
|
const functionCall = currentFunctionCalls.find(
|
||||||
(fc) =>
|
fc =>
|
||||||
fc.id === chunk.item.id ||
|
fc.id === chunk.item.id ||
|
||||||
fc.name === chunk.item.tool_name ||
|
fc.name === chunk.item.tool_name ||
|
||||||
fc.name === chunk.item.name ||
|
fc.name === chunk.item.name ||
|
||||||
|
|
@ -1261,13 +1261,13 @@ function ChatPage() {
|
||||||
|
|
||||||
// Dedupe by id or pending with same name
|
// Dedupe by id or pending with same name
|
||||||
let existing = currentFunctionCalls.find(
|
let existing = currentFunctionCalls.find(
|
||||||
(fc) => fc.id === chunk.item.id
|
fc => fc.id === chunk.item.id
|
||||||
);
|
);
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
existing = [...currentFunctionCalls]
|
existing = [...currentFunctionCalls]
|
||||||
.reverse()
|
.reverse()
|
||||||
.find(
|
.find(
|
||||||
(fc) =>
|
fc =>
|
||||||
fc.status === "pending" &&
|
fc.status === "pending" &&
|
||||||
!fc.id &&
|
!fc.id &&
|
||||||
fc.name ===
|
fc.name ===
|
||||||
|
|
@ -1306,7 +1306,7 @@ function ChatPage() {
|
||||||
currentFunctionCalls.push(functionCall);
|
currentFunctionCalls.push(functionCall);
|
||||||
console.log(
|
console.log(
|
||||||
"🟡 Function calls now:",
|
"🟡 Function calls now:",
|
||||||
currentFunctionCalls.map((fc) => ({
|
currentFunctionCalls.map(fc => ({
|
||||||
id: fc.id,
|
id: fc.id,
|
||||||
name: fc.name,
|
name: fc.name,
|
||||||
type: fc.type,
|
type: fc.type,
|
||||||
|
|
@ -1404,7 +1404,7 @@ function ChatPage() {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!controller.signal.aborted && thisStreamId === streamIdRef.current) {
|
if (!controller.signal.aborted && thisStreamId === streamIdRef.current) {
|
||||||
setMessages((prev) => [...prev, finalMessage]);
|
setMessages(prev => [...prev, finalMessage]);
|
||||||
setStreamingMessage(null);
|
setStreamingMessage(null);
|
||||||
if (previousResponseIds[endpoint]) {
|
if (previousResponseIds[endpoint]) {
|
||||||
cancelNudges();
|
cancelNudges();
|
||||||
|
|
@ -1417,7 +1417,7 @@ function ChatPage() {
|
||||||
!controller.signal.aborted &&
|
!controller.signal.aborted &&
|
||||||
thisStreamId === streamIdRef.current
|
thisStreamId === streamIdRef.current
|
||||||
) {
|
) {
|
||||||
setPreviousResponseIds((prev) => ({
|
setPreviousResponseIds(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[endpoint]: newResponseId,
|
[endpoint]: newResponseId,
|
||||||
}));
|
}));
|
||||||
|
|
@ -1445,7 +1445,7 @@ function ChatPage() {
|
||||||
"Sorry, I couldn't connect to the chat service. Please try again.",
|
"Sorry, I couldn't connect to the chat service. Please try again.",
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
};
|
};
|
||||||
setMessages((prev) => [...prev, errorMessage]);
|
setMessages(prev => [...prev, errorMessage]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1458,7 +1458,7 @@ function ChatPage() {
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
};
|
};
|
||||||
|
|
||||||
setMessages((prev) => [...prev, userMessage]);
|
setMessages(prev => [...prev, userMessage]);
|
||||||
setInput("");
|
setInput("");
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setIsFilterHighlighted(false);
|
setIsFilterHighlighted(false);
|
||||||
|
|
@ -1524,14 +1524,14 @@ function ChatPage() {
|
||||||
content: result.response,
|
content: result.response,
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
};
|
};
|
||||||
setMessages((prev) => [...prev, assistantMessage]);
|
setMessages(prev => [...prev, assistantMessage]);
|
||||||
if (result.response_id) {
|
if (result.response_id) {
|
||||||
cancelNudges();
|
cancelNudges();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the response ID if present for this endpoint
|
// Store the response ID if present for this endpoint
|
||||||
if (result.response_id) {
|
if (result.response_id) {
|
||||||
setPreviousResponseIds((prev) => ({
|
setPreviousResponseIds(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[endpoint]: result.response_id,
|
[endpoint]: result.response_id,
|
||||||
}));
|
}));
|
||||||
|
|
@ -1552,7 +1552,7 @@ function ChatPage() {
|
||||||
content: "Sorry, I encountered an error. Please try again.",
|
content: "Sorry, I encountered an error. Please try again.",
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
};
|
};
|
||||||
setMessages((prev) => [...prev, errorMessage]);
|
setMessages(prev => [...prev, errorMessage]);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Chat error:", error);
|
console.error("Chat error:", error);
|
||||||
|
|
@ -1562,7 +1562,7 @@ function ChatPage() {
|
||||||
"Sorry, I couldn't connect to the chat service. Please try again.",
|
"Sorry, I couldn't connect to the chat service. Please try again.",
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
};
|
};
|
||||||
setMessages((prev) => [...prev, errorMessage]);
|
setMessages(prev => [...prev, errorMessage]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1575,7 +1575,7 @@ function ChatPage() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleFunctionCall = (functionCallId: string) => {
|
const toggleFunctionCall = (functionCallId: string) => {
|
||||||
setExpandedFunctionCalls((prev) => {
|
setExpandedFunctionCalls(prev => {
|
||||||
const newSet = new Set(prev);
|
const newSet = new Set(prev);
|
||||||
if (newSet.has(functionCallId)) {
|
if (newSet.has(functionCallId)) {
|
||||||
newSet.delete(functionCallId);
|
newSet.delete(functionCallId);
|
||||||
|
|
@ -1632,7 +1632,7 @@ function ChatPage() {
|
||||||
|
|
||||||
// Set the response_id we want to continue from as the previous response ID
|
// Set the response_id we want to continue from as the previous response ID
|
||||||
// This tells the backend to continue the conversation from this point
|
// This tells the backend to continue the conversation from this point
|
||||||
setPreviousResponseIds((prev) => ({
|
setPreviousResponseIds(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[endpoint]: responseIdToForkFrom,
|
[endpoint]: responseIdToForkFrom,
|
||||||
}));
|
}));
|
||||||
|
|
@ -1903,7 +1903,7 @@ function ChatPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFilterDropdownOpen) {
|
if (isFilterDropdownOpen) {
|
||||||
const filteredFilters = availableFilters.filter((filter) =>
|
const filteredFilters = availableFilters.filter(filter =>
|
||||||
filter.name.toLowerCase().includes(filterSearchTerm.toLowerCase())
|
filter.name.toLowerCase().includes(filterSearchTerm.toLowerCase())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -1921,7 +1921,7 @@ function ChatPage() {
|
||||||
|
|
||||||
if (e.key === "ArrowDown") {
|
if (e.key === "ArrowDown") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setSelectedFilterIndex((prev) =>
|
setSelectedFilterIndex(prev =>
|
||||||
prev < filteredFilters.length - 1 ? prev + 1 : 0
|
prev < filteredFilters.length - 1 ? prev + 1 : 0
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
|
@ -1929,7 +1929,7 @@ function ChatPage() {
|
||||||
|
|
||||||
if (e.key === "ArrowUp") {
|
if (e.key === "ArrowUp") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setSelectedFilterIndex((prev) =>
|
setSelectedFilterIndex(prev =>
|
||||||
prev > 0 ? prev - 1 : filteredFilters.length - 1
|
prev > 0 ? prev - 1 : filteredFilters.length - 1
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
|
@ -2159,7 +2159,7 @@ function ChatPage() {
|
||||||
{endpoint === "chat" && (
|
{endpoint === "chat" && (
|
||||||
<div className="flex-shrink-0 ml-2">
|
<div className="flex-shrink-0 ml-2">
|
||||||
<button
|
<button
|
||||||
onClick={(e) => handleForkConversation(index, e)}
|
onClick={e => handleForkConversation(index, e)}
|
||||||
className="opacity-0 group-hover:opacity-100 transition-opacity p-1 hover:bg-accent rounded text-muted-foreground hover:text-foreground"
|
className="opacity-0 group-hover:opacity-100 transition-opacity p-1 hover:bg-accent rounded text-muted-foreground hover:text-foreground"
|
||||||
title="Fork conversation from here"
|
title="Fork conversation from here"
|
||||||
>
|
>
|
||||||
|
|
@ -2223,8 +2223,8 @@ function ChatPage() {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Input Area - Fixed at bottom */}
|
{/* Input Area - Fixed at bottom */}
|
||||||
<div className="flex-shrink-0 p-6 pb-8 pt-4 flex justify-center">
|
<div className="pb-8 pt-4 flex px-6">
|
||||||
<div className="w-full max-w-[75%]">
|
<div className="w-full">
|
||||||
<form onSubmit={handleSubmit} className="relative">
|
<form onSubmit={handleSubmit} className="relative">
|
||||||
<div className="relative w-full bg-muted/20 rounded-lg border border-border/50 focus-within:ring-1 focus-within:ring-ring">
|
<div className="relative w-full bg-muted/20 rounded-lg border border-border/50 focus-within:ring-1 focus-within:ring-ring">
|
||||||
{selectedFilter && (
|
{selectedFilter && (
|
||||||
|
|
@ -2257,7 +2257,7 @@ function ChatPage() {
|
||||||
value={input}
|
value={input}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
onHeightChange={(height) => setTextareaHeight(height)}
|
onHeightChange={height => setTextareaHeight(height)}
|
||||||
maxRows={7}
|
maxRows={7}
|
||||||
minRows={2}
|
minRows={2}
|
||||||
placeholder="Type to ask a question..."
|
placeholder="Type to ask a question..."
|
||||||
|
|
@ -2286,7 +2286,7 @@ function ChatPage() {
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="iconSm"
|
size="iconSm"
|
||||||
className="absolute bottom-3 left-3 h-8 w-8 p-0 rounded-full hover:bg-muted/50"
|
className="absolute bottom-3 left-3 h-8 w-8 p-0 rounded-full hover:bg-muted/50"
|
||||||
onMouseDown={(e) => {
|
onMouseDown={e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}}
|
}}
|
||||||
onClick={onAtClick}
|
onClick={onAtClick}
|
||||||
|
|
@ -2296,7 +2296,7 @@ function ChatPage() {
|
||||||
</Button>
|
</Button>
|
||||||
<Popover
|
<Popover
|
||||||
open={isFilterDropdownOpen}
|
open={isFilterDropdownOpen}
|
||||||
onOpenChange={(open) => {
|
onOpenChange={open => {
|
||||||
setIsFilterDropdownOpen(open);
|
setIsFilterDropdownOpen(open);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -2321,7 +2321,7 @@ function ChatPage() {
|
||||||
align="start"
|
align="start"
|
||||||
sideOffset={6}
|
sideOffset={6}
|
||||||
alignOffset={-18}
|
alignOffset={-18}
|
||||||
onOpenAutoFocus={(e) => {
|
onOpenAutoFocus={e => {
|
||||||
// Prevent auto focus on the popover content
|
// Prevent auto focus on the popover content
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
// Keep focus on the input
|
// Keep focus on the input
|
||||||
|
|
@ -2354,7 +2354,7 @@ function ChatPage() {
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{availableFilters
|
{availableFilters
|
||||||
.filter((filter) =>
|
.filter(filter =>
|
||||||
filter.name
|
filter.name
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.includes(filterSearchTerm.toLowerCase())
|
.includes(filterSearchTerm.toLowerCase())
|
||||||
|
|
@ -2383,7 +2383,7 @@ function ChatPage() {
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
{availableFilters.filter((filter) =>
|
{availableFilters.filter(filter =>
|
||||||
filter.name
|
filter.name
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.includes(filterSearchTerm.toLowerCase())
|
.includes(filterSearchTerm.toLowerCase())
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ function ChunksPageContent() {
|
||||||
() =>
|
() =>
|
||||||
chunks.reduce((acc, chunk) => acc + chunk.text.length, 0) /
|
chunks.reduce((acc, chunk) => acc + chunk.text.length, 0) /
|
||||||
chunks.length || 0,
|
chunks.length || 0,
|
||||||
[chunks],
|
[chunks]
|
||||||
);
|
);
|
||||||
|
|
||||||
// const [selectAll, setSelectAll] = useState(false);
|
// const [selectAll, setSelectAll] = useState(false);
|
||||||
|
|
@ -67,7 +67,7 @@ function ChunksPageContent() {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const fileData = (data as File[]).find(
|
const fileData = (data as File[]).find(
|
||||||
(file: File) => file.filename === filename,
|
(file: File) => file.filename === filename
|
||||||
);
|
);
|
||||||
|
|
||||||
// Extract chunks for the specific file
|
// Extract chunks for the specific file
|
||||||
|
|
@ -78,7 +78,7 @@ function ChunksPageContent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
setChunks(
|
setChunks(
|
||||||
fileData?.chunks?.map((chunk, i) => ({ ...chunk, index: i + 1 })) || [],
|
fileData?.chunks?.map((chunk, i) => ({ ...chunk, index: i + 1 })) || []
|
||||||
);
|
);
|
||||||
}, [data, filename]);
|
}, [data, filename]);
|
||||||
|
|
||||||
|
|
@ -149,7 +149,7 @@ function ChunksPageContent() {
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="selectAllChunks"
|
id="selectAllChunks"
|
||||||
checked={selectAll}
|
checked={selectAll}
|
||||||
onCheckedChange={(handleSelectAll) =>
|
onCheckedChange={handleSelectAll =>
|
||||||
setSelectAll(!!handleSelectAll)
|
setSelectAll(!!handleSelectAll)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ function SearchPage() {
|
||||||
parsedFilterData
|
parsedFilterData
|
||||||
);
|
);
|
||||||
// Convert TaskFiles to File format and merge with backend results
|
// Convert TaskFiles to File format and merge with backend results
|
||||||
const taskFilesAsFiles: File[] = taskFiles.map((taskFile) => {
|
const taskFilesAsFiles: File[] = taskFiles.map(taskFile => {
|
||||||
return {
|
return {
|
||||||
filename: taskFile.filename,
|
filename: taskFile.filename,
|
||||||
mimetype: taskFile.mimetype,
|
mimetype: taskFile.mimetype,
|
||||||
|
|
@ -82,12 +82,12 @@ function SearchPage() {
|
||||||
|
|
||||||
// Create a map of task files by filename for quick lookup
|
// Create a map of task files by filename for quick lookup
|
||||||
const taskFileMap = new Map(
|
const taskFileMap = new Map(
|
||||||
taskFilesAsFiles.map((file) => [file.filename, file])
|
taskFilesAsFiles.map(file => [file.filename, file])
|
||||||
);
|
);
|
||||||
|
|
||||||
// Override backend files with task file status if they exist
|
// Override backend files with task file status if they exist
|
||||||
const backendFiles = (searchData as File[])
|
const backendFiles = (searchData as File[])
|
||||||
.map((file) => {
|
.map(file => {
|
||||||
const taskFile = taskFileMap.get(file.filename);
|
const taskFile = taskFileMap.get(file.filename);
|
||||||
if (taskFile) {
|
if (taskFile) {
|
||||||
// Override backend file with task file data (includes status)
|
// Override backend file with task file data (includes status)
|
||||||
|
|
@ -95,17 +95,17 @@ function SearchPage() {
|
||||||
}
|
}
|
||||||
return file;
|
return file;
|
||||||
})
|
})
|
||||||
.filter((file) => {
|
.filter(file => {
|
||||||
// Only filter out files that are currently processing AND in taskFiles
|
// Only filter out files that are currently processing AND in taskFiles
|
||||||
const taskFile = taskFileMap.get(file.filename);
|
const taskFile = taskFileMap.get(file.filename);
|
||||||
return !taskFile || taskFile.status !== "processing";
|
return !taskFile || taskFile.status !== "processing";
|
||||||
});
|
});
|
||||||
|
|
||||||
const filteredTaskFiles = taskFilesAsFiles.filter((taskFile) => {
|
const filteredTaskFiles = taskFilesAsFiles.filter(taskFile => {
|
||||||
return (
|
return (
|
||||||
taskFile.status !== "active" &&
|
taskFile.status !== "active" &&
|
||||||
!backendFiles.some(
|
!backendFiles.some(
|
||||||
(backendFile) => backendFile.filename === taskFile.filename
|
backendFile => backendFile.filename === taskFile.filename
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
@ -184,7 +184,6 @@ function SearchPage() {
|
||||||
{
|
{
|
||||||
field: "avgScore",
|
field: "avgScore",
|
||||||
headerName: "Avg score",
|
headerName: "Avg score",
|
||||||
initialFlex: 0.5,
|
|
||||||
cellRenderer: ({ value }: CustomCellRendererProps<File>) => {
|
cellRenderer: ({ value }: CustomCellRendererProps<File>) => {
|
||||||
return (
|
return (
|
||||||
<span className="text-xs text-accent-emerald-foreground bg-accent-emerald px-2 py-1 rounded">
|
<span className="text-xs text-accent-emerald-foreground bg-accent-emerald px-2 py-1 rounded">
|
||||||
|
|
@ -246,7 +245,7 @@ function SearchPage() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Delete each file individually since the API expects one filename at a time
|
// Delete each file individually since the API expects one filename at a time
|
||||||
const deletePromises = selectedRows.map((row) =>
|
const deletePromises = selectedRows.map(row =>
|
||||||
deleteDocumentMutation.mutateAsync({ filename: row.filename })
|
deleteDocumentMutation.mutateAsync({ filename: row.filename })
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -345,7 +344,7 @@ function SearchPage() {
|
||||||
}? This will remove all chunks and data associated with these documents. This action cannot be undone.
|
}? This will remove all chunks and data associated with these documents. This action cannot be undone.
|
||||||
|
|
||||||
Documents to be deleted:
|
Documents to be deleted:
|
||||||
${selectedRows.map((row) => `• ${row.filename}`).join("\n")}`}
|
${selectedRows.map(row => `• ${row.filename}`).join("\n")}`}
|
||||||
confirmText="Delete All"
|
confirmText="Delete All"
|
||||||
onConfirm={handleBulkDelete}
|
onConfirm={handleBulkDelete}
|
||||||
isLoading={deleteDocumentMutation.isPending}
|
isLoading={deleteDocumentMutation.isPending}
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ function KnowledgeSourcesPage() {
|
||||||
{
|
{
|
||||||
enabled:
|
enabled:
|
||||||
(isAuthenticated || isNoAuthMode) && currentProvider === "openai",
|
(isAuthenticated || isNoAuthMode) && currentProvider === "openai",
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: ollamaModelsData } = useGetOllamaModelsQuery(
|
const { data: ollamaModelsData } = useGetOllamaModelsQuery(
|
||||||
|
|
@ -177,7 +177,7 @@ function KnowledgeSourcesPage() {
|
||||||
{
|
{
|
||||||
enabled:
|
enabled:
|
||||||
(isAuthenticated || isNoAuthMode) && currentProvider === "ollama",
|
(isAuthenticated || isNoAuthMode) && currentProvider === "ollama",
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: ibmModelsData } = useGetIBMModelsQuery(
|
const { data: ibmModelsData } = useGetIBMModelsQuery(
|
||||||
|
|
@ -185,7 +185,7 @@ function KnowledgeSourcesPage() {
|
||||||
{
|
{
|
||||||
enabled:
|
enabled:
|
||||||
(isAuthenticated || isNoAuthMode) && currentProvider === "watsonx",
|
(isAuthenticated || isNoAuthMode) && currentProvider === "watsonx",
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Select the appropriate models data based on provider
|
// Select the appropriate models data based on provider
|
||||||
|
|
@ -203,7 +203,7 @@ function KnowledgeSourcesPage() {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
console.log("Setting updated successfully");
|
console.log("Setting updated successfully");
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: error => {
|
||||||
console.error("Failed to update setting:", error.message);
|
console.error("Failed to update setting:", error.message);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -213,7 +213,7 @@ function KnowledgeSourcesPage() {
|
||||||
(variables: Parameters<typeof updateFlowSettingMutation.mutate>[0]) => {
|
(variables: Parameters<typeof updateFlowSettingMutation.mutate>[0]) => {
|
||||||
updateFlowSettingMutation.mutate(variables);
|
updateFlowSettingMutation.mutate(variables);
|
||||||
},
|
},
|
||||||
500,
|
500
|
||||||
);
|
);
|
||||||
|
|
||||||
// Sync system prompt state with settings data
|
// Sync system prompt state with settings data
|
||||||
|
|
@ -338,8 +338,8 @@ function KnowledgeSourcesPage() {
|
||||||
|
|
||||||
// Initialize connectors list with metadata from backend
|
// Initialize connectors list with metadata from backend
|
||||||
const initialConnectors = connectorTypes
|
const initialConnectors = connectorTypes
|
||||||
.filter((type) => connectorsResult.connectors[type].available) // Only show available connectors
|
.filter(type => connectorsResult.connectors[type].available) // Only show available connectors
|
||||||
.map((type) => ({
|
.map(type => ({
|
||||||
id: type,
|
id: type,
|
||||||
name: connectorsResult.connectors[type].name,
|
name: connectorsResult.connectors[type].name,
|
||||||
description: connectorsResult.connectors[type].description,
|
description: connectorsResult.connectors[type].description,
|
||||||
|
|
@ -358,20 +358,20 @@ function KnowledgeSourcesPage() {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
const connections = data.connections || [];
|
const connections = data.connections || [];
|
||||||
const activeConnection = connections.find(
|
const activeConnection = connections.find(
|
||||||
(conn: Connection) => conn.is_active,
|
(conn: Connection) => conn.is_active
|
||||||
);
|
);
|
||||||
const isConnected = activeConnection !== undefined;
|
const isConnected = activeConnection !== undefined;
|
||||||
|
|
||||||
setConnectors((prev) =>
|
setConnectors(prev =>
|
||||||
prev.map((c) =>
|
prev.map(c =>
|
||||||
c.type === connectorType
|
c.type === connectorType
|
||||||
? {
|
? {
|
||||||
...c,
|
...c,
|
||||||
status: isConnected ? "connected" : "not_connected",
|
status: isConnected ? "connected" : "not_connected",
|
||||||
connectionId: activeConnection?.connection_id,
|
connectionId: activeConnection?.connection_id,
|
||||||
}
|
}
|
||||||
: c,
|
: c
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -382,7 +382,7 @@ function KnowledgeSourcesPage() {
|
||||||
|
|
||||||
const handleConnect = async (connector: Connector) => {
|
const handleConnect = async (connector: Connector) => {
|
||||||
setIsConnecting(connector.id);
|
setIsConnecting(connector.id);
|
||||||
setSyncResults((prev) => ({ ...prev, [connector.id]: null }));
|
setSyncResults(prev => ({ ...prev, [connector.id]: null }));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Use the shared auth callback URL, same as connectors page
|
// Use the shared auth callback URL, same as connectors page
|
||||||
|
|
@ -414,7 +414,7 @@ function KnowledgeSourcesPage() {
|
||||||
`response_type=code&` +
|
`response_type=code&` +
|
||||||
`scope=${result.oauth_config.scopes.join(" ")}&` +
|
`scope=${result.oauth_config.scopes.join(" ")}&` +
|
||||||
`redirect_uri=${encodeURIComponent(
|
`redirect_uri=${encodeURIComponent(
|
||||||
result.oauth_config.redirect_uri,
|
result.oauth_config.redirect_uri
|
||||||
)}&` +
|
)}&` +
|
||||||
`access_type=offline&` +
|
`access_type=offline&` +
|
||||||
`prompt=consent&` +
|
`prompt=consent&` +
|
||||||
|
|
@ -522,9 +522,9 @@ function KnowledgeSourcesPage() {
|
||||||
// Watch for task completions and refresh stats
|
// Watch for task completions and refresh stats
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Find newly completed tasks by comparing with previous state
|
// Find newly completed tasks by comparing with previous state
|
||||||
const newlyCompletedTasks = tasks.filter((task) => {
|
const newlyCompletedTasks = tasks.filter(task => {
|
||||||
const wasCompleted =
|
const wasCompleted =
|
||||||
prevTasks.find((prev) => prev.task_id === task.task_id)?.status ===
|
prevTasks.find(prev => prev.task_id === task.task_id)?.status ===
|
||||||
"completed";
|
"completed";
|
||||||
return task.status === "completed" && !wasCompleted;
|
return task.status === "completed" && !wasCompleted;
|
||||||
});
|
});
|
||||||
|
|
@ -547,7 +547,7 @@ function KnowledgeSourcesPage() {
|
||||||
|
|
||||||
const handleEditInLangflow = (
|
const handleEditInLangflow = (
|
||||||
flowType: "chat" | "ingest",
|
flowType: "chat" | "ingest",
|
||||||
closeDialog: () => void,
|
closeDialog: () => void
|
||||||
) => {
|
) => {
|
||||||
// Select the appropriate flow ID and edit URL based on flow type
|
// Select the appropriate flow ID and edit URL based on flow type
|
||||||
const targetFlowId =
|
const targetFlowId =
|
||||||
|
|
@ -578,7 +578,7 @@ function KnowledgeSourcesPage() {
|
||||||
fetch(`/api/reset-flow/retrieval`, {
|
fetch(`/api/reset-flow/retrieval`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then(response => {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
return response.json();
|
return response.json();
|
||||||
}
|
}
|
||||||
|
|
@ -591,7 +591,7 @@ function KnowledgeSourcesPage() {
|
||||||
handleModelChange(DEFAULT_AGENT_SETTINGS.llm_model);
|
handleModelChange(DEFAULT_AGENT_SETTINGS.llm_model);
|
||||||
closeDialog(); // Close after successful completion
|
closeDialog(); // Close after successful completion
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch(error => {
|
||||||
console.error("Error restoring retrieval flow:", error);
|
console.error("Error restoring retrieval flow:", error);
|
||||||
closeDialog(); // Close even on error (could show error toast instead)
|
closeDialog(); // Close even on error (could show error toast instead)
|
||||||
});
|
});
|
||||||
|
|
@ -601,7 +601,7 @@ function KnowledgeSourcesPage() {
|
||||||
fetch(`/api/reset-flow/ingest`, {
|
fetch(`/api/reset-flow/ingest`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then(response => {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
return response.json();
|
return response.json();
|
||||||
}
|
}
|
||||||
|
|
@ -616,7 +616,7 @@ function KnowledgeSourcesPage() {
|
||||||
setPictureDescriptions(false);
|
setPictureDescriptions(false);
|
||||||
closeDialog(); // Close after successful completion
|
closeDialog(); // Close after successful completion
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch(error => {
|
||||||
console.error("Error restoring ingest flow:", error);
|
console.error("Error restoring ingest flow:", error);
|
||||||
closeDialog(); // Close even on error (could show error toast instead)
|
closeDialog(); // Close even on error (could show error toast instead)
|
||||||
});
|
});
|
||||||
|
|
@ -738,10 +738,8 @@ function KnowledgeSourcesPage() {
|
||||||
|
|
||||||
{/* Connectors Grid */}
|
{/* Connectors Grid */}
|
||||||
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||||
{DEFAULT_CONNECTORS.map((connector) => {
|
{DEFAULT_CONNECTORS.map(connector => {
|
||||||
const actualConnector = connectors.find(
|
const actualConnector = connectors.find(c => c.id === connector.id);
|
||||||
(c) => c.id === connector.id,
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<Card key={connector.id} className="relative flex flex-col">
|
<Card key={connector.id} className="relative flex flex-col">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
|
@ -884,7 +882,7 @@ function KnowledgeSourcesPage() {
|
||||||
}
|
}
|
||||||
confirmText="Proceed"
|
confirmText="Proceed"
|
||||||
confirmIcon={<ArrowUpRight />}
|
confirmIcon={<ArrowUpRight />}
|
||||||
onConfirm={(closeDialog) =>
|
onConfirm={closeDialog =>
|
||||||
handleEditInLangflow("chat", closeDialog)
|
handleEditInLangflow("chat", closeDialog)
|
||||||
}
|
}
|
||||||
variant="warning"
|
variant="warning"
|
||||||
|
|
@ -903,7 +901,11 @@ function KnowledgeSourcesPage() {
|
||||||
>
|
>
|
||||||
<ModelSelector
|
<ModelSelector
|
||||||
options={modelsData?.language_models || []}
|
options={modelsData?.language_models || []}
|
||||||
noOptionsPlaceholder={modelsData ? "No language models detected." : "Loading models..."}
|
noOptionsPlaceholder={
|
||||||
|
modelsData
|
||||||
|
? "No language models detected."
|
||||||
|
: "Loading models..."
|
||||||
|
}
|
||||||
icon={<OpenAILogo className="w-4 h-4" />}
|
icon={<OpenAILogo className="w-4 h-4" />}
|
||||||
value={modelsData ? settings.agent?.llm_model || "" : ""}
|
value={modelsData ? settings.agent?.llm_model || "" : ""}
|
||||||
onValueChange={handleModelChange}
|
onValueChange={handleModelChange}
|
||||||
|
|
@ -916,7 +918,7 @@ function KnowledgeSourcesPage() {
|
||||||
id="system-prompt"
|
id="system-prompt"
|
||||||
placeholder="Enter your agent instructions here..."
|
placeholder="Enter your agent instructions here..."
|
||||||
value={systemPrompt}
|
value={systemPrompt}
|
||||||
onChange={(e) => setSystemPrompt(e.target.value)}
|
onChange={e => setSystemPrompt(e.target.value)}
|
||||||
rows={6}
|
rows={6}
|
||||||
className={`resize-none ${
|
className={`resize-none ${
|
||||||
systemPrompt.length > MAX_SYSTEM_PROMPT_CHARS
|
systemPrompt.length > MAX_SYSTEM_PROMPT_CHARS
|
||||||
|
|
@ -1030,7 +1032,7 @@ function KnowledgeSourcesPage() {
|
||||||
confirmText="Proceed"
|
confirmText="Proceed"
|
||||||
confirmIcon={<ArrowUpRight />}
|
confirmIcon={<ArrowUpRight />}
|
||||||
variant="warning"
|
variant="warning"
|
||||||
onConfirm={(closeDialog) =>
|
onConfirm={closeDialog =>
|
||||||
handleEditInLangflow("ingest", closeDialog)
|
handleEditInLangflow("ingest", closeDialog)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
@ -1050,8 +1052,7 @@ function KnowledgeSourcesPage() {
|
||||||
disabled={true}
|
disabled={true}
|
||||||
value={
|
value={
|
||||||
settings.knowledge?.embedding_model ||
|
settings.knowledge?.embedding_model ||
|
||||||
modelsData?.embedding_models?.find((m) => m.default)
|
modelsData?.embedding_models?.find(m => m.default)?.value ||
|
||||||
?.value ||
|
|
||||||
"text-embedding-ada-002"
|
"text-embedding-ada-002"
|
||||||
}
|
}
|
||||||
onValueChange={handleEmbeddingModelChange}
|
onValueChange={handleEmbeddingModelChange}
|
||||||
|
|
@ -1087,7 +1088,7 @@ function KnowledgeSourcesPage() {
|
||||||
type="number"
|
type="number"
|
||||||
min="1"
|
min="1"
|
||||||
value={chunkSize}
|
value={chunkSize}
|
||||||
onChange={(e) => handleChunkSizeChange(e.target.value)}
|
onChange={e => handleChunkSizeChange(e.target.value)}
|
||||||
className="w-full pr-20 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
className="w-full pr-20 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-y-0 right-0 flex items-center">
|
<div className="absolute inset-y-0 right-0 flex items-center">
|
||||||
|
|
@ -1130,7 +1131,7 @@ function KnowledgeSourcesPage() {
|
||||||
type="number"
|
type="number"
|
||||||
min="0"
|
min="0"
|
||||||
value={chunkOverlap}
|
value={chunkOverlap}
|
||||||
onChange={(e) => handleChunkOverlapChange(e.target.value)}
|
onChange={e => handleChunkOverlapChange(e.target.value)}
|
||||||
className="w-full pr-20 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
className="w-full pr-20 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-y-0 right-0 flex items-center">
|
<div className="absolute inset-y-0 right-0 flex items-center">
|
||||||
|
|
@ -1145,7 +1146,7 @@ function KnowledgeSourcesPage() {
|
||||||
size="iconSm"
|
size="iconSm"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
handleChunkOverlapChange(
|
handleChunkOverlapChange(
|
||||||
(chunkOverlap + 1).toString(),
|
(chunkOverlap + 1).toString()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
@ -1158,7 +1159,7 @@ function KnowledgeSourcesPage() {
|
||||||
size="iconSm"
|
size="iconSm"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
handleChunkOverlapChange(
|
handleChunkOverlapChange(
|
||||||
(chunkOverlap - 1).toString(),
|
(chunkOverlap - 1).toString()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -60,12 +60,12 @@ export function LayoutWrapper({ children }: { children: React.ReactNode }) {
|
||||||
const isOnKnowledgePage = pathname.startsWith("/knowledge");
|
const isOnKnowledgePage = pathname.startsWith("/knowledge");
|
||||||
|
|
||||||
// List of paths with smaller max-width
|
// List of paths with smaller max-width
|
||||||
const smallWidthPaths = ["/settings", "/settings/connector/new"];
|
const smallWidthPaths = ["/settings/connector/new"];
|
||||||
const isSmallWidthPath = smallWidthPaths.includes(pathname);
|
const isSmallWidthPath = smallWidthPaths.includes(pathname);
|
||||||
|
|
||||||
// Calculate active tasks for the bell icon
|
// Calculate active tasks for the bell icon
|
||||||
const activeTasks = tasks.filter(
|
const activeTasks = tasks.filter(
|
||||||
(task) =>
|
task =>
|
||||||
task.status === "pending" ||
|
task.status === "pending" ||
|
||||||
task.status === "running" ||
|
task.status === "running" ||
|
||||||
task.status === "processing"
|
task.status === "processing"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue