@seed-ship/mcp-ui-solid 6.11.0 → 6.13.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.
- package/CHANGELOG.md +42 -0
- package/dist/services/component-registry.cjs +67 -0
- package/dist/services/component-registry.cjs.map +1 -1
- package/dist/services/component-registry.d.ts +4 -0
- package/dist/services/component-registry.d.ts.map +1 -1
- package/dist/services/component-registry.js +67 -0
- package/dist/services/component-registry.js.map +1 -1
- package/dist/types/index.d.ts +54 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types.d.cts +54 -1
- package/dist/types.d.ts +54 -1
- package/package.json +1 -1
- package/src/services/component-registry.test.ts +31 -4
- package/src/services/component-registry.ts +71 -0
- package/src/types/graph-types.test.ts +42 -0
- package/src/types/index.ts +58 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -5,19 +5,46 @@
|
|
|
5
5
|
import { describe, it, expect } from 'vitest'
|
|
6
6
|
import { validateAgainstRegistry, getComponentEntry, ComponentRegistry } from './component-registry'
|
|
7
7
|
import type { ComponentType } from '../types'
|
|
8
|
+
import { ComponentTypeSchema } from '@seed-ship/mcp-ui-spec'
|
|
8
9
|
|
|
9
|
-
/** All
|
|
10
|
+
/** All 20 component types in the registry */
|
|
10
11
|
const ALL_TYPES: ComponentType[] = [
|
|
11
12
|
'chart', 'table', 'metric', 'text', 'grid',
|
|
12
13
|
'action', 'footer', 'carousel', 'artifact',
|
|
13
|
-
'code', 'map', 'form', 'modal', 'action-group',
|
|
14
|
+
'code', 'map', 'graph', 'form', 'modal', 'action-group',
|
|
14
15
|
'image-gallery', 'video', 'iframe', 'image', 'link',
|
|
15
16
|
]
|
|
16
17
|
|
|
18
|
+
// Schema component types that are intentionally NOT standalone registry
|
|
19
|
+
// entries. `composite` is a layout container rendered inline by
|
|
20
|
+
// UIResourceRenderer (like a bare layout), not a leaf component with its own
|
|
21
|
+
// params schema / examples.
|
|
22
|
+
const REGISTRY_EXCEPTIONS = new Set<string>(['composite'])
|
|
23
|
+
|
|
24
|
+
describe('registry ↔ schema parity (P1.5)', () => {
|
|
25
|
+
it('every schema component type has a registry entry (except documented containers)', () => {
|
|
26
|
+
const missing = (ComponentTypeSchema.options as readonly string[]).filter(
|
|
27
|
+
(t) => !REGISTRY_EXCEPTIONS.has(t) && !ComponentRegistry.has(t as ComponentType)
|
|
28
|
+
)
|
|
29
|
+
expect(missing).toEqual([])
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('every registry type is a valid schema component type', () => {
|
|
33
|
+
const schemaTypes = new Set<string>(ComponentTypeSchema.options)
|
|
34
|
+
const extra = Array.from(ComponentRegistry.keys()).filter((t) => !schemaTypes.has(t))
|
|
35
|
+
expect(extra).toEqual([])
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('graph is registered (regression for P1.5)', () => {
|
|
39
|
+
expect(ComponentRegistry.has('graph')).toBe(true)
|
|
40
|
+
expect(getComponentEntry('graph')?.type).toBe('graph')
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
17
44
|
describe('ComponentRegistry', () => {
|
|
18
45
|
describe('registry completeness', () => {
|
|
19
|
-
it('has exactly
|
|
20
|
-
expect(ComponentRegistry.size).toBe(
|
|
46
|
+
it('has exactly 20 registered types', () => {
|
|
47
|
+
expect(ComponentRegistry.size).toBe(20)
|
|
21
48
|
})
|
|
22
49
|
|
|
23
50
|
it.each(ALL_TYPES)('has registry entry for "%s"', (type) => {
|
|
@@ -632,6 +632,75 @@ export const MapRegistry: ComponentRegistryEntry = {
|
|
|
632
632
|
limits: DEFAULT_RESOURCE_LIMITS,
|
|
633
633
|
}
|
|
634
634
|
|
|
635
|
+
/**
|
|
636
|
+
* Graph Registry Entry (v6.12.0 — audit P1.5)
|
|
637
|
+
*/
|
|
638
|
+
export const GraphRegistry: ComponentRegistryEntry = {
|
|
639
|
+
type: 'graph',
|
|
640
|
+
name: 'NodeLinkGraph',
|
|
641
|
+
description:
|
|
642
|
+
'Render a node-link graph (entities and their relationships) with @antv/g6. Best for provenance/source chains, dependency or process graphs, and ontology-lite entity/relation views. Degrades to an edge table when the graph engine is unavailable.',
|
|
643
|
+
schema: {
|
|
644
|
+
type: 'object',
|
|
645
|
+
properties: {
|
|
646
|
+
nodes: {
|
|
647
|
+
type: 'array',
|
|
648
|
+
description: 'Graph nodes (at least one required)',
|
|
649
|
+
items: {
|
|
650
|
+
type: 'object',
|
|
651
|
+
properties: {
|
|
652
|
+
id: { type: 'string' },
|
|
653
|
+
label: { type: 'string' },
|
|
654
|
+
group: { type: 'string' },
|
|
655
|
+
},
|
|
656
|
+
required: ['id'],
|
|
657
|
+
},
|
|
658
|
+
},
|
|
659
|
+
edges: {
|
|
660
|
+
type: 'array',
|
|
661
|
+
description: 'Edges between node ids',
|
|
662
|
+
items: {
|
|
663
|
+
type: 'object',
|
|
664
|
+
properties: {
|
|
665
|
+
source: { type: 'string' },
|
|
666
|
+
target: { type: 'string' },
|
|
667
|
+
label: { type: 'string' },
|
|
668
|
+
weight: { type: 'number' },
|
|
669
|
+
},
|
|
670
|
+
required: ['source', 'target'],
|
|
671
|
+
},
|
|
672
|
+
},
|
|
673
|
+
layout: {
|
|
674
|
+
type: 'string',
|
|
675
|
+
enum: ['force', 'radial', 'grid', 'dagre', 'circular'],
|
|
676
|
+
description: 'Layout algorithm (default: force)',
|
|
677
|
+
},
|
|
678
|
+
directed: { type: 'boolean', description: 'Render edges as directed (arrows)' },
|
|
679
|
+
},
|
|
680
|
+
required: ['nodes'],
|
|
681
|
+
},
|
|
682
|
+
examples: [
|
|
683
|
+
{
|
|
684
|
+
query: 'Show how this figure was derived',
|
|
685
|
+
component: {
|
|
686
|
+
id: 'example-graph-1',
|
|
687
|
+
type: 'graph',
|
|
688
|
+
position: { colStart: 1, colSpan: 12 },
|
|
689
|
+
params: {
|
|
690
|
+
directed: true,
|
|
691
|
+
layout: 'dagre',
|
|
692
|
+
nodes: [
|
|
693
|
+
{ id: 'claim', label: 'Population = 522 250', group: 'claim' },
|
|
694
|
+
{ id: 'source', label: 'INSEE 2021', group: 'source' },
|
|
695
|
+
],
|
|
696
|
+
edges: [{ source: 'claim', target: 'source', label: 'derived from' }],
|
|
697
|
+
},
|
|
698
|
+
},
|
|
699
|
+
},
|
|
700
|
+
],
|
|
701
|
+
limits: DEFAULT_RESOURCE_LIMITS,
|
|
702
|
+
}
|
|
703
|
+
|
|
635
704
|
/**
|
|
636
705
|
* Form Registry Entry
|
|
637
706
|
*/
|
|
@@ -990,6 +1059,8 @@ export const ComponentRegistry: Map<ComponentType, ComponentRegistryEntry> = new
|
|
|
990
1059
|
// v2.2.5: Complete registry
|
|
991
1060
|
['code', CodeRegistry],
|
|
992
1061
|
['map', MapRegistry],
|
|
1062
|
+
['graph', GraphRegistry], // v6.12.0: audit P1.5 — registry/schema parity
|
|
1063
|
+
|
|
993
1064
|
['form', FormRegistry],
|
|
994
1065
|
['modal', ModalRegistry],
|
|
995
1066
|
['action-group', ActionGroupRegistry],
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v6.13.0 — graph is now first-class in the `UIComponent` params union
|
|
3
|
+
* (audit follow-up to P1.4/P1.5).
|
|
4
|
+
*
|
|
5
|
+
* Compile-time: a `graph` component with `nodes`/`edges` params must be
|
|
6
|
+
* assignable to `UIComponent` (it was not before — the union ended at
|
|
7
|
+
* `MapComponentParams`). Runtime asserts keep the shape visible in reports.
|
|
8
|
+
*/
|
|
9
|
+
import { describe, it, expect } from 'vitest'
|
|
10
|
+
import type { UIComponent, GraphComponentParams, GraphNode, GraphEdge } from './index'
|
|
11
|
+
|
|
12
|
+
describe('GraphComponentParams in the UIComponent union (P1.4/P1.5 follow-up)', () => {
|
|
13
|
+
it('accepts a graph component with nodes/edges/layout/directed', () => {
|
|
14
|
+
const nodes: GraphNode[] = [
|
|
15
|
+
{ id: 'a', label: 'A', group: 'g1' },
|
|
16
|
+
{ id: 'b', label: 'B' },
|
|
17
|
+
]
|
|
18
|
+
const edges: GraphEdge[] = [{ source: 'a', target: 'b', label: 'rel', weight: 1 }]
|
|
19
|
+
const params: GraphComponentParams = { nodes, edges, layout: 'dagre', directed: true }
|
|
20
|
+
|
|
21
|
+
const component: UIComponent = {
|
|
22
|
+
id: 'g1',
|
|
23
|
+
type: 'graph',
|
|
24
|
+
position: { colStart: 1, colSpan: 12 },
|
|
25
|
+
params,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
expect(component.type).toBe('graph')
|
|
29
|
+
expect((component.params as GraphComponentParams).nodes).toHaveLength(2)
|
|
30
|
+
expect((component.params as GraphComponentParams).edges).toHaveLength(1)
|
|
31
|
+
expect((component.params as GraphComponentParams).layout).toBe('dagre')
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('requires nodes (edges optional) and tolerates passthrough props', () => {
|
|
35
|
+
const minimal: GraphComponentParams = { nodes: [{ id: 'only' }] }
|
|
36
|
+
expect(minimal.edges).toBeUndefined()
|
|
37
|
+
|
|
38
|
+
const extra: GraphComponentParams = { nodes: [{ id: 'x', custom: 42 }], theme: 'dark' }
|
|
39
|
+
expect((extra.nodes[0] as Record<string, unknown>).custom).toBe(42)
|
|
40
|
+
expect((extra as Record<string, unknown>).theme).toBe('dark')
|
|
41
|
+
})
|
|
42
|
+
})
|
package/src/types/index.ts
CHANGED
|
@@ -1021,6 +1021,63 @@ export interface MapPMTilesConfig {
|
|
|
1021
1021
|
minZoom?: number
|
|
1022
1022
|
}
|
|
1023
1023
|
|
|
1024
|
+
/**
|
|
1025
|
+
* Node-link graph params (v6.13.0 — audit follow-up to P1.4/P1.5).
|
|
1026
|
+
*
|
|
1027
|
+
* Mirrors `GraphComponentParamsSchema` in `@seed-ship/mcp-ui-spec`. The
|
|
1028
|
+
* `<GraphRenderer>` reads these loosely (and the spec schema accepts
|
|
1029
|
+
* passthrough node/edge props), so an index signature keeps the type
|
|
1030
|
+
* permissive — matching the runtime behaviour without over-constraining.
|
|
1031
|
+
*/
|
|
1032
|
+
export interface GraphNode {
|
|
1033
|
+
/** Stable node id — referenced by edges. */
|
|
1034
|
+
id: string
|
|
1035
|
+
label?: string
|
|
1036
|
+
/** Optional grouping/category key (drives default coloring). */
|
|
1037
|
+
group?: string
|
|
1038
|
+
/** Generic ranking/importance signal (opaque to the lib). */
|
|
1039
|
+
weight?: number
|
|
1040
|
+
/** Passthrough G6 node props (type, size, style, data, …). */
|
|
1041
|
+
[key: string]: unknown
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
export interface GraphEdge {
|
|
1045
|
+
/** Must match a `GraphNode.id`. */
|
|
1046
|
+
source: string
|
|
1047
|
+
/** Must match a `GraphNode.id`. */
|
|
1048
|
+
target: string
|
|
1049
|
+
label?: string
|
|
1050
|
+
weight?: number
|
|
1051
|
+
/** Passthrough G6 edge props (style, data, …). */
|
|
1052
|
+
[key: string]: unknown
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
export type GraphLayout = 'force' | 'radial' | 'grid' | 'dagre' | 'circular' | 'concentric'
|
|
1056
|
+
|
|
1057
|
+
/**
|
|
1058
|
+
* Generic node-link graph component params. Domain-neutral by design — the
|
|
1059
|
+
* meaning of `weight`/`group` is decided by the consumer.
|
|
1060
|
+
*/
|
|
1061
|
+
export interface GraphComponentParams {
|
|
1062
|
+
/** Nodes (at least one expected at runtime). */
|
|
1063
|
+
nodes: GraphNode[]
|
|
1064
|
+
edges?: GraphEdge[]
|
|
1065
|
+
layout?: GraphLayout
|
|
1066
|
+
/** Render edges as directed (arrows). */
|
|
1067
|
+
directed?: boolean
|
|
1068
|
+
/**
|
|
1069
|
+
* Rendering hint only — NOT wired; the renderer always uses the G6 canvas
|
|
1070
|
+
* default (cf. audit P0). Kept for forward-compat with the spec.
|
|
1071
|
+
*/
|
|
1072
|
+
rendererPref?: 'canvas' | 'svg'
|
|
1073
|
+
height?: number
|
|
1074
|
+
width?: number
|
|
1075
|
+
/** Custom CSS class. */
|
|
1076
|
+
className?: string
|
|
1077
|
+
/** Passthrough for forward-compat graph options. */
|
|
1078
|
+
[key: string]: unknown
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1024
1081
|
/**
|
|
1025
1082
|
* Grid component parameters (Phase 5.0)
|
|
1026
1083
|
* Enables nested CSS Grid layouts for template builder
|
|
@@ -1079,7 +1136,7 @@ export interface UIComponent {
|
|
|
1079
1136
|
/**
|
|
1080
1137
|
* Component parameters (type-specific)
|
|
1081
1138
|
*/
|
|
1082
|
-
params: ChartComponentParams | TableComponentParams | MetricComponentParams | TextComponentParams | ActionComponentParams | GridComponentParams | FormComponentParams | ModalComponentParams | ActionGroupParams | ImageGalleryParams | VideoComponentParams | CodeComponentParams | MapComponentParams
|
|
1139
|
+
params: ChartComponentParams | TableComponentParams | MetricComponentParams | TextComponentParams | ActionComponentParams | GridComponentParams | FormComponentParams | ModalComponentParams | ActionGroupParams | ImageGalleryParams | VideoComponentParams | CodeComponentParams | MapComponentParams | GraphComponentParams
|
|
1083
1140
|
|
|
1084
1141
|
/**
|
|
1085
1142
|
* Metadata for observability
|