@vertesia/tools-admin-ui 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +120 -0
  3. package/lib/AdminApp.d.ts +13 -0
  4. package/lib/AdminApp.d.ts.map +1 -0
  5. package/lib/AdminContext.d.ts +10 -0
  6. package/lib/AdminContext.d.ts.map +1 -0
  7. package/lib/components/CollectionCard.d.ts +5 -0
  8. package/lib/components/CollectionCard.d.ts.map +1 -0
  9. package/lib/components/DetailPage.d.ts +13 -0
  10. package/lib/components/DetailPage.d.ts.map +1 -0
  11. package/lib/components/EndpointPanel.d.ts +5 -0
  12. package/lib/components/EndpointPanel.d.ts.map +1 -0
  13. package/lib/components/HeroSection.d.ts +9 -0
  14. package/lib/components/HeroSection.d.ts.map +1 -0
  15. package/lib/components/ResourceCard.d.ts +5 -0
  16. package/lib/components/ResourceCard.d.ts.map +1 -0
  17. package/lib/components/ResourceSection.d.ts +10 -0
  18. package/lib/components/ResourceSection.d.ts.map +1 -0
  19. package/lib/components/SearchBar.d.ts +10 -0
  20. package/lib/components/SearchBar.d.ts.map +1 -0
  21. package/lib/components/SummaryBadge.d.ts +5 -0
  22. package/lib/components/SummaryBadge.d.ts.map +1 -0
  23. package/lib/components/index.d.ts +9 -0
  24. package/lib/components/index.d.ts.map +1 -0
  25. package/lib/hooks.d.ts +26 -0
  26. package/lib/hooks.d.ts.map +1 -0
  27. package/lib/index.d.ts +7 -0
  28. package/lib/index.d.ts.map +1 -0
  29. package/lib/pages/HomePage.d.ts +2 -0
  30. package/lib/pages/HomePage.d.ts.map +1 -0
  31. package/lib/pages/InteractionCollection.d.ts +2 -0
  32. package/lib/pages/InteractionCollection.d.ts.map +1 -0
  33. package/lib/pages/InteractionDetail.d.ts +2 -0
  34. package/lib/pages/InteractionDetail.d.ts.map +1 -0
  35. package/lib/pages/SkillCollection.d.ts +2 -0
  36. package/lib/pages/SkillCollection.d.ts.map +1 -0
  37. package/lib/pages/SkillDetail.d.ts +2 -0
  38. package/lib/pages/SkillDetail.d.ts.map +1 -0
  39. package/lib/pages/TemplateCollection.d.ts +2 -0
  40. package/lib/pages/TemplateCollection.d.ts.map +1 -0
  41. package/lib/pages/TemplateDetail.d.ts +2 -0
  42. package/lib/pages/TemplateDetail.d.ts.map +1 -0
  43. package/lib/pages/ToolCollection.d.ts +2 -0
  44. package/lib/pages/ToolCollection.d.ts.map +1 -0
  45. package/lib/pages/TypeCollection.d.ts +2 -0
  46. package/lib/pages/TypeCollection.d.ts.map +1 -0
  47. package/lib/pages/TypeDetail.d.ts +2 -0
  48. package/lib/pages/TypeDetail.d.ts.map +1 -0
  49. package/lib/tools-admin-ui.js +935 -0
  50. package/lib/tools-admin-ui.js.map +1 -0
  51. package/lib/types.d.ts +89 -0
  52. package/lib/types.d.ts.map +1 -0
  53. package/package.json +50 -0
  54. package/src/AdminApp.tsx +87 -0
  55. package/src/AdminContext.ts +17 -0
  56. package/src/admin.css +650 -0
  57. package/src/components/CollectionCard.tsx +23 -0
  58. package/src/components/DetailPage.tsx +40 -0
  59. package/src/components/EndpointPanel.tsx +24 -0
  60. package/src/components/HeroSection.tsx +88 -0
  61. package/src/components/ResourceCard.tsx +25 -0
  62. package/src/components/ResourceSection.tsx +31 -0
  63. package/src/components/SearchBar.tsx +35 -0
  64. package/src/components/SummaryBadge.tsx +9 -0
  65. package/src/components/index.ts +8 -0
  66. package/src/dev/env.ts +14 -0
  67. package/src/dev/main.tsx +37 -0
  68. package/src/hooks.ts +36 -0
  69. package/src/index.ts +6 -0
  70. package/src/pages/HomePage.tsx +99 -0
  71. package/src/pages/InteractionCollection.tsx +59 -0
  72. package/src/pages/InteractionDetail.tsx +92 -0
  73. package/src/pages/SkillCollection.tsx +111 -0
  74. package/src/pages/SkillDetail.tsx +112 -0
  75. package/src/pages/TemplateCollection.tsx +54 -0
  76. package/src/pages/TemplateDetail.tsx +68 -0
  77. package/src/pages/ToolCollection.tsx +55 -0
  78. package/src/pages/TypeCollection.tsx +60 -0
  79. package/src/pages/TypeDetail.tsx +63 -0
  80. package/src/types.ts +304 -0
  81. package/src/vite-env.d.ts +1 -0
