Skip to content

Commit 465abd5

Browse files
Hashclaude
andcommitted
fix: blueprint edit/search/import polish
- preserve runtimeConfig and permissions on edit by omitting them from the PATCH payload (only sent on create where they default to {}) - debounce blueprint search via useDeferredValue to avoid a fetch on every keystroke - add success toast after a successful blueprint import Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 3fe4e9e commit 465abd5

1 file changed

Lines changed: 8 additions & 8 deletions

File tree

ui/src/pages/Blueprints.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useEffect, useMemo } from "react";
1+
import { useState, useEffect, useMemo, useDeferredValue } from "react";
22
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
33
import { useNavigate } from "@/lib/router";
44
import { useCompany } from "../context/CompanyContext";
@@ -454,6 +454,7 @@ export function Blueprints() {
454454
const { pushToast } = useToastActions();
455455

456456
const [search, setSearch] = useState("");
457+
const deferredSearch = useDeferredValue(search);
457458
const [roleFilter, setRoleFilter] = useState("");
458459
const [activeTag, setActiveTag] = useState<string | null>(null);
459460
const [dialogMode, setDialogMode] = useState<DialogMode>(null);
@@ -466,8 +467,8 @@ export function Blueprints() {
466467
}, [setBreadcrumbs]);
467468

468469
const blueprintsQ = useQuery({
469-
queryKey: queryKeys.blueprints.list(search || undefined, roleFilter || undefined),
470-
queryFn: () => blueprintsApi.list({ search: search || undefined, role: roleFilter || undefined }),
470+
queryKey: queryKeys.blueprints.list(deferredSearch || undefined, roleFilter || undefined),
471+
queryFn: () => blueprintsApi.list({ search: deferredSearch || undefined, role: roleFilter || undefined }),
471472
});
472473

473474
const { data: companySkills } = useQuery({
@@ -516,7 +517,7 @@ export function Blueprints() {
516517
const adapter = getUIAdapter(state.configValues.adapterType);
517518
const adapterConfig = adapter.buildAdapterConfig(state.configValues);
518519

519-
const payload = {
520+
const basePayload = {
520521
name: state.name.trim(),
521522
description: state.description.trim() || null,
522523
role: state.role as typeof AGENT_ROLES[number],
@@ -525,16 +526,14 @@ export function Blueprints() {
525526
tags: state.tags,
526527
adapterType: state.configValues.adapterType,
527528
adapterConfig,
528-
runtimeConfig: (dialogMode === "edit" ? activeBlueprint?.runtimeConfig : null) ?? {},
529529
budgetMonthlyCents: state.budgetMonthlyCents,
530-
permissions: (dialogMode === "edit" ? activeBlueprint?.permissions : null) ?? {},
531530
metadata: state.desiredSkills.length > 0 ? { desiredSkills: state.desiredSkills } : null,
532531
};
533532

534533
if (dialogMode === "create") {
535-
createMutation.mutate(payload);
534+
createMutation.mutate({ ...basePayload, runtimeConfig: {}, permissions: {} });
536535
} else if (dialogMode === "edit" && activeBlueprint) {
537-
updateMutation.mutate({ id: activeBlueprint.id, input: payload });
536+
updateMutation.mutate({ id: activeBlueprint.id, input: basePayload });
538537
}
539538
}
540539

@@ -575,6 +574,7 @@ export function Blueprints() {
575574
metadata: payload.metadata ?? null,
576575
});
577576
queryClient.invalidateQueries({ queryKey: queryKeys.blueprints.all });
577+
pushToast({ tone: "success", title: "Blueprint imported" });
578578
} catch (err) {
579579
setImportError(err instanceof Error ? err.message : "Invalid blueprint file");
580580
}

0 commit comments

Comments
 (0)