Merge branch 'feat/onboarding' of github.com:langflow-ai/openrag into feat/onboarding

This commit is contained in:
Mike Fortman 2025-09-18 14:50:02 -05:00
commit facbb76171
17 changed files with 522 additions and 105 deletions

View file

@ -0,0 +1,26 @@
import { LabelWrapper } from "./label-wrapper";
import { Input } from "./ui/input";
export function LabelInput({
label,
helperText,
id,
required,
...props
}: {
label: string;
helperText: string;
id: string;
required: boolean;
} & React.InputHTMLAttributes<HTMLInputElement>) {
return (
<LabelWrapper
label={label}
helperText={helperText}
id={id}
required={required}
>
<Input id={id} {...props} />
</LabelWrapper>
);
}

View file

@ -0,0 +1,43 @@
import { Info } from "lucide-react";
import {
DropdownMenu,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "./ui/input";
import { Label } from "./ui/label";
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
export function LabelWrapper({
label,
helperText,
id,
required,
children,
}: {
label: string;
helperText: string;
id: string;
required: boolean;
children: React.ReactNode;
}) {
return (
<div className="space-y-2">
<Label
htmlFor={id}
className="text-mmd font-medium flex items-center gap-1"
>
{label}
{required && <span className="text-red-500">*</span>}
{helperText && (
<Tooltip>
<TooltipTrigger>
<Info className="w-3.5 h-3.5 text-muted-foreground" />
</TooltipTrigger>
<TooltipContent>{helperText}</TooltipContent>
</Tooltip>
)}
</Label>
<div className="relative">{children}</div>
</div>
);
}

View file

@ -9,10 +9,10 @@ export default function OllamaLogo(props: React.SVGProps<SVGSVGElement>) {
{...props}
>
<title>Ollama Logo</title>
<g clip-path="url(#clip0_2060_5748)">
<g clipPath="url(#clip0_2060_5748)">
<path
d="M4.67944 0.0576172C4.94223 -0.0366808 5.15143 -0.016476 5.44116 0.125C5.91976 0.37441 6.25025 1.04885 6.49292 2.2959L6.51929 2.44434L6.88354 2.28223C7.86769 1.85082 8.64306 1.88458 9.86987 2.42383C9.91704 2.45078 9.96389 2.39703 9.98413 2.30273C10.1931 1.22439 10.4493 0.610811 10.8132 0.293945C11.4266 -0.245299 12.1553 -0.0230936 12.5867 0.826172C12.89 1.4395 13.0042 2.12721 12.9773 3.23242L12.9568 4.19043L13.3484 4.60156C14.3255 5.62615 14.5614 7.35153 13.8943 8.58496L13.7253 8.89551L13.8601 9.21191C14.3522 10.3511 14.3324 11.8345 13.8201 12.7715L13.6443 13.0947L13.7859 13.4248C13.8668 13.6068 13.9613 13.9039 14.0017 14.0859C14.096 14.5041 14.1029 15.5757 14.0085 15.8184C13.9413 15.9932 13.914 16 13.4968 16C13.0047 16 13.0248 16.0266 13.1394 15.4199C13.2404 14.8672 13.1258 14.1526 12.8562 13.627C12.6069 13.1554 12.5998 12.9263 12.822 12.6299C13.1388 12.1985 13.2811 11.7128 13.2878 11.0117C13.2946 10.3175 13.193 9.93275 12.8425 9.25195C12.6405 8.8545 12.6476 8.65255 12.8767 8.46387C12.9308 8.41627 13.0581 8.19361 13.1658 7.95801C13.3208 7.60752 13.3551 7.45259 13.3484 7.00098C13.3484 6.0101 12.8757 5.20837 12.0466 4.75C11.6626 4.54113 11.5548 4.51358 11.1033 4.50684C10.8277 4.50683 10.5589 4.48001 10.5173 4.45312C10.4701 4.42616 10.3826 4.28423 10.3152 4.14941C10.1399 3.78545 9.70125 3.3748 9.24292 3.15234C8.8925 2.98387 8.77115 2.95607 8.23901 2.95605C7.72001 2.95605 7.57805 2.98366 7.2478 3.13867C6.76921 3.36112 6.32405 3.76538 6.12183 4.16309C6.0411 4.33126 5.95367 4.47222 5.92651 4.47949C5.89955 4.47949 5.65013 4.49316 5.37378 4.49316C4.71996 4.50664 4.23428 4.73581 3.76245 5.24805C3.2906 5.76708 3.12183 6.23255 3.12183 7.00098C3.11509 7.49291 3.14912 7.67504 3.2771 7.95801C3.35791 8.14657 3.49295 8.36207 3.56714 8.42969C3.82995 8.66555 3.8433 8.84102 3.63452 9.25195C3.28401 9.93275 3.18248 10.3175 3.18921 11.0117C3.19595 11.7128 3.33821 12.1985 3.65503 12.6299C3.87723 12.9263 3.87012 13.1553 3.62085 13.627C3.35128 14.1526 3.23666 14.8672 3.33765 15.4199C3.4522 16.0264 3.4728 16 2.9812 16C2.56356 16 2.53581 15.9933 2.46851 15.8184C2.37416 15.5757 2.38103 14.5041 2.47534 14.0859C2.51579 13.9039 2.61027 13.6068 2.69116 13.4248L2.83276 13.0947L2.65698 12.7715C2.38735 12.2861 2.26636 11.7329 2.26636 11.0049C2.26638 10.3377 2.37415 9.78507 2.60327 9.23242L2.73804 8.93555L2.50854 8.4707C1.88172 7.2103 2.13128 5.64639 3.12866 4.60156L3.52026 4.19043L3.49976 3.23242C3.47284 2.134 3.58712 1.43967 3.89038 0.839844C4.11957 0.38821 4.32892 0.178952 4.67944 0.0576172ZM7.38257 6.82617C7.90159 6.65092 8.75736 6.68461 9.29663 6.89355C9.81567 7.09578 10.3687 7.6012 10.5642 8.05957C10.7798 8.56509 10.7389 9.21173 10.4558 9.60938C9.97728 10.2968 9.39813 10.54 8.23901 10.54C7.36289 10.54 6.92444 10.4319 6.50659 10.1152C6.02804 9.75127 5.82548 9.39406 5.79175 8.88184C5.75804 8.33583 5.89952 7.93082 6.27026 7.52637C6.60046 7.16927 6.89062 6.98791 7.38257 6.82617ZM8.3396 7.33105C6.70163 7.24348 5.71788 8.83467 6.91772 9.64355C7.2479 9.86583 7.55167 9.93359 8.23901 9.93359C8.926 9.93356 9.22924 9.86576 9.55933 9.64355C10.4221 9.06388 10.2001 7.97864 9.11499 7.5C8.91951 7.41237 8.60249 7.34454 8.3396 7.33105ZM7.78687 8.1875C7.92842 8.09987 7.92187 8.09977 8.0769 8.18066C8.16448 8.23451 8.24529 8.22781 8.3396 8.18066C8.42038 8.14028 8.54167 8.12638 8.60913 8.14648C8.79113 8.20715 8.79113 8.55123 8.60913 8.65234C8.50812 8.70625 8.4744 8.79402 8.47437 8.98926C8.47437 9.21824 8.44763 9.26611 8.3064 9.2998C8.06383 9.36045 7.91564 9.21222 7.96265 8.96973C7.99635 8.81469 7.96856 8.74652 7.83374 8.63867C7.63866 8.4837 7.61855 8.28183 7.78687 8.1875ZM5.17847 6.83203C5.38052 6.83207 5.46861 6.8794 5.61011 7.04785C5.82577 7.30397 5.80544 7.57425 5.53589 7.85059C5.32028 8.07294 5.20535 8.10625 4.91577 8.03223C4.59221 7.9446 4.45683 7.60726 4.59839 7.25C4.65906 7.11525 4.75359 6.96024 4.81421 6.91309C4.87498 6.87267 5.04374 6.83203 5.17847 6.83203ZM11.2849 6.83203C11.6152 6.83203 11.7438 6.92049 11.8718 7.2373C12.0199 7.61448 11.8921 7.94442 11.5623 8.03223C11.2724 8.10638 11.1569 8.07303 10.9412 7.85059C10.6716 7.57425 10.6522 7.30397 10.8679 7.04785C11.0092 6.87983 11.1034 6.83211 11.2849 6.83203ZM4.96948 0.900391C4.86841 0.900391 4.63911 1.3317 4.54468 1.71582C4.40989 2.22801 4.34238 2.98992 4.39624 3.3877L4.44312 3.71777L4.6521 3.66406C4.77343 3.63036 5.01688 3.59063 5.19214 3.57715C5.374 3.56362 5.54908 3.50897 5.58276 3.45508C5.74422 3.21839 5.48102 1.66887 5.198 1.19043C5.10386 1.02909 5.00338 0.900927 4.96948 0.900391ZM11.5076 0.900391C11.3928 0.901308 11.1096 1.48104 11.0085 1.91211C10.8739 2.50484 10.8137 3.33956 10.8943 3.45508C10.928 3.50896 11.1031 3.56361 11.2849 3.57715C11.4602 3.59063 11.7036 3.63036 11.825 3.66406L12.0339 3.71777L12.0808 3.3877C12.1684 2.73379 11.9725 1.56114 11.7029 1.12305C11.6287 1.0018 11.5345 0.900391 11.5076 0.900391Z"
fill="#A1A1AA"
fill="currentColor"
/>
</g>
<defs>

View file

@ -1,52 +1,73 @@
import * as React from "react";
import { cn } from "@/lib/utils";
const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"rounded-lg border border-border bg-card text-card-foreground shadow-sm",
className,
)}
{...props}
/>
)
);
const Card = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"rounded-lg border border-border bg-card text-card-foreground shadow-sm",
className,
)}
{...props}
/>
));
const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex flex-col space-y-1.5 p-4", className)} {...props} />
)
);
const CardHeader = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col space-y-1.5 p-5", className)}
{...props}
/>
));
const CardTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
({ className, ...props }, ref) => (
<h3
ref={ref}
className={cn("text-base font-semibold leading-tight tracking-tight", className)}
{...props}
/>
)
);
const CardTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
<h3
ref={ref}
className={cn(
"text-base font-semibold leading-tight tracking-tight",
className,
)}
{...props}
/>
));
const CardDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />
)
);
const CardDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-4 pt-0", className)} {...props} />
)
);
const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-5 pt-0", className)} {...props} />
));
const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex items-center p-4 pt-0", className)} {...props} />
)
);
const CardFooter = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex items-center p-4 pt-0", className)}
{...props}
/>
));
Card.displayName = "Card";
CardHeader.displayName = "CardHeader";
@ -55,4 +76,11 @@ CardDescription.displayName = "CardDescription";
CardContent.displayName = "CardContent";
CardFooter.displayName = "CardFooter";
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle };
export {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
};

View file

@ -1,15 +1,32 @@
import * as React from "react";
import { cn } from "@/lib/utils";
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {
icon?: React.ReactNode;
inputClassName?: string;
}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, inputClassName, icon, type, placeholder, ...props }, ref) => {
const [hasValue, setHasValue] = React.useState(
Boolean(props.value || props.defaultValue),
);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setHasValue(e.target.value.length > 0);
if (props.onChange) {
props.onChange(e);
}
};
return (
<label className={cn("relative block h-fit w-full text-sm", icon ? className : "")}>
<label
className={cn(
"relative block h-fit w-full text-xs",
icon ? className : "",
)}
>
{icon && (
<div className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 transform text-muted-foreground">
{icon}
@ -26,12 +43,13 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
)}
ref={ref}
{...props}
onChange={handleChange}
/>
<span
className={cn(
"pointer-events-none absolute top-1/2 -translate-y-1/2 pl-px text-placeholder-foreground font-mono",
icon ? "left-9" : "left-3",
props.value && "hidden",
hasValue && "hidden",
)}
>
{placeholder}

View file

@ -43,7 +43,7 @@ const TabsContent = React.forwardRef<
<TabsPrimitive.Content
ref={ref}
className={cn(
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"mt-2 space-y-5 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
className,
)}
{...props}

View file

@ -0,0 +1,30 @@
"use client";
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import * as React from "react";
import { cn } from "@/lib/utils";
const TooltipProvider = TooltipPrimitive.Provider;
const Tooltip = TooltipPrimitive.Root;
const TooltipTrigger = TooltipPrimitive.Trigger;
const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",
className,
)}
{...props}
/>
));
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };

View file

@ -23,6 +23,7 @@
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.2.5",
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-tooltip": "^1.2.8",
"@tailwindcss/forms": "^0.5.10",
"@tailwindcss/typography": "^0.5.16",
"@tanstack/react-query": "^5.86.0",
@ -1968,6 +1969,40 @@
}
}
},
"node_modules/@radix-ui/react-tooltip": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz",
"integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.3",
"@radix-ui/react-compose-refs": "1.1.2",
"@radix-ui/react-context": "1.1.2",
"@radix-ui/react-dismissable-layer": "1.1.11",
"@radix-ui/react-id": "1.1.1",
"@radix-ui/react-popper": "1.2.8",
"@radix-ui/react-portal": "1.1.9",
"@radix-ui/react-presence": "1.1.5",
"@radix-ui/react-primitive": "2.1.3",
"@radix-ui/react-slot": "1.2.3",
"@radix-ui/react-use-controllable-state": "1.2.2",
"@radix-ui/react-visually-hidden": "1.2.3"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-callback-ref": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",

View file

@ -24,6 +24,7 @@
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.2.5",
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-tooltip": "^1.2.8",
"@tailwindcss/forms": "^0.5.10",
"@tailwindcss/typography": "^0.5.16",
"@tanstack/react-query": "^5.86.0",

