@xpert-ai/plugin-live-dashboard 0.3.1 → 0.4.1

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 (148) hide show
  1. package/.xpertai-plugin/plugin.json +10 -2
  2. package/README.md +6 -0
  3. package/assets/branding/cover-v1.prompt.txt +27 -0
  4. package/assets/branding/cover-v1.webp +0 -0
  5. package/assets/previews/customer-brief.png +0 -0
  6. package/assets/previews/profit-atlas.png +0 -0
  7. package/assets/previews/trend-workspace.png +0 -0
  8. package/dist/index.js +6 -3
  9. package/dist/lib/agent.schema.d.ts +43 -37
  10. package/dist/lib/agent.schema.js +2 -1
  11. package/dist/lib/app-config.d.ts +62 -0
  12. package/dist/lib/app-config.js +38 -0
  13. package/dist/lib/artifact-type.provider.d.ts +15 -0
  14. package/dist/lib/artifact-type.provider.js +78 -0
  15. package/dist/lib/assistant-template.d.ts +1 -2
  16. package/dist/lib/assistant-template.js +3 -52
  17. package/dist/lib/content.provider.js +13 -5
  18. package/dist/lib/dashboard-navigation.d.ts +58 -14
  19. package/dist/lib/dashboard-navigation.js +11 -10
  20. package/dist/lib/dashboard-view.schema.d.ts +278 -46
  21. package/dist/lib/dashboard-view.schema.js +9 -1
  22. package/dist/lib/dashboard.service.d.ts +49 -3
  23. package/dist/lib/dashboard.service.js +64 -28
  24. package/dist/lib/document-libraries.d.ts +1 -1
  25. package/dist/lib/document-libraries.js +3 -2
  26. package/dist/lib/document-network.d.ts +1 -1
  27. package/dist/lib/document-network.js +2 -6
  28. package/dist/lib/editing-feedback.d.ts +5 -0
  29. package/dist/lib/editing-feedback.js +19 -0
  30. package/dist/lib/editing-patch.d.ts +22 -0
  31. package/dist/lib/editing-patch.js +46 -0
  32. package/dist/lib/editing-session.d.ts +167 -0
  33. package/dist/lib/editing-session.js +53 -0
  34. package/dist/lib/editing.d.ts +92 -60
  35. package/dist/lib/editing.js +36 -24
  36. package/dist/lib/html-guidance.d.ts +1 -1
  37. package/dist/lib/html-guidance.js +1 -1
  38. package/dist/lib/middleware.js +42 -18
  39. package/dist/lib/monitor.d.ts +70 -0
  40. package/dist/lib/monitor.js +101 -0
  41. package/dist/lib/plugin.js +4 -1
  42. package/dist/lib/project.d.ts +106 -0
  43. package/dist/lib/project.js +17 -0
  44. package/dist/lib/projects.schema.d.ts +63 -0
  45. package/dist/lib/projects.schema.js +8 -0
  46. package/dist/lib/projects.service.d.ts +25 -0
  47. package/dist/lib/projects.service.js +75 -0
  48. package/dist/lib/resource-card.js +1 -1
  49. package/dist/lib/runtime-context.d.ts +3 -0
  50. package/dist/lib/runtime-context.js +13 -0
  51. package/dist/lib/save-evidence.d.ts +1 -1
  52. package/dist/lib/templates.d.ts +2 -0
  53. package/dist/lib/templates.js +55 -0
  54. package/dist/lib/view.provider.d.ts +127 -8
  55. package/dist/lib/view.provider.js +49 -12
  56. package/dist/libraries/TREND-WORKSPACE-ICONS-LICENSE.txt +43 -0
  57. package/dist/libraries/catalog.json +1 -1
  58. package/dist/remote/app.css +1 -1
  59. package/dist/remote/app.js +34 -34
  60. package/dist/remote/build-manifest.json +116 -32
  61. package/dist/sandbox-actions/action.json +1 -1
  62. package/dist/sandbox-actions/bundle/host.js +2 -2
  63. package/dist/sandbox-actions/bundle/resource-cache.mjs +2 -1
  64. package/dist/sandbox-actions/bundle/validate.mjs +1 -1
  65. package/docs/docs.json +7 -0
  66. package/docs/frontend-libraries.mdx +12 -4
  67. package/docs/html-mode.md +3 -3
  68. package/docs/quick-start-acceptance.mdx +50 -0
  69. package/docs/quick-start.mdx +64 -0
  70. package/docs/superstore.mdx +38 -0
  71. package/docs/team-sharing.mdx +6 -2
  72. package/docs/trend-workspace-acceptance.mdx +43 -0
  73. package/docs/trend-workspace.mdx +30 -0
  74. package/docs/verification.mdx +4 -2
  75. package/docs/visual-styles-acceptance.mdx +40 -0
  76. package/docs/visual-styles.mdx +46 -0
  77. package/package.json +23 -17
  78. package/skills/live-dashboard/SKILL.md +27 -3
  79. package/skills/live-dashboard/examples/README.md +25 -0
  80. package/skills/live-dashboard/examples/catalog.json +79 -0
  81. package/skills/live-dashboard/examples/production-quality/README.md +25 -0
  82. package/skills/live-dashboard/examples/production-quality/dashboard.html +129 -0
  83. package/skills/live-dashboard/examples/production-quality/definition.json +67 -0
  84. package/skills/live-dashboard/examples/production-quality/demo.csv +7 -0
  85. package/skills/live-dashboard/examples/production-quality/demo.json +44 -0
  86. package/skills/live-dashboard/examples/production-quality/expected.json +26 -0
  87. package/skills/live-dashboard/examples/production-quality/preview.png +0 -0
  88. package/skills/live-dashboard/examples/production-quality/query.json +53 -0
  89. package/skills/live-dashboard/examples/regional-sales/README.md +25 -0
  90. package/skills/live-dashboard/examples/regional-sales/dashboard-create.json +35 -0
  91. package/skills/live-dashboard/examples/regional-sales/definition.json +35 -0
  92. package/skills/live-dashboard/examples/regional-sales/demo.csv +5 -0
  93. package/skills/live-dashboard/examples/regional-sales/demo.json +18 -0
  94. package/skills/live-dashboard/examples/regional-sales/expected.json +19 -0
  95. package/skills/live-dashboard/examples/regional-sales/preview.png +0 -0
  96. package/skills/live-dashboard/examples/regional-sales/query.json +45 -0
  97. package/skills/live-dashboard/examples/sales-overview/README.md +25 -0
  98. package/skills/live-dashboard/examples/sales-overview/dashboard.html +129 -0
  99. package/skills/live-dashboard/examples/sales-overview/definition.json +57 -0
  100. package/skills/live-dashboard/examples/sales-overview/demo.csv +7 -0
  101. package/skills/live-dashboard/examples/sales-overview/demo.json +38 -0
  102. package/skills/live-dashboard/examples/sales-overview/expected.json +22 -0
  103. package/skills/live-dashboard/examples/sales-overview/preview.png +0 -0
  104. package/skills/live-dashboard/examples/sales-overview/query.json +52 -0
  105. package/skills/live-dashboard/examples/superstore/README.md +64 -0
  106. package/skills/live-dashboard/examples/superstore/THIRD_PARTY_LICENSE.txt +207 -0
  107. package/skills/live-dashboard/examples/superstore/build_data.py +155 -0
  108. package/skills/live-dashboard/examples/superstore/build_pages.py +129 -0
  109. package/skills/live-dashboard/examples/superstore/checks.json +104 -0
  110. package/skills/live-dashboard/examples/superstore/customers-mobile-dark.png +0 -0
  111. package/skills/live-dashboard/examples/superstore/customers-select.png +0 -0
  112. package/skills/live-dashboard/examples/superstore/customers.html +316 -0
  113. package/skills/live-dashboard/examples/superstore/customers.png +0 -0
  114. package/skills/live-dashboard/examples/superstore/customers.queries.json +512 -0
  115. package/skills/live-dashboard/examples/superstore/expected.json +4069 -0
  116. package/skills/live-dashboard/examples/superstore/import.json +200 -0
  117. package/skills/live-dashboard/examples/superstore/orders.csv +10195 -0
  118. package/skills/live-dashboard/examples/superstore/overview-mobile-dark.png +0 -0
  119. package/skills/live-dashboard/examples/superstore/overview-select.png +0 -0
  120. package/skills/live-dashboard/examples/superstore/overview.html +310 -0
  121. package/skills/live-dashboard/examples/superstore/overview.png +0 -0
  122. package/skills/live-dashboard/examples/superstore/overview.queries.json +636 -0
  123. package/skills/live-dashboard/examples/superstore/page.js +109 -0
  124. package/skills/live-dashboard/examples/superstore/profitability-mobile-dark.png +0 -0
  125. package/skills/live-dashboard/examples/superstore/profitability-select.png +0 -0
  126. package/skills/live-dashboard/examples/superstore/profitability.html +307 -0
  127. package/skills/live-dashboard/examples/superstore/profitability.png +0 -0
  128. package/skills/live-dashboard/examples/superstore/profitability.queries.json +334 -0
  129. package/skills/live-dashboard/examples/superstore/provenance.json +24 -0
  130. package/skills/live-dashboard/examples/superstore/semantic-model.json +220 -0
  131. package/skills/live-dashboard/examples/superstore/test_data.py +62 -0
  132. package/skills/live-dashboard/references/html-runtime.md +1 -1
  133. package/skills/live-dashboard/themes/README.md +50 -0
  134. package/skills/live-dashboard/themes/customer-brief/README.md +47 -0
  135. package/skills/live-dashboard/themes/customer-brief/charts.js +17 -0
  136. package/skills/live-dashboard/themes/customer-brief/layout.html +22 -0
  137. package/skills/live-dashboard/themes/customer-brief/theme.css +108 -0
  138. package/skills/live-dashboard/themes/profit-atlas/README.md +43 -0
  139. package/skills/live-dashboard/themes/profit-atlas/charts.js +30 -0
  140. package/skills/live-dashboard/themes/profit-atlas/layout.html +19 -0
  141. package/skills/live-dashboard/themes/profit-atlas/theme.css +75 -0
  142. package/skills/live-dashboard/themes/trend-workspace/ICON_LICENSE.txt +43 -0
  143. package/skills/live-dashboard/themes/trend-workspace/README.md +144 -0
  144. package/skills/live-dashboard/themes/trend-workspace/charts.js +60 -0
  145. package/skills/live-dashboard/themes/trend-workspace/icons.js +11 -0
  146. package/skills/live-dashboard/themes/trend-workspace/layout.html +45 -0
  147. package/skills/live-dashboard/themes/trend-workspace/select.js +127 -0
  148. package/skills/live-dashboard/themes/trend-workspace/theme.css +137 -0
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.DashboardProjectsService = exports.projectSearchSchema = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const plugin_sdk_1 = require("@xpert-ai/plugin-sdk");
18
+ const dashboard_service_1 = require("./dashboard.service");
19
+ var projects_schema_1 = require("./projects.schema");
20
+ Object.defineProperty(exports, "projectSearchSchema", { enumerable: true, get: function () { return projects_schema_1.projectSearchSchema; } });
21
+ /** Selection uses the host's membership and Assistant binding policy, never a client-supplied data scope. */
22
+ let DashboardProjectsService = class DashboardProjectsService {
23
+ constructor(runtime) {
24
+ this.runtime = runtime;
25
+ }
26
+ actor(context) {
27
+ if (context.hostType !== 'agent' || !context.tenantId || !context.organizationId || !context.userId)
28
+ throw new common_1.ForbiddenException('DASHBOARD_ACCESS_DENIED');
29
+ return { tenantId: context.tenantId, organizationId: context.organizationId, userId: context.userId };
30
+ }
31
+ async current(context) {
32
+ const id = (0, dashboard_service_1.projectId)(context);
33
+ if (!id)
34
+ return null;
35
+ const access = await this.runtime.require(plugin_sdk_1.ProjectAccessRuntimeCapability).assertAssistant({ actor: this.actor(context), projectId: id, assistantId: context.hostId });
36
+ return { id, name: access.name ?? id };
37
+ }
38
+ /** A picker target is untrusted until membership and the Assistant binding are revalidated. */
39
+ async pickerContext(context, targetProjectId) {
40
+ const access = await this.runtime.require(plugin_sdk_1.ProjectAccessRuntimeCapability).assertAssistant({
41
+ actor: this.actor(context), projectId: targetProjectId, assistantId: context.hostId
42
+ });
43
+ if (access.archived || access.projectId !== targetProjectId)
44
+ throw new common_1.ForbiddenException('DASHBOARD_ACCESS_DENIED');
45
+ // Domain reads/deletes accept a Project host. Do not fabricate file/conversation grants.
46
+ return { ...context, hostType: 'project', hostId: access.projectId, runtimeScope: undefined };
47
+ }
48
+ async list(context, input) {
49
+ const actor = this.actor(context), access = this.runtime.require(plugin_sdk_1.ProjectAccessRuntimeCapability);
50
+ const projects = await access.listReadable({ actor });
51
+ const items = [];
52
+ for (const project of projects) {
53
+ if (project.archived || !(project.name ?? project.projectId).toLocaleLowerCase().includes(input.search.toLocaleLowerCase()))
54
+ continue;
55
+ try {
56
+ await access.assertAssistant({ actor, projectId: project.projectId, assistantId: context.hostId });
57
+ }
58
+ catch (error) {
59
+ if (error instanceof common_1.ForbiddenException)
60
+ continue;
61
+ throw error;
62
+ }
63
+ items.push({ id: project.projectId, name: project.name ?? project.projectId });
64
+ }
65
+ items.sort((a, b) => a.name.localeCompare(b.name) || a.id.localeCompare(b.id));
66
+ const start = (input.page - 1) * 20;
67
+ return { items: items.slice(start, start + 20), page: input.page, hasMore: start + 20 < items.length };
68
+ }
69
+ };
70
+ exports.DashboardProjectsService = DashboardProjectsService;
71
+ exports.DashboardProjectsService = DashboardProjectsService = __decorate([
72
+ (0, common_1.Injectable)(),
73
+ __param(0, (0, common_1.Inject)(plugin_sdk_1.XPERT_RUNTIME_CAPABILITIES_TOKEN)),
74
+ __metadata("design:paramtypes", [Object])
75
+ ], DashboardProjectsService);
@@ -16,7 +16,7 @@ function dashboardResourceCard(scope, saved) {
16
16
  icon: { type: dashboard_icon_1.dashboardIcon.type, value: dashboard_icon_1.dashboardIcon.value },
17
17
  open: {
18
18
  ...(0, dashboard_navigation_1.dashboardNavigationTarget)(scope), selectionId: saved.artifactId,
19
- ...(saved.state === 'published' && saved.versionId ? { parameters: { versionId: saved.versionId } } : {})
19
+ parameters: saved.state === 'published' && saved.versionId ? { versionId: saved.versionId } : { mode: 'draft' }
20
20
  }
21
21
  };
22
22
  }
@@ -0,0 +1,3 @@
1
+ import type { XpertResolvedViewHostContext } from '@xpert-ai/contracts';
2
+ import { type IAgentMiddlewareContext } from '@xpert-ai/plugin-sdk';
3
+ export declare function dashboardRuntimeContext(context: IAgentMiddlewareContext): XpertResolvedViewHostContext;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dashboardRuntimeContext = dashboardRuntimeContext;
4
+ const plugin_sdk_1 = require("@xpert-ai/plugin-sdk");
5
+ function dashboardRuntimeContext(context) {
6
+ if (!context.xpertId)
7
+ throw new Error('DASHBOARD_ASSISTANT_REQUIRED');
8
+ return { tenantId: context.tenantId ?? plugin_sdk_1.RequestContext.currentTenantId(),
9
+ organizationId: context.organizationId ?? plugin_sdk_1.RequestContext.getOrganizationId(), userId: context.userId ?? plugin_sdk_1.RequestContext.currentUserId(),
10
+ hostType: 'agent', hostId: context.xpertId, slots: [],
11
+ ...(context.projectId ? { runtimeScope: { projectId: context.projectId, conversationId: context.conversationId ?? null,
12
+ dataScopeKey: `project:${context.projectId}`, workspaceFiles: { catalog: 'projects', scopeId: context.projectId, projectId: context.projectId } } } : {}) };
13
+ }
@@ -15,7 +15,7 @@ export declare function dashboardSaveEvidence(files: () => WorkspaceFilesApi): {
15
15
  token: number;
16
16
  generations: Map<string, number>;
17
17
  supersedesPaths: string[];
18
- confirmation: "draft" | "source";
18
+ confirmation: "source" | "draft";
19
19
  };
20
20
  accept(save: SaveAttempt, output: unknown): Promise<void>;
21
21
  readonly pending: boolean;
@@ -0,0 +1,2 @@
1
+ import type { XpertTemplateContribution } from '@xpert-ai/plugin-sdk';
2
+ export declare const dashboardTemplates: XpertTemplateContribution[];
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dashboardTemplates = void 0;
4
+ const contracts_1 = require("@xpert-ai/contracts");
5
+ const project_1 = require("./project");
6
+ const dashboard_icon_1 = require("./dashboard-icon");
7
+ const prompt_workflows_1 = require("./prompt-workflows");
8
+ const startPrompts = [
9
+ "请读取 live-dashboard 技能中 regional-sales 的完整配方,使用该配方随附的演示文件和标准图表定义,在当前项目新建区域销售看板。核对区域筛选、销售额和明细;不要使用其他样例或项目中已有的不同数据替代。完成实际查询与两个筛选验证后保存草稿,保留演示标识,不发布。",
10
+ "请读取 live-dashboard 技能中 sales-overview 的完整配方,使用该配方随附的演示文件和完整页面,在当前项目新建销售总览看板。包含销售额、订单数、日趋势、区域筛选和明细;不要使用其他样例或项目中已有的不同数据替代。完成实际查询与两个筛选验证后保存草稿,保留演示标识,不发布。",
11
+ "请读取 live-dashboard 技能中 production-quality 的完整配方,使用该配方随附的演示文件和完整页面,在当前项目新建生产质量看板。必须包含产量、良品数、加权良品率、不良品数和产线筛选;不要将销售数据或其他看板改名替代。完成实际查询与两个产线筛选验证后保存草稿,保留演示标识,不发布。",
12
+ "请读取 live-dashboard 技能中的 themes/README.md 和 superstore 完整配方(总览使用 Trend Workspace、盈利使用 Profit Atlas、客户退货使用 Customer Brief),在当前项目使用已授权的 Data Xpert SuperstoreOrders 发布模型,分别制作经营总览、商品盈利、客户与退货三个看板。必须保留演示标识;先核对全量及区域、年份、品类筛选,再按完整 HTML 和全部 Binding 保存三个草稿,不发布。若模型不可用,请说明数据准备步骤,不得用其他样例或自造数据替代。",
13
+ "使用我的业务数据制作看板,先检查当前项目可用的数据及指标口径。"
14
+ ];
15
+ const startLabels = ['区域销售 · 入门', '销售总览 · 入门', '生产质量 · 入门', 'Superstore 企业分析 · 进阶', '使用我的数据'];
16
+ const dsl = (monitor) => JSON.stringify({
17
+ team: { name: monitor ? 'live-dashboard-monitor' : 'live-dashboard-assistant', type: 'agent',
18
+ title: monitor ? '看板巡检' : '实时看板助理', version: '1', agent: { key: 'Agent_Dashboard' },
19
+ options: { workspaceScope: { mode: 'project-required', projectType: project_1.DASHBOARD_PROJECT_TYPE } },
20
+ features: monitor ? {} : { sandbox: { enabled: true }, opener: { enabled: true,
21
+ message: '选择或创建项目,从样例开始,或连接你的业务数据制作实时看板。', questions: startPrompts.map((prompt, index) => ({ label: startLabels[index], prompt })) } },
22
+ // Reading a recipe, registering its file and validating filters spans multiple graph steps per tool call.
23
+ agentConfig: { recursionLimit: monitor ? 100 : 300 }, workspaceDataScope: 'shared', knowledgebases: [], toolsets: [], tags: [] },
24
+ nodes: [
25
+ { type: 'agent', key: 'Agent_Dashboard', position: { x: 200, y: 100 }, entity: { key: 'Agent_Dashboard',
26
+ name: monitor ? 'dashboard-monitor' : 'dashboard-author', title: monitor ? '看板巡检' : '看板制作',
27
+ prompt: monitor
28
+ ? 'Inspect explicitly selected published dashboards in the current Project. Use dashboard_inspect to check live bindings as the scheduled run actor. Report failed bindings, incomplete results and the observed freshness; never claim business-data freshness from query time alone. Do not change definitions, publish, or expand access. Only schedule work when the human requests it. Use the user language.'
29
+ : 'Create and maintain dashboards in the current Project. Read the live-dashboard skill before authoring. For example requests use read_skill_file to read examples/catalog.json and the selected recipe directly relative to the catalog SKILL.md path; do not list sandbox directories to locate bundled files. After a successful draft receipt, report the receipt and let the user open its emitted card; do not reopen/update an unchanged dashboard merely to verify the save. Ask whether to use labeled synthetic demo data or authorized real data when unspecified. Small onboarding demo files belong to the current Project and use file.table after registration. The Superstore enterprise recipe instead requires the authorized published Data Xpert ontology; follow its own setup and query plans, never replace it with file.table or other sample rows. Never substitute demo values for missing real data. For enterprise BI pages, read themes/README.md, choose one visual style appropriate to the requested analysis and read its guide and complete recipe. The Superstore suite uses Trend Workspace for overview, Profit Atlas for profitability and Customer Brief for customers and returns. Use echarts plus exactly one matching theme library, adapt chart fields to discovered data, and preserve the selected theme on edits unless a redesign is requested. Discover registered data sources and validate exact bindings. Preserve the selected Artifact, component IDs and current draft revision on edits. Saving is not publication. Publication requires a manager in the Workbench. Never infer another dashboard from titles or recency. Use the user language.',
30
+ collaboratorNames: [], toolsetIds: [], knowledgebaseIds: [] } },
31
+ ...(monitor ? ['LiveDashboardMonitor', 'scheduler'] : ['LiveDashboard', 'SandboxFile', 'skillsMiddleware']).map((provider, index) => ({
32
+ type: 'workflow', key: `Middleware_${provider}`, position: { x: 550, y: 100 + index * 120 },
33
+ entity: { type: 'middleware', key: `Middleware_${provider}`, title: provider, provider, required: true,
34
+ ...(provider === 'LiveDashboard' ? { options: { maxModelCalls: 64 } } : {}) }
35
+ }))
36
+ ],
37
+ connections: (monitor ? ['LiveDashboardMonitor', 'scheduler'] : ['LiveDashboard', 'SandboxFile', 'skillsMiddleware']).map(provider => ({
38
+ type: 'workflow', key: `Agent_Dashboard/Middleware_${provider}`, from: 'Agent_Dashboard', to: `Middleware_${provider}`, required: true
39
+ }))
40
+ });
41
+ exports.dashboardTemplates = [false, true].map(monitor => ({
42
+ key: monitor ? 'live-dashboard-monitor' : 'live-dashboard-assistant',
43
+ name: monitor ? 'Live Dashboard Monitor' : 'Live Dashboard Assistant',
44
+ title: monitor ? '看板巡检' : '实时看板助理', type: contracts_1.XpertTypeEnum.Agent, icon: dashboard_icon_1.dashboardIcon,
45
+ description: monitor ? '在项目内以授权身份检查正式看板,不修改或发布。' : '在项目内制作和维护看板,草稿与正式发布分离。',
46
+ targetApps: ['xpert', 'data-xpert'], targetAppMeta: { xpert: { types: ['business-assistant'],
47
+ capabilities: [monitor ? 'live_dashboard.monitor' : 'live_dashboard'], requiredPlugins: monitor ? ['@xpert-ai/plugin-live-dashboard'] : ['@xpert-ai/plugin-live-dashboard', '@xpert-ai/plugin-analytics-files'] } },
48
+ dependencies: { plugins: monitor ? ['@xpert-ai/plugin-live-dashboard'] : ['@xpert-ai/plugin-live-dashboard', '@xpert-ai/plugin-analytics-files'],
49
+ skills: monitor ? [] : [{ componentKey: 'live-dashboard', targetAgentKey: 'Agent_Dashboard' }] },
50
+ category: 'Analytics',
51
+ promptWorkflows: monitor ? undefined : prompt_workflows_1.dashboardWorkspacePrompts,
52
+ startPrompts: monitor ? [] : startPrompts,
53
+ releaseNotes: monitor ? undefined : 'Adds project-scoped onboarding, three small examples and the Data Xpert Superstore enterprise suite with three optional reusable visual styles (Trend Workspace, Profit Atlas and Customer Brief) and accessible select controls; existing dashboards are never overwritten by template updates.',
54
+ dslContent: dsl(monitor), default: false, order: monitor ? 36 : 35
55
+ }));
@@ -1,3 +1,4 @@
1
+ import { DashboardProjectsService } from './projects.service';
1
2
  import type { XpertExtensionViewManifest, XpertResolvedViewHostContext, XpertViewActionRequest, XpertViewQuery } from '@xpert-ai/contracts';
