mirror of
https://github.com/fosrl/pangolin.git
synced 2026-09-01 08:51:35 +02:00
add alert warning for configure coding agents
This commit is contained in:
@@ -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"}
|
||||
|
||||
Reference in New Issue
Block a user