package/src/types.ts ADDED
@@ -0,0 +1,304 @@
1
+ /**
2
+ * Types for the admin panel
3
+ */
4
+
5
+ import type {
6
+ AgentToolDefinition,
7
+ CatalogInteractionRef,
8
+ InCodeTypeDefinition,
9
+ RenderingTemplateDefinitionRef,
10
+ } from '@vertesia/common';
11
+
12
+ /**
13
+ * Server info from GET /api
14
+ */
15
+ export interface ServerInfo {
16
+ message: string;
17
+ version: string;
18
+ endpoints: {
19
+ tools: string[];
20
+ interactions: string[];
21
+ templates: string[];
22
+ mcp: string[];
23
+ };
24
+ }
25
+
26
+ export type ResourceType = 'tool' | 'skill' | 'interaction' | 'type' | 'template' | 'mcp';
27
+
28
+ /**
29
+ * A normalized resource entry for display and search.
30
+ */
31
+ export interface ResourceItem {
32
+ /** Unique identifier used for fetching details (e.g. "collection:name" for interactions). */
33
+ id?: string;
34
+ name: string;
35
+ title: string;
36
+ description: string;
37
+ type: ResourceType;
38
+ tags?: string[];
39
+ url?: string;
40
+ }
41
+
42
+ /**
43
+ * Metadata about a collection of resources, enriched with type and count client-side.
44
+ */
45
+ export interface CollectionInfo {
46
+ name: string;
47
+ title: string;
48
+ description: string;
49
+ type: ResourceType;
50
+ count: number;
51
+ }
52
+
53
+ /**
54
+ * Collection metadata as returned by each API endpoint.
55
+ */
56
+ interface CollectionMeta {
57
+ name: string;
58
+ title?: string;
59
+ description?: string;
60
+ }
61
+
62
+ /**
63
+ * Response shapes for each resource endpoint.
64
+ */
65
+ interface InteractionsResponse {
66
+ interactions: CatalogInteractionRef[];
67
+ collections: CollectionMeta[];
68
+ }
69
+
70
+ interface ToolsResponse {
71
+ tools: AgentToolDefinition[];
72
+ collections: CollectionMeta[];
73
+ }
74
+
75
+ interface SkillsResponse {
76
+ tools: AgentToolDefinition[];
77
+ collections: CollectionMeta[];
78
+ }
79
+
80
+ interface TypesResponse {
81
+ types: InCodeTypeDefinition[];
82
+ collections: CollectionMeta[];
83
+ }
84
+
85
+ interface TemplatesResponse {
86
+ templates: RenderingTemplateDefinitionRef[];
87
+ collections: CollectionMeta[];
88
+ }
89
+
90
+ /**
91
+ * Combined result of processing all endpoint responses.
92
+ */
93
+ export interface ResourceData {
94
+ collections: CollectionInfo[];
95
+ resources: ResourceItem[];
96
+ }
97
+
98
+ /**
99
+ * Formats a kebab/snake-case name into a title.
100
+ */
101
+ function formatTitle(name: string): string {
102
+ return name.replace(/[-_]/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
103
+ }
104
+
105
+ /**
106
+ * Counts items per collection by matching each item to a collection name.
107
+ * If there is only one collection, all items belong to it.
108
+ */
109
+ function countPerCollection<T>(
110
+ items: T[],
111
+ collections: CollectionMeta[],
112
+ extractCollection: (item: T) => string | undefined,
113
+ ): Map<string, number> {
114
+ const counts = new Map<string, number>();
115
+ for (const col of collections) counts.set(col.name, 0);
116
+
117
+ if (collections.length === 1) {
118
+ counts.set(collections[0].name, items.length);
119
+ return counts;
120
+ }
121
+
122
+ for (const item of items) {
123
+ const colName = extractCollection(item);
124
+ if (colName && counts.has(colName)) {
125
+ counts.set(colName, (counts.get(colName) || 0) + 1);
126
+ }
127
+ }
128
+
129
+ return counts;
130
+ }
131
+
132
+ /**
133
+ * Builds collections and a flat resource list from the 5 endpoint responses + MCP endpoints.
134
+ */
135
+ export function buildResourceData(
136
+ interactionsResp: InteractionsResponse,
137
+ toolsResp: ToolsResponse,
138
+ skillsResp: SkillsResponse,
139
+ typesResp: TypesResponse,
140
+ templatesResp: TemplatesResponse,
141
+ mcpEndpoints?: string[],
142
+ ): ResourceData {
143
+ const collections: CollectionInfo[] = [];
144
+ const resources: ResourceItem[] = [];
145
+
146
+ // --- Interactions (id format: "collection:name") ---
147
+ const interCounts = countPerCollection(
148
+ interactionsResp.interactions,
149
+ interactionsResp.collections,
150
+ (i) => i.id.split(':')[0],
151
+ );
152
+ for (const col of interactionsResp.collections) {
153
+ collections.push({
154
+ name: col.name,
155
+ title: col.title || formatTitle(col.name),
156
+ description: col.description || '',
157
+ type: 'interaction',
158
+ count: interCounts.get(col.name) || 0,
159
+ });
160
+ }
161
+ for (const inter of interactionsResp.interactions) {
162
+ resources.push({
163
+ id: inter.id,
164
+ name: inter.name,
165
+ title: inter.title || formatTitle(inter.name),
166
+ description: inter.description || '',
167
+ type: 'interaction',
168
+ tags: inter.tags,
169
+ });
170
+ }
171
+
172
+ // --- Tools (url format: "tools/{collection}") ---
173
+ const toolCounts = countPerCollection(
174
+ toolsResp.tools,
175
+ toolsResp.collections,
176
+ (t) => t.url?.split('/').pop(),
177
+ );
178
+ for (const col of toolsResp.collections) {
179
+ collections.push({
180
+ name: col.name,
181
+ title: col.title || formatTitle(col.name),
182
+ description: col.description || '',
183
+ type: 'tool',
184
+ count: toolCounts.get(col.name) || 0,
185
+ });
186
+ }
187
+ for (const tool of toolsResp.tools) {
188
+ resources.push({
189
+ name: tool.name,
190
+ title: formatTitle(tool.name),
191
+ description: tool.description || '',
192
+ type: 'tool',
193
+ url: tool.url,
194
+ });
195
+ }
196
+
197
+ // --- Skills (url format: "skills/{collection}") ---
198
+ const skillCounts = countPerCollection(
199
+ skillsResp.tools,
200
+ skillsResp.collections,
201
+ (t) => t.url?.split('/').pop(),
202
+ );
203
+ for (const col of skillsResp.collections) {
204
+ collections.push({
205
+ name: col.name,
206
+ title: col.title || formatTitle(col.name),
207
+ description: col.description || '',
208
+ type: 'skill',
209
+ count: skillCounts.get(col.name) || 0,
210
+ });
211
+ }
212
+ for (const skill of skillsResp.tools) {
213
+ resources.push({
214
+ name: skill.name,
215
+ title: formatTitle(skill.name),
216
+ description: skill.description || '',
217
+ type: 'skill',
218
+ url: skill.url,
219
+ });
220
+ }
221
+
222
+ // --- Types (id format: "collection:pathName") ---
223
+ const typeCounts = countPerCollection(
224
+ typesResp.types,
225
+ typesResp.collections,
226
+ (t) => t.id?.split(':')[0],
227
+ );
228
+ for (const col of typesResp.collections) {
229
+ collections.push({
230
+ name: col.name,
231
+ title: col.title || formatTitle(col.name),
232
+ description: col.description || '',
233
+ type: 'type',
234
+ count: typeCounts.get(col.name) || 0,
235
+ });
236
+ }
237
+ for (const t of typesResp.types) {
238
+ resources.push({
239
+ name: t.name,
240
+ title: formatTitle(t.name),
241
+ description: t.description || '',
242
+ type: 'type',
243
+ tags: t.tags,
244
+ });
245
+ }
246
+
247
+ // --- Templates (path format: "/api/templates/{collection}/{name}") ---
248
+ const tmplCounts = countPerCollection(
249
+ templatesResp.templates,
250
+ templatesResp.collections,
251
+ (t) => {
252
+ const segments = t.path?.split('/');
253
+ return segments && segments.length >= 4 ? segments[3] : undefined;
254
+ },
255
+ );
256
+ for (const col of templatesResp.collections) {
257
+ collections.push({
258
+ name: col.name,
259
+ title: col.title || formatTitle(col.name),
260
+ description: col.description || '',
261
+ type: 'template',
262
+ count: tmplCounts.get(col.name) || 0,
263
+ });
264
+ }
265
+ for (const tmpl of templatesResp.templates) {
266
+ resources.push({
267
+ name: tmpl.name,
268
+ title: tmpl.title || formatTitle(tmpl.name),
269
+ description: tmpl.description || '',
270
+ type: 'template',
271
+ tags: tmpl.tags,
272
+ url: tmpl.path,
273
+ });
274
+ }
275
+
276
+ // --- MCP (derived from serverInfo, no endpoint) ---
277
+ for (const endpoint of mcpEndpoints || []) {
278
+ const name = endpoint.split('/').pop() || endpoint;
279
+ resources.push({
280
+ name,
281
+ title: formatTitle(name),
282
+ description: '',
283
+ type: 'mcp',
284
+ url: endpoint,
285
+ });
286
+ }
287
+
288
+ return { collections, resources };
289
+ }
290
+
291
+ /**
292
+ * Filters resources by a search query, matching against name, title, description, type, and tags.
293
+ */
294
+ export function filterResources(items: ResourceItem[], query: string): ResourceItem[] {
295
+ const q = query.toLowerCase().trim();
296
+ if (!q) return items;
297
+ return items.filter(item =>
298
+ item.name.toLowerCase().includes(q) ||
299
+ item.title.toLowerCase().includes(q) ||
300
+ item.description.toLowerCase().includes(q) ||
301
+ item.type.includes(q) ||
302
+ item.tags?.some(t => t.toLowerCase().includes(q))
303
+ );
304
+ }
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />