Compare commits

...
Sign in to create a new pull request.

13 commits

Author SHA1 Message Date
Lucas Oliveira
08ad220bbf fix card border radius 2025-10-01 14:35:16 -03:00
Lucas Oliveira
3dd9cdf39c removed onboarding toast 2025-10-01 11:59:37 -03:00
Lucas Oliveira
07ae567d18 removed ! 2025-10-01 11:41:05 -03:00
Lucas Oliveira
df1324ac36 made selector full width and made default disappear 2025-10-01 11:34:45 -03:00
Lucas Oliveira
c8968bbb2e disable default tag 2025-10-01 11:10:00 -03:00
Lucas Oliveira
20ff071d4d Changed width to match designs 2025-10-01 11:07:10 -03:00
Lucas Oliveira
25426eea80 changed use env open ai api key style 2025-10-01 11:06:28 -03:00
Lucas Oliveira
2b6695deb2 disable select on disabled button 2025-10-01 11:01:33 -03:00
Lucas Oliveira
62d54b380d upload copies on ibm onboarding 2025-10-01 11:00:00 -03:00
Lucas Oliveira
bff0cf5ac2 changed IBM to IBM watsonx.ai 2025-10-01 10:57:30 -03:00
Lucas Oliveira
b92a39097a set endpoint selector as custom 2025-10-01 10:57:21 -03:00
Lucas Oliveira
d46b9c2425 changed ibm logo to watsonx 2025-10-01 10:57:13 -03:00
Lucas Oliveira
b3ae29db83 implement custom value when custom is active on model selector 2025-10-01 10:57:06 -03:00
8 changed files with 287 additions and 238 deletions

View file

