@xpert-ai/plugin-live-dashboard 0.4.0 → 0.5.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/.xpertai-plugin/plugin.json +1 -1
- package/README.md +4 -0
- package/dist/lib/agent.schema.d.ts +179 -25
- package/dist/lib/agent.schema.js +10 -9
- package/dist/lib/archive.service.d.ts +145 -0
- package/dist/lib/archive.service.js +133 -0
- package/dist/lib/content.provider.d.ts +1 -1
- package/dist/lib/dashboard-archive.d.ts +70 -0
- package/dist/lib/dashboard-archive.js +118 -0
- package/dist/lib/dashboard-sources.d.ts +69 -0
- package/dist/lib/dashboard-sources.js +37 -0
- package/dist/lib/dashboard-view.schema.d.ts +503 -88
- package/dist/lib/dashboard-view.schema.js +2 -1
- package/dist/lib/dashboard.schema.d.ts +379 -58
- package/dist/lib/dashboard.schema.js +18 -1
- package/dist/lib/dashboard.service.d.ts +72 -17
- package/dist/lib/dashboard.service.js +21 -3
- package/dist/lib/document-package.d.ts +19 -4
- package/dist/lib/editing-patch.d.ts +3 -0
- package/dist/lib/editing-patch.js +2 -1
- package/dist/lib/editing-session.d.ts +4 -4
- package/dist/lib/editing.d.ts +202 -19
- package/dist/lib/editing.js +5 -2
- package/dist/lib/html-validation-feedback.d.ts +7 -0
- package/dist/lib/html-validation-feedback.js +19 -0
- package/dist/lib/html-validation.js +2 -1
- package/dist/lib/inspection-host.d.ts +7 -0
- package/dist/lib/inspection-host.js +48 -0
- package/dist/lib/inspection-runtime.d.ts +2 -0
- package/dist/lib/inspection-runtime.js +77 -0
- package/dist/lib/json-input.d.ts +4 -0
- package/dist/lib/json-input.js +21 -0
- package/dist/lib/middleware.js +3 -2
- package/dist/lib/plugin.js +2 -1
- package/dist/lib/presentation.provider.d.ts +24 -9
- package/dist/lib/presentation.provider.js +2 -1
- package/dist/lib/projects.schema.d.ts +14 -0
- package/dist/lib/projects.schema.js +2 -1
- package/dist/lib/projects.service.d.ts +2 -0
- package/dist/lib/projects.service.js +10 -0
- package/dist/lib/source-executions.d.ts +196 -0
- package/dist/lib/source-executions.js +25 -0
- package/dist/lib/source-validation.d.ts +2 -0
- package/dist/lib/source-validation.js +21 -0
- package/dist/lib/view.provider.d.ts +211 -12
- package/dist/lib/view.provider.js +43 -9
- package/dist/remote/app.css +1 -1
- package/dist/remote/app.js +99 -26
- package/dist/remote/build-manifest.json +42 -27
- package/docs/docs.json +3 -1
- package/docs/sources-inspect-portability-acceptance.mdx +67 -0
- package/docs/sources-inspect-portability.mdx +115 -0
- package/package.json +6 -5
- package/skills/live-dashboard/SKILL.md +5 -4
- package/skills/live-dashboard/references/source-inspection.md +17 -0
|
@@ -4,10 +4,13 @@ exports.queryBindingSchema = exports.querySchema = exports.saveSchema = exports.
|
|
|
4
4
|
const v3_1 = require("zod/v3");
|
|
5
5
|
const analytics_1 = require("@xpert-ai/plugin-sdk/analytics");
|
|
6
6
|
const artifact_document_1 = require("@xpert-ai/plugin-sdk/artifact-document");
|
|
7
|
+
const dashboard_sources_1 = require("./dashboard-sources");
|
|
7
8
|
const id = v3_1.z.string().regex(/^[A-Za-z][A-Za-z0-9_.-]{0,79}$/);
|
|
8
9
|
exports.dashboardSchema = v3_1.z.object({
|
|
9
10
|
schema: v3_1.z.literal('xpert.live-dashboard'), id: v3_1.z.string().uuid(), title: v3_1.z.string().min(1).max(160),
|
|
10
11
|
bindings: v3_1.z.array(analytics_1.analyticsBindingSchema).max(8),
|
|
12
|
+
sourceMetadata: dashboard_sources_1.sourceMetadataSchema.optional(),
|
|
13
|
+
components: dashboard_sources_1.dashboardComponentsSchema.optional(),
|
|
11
14
|
presentation: v3_1.z.object({ type: v3_1.z.literal('html'), html: artifact_document_1.artifactDocumentHtml, dependencies: artifact_document_1.artifactDocumentDependencyLocks.optional() }).strict().optional(),
|
|
12
15
|
controls: v3_1.z.array(v3_1.z.object({ controlId: id, type: v3_1.z.enum(['string', 'number', 'boolean', 'date']),
|
|
13
16
|
defaultValue: v3_1.z.union([v3_1.z.string(), v3_1.z.number(), v3_1.z.boolean(), v3_1.z.null()]).optional(),
|
|
@@ -25,6 +28,20 @@ exports.dashboardSchema = v3_1.z.object({
|
|
|
25
28
|
ctx.addIssue({ code: 'custom', message: 'An unconfigured draft must contain no views or controls' });
|
|
26
29
|
unique(manifest.bindings.map((binding) => binding.id), 'binding');
|
|
27
30
|
unique(manifest.bindings.map((binding) => binding.output.datasetId), 'dataset');
|
|
31
|
+
unique((manifest.sourceMetadata ?? []).map(item => item.bindingId), 'source metadata');
|
|
32
|
+
unique((manifest.components ?? []).map(item => item.id), 'component');
|
|
33
|
+
unique((manifest.components ?? []).map(item => item.elementId), 'component element');
|
|
34
|
+
for (const metadata of manifest.sourceMetadata ?? [])
|
|
35
|
+
if (!manifest.bindings.some(binding => binding.id === metadata.bindingId))
|
|
36
|
+
ctx.addIssue({ code: 'custom', message: 'Source metadata references an undeclared Binding' });
|
|
37
|
+
for (const component of manifest.components ?? []) {
|
|
38
|
+
unique(component.sources.map(source => source.bindingId), 'component source');
|
|
39
|
+
for (const source of component.sources) {
|
|
40
|
+
const binding = manifest.bindings.find(item => item.id === source.bindingId);
|
|
41
|
+
if (!binding || source.fieldIds?.some(field => !binding.output.fields.some(item => item.id === field)))
|
|
42
|
+
ctx.addIssue({ code: 'custom', message: 'Component references an undeclared Binding or field' });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
28
45
|
unique(manifest.controls.map((control) => control.controlId), 'control');
|
|
29
46
|
unique([...manifest.charts, ...manifest.tables].map((view) => view.id), 'view');
|
|
30
47
|
if (manifest.bindings.length && !manifest.presentation && !manifest.charts.length && !manifest.tables.length)
|
|
@@ -68,7 +85,7 @@ exports.dashboardSchema = v3_1.z.object({
|
|
|
68
85
|
});
|
|
69
86
|
/** Updates never choose identity or source scope; those come from the authorized saved version. */
|
|
70
87
|
exports.dashboardChangesSchema = exports.dashboardSchema.innerType().pick({ title: true, bindings: true,
|
|
71
|
-
controls: true, charts: true, tables: true, presentation: true }).partial().strict();
|
|
88
|
+
controls: true, charts: true, tables: true, presentation: true, sourceMetadata: true, components: true }).partial().strict();
|
|
72
89
|
exports.controlsSchema = v3_1.z.record(v3_1.z.union([v3_1.z.string().max(4000), v3_1.z.number().finite(), v3_1.z.boolean(), v3_1.z.null()]));
|
|
73
90
|
exports.saveSchema = v3_1.z.object({ manifest: exports.dashboardSchema, expectedVersionId: v3_1.z.string().uuid().nullable(), expectedRevision: v3_1.z.number().int().nonnegative().default(0) }).strict();
|
|
74
91
|
exports.querySchema = v3_1.z.object({ artifactId: v3_1.z.string().uuid(), versionId: v3_1.z.string().uuid().optional(), draftRevision: v3_1.z.number().int().positive().optional(), controls: exports.controlsSchema.default({}) }).strict();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AnalyticsValue, AnalyticsDiscoveryRequest, AnalyticsQueryRequest, XpertResolvedViewHostContext } from '@xpert-ai/contracts';
|
|
2
2
|
import { type RuntimeCapabilityRegistry } from '@xpert-ai/plugin-sdk';
|
|
3
3
|
import { type DashboardManifest, type DashboardChanges } from './dashboard.schema';
|
|
4
|
+
import { type ArtifactDocumentDependencyAsset } from '@xpert-ai/plugin-sdk/artifact-document';
|
|
4
5
|
import { HtmlDashboardValidation } from './html-validation';
|
|
5
6
|
import type { DashboardAccess, DashboardMode } from './project';
|
|
6
7
|
export declare const PLUGIN_NAME = "@xpert-ai/plugin-live-dashboard";
|
|
@@ -14,11 +15,11 @@ export declare class DashboardService {
|
|
|
14
15
|
list(context: XpertResolvedViewHostContext): Promise<{
|
|
15
16
|
title: string | null | undefined;
|
|
16
17
|
draftRevision?: number | undefined;
|
|
18
|
+
updatedAt: string | Date | undefined;
|
|
17
19
|
canDelete: boolean;
|
|
18
20
|
artifactId: string;
|
|
19
21
|
versionId: string | null | undefined;
|
|
20
22
|
versionNumber: number | undefined;
|
|
21
|
-
updatedAt: string | Date | undefined;
|
|
22
23
|
}[]>;
|
|
23
24
|
access(context: XpertResolvedViewHostContext): Promise<DashboardAccess>;
|
|
24
25
|
listPage(context: XpertResolvedViewHostContext, page?: number, pageSize?: number): Promise<{
|
|
@@ -28,11 +29,11 @@ export declare class DashboardService {
|
|
|
28
29
|
items: {
|
|
29
30
|
title: string | null | undefined;
|
|
30
31
|
draftRevision?: number | undefined;
|
|
32
|
+
updatedAt: string | Date | undefined;
|
|
31
33
|
canDelete: boolean;
|
|
32
34
|
artifactId: string;
|
|
33
35
|
versionId: string | null | undefined;
|
|
34
36
|
versionNumber: number | undefined;
|
|
35
|
-
updatedAt: string | Date | undefined;
|
|
36
37
|
}[];
|
|
37
38
|
}>;
|
|
38
39
|
searchPage(context: XpertResolvedViewHostContext, input: {
|
|
@@ -42,19 +43,28 @@ export declare class DashboardService {
|
|
|
42
43
|
items: {
|
|
43
44
|
title: string | null | undefined;
|
|
44
45
|
draftRevision?: number | undefined;
|
|
46
|
+
updatedAt: string | Date | undefined;
|
|
45
47
|
canDelete: boolean;
|
|
46
48
|
artifactId: string;
|
|
47
49
|
versionId: string | null | undefined;
|
|
48
50
|
versionNumber: number | undefined;
|
|
49
|
-
updatedAt: string | Date | undefined;
|
|
50
51
|
}[];
|
|
51
52
|
page: number;
|
|
52
53
|
hasMore: boolean;
|
|
53
54
|
}>;
|
|
55
|
+
selectedSummary(context: XpertResolvedViewHostContext, artifactId: string): Promise<{
|
|
56
|
+
title: string | null | undefined;
|
|
57
|
+
draftRevision?: number | undefined;
|
|
58
|
+
canDelete: boolean;
|
|
59
|
+
artifactId: string;
|
|
60
|
+
versionId: string | null | undefined;
|
|
61
|
+
versionNumber: number | undefined;
|
|
62
|
+
updatedAt: string | Date | undefined;
|
|
63
|
+
} | undefined>;
|
|
54
64
|
trash(context: XpertResolvedViewHostContext, artifactId: string, expectedRevision: number): Promise<{
|
|
55
65
|
artifactId: string;
|
|
56
66
|
}>;
|
|
57
|
-
save(context: XpertResolvedViewHostContext, manifest: DashboardManifest, expectedVersionId: string | null, expectedRevision?: number): Promise<{
|
|
67
|
+
save(context: XpertResolvedViewHostContext, manifest: DashboardManifest, expectedVersionId: string | null, expectedRevision?: number, importedDependencies?: ArtifactDocumentDependencyAsset[]): Promise<{
|
|
58
68
|
artifactId: string;
|
|
59
69
|
draftId: string;
|
|
60
70
|
draftRevision: number;
|
|
@@ -64,9 +74,9 @@ export declare class DashboardService {
|
|
|
64
74
|
}>;
|
|
65
75
|
open(context: XpertResolvedViewHostContext, artifactId: string, versionId?: string, draftRevision?: number, mode?: DashboardMode): Promise<{
|
|
66
76
|
manifest: {
|
|
67
|
-
schema: "xpert.live-dashboard";
|
|
68
|
-
id: string;
|
|
69
77
|
title: string;
|
|
78
|
+
id: string;
|
|
79
|
+
schema: "xpert.live-dashboard";
|
|
70
80
|
bindings: import("@xpert-ai/contracts").AnalyticsBinding[];
|
|
71
81
|
controls: {
|
|
72
82
|
type: "string" | "number" | "boolean" | "date";
|
|
@@ -76,20 +86,35 @@ export declare class DashboardService {
|
|
|
76
86
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
77
87
|
}[];
|
|
78
88
|
charts: {
|
|
89
|
+
title: string;
|
|
79
90
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
80
91
|
id: string;
|
|
81
|
-
title: string;
|
|
82
92
|
datasetId: string;
|
|
83
93
|
x: string;
|
|
84
94
|
y: string;
|
|
85
95
|
color?: string | undefined;
|
|
86
96
|
}[];
|
|
87
97
|
tables: {
|
|
88
|
-
id: string;
|
|
89
98
|
title: string;
|
|
99
|
+
id: string;
|
|
90
100
|
datasetId: string;
|
|
91
101
|
fields: string[];
|
|
92
102
|
}[];
|
|
103
|
+
sourceMetadata?: {
|
|
104
|
+
bindingId: string;
|
|
105
|
+
title: string;
|
|
106
|
+
description?: string | undefined;
|
|
107
|
+
}[] | undefined;
|
|
108
|
+
components?: {
|
|
109
|
+
title: string;
|
|
110
|
+
id: string;
|
|
111
|
+
elementId: string;
|
|
112
|
+
kind: "filter" | "metric" | "chart" | "table" | "text";
|
|
113
|
+
sources: {
|
|
114
|
+
bindingId: string;
|
|
115
|
+
fieldIds?: string[] | undefined;
|
|
116
|
+
}[];
|
|
117
|
+
}[] | undefined;
|
|
93
118
|
presentation?: {
|
|
94
119
|
type: "html";
|
|
95
120
|
html: string;
|
|
@@ -110,9 +135,9 @@ export declare class DashboardService {
|
|
|
110
135
|
/** Trusted View transport only. Agent read tools receive locks, never megabytes of library code. */
|
|
111
136
|
openDocument(context: XpertResolvedViewHostContext, artifactId: string, versionId?: string, draftRevision?: number, mode?: DashboardMode): Promise<{
|
|
112
137
|
manifest: {
|
|
113
|
-
schema: "xpert.live-dashboard";
|
|
114
|
-
id: string;
|
|
115
138
|
title: string;
|
|
139
|
+
id: string;
|
|
140
|
+
schema: "xpert.live-dashboard";
|
|
116
141
|
bindings: import("@xpert-ai/contracts").AnalyticsBinding[];
|
|
117
142
|
controls: {
|
|
118
143
|
type: "string" | "number" | "boolean" | "date";
|
|
@@ -122,27 +147,42 @@ export declare class DashboardService {
|
|
|
122
147
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
123
148
|
}[];
|
|
124
149
|
charts: {
|
|
150
|
+
title: string;
|
|
125
151
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
126
152
|
id: string;
|
|
127
|
-
title: string;
|
|
128
153
|
datasetId: string;
|
|
129
154
|
x: string;
|
|
130
155
|
y: string;
|
|
131
156
|
color?: string | undefined;
|
|
132
157
|
}[];
|
|
133
158
|
tables: {
|
|
134
|
-
id: string;
|
|
135
159
|
title: string;
|
|
160
|
+
id: string;
|
|
136
161
|
datasetId: string;
|
|
137
162
|
fields: string[];
|
|
138
163
|
}[];
|
|
164
|
+
sourceMetadata?: {
|
|
165
|
+
bindingId: string;
|
|
166
|
+
title: string;
|
|
167
|
+
description?: string | undefined;
|
|
168
|
+
}[] | undefined;
|
|
169
|
+
components?: {
|
|
170
|
+
title: string;
|
|
171
|
+
id: string;
|
|
172
|
+
elementId: string;
|
|
173
|
+
kind: "filter" | "metric" | "chart" | "table" | "text";
|
|
174
|
+
sources: {
|
|
175
|
+
bindingId: string;
|
|
176
|
+
fieldIds?: string[] | undefined;
|
|
177
|
+
}[];
|
|
178
|
+
}[] | undefined;
|
|
139
179
|
presentation?: {
|
|
140
180
|
type: "html";
|
|
141
181
|
html: string;
|
|
142
182
|
dependencies?: import("@xpert-ai/plugin-sdk/artifact-document").ArtifactDocumentDependencyLock[] | undefined;
|
|
143
183
|
} | undefined;
|
|
144
184
|
};
|
|
145
|
-
dependencies:
|
|
185
|
+
dependencies: ArtifactDocumentDependencyAsset[];
|
|
146
186
|
contentHash: string;
|
|
147
187
|
draftId?: string | undefined;
|
|
148
188
|
draftRevision?: number | undefined;
|
|
@@ -241,9 +281,9 @@ export declare class DashboardService {
|
|
|
241
281
|
reason: "unavailable";
|
|
242
282
|
}[];
|
|
243
283
|
manifest: {
|
|
244
|
-
schema: "xpert.live-dashboard";
|
|
245
|
-
id: string;
|
|
246
284
|
title: string;
|
|
285
|
+
id: string;
|
|
286
|
+
schema: "xpert.live-dashboard";
|
|
247
287
|
bindings: import("@xpert-ai/contracts").AnalyticsBinding[];
|
|
248
288
|
controls: {
|
|
249
289
|
type: "string" | "number" | "boolean" | "date";
|
|
@@ -253,20 +293,35 @@ export declare class DashboardService {
|
|
|
253
293
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
254
294
|
}[];
|
|
255
295
|
charts: {
|
|
296
|
+
title: string;
|
|
256
297
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
257
298
|
id: string;
|
|
258
|
-
title: string;
|
|
259
299
|
datasetId: string;
|
|
260
300
|
x: string;
|
|
261
301
|
y: string;
|
|
262
302
|
color?: string | undefined;
|
|
263
303
|
}[];
|
|
264
304
|
tables: {
|
|
265
|
-
id: string;
|
|
266
305
|
title: string;
|
|
306
|
+
id: string;
|
|
267
307
|
datasetId: string;
|
|
268
308
|
fields: string[];
|
|
269
309
|
}[];
|
|
310
|
+
sourceMetadata?: {
|
|
311
|
+
bindingId: string;
|
|
312
|
+
title: string;
|
|
313
|
+
description?: string | undefined;
|
|
314
|
+
}[] | undefined;
|
|
315
|
+
components?: {
|
|
316
|
+
title: string;
|
|
317
|
+
id: string;
|
|
318
|
+
elementId: string;
|
|
319
|
+
kind: "filter" | "metric" | "chart" | "table" | "text";
|
|
320
|
+
sources: {
|
|
321
|
+
bindingId: string;
|
|
322
|
+
fieldIds?: string[] | undefined;
|
|
323
|
+
}[];
|
|
324
|
+
}[] | undefined;
|
|
270
325
|
presentation?: {
|
|
271
326
|
type: "html";
|
|
272
327
|
html: string;
|
|
@@ -18,6 +18,8 @@ const common_1 = require("@nestjs/common");
|
|
|
18
18
|
const node_crypto_1 = require("node:crypto");
|
|
19
19
|
const plugin_sdk_1 = require("@xpert-ai/plugin-sdk");
|
|
20
20
|
const dashboard_schema_1 = require("./dashboard.schema");
|
|
21
|
+
const source_validation_1 = require("./source-validation");
|
|
22
|
+
const artifact_document_1 = require("@xpert-ai/plugin-sdk/artifact-document");
|
|
21
23
|
const renderer_1 = require("./renderer");
|
|
22
24
|
const dashboard_queries_1 = require("./dashboard-queries");
|
|
23
25
|
const html_validation_1 = require("./html-validation");
|
|
@@ -59,7 +61,7 @@ let DashboardService = class DashboardService {
|
|
|
59
61
|
return { page, pageSize, hasMore: page * pageSize < result.total, items: items.filter(item => access.canReadDraft || !!item.currentVersionId).map(item => {
|
|
60
62
|
const draft = drafts.get(item.id);
|
|
61
63
|
return { ...summary(item), canDelete: !!draft && access.canManage,
|
|
62
|
-
...(draft ? { title: draft.title ?? item.title, draftRevision: draft.revision } : {}) };
|
|
64
|
+
...(draft ? { title: draft.title ?? item.title, draftRevision: draft.revision, updatedAt: draft.updatedAt ?? item.updatedAt } : {}) };
|
|
63
65
|
}) };
|
|
64
66
|
}
|
|
65
67
|
async searchPage(context, input) {
|
|
@@ -76,6 +78,18 @@ let DashboardService = class DashboardService {
|
|
|
76
78
|
}
|
|
77
79
|
return { items: matches.slice(offset, offset + pageSize), page: input.page, hasMore: matches.length > offset + pageSize };
|
|
78
80
|
}
|
|
81
|
+
async selectedSummary(context, artifactId) {
|
|
82
|
+
const access = await this.access(context);
|
|
83
|
+
const artifact = await this.runtime.require(plugin_sdk_1.ArtifactsRuntimeCapability).getArtifact(artifactId);
|
|
84
|
+
assertOwned(context, artifact);
|
|
85
|
+
if (artifact.status !== 'active')
|
|
86
|
+
throw new common_1.ForbiddenException('DASHBOARD_ARCHIVED');
|
|
87
|
+
if (!access.canReadDraft && !artifact.currentVersionId)
|
|
88
|
+
return undefined;
|
|
89
|
+
const draft = access.canReadDraft ? (await this.runtime.require(plugin_sdk_1.ArtifactDraftsRuntimeCapability).list([artifactId]))[0] : undefined;
|
|
90
|
+
return { ...summary(artifact), canDelete: !!draft && access.canManage,
|
|
91
|
+
...(draft ? { title: draft.title ?? artifact.title, draftRevision: draft.revision } : {}) };
|
|
92
|
+
}
|
|
79
93
|
async trash(context, artifactId, expectedRevision) {
|
|
80
94
|
await this.authorizeProject(context, 'manage');
|
|
81
95
|
const artifact = await this.runtime.require(plugin_sdk_1.ArtifactsRuntimeCapability).getArtifact(artifactId);
|
|
@@ -86,10 +100,11 @@ let DashboardService = class DashboardService {
|
|
|
86
100
|
await this.runtime.require(plugin_sdk_1.ArtifactDraftsRuntimeCapability).setRecycled({ artifactId, expectedRevision, recycled: true });
|
|
87
101
|
return { artifactId };
|
|
88
102
|
}
|
|
89
|
-
async save(context, manifest, expectedVersionId, expectedRevision = 0) {
|
|
103
|
+
async save(context, manifest, expectedVersionId, expectedRevision = 0, importedDependencies) {
|
|
90
104
|
await this.authorizeProject(context, 'write');
|
|
91
105
|
const scopedActor = actor(context);
|
|
92
106
|
const parsed = dashboard_schema_1.dashboardSchema.parse(manifest);
|
|
107
|
+
(0, source_validation_1.assertComponentElements)(parsed);
|
|
93
108
|
const artifacts = this.runtime.require(plugin_sdk_1.ArtifactsRuntimeCapability);
|
|
94
109
|
const source = { pluginName: exports.PLUGIN_NAME, resourceType: RESOURCE_TYPE, resourceId: `${hostPrefix(context)}${parsed.id}` };
|
|
95
110
|
const existing = await artifacts.findArtifactBySource(source);
|
|
@@ -100,7 +115,10 @@ let DashboardService = class DashboardService {
|
|
|
100
115
|
}
|
|
101
116
|
// A failed first upload can leave an Artifact with no saved content; revision 0 initializes it.
|
|
102
117
|
const previous = existing && (existing.currentVersionId || expectedRevision > 0) ? await this.openDocument(context, existing.id) : null;
|
|
103
|
-
|
|
118
|
+
if (importedDependencies && existing)
|
|
119
|
+
throw new common_1.BadRequestException('DASHBOARD_IMPORT_NEW_ID_REQUIRED');
|
|
120
|
+
const dependencies = importedDependencies ? (0, artifact_document_1.verifyArtifactDocumentDependencies)(importedDependencies, parsed.presentation?.dependencies ?? [])
|
|
121
|
+
: await (0, document_libraries_1.resolveLibraryAssets)(parsed.presentation?.dependencies ?? [], previous?.dependencies);
|
|
104
122
|
const buffer = (0, document_package_1.encodeDashboardPackage)(parsed, dependencies);
|
|
105
123
|
if (buffer.byteLength > document_package_1.MAX_DASHBOARD_PACKAGE_BYTES)
|
|
106
124
|
throw new common_1.BadRequestException('DASHBOARD_MANIFEST_TOO_LARGE');
|
|
@@ -5,9 +5,9 @@ export declare const MAX_DASHBOARD_PACKAGE_BYTES = 9000000;
|
|
|
5
5
|
export declare function encodeDashboardPackage(manifest: DashboardManifest, dependencies: ArtifactDocumentDependencyAsset[]): Buffer<ArrayBuffer>;
|
|
6
6
|
export declare function decodeDashboardPackage(bytes: Buffer): {
|
|
7
7
|
manifest: {
|
|
8
|
-
schema: "xpert.live-dashboard";
|
|
9
|
-
id: string;
|
|
10
8
|
title: string;
|
|
9
|
+
id: string;
|
|
10
|
+
schema: "xpert.live-dashboard";
|
|
11
11
|
bindings: import("@xpert-ai/contracts").AnalyticsBinding[];
|
|
12
12
|
controls: {
|
|
13
13
|
type: "string" | "number" | "boolean" | "date";
|
|
@@ -17,20 +17,35 @@ export declare function decodeDashboardPackage(bytes: Buffer): {
|
|
|
17
17
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
18
18
|
}[];
|
|
19
19
|
charts: {
|
|
20
|
+
title: string;
|
|
20
21
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
21
22
|
id: string;
|
|
22
|
-
title: string;
|
|
23
23
|
datasetId: string;
|
|
24
24
|
x: string;
|
|
25
25
|
y: string;
|
|
26
26
|
color?: string | undefined;
|
|
27
27
|
}[];
|
|
28
28
|
tables: {
|
|
29
|
-
id: string;
|
|
30
29
|
title: string;
|
|
30
|
+
id: string;
|
|
31
31
|
datasetId: string;
|
|
32
32
|
fields: string[];
|
|
33
33
|
}[];
|
|
34
|
+
sourceMetadata?: {
|
|
35
|
+
bindingId: string;
|
|
36
|
+
title: string;
|
|
37
|
+
description?: string | undefined;
|
|
38
|
+
}[] | undefined;
|
|
39
|
+
components?: {
|
|
40
|
+
title: string;
|
|
41
|
+
id: string;
|
|
42
|
+
elementId: string;
|
|
43
|
+
kind: "filter" | "metric" | "chart" | "table" | "text";
|
|
44
|
+
sources: {
|
|
45
|
+
bindingId: string;
|
|
46
|
+
fieldIds?: string[] | undefined;
|
|
47
|
+
}[];
|
|
48
|
+
}[] | undefined;
|
|
34
49
|
presentation?: {
|
|
35
50
|
type: "html";
|
|
36
51
|
html: string;
|
|
@@ -5,16 +5,19 @@ export declare const removalsSchema: z.ZodOptional<z.ZodObject<{
|
|
|
5
5
|
controlIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
6
6
|
viewIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
7
7
|
htmlElementIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
8
|
+
componentIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
8
9
|
}, "strict", z.ZodTypeAny, {
|
|
9
10
|
bindingIds: string[];
|
|
10
11
|
controlIds: string[];
|
|
11
12
|
viewIds: string[];
|
|
12
13
|
htmlElementIds: string[];
|
|
14
|
+
componentIds: string[];
|
|
13
15
|
}, {
|
|
14
16
|
bindingIds?: string[] | undefined;
|
|
15
17
|
controlIds?: string[] | undefined;
|
|
16
18
|
viewIds?: string[] | undefined;
|
|
17
19
|
htmlElementIds?: string[] | undefined;
|
|
20
|
+
componentIds?: string[] | undefined;
|
|
18
21
|
}>>;
|
|
19
22
|
export declare function upsertComponents<T>(existing: T[], changes: T[] | undefined, id: (item: T) => string, removed?: string[]): T[];
|
|
20
23
|
export declare function htmlElementIds(html: string): Set<string>;
|
|
@@ -8,7 +8,8 @@ const parse5_1 = require("parse5");
|
|
|
8
8
|
const v3_1 = require("zod/v3");
|
|
9
9
|
exports.removalsSchema = v3_1.z.object({
|
|
10
10
|
bindingIds: v3_1.z.array(v3_1.z.string()).max(8).default([]), controlIds: v3_1.z.array(v3_1.z.string()).max(24).default([]),
|
|
11
|
-
viewIds: v3_1.z.array(v3_1.z.string()).max(40).default([]), htmlElementIds: v3_1.z.array(v3_1.z.string()).max(500).default([])
|
|
11
|
+
viewIds: v3_1.z.array(v3_1.z.string()).max(40).default([]), htmlElementIds: v3_1.z.array(v3_1.z.string()).max(500).default([]),
|
|
12
|
+
componentIds: v3_1.z.array(v3_1.z.string()).max(160).default([])
|
|
12
13
|
}).strict().optional().describe('Only explicitly requested removals. Arrays of changed components otherwise upsert by stable ID and preserve omitted components.');
|
|
13
14
|
function upsertComponents(existing, changes, id, removed = []) {
|
|
14
15
|
if (new Set(changes?.map(id)).size !== (changes?.length ?? 0))
|
|
@@ -84,41 +84,41 @@ export declare const dashboardStateSchema: z.ZodObject<{
|
|
|
84
84
|
draftRevision?: number | undefined;
|
|
85
85
|
}>>;
|
|
86
86
|
}, "strip", z.ZodTypeAny, {
|
|
87
|
+
scope: string;
|
|
87
88
|
target: {
|
|
88
89
|
artifactId: string;
|
|
89
90
|
schemaVersion: 1;
|
|
90
91
|
versionId?: string | undefined;
|
|
91
92
|
draftRevision?: number | undefined;
|
|
92
93
|
} | null;
|
|
93
|
-
scope: string;
|
|
94
94
|
}, {
|
|
95
|
+
scope: string;
|
|
95
96
|
target: {
|
|
96
97
|
artifactId: string;
|
|
97
98
|
schemaVersion: 1;
|
|
98
99
|
versionId?: string | undefined;
|
|
99
100
|
draftRevision?: number | undefined;
|
|
100
101
|
} | null;
|
|
101
|
-
scope: string;
|
|
102
102
|
}>>>;
|
|
103
103
|
}, "strip", z.ZodTypeAny, {
|
|
104
104
|
dashboardEditing?: {
|
|
105
|
+
scope: string;
|
|
105
106
|
target: {
|
|
106
107
|
artifactId: string;
|
|
107
108
|
schemaVersion: 1;
|
|
108
109
|
versionId?: string | undefined;
|
|
109
110
|
draftRevision?: number | undefined;
|
|
110
111
|
} | null;
|
|
111
|
-
scope: string;
|
|
112
112
|
} | null | undefined;
|
|
113
113
|
}, {
|
|
114
114
|
dashboardEditing?: {
|
|
115
|
+
scope: string;
|
|
115
116
|
target: {
|
|
116
117
|
artifactId: string;
|
|
117
118
|
schemaVersion: 1;
|
|
118
119
|
versionId?: string | undefined;
|
|
119
120
|
draftRevision?: number | undefined;
|
|
120
121
|
} | null;
|
|
121
|
-
scope: string;
|
|
122
122
|
} | null | undefined;
|
|
123
123
|
}>;
|
|
124
124
|
/** Checkpoints belong to an actor and conversation. Copied state must never choose another user's target. */
|