Settings page design sweep

This commit is contained in:
Brent O'Neill 2025-09-24 11:54:25 -06:00
parent be8e13a173
commit 2ac257480c
3 changed files with 396 additions and 392 deletions

View file

@ -14,8 +14,7 @@ const buttonVariants = cva(
"border border-input hover:bg-muted hover:text-accent-foreground disabled:bg-muted disabled:!border-none",
primary:
"border bg-background text-secondary-foreground hover:bg-muted hover:shadow-sm",
warning:
"bg-warning-foreground text-warning-text hover:bg-warning-foreground/90 hover:shadow-sm",
warning: "bg-warning text-secondary hover:bg-warning/90",
secondary:
"border border-muted bg-muted text-secondary-foreground hover:bg-secondary-foreground/5",
ghost:
@ -39,14 +38,14 @@ const buttonVariants = cva(
variant: "default",
size: "default",
},
},
}
);
function toTitleCase(text: string) {
return text
?.split(" ")
?.map(
(word) => word?.charAt(0)?.toUpperCase() + word?.slice(1)?.toLowerCase(),
(word) => word?.charAt(0)?.toUpperCase() + word?.slice(1)?.toLowerCase()
)
?.join(" ");
}
@ -72,7 +71,7 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
ignoreTitleCase = false,
...props
},
ref,
ref
) => {
const Comp = asChild ? Slot : "button";
let newChildren = children;
@ -101,7 +100,7 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
)}
</Comp>
);
},
}
);
Button.displayName = "Button";

View file