2
3
  import { type IXpertViewExtensionProvider } from '@xpert-ai/plugin-sdk';
3
4
  import { DashboardService } from './dashboard.service';
@@ -8,7 +9,8 @@ export declare const FEATURE = "live_dashboard";
8
9
  export declare class DashboardViewProvider implements IXpertViewExtensionProvider {
9
10
  private readonly service;
10
11
  private readonly sharing;
11
- constructor(service: DashboardService, sharing: DashboardSharingService);
12
+ private readonly projects;
13
+ constructor(service: DashboardService, sharing: DashboardSharingService, projects: DashboardProjectsService);
12
14
  supports(context: XpertResolvedViewHostContext): boolean;
13
15
  getViewManifests(context: XpertResolvedViewHostContext, slot: string): XpertExtensionViewManifest[];
14
16
  getRemoteComponentEntry(): Promise<{
@@ -17,7 +19,43 @@ export declare class DashboardViewProvider implements IXpertViewExtensionProvide
17
19
  }>;
18
20
  getViewData(context: XpertResolvedViewHostContext, viewKey: string, query: XpertViewQuery): Promise<{
19
21
  meta: {
20
- saved?: {
22
+ notice: "not_published";
23
+ navigationTarget: {
24
+ target: "workbench.view";
25
+ viewKey: "live-dashboard__live-dashboard";
26
+ };
27
+ access: import("./project").DashboardAccess;
28
+ mode: "draft" | "published";
29
+ currentProject: {
30
+ id: string;
31
+ name: string;
32
+ } | null;
33
+ dashboards: {
34
+ title: string | null | undefined;
35
+ draftRevision?: number | undefined;
36
+ updatedAt: string | Date | undefined;
37
+ canDelete: boolean;
38
+ artifactId: string;
39
+ versionId: string | null | undefined;
40
+ versionNumber: number | undefined;
41
+ }[];
42
+ selectedDashboard: {
43
+ title: string | null | undefined;
44
+ draftRevision?: number | undefined;
45
+ updatedAt: string | Date | undefined;
46
+ canDelete: boolean;
47
+ artifactId: string;
48
+ versionId: string | null | undefined;
49
+ versionNumber: number | undefined;
50
+ } | undefined;
51
+ pagination: {
52
+ page: number;
53
+ pageSize: number;
54
+ hasMore: boolean;
55
+ };
56
+ sources: import("@xpert-ai/contracts").AnalyticsSourceSummary[];
57
+ } | {
58
+ saved: {
21
59
  manifest: {
22
60
  schema: "xpert.live-dashboard";
23
61
  id: string;
@@ -52,6 +90,7 @@ export declare class DashboardViewProvider implements IXpertViewExtensionProvide
52
90
  } | undefined;
53
91
  };
54
92
  dependencies: import("@xpert-ai/plugin-sdk/artifact-document").ArtifactDocumentDependencyAsset[];
93
+ contentHash: string;
55
94
  draftId?: string | undefined;
56
95
  draftRevision?: number | undefined;
57
96
  baseVersionId?: string | null | undefined;
@@ -61,8 +100,8 @@ export declare class DashboardViewProvider implements IXpertViewExtensionProvide
61
100
  artifactId: string;
62
101
  versionId: string | null | undefined;
63
102
  versionNumber: number | undefined;
64
- } | undefined;
65
- versions?: {
103
+ };
104
+ versions: {
66
105
  current: boolean;
67
106
  artifactId: string;
68
107
  versionId: string | null | undefined;
@@ -73,24 +112,104 @@ export declare class DashboardViewProvider implements IXpertViewExtensionProvide
73
112
  navigationTarget: {
74
113
  target: "workbench.view";
75
114
  viewKey: "live-dashboard__live-dashboard";
76
- } | {
77
- projectId: string;
78
- target: "assistant.project";
79
- viewKey: "live-dashboard__live-dashboard";
80
115
  };
116
+ access: import("./project").DashboardAccess;
117
+ mode: "draft" | "published";
118
+ currentProject: {
119
+ id: string;
120
+ name: string;
121
+ } | null;
81
122
  dashboards: {
82
123
  title: string | null | undefined;
83
124
  draftRevision?: number | undefined;
125
+ updatedAt: string | Date | undefined;
126
+ canDelete: boolean;
127
+ artifactId: string;
128
+ versionId: string | null | undefined;
129
+ versionNumber: number | undefined;
130
+ }[];
131
+ selectedDashboard: {
132
+ title: string | null | undefined;
133
+ draftRevision?: number | undefined;
134
+ updatedAt: string | Date | undefined;
84
135
  canDelete: boolean;
85
136
  artifactId: string;
86
137
  versionId: string | null | undefined;
87
138
  versionNumber: number | undefined;
139
+ } | undefined;
140
+ pagination: {
141
+ page: number;
142
+ pageSize: number;
143
+ hasMore: boolean;
144
+ };
145
+ sources: import("@xpert-ai/contracts").AnalyticsSourceSummary[];
146
+ } | {
147
+ navigationTarget: {
148
+ target: "workbench.view";
149
+ viewKey: "live-dashboard__live-dashboard";
150
+ };
151
+ access: import("./project").DashboardAccess;
152
+ mode: "draft" | "published";
153
+ currentProject: {
154
+ id: string;
155
+ name: string;
156
+ } | null;
157
+ dashboards: {
158
+ title: string | null | undefined;
159
+ draftRevision?: number | undefined;
88
160
  updatedAt: string | Date | undefined;
161
+ canDelete: boolean;
162
+ artifactId: string;
163
+ versionId: string | null | undefined;
164
+ versionNumber: number | undefined;
89
165
  }[];
166
+ selectedDashboard: {
167
+ title: string | null | undefined;
168
+ draftRevision?: number | undefined;
169
+ updatedAt: string | Date | undefined;
170
+ canDelete: boolean;
171
+ artifactId: string;
172
+ versionId: string | null | undefined;
173
+ versionNumber: number | undefined;
174
+ } | undefined;
175
+ pagination: {
176
+ page: number;
177
+ pageSize: number;
178
+ hasMore: boolean;
179
+ };
90
180
  sources: import("@xpert-ai/contracts").AnalyticsSourceSummary[];
91
181
  };
92
182
  }>;
93
183
  executeViewAction(context: XpertResolvedViewHostContext, viewKey: string, action: string, request: XpertViewActionRequest): Promise<{
184
+ success: boolean;
185
+ data: {
186
+ canEdit: boolean;
187
+ mode: string;
188
+ items: {
189
+ title: string | null | undefined;
190
+ draftRevision?: number | undefined;
191
+ updatedAt: string | Date | undefined;
192
+ canDelete: boolean;
193
+ artifactId: string;
194
+ versionId: string | null | undefined;
195
+ versionNumber: number | undefined;
196
+ }[];
197
+ page: number;
198
+ hasMore: boolean;
199
+ };
200
+ refresh: boolean;
201
+ } | {
202
+ success: boolean;
203
+ data: {
204
+ items: {
205
+ id: string;
206
+ name: string;
207
+ }[];
208
+ page: number;
209
+ hasMore: boolean;
210
+ };
211
+ refresh: boolean;
212
+ } | {
94
213
  success: boolean;
95
214
  data: {
96
215
  published: {
@@ -10,6 +10,8 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.DashboardViewProvider = exports.FEATURE = exports.VIEW_PROVIDER = exports.VIEW_KEY = void 0;
13
+ const projects_service_1 = require("./projects.service");
14
+ const projects_schema_1 = require("./projects.schema");
13
15
  const common_1 = require("@nestjs/common");
14
16
  const v3_1 = require("zod/v3");
15
17
  const contracts_1 = require("@xpert-ai/contracts");
@@ -20,33 +22,42 @@ const sharing_service_1 = require("./sharing.service");
20
22
  const dashboard_schema_1 = require("./dashboard.schema");
21
23
  const dashboard_receipt_1 = require("./dashboard-receipt");
22
24
  const dashboard_navigation_1 = require("./dashboard-navigation");
25
+ const project_1 = require("./project");
23
26
  const dashboard_icon_1 = require("./dashboard-icon");
24
27
  exports.VIEW_KEY = 'live-dashboard';
25
28
  exports.VIEW_PROVIDER = 'live-dashboard';
26
29
  exports.FEATURE = 'live_dashboard';
27
30
  const text = (en_US, zh_Hans) => ({ en_US, zh_Hans });
28
31
  let DashboardViewProvider = class DashboardViewProvider {
29
- constructor(service, sharing) {
32
+ constructor(service, sharing, projects) {
30
33
  this.service = service;
31
34
  this.sharing = sharing;
35
+ this.projects = projects;
32
36
  }
33
- supports(context) { return context.hostType === 'agent' || context.hostType === 'project'; }
37
+ supports(context) { return context.hostType === 'agent'; }
34
38
  getViewManifests(context, slot) {
35
- if (!(context.hostType === 'agent' && ['agent.workbench', 'agent.workbench.fixed', 'agent.workbench.main'].includes(slot) || context.hostType === 'project' && slot === 'detail.sections'))
39
+ if (!this.supports(context) || !['agent.workbench', 'agent.workbench.fixed', 'agent.workbench.main'].includes(slot))
36
40
  return [];
37
41
  return [{ key: exports.VIEW_KEY, title: text('Live dashboards', '实时看板'), hostType: context.hostType, slot, order: 35,
38
42
  icon: dashboard_icon_1.dashboardIcon, refreshable: true, activation: { projectResource: true, requiredFeatures: [exports.FEATURE] },
39
43
  source: { provider: exports.VIEW_PROVIDER, plugin: dashboard_service_1.PLUGIN_NAME },
40
- workbench: { fixed: true, openMode: 'on-demand', menu: { enabled: true, label: text('Live dashboards', '实时看板'), icon: dashboard_icon_1.dashboardIcon, order: 35 } },
44
+ 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 } },
41
45
  view: { type: 'remote_component', runtime: 'react', protocolVersion: 1, component: { isolation: 'iframe', entry: exports.VIEW_KEY }, dataSource: { mode: 'platform' } },
42
- dataSource: { mode: 'platform', querySchema: { supportsSelection: true, supportsParameters: true }, cache: { enabled: false } },
46
+ dataSource: { mode: 'platform', querySchema: { supportsSelection: true, supportsParameters: true, supportsPagination: true, defaultPageSize: 50 }, cache: { enabled: false } },
43
47
  clientCommands: [{ key: 'workbench.content.status' }, { key: 'workbench.content.resolve' }, { key: contracts_1.ASSISTANT_CONTEXT_SET_COMMAND, label: text('Select dashboard for Assistant', '设置助理当前看板') },
48
+ { key: contracts_1.ASSISTANT_CHAT_SEND_MESSAGE_COMMAND, label: text('Create with Assistant', '交给助理制作') },
44
49
  { key: contracts_1.ARTIFACT_PRESENTATION_OPEN_COMMAND, label: text('Open shared page', '打开独立页面') },
45
50
  { key: contracts_1.WORKBENCH_NAVIGATION_OPEN_COMMAND, label: text('Open dashboard', '打开看板') }],
46
51
  hostEvents: { subscriptions: [{ key: 'dashboard-created', event: 'assistant.tool.completed',
47
52
  filter: { toolNames: dashboard_receipt_1.DASHBOARD_MUTATION_TOOLS }, action: { type: 'forward', debounceMs: 0 } }] },
48
53
  actions: [
49
- ...['share-status', 'share', 'revoke-share'].map(key => ({ key, label: text('Team sharing', '团队分享'), actionType: 'invoke', placement: 'toolbar', inputSchema: { type: 'object', properties: {}, additionalProperties: true } })),
54
+ ...[
55
+ { key: 'dashboards', label: text('Select dashboard', '选择看板') },
56
+ { key: 'projects', label: text('Select project', '选择项目') },
57
+ { key: 'share-status', label: text('Sharing status', '分享状态') },
58
+ { key: 'share', label: text('Team sharing', '团队分享') },
59
+ { key: 'revoke-share', label: text('Revoke sharing', '撤销分享') }
60
+ ].map(({ key, label }) => ({ key, label, actionType: 'invoke', placement: 'toolbar', inputSchema: { type: 'object', properties: {}, additionalProperties: true } })),
50
61
  { key: 'delete', label: text('Delete dashboard', '删除看板'), actionType: 'invoke', placement: 'toolbar', inputSchema: { type: 'object', properties: {}, additionalProperties: true } },
51
62
  { key: 'publish', label: text('Publish draft', '发布草稿'), actionType: 'invoke', placement: 'toolbar', inputSchema: { type: 'object', properties: {}, additionalProperties: true } },
52
63
  { key: 'save', label: text('Save', '保存'), actionType: 'invoke', placement: 'toolbar', inputSchema: { type: 'object', properties: {}, additionalProperties: true } },
@@ -58,12 +69,37 @@ let DashboardViewProvider = class DashboardViewProvider {
58
69
  async getViewData(context, viewKey, query) {
59
70
  assertView(viewKey);
60
71
  const params = dashboard_navigation_1.dashboardNavigationSchema.parse(query);
61
- return { meta: { navigationTarget: (0, dashboard_navigation_1.dashboardNavigationTarget)(context), dashboards: await this.service.list(context), sources: await this.service.sources(context),
62
- ...(params.artifactId ? { saved: await this.service.openDocument(context, params.artifactId, params.versionId),
63
- versions: await this.service.history(context, params.artifactId) } : {}) } };
72
+ const access = await this.service.access(context);
73
+ const currentProject = await this.projects.current(context);
74
+ const mode = params.newDashboard ? 'draft' : params.mode ?? (access.canReadDraft ? 'draft' : 'published');
75
+ if (mode === 'draft' && !access.canReadDraft)
76
+ throw new common_1.ForbiddenException('DASHBOARD_DRAFT_ACCESS_DENIED');
77
+ const page = await this.service.listPage(context, params.page, params.pageSize);
78
+ const selectedDashboard = params.artifactId
79
+ ? page.items.find(item => item.artifactId === params.artifactId) ?? await this.service.selectedSummary(context, params.artifactId)
80
+ : undefined;
81
+ const versions = params.artifactId ? await this.service.history(context, params.artifactId) : undefined;
82
+ const unavailable = params.artifactId && mode === 'published' && !params.versionId && !versions?.some(version => version.current);
83
+ return { meta: { navigationTarget: (0, dashboard_navigation_1.dashboardNavigationTarget)(context), access, mode, currentProject,
84
+ dashboards: page.items, selectedDashboard, pagination: { page: page.page, pageSize: page.pageSize, hasMore: page.hasMore },
85
+ sources: access.canEdit ? await this.service.sources(context) : [],
86
+ ...(unavailable ? { notice: 'not_published' } : params.artifactId ? {
87
+ saved: await this.service.openDocument(context, params.artifactId, params.versionId, params.draftRevision, mode), versions
88
+ } : {}) } };
64
89
  }
65
90
  async executeViewAction(context, viewKey, action, request) {
66
91
  assertView(viewKey);
92
+ if (action === 'dashboards') {
93
+ const parsed = projects_schema_1.dashboardSearchSchema.safeParse(request.input);
94
+ if (!parsed.success)
95
+ throw new common_1.BadRequestException('DASHBOARD_INVALID_PICKER_QUERY');
96
+ const target = parsed.data.projectId ? await this.projects.pickerContext(context, parsed.data.projectId) : context;
97
+ const page = await this.service.searchPage(target, parsed.data);
98
+ const access = await this.service.access(target);
99
+ return { success: true, data: { ...page, canEdit: access.canEdit, mode: access.canReadDraft ? 'draft' : 'published' }, refresh: false };
100
+ }
101
+ if (action === 'projects')
102
+ return { success: true, data: await this.projects.list(context, projects_service_1.projectSearchSchema.parse(request.input)), refresh: false };
67
103
  if (action === 'share')
68
104
  return { success: true, data: await this.sharing.share(context, sharing_service_1.shareInput.parse(request.input)), refresh: false };
69
105
  if (action === 'share-status' || action === 'revoke-share') {
@@ -71,11 +107,12 @@ let DashboardViewProvider = class DashboardViewProvider {
71
107
  return { success: true, data: action === 'share-status' ? await this.sharing.inspect(context, input.artifactId, input.versionId) : await this.sharing.revoke(context, input.artifactId), refresh: false };
72
108
  }
73
109
  if (action === 'delete') {
74
- const parsed = v3_1.z.object({ artifactId: v3_1.z.string().uuid(), expectedRevision: v3_1.z.number().int().positive(), confirmed: v3_1.z.literal(true) }).strict().safeParse(request.input);
110
+ const parsed = v3_1.z.object({ artifactId: v3_1.z.string().uuid(), expectedRevision: v3_1.z.number().int().positive(), confirmed: v3_1.z.literal(true), projectId: v3_1.z.string().uuid().optional() }).strict().safeParse(request.input);
75
111
  if (!parsed.success)
76
112
  throw new common_1.BadRequestException('DASHBOARD_DELETION_CONFIRMATION_REQUIRED');
77
113
  const input = parsed.data;
78
- return { success: true, data: await this.service.trash(context, input.artifactId, input.expectedRevision), refresh: false };
114
+ const target = input.projectId ? await this.projects.pickerContext(context, input.projectId) : context;
115
+ return { success: true, data: await this.service.trash(target, input.artifactId, input.expectedRevision), refresh: false };
79
116
  }
80
117
  if (action === 'publish') {
81
118
  const parsed = v3_1.z.object({ artifactId: v3_1.z.string().uuid(), expectedRevision: v3_1.z.number().int().positive(),
@@ -106,7 +143,7 @@ let DashboardViewProvider = class DashboardViewProvider {
106
143
  exports.DashboardViewProvider = DashboardViewProvider;
107
144
  exports.DashboardViewProvider = DashboardViewProvider = __decorate([
108
145
  (0, plugin_sdk_1.ViewExtensionProvider)(exports.VIEW_PROVIDER),
109
- __metadata("design:paramtypes", [dashboard_service_1.DashboardService, sharing_service_1.DashboardSharingService])
146
+ __metadata("design:paramtypes", [dashboard_service_1.DashboardService, sharing_service_1.DashboardSharingService, projects_service_1.DashboardProjectsService])
110
147
  ], DashboardViewProvider);
111
148
  function assertView(key) { if (key !== exports.VIEW_KEY)
112
149
  throw new common_1.BadRequestException('DASHBOARD_VIEW_UNSUPPORTED'); }
@@ -0,0 +1,43 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026 Lucide Icons and Contributors
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+
17
+ ---
18
+
19
+ The following Lucide icons are derived from the Feather project:
20
+
21
+ airplay, alert-circle, alert-octagon, alert-triangle, aperture, arrow-down-circle, arrow-down-left, arrow-down-right, arrow-down, arrow-left-circle, arrow-left, arrow-right-circle, arrow-right, arrow-up-circle, arrow-up-left, arrow-up-right, arrow-up, at-sign, calendar, cast, check, chevron-down, chevron-left, chevron-right, chevron-up, chevrons-down, chevrons-left, chevrons-right, chevrons-up, circle, clipboard, clock, code, columns, command, compass, corner-down-left, corner-down-right, corner-left-down, corner-left-up, corner-right-down, corner-right-up, corner-up-left, corner-up-right, crosshair, database, divide-circle, divide-square, dollar-sign, download, external-link, feather, frown, hash, headphones, help-circle, info, italic, key, layout, life-buoy, link-2, link, loader, lock, log-in, log-out, maximize, meh, minimize, minimize-2, minus-circle, minus-square, minus, monitor, moon, more-horizontal, more-vertical, move, music, navigation-2, navigation, octagon, pause-circle, percent, plus-circle, plus-square, plus, power, radio, rss, search, server, share, shopping-bag, sidebar, smartphone, smile, square, table-2, tablet, target, terminal, trash-2, trash, triangle, tv, type, upload, x-circle, x-octagon, x-square, x, zoom-in, zoom-out
22
+
23
+ The MIT License (MIT) (for the icons listed above)
24
+
25
+ Copyright (c) 2013-present Cole Bemis
26
+
27
+ Permission is hereby granted, free of charge, to any person obtaining a copy
28
+ of this software and associated documentation files (the "Software"), to deal
29
+ in the Software without restriction, including without limitation the rights
30
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31
+ copies of the Software, and to permit persons to whom the Software is
32
+ furnished to do so, subject to the following conditions:
33
+
34
+ The above copyright notice and this permission notice shall be included in all
35
+ copies or substantial portions of the Software.
36
+
37
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
43
+ SOFTWARE.