@xpert-ai/plugin-live-dashboard 0.4.1 → 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.
Files changed (50) hide show
  1. package/.xpertai-plugin/plugin.json +1 -1
  2. package/README.md +4 -0
  3. package/dist/lib/agent.schema.d.ts +179 -25
  4. package/dist/lib/agent.schema.js +10 -9
  5. package/dist/lib/archive.service.d.ts +145 -0
  6. package/dist/lib/archive.service.js +133 -0
  7. package/dist/lib/content.provider.d.ts +1 -1
  8. package/dist/lib/dashboard-archive.d.ts +70 -0
  9. package/dist/lib/dashboard-archive.js +118 -0
  10. package/dist/lib/dashboard-sources.d.ts +69 -0
  11. package/dist/lib/dashboard-sources.js +37 -0
  12. package/dist/lib/dashboard-view.schema.d.ts +422 -88
  13. package/dist/lib/dashboard.schema.d.ts +379 -58
  14. package/dist/lib/dashboard.schema.js +18 -1
  15. package/dist/lib/dashboard.service.d.ts +60 -14
  16. package/dist/lib/dashboard.service.js +8 -2
  17. package/dist/lib/document-package.d.ts +19 -4
  18. package/dist/lib/editing-patch.d.ts +3 -0
  19. package/dist/lib/editing-patch.js +2 -1
  20. package/dist/lib/editing-session.d.ts +4 -4
  21. package/dist/lib/editing.d.ts +202 -19
  22. package/dist/lib/editing.js +5 -2
  23. package/dist/lib/html-validation-feedback.d.ts +7 -0
  24. package/dist/lib/html-validation-feedback.js +19 -0
  25. package/dist/lib/html-validation.js +2 -1
  26. package/dist/lib/inspection-host.d.ts +7 -0
  27. package/dist/lib/inspection-host.js +48 -0
  28. package/dist/lib/inspection-runtime.d.ts +2 -0
  29. package/dist/lib/inspection-runtime.js +77 -0
  30. package/dist/lib/json-input.d.ts +4 -0
  31. package/dist/lib/json-input.js +21 -0
  32. package/dist/lib/middleware.js +3 -2
  33. package/dist/lib/plugin.js +2 -1
  34. package/dist/lib/presentation.provider.d.ts +24 -9
  35. package/dist/lib/presentation.provider.js +2 -1
  36. package/dist/lib/source-executions.d.ts +196 -0
  37. package/dist/lib/source-executions.js +25 -0
  38. package/dist/lib/source-validation.d.ts +2 -0
  39. package/dist/lib/source-validation.js +21 -0
  40. package/dist/lib/view.provider.d.ts +178 -8
  41. package/dist/lib/view.provider.js +30 -4
  42. package/dist/remote/app.css +1 -1
  43. package/dist/remote/app.js +100 -27
  44. package/dist/remote/build-manifest.json +37 -23
  45. package/docs/docs.json +3 -1
  46. package/docs/sources-inspect-portability-acceptance.mdx +67 -0
  47. package/docs/sources-inspect-portability.mdx +115 -0
  48. package/package.json +6 -5
  49. package/skills/live-dashboard/SKILL.md +5 -4
  50. package/skills/live-dashboard/references/source-inspection.md +17 -0
@@ -1,8 +1,9 @@
1
1
  import { DashboardProjectsService } from './projects.service';
2
- import type { XpertExtensionViewManifest, XpertResolvedViewHostContext, XpertViewActionRequest, XpertViewQuery } from '@xpert-ai/contracts';
3
- import { type IXpertViewExtensionProvider } from '@xpert-ai/plugin-sdk';
2
+ import type { XpertExtensionViewManifest, XpertResolvedViewHostContext, XpertViewActionRequest, XpertViewQuery, XpertViewFileAccessRequest } from '@xpert-ai/contracts';
3
+ import { type IXpertViewExtensionProvider, type XpertViewFileActionFile } from '@xpert-ai/plugin-sdk';
4
4
  import { DashboardService } from './dashboard.service';
5
5
  import { DashboardSharingService } from './sharing.service';
6
+ import { DashboardArchiveService } from './archive.service';
6
7
  export declare const VIEW_KEY = "live-dashboard";
7
8
  export declare const VIEW_PROVIDER = "live-dashboard";