@ -37,7 +37,7 @@ export function LabelWrapper({
> >
<Label <Label
htmlFor={id} htmlFor={id}
className="!text-mmd font-medium flex items-center gap-1.5" className={cn("font-medium flex items-center gap-1.5", description ? "!text-sm" : "!text-mmd")}
> >
{label} {label}
{required && <span className="text-red-500">*</span>} {required && <span className="text-red-500">*</span>}

View file

@ -8,11 +8,24 @@ export default function IBMLogo(props: React.SVGProps<SVGSVGElement>) {
fill="none" fill="none"
{...props} {...props}
> >
<title>IBM Logo</title> <title>IBM watsonx.ai Logo</title>
<g clip-path="url(#clip0_2620_2081)">
<path <path
d="M15.696 10.9901C15.7213 10.9901 15.7356 10.979 15.7356 10.9552V10.9313C15.7356 10.9076 15.7213 10.8964 15.696 10.8964H15.6359V10.9901H15.696ZM15.6359 11.1649H15.5552V10.8329H15.7055C15.7799 10.8329 15.8179 10.8773 15.8179 10.9378C15.8179 10.9901 15.7942 11.0235 15.7577 11.0378L15.8321 11.1649H15.7436L15.6818 11.0504H15.6359V11.1649ZM15.9255 11.0171V10.9759C15.9255 10.8424 15.821 10.7376 15.6833 10.7376C15.5456 10.7376 15.4412 10.8424 15.4412 10.9759V11.0171C15.4412 11.1505 15.5456 11.2554 15.6833 11.2554C15.821 11.2554 15.9255 11.1505 15.9255 11.0171ZM15.3668 10.9964C15.3668 10.8107 15.5077 10.6693 15.6833 10.6693C15.859 10.6693 16 10.8107 16 10.9964C16 11.1823 15.859 11.3237 15.6833 11.3237C15.5077 11.3237 15.3668 11.1823 15.3668 10.9964ZM10.8069 5.74885L10.6627 5.33301H8.28904V5.74885H10.8069ZM11.0821 6.54285L10.9379 6.12691H8.28904V6.54285H11.0821ZM12.8481 11.3067H14.9203V10.8908H12.8481V11.3067ZM12.8481 10.5126H14.9203V10.0968H12.8481V10.5126ZM12.8481 9.71873H14.0914V9.3028H12.8481V9.71873ZM12.8481 8.92474H14.0914V8.50889H12.8481V8.92474ZM12.8481 8.13084H14.0914V7.7149H11.7212L11.6047 8.05102L11.4882 7.7149H9.11794V8.13084H10.3613V7.74863L10.4951 8.13084H12.7143L12.8481 7.74863V8.13084ZM14.0914 6.921H11.9964L11.8522 7.33675H14.0914V6.921ZM9.11794 8.92474H10.3613V8.50889H9.11794V8.92474ZM9.11794 9.71873H10.3613V9.3028H9.11794V9.71873ZM8.28904 10.5126H10.3613V10.0968H8.28904V10.5126ZM8.28904 11.3067H10.3613V10.8908H8.28904V11.3067ZM12.5466 5.33301L12.4025 5.74885H14.9203V5.33301H12.5466ZM12.1273 6.54285H14.9203V6.12691H12.2714L12.1273 6.54285ZM9.11794 7.33675H11.3572L11.213 6.921H9.11794V7.33675ZM10.7727 8.92474H12.4366L12.5821 8.50889H10.6272L10.7727 8.92474ZM11.0505 9.71873H12.1588L12.3042 9.3028H10.9051L11.0505 9.71873ZM11.3283 10.5126H11.881L12.0265 10.0969H11.1828L11.3283 10.5126ZM11.604 11.3067L11.7487 10.8908H11.4606L11.604 11.3067ZM3.31561 11.3026L6.36754 11.3067C6.78195 11.3067 7.15365 11.1491 7.43506 10.8908H3.31561V11.3026ZM6.55592 9.3028V9.71873H7.94994C7.94994 9.57477 7.93029 9.43551 7.89456 9.3028H6.55592ZM4.14452 9.71873H5.38783V9.3028H4.14452V9.71873ZM6.55592 7.33675H7.89456C7.93029 7.20422 7.94994 7.06486 7.94994 6.921H6.55592V7.33675ZM4.14452 7.33675H5.38783V6.9209H4.14452V7.33675ZM6.36754 5.33301H3.31561V5.74885H7.43506C7.15365 5.49061 6.77892 5.33301 6.36754 5.33301ZM7.73778 6.12691H3.31561V6.54285H7.90448C7.86839 6.39502 7.81172 6.25539 7.73778 6.12691ZM4.14452 7.7149V8.13084H7.39152C7.5292 8.01333 7.64621 7.87268 7.73732 7.7149H4.14452ZM7.39152 8.50889H4.14452V8.92474H7.73732C7.64621 8.76695 7.5292 8.62631 7.39152 8.50889ZM3.31561 10.5126H7.73778C7.81172 10.3843 7.86839 10.2447 7.90448 10.0969H3.31561V10.5126ZM0 5.74885H2.90121V5.33301H0V5.74885ZM0 6.54285H2.90121V6.12691H0V6.54285ZM0.828996 7.33684H2.0723V6.921H0.828996V7.33684ZM0.828996 8.13084H2.0723V7.7149H0.828996V8.13084ZM0.828996 8.92474H2.0723V8.50889H0.828996V8.92474ZM0.828996 9.71873H2.0723V9.3028H0.828996V9.71873ZM0 10.5126H2.90121V10.0968H0V10.5126ZM0 11.3067H2.90121V10.8908H0V11.3067Z" d="M13 12.0007C12.4477 12.0007 12 12.4484 12 13.0007C12 13.0389 12.0071 13.0751 12.0112 13.1122C10.8708 14.0103 9.47165 14.5007 8 14.5007C5.86915 14.5007 4 12.5146 4 10.2507C4 7.90722 5.9065 6.00072 8.25 6.00072H8.5V5.00072H8.25C5.3552 5.00072 3 7.35592 3 10.2507C3 11.1927 3.2652 12.0955 3.71855 12.879C2.3619 11.6868 1.5 9.94447 1.5 8.00072C1.5 6.94312 1.74585 5.93432 2.23095 5.00292L1.34375 4.54102C0.79175 5.60157 0.5 6.79787 0.5 8.00072C0.5 12.1362 3.8645 15.5007 8 15.5007C9.6872 15.5007 11.2909 14.9411 12.6024 13.9176C12.7244 13.9706 12.8586 14.0007 13 14.0007C13.5523 14.0007 14 13.553 14 13.0007C14 12.4484 13.5523 12.0007 13 12.0007Z"
fill="currentColor" fill="currentColor"
/> />
<path d="M6.5 11V10H5.5V11H6.5Z" fill="currentColor" />
<path d="M10.5 6V5H9.5V6H10.5Z" fill="currentColor" />
<path
d="M8 0.5C6.3128 0.5 4.7091 1.05965 3.3976 2.0831C3.2756 2.0301 3.14145 2 3 2C2.4477 2 2 2.4477 2 3C2 3.5523 2.4477 4 3 4C3.5523 4 4 3.5523 4 3C4 2.9618 3.9929 2.9256 3.98875 2.88855C5.12915 1.9904 6.52835 1.5 8 1.5C10.1308 1.5 12 3.4861 12 5.75C12 8.0935 10.0935 10 7.75 10H7.5V11H7.75C10.6448 11 13 8.6448 13 5.75C13 4.80735 12.7339 3.90415 12.28 3.12035C13.6375 4.3125 14.5 6.05555 14.5 8C14.5 9.0576 14.2541 10.0664 13.769 10.9978L14.6562 11.4597C15.2083 10.3991 15.5 9.20285 15.5 8C15.5 3.8645 12.1355 0.5 8 0.5Z"
fill="currentColor"
/>
</g>
<defs>
<clipPath id="clip0_2620_2081">
<rect width="16" height="16" fill="white" />
</clipPath>
</defs>
</svg> </svg>
); );
} }

View file

@ -3,7 +3,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react"; import * as React from "react";
const buttonVariants = cva( const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none disabled:select-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{ {
variants: { variants: {
variant: { variant: {

View file

@ -8,7 +8,7 @@ const Card = React.forwardRef<
<div <div
ref={ref} ref={ref}
className={cn( className={cn(
"rounded-lg border border-border bg-card text-card-foreground shadow-sm", "rounded-xl border border-border bg-card text-card-foreground shadow-sm",
className, className,
)} )}
{...props} {...props}

View file

@ -111,6 +111,7 @@ export function IBMOnboarding({
<ModelSelector <ModelSelector
options={options} options={options}
value={endpoint} value={endpoint}
custom
onValueChange={setEndpoint} onValueChange={setEndpoint}
searchPlaceholder="Search endpoint..." searchPlaceholder="Search endpoint..."
noOptionsPlaceholder="No endpoints available" noOptionsPlaceholder="No endpoints available"
@ -118,8 +119,17 @@ export function IBMOnboarding({
/> />
</LabelWrapper> </LabelWrapper>
<LabelInput <LabelInput
label="IBM API key" label="watsonx Project ID"
helperText="The API key for your watsonx.ai account." helperText="Project ID for the model"
id="project-id"
required
placeholder="your-project-id"
value={projectId}
onChange={(e) => setProjectId(e.target.value)}
/>
<LabelInput
label="watsonx API key"
helperText="API key to access watsonx.ai"
id="api-key" id="api-key"
type="password" type="password"
required required
@ -127,15 +137,6 @@ export function IBMOnboarding({
value={apiKey} value={apiKey}
onChange={(e) => setApiKey(e.target.value)} onChange={(e) => setApiKey(e.target.value)}
/> />
<LabelInput
label="IBM Project ID"
helperText="The project ID for your watsonx.ai account."
id="project-id"
required
placeholder="your-project-id"
value={projectId}
onChange={(e) => setProjectId(e.target.value)}
/>
{isLoadingModels && ( {isLoadingModels && (
<p className="text-mmd text-muted-foreground"> <p className="text-mmd text-muted-foreground">
Validating configuration... Validating configuration...

View file

@ -1,5 +1,6 @@
import { CheckIcon, ChevronsUpDownIcon } from "lucide-react"; import { CheckIcon, ChevronsUpDownIcon } from "lucide-react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {
Command, Command,
@ -24,6 +25,7 @@ export function ModelSelector({
placeholder = "Select model...", placeholder = "Select model...",
searchPlaceholder = "Search model...", searchPlaceholder = "Search model...",
noOptionsPlaceholder = "No models available", noOptionsPlaceholder = "No models available",
custom = false,
}: { }: {
options: { options: {
value: string; value: string;
@ -35,14 +37,17 @@ export function ModelSelector({
placeholder?: string; placeholder?: string;
searchPlaceholder?: string; searchPlaceholder?: string;
noOptionsPlaceholder?: string; noOptionsPlaceholder?: string;
custom?: boolean;
onValueChange: (value: string) => void; onValueChange: (value: string) => void;
}) { }) {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [searchValue, setSearchValue] = useState("");
useEffect(() => { useEffect(() => {
if (value && !options.find((option) => option.value === value)) { if (value && (!options.find((option) => option.value === value) && !custom)) {
onValueChange(""); onValueChange("");
} }
}, [options, value, onValueChange]); }, [options, value, custom, onValueChange]);
return ( return (
<Popover open={open} onOpenChange={setOpen}> <Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild> <PopoverTrigger asChild>
@ -57,12 +62,20 @@ export function ModelSelector({
{value ? ( {value ? (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{icon && <div className="w-4 h-4">{icon}</div>} {icon && <div className="w-4 h-4">{icon}</div>}
{options.find((framework) => framework.value === value)?.label} {options.find((framework) => framework.value === value)?.label ||
{options.find((framework) => framework.value === value) value}
{/* {options.find((framework) => framework.value === value)
?.default && ( ?.default && (
<span className="text-xs text-foreground p-1 rounded-md bg-muted"> <span className="text-xs text-foreground p-1 rounded-md bg-muted">
Default Default
</span> </span>
)} */}
{custom &&
value &&
!options.find((framework) => framework.value === value) && (
<Badge variant="outline" className="text-xs">
CUSTOM
</Badge>
)} )}
</div> </div>
) : options.length === 0 ? ( ) : options.length === 0 ? (
@ -73,9 +86,13 @@ export function ModelSelector({
<ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" /> <ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent align="start" className="w-[400px] p-0"> <PopoverContent align="start" className=" p-0 w-[var(--radix-popover-trigger-width)]">
<Command> <Command>
<CommandInput placeholder={searchPlaceholder} /> <CommandInput
placeholder={searchPlaceholder}
value={searchValue}
onValueChange={setSearchValue}
/>
<CommandList> <CommandList>
<CommandEmpty>{noOptionsPlaceholder}</CommandEmpty> <CommandEmpty>{noOptionsPlaceholder}</CommandEmpty>
<CommandGroup> <CommandGroup>
@ -98,14 +115,40 @@ export function ModelSelector({
/> />
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{option.label} {option.label}
{option.default && ( {/* {option.default && (
<span className="text-xs text-foreground p-1 rounded-md bg-muted"> <span className="text-xs text-foreground p-1 rounded-md bg-muted"> // DISABLING DEFAULT TAG FOR NOW
Default Default
</span> </span>
)} )} */}
</div> </div>
</CommandItem> </CommandItem>
))} ))}
{custom &&
searchValue &&
!options.find((option) => option.value === searchValue) && (
<CommandItem
value={searchValue}
onSelect={(currentValue) => {
if (currentValue !== value) {
onValueChange(currentValue);
}
setOpen(false);
}}
>
<CheckIcon
className={cn(
"mr-2 h-4 w-4",
value === searchValue ? "opacity-100" : "opacity-0",
)}
/>
<div className="flex items-center gap-2">
{searchValue}
<span className="text-xs text-foreground p-1 rounded-md bg-muted">
Custom
</span>
</div>
</CommandItem>
)}
</CommandGroup> </CommandGroup>
</CommandList> </CommandList>
</Command> </Command>

View file

@ -2,7 +2,7 @@ import { useState } from "react";
import { LabelInput } from "@/components/label-input"; import { LabelInput } from "@/components/label-input";
import { LabelWrapper } from "@/components/label-wrapper"; import { LabelWrapper } from "@/components/label-wrapper";
import OpenAILogo from "@/components/logo/openai-logo"; import OpenAILogo from "@/components/logo/openai-logo";
import { Checkbox } from "@/components/ui/checkbox"; import { Switch } from "@/components/ui/switch";
import { useDebouncedValue } from "@/lib/debounce"; import { useDebouncedValue } from "@/lib/debounce";
import type { OnboardingVariables } from "../../api/mutations/useOnboardingMutation"; import type { OnboardingVariables } from "../../api/mutations/useOnboardingMutation";
import { useGetOpenAIModelsQuery } from "../../api/queries/useGetModelsQuery"; import { useGetOpenAIModelsQuery } from "../../api/queries/useGetModelsQuery";
@ -74,17 +74,10 @@ export function OpenAIOnboarding({
<LabelWrapper <LabelWrapper
label="Use environment OpenAI API key" label="Use environment OpenAI API key"
id="get-api-key" id="get-api-key"
helperText={ description="Reuse the key from your environment config. Turn off to enter a different key."
<>
Reuse the key from your environment config.
<br />
Uncheck to enter a different key.
</>
}
flex flex
start
> >
<Checkbox <Switch
checked={getFromEnv} checked={getFromEnv}
onCheckedChange={handleGetFromEnvChange} onCheckedChange={handleGetFromEnvChange}
/> />

View file

@ -68,7 +68,6 @@ function OnboardingPage() {
// Mutations // Mutations
const onboardingMutation = useOnboardingMutation({ const onboardingMutation = useOnboardingMutation({
onSuccess: (data) => { onSuccess: (data) => {
toast.success("Onboarding completed successfully!");
console.log("Onboarding completed successfully", data); console.log("Onboarding completed successfully", data);
router.push(redirect); router.push(redirect);
}, },
@ -137,7 +136,7 @@ function OnboardingPage() {
Connect a model provider Connect a model provider
</h1> </h1>
</div> </div>
<Card className="w-full max-w-[580px]"> <Card className="w-full max-w-[600px]">
<Tabs <Tabs
defaultValue={modelProvider} defaultValue={modelProvider}
onValueChange={handleSetModelProvider} onValueChange={handleSetModelProvider}
@ -150,7 +149,7 @@ function OnboardingPage() {
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="watsonx"> <TabsTrigger value="watsonx">
<IBMLogo className="w-4 h-4" /> <IBMLogo className="w-4 h-4" />
IBM IBM watsonx.ai
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="ollama"> <TabsTrigger value="ollama">
<OllamaLogo className="w-4 h-4" /> <OllamaLogo className="w-4 h-4" />
@ -192,7 +191,7 @@ function OnboardingPage() {
disabled={!isComplete} disabled={!isComplete}
loading={onboardingMutation.isPending} loading={onboardingMutation.isPending}
> >
Complete <span className="select-none">Complete</span>
</Button> </Button>
</div> </div>
</TooltipTrigger> </TooltipTrigger>