View file

@ -4,18 +4,18 @@ import {
useQueryClient,
} from "@tanstack/react-query";
interface AgentSettings {
export interface AgentSettings {
llm_model?: string;
system_prompt?: string;
}
interface IngestSettings {
export interface IngestSettings {
embedding_model?: string;
chunk_size?: number;
chunk_overlap?: number;
}
interface Settings {
export interface Settings {
flow_id?: string;
ingest_flow_id?: string;
langflow_edit_url?: string;

View file

@ -1,13 +1,14 @@
import type { Metadata } from "next";
import { Inter, JetBrains_Mono, Chivo } from "next/font/google";
import { Chivo, Inter, JetBrains_Mono } from "next/font/google";
import "./globals.css";
import { ThemeProvider } from "@/components/theme-provider";
import { AuthProvider } from "@/contexts/auth-context";
import { TaskProvider } from "@/contexts/task-context";
import { KnowledgeFilterProvider } from "@/contexts/knowledge-filter-context";
import { ChatProvider } from "@/contexts/chat-context";
import { LayoutWrapper } from "@/components/layout-wrapper";
import { ThemeProvider } from "@/components/theme-provider";
import { Toaster } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip";
import { AuthProvider } from "@/contexts/auth-context";
import { ChatProvider } from "@/contexts/chat-context";
import { KnowledgeFilterProvider } from "@/contexts/knowledge-filter-context";
import { TaskProvider } from "@/contexts/task-context";
import Providers from "./providers";
const inter = Inter({
@ -46,15 +47,17 @@ export default function RootLayout({
disableTransitionOnChange
>
<Providers>
<AuthProvider>
<TaskProvider>
<KnowledgeFilterProvider>
<ChatProvider>
<LayoutWrapper>{children}</LayoutWrapper>
</ChatProvider>
</KnowledgeFilterProvider>
</TaskProvider>
</AuthProvider>
<TooltipProvider>
<AuthProvider>
<TaskProvider>
<KnowledgeFilterProvider>
<ChatProvider>
<LayoutWrapper>{children}</LayoutWrapper>
</ChatProvider>
</KnowledgeFilterProvider>
</TaskProvider>
</AuthProvider>
</TooltipProvider>
</Providers>
</ThemeProvider>
<Toaster />

View file

@ -0,0 +1,38 @@
import { LabelInput } from "@/components/label-input";
import type { Settings } from "../api/queries/useGetSettingsQuery";
import { AdvancedOnboarding } from "./advanced";
export function IBMOnboarding({
settings,
setSettings,
}: {
settings: Settings;
setSettings: (settings: Settings) => void;
}) {
return (
<>
<LabelInput
label="watsonx.ai API Endpoint"
helperText="The API endpoint for your watsonx.ai account."
id="api-endpoint"
required
placeholder="https://..."
/>
<LabelInput
label="IBM API key"
helperText="The API key for your watsonx.ai account."
id="api-key"
required
placeholder="sk-..."
/>
<LabelInput
label="IBM Project ID"
helperText="The project ID for your watsonx.ai account."
id="project-id"
required
placeholder="..."
/>
<AdvancedOnboarding modelProvider="watsonx" />
</>
);
}

View file

@ -0,0 +1,100 @@
import { CheckIcon, ChevronsUpDownIcon } from "lucide-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/components/ui/command";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { cn } from "@/lib/utils";
export function ModelSelector({
options,
value,
onValueChange,
icon,
}: {
options: {
value: string;
label: string;
default?: boolean;
}[];
value: string;
icon?: React.ReactNode;
onValueChange: (value: string) => void;
}) {
const [open, setOpen] = useState(false);
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className="w-full gap-2 justify-between"
>
{value ? (
<div className="flex items-center gap-2 font-normal text-sm">
<div className="w-4 h-4">{icon}</div>
{options.find((framework) => framework.value === value)?.label}
{options.find((framework) => framework.value === value)
?.default && (
<span className="text-xs text-foreground p-1 rounded-md bg-muted">
Default
</span>
)}
</div>
) : (
"Select model..."
)}
<ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent align="start" className="w-[400px] p-0">
<Command>
<CommandInput placeholder="Search model..." />
<CommandList>
<CommandEmpty>No model found.</CommandEmpty>
<CommandGroup>
{options.map((option) => (
<CommandItem
key={option.value}
value={option.value}
onSelect={(currentValue) => {
if (currentValue !== value) {
onValueChange(currentValue);
}
setOpen(false);
}}
>
<CheckIcon
className={cn(
"mr-2 h-4 w-4",
value === option.value ? "opacity-100" : "opacity-0",
)}
/>
<div className="flex items-center gap-2">
{option.label}
{option.default && (
<span className="text-xs text-foreground p-1 rounded-md bg-muted">
Default
</span>
)}
</div>
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
);
}

View file

@ -0,0 +1,53 @@
import { useState } from "react";
import { LabelInput } from "@/components/label-input";
import { LabelWrapper } from "@/components/label-wrapper";
import OllamaLogo from "@/components/logo/ollama-logo";
import type { Settings } from "../api/queries/useGetSettingsQuery";
import { AdvancedOnboarding } from "./advanced";
import { ModelSelector } from "./model-selector";
export function OllamaOnboarding({
settings,
setSettings,
}: {
settings: Settings;
setSettings: (settings: Settings) => void;
}) {
const [open, setOpen] = useState(false);
const [value, setValue] = useState("");
const frameworks = [
{ value: "gpt-oss", label: "gpt-oss", default: true },
{ value: "llama3.1", label: "llama3.1" },
{ value: "llama3.2", label: "llama3.2" },
{ value: "llama3.3", label: "llama3.3" },
{ value: "llama3.4", label: "llama3.4" },
{ value: "llama3.5", label: "llama3.5" },
];
return (
<>
<LabelInput
label="Ollama Endpoint"
helperText="The endpoint for your Ollama server."
id="api-endpoint"
required
placeholder="http://..."
/>
<LabelWrapper
label="Embedding Model"
helperText="The embedding model for your Ollama server."
id="embedding-model"
required={true}
>
<ModelSelector
options={frameworks}
icon={<OllamaLogo className="w-4 h-4" />}
value={value}
onValueChange={setValue}
/>
</LabelWrapper>
<AdvancedOnboarding modelProvider="ollama" />
</>
);
}

View file

@ -0,0 +1,24 @@
import { LabelInput } from "@/components/label-input";
import type { Settings } from "../api/queries/useGetSettingsQuery";
import { AdvancedOnboarding } from "./advanced";
export function OpenAIOnboarding({
settings,
setSettings,
}: {
settings: Settings;
setSettings: (settings: Settings) => void;
}) {
return (
<>
<LabelInput
label="OpenAI API key"
helperText="The API key for your OpenAI account."
id="api-key"
required
placeholder="sk-..."
/>
<AdvancedOnboarding modelProvider="openai" />
</>
);
}

View file

@ -2,7 +2,11 @@
import { Suspense, useState } from "react";
import { useUpdateFlowSettingMutation } from "@/app/api/mutations/useUpdateFlowSettingMutation";
import { useGetSettingsQuery } from "@/app/api/queries/useGetSettingsQuery";
import {
type Settings,
useGetSettingsQuery,
} from "@/app/api/queries/useGetSettingsQuery";
import { LabelInput } from "@/components/label-input";
import IBMLogo from "@/components/logo/ibm-logo";
import OllamaLogo from "@/components/logo/ollama-logo";
import OpenAILogo from "@/components/logo/openai-logo";
@ -11,16 +15,21 @@ import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { useAuth } from "@/contexts/auth-context";
import { AdvancedOnboarding } from "./advanced";
import { IBMOnboarding } from "./ibm-onboarding";
import { OllamaOnboarding } from "./ollama-onboarding";
import { OpenAIOnboarding } from "./openai-onboarding";
function OnboardingPage() {
const { isAuthenticated } = useAuth();
const [modelProvider, setModelProvider] = useState<string>("openai");
// Fetch settings using React Query
const { data: settings = {} } = useGetSettingsQuery({
const { data: settingsDb = {} } = useGetSettingsQuery({
enabled: isAuthenticated,
});
const [settings, setSettings] = useState<Settings>(settingsDb);
// Mutations
const updateFlowSettingMutation = useUpdateFlowSettingMutation({
onSuccess: () => {
@ -40,43 +49,51 @@ function OnboardingPage() {
backgroundPosition: "center",
}}
>
<div className="flex flex-col items-center justify-center gap-4">
<h1 className="text-2xl font-medium font-chivo">
Configure your models
</h1>
<p className="text-sm text-muted-foreground">[description of task]</p>
<div className="flex flex-col items-center gap-5 min-h-[480px] w-full">
<div className="flex flex-col items-center justify-center gap-4">
<h1 className="text-2xl font-medium font-chivo">
Configure your models
</h1>
<p className="text-sm text-muted-foreground">[description of task]</p>
</div>
<Card className="w-full max-w-[580px]">
<Tabs defaultValue={modelProvider} onValueChange={setModelProvider}>
<CardHeader>
<TabsList>
<TabsTrigger value="openai">
<OpenAILogo className="w-4 h-4" />
OpenAI
</TabsTrigger>
<TabsTrigger value="watsonx">
<IBMLogo className="w-4 h-4" />
IBM
</TabsTrigger>
<TabsTrigger value="ollama">
<OllamaLogo className="w-4 h-4" />
Ollama
</TabsTrigger>
</TabsList>
</CardHeader>
<CardContent>
<TabsContent value="openai">
<OpenAIOnboarding
settings={settings}
setSettings={setSettings}
/>
</TabsContent>
<TabsContent value="watsonx">
<IBMOnboarding settings={settings} setSettings={setSettings} />
</TabsContent>
<TabsContent value="ollama">
<OllamaOnboarding
settings={settings}
setSettings={setSettings}
/>
</TabsContent>
</CardContent>
</Tabs>
</Card>
</div>
<Card className="w-full max-w-[580px]">
<Tabs defaultValue={modelProvider} onValueChange={setModelProvider}>
<CardHeader>
<TabsList>
<TabsTrigger value="openai">
<OpenAILogo className="w-4 h-4" />
OpenAI
</TabsTrigger>
<TabsTrigger value="watsonx">
<IBMLogo className="w-4 h-4" />
IBM
</TabsTrigger>
<TabsTrigger value="ollama">
<OllamaLogo className="w-4 h-4" />
Ollama
</TabsTrigger>
</TabsList>
</CardHeader>
<CardContent>
<TabsContent value="openai">
<AdvancedOnboarding modelProvider={modelProvider} />
</TabsContent>
<TabsContent value="watsonx">
<AdvancedOnboarding modelProvider={modelProvider} />
</TabsContent>
<TabsContent value="ollama">
<AdvancedOnboarding modelProvider={modelProvider} />
</TabsContent>
</CardContent>
</Tabs>
</Card>
</div>
);
}

View file

@ -184,8 +184,9 @@ const config = {
".primary-input": {
display: "block",
width: "100%",
height: "40px",
borderRadius: "0.375rem",
border: "1px solid hsl(var(--border))",
border: "1px solid hsl(var(--input))",
backgroundColor: "hsl(var(--background))",
paddingLeft: "0.75rem",
paddingRight: "0.75rem",