8
9
  export declare const FEATURE = "live_dashboard";
@@ -10,7 +11,8 @@ export declare class DashboardViewProvider implements IXpertViewExtensionProvide
10
11
  private readonly service;
11
12
  private readonly sharing;
12
13
  private readonly projects;
13
- constructor(service: DashboardService, sharing: DashboardSharingService, projects: DashboardProjectsService);
14
+ private readonly archives;
15
+ constructor(service: DashboardService, sharing: DashboardSharingService, projects: DashboardProjectsService, archives: DashboardArchiveService);
14
16
  supports(context: XpertResolvedViewHostContext): boolean;
15
17
  getViewManifests(context: XpertResolvedViewHostContext, slot: string): XpertExtensionViewManifest[];
16
18
  getRemoteComponentEntry(): Promise<{
@@ -57,9 +59,9 @@ export declare class DashboardViewProvider implements IXpertViewExtensionProvide
57
59
  } | {
58
60
  saved: {
59
61
  manifest: {
60
- schema: "xpert.live-dashboard";
61
- id: string;
62
62
  title: string;
63
+ id: string;
64
+ schema: "xpert.live-dashboard";
63
65
  bindings: import("@xpert-ai/contracts").AnalyticsBinding[];
64
66
  controls: {
65
67
  type: "string" | "number" | "boolean" | "date";
@@ -69,20 +71,35 @@ export declare class DashboardViewProvider implements IXpertViewExtensionProvide
69
71
  allowedValues?: (string | number | boolean | null)[] | undefined;
70
72
  }[];
71
73
  charts: {
74
+ title: string;
72
75
  type: "bar" | "line" | "area" | "pie" | "scatter";
73
76
  id: string;
74
- title: string;
75
77
  datasetId: string;
76
78
  x: string;
77
79
  y: string;
78
80
  color?: string | undefined;
79
81
  }[];
80
82
  tables: {
81
- id: string;
82
83
  title: string;
84
+ id: string;
83
85
  datasetId: string;
84
86
  fields: string[];
85
87
  }[];
88
+ sourceMetadata?: {
89
+ bindingId: string;
90
+ title: string;
91
+ description?: string | undefined;
92
+ }[] | undefined;
93
+ components?: {
94
+ title: string;
95
+ id: string;
96
+ elementId: string;
97
+ kind: "filter" | "metric" | "chart" | "table" | "text";
98
+ sources: {
99
+ bindingId: string;
100
+ fieldIds?: string[] | undefined;
101
+ }[];
102
+ }[] | undefined;
86
103
  presentation?: {
87
104
  type: "html";
88
105
  html: string;
@@ -100,7 +117,7 @@ export declare class DashboardViewProvider implements IXpertViewExtensionProvide
100
117
  artifactId: string;
101
118
  versionId: string | null | undefined;
102
119
  versionNumber: number | undefined;
103
- };
120
+ } | undefined;
104
121
  versions: {
105
122
  current: boolean;
106
123
  artifactId: string;
@@ -181,6 +198,16 @@ export declare class DashboardViewProvider implements IXpertViewExtensionProvide
181
198
  };
182
199
  }>;
183
200
  executeViewAction(context: XpertResolvedViewHostContext, viewKey: string, action: string, request: XpertViewActionRequest): Promise<{
201
+ success: boolean;
202
+ data: import("@xpert-ai/contracts").AnalyticsDiscoveryResult;
203
+ refresh: boolean;
204
+ } | {
205
+ success: boolean;
206
+ data: {
207
+ discarded: boolean;
208
+ };
209
+ refresh: boolean;
210
+ } | {
184
211
  success: boolean;
185
212
  data: {
186
213
  canEdit: boolean;
@@ -239,9 +266,152 @@ export declare class DashboardViewProvider implements IXpertViewExtensionProvide
239
266
  artifactId: string;
240
267
  };
241
268
  refresh: boolean;
269
+ } | {
270
+ success: boolean;
271
+ data: {
272
+ payload?: {
273
+ ok: boolean;
274
+ widget_type: string;
275
+ surface: string;
276
+ sources: never[];
277
+ manifest: {
278
+ version: number;
279
+ surface: string;
280
+ title: string;
281
+ cards: never[];
282
+ filters: never[];
283
+ sources: never[];
284
+ charts: {
285
+ id: string;
286
+ title: string;
287
+ type: "bar" | "line" | "area" | "pie" | "scatter";
288
+ dataset: string;
289
+ encodings: {
290
+ color?: {
291
+ field: string;
292
+ } | undefined;
293
+ x: {
294
+ field: string;
295
+ };
296
+ y: {
297
+ field: string;
298
+ };
299
+ };
300
+ }[];
301
+ tables: {
302
+ id: string;
303
+ title: string;
304
+ dataset: string;
305
+ columns: {
306
+ field: string;
307
+ label: string;
308
+ }[];
309
+ }[];
310
+ blocks: ({
311
+ id: string;
312
+ type: string;
313
+ chartId: string;
314
+ } | {
315
+ id: string;
316
+ type: string;
317
+ tableId: string;
318
+ })[];
319
+ };
320
+ snapshot: {
321
+ version: number;
322
+ generatedAt: string;
323
+ status: string;
324
+ datasets: any;
325
+ };
326
+ } | undefined;
327
+ datasets: import("@xpert-ai/contracts").AnalyticalDataset[];
328
+ failures: {
329
+ bindingId: string;
330
+ datasetId: string;
331
+ reason: "unavailable";
332
+ }[];
333
+ };
334
+ refresh: boolean;
242
335
  } | {
243
336
  success: boolean;
244
337
  data: import("@xpert-ai/contracts").AnalyticalDataset;
245
338
  refresh: boolean;
246
339
  }>;
340
+ executeViewFileAction(context: XpertResolvedViewHostContext, viewKey: string, action: string, _request: XpertViewActionRequest, file: XpertViewFileActionFile): Promise<{
341
+ success: boolean;
342
+ data: {
343
+ importId: `${string}-${string}-${string}-${string}-${string}`;
344
+ manifest: {
345
+ title: string;
346
+ id: string;
347
+ schema: "xpert.live-dashboard";
348
+ bindings: import("@xpert-ai/contracts").AnalyticsBinding[];
349
+ controls: {
350
+ type: "string" | "number" | "boolean" | "date";
351
+ controlId: string;
352
+ label: string;
353
+ defaultValue?: string | number | boolean | null | undefined;
354
+ allowedValues?: (string | number | boolean | null)[] | undefined;
355
+ }[];
356
+ charts: {
357
+ title: string;
358
+ type: "bar" | "line" | "area" | "pie" | "scatter";
359
+ id: string;
360
+ datasetId: string;
361
+ x: string;
362
+ y: string;
363
+ color?: string | undefined;
364
+ }[];
365
+ tables: {
366
+ title: string;
367
+ id: string;
368
+ datasetId: string;
369
+ fields: string[];
370
+ }[];
371
+ sourceMetadata?: {
372
+ bindingId: string;
373
+ title: string;
374
+ description?: string | undefined;
375
+ }[] | undefined;
376
+ components?: {
377
+ title: string;
378
+ id: string;
379
+ elementId: string;
380
+ kind: "filter" | "metric" | "chart" | "table" | "text";
381
+ sources: {
382
+ bindingId: string;
383
+ fieldIds?: string[] | undefined;
384
+ }[];
385
+ }[] | undefined;
386
+ presentation?: {
387
+ type: "html";
388
+ html: string;
389
+ dependencies?: import("@xpert-ai/plugin-sdk/artifact-document").ArtifactDocumentDependencyLock[] | undefined;
390
+ } | undefined;
391
+ };
392
+ requirements: {
393
+ schema: string;
394
+ version: number;
395
+ bindings: {
396
+ id: string;
397
+ providerId: string;
398
+ operation: string;
399
+ contractVersion: number;
400
+ source: import("@xpert-ai/contracts").AnalyticsSourceRef;
401
+ }[];
402
+ externalResources: string[];
403
+ dynamicResourcesMayExist: boolean;
404
+ includesQueryResults: boolean;
405
+ requiresAuthorizedHost: boolean;
406
+ };
407
+ sources: import("@xpert-ai/contracts").AnalyticsSourceSummary[];
408
+ };
409
+ refresh: boolean;
410
+ }>;
411
+ resolveViewFile(context: XpertResolvedViewHostContext, viewKey: string, request: XpertViewFileAccessRequest): Promise<{
412
+ reference: import("@xpert-ai/plugin-sdk").WorkspacePortableFileReference;
413
+ fileName: string;
414
+ mimeType: string;
415
+ size: number;
416
+ }>;
247
417
  }
@@ -24,15 +24,18 @@ const dashboard_receipt_1 = require("./dashboard-receipt");
24
24
  const dashboard_navigation_1 = require("./dashboard-navigation");
25
25
  const project_1 = require("./project");
26
26
  const dashboard_icon_1 = require("./dashboard-icon");
27
+ const dashboard_sources_1 = require("./dashboard-sources");
28
+ const archive_service_1 = require("./archive.service");
27
29
  exports.VIEW_KEY = 'live-dashboard';
28
30
  exports.VIEW_PROVIDER = 'live-dashboard';
29
31
  exports.FEATURE = 'live_dashboard';
30
32
  const text = (en_US, zh_Hans) => ({ en_US, zh_Hans });
31
33
  let DashboardViewProvider = class DashboardViewProvider {
32
- constructor(service, sharing, projects) {
34
+ constructor(service, sharing, projects, archives) {
33
35
  this.service = service;
34
36
  this.sharing = sharing;
35
37
  this.projects = projects;
38
+ this.archives = archives;
36
39
  }
37
40
  supports(context) { return context.hostType === 'agent'; }
38
41
  getViewManifests(context, slot) {
@@ -44,6 +47,7 @@ let DashboardViewProvider = class DashboardViewProvider {
44
47
  workbench: { projectType: project_1.DASHBOARD_PROJECT_TYPE, fixed: true, openMode: 'on-demand', menu: { enabled: true, label: text('Live dashboards', '实时看板'), icon: dashboard_icon_1.dashboardIcon, order: 35 } },
45
48
  view: { type: 'remote_component', runtime: 'react', protocolVersion: 1, component: { isolation: 'iframe', entry: exports.VIEW_KEY }, dataSource: { mode: 'platform' } },
46
49
  dataSource: { mode: 'platform', querySchema: { supportsSelection: true, supportsParameters: true, supportsPagination: true, defaultPageSize: 50 }, cache: { enabled: false } },
50
+ fileAccess: { purposes: ['download'] },
47
51
  clientCommands: [{ key: 'workbench.content.status' }, { key: 'workbench.content.resolve' }, { key: contracts_1.ASSISTANT_CONTEXT_SET_COMMAND, label: text('Select dashboard for Assistant', '设置助理当前看板') },
48
52
  { key: contracts_1.ASSISTANT_CHAT_SEND_MESSAGE_COMMAND, label: text('Create with Assistant', '交给助理制作') },
49
53
  { key: contracts_1.ARTIFACT_PRESENTATION_OPEN_COMMAND, label: text('Open shared page', '打开独立页面') },
@@ -51,6 +55,8 @@ let DashboardViewProvider = class DashboardViewProvider {
51
55
  hostEvents: { subscriptions: [{ key: 'dashboard-created', event: 'assistant.tool.completed',
52
56
  filter: { toolNames: dashboard_receipt_1.DASHBOARD_MUTATION_TOOLS }, action: { type: 'forward', debounceMs: 0 } }] },
53
57
  actions: [
58
+ { key: 'import-preview', label: text('Import dashboard file', '导入看板文件'), actionType: 'invoke', transport: 'file' },
59
+ ...['import-commit', 'import-discard', 'import-browse'].map(key => ({ key, label: text('Import dashboard', '导入看板'), actionType: 'invoke' })),
54
60
  ...[
55
61
  { key: 'dashboards', label: text('Select dashboard', '选择看板') },
56
62
  { key: 'projects', label: text('Select project', '选择项目') },
@@ -80,15 +86,22 @@ let DashboardViewProvider = class DashboardViewProvider {
80
86
  : undefined;
81
87
  const versions = params.artifactId ? await this.service.history(context, params.artifactId) : undefined;
82
88
  const unavailable = params.artifactId && mode === 'published' && !params.versionId && !versions?.some(version => version.current);
89
+ const saved = !unavailable && params.artifactId ? await this.service.openDocument(context, params.artifactId, params.versionId, params.draftRevision, mode) : undefined;
83
90
  return { meta: { navigationTarget: (0, dashboard_navigation_1.dashboardNavigationTarget)(context), access, mode, currentProject,
84
91
  dashboards: page.items, selectedDashboard, pagination: { page: page.page, pageSize: page.pageSize, hasMore: page.hasMore },
85
92
  sources: access.canEdit ? await this.service.sources(context) : [],
86
93
  ...(unavailable ? { notice: 'not_published' } : params.artifactId ? {
87
- saved: await this.service.openDocument(context, params.artifactId, params.versionId, params.draftRevision, mode), versions
94
+ saved: saved && { ...saved, manifest: access.canEdit ? saved.manifest : (0, dashboard_sources_1.publicDashboardManifest)(saved.manifest) }, versions
88
95
  } : {}) } };
89
96
  }
90
97
  async executeViewAction(context, viewKey, action, request) {
91
98
  assertView(viewKey);
99
+ if (action === 'import-commit')
100
+ return { success: true, data: await this.archives.commit(context, archive_service_1.importInputSchema.parse(request.input)), refresh: false };
101
+ if (action === 'import-browse')
102
+ return { success: true, data: await this.archives.browse(context, archive_service_1.importBrowseSchema.parse(request.input)), refresh: false };
103
+ if (action === 'import-discard')
104
+ return { success: true, data: await this.archives.discard(context, v3_1.z.object({ importId: v3_1.z.string().uuid() }).strict().parse(request.input).importId), refresh: false };
92
105
  if (action === 'dashboards') {
93
106
  const parsed = projects_schema_1.dashboardSearchSchema.safeParse(request.input);
94
107
  if (!parsed.success)
@@ -128,7 +141,8 @@ let DashboardViewProvider = class DashboardViewProvider {
128
141
  }
129
142
  if (action === 'query') {
130
143
  const input = dashboard_schema_1.querySchema.parse(request.input);
131
- return { success: true, data: await this.service.query(context, input.artifactId, input.versionId, input.controls, input.draftRevision), refresh: false };
144
+ const result = await this.service.query(context, input.artifactId, input.versionId, input.controls, input.draftRevision);
145
+ return { success: true, data: { datasets: result.datasets, failures: result.failures, ...('payload' in result ? { payload: result.payload } : {}) }, refresh: false };
132
146
  }
133
147
  if (action === 'query-binding') {
134
148
  const parsed = dashboard_schema_1.queryBindingSchema.safeParse(request.input);
@@ -139,11 +153,23 @@ let DashboardViewProvider = class DashboardViewProvider {
139
153
  }
140
154
  throw new common_1.BadRequestException('DASHBOARD_ACTION_UNSUPPORTED');
141
155
  }
156
+ async executeViewFileAction(context, viewKey, action, _request, file) {
157
+ assertView(viewKey);
158
+ if (action !== 'import-preview')
159
+ throw new common_1.BadRequestException('DASHBOARD_ACTION_UNSUPPORTED');
160
+ return { success: true, data: await this.archives.prepare(context, file.buffer), refresh: false };
161
+ }
162
+ async resolveViewFile(context, viewKey, request) {
163
+ assertView(viewKey);
164
+ if (request.purpose !== 'download')
165
+ throw new common_1.ForbiddenException('DASHBOARD_ACTION_UNSUPPORTED');
166
+ return this.archives.exportFile(context, request.fileKey);
167
+ }
142
168
  };
143
169
  exports.DashboardViewProvider = DashboardViewProvider;
144
170
  exports.DashboardViewProvider = DashboardViewProvider = __decorate([
145
171
  (0, plugin_sdk_1.ViewExtensionProvider)(exports.VIEW_PROVIDER),
146
- __metadata("design:paramtypes", [dashboard_service_1.DashboardService, sharing_service_1.DashboardSharingService, projects_service_1.DashboardProjectsService])
172
+ __metadata("design:paramtypes", [dashboard_service_1.DashboardService, sharing_service_1.DashboardSharingService, projects_service_1.DashboardProjectsService, archive_service_1.DashboardArchiveService])
147
173
  ], DashboardViewProvider);
148
174
  function assertView(key) { if (key !== exports.VIEW_KEY)
149
175
  throw new common_1.BadRequestException('DASHBOARD_VIEW_UNSUPPORTED'); }