add alert warning for configure coding agents

This commit is contained in:
miloschwartz
2026-08-19 10:24:53 -04:00
parent dc8e724482
commit 350de6ad2e
7 changed files with 264 additions and 119 deletions
@@ -1,25 +1,13 @@
"use client";
import { AiConfigCodeBlock } from "@app/components/ai-client-config/AiConfigCodeBlock";
import { AiConfigBlocks } from "@app/components/ai-client-config/AiConfigBlocks";
import { Button } from "@app/components/ui/button";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger
} from "@app/components/ui/collapsible";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue
} from "@app/components/ui/select";
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger
} from "@app/components/ui/tabs";
import { OptionSelect } from "@app/components/OptionSelect";
import type {
AiClientAuthInput,
AiClientId,
@@ -43,6 +31,8 @@ type AiClientConfigCardProps = {
resourceNiceId?: string;
};
type SetupMode = "cli" | "manual";
export function AiClientConfigCard({
clientId,
name,
@@ -57,6 +47,7 @@ export function AiClientConfigCard({
const [resolvedIconSrc, setResolvedIconSrc] = useState(iconSrc.light);
const [open, setOpen] = useState(false);
const [presetId, setPresetId] = useState<AiClientPresetId>("default");
const [setupMode, setSetupMode] = useState<SetupMode>("cli");
const [revealedKey, setRevealedKey] = useState<string | null>(null);
const [revealing, setRevealing] = useState(false);
const [revealError, setRevealError] = useState(false);
@@ -120,29 +111,24 @@ export function AiClientConfigCard({
const manualContent = guide ? (
<div className="min-w-0 space-y-4">
{guide.presets.length > 1 ? (
<Select
value={presetId}
onValueChange={(value) =>
setPresetId(value as AiClientPresetId)
}
>
<SelectTrigger size="sm" className="max-w-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
{guide.presets.map((p) => (
<SelectItem key={p.id} value={p.id}>
{p.label}
</SelectItem>
))}
</SelectContent>
</Select>
<OptionSelect<AiClientPresetId>
label={t("aiClientConfigPreset")}
options={guide.presets.map((p) => ({
value: p.id,
label: p.label
}))}
value={preset?.id ?? presetId}
onChange={setPresetId}
cols={2}
/>
) : null}
{preset ? (
<AiConfigBlocks
key={preset.id}
blocks={preset.blocks}
relation={preset.relation}
/>
) : null}
<div className="grid min-w-0 gap-4">
{preset?.blocks.map((block) => (
<AiConfigCodeBlock key={block.id} block={block} />
))}
</div>
</div>
) : null;
@@ -191,35 +177,32 @@ export function AiClientConfigCard({
) : null}
{guide ? (
guide.cli ? (
<Tabs defaultValue="cli">
<TabsList>
<TabsTrigger value="cli">
{t("aiClientConfigTabCli")}
</TabsTrigger>
<TabsTrigger value="manual">
{t("aiClientConfigTabManual")}
</TabsTrigger>
</TabsList>
<TabsContent
value="cli"
className="grid min-w-0 gap-4 mt-4"
>
<AiConfigCodeBlock
block={guide.cli.configure}
<div className="min-w-0 space-y-4">
<OptionSelect<SetupMode>
label={t("aiClientConfigSetup")}
options={[
{
value: "cli",
label: t("aiClientConfigTabCli")
},
{
value: "manual",
label: t("aiClientConfigTabManual")
}
]}
value={setupMode}
onChange={setSetupMode}
cols={2}
/>
{setupMode === "cli" ? (
<AiConfigBlocks
blocks={guide.cli}
relation="options"
/>
{guide.cli.configureWithKey ? (
<AiConfigCodeBlock
block={guide.cli.configureWithKey}
/>
) : null}
</TabsContent>
<TabsContent
value="manual"
className="min-w-0 mt-4"
>
{manualContent}
</TabsContent>
</Tabs>
) : (
manualContent
)}
</div>
) : (
manualContent
)
@@ -0,0 +1,72 @@
"use client";
import { AiConfigCodeBlock } from "@app/components/ai-client-config/AiConfigCodeBlock";
import {
OptionSelect,
type OptionSelectOption
} from "@app/components/OptionSelect";
import type { AiConfigBlock, AiConfigRelation } from "@app/lib/aiClientConfig";
import { useTranslations } from "next-intl";
import { useEffect, useMemo, useState } from "react";
type AiConfigBlocksProps = {
blocks: AiConfigBlock[];
relation: AiConfigRelation;
};
export function AiConfigBlocks({ blocks, relation }: AiConfigBlocksProps) {
const t = useTranslations();
const showPicker = relation === "options" && blocks.length > 1;
const [selectedId, setSelectedId] = useState(blocks[0]?.id ?? "");
const methodOptions: OptionSelectOption<string>[] = useMemo(
() =>
blocks.map((block) => ({
value: block.id,
label: block.label
})),
[blocks]
);
useEffect(() => {
if (!blocks.some((block) => block.id === selectedId)) {
setSelectedId(blocks[0]?.id ?? "");
}
}, [blocks, selectedId]);
if (blocks.length === 0) {
return null;
}
if (showPicker) {
const selected =
blocks.find((block) => block.id === selectedId) ?? blocks[0];
return (
<div className="min-w-0 space-y-4">
<OptionSelect
label={t("method")}
options={methodOptions}
value={selected.id}
onChange={setSelectedId}
cols={2}
/>
<AiConfigCodeBlock block={selected} hideLabel />
</div>
);
}
const numberSteps = relation === "steps" && blocks.length > 1;
return (
<div className="grid min-w-0 gap-4">
{blocks.map((block, index) => (
<AiConfigCodeBlock
key={block.id}
block={block}
step={numberSteps ? index + 1 : undefined}
/>
))}
</div>
);
}
@@ -1,23 +1,53 @@
"use client";
import CopyTextBox from "@app/components/CopyTextBox";
import type { AiConfigBlock } from "@app/lib/aiClientConfig";
import { Alert, AlertDescription } from "@app/components/ui/alert";
import {
aiConfigBlockHasPlaceholders,
type AiConfigBlock
} from "@app/lib/aiClientConfig";
import { cn } from "@app/lib/cn";
import { AlertCircle } from "lucide-react";
import { useTranslations } from "next-intl";
type AiConfigCodeBlockProps = {
block: AiConfigBlock;
step?: number;
hideLabel?: boolean;
};
export function AiConfigCodeBlock({
block,
step,
hideLabel = false
}: AiConfigCodeBlockProps) {
const t = useTranslations();
const label =
step != null
? `${t("aiClientConfigStep", { number: step })}: ${block.label}`
: block.label;
export function AiConfigCodeBlock({ block }: { block: AiConfigBlock }) {
return (
<div className="min-w-0 space-y-1.5">
<p className="font-mono text-xs text-muted-foreground">
{block.label}
</p>
{!hideLabel ? (
<p className="font-mono text-xs text-muted-foreground">
{label}
</p>
) : null}
<div
className={cn(
"min-w-0",
block.kind === "steps"
? "[&_pre]:text-sm"
: "[&_pre]:text-xs [&_code]:font-mono"
block.kind !== "steps" && "[&_code]:font-mono"
)}
>
{aiConfigBlockHasPlaceholders(block) ? (
<Alert variant="neutral" className="mb-3">
<AlertCircle className="h-4 w-4" />
<AlertDescription>
{t("aiClientConfigPlaceholderWarning")}
</AlertDescription>
</Alert>
) : null}
<CopyTextBox
text={block.displayText}
wrapText={block.kind === "steps"}