@ -1,6 +1,6 @@
"use client";
import { Loader2, PlugZap, RefreshCw } from "lucide-react";
import { ArrowUpRight, Loader2, PlugZap, RefreshCw } from "lucide-react";
import { useSearchParams } from "next/navigation";
import { Suspense, useCallback, useEffect, useState } from "react";
import { useUpdateFlowSettingMutation } from "@/app/api/mutations/useUpdateFlowSettingMutation";
@ -88,6 +88,7 @@ interface Connection {
function KnowledgeSourcesPage() {
const { isAuthenticated, isNoAuthMode } = useAuth();
console.log({ isAuthenticated, isNoAuthMode });
const { addTask, tasks } = useTask();
const searchParams = useSearchParams();
@ -122,7 +123,7 @@ function KnowledgeSourcesPage() {
{
enabled:
(isAuthenticated || isNoAuthMode) && currentProvider === "openai",
},
}
);
const { data: ollamaModelsData } = useGetOllamaModelsQuery(
@ -130,14 +131,14 @@ function KnowledgeSourcesPage() {
{
enabled:
(isAuthenticated || isNoAuthMode) && currentProvider === "ollama",
},
}
);
const { data: ibmModelsData } = useGetIBMModelsQuery(
undefined, // No params for now, could be extended later
{
enabled: (isAuthenticated || isNoAuthMode) && currentProvider === "ibm",
},
}
);
// Select the appropriate models data based on provider
@ -165,7 +166,7 @@ function KnowledgeSourcesPage() {
(variables: Parameters<typeof updateFlowSettingMutation.mutate>[0]) => {
updateFlowSettingMutation.mutate(variables);
},
500,
500
);
// Sync system prompt state with settings data
@ -293,7 +294,7 @@ function KnowledgeSourcesPage() {
const data = await response.json();
const connections = data.connections || [];
const activeConnection = connections.find(
(conn: Connection) => conn.is_active,
(conn: Connection) => conn.is_active
);
const isConnected = activeConnection !== undefined;
@ -305,8 +306,8 @@ function KnowledgeSourcesPage() {
status: isConnected ? "connected" : "not_connected",
connectionId: activeConnection?.connection_id,
}
: c,
),
: c
)
);
}
}
@ -349,7 +350,7 @@ function KnowledgeSourcesPage() {
`response_type=code&` +
`scope=${result.oauth_config.scopes.join(" ")}&` +
`redirect_uri=${encodeURIComponent(
result.oauth_config.redirect_uri,
result.oauth_config.redirect_uri
)}&` +
`access_type=offline&` +
`prompt=consent&` +
@ -498,7 +499,7 @@ function KnowledgeSourcesPage() {
const handleEditInLangflow = (
flowType: "chat" | "ingest",
closeDialog: () => void,
closeDialog: () => void
) => {
// Select the appropriate flow ID and edit URL based on flow type
const targetFlowId =
@ -555,349 +556,6 @@ function KnowledgeSourcesPage() {
return (
<div className="space-y-8">
{/* Agent Behavior Section */}
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle className="text-lg">Agent</CardTitle>
<CardDescription>
Quick Agent settings. Edit in Langflow for full control.
</CardDescription>
</div>
<div className="flex gap-2">
<ConfirmationDialog
trigger={<Button variant="outline">Restore flow</Button>}
title="Restore default Agent flow"
description="This restores defaults and discards all custom settings and overrides. This can't be undone."
confirmText="Restore"
variant="destructive"
onConfirm={handleRestoreRetrievalFlow}
/>
<ConfirmationDialog
trigger={
<Button>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="22"
viewBox="0 0 24 22"
className="h-4 w-4 mr-2"
aria-label="Langflow icon"
>
<title>Langflow icon</title>
<path
fill="currentColor"
d="M13.0486 0.462158H9.75399C9.44371 0.462158 9.14614 0.586082 8.92674 0.806667L4.03751 5.72232C3.81811 5.9429 3.52054 6.06682 3.21026 6.06682H1.16992C0.511975 6.06682 -0.0165756 6.61212 0.000397655 7.2734L0.0515933 9.26798C0.0679586 9.90556 0.586745 10.4139 1.22111 10.4139H3.59097C3.90124 10.4139 4.19881 10.2899 4.41821 10.0694L9.34823 5.11269C9.56763 4.89211 9.8652 4.76818 10.1755 4.76818H13.0486C13.6947 4.76818 14.2185 4.24157 14.2185 3.59195V1.63839C14.2185 0.988773 13.6947 0.462158 13.0486 0.462158Z"
></path>
<path
fill="currentColor"
d="M19.5355 11.5862H22.8301C23.4762 11.5862 24 12.1128 24 12.7624V14.716C24 15.3656 23.4762 15.8922 22.8301 15.8922H19.957C19.6467 15.8922 19.3491 16.0161 19.1297 16.2367L14.1997 21.1934C13.9803 21.414 13.6827 21.5379 13.3725 21.5379H11.0026C10.3682 21.5379 9.84945 21.0296 9.83309 20.392L9.78189 18.3974C9.76492 17.7361 10.2935 17.1908 10.9514 17.1908H12.9918C13.302 17.1908 13.5996 17.0669 13.819 16.8463L18.7082 11.9307C18.9276 11.7101 19.2252 11.5862 19.5355 11.5862Z"
></path>
<path
fill="currentColor"
d="M19.5355 2.9796L22.8301 2.9796C23.4762 2.9796 24 3.50622 24 4.15583V6.1094C24 6.75901 23.4762 7.28563 22.8301 7.28563H19.957C19.6467 7.28563 19.3491 7.40955 19.1297 7.63014L14.1997 12.5868C13.9803 12.8074 13.6827 12.9313 13.3725 12.9313H10.493C10.1913 12.9313 9.90126 13.0485 9.68346 13.2583L4.14867 18.5917C3.93087 18.8016 3.64085 18.9187 3.33917 18.9187H1.32174C0.675616 18.9187 0.151832 18.3921 0.151832 17.7425V15.7343C0.151832 15.0846 0.675616 14.558 1.32174 14.558H3.32468C3.63496 14.558 3.93253 14.4341 4.15193 14.2135L9.40827 8.92878C9.62767 8.70819 9.92524 8.58427 10.2355 8.58427H12.9918C13.302 8.58427 13.5996 8.46034 13.819 8.23976L18.7082 3.32411C18.9276 3.10353 19.2252 2.9796 19.5355 2.9796Z"
></path>
</svg>
Edit in Langflow
</Button>
}
title="Edit Agent flow in Langflow"
description="You're entering Langflow. You can edit the Agent flow and other underlying flows. Manual changes to components, wiring, or I/O can break this experience."
confirmText="Proceed"
onConfirm={(closeDialog) =>
handleEditInLangflow("chat", closeDialog)
}
/>
</div>
</div>
</CardHeader>
<CardContent>
<div className="space-y-6">
<div className="space-y-2">
<Label htmlFor="model-select" className="text-base font-medium">
Language Model
</Label>
<Select
value={
settings.agent?.llm_model ||
modelsData?.language_models?.find((m) => m.default)?.value ||
"gpt-4"
}
onValueChange={handleModelChange}
>
<SelectTrigger id="model-select">
<SelectValue placeholder="Select a model" />
</SelectTrigger>
<SelectContent>
<ModelSelectItems
models={modelsData?.language_models}
fallbackModels={getFallbackModels(currentProvider).language}
provider={currentProvider}
/>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="system-prompt" className="text-base font-medium">
Agent Instructions
</Label>
<Textarea
id="system-prompt"
placeholder="Enter your agent instructions here..."
value={systemPrompt}
onChange={(e) => setSystemPrompt(e.target.value)}
rows={6}
className={`resize-none ${
systemPrompt.length > MAX_SYSTEM_PROMPT_CHARS
? "border-red-500 focus:border-red-500"
: ""
}`}
/>
<div className="flex justify-start">
<span
className={`text-xs ${
systemPrompt.length > MAX_SYSTEM_PROMPT_CHARS
? "text-red-500"
: "text-muted-foreground"
}`}
>
{systemPrompt.length}/{MAX_SYSTEM_PROMPT_CHARS} characters
</span>
</div>
</div>
<div className="flex justify-end pt-2">
<Button
onClick={handleSystemPromptSave}
disabled={
updateFlowSettingMutation.isPending ||
systemPrompt.length > MAX_SYSTEM_PROMPT_CHARS
}
className="min-w-[120px]"
size="sm"
variant="outline"
>
{updateFlowSettingMutation.isPending ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Saving...
</>
) : (
"Save Agent Instructions"
)}
</Button>
</div>
</div>
</CardContent>
</Card>
{/* Knowledge Ingest Section */}
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle className="text-lg">Knowledge</CardTitle>
<CardDescription>
Quick ingest options. Edit in Langflow for full control.
</CardDescription>
</div>
<div className="flex gap-2">
<ConfirmationDialog
trigger={<Button variant="outline">Restore flow</Button>}
title="Restore default Ingest flow"
description="This restores defaults and discards all custom settings and overrides. This can't be undone."
confirmText="Restore"
variant="destructive"
onConfirm={handleRestoreIngestFlow}
/>
<ConfirmationDialog
trigger={
<Button>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="22"
viewBox="0 0 24 22"
className="h-4 w-4 mr-2"
aria-label="Langflow icon"
>
<title>Langflow icon</title>
<path
fill="currentColor"
d="M13.0486 0.462158H9.75399C9.44371 0.462158 9.14614 0.586082 8.92674 0.806667L4.03751 5.72232C3.81811 5.9429 3.52054 6.06682 3.21026 6.06682H1.16992C0.511975 6.06682 -0.0165756 6.61212 0.000397655 7.2734L0.0515933 9.26798C0.0679586 9.90556 0.586745 10.4139 1.22111 10.4139H3.59097C3.90124 10.4139 4.19881 10.2899 4.41821 10.0694L9.34823 5.11269C9.56763 4.89211 9.8652 4.76818 10.1755 4.76818H13.0486C13.6947 4.76818 14.2185 4.24157 14.2185 3.59195V1.63839C14.2185 0.988773 13.6947 0.462158 13.0486 0.462158Z"
></path>
<path
fill="currentColor"
d="M19.5355 11.5862H22.8301C23.4762 11.5862 24 12.1128 24 12.7624V14.716C24 15.3656 23.4762 15.8922 22.8301 15.8922H19.957C19.6467 15.8922 19.3491 16.0161 19.1297 16.2367L14.1997 21.1934C13.9803 21.414 13.6827 21.5379 13.3725 21.5379H11.0026C10.3682 21.5379 9.84945 21.0296 9.83309 20.392L9.78189 18.3974C9.76492 17.7361 10.2935 17.1908 10.9514 17.1908H12.9918C13.302 17.1908 13.5996 17.0669 13.819 16.8463L18.7082 11.9307C18.9276 11.7101 19.2252 11.5862 19.5355 11.5862Z"
></path>
<path
fill="currentColor"
d="M19.5355 2.9796L22.8301 2.9796C23.4762 2.9796 24 3.50622 24 4.15583V6.1094C24 6.75901 23.4762 7.28563 22.8301 7.28563H19.957C19.6467 7.28563 19.3491 7.40955 19.1297 7.63014L14.1997 12.5868C13.9803 12.8074 13.6827 12.9313 13.3725 12.9313H10.493C10.1913 12.9313 9.90126 13.0485 9.68346 13.2583L4.14867 18.5917C3.93087 18.8016 3.64085 18.9187 3.33917 18.9187H1.32174C0.675616 18.9187 0.151832 18.3921 0.151832 17.7425V15.7343C0.151832 15.0846 0.675616 14.558 1.32174 14.558H3.32468C3.63496 14.558 3.93253 14.4341 4.15193 14.2135L9.40827 8.92878C9.62767 8.70819 9.92524 8.58427 10.2355 8.58427H12.9918C13.302 8.58427 13.5996 8.46034 13.819 8.23976L18.7082 3.32411C18.9276 3.10353 19.2252 2.9796 19.5355 2.9796Z"
></path>
</svg>
Edit in Langflow
</Button>
}
title="Edit Ingest flow in Langflow"
description="You're entering Langflow. You can edit the Ingest flow and other underlying flows. Manual changes to components, wiring, or I/O can break this experience."
confirmText="Proceed"
onConfirm={(closeDialog) =>
handleEditInLangflow("ingest", closeDialog)
}
/>
</div>
</div>
</CardHeader>
<CardContent>
<div className="space-y-6">
<div className="space-y-2">
<Label
htmlFor="embedding-model-select"
className="text-base font-medium"
>
Embedding Model
</Label>
<Select
value={
settings.knowledge?.embedding_model ||
modelsData?.embedding_models?.find((m) => m.default)?.value ||
"text-embedding-ada-002"
}
onValueChange={handleEmbeddingModelChange}
>
<SelectTrigger id="embedding-model-select">
<SelectValue placeholder="Select an embedding model" />
</SelectTrigger>
<SelectContent>
<ModelSelectItems
models={modelsData?.embedding_models}
fallbackModels={
getFallbackModels(currentProvider).embedding
}
provider={currentProvider}
/>
</SelectContent>
</Select>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="chunk-size" className="text-base font-medium">
Chunk Size
</Label>
<div className="relative">
<Input
id="chunk-size"
type="number"
min="1"
value={chunkSize}
onChange={(e) => handleChunkSizeChange(e.target.value)}
className="w-full pr-20"
/>
<div className="absolute inset-y-0 right-0 flex items-center pr-8 pointer-events-none">
<span className="text-sm text-muted-foreground">
characters
</span>
</div>
</div>
</div>
<div className="space-y-2">
<Label
htmlFor="chunk-overlap"
className="text-base font-medium"
>
Chunk Overlap
</Label>
<div className="relative">
<Input
id="chunk-overlap"
type="number"
min="0"
value={chunkOverlap}
onChange={(e) => handleChunkOverlapChange(e.target.value)}
className="w-full pr-20"
/>
<div className="absolute inset-y-0 right-0 flex items-center pr-8 pointer-events-none">
<span className="text-sm text-muted-foreground">
characters
</span>
</div>
</div>
</div>
</div>
<div className="space-y-3">
<Label className="text-base font-medium">Ingest Presets</Label>
<RadioGroup
value={processingMode}
onValueChange={handleProcessingModeChange}
className="space-y-3"
>
<div className="flex items-center space-x-3">
<RadioGroupItem value="standard" id="standard" />
<div className="flex-1">
<Label
htmlFor="standard"
className="text-base font-medium cursor-pointer"
>
Standard
</Label>
<div className="text-sm text-muted-foreground">
Fast ingest for text-based documents without images
</div>
</div>
</div>
<div className="flex items-center space-x-3">
<RadioGroupItem value="ocr" id="ocr" />
<div className="flex-1">
<Label
htmlFor="ocr"
className="text-base font-medium cursor-pointer"
>
Extract text from images
</Label>
<div className="text-sm text-muted-foreground">
Uses OCR to extract text from images/PDFs. Ingest is
slower when enabled
</div>
</div>
</div>
<div className="flex items-center space-x-3">
<RadioGroupItem
value="picture_description"
id="picture_description"
/>
<div className="flex-1">
<Label
htmlFor="picture_description"
className="text-base font-medium cursor-pointer"
>
Generate Description
</Label>
<div className="text-sm text-muted-foreground">
Text extraction plust AI generated image descriptions
</div>
</div>
</div>
<div className="flex items-center space-x-3">
<RadioGroupItem value="VLM" id="VLM" />
<div className="flex-1">
<Label
htmlFor="VLM"
className="text-base font-medium cursor-pointer"
>
AI Vision
</Label>
<div className="text-sm text-muted-foreground">
Advanced processing with vision language models. Highest
quality but most expensive
</div>
</div>
</div>
</RadioGroup>
</div>
</div>
</CardContent>
</Card>
{/* Connectors Section */}
<div className="space-y-6">
<div>
@ -1063,6 +721,358 @@ function KnowledgeSourcesPage() {
))}
</div>
</div>
{/* Agent Behavior Section */}
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle className="text-lg mb-4">Agent</CardTitle>
<CardDescription>
Quick Agent settings. Edit in Langflow for full control.
</CardDescription>
</div>
<div className="flex gap-2">
<ConfirmationDialog
trigger={
<Button ignoreTitleCase={true} variant="outline">
Restore Flow
</Button>
}
title="Restore default Agent flow"
description="This restores defaults and discards all custom settings and overrides. This can't be undone."
confirmText="Restore"
variant="destructive"
onConfirm={handleRestoreRetrievalFlow}
/>
<ConfirmationDialog
trigger={
<Button>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="22"
viewBox="0 0 24 22"
className="h-4 w-4 mr-2"
aria-label="Langflow icon"
>
<title>Langflow icon</title>
<path
fill="currentColor"
d="M13.0486 0.462158H9.75399C9.44371 0.462158 9.14614 0.586082 8.92674 0.806667L4.03751 5.72232C3.81811 5.9429 3.52054 6.06682 3.21026 6.06682H1.16992C0.511975 6.06682 -0.0165756 6.61212 0.000397655 7.2734L0.0515933 9.26798C0.0679586 9.90556 0.586745 10.4139 1.22111 10.4139H3.59097C3.90124 10.4139 4.19881 10.2899 4.41821 10.0694L9.34823 5.11269C9.56763 4.89211 9.8652 4.76818 10.1755 4.76818H13.0486C13.6947 4.76818 14.2185 4.24157 14.2185 3.59195V1.63839C14.2185 0.988773 13.6947 0.462158 13.0486 0.462158Z"
></path>
<path
fill="currentColor"
d="M19.5355 11.5862H22.8301C23.4762 11.5862 24 12.1128 24 12.7624V14.716C24 15.3656 23.4762 15.8922 22.8301 15.8922H19.957C19.6467 15.8922 19.3491 16.0161 19.1297 16.2367L14.1997 21.1934C13.9803 21.414 13.6827 21.5379 13.3725 21.5379H11.0026C10.3682 21.5379 9.84945 21.0296 9.83309 20.392L9.78189 18.3974C9.76492 17.7361 10.2935 17.1908 10.9514 17.1908H12.9918C13.302 17.1908 13.5996 17.0669 13.819 16.8463L18.7082 11.9307C18.9276 11.7101 19.2252 11.5862 19.5355 11.5862Z"
></path>
<path
fill="currentColor"
d="M19.5355 2.9796L22.8301 2.9796C23.4762 2.9796 24 3.50622 24 4.15583V6.1094C24 6.75901 23.4762 7.28563 22.8301 7.28563H19.957C19.6467 7.28563 19.3491 7.40955 19.1297 7.63014L14.1997 12.5868C13.9803 12.8074 13.6827 12.9313 13.3725 12.9313H10.493C10.1913 12.9313 9.90126 13.0485 9.68346 13.2583L4.14867 18.5917C3.93087 18.8016 3.64085 18.9187 3.33917 18.9187H1.32174C0.675616 18.9187 0.151832 18.3921 0.151832 17.7425V15.7343C0.151832 15.0846 0.675616 14.558 1.32174 14.558H3.32468C3.63496 14.558 3.93253 14.4341 4.15193 14.2135L9.40827 8.92878C9.62767 8.70819 9.92524 8.58427 10.2355 8.58427H12.9918C13.302 8.58427 13.5996 8.46034 13.819 8.23976L18.7082 3.32411C18.9276 3.10353 19.2252 2.9796 19.5355 2.9796Z"
></path>
</svg>
Edit in Langflow
</Button>
}
title="Edit Agent flow in Langflow"
description="You're entering Langflow. You can edit the Agent flow and other underlying flows. Manual changes to components, wiring, or I/O can break this experience.\nYou can restore this flow from Settings."
confirmText="Proceed"
confirmIcon={<ArrowUpRight />}
onConfirm={(closeDialog) =>
handleEditInLangflow("chat", closeDialog)
}
variant="warning"
/>
</div>
</div>
</CardHeader>
<CardContent>
<div className="space-y-6">
<div className="space-y-2">
<Label htmlFor="model-select" className="text-base font-medium">
Language Model
</Label>
<Select
value={
settings.agent?.llm_model ||
modelsData?.language_models?.find((m) => m.default)?.value ||
"gpt-4"
}
onValueChange={handleModelChange}
>
<SelectTrigger id="model-select">
<SelectValue placeholder="Select a model" />
</SelectTrigger>
<SelectContent>
<ModelSelectItems
models={modelsData?.language_models}
fallbackModels={getFallbackModels(currentProvider).language}
provider={currentProvider}
/>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="system-prompt" className="text-base font-medium">
Agent Instructions
</Label>
<Textarea
id="system-prompt"
placeholder="Enter your agent instructions here..."
value={systemPrompt}
onChange={(e) => setSystemPrompt(e.target.value)}
rows={6}
className={`resize-none ${
systemPrompt.length > MAX_SYSTEM_PROMPT_CHARS
? "border-red-500 focus:border-red-500"
: ""
}`}
/>
<div className="flex justify-start">
<span
className={`text-xs ${
systemPrompt.length > MAX_SYSTEM_PROMPT_CHARS
? "text-red-500"
: "text-muted-foreground"
}`}
>
{systemPrompt.length}/{MAX_SYSTEM_PROMPT_CHARS} characters
</span>
</div>
</div>
<div className="flex justify-end pt-2">
<Button
onClick={handleSystemPromptSave}
disabled={
updateFlowSettingMutation.isPending ||
systemPrompt.length > MAX_SYSTEM_PROMPT_CHARS
}
className="min-w-[120px]"
size="sm"
variant="outline"
>
{updateFlowSettingMutation.isPending ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Saving...
</>
) : (
"Save Agent Instructions"
)}
</Button>
</div>
</div>
</CardContent>
</Card>
{/* Knowledge Ingest Section */}
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle className="text-lg mb-4">Knowledge</CardTitle>
<CardDescription>
Quick knowledge settings. Edit in Langflow for full control.
</CardDescription>
</div>
<div className="flex gap-2">
<ConfirmationDialog
trigger={<Button variant="outline">Restore flow</Button>}
title="Restore default Ingest flow"
description="This restores defaults and discards all custom settings and overrides. This can't be undone."
confirmText="Restore"
variant="destructive"
onConfirm={handleRestoreIngestFlow}
/>
<ConfirmationDialog
trigger={
<Button>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="22"
viewBox="0 0 24 22"
className="h-4 w-4 mr-2"
aria-label="Langflow icon"
>
<title>Langflow icon</title>
<path
fill="currentColor"
d="M13.0486 0.462158H9.75399C9.44371 0.462158 9.14614 0.586082 8.92674 0.806667L4.03751 5.72232C3.81811 5.9429 3.52054 6.06682 3.21026 6.06682H1.16992C0.511975 6.06682 -0.0165756 6.61212 0.000397655 7.2734L0.0515933 9.26798C0.0679586 9.90556 0.586745 10.4139 1.22111 10.4139H3.59097C3.90124 10.4139 4.19881 10.2899 4.41821 10.0694L9.34823 5.11269C9.56763 4.89211 9.8652 4.76818 10.1755 4.76818H13.0486C13.6947 4.76818 14.2185 4.24157 14.2185 3.59195V1.63839C14.2185 0.988773 13.6947 0.462158 13.0486 0.462158Z"
></path>
<path
fill="currentColor"
d="M19.5355 11.5862H22.8301C23.4762 11.5862 24 12.1128 24 12.7624V14.716C24 15.3656 23.4762 15.8922 22.8301 15.8922H19.957C19.6467 15.8922 19.3491 16.0161 19.1297 16.2367L14.1997 21.1934C13.9803 21.414 13.6827 21.5379 13.3725 21.5379H11.0026C10.3682 21.5379 9.84945 21.0296 9.83309 20.392L9.78189 18.3974C9.76492 17.7361 10.2935 17.1908 10.9514 17.1908H12.9918C13.302 17.1908 13.5996 17.0669 13.819 16.8463L18.7082 11.9307C18.9276 11.7101 19.2252 11.5862 19.5355 11.5862Z"
></path>
<path
fill="currentColor"
d="M19.5355 2.9796L22.8301 2.9796C23.4762 2.9796 24 3.50622 24 4.15583V6.1094C24 6.75901 23.4762 7.28563 22.8301 7.28563H19.957C19.6467 7.28563 19.3491 7.40955 19.1297 7.63014L14.1997 12.5868C13.9803 12.8074 13.6827 12.9313 13.3725 12.9313H10.493C10.1913 12.9313 9.90126 13.0485 9.68346 13.2583L4.14867 18.5917C3.93087 18.8016 3.64085 18.9187 3.33917 18.9187H1.32174C0.675616 18.9187 0.151832 18.3921 0.151832 17.7425V15.7343C0.151832 15.0846 0.675616 14.558 1.32174 14.558H3.32468C3.63496 14.558 3.93253 14.4341 4.15193 14.2135L9.40827 8.92878C9.62767 8.70819 9.92524 8.58427 10.2355 8.58427H12.9918C13.302 8.58427 13.5996 8.46034 13.819 8.23976L18.7082 3.32411C18.9276 3.10353 19.2252 2.9796 19.5355 2.9796Z"
></path>
</svg>
Edit in Langflow
</Button>
}
title="Edit Ingest flow in Langflow"
description={`
You're entering Langflow. You can edit the Ingest flow and other underlying flows. Manual changes to components, wiring, or I/O can break this experience.
You can restore this flow from Settings.`}
confirmText="Proceed"
confirmIcon={<ArrowUpRight />}
variant="warning"
onConfirm={(closeDialog) =>
handleEditInLangflow("ingest", closeDialog)
}
/>
</div>
</div>
</CardHeader>
<CardContent>
<div className="space-y-6">
<div className="space-y-2">
<Label
htmlFor="embedding-model-select"
className="text-base font-medium"
>
Embedding Model
</Label>
<Select
value={
settings.knowledge?.embedding_model ||
modelsData?.embedding_models?.find((m) => m.default)?.value ||
"text-embedding-ada-002"
}
onValueChange={handleEmbeddingModelChange}
>
<SelectTrigger id="embedding-model-select">
<SelectValue placeholder="Select an embedding model" />
</SelectTrigger>
<SelectContent>
<ModelSelectItems
models={modelsData?.embedding_models}
fallbackModels={
getFallbackModels(currentProvider).embedding
}
provider={currentProvider}
/>
</SelectContent>
</Select>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="chunk-size" className="text-base font-medium">
Chunk Size
</Label>
<div className="relative">
<Input
id="chunk-size"
type="number"
min="1"
value={chunkSize}
onChange={(e) => handleChunkSizeChange(e.target.value)}
className="w-full pr-20"
/>
<div className="absolute inset-y-0 right-0 flex items-center pr-8 pointer-events-none">
<span className="text-sm text-muted-foreground">
characters
</span>
</div>
</div>
</div>
<div className="space-y-2">
<Label
htmlFor="chunk-overlap"
className="text-base font-medium"
>
Chunk Overlap
</Label>
<div className="relative">
<Input
id="chunk-overlap"
type="number"
min="0"
value={chunkOverlap}
onChange={(e) => handleChunkOverlapChange(e.target.value)}
className="w-full pr-20"
/>
<div className="absolute inset-y-0 right-0 flex items-center pr-8 pointer-events-none">
<span className="text-sm text-muted-foreground">
characters
</span>
</div>
</div>
</div>
</div>
<div className="space-y-3">
<Label className="text-base font-medium">Ingest Presets</Label>
<RadioGroup
value={processingMode}
onValueChange={handleProcessingModeChange}
className="space-y-3"
>
<div className="flex items-center space-x-3">
<RadioGroupItem value="standard" id="standard" />
<div className="flex-1">
<Label
htmlFor="standard"
className="text-base font-medium cursor-pointer"
>
Standard
</Label>
<div className="text-sm text-muted-foreground">
Fast ingest for text-based documents without images
</div>
</div>
</div>
<div className="flex items-center space-x-3">
<RadioGroupItem value="ocr" id="ocr" />
<div className="flex-1">
<Label
htmlFor="ocr"
className="text-base font-medium cursor-pointer"
>
Extract text from images
</Label>
<div className="text-sm text-muted-foreground">
Uses OCR to extract text from images/PDFs. Ingest is
slower when enabled
</div>
</div>
</div>
<div className="flex items-center space-x-3">
<RadioGroupItem
value="picture_description"
id="picture_description"
/>
<div className="flex-1">
<Label
htmlFor="picture_description"
className="text-base font-medium cursor-pointer"
>
Generate Description
</Label>
<div className="text-sm text-muted-foreground">
Text extraction plust AI generated image descriptions
</div>
</div>
</div>
<div className="flex items-center space-x-3">
<RadioGroupItem value="VLM" id="VLM" />
<div className="flex-1">
<Label
htmlFor="VLM"
className="text-base font-medium cursor-pointer"
>
AI Vision
</Label>
<div className="text-sm text-muted-foreground">
Advanced processing with vision language models. Highest
quality but most expensive
</div>
</div>
</div>
</RadioGroup>
</div>
</div>
</CardContent>
</Card>
</div>
);
}

