refactor: consolidate AvailableVariables component and enhance variable display logic across dialogs

- Moved `AvailableVariables` to shared directory.
- Updated dialogs to use shared `AvailableVariables` component.
- Enhanced inline expressions and processors dialog with better variable display.
This commit is contained in:
shine1i 2026-02-09 20:07:41 +01:00
commit aab37f8dc2
5 changed files with 93 additions and 65 deletions

View file

@ -1,3 +1,4 @@
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import {
Select,
@ -7,7 +8,9 @@ import {
SelectValue,
} from "@/components/ui/select";
import type { ReactElement } from "react";
import { useCanvasLabStore } from "../../stores/canvas-lab";
import type { ExpressionConfig, ExpressionDtype } from "../../types";
import { getAvailableVariables } from "../../utils/variables";
import { InlineField } from "./inline-field";
type InlineExpressionProps = {
@ -21,35 +24,56 @@ export function InlineExpression({
config,
onUpdate,
}: InlineExpressionProps): ReactElement {
const configs = useCanvasLabStore((state) => state.configs);
const vars = getAvailableVariables(configs, config.id);
return (
<div className="grid gap-3 sm:grid-cols-[130px_1fr]">
<InlineField label="Output type">
<Select
value={config.dtype}
onValueChange={(value) =>
onUpdate({ dtype: value as ExpressionDtype })
}
>
<SelectTrigger className="nodrag h-8 w-full text-xs">
<SelectValue placeholder="dtype" />
</SelectTrigger>
<SelectContent>
{DTYPE_OPTIONS.map((dtype) => (
<SelectItem key={dtype} value={dtype}>
{dtype}
</SelectItem>
<div className="space-y-3">
<div className="grid gap-3 sm:grid-cols-[130px_1fr]">
<InlineField label="Output type">
<Select
value={config.dtype}
onValueChange={(value) =>
onUpdate({ dtype: value as ExpressionDtype })
}
>
<SelectTrigger className="nodrag h-8 w-full text-xs">
<SelectValue placeholder="dtype" />
</SelectTrigger>
<SelectContent>
{DTYPE_OPTIONS.map((dtype) => (
<SelectItem key={dtype} value={dtype}>
{dtype}
</SelectItem>
))}
</SelectContent>
</Select>
</InlineField>
<InlineField label="Expression">
<Input
className="nodrag h-8 w-full text-xs"
placeholder="{{ column_name }}"
value={config.expr}
onChange={(event) => onUpdate({ expr: event.target.value })}
/>
</InlineField>
</div>
{vars.length > 0 && (
<div className="space-y-1">
<p className="text-[10px] font-medium text-muted-foreground">Available references</p>
<div className="flex flex-wrap gap-1">
{vars.map((v) => (
<Badge
key={v}
variant="secondary"
className="corner-squircle h-4 px-1.5 font-mono text-[10px]"
>
{v}
</Badge>
))}
</SelectContent>
</Select>
</InlineField>
<InlineField label="Expression">
<Input
className="nodrag h-8 w-full text-xs"
placeholder="{{ column_name }}"
value={config.expr}
onChange={(event) => onUpdate({ expr: event.target.value })}
/>
</InlineField>
</div>
</div>
)}
</div>
);
}

View file

@ -8,6 +8,7 @@ import {
import { Textarea } from "@/components/ui/textarea";
import type { ReactElement } from "react";
import type { ExpressionConfig, ExpressionDtype } from "../../types";
import { AvailableVariables } from "../shared/available-variables";
import { NameField } from "../shared/name-field";
const DTYPE_OPTIONS: ExpressionDtype[] = ["str", "int", "float", "bool"];
@ -31,6 +32,7 @@ export function ExpressionDialog({
};
return (
<div className="space-y-4">
<AvailableVariables configId={config.id} />
<NameField
value={config.name}
onChange={(value) => onUpdate({ name: value })}

View file

@ -17,7 +17,7 @@ import {
import { Textarea } from "@/components/ui/textarea";
import { type ReactElement, useEffect, useRef, useState } from "react";
import type { LlmConfig, Score } from "../../types";
import { AvailableVariables } from "./available-variables";
import { AvailableVariables } from "../shared/available-variables";
import { NameField } from "../shared/name-field";
const CODE_LANG_OPTIONS = [

View file

@ -7,6 +7,7 @@ import { VisuallyHidden } from "radix-ui";
import { type ReactElement, useMemo } from "react";
import type { CanvasProcessorConfig } from "../types";
import { buildDefaultSchemaTransform } from "../utils/processors";
import { AvailableVariables } from "./shared/available-variables";
type ProcessorsDialogProps = {
open: boolean;
onOpenChange: (open: boolean) => void;
@ -72,7 +73,7 @@ export function ProcessorsDialog({
<DialogTitle>Processors</DialogTitle>
</VisuallyHidden.Root>
<div className="space-y-4">
<div className="flex items-center justify-between gap-3 rounded-2xl border border-border/60 px-3 py-2">
<div className="flex items-center justify-between gap-3 corner-squircle rounded-2xl border border-border/60 px-3 py-2">
<div>
<p className="text-sm font-semibold">Schema transform</p>
<p className="text-xs text-muted-foreground">
@ -87,6 +88,7 @@ export function ProcessorsDialog({
{schemaProcessor && (
<div className="space-y-3">
<AvailableVariables configId="" />
<div className="grid gap-2">
<label
className="text-xs font-semibold uppercase text-muted-foreground"

View file

@ -1,36 +1,36 @@
import { Badge } from "@/components/ui/badge";
import type { ReactElement } from "react";
import { useCanvasLabStore } from "../../stores/canvas-lab";
import { getAvailableVariables } from "../../utils/variables";
type AvailableVariablesProps = {
configId: string;
};
export function AvailableVariables({
configId,
}: AvailableVariablesProps): ReactElement | null {
const configs = useCanvasLabStore((state) => state.configs);
const vars = getAvailableVariables(configs, configId);
if (vars.length === 0) return null;
return (
<div className="corner-squircle rounded-2xl border border-border/60 px-3 py-2">
<p className="mb-2 text-xs font-semibold uppercase text-muted-foreground">
Available variables
</p>
<div className="flex flex-wrap gap-1.5">
{vars.map((v) => (
<Badge
key={v}
variant="secondary"
className="corner-squircle font-mono text-[11px]"
>
{`{{ ${v} }}`}
</Badge>
))}
</div>
</div>
);
}
import { Badge } from "@/components/ui/badge";
import type { ReactElement } from "react";
import { useCanvasLabStore } from "../../stores/canvas-lab";
import { getAvailableVariables } from "../../utils/variables";
type AvailableVariablesProps = {
configId: string;
};
export function AvailableVariables({
configId,
}: AvailableVariablesProps): ReactElement | null {
const configs = useCanvasLabStore((state) => state.configs);
const vars = getAvailableVariables(configs, configId);
if (vars.length === 0) return null;
return (
<div className="corner-squircle rounded-2xl border border-border/60 px-3 py-2">
<p className="mb-2 text-xs font-semibold uppercase text-muted-foreground">
Available references
</p>
<div className="flex flex-wrap gap-1.5">
{vars.map((v) => (
<Badge
key={v}
variant="secondary"
className="corner-squircle font-mono text-[11px]"
>
{`{{ ${v} }}`}
</Badge>
))}
</div>
</div>
);
}