@vertesia/fusion-ux 1.2.0 → 1.4.0-dev.20260614.160504Z
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/LICENSE +198 -10
- package/lib/fusion-fragment/ChartRenderer.d.ts.map +1 -0
- package/lib/{esm/fusion-fragment → fusion-fragment}/ChartRenderer.js +8 -6
- package/lib/fusion-fragment/ChartRenderer.js.map +1 -0
- package/lib/{types/fusion-fragment → fusion-fragment}/FieldRenderer.d.ts +1 -1
- package/lib/fusion-fragment/FieldRenderer.d.ts.map +1 -0
- package/lib/{esm/fusion-fragment → fusion-fragment}/FieldRenderer.js +14 -8
- package/lib/fusion-fragment/FieldRenderer.js.map +1 -0
- package/lib/{types/fusion-fragment → fusion-fragment}/FusionFragmentContext.d.ts +3 -3
- package/lib/fusion-fragment/FusionFragmentContext.d.ts.map +1 -0
- package/lib/{esm/fusion-fragment → fusion-fragment}/FusionFragmentContext.js +2 -2
- package/lib/fusion-fragment/FusionFragmentContext.js.map +1 -0
- package/lib/fusion-fragment/FusionFragmentHandler.d.ts.map +1 -0
- package/lib/{esm/fusion-fragment → fusion-fragment}/FusionFragmentHandler.js +7 -14
- package/lib/fusion-fragment/FusionFragmentHandler.js.map +1 -0
- package/lib/fusion-fragment/FusionFragmentRenderer.d.ts.map +1 -0
- package/lib/{esm/fusion-fragment → fusion-fragment}/FusionFragmentRenderer.js +2 -2
- package/lib/fusion-fragment/FusionFragmentRenderer.js.map +1 -0
- package/lib/{types/fusion-fragment → fusion-fragment}/SectionRenderer.d.ts +1 -1
- package/lib/fusion-fragment/SectionRenderer.d.ts.map +1 -0
- package/lib/{esm/fusion-fragment → fusion-fragment}/SectionRenderer.js +12 -5
- package/lib/fusion-fragment/SectionRenderer.js.map +1 -0
- package/lib/fusion-fragment/TableRenderer.d.ts.map +1 -0
- package/lib/{esm/fusion-fragment → fusion-fragment}/TableRenderer.js +9 -7
- package/lib/fusion-fragment/TableRenderer.js.map +1 -0
- package/lib/{types/fusion-fragment → fusion-fragment}/index.d.ts +4 -4
- package/lib/fusion-fragment/index.d.ts.map +1 -0
- package/lib/{esm/fusion-fragment → fusion-fragment}/index.js +4 -4
- package/lib/fusion-fragment/index.js.map +1 -0
- package/lib/{types/index.d.ts → index.d.ts} +4 -4
- package/lib/index.d.ts.map +1 -0
- package/lib/{esm/index.js → index.js} +4 -4
- package/lib/index.js.map +1 -0
- package/lib/{types/render → render}/index.d.ts +1 -1
- package/lib/render/index.d.ts.map +1 -0
- package/lib/{esm/render → render}/index.js +1 -1
- package/lib/render/index.js.map +1 -0
- package/lib/render/textPreview.d.ts.map +1 -0
- package/lib/{esm/render → render}/textPreview.js +12 -9
- package/lib/render/textPreview.js.map +1 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js.map +1 -0
- package/lib/validation/formatErrors.d.ts.map +1 -0
- package/lib/{esm/validation → validation}/formatErrors.js +1 -1
- package/lib/validation/formatErrors.js.map +1 -0
- package/lib/validation/fuzzyMatch.d.ts.map +1 -0
- package/lib/{esm/validation → validation}/fuzzyMatch.js +3 -4
- package/lib/validation/fuzzyMatch.js.map +1 -0
- package/lib/validation/index.d.ts +8 -0
- package/lib/validation/index.d.ts.map +1 -0
- package/lib/validation/index.js +8 -0
- package/lib/validation/index.js.map +1 -0
- package/lib/{types/validation → validation}/schemas.d.ts +1 -1
- package/lib/validation/schemas.d.ts.map +1 -0
- package/lib/{esm/validation → validation}/schemas.js +25 -25
- package/lib/validation/schemas.js.map +1 -0
- package/lib/validation/validateTemplate.d.ts.map +1 -0
- package/lib/{esm/validation → validation}/validateTemplate.js +23 -21
- package/lib/validation/validateTemplate.js.map +1 -0
- package/lib/vertesia-fusion-ux.js +1 -1
- package/lib/vertesia-fusion-ux.js.map +1 -1
- package/package.json +23 -35
- package/src/fusion-fragment/ChartRenderer.tsx +95 -96
- package/src/fusion-fragment/FieldRenderer.tsx +173 -174
- package/src/fusion-fragment/FusionFragmentContext.tsx +31 -37
- package/src/fusion-fragment/FusionFragmentHandler.tsx +214 -223
- package/src/fusion-fragment/FusionFragmentRenderer.tsx +102 -107
- package/src/fusion-fragment/SectionRenderer.tsx +174 -169
- package/src/fusion-fragment/TableRenderer.tsx +175 -171
- package/src/fusion-fragment/index.ts +11 -11
- package/src/index.ts +42 -45
- package/src/render/index.ts +3 -3
- package/src/render/textPreview.ts +183 -186
- package/src/types.ts +174 -174
- package/src/validation/formatErrors.ts +86 -86
- package/src/validation/fuzzyMatch.ts +69 -77
- package/src/validation/index.ts +3 -3
- package/src/validation/schemas.ts +120 -120
- package/src/validation/validateTemplate.ts +225 -226
- package/lib/esm/fusion-fragment/ChartRenderer.js.map +0 -1
- package/lib/esm/fusion-fragment/FieldRenderer.js.map +0 -1
- package/lib/esm/fusion-fragment/FusionFragmentContext.js.map +0 -1
- package/lib/esm/fusion-fragment/FusionFragmentHandler.js.map +0 -1
- package/lib/esm/fusion-fragment/FusionFragmentRenderer.js.map +0 -1
- package/lib/esm/fusion-fragment/SectionRenderer.js.map +0 -1
- package/lib/esm/fusion-fragment/TableRenderer.js.map +0 -1
- package/lib/esm/fusion-fragment/index.js.map +0 -1
- package/lib/esm/index.js.map +0 -1
- package/lib/esm/render/index.js.map +0 -1
- package/lib/esm/render/textPreview.js.map +0 -1
- package/lib/esm/types.js.map +0 -1
- package/lib/esm/validation/formatErrors.js.map +0 -1
- package/lib/esm/validation/fuzzyMatch.js.map +0 -1
- package/lib/esm/validation/index.js +0 -8
- package/lib/esm/validation/index.js.map +0 -1
- package/lib/esm/validation/schemas.js.map +0 -1
- package/lib/esm/validation/validateTemplate.js.map +0 -1
- package/lib/tsconfig.tsbuildinfo +0 -1
- package/lib/types/fusion-fragment/ChartRenderer.d.ts.map +0 -1
- package/lib/types/fusion-fragment/FieldRenderer.d.ts.map +0 -1
- package/lib/types/fusion-fragment/FusionFragmentContext.d.ts.map +0 -1
- package/lib/types/fusion-fragment/FusionFragmentHandler.d.ts.map +0 -1
- package/lib/types/fusion-fragment/FusionFragmentRenderer.d.ts.map +0 -1
- package/lib/types/fusion-fragment/SectionRenderer.d.ts.map +0 -1
- package/lib/types/fusion-fragment/TableRenderer.d.ts.map +0 -1
- package/lib/types/fusion-fragment/index.d.ts.map +0 -1
- package/lib/types/index.d.ts.map +0 -1
- package/lib/types/render/index.d.ts.map +0 -1
- package/lib/types/render/textPreview.d.ts.map +0 -1
- package/lib/types/types.d.ts.map +0 -1
- package/lib/types/validation/formatErrors.d.ts.map +0 -1
- package/lib/types/validation/fuzzyMatch.d.ts.map +0 -1
- package/lib/types/validation/index.d.ts +0 -8
- package/lib/types/validation/index.d.ts.map +0 -1
- package/lib/types/validation/schemas.d.ts.map +0 -1
- package/lib/types/validation/validateTemplate.d.ts.map +0 -1
- /package/lib/{types/fusion-fragment → fusion-fragment}/ChartRenderer.d.ts +0 -0
- /package/lib/{types/fusion-fragment → fusion-fragment}/FusionFragmentHandler.d.ts +0 -0
- /package/lib/{types/fusion-fragment → fusion-fragment}/FusionFragmentRenderer.d.ts +0 -0
- /package/lib/{types/fusion-fragment → fusion-fragment}/TableRenderer.d.ts +0 -0
- /package/lib/{types/render → render}/textPreview.d.ts +0 -0
- /package/lib/{types/types.d.ts → types.d.ts} +0 -0
- /package/lib/{esm/types.js → types.js} +0 -0
- /package/lib/{types/validation → validation}/formatErrors.d.ts +0 -0
- /package/lib/{types/validation → validation}/fuzzyMatch.d.ts +0 -0
- /package/lib/{types/validation → validation}/validateTemplate.d.ts +0 -0
package/src/types.ts
CHANGED
|
@@ -13,74 +13,74 @@ import type React from 'react';
|
|
|
13
13
|
* Root template structure for a fusion fragment
|
|
14
14
|
*/
|
|
15
15
|
export interface FragmentTemplate {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
/** Optional title displayed at the top */
|
|
17
|
+
title?: string;
|
|
18
|
+
/** Type of entity being displayed - helps with context */
|
|
19
|
+
entityType?: 'fund' | 'scenario' | 'portfolio' | 'transaction' | 'custom';
|
|
20
|
+
/** Sections containing fields */
|
|
21
|
+
sections: SectionTemplate[];
|
|
22
|
+
/** Optional footer text */
|
|
23
|
+
footer?: string;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* A section within the fragment, containing related fields, a table, or a chart
|
|
28
28
|
*/
|
|
29
29
|
export interface SectionTemplate {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
30
|
+
/** Section title/header */
|
|
31
|
+
title: string;
|
|
32
|
+
/** Layout mode for the fields */
|
|
33
|
+
layout?: 'grid-2' | 'grid-3' | 'grid-4' | 'list' | 'table' | 'chart';
|
|
34
|
+
/** Whether the section is initially collapsed */
|
|
35
|
+
collapsed?: boolean;
|
|
36
|
+
/** Fields in this section (for grid/list layouts) */
|
|
37
|
+
fields?: FieldTemplate[];
|
|
38
|
+
/** Table columns (for table layout) */
|
|
39
|
+
columns?: ColumnTemplate[];
|
|
40
|
+
/** Data key for table rows - points to an array in data */
|
|
41
|
+
dataKey?: string;
|
|
42
|
+
/** Chart specification (for chart layout) */
|
|
43
|
+
chart?: ChartTemplate;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
47
|
* A column definition for table layout
|
|
48
48
|
*/
|
|
49
49
|
export interface ColumnTemplate {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
50
|
+
/** Column header text */
|
|
51
|
+
header: string;
|
|
52
|
+
/** Key to look up in each row object */
|
|
53
|
+
key: string;
|
|
54
|
+
/** Display format */
|
|
55
|
+
format?: 'text' | 'number' | 'currency' | 'percent' | 'date' | 'boolean';
|
|
56
|
+
/** Column width (optional, e.g., '100px', '20%') */
|
|
57
|
+
width?: string;
|
|
58
|
+
/** Text alignment */
|
|
59
|
+
align?: 'left' | 'center' | 'right';
|
|
60
|
+
/** Currency code for currency format */
|
|
61
|
+
currency?: string;
|
|
62
|
+
/** Number of decimal places */
|
|
63
|
+
decimals?: number;
|
|
64
|
+
/** Highlight based on value (function key in data or static) */
|
|
65
|
+
highlight?: 'success' | 'warning' | 'error' | 'info';
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
69
|
* Chart specification for chart layout (Vega-Lite based)
|
|
70
70
|
*/
|
|
71
71
|
export interface ChartTemplate {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
72
|
+
/** Chart title (displayed above the chart) */
|
|
73
|
+
title?: string;
|
|
74
|
+
/** Chart description */
|
|
75
|
+
description?: string;
|
|
76
|
+
/** Vega-Lite specification */
|
|
77
|
+
spec: VegaLiteSpec;
|
|
78
|
+
/** Chart height in pixels */
|
|
79
|
+
height?: number;
|
|
80
|
+
/** Chart width in pixels (defaults to container width) */
|
|
81
|
+
width?: number;
|
|
82
|
+
/** Data key - if provided, data from this key replaces spec.data.values */
|
|
83
|
+
dataKey?: string;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
/**
|
|
@@ -88,67 +88,67 @@ export interface ChartTemplate {
|
|
|
88
88
|
* Full spec: https://vega.github.io/vega-lite/docs/spec.html
|
|
89
89
|
*/
|
|
90
90
|
export interface VegaLiteSpec {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
91
|
+
/** Schema URL (optional) */
|
|
92
|
+
$schema?: string;
|
|
93
|
+
/** Inline data or data source */
|
|
94
|
+
data?: {
|
|
95
|
+
/** Inline data values */
|
|
96
|
+
values?: Record<string, unknown>[];
|
|
97
|
+
/** URL to fetch data from */
|
|
98
|
+
url?: string;
|
|
99
|
+
/** Data format */
|
|
100
|
+
format?: { type?: 'json' | 'csv' | 'tsv' };
|
|
101
|
+
};
|
|
102
|
+
/** Mark type (bar, line, point, area, etc.) */
|
|
103
|
+
mark?: string | { type: string; [key: string]: unknown };
|
|
104
|
+
/** Encoding channels (x, y, color, size, etc.) */
|
|
105
|
+
encoding?: Record<string, unknown>;
|
|
106
|
+
/** Vertical concatenation */
|
|
107
|
+
vconcat?: VegaLiteSpec[];
|
|
108
|
+
/** Horizontal concatenation */
|
|
109
|
+
hconcat?: VegaLiteSpec[];
|
|
110
|
+
/** Layer multiple marks */
|
|
111
|
+
layer?: VegaLiteSpec[];
|
|
112
|
+
/** Transform operations */
|
|
113
|
+
transform?: Record<string, unknown>[];
|
|
114
|
+
/** Interactive parameters */
|
|
115
|
+
params?: Record<string, unknown>[];
|
|
116
|
+
/** Chart configuration */
|
|
117
|
+
config?: Record<string, unknown>;
|
|
118
|
+
/** Allow additional Vega-Lite properties */
|
|
119
|
+
[key: string]: unknown;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
/**
|
|
123
123
|
* A single field definition
|
|
124
124
|
*/
|
|
125
125
|
export interface FieldTemplate {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
126
|
+
/** Display label for the field */
|
|
127
|
+
label: string;
|
|
128
|
+
/** Key to look up in data - REQUIRED */
|
|
129
|
+
key: string;
|
|
130
|
+
/** Display format */
|
|
131
|
+
format?: 'text' | 'number' | 'currency' | 'percent' | 'date' | 'boolean';
|
|
132
|
+
/** Unit to display after value (e.g., "years", "USD") */
|
|
133
|
+
unit?: string;
|
|
134
|
+
/** Whether this field is editable */
|
|
135
|
+
editable?: boolean;
|
|
136
|
+
/** Input type when editing */
|
|
137
|
+
inputType?: 'text' | 'number' | 'date' | 'select' | 'checkbox';
|
|
138
|
+
/** Options for select input type */
|
|
139
|
+
options?: Array<{ label: string; value: string }>;
|
|
140
|
+
/** Min value for number inputs */
|
|
141
|
+
min?: number;
|
|
142
|
+
/** Max value for number inputs */
|
|
143
|
+
max?: number;
|
|
144
|
+
/** Visual highlight style */
|
|
145
|
+
highlight?: 'success' | 'warning' | 'error' | 'info';
|
|
146
|
+
/** Tooltip text on hover */
|
|
147
|
+
tooltip?: string;
|
|
148
|
+
/** Number of decimal places for number format */
|
|
149
|
+
decimals?: number;
|
|
150
|
+
/** Currency code for currency format */
|
|
151
|
+
currency?: string;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
// ============ Validation Types ============
|
|
@@ -157,22 +157,22 @@ export interface FieldTemplate {
|
|
|
157
157
|
* Result of template validation
|
|
158
158
|
*/
|
|
159
159
|
export interface ValidationResult {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
160
|
+
/** Whether the template is valid */
|
|
161
|
+
valid: boolean;
|
|
162
|
+
/** List of validation errors */
|
|
163
|
+
errors: ValidationError[];
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
/**
|
|
167
167
|
* A single validation error with path and suggestion
|
|
168
168
|
*/
|
|
169
169
|
export interface ValidationError {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
170
|
+
/** JSON path to the error (e.g., "sections[0].fields[2].key") */
|
|
171
|
+
path: string;
|
|
172
|
+
/** Human-readable error message */
|
|
173
|
+
message: string;
|
|
174
|
+
/** Suggested fix (for model feedback) */
|
|
175
|
+
suggestion?: string;
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
// ============ Component Props ============
|
|
@@ -181,48 +181,48 @@ export interface ValidationError {
|
|
|
181
181
|
* Props for the main FusionFragmentRenderer component
|
|
182
182
|
*/
|
|
183
183
|
export interface FusionFragmentRendererProps {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
184
|
+
/** The template structure (from model) */
|
|
185
|
+
template: FragmentTemplate;
|
|
186
|
+
/** Actual data values to display */
|
|
187
|
+
data: Record<string, unknown>;
|
|
188
|
+
/** Callback for field updates (direct mode) */
|
|
189
|
+
onUpdate?: (key: string, value: unknown) => Promise<void>;
|
|
190
|
+
/** Agent mode configuration */
|
|
191
|
+
agentMode?: {
|
|
192
|
+
enabled: true;
|
|
193
|
+
/** Send message to conversation */
|
|
194
|
+
sendMessage: (message: string) => void;
|
|
195
|
+
};
|
|
196
|
+
/** CSS class name */
|
|
197
|
+
className?: string;
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
/**
|
|
201
201
|
* Props for section renderer
|
|
202
202
|
*/
|
|
203
203
|
export interface SectionRendererProps {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
204
|
+
/** Section template */
|
|
205
|
+
section: SectionTemplate;
|
|
206
|
+
/** Data for fields */
|
|
207
|
+
data: Record<string, unknown>;
|
|
208
|
+
/** Update callback */
|
|
209
|
+
onUpdate?: (key: string, value: unknown) => Promise<void>;
|
|
210
|
+
/** Agent mode */
|
|
211
|
+
agentMode?: FusionFragmentRendererProps['agentMode'];
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
/**
|
|
215
215
|
* Props for field renderer
|
|
216
216
|
*/
|
|
217
217
|
export interface FieldRendererProps {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
218
|
+
/** Field template */
|
|
219
|
+
field: FieldTemplate;
|
|
220
|
+
/** Field value from data */
|
|
221
|
+
value: unknown;
|
|
222
|
+
/** Update callback */
|
|
223
|
+
onUpdate?: (value: unknown) => Promise<void>;
|
|
224
|
+
/** Agent mode */
|
|
225
|
+
agentMode?: FusionFragmentRendererProps['agentMode'];
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
// ============ Context Types ============
|
|
@@ -231,34 +231,34 @@ export interface FieldRendererProps {
|
|
|
231
231
|
* Props for the injected chart component (matches @vertesia/ui VegaLiteChart)
|
|
232
232
|
*/
|
|
233
233
|
export interface ChartComponentProps {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
234
|
+
/** The chart specification in VegaLiteChartSpec format */
|
|
235
|
+
spec: {
|
|
236
|
+
library: 'vega-lite';
|
|
237
|
+
title?: string;
|
|
238
|
+
description?: string;
|
|
239
|
+
spec: Record<string, unknown>;
|
|
240
|
+
options?: {
|
|
241
|
+
height?: number;
|
|
242
|
+
};
|
|
242
243
|
};
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
artifactRunId?: string;
|
|
244
|
+
/** Optional artifact run ID for resolving artifact: URLs */
|
|
245
|
+
artifactRunId?: string;
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
/**
|
|
249
249
|
* Context value for FusionFragment components
|
|
250
250
|
*/
|
|
251
251
|
export interface FusionFragmentContextValue {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
252
|
+
/** Data to display */
|
|
253
|
+
data: Record<string, unknown>;
|
|
254
|
+
/** Update callback */
|
|
255
|
+
onUpdate?: (key: string, value: unknown) => Promise<void>;
|
|
256
|
+
/** Send message to agent */
|
|
257
|
+
sendMessage?: (message: string) => void;
|
|
258
|
+
/** Optional chart component to render Vega-Lite charts (injected to avoid circular deps) */
|
|
259
|
+
ChartComponent?: React.ComponentType<ChartComponentProps>;
|
|
260
|
+
/** Optional artifact run ID for resolving artifact references */
|
|
261
|
+
artifactRunId?: string;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
// ============ Tool Types ============
|
|
@@ -267,12 +267,12 @@ export interface FusionFragmentContextValue {
|
|
|
267
267
|
* Input for validate_fusion_fragment tool
|
|
268
268
|
*/
|
|
269
269
|
export interface ValidateFusionFragmentInput {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
270
|
+
/** The template to validate */
|
|
271
|
+
template: FragmentTemplate;
|
|
272
|
+
/** Available data keys */
|
|
273
|
+
dataKeys: string[];
|
|
274
|
+
/** Optional sample data for preview rendering */
|
|
275
|
+
sampleData?: Record<string, unknown>;
|
|
276
|
+
/** Preview mode */
|
|
277
|
+
preview?: 'image' | 'text' | 'none';
|
|
278
278
|
}
|
|
@@ -10,22 +10,22 @@ import type { ValidationError } from '../types.js';
|
|
|
10
10
|
* @returns Formatted error message
|
|
11
11
|
*/
|
|
12
12
|
export function formatValidationErrors(errors: ValidationError[]): string {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
if (errors.length === 0) {
|
|
14
|
+
return 'Template is valid.';
|
|
15
|
+
}
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
const header = `Template validation failed with ${errors.length} error${errors.length > 1 ? 's' : ''}:\n`;
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
const formattedErrors = errors.map((error, index) => {
|
|
20
|
+
let message = `${index + 1}. ${error.message}`;
|
|
21
|
+
message += `\n Path: ${error.path}`;
|
|
22
|
+
if (error.suggestion) {
|
|
23
|
+
message += `\n \u2192 ${error.suggestion}`;
|
|
24
|
+
}
|
|
25
|
+
return message;
|
|
26
|
+
});
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
return `${header}\n${formattedErrors.join('\n\n')}`;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
@@ -35,39 +35,42 @@ export function formatValidationErrors(errors: ValidationError[]): string {
|
|
|
35
35
|
* @returns Success message with preview
|
|
36
36
|
*/
|
|
37
37
|
export function formatValidationSuccess(
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
template: {
|
|
39
|
+
title?: string;
|
|
40
|
+
sections: Array<{ title: string; fields: Array<{ label: string; key: string; format?: string }> }>;
|
|
41
|
+
},
|
|
42
|
+
dataKeys: string[],
|
|
40
43
|
): string {
|
|
41
|
-
|
|
42
|
-
lines.push('');
|
|
43
|
-
|
|
44
|
-
if (template.title) {
|
|
45
|
-
lines.push(`**${template.title}**`);
|
|
44
|
+
const lines: string[] = ['Template valid. Preview:'];
|
|
46
45
|
lines.push('');
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
for (const section of template.sections) {
|
|
50
|
-
const fieldCount = section.fields.length;
|
|
51
|
-
lines.push(`[${section.title}] ${fieldCount} field${fieldCount > 1 ? 's' : ''}:`);
|
|
52
46
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
fieldDesc += ')';
|
|
59
|
-
|
|
60
|
-
// Check if key exists in data
|
|
61
|
-
if (!dataKeys.includes(field.key)) {
|
|
62
|
-
fieldDesc += ' \u26a0\ufe0f key not in data';
|
|
63
|
-
}
|
|
47
|
+
if (template.title) {
|
|
48
|
+
lines.push(`**${template.title}**`);
|
|
49
|
+
lines.push('');
|
|
50
|
+
}
|
|
64
51
|
|
|
65
|
-
|
|
52
|
+
for (const section of template.sections) {
|
|
53
|
+
const fieldCount = section.fields.length;
|
|
54
|
+
lines.push(`[${section.title}] ${fieldCount} field${fieldCount > 1 ? 's' : ''}:`);
|
|
55
|
+
|
|
56
|
+
for (const field of section.fields) {
|
|
57
|
+
let fieldDesc = `- ${field.label} (${field.key}`;
|
|
58
|
+
if (field.format && field.format !== 'text') {
|
|
59
|
+
fieldDesc += `, ${field.format}`;
|
|
60
|
+
}
|
|
61
|
+
fieldDesc += ')';
|
|
62
|
+
|
|
63
|
+
// Check if key exists in data
|
|
64
|
+
if (!dataKeys.includes(field.key)) {
|
|
65
|
+
fieldDesc += ' \u26a0\ufe0f key not in data';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
lines.push(fieldDesc);
|
|
69
|
+
}
|
|
70
|
+
lines.push('');
|
|
66
71
|
}
|
|
67
|
-
lines.push('');
|
|
68
|
-
}
|
|
69
72
|
|
|
70
|
-
|
|
73
|
+
return lines.join('\n');
|
|
71
74
|
}
|
|
72
75
|
|
|
73
76
|
/**
|
|
@@ -76,53 +79,50 @@ export function formatValidationSuccess(
|
|
|
76
79
|
* @param groupByPrefix - Whether to group keys by common prefix
|
|
77
80
|
* @returns Formatted key list
|
|
78
81
|
*/
|
|
79
|
-
export function formatAvailableKeys(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
): string {
|
|
83
|
-
if (dataKeys.length === 0) {
|
|
84
|
-
return 'No data keys available.';
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (!groupByPrefix || dataKeys.length <= 10) {
|
|
88
|
-
return `Available keys: ${dataKeys.join(', ')}`;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Group by prefix (e.g., fund.name, fund.type -> fund.*)
|
|
92
|
-
const groups = new Map<string, string[]>();
|
|
93
|
-
|
|
94
|
-
for (const key of dataKeys) {
|
|
95
|
-
const dotIndex = key.indexOf('.');
|
|
96
|
-
if (dotIndex > 0) {
|
|
97
|
-
const prefix = key.substring(0, dotIndex);
|
|
98
|
-
const rest = key.substring(dotIndex + 1);
|
|
99
|
-
const group = groups.get(prefix) || [];
|
|
100
|
-
group.push(rest);
|
|
101
|
-
groups.set(prefix, group);
|
|
102
|
-
} else {
|
|
103
|
-
const group = groups.get('') || [];
|
|
104
|
-
group.push(key);
|
|
105
|
-
groups.set('', group);
|
|
82
|
+
export function formatAvailableKeys(dataKeys: string[], groupByPrefix: boolean = true): string {
|
|
83
|
+
if (dataKeys.length === 0) {
|
|
84
|
+
return 'No data keys available.';
|
|
106
85
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
86
|
+
|
|
87
|
+
if (!groupByPrefix || dataKeys.length <= 10) {
|
|
88
|
+
return `Available keys: ${dataKeys.join(', ')}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Group by prefix (e.g., fund.name, fund.type -> fund.*)
|
|
92
|
+
const groups = new Map<string, string[]>();
|
|
93
|
+
|
|
94
|
+
for (const key of dataKeys) {
|
|
95
|
+
const dotIndex = key.indexOf('.');
|
|
96
|
+
if (dotIndex > 0) {
|
|
97
|
+
const prefix = key.substring(0, dotIndex);
|
|
98
|
+
const rest = key.substring(dotIndex + 1);
|
|
99
|
+
const group = groups.get(prefix) || [];
|
|
100
|
+
group.push(rest);
|
|
101
|
+
groups.set(prefix, group);
|
|
102
|
+
} else {
|
|
103
|
+
const group = groups.get('') || [];
|
|
104
|
+
group.push(key);
|
|
105
|
+
groups.set('', group);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const lines: string[] = ['Available keys:'];
|
|
110
|
+
|
|
111
|
+
// Top-level keys first
|
|
112
|
+
const topLevel = groups.get('');
|
|
113
|
+
if (topLevel && topLevel.length > 0) {
|
|
114
|
+
lines.push(` ${topLevel.join(', ')}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Grouped keys
|
|
118
|
+
for (const [prefix, keys] of groups) {
|
|
119
|
+
if (prefix === '') continue;
|
|
120
|
+
if (keys.length <= 3) {
|
|
121
|
+
lines.push(` ${prefix}: ${keys.join(', ')}`);
|
|
122
|
+
} else {
|
|
123
|
+
lines.push(` ${prefix}: ${keys.slice(0, 3).join(', ')}, ... (${keys.length} total)`);
|
|
124
|
+
}
|
|
124
125
|
}
|
|
125
|
-
}
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
return lines.join('\n');
|
|
128
128
|
}
|