View file

@ -1,6 +1,6 @@
"use client"
"use client";
import { ReactNode, useState } from "react"
import { ReactNode, useState } from "react";
import {
Dialog,
DialogContent,
@ -9,18 +9,19 @@ import {
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
interface ConfirmationDialogProps {
trigger: ReactNode
title: string
description: string
confirmText?: string
cancelText?: string
onConfirm: (closeDialog: () => void) => void
onCancel?: () => void
variant?: "default" | "destructive"
trigger: ReactNode;
title: string;
description: string;
confirmText?: string;
cancelText?: string;
onConfirm: (closeDialog: () => void) => void;
onCancel?: () => void;
variant?: "default" | "destructive" | "warning";
confirmIcon?: ReactNode | null;
}
export function ConfirmationDialog({
@ -31,25 +32,24 @@ export function ConfirmationDialog({
cancelText = "Cancel",
onConfirm,
onCancel,
variant = "default"
variant = "default",
confirmIcon = null,
}: ConfirmationDialogProps) {
const [open, setOpen] = useState(false)
const [open, setOpen] = useState(false);
const handleConfirm = () => {
const closeDialog = () => setOpen(false)
onConfirm(closeDialog)
}
const closeDialog = () => setOpen(false);
onConfirm(closeDialog);
};
const handleCancel = () => {
onCancel?.()
setOpen(false)
}
onCancel?.();
setOpen(false);
};
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
{trigger}
</DialogTrigger>
<DialogTrigger asChild>{trigger}</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle className="mb-4">{title}</DialogTitle>
@ -58,20 +58,15 @@ export function ConfirmationDialog({
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button
variant="outline"
onClick={handleCancel}
>
<Button variant="ghost" onClick={handleCancel} size="sm">
{cancelText}
</Button>
<Button
variant={variant}
onClick={handleConfirm}
>
<Button variant={variant} onClick={handleConfirm} size="sm">
{confirmText}
{confirmIcon}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}
);
}