From da35ad3d7cd56cd288c27751fe516471479301df Mon Sep 17 00:00:00 2001 From: decobot Date: Wed, 15 Apr 2026 10:31:43 -0300 Subject: [PATCH] improve matcher picker: 3-col grid layout, fix description/icon extraction Redesign matcher picker modal as a 3-column grid with icon, title, and description per card. Fix getDescription to resolve top-level $ref in matcher schemas from _meta, matching how getTitle/getIcon already worked. Co-Authored-By: Claude Opus 4.6 --- api/tools/files.ts | 5 + web/tools/file-explorer/index.tsx | 147 +++++++++++++++--------------- 2 files changed, 77 insertions(+), 75 deletions(-) diff --git a/api/tools/files.ts b/api/tools/files.ts index d64541e..e9d67c1 100644 --- a/api/tools/files.ts +++ b/api/tools/files.ts @@ -1376,6 +1376,11 @@ export const listMatchersTool = createTool({ const getDescription = (schema: RawSchema): string | undefined => { if (typeof schema.description === "string") return schema.description; + if (typeof schema.$ref === "string") { + const resolved = resolveRef(schema.$ref); + if (typeof resolved.description === "string") + return resolved.description; + } for (const key of ["allOf", "anyOf", "oneOf"] as const) { const arr = schema[key]; if (!Array.isArray(arr)) continue; diff --git a/web/tools/file-explorer/index.tsx b/web/tools/file-explorer/index.tsx index 618faaf..31dcffd 100644 --- a/web/tools/file-explorer/index.tsx +++ b/web/tools/file-explorer/index.tsx @@ -780,7 +780,7 @@ function MatcherPicker({ return ( <> - {/* Trigger button */} + {/* Trigger */} - - - {/* Search */} -
-
+
+ {/* Header + search */} +
+ + Segment Rule + +
setSearch(e.target.value)} - placeholder="Search…" + placeholder="Search\u2026" className="w-full bg-transparent text-xs outline-none placeholder:text-muted-foreground/50" />
-
- - {/* List */} -
- {/* Always */} +
+ {/* Grid */} +
{!matchers ? ( -
+
- Loading… -
- ) : filtered?.length === 0 ? ( -
- No matchers found + Loading matchers\u2026
) : ( - filtered?.map((m) => { - const Icon = matcherIcon(m.icon); - return ( - + + {(filtered ?? []).map((m) => { + const Icon = matcherIcon(m.icon); + return ( +
- - ); - }) + > + +
+
{m.title}
+ {m.description && ( +
+ {m.description} +
+ )} +
+ + ); + })} +
+ )} + + {matchers && filtered?.length === 0 && ( +
+ No matchers found +
)}