feat(recipe-studio): enforce run name validation for full runs and refine validation UI

This commit is contained in:
Shine1i 2026-03-09 02:53:59 +01:00
commit f41a552c29
3 changed files with 25 additions and 13 deletions

View file

@ -254,6 +254,8 @@ export function RunDialog({
}: RunDialogProps): ReactElement {
const [advancedOpen, setAdvancedOpen] = useState(false);
const kindLabel = kind === "preview" ? "Preview" : "Full run";
const normalizedFullRunName = fullRunName.trim();
const isFullRunNameMissing = kind === "full" && normalizedFullRunName.length === 0;
const rowHint =
kind === "preview"
? "How many sample rows to generate for a quick check."
@ -376,7 +378,13 @@ export function RunDialog({
value={fullRunName}
onChange={(event) => onFullRunNameChange(event.target.value)}
placeholder="Sprint dataset v2"
aria-invalid={isFullRunNameMissing}
/>
{isFullRunNameMissing ? (
<p className="text-xs text-destructive">
Run name is required before starting a full run.
</p>
) : null}
</div>
)}
@ -657,7 +665,12 @@ export function RunDialog({
<HugeiconsIcon icon={TestTube01Icon} className="size-3.5" />
{validateLoading ? "Validating..." : "Validate recipe"}
</Button>
<Button type="button" onClick={onRun} disabled={loading} className="corner-squircle">
<Button
type="button"
onClick={onRun}
disabled={loading || isFullRunNameMissing}
className="corner-squircle"
>
<HugeiconsIcon icon={CookBookIcon} className="size-3.5" />
{loading ? "Starting..." : `Start ${kindLabel.toLowerCase()}`}
</Button>

View file

@ -324,19 +324,26 @@ export function useRecipeExecutions({
rows: number,
runName: string | null,
): Promise<boolean> => {
const trimmedRunName = typeof runName === "string" ? runName.trim() : "";
if (kind === "full" && !trimmedRunName) {
const message = "Run name required for full runs.";
setRunErrors([message]);
toastError("Run name required", message);
return false;
}
const payload = readExecutablePayload();
if (!payload) {
return false;
}
const normalizedRows = sanitizeExecutionRows(rows, kind);
const normalizedRunName = kind === "full" ? normalizeRunName(runName) : null;
const executionPayload = buildExecutionPayload({
payload,
kind,
rows: normalizedRows,
settings: runSettings,
runName: normalizedRunName,
runName,
});
try {
@ -361,7 +368,7 @@ export function useRecipeExecutions({
payload,
rows: normalizedRows,
settings: runSettings,
runName: normalizedRunName,
runName,
});
},
[readExecutablePayload, runExecution, runSettings, setRunErrors],

View file

@ -604,21 +604,13 @@ export function DatasetSection() {
Local dataset metadata
</p>
<p className="text-[10px] text-muted-foreground/80">
Data Recipe output. Eval split unavailable for local datasets.
Data Recipe output.
</p>
</div>
</div>
{uploadedFile ? (
<div className="flex flex-col gap-3">
<div className="rounded-md bg-background/60 px-2.5 py-2">
<p className="mb-1 text-[10px] uppercase tracking-[0.12em] text-muted-foreground">
Path
</p>
<p className="truncate font-mono text-[11px] text-foreground" title={uploadedFile}>
{uploadedFile}
</p>
</div>
<div className="grid grid-cols-2 gap-x-4 gap-y-2 text-xs">
<MetadataRow
label="Rows"