@memberjunction/ng-dashboards 5.37.0 → 5.39.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/README.md +46 -7
- package/dist/AI/components/agents/agent-configuration.component.js +199 -198
- package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
- package/dist/AI/components/analytics/ai-analytics-resource.component.d.ts.map +1 -1
- package/dist/AI/components/analytics/ai-analytics-resource.component.js +20 -17
- package/dist/AI/components/analytics/ai-analytics-resource.component.js.map +1 -1
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts +15 -0
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts.map +1 -1
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.js +166 -58
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.js.map +1 -1
- package/dist/AI/components/analytics/executive-summary/executive-summary.component.d.ts.map +1 -1
- package/dist/AI/components/analytics/executive-summary/executive-summary.component.js +2 -1
- package/dist/AI/components/analytics/executive-summary/executive-summary.component.js.map +1 -1
- package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts +1 -0
- package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts.map +1 -1
- package/dist/AI/components/analytics/model-performance/model-performance.component.js +55 -36
- package/dist/AI/components/analytics/model-performance/model-performance.component.js.map +1 -1
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts +9 -1
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts.map +1 -1
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js +158 -117
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js.map +1 -1
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts +1 -0
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts.map +1 -1
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js +22 -8
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +89 -842
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +1353 -7683
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.d.ts +87 -0
- package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.js +475 -0
- package/dist/AI/components/autotagging/dialogs/dry-run-preview.dialog.component.js.map +1 -0
- package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.d.ts +29 -0
- package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.js +208 -0
- package/dist/AI/components/autotagging/dialogs/item-detail.dialog.component.js.map +1 -0
- package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.d.ts +21 -0
- package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.js +70 -0
- package/dist/AI/components/autotagging/dialogs/no-content-type-warning.dialog.component.js.map +1 -0
- package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts +235 -0
- package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js +1735 -0
- package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js.map +1 -0
- package/dist/AI/components/autotagging/shared/classify.dryrun.d.ts +61 -0
- package/dist/AI/components/autotagging/shared/classify.dryrun.d.ts.map +1 -0
- package/dist/AI/components/autotagging/shared/classify.dryrun.js +78 -0
- package/dist/AI/components/autotagging/shared/classify.dryrun.js.map +1 -0
- package/dist/AI/components/autotagging/shared/classify.format.d.ts +43 -0
- package/dist/AI/components/autotagging/shared/classify.format.d.ts.map +1 -0
- package/dist/AI/components/autotagging/shared/classify.format.js +209 -0
- package/dist/AI/components/autotagging/shared/classify.format.js.map +1 -0
- package/dist/AI/components/autotagging/shared/classify.types.d.ts +276 -0
- package/dist/AI/components/autotagging/shared/classify.types.d.ts.map +1 -0
- package/dist/AI/components/autotagging/shared/classify.types.js +6 -0
- package/dist/AI/components/autotagging/shared/classify.types.js.map +1 -0
- package/dist/AI/components/autotagging/tabs/health-tab.component.d.ts +103 -0
- package/dist/AI/components/autotagging/tabs/health-tab.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/tabs/health-tab.component.js +571 -0
- package/dist/AI/components/autotagging/tabs/health-tab.component.js.map +1 -0
- package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts +40 -0
- package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/tabs/history-tab.component.js +402 -0
- package/dist/AI/components/autotagging/tabs/history-tab.component.js.map +1 -0
- package/dist/AI/components/autotagging/tabs/inbox-tab.component.d.ts +107 -0
- package/dist/AI/components/autotagging/tabs/inbox-tab.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/tabs/inbox-tab.component.js +719 -0
- package/dist/AI/components/autotagging/tabs/inbox-tab.component.js.map +1 -0
- package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts +122 -0
- package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js +752 -0
- package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js.map +1 -0
- package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts +166 -0
- package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/tabs/sources-tab.component.js +1384 -0
- package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -0
- package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts +70 -0
- package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/tabs/tags-tab.component.js +448 -0
- package/dist/AI/components/autotagging/tabs/tags-tab.component.js.map +1 -0
- package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.d.ts +397 -0
- package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.js +3490 -0
- package/dist/AI/components/autotagging/tabs/taxonomy-tab.component.js.map +1 -0
- package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts +47 -0
- package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/tabs/types-tab.component.js +220 -0
- package/dist/AI/components/autotagging/tabs/types-tab.component.js.map +1 -0
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +293 -289
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
- package/dist/AI/components/models/model-management.component.js +209 -208
- package/dist/AI/components/models/model-management.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-management.component.js +130 -128
- package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
- package/dist/AI/components/requests/agent-requests-resource.component.js +61 -61
- package/dist/AI/components/requests/agent-requests-resource.component.js.map +1 -1
- package/dist/AI/components/system/system-configuration.component.js +17 -17
- package/dist/AI/components/system/system-configuration.component.js.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.js +550 -532
- package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
- package/dist/AI/services/ai-instrumentation.service.d.ts +5 -0
- package/dist/AI/services/ai-instrumentation.service.d.ts.map +1 -1
- package/dist/AI/services/ai-instrumentation.service.js +14 -2
- package/dist/AI/services/ai-instrumentation.service.js.map +1 -1
- package/dist/AI/services/cache-metrics.d.ts +50 -0
- package/dist/AI/services/cache-metrics.d.ts.map +1 -0
- package/dist/AI/services/cache-metrics.js +43 -0
- package/dist/AI/services/cache-metrics.js.map +1 -0
- package/dist/APIKeys/api-key-edit-panel.component.js +2 -2
- package/dist/APIKeys/api-keys-resource.component.js +132 -131
- package/dist/APIKeys/api-keys-resource.component.js.map +1 -1
- package/dist/Actions/components/actions-overview.component.js +141 -141
- package/dist/Actions/components/actions-overview.component.js.map +1 -1
- package/dist/Actions/components/execution-monitoring.component.js +15 -15
- package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
- package/dist/Actions/components/explorer/action-explorer.component.d.ts +0 -5
- package/dist/Actions/components/explorer/action-explorer.component.d.ts.map +1 -1
- package/dist/Actions/components/explorer/action-explorer.component.js +139 -212
- package/dist/Actions/components/explorer/action-explorer.component.js.map +1 -1
- package/dist/Admin/admin-data-schema.component.js +2 -2
- package/dist/Admin/admin-data-schema.component.js.map +1 -1
- package/dist/Admin/admin-dev-tools-resource.component.js +2 -2
- package/dist/Admin/admin-dev-tools-resource.component.js.map +1 -1
- package/dist/Admin/admin-identity-access.component.js +2 -2
- package/dist/Admin/admin-identity-access.component.js.map +1 -1
- package/dist/Admin/admin-monitoring.component.js +2 -2
- package/dist/Admin/admin-monitoring.component.js.map +1 -1
- package/dist/ApplicationRoles/application-roles-resource.component.js +54 -49
- package/dist/ApplicationRoles/application-roles-resource.component.js.map +1 -1
- package/dist/Communication/communication-logs-resource.component.d.ts +6 -0
- package/dist/Communication/communication-logs-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-logs-resource.component.js +72 -50
- package/dist/Communication/communication-logs-resource.component.js.map +1 -1
- package/dist/Communication/communication-monitor-resource.component.js +103 -102
- package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
- package/dist/Communication/communication-providers-resource.component.js +52 -51
- package/dist/Communication/communication-providers-resource.component.js.map +1 -1
- package/dist/Communication/communication-runs-resource.component.js +39 -38
- package/dist/Communication/communication-runs-resource.component.js.map +1 -1
- package/dist/Communication/communication-templates-resource.component.d.ts +6 -0
- package/dist/Communication/communication-templates-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-templates-resource.component.js +92 -89
- package/dist/Communication/communication-templates-resource.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts +73 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.js +512 -127
- package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-resource.component.d.ts +22 -0
- package/dist/ComponentStudio/component-studio-resource.component.d.ts.map +1 -0
- package/dist/ComponentStudio/component-studio-resource.component.js +55 -0
- package/dist/ComponentStudio/component-studio-resource.component.js.map +1 -0
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts +104 -45
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +234 -331
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js.map +1 -1
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts +54 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js +339 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts +65 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js +492 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts +88 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js +457 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js.map +1 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.d.ts +106 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.js +478 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.js.map +1 -0
- package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts +54 -0
- package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/workspace/component-preview.component.js +361 -50
- package/dist/ComponentStudio/components/workspace/component-preview.component.js.map +1 -1
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts +10 -0
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.js +114 -45
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.js.map +1 -1
- package/dist/ComponentStudio/services/canvas-to-code.d.ts +32 -0
- package/dist/ComponentStudio/services/canvas-to-code.d.ts.map +1 -0
- package/dist/ComponentStudio/services/canvas-to-code.js +347 -0
- package/dist/ComponentStudio/services/canvas-to-code.js.map +1 -0
- package/dist/ComponentStudio/services/code-to-canvas.d.ts +32 -0
- package/dist/ComponentStudio/services/code-to-canvas.d.ts.map +1 -0
- package/dist/ComponentStudio/services/code-to-canvas.js +92 -0
- package/dist/ComponentStudio/services/code-to-canvas.js.map +1 -0
- package/dist/ComponentStudio/services/component-studio-state.service.d.ts +29 -0
- package/dist/ComponentStudio/services/component-studio-state.service.d.ts.map +1 -1
- package/dist/ComponentStudio/services/component-studio-state.service.js +76 -0
- package/dist/ComponentStudio/services/component-studio-state.service.js.map +1 -1
- package/dist/ComponentStudio/services/entity-form-override.service.d.ts +86 -0
- package/dist/ComponentStudio/services/entity-form-override.service.d.ts.map +1 -0
- package/dist/ComponentStudio/services/entity-form-override.service.js +246 -0
- package/dist/ComponentStudio/services/entity-form-override.service.js.map +1 -0
- package/dist/ComponentStudio/services/field-binding-scanner.d.ts +29 -0
- package/dist/ComponentStudio/services/field-binding-scanner.d.ts.map +1 -0
- package/dist/ComponentStudio/services/field-binding-scanner.js +110 -0
- package/dist/ComponentStudio/services/field-binding-scanner.js.map +1 -0
- package/dist/ComponentStudio/services/form-canvas-model.d.ts +56 -0
- package/dist/ComponentStudio/services/form-canvas-model.d.ts.map +1 -0
- package/dist/ComponentStudio/services/form-canvas-model.js +35 -0
- package/dist/ComponentStudio/services/form-canvas-model.js.map +1 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.d.ts +10 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.d.ts.map +1 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.js +10 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.js.map +1 -0
- package/dist/Credentials/components/credentials-audit-resource.component.js +136 -135
- package/dist/Credentials/components/credentials-audit-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-categories-resource.component.js +155 -152
- package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-list-resource.component.js +119 -118
- package/dist/Credentials/components/credentials-list-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-overview-resource.component.js +129 -128
- package/dist/Credentials/components/credentials-overview-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-types-resource.component.js +107 -106
- package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +2 -2
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/DatabaseDesigner/components/database-designer-dashboard.component.js +1 -1
- package/dist/DatabaseDesigner/components/entity-list.component.js +115 -114
- package/dist/DatabaseDesigner/components/entity-list.component.js.map +1 -1
- package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts +5 -6
- package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts.map +1 -1
- package/dist/DatabaseDesigner/database-designer-dashboards.module.js +4 -5
- package/dist/DatabaseDesigner/database-designer-dashboards.module.js.map +1 -1
- package/dist/DevTools/app-state-inspector.component.js +18 -17
- package/dist/DevTools/app-state-inspector.component.js.map +1 -1
- package/dist/DevTools/class-registry.component.js +88 -85
- package/dist/DevTools/class-registry.component.js.map +1 -1
- package/dist/DevTools/event-monitor.component.js +155 -150
- package/dist/DevTools/event-monitor.component.js.map +1 -1
- package/dist/DevTools/graphql-console.component.js +245 -243
- package/dist/DevTools/graphql-console.component.js.map +1 -1
- package/dist/DevTools/layout-inspector.component.js +18 -17
- package/dist/DevTools/layout-inspector.component.js.map +1 -1
- package/dist/EntityAdmin/entity-admin-dashboard.component.js +20 -19
- package/dist/EntityAdmin/entity-admin-dashboard.component.js.map +1 -1
- package/dist/FormBuilder/form-builder-resource.component.d.ts +964 -0
- package/dist/FormBuilder/form-builder-resource.component.d.ts.map +1 -0
- package/dist/FormBuilder/form-builder-resource.component.js +4487 -0
- package/dist/FormBuilder/form-builder-resource.component.js.map +1 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts +55 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts.map +1 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.js +73 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.js.map +1 -0
- package/dist/Home/home-application.d.ts +21 -1
- package/dist/Home/home-application.d.ts.map +1 -1
- package/dist/Home/home-application.js +60 -8
- package/dist/Home/home-application.js.map +1 -1
- package/dist/Home/home-dashboard.component.js +2 -2
- package/dist/Integration/components/activity/activity.component.d.ts.map +1 -1
- package/dist/Integration/components/activity/activity.component.js +236 -229
- package/dist/Integration/components/activity/activity.component.js.map +1 -1
- package/dist/Integration/components/connections/connections.component.js +390 -389
- package/dist/Integration/components/connections/connections.component.js.map +1 -1
- package/dist/Integration/components/overview/overview.component.js +2 -2
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +2 -2
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +45 -44
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +293 -291
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js +62 -61
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.d.ts +6 -2
- package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.js +525 -566
- package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-categories-resource.component.js +135 -134
- package/dist/Lists/components/lists-categories-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-my-lists-resource.component.js +199 -198
- package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
- package/dist/MCP/mcp-dashboard.component.js +443 -438
- package/dist/MCP/mcp-dashboard.component.js.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.d.ts +14 -14
- package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.js +11 -10
- package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
- package/dist/Scheduling/components/scheduling-activity.component.d.ts.map +1 -1
- package/dist/Scheduling/components/scheduling-activity.component.js +146 -147
- package/dist/Scheduling/components/scheduling-activity.component.js.map +1 -1
- package/dist/Scheduling/components/scheduling-jobs.component.js +76 -75
- package/dist/Scheduling/components/scheduling-jobs.component.js.map +1 -1
- package/dist/Scheduling/components/scheduling-overview.component.js +97 -96
- package/dist/Scheduling/components/scheduling-overview.component.js.map +1 -1
- package/dist/Scheduling/scheduling-dashboard.component.js +24 -22
- package/dist/Scheduling/scheduling-dashboard.component.js.map +1 -1
- package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts +2 -0
- package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts.map +1 -1
- package/dist/Scheduling/services/scheduling-instrumentation.service.js +1 -0
- package/dist/Scheduling/services/scheduling-instrumentation.service.js.map +1 -1
- package/dist/Testing/components/testing-dashboard-tab-resource.component.js +1 -1
- package/dist/Testing/components/testing-explorer.component.d.ts +14 -4
- package/dist/Testing/components/testing-explorer.component.d.ts.map +1 -1
- package/dist/Testing/components/testing-explorer.component.js +436 -427
- package/dist/Testing/components/testing-explorer.component.js.map +1 -1
- package/dist/Testing/components/testing-runs-resource.component.js +1 -1
- package/dist/Testing/components/testing-runs.component.js +116 -115
- package/dist/Testing/components/testing-runs.component.js.map +1 -1
- package/dist/Testing/testing-dashboard.component.js +6 -7
- package/dist/Testing/testing-dashboard.component.js.map +1 -1
- package/dist/VersionHistory/components/labels-resource.component.js +173 -172
- package/dist/VersionHistory/components/labels-resource.component.js.map +1 -1
- package/dist/VersionHistory/components/restore-resource.component.d.ts +6 -0
- package/dist/VersionHistory/components/restore-resource.component.d.ts.map +1 -1
- package/dist/VersionHistory/components/restore-resource.component.js +116 -92
- package/dist/VersionHistory/components/restore-resource.component.js.map +1 -1
- package/dist/ai-dashboards.module.d.ts +47 -35
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +40 -1
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/communication-dashboards.module.d.ts +1 -1
- package/dist/communication-dashboards.module.d.ts.map +1 -1
- package/dist/communication-dashboards.module.js +7 -1
- package/dist/communication-dashboards.module.js.map +1 -1
- package/dist/component-studio-dashboards.module.d.ts +34 -22
- package/dist/component-studio-dashboards.module.d.ts.map +1 -1
- package/dist/component-studio-dashboards.module.js +65 -9
- package/dist/component-studio-dashboards.module.js.map +1 -1
- package/dist/testing-dashboards.module.d.ts +4 -5
- package/dist/testing-dashboards.module.d.ts.map +1 -1
- package/dist/testing-dashboards.module.js +7 -5
- package/dist/testing-dashboards.module.js.map +1 -1
- package/package.json +55 -53
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-assistant-panel.component.js","sourceRoot":"","sources":["../../../../src/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.ts","../../../../src/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ViewChild, ElementRef, ChangeDetectorRef } from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { RunView } from '@memberjunction/core';\nimport { MJAIModelEntity } from '@memberjunction/core-entities';\nimport { ComponentStudioStateService, ComponentError } from '../../services/component-studio-state.service';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\n/**\n * Represents a single message in the AI assistant chat thread\n */\nexport interface ChatMessage {\n Role: 'user' | 'assistant' | 'system';\n Content: string;\n Timestamp: Date;\n}\n\n/**\n * Represents a quick action button in the AI assistant panel\n */\ninterface QuickAction {\n Label: string;\n Icon: string;\n Prompt: string;\n RequiresError: boolean;\n}\n\n/**\n * Represents an AI model option in the model selector dropdown\n */\ninterface AIModelOption {\n ID: string;\n Name: string;\n Vendor: string | null;\n DisplayLabel: string;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-ai-assistant-panel',\n templateUrl: './ai-assistant-panel.component.html',\n styleUrls: ['./ai-assistant-panel.component.css']\n})\nexport class AIAssistantPanelComponent extends BaseAngularComponent implements OnInit, OnDestroy {\n\n @ViewChild('chatThread') chatThreadEl!: ElementRef<HTMLDivElement>;\n @ViewChild('chatInput') chatInputEl!: ElementRef<HTMLTextAreaElement>;\n\n // --- Chat State ---\n Messages: ChatMessage[] = [];\n InputText = '';\n IsWaitingForResponse = false;\n\n // --- Model Selector ---\n AvailableModels: AIModelOption[] = [];\n SelectedModelID: string | null = null;\n IsLoadingModels = false;\n\n // --- Quick Actions ---\n QuickActions: QuickAction[] = [\n { Label: 'Fix Errors', Icon: 'fa-bug', Prompt: 'Fix this error: ', RequiresError: true },\n { Label: 'Improve Code', Icon: 'fa-magic', Prompt: 'Review and improve the current component code. Suggest optimizations, better patterns, and cleaner structure.', RequiresError: false },\n { Label: 'Generate Code', Icon: 'fa-code', Prompt: 'Generate code for the current component based on its specification.', RequiresError: false },\n { Label: 'Explain', Icon: 'fa-question-circle', Prompt: 'Explain what the current component does, including its structure, data flow, and key behaviors.', RequiresError: false }\n ];\n\n private destroy$ = new Subject<void>();\n\n constructor(\n public State: ComponentStudioStateService,\n private cdr: ChangeDetectorRef\n ) { super(); }\n\n async ngOnInit(): Promise<void> {\n this.subscribeToErrorEvents();\n await this.LoadModels();\n this.addWelcomeMessage();\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n // ============================================================\n // MODEL LOADING\n // ============================================================\n\n async LoadModels(): Promise<void> {\n this.IsLoadingModels = true;\n try {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const result = await rv.RunView<MJAIModelEntity>({\n EntityName: 'MJ: AI Models',\n ExtraFilter: `IsActive = 1 AND AIModelTypeID IN (SELECT ID FROM __mj.vwAIModelTypes WHERE Name = 'LLM')`,\n OrderBy: 'PowerRank DESC, Name ASC',\n ResultType: 'entity_object'\n });\n\n if (result.Success && result.Results) {\n this.AvailableModels = result.Results.map(model => ({\n ID: model.ID,\n Name: model.Name,\n Vendor: model.Vendor,\n DisplayLabel: model.Vendor ? `${model.Name} (${model.Vendor})` : model.Name\n }));\n\n if (this.AvailableModels.length > 0) {\n this.SelectedModelID = this.AvailableModels[0].ID;\n }\n }\n } catch (error) {\n console.error('Error loading AI models:', error);\n } finally {\n this.IsLoadingModels = false;\n this.cdr.detectChanges();\n }\n }\n\n // ============================================================\n // ERROR SUBSCRIPTION\n // ============================================================\n\n private subscribeToErrorEvents(): void {\n this.State.SendErrorToAI\n .pipe(takeUntil(this.destroy$))\n .subscribe((error: ComponentError) => {\n this.handleIncomingError(error);\n });\n }\n\n private handleIncomingError(error: ComponentError): void {\n const errorDetails = error.technicalDetails\n ? (typeof error.technicalDetails === 'string' ? error.technicalDetails : JSON.stringify(error.technicalDetails, null, 2))\n : '';\n\n const systemContent = `Error detected [${error.type}]: ${error.message}${errorDetails ? '\\n\\nDetails:\\n' + errorDetails : ''}`;\n\n this.addMessage('system', systemContent);\n this.InputText = `Fix this error: ${error.type} - ${error.message}`;\n this.cdr.detectChanges();\n this.focusInput();\n }\n\n // ============================================================\n // WELCOME MESSAGE\n // ============================================================\n\n private addWelcomeMessage(): void {\n this.addMessage(\n 'assistant',\n 'Welcome to the Component Studio AI Assistant. I can help you fix errors, improve code, generate components, and explain how things work. Select a component and ask me anything!'\n );\n }\n\n // ============================================================\n // CHAT ACTIONS\n // ============================================================\n\n OnSendMessage(): void {\n const text = this.InputText.trim();\n if (!text || this.IsWaitingForResponse) return;\n\n this.addMessage('user', text);\n this.InputText = '';\n this.resetInputHeight();\n this.simulateResponse(text);\n }\n\n OnQuickAction(action: QuickAction): void {\n if (action.RequiresError && !this.State.CurrentError) return;\n\n if (action.RequiresError && this.State.CurrentError) {\n const errorContext = `${this.State.CurrentError.type} - ${this.State.CurrentError.message}`;\n this.InputText = `${action.Prompt}${errorContext}`;\n } else {\n this.InputText = action.Prompt;\n }\n\n this.cdr.detectChanges();\n this.focusInput();\n }\n\n OnInputKeydown(event: KeyboardEvent): void {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n this.OnSendMessage();\n }\n }\n\n OnInputChange(): void {\n this.autoGrowTextarea();\n }\n\n OnCollapsePanel(): void {\n this.State.IsAIPanelCollapsed = true;\n this.State.StateChanged.emit();\n }\n\n IsQuickActionEnabled(action: QuickAction): boolean {\n if (action.RequiresError) {\n return this.State.CurrentError != null;\n }\n return true;\n }\n\n // ============================================================\n // MESSAGE MANAGEMENT\n // ============================================================\n\n private addMessage(role: 'user' | 'assistant' | 'system', content: string): void {\n this.Messages.push({\n Role: role,\n Content: content,\n Timestamp: new Date()\n });\n this.cdr.detectChanges();\n this.scrollToBottom();\n }\n\n private simulateResponse(userMessage: string): void {\n this.IsWaitingForResponse = true;\n this.cdr.detectChanges();\n this.scrollToBottom();\n\n setTimeout(() => {\n this.addMessage(\n 'assistant',\n 'AI assistant coming soon \\u2014 agent integration in progress. Your message has been received and will be processed once the AI backend is connected.'\n );\n this.IsWaitingForResponse = false;\n this.cdr.detectChanges();\n }, 1000);\n }\n\n // ============================================================\n // UI HELPERS\n // ============================================================\n\n private scrollToBottom(): void {\n Promise.resolve().then(() => {\n if (this.chatThreadEl) {\n const el = this.chatThreadEl.nativeElement;\n el.scrollTop = el.scrollHeight;\n }\n });\n }\n\n private focusInput(): void {\n Promise.resolve().then(() => {\n if (this.chatInputEl) {\n this.chatInputEl.nativeElement.focus();\n }\n });\n }\n\n private autoGrowTextarea(): void {\n if (!this.chatInputEl) return;\n const textarea = this.chatInputEl.nativeElement;\n textarea.style.height = 'auto';\n const lineHeight = 20;\n const maxLines = 4;\n const maxHeight = lineHeight * maxLines;\n textarea.style.height = Math.min(textarea.scrollHeight, maxHeight) + 'px';\n }\n\n private resetInputHeight(): void {\n if (!this.chatInputEl) return;\n this.chatInputEl.nativeElement.style.height = 'auto';\n }\n\n FormatTimestamp(date: Date): string {\n return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n }\n\n TrackByTimestamp(index: number, message: ChatMessage): number {\n return message.Timestamp.getTime();\n }\n}\n","<div class=\"ai-assistant-panel\">\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"header-title\">\n <i class=\"fa-solid fa-robot\"></i>\n <span>AI Assistant</span>\n </div>\n <button class=\"collapse-btn\" (click)=\"OnCollapsePanel()\" title=\"Collapse panel\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </button>\n </div>\n\n <!-- Model Selector -->\n <div class=\"model-selector\">\n <label class=\"model-label\">Model</label>\n <div class=\"model-dropdown-wrapper\">\n @if (IsLoadingModels) {\n <div class=\"model-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading models...</span>\n </div>\n } @else {\n <select\n class=\"model-dropdown\"\n [(ngModel)]=\"SelectedModelID\"\n [disabled]=\"AvailableModels.length === 0\">\n @for (model of AvailableModels; track model.ID) {\n <option [value]=\"model.ID\">{{ model.DisplayLabel }}</option>\n }\n @if (AvailableModels.length === 0) {\n <option [value]=\"null\" disabled>No models available</option>\n }\n </select>\n }\n </div>\n </div>\n\n <!-- Quick Actions Bar -->\n <div class=\"quick-actions\">\n @for (action of QuickActions; track action.Label) {\n <button\n class=\"quick-action-btn\"\n [class.disabled]=\"!IsQuickActionEnabled(action)\"\n [disabled]=\"!IsQuickActionEnabled(action) || IsWaitingForResponse\"\n (click)=\"OnQuickAction(action)\"\n [title]=\"action.Label\">\n <i class=\"fa-solid {{ action.Icon }}\"></i>\n <span>{{ action.Label }}</span>\n </button>\n }\n </div>\n\n <!-- Chat Thread -->\n <div class=\"chat-thread\" #chatThread>\n @if (Messages.length === 0) {\n <div class=\"empty-thread\">\n <i class=\"fa-solid fa-comments\"></i>\n <p>No messages yet. Start a conversation or use a quick action above.</p>\n </div>\n }\n\n @for (message of Messages; track TrackByTimestamp($index, message)) {\n <div class=\"message-wrapper\" [class.user]=\"message.Role === 'user'\" [class.assistant]=\"message.Role === 'assistant'\" [class.system]=\"message.Role === 'system'\">\n @if (message.Role === 'assistant') {\n <div class=\"message-avatar assistant-avatar\">\n <i class=\"fa-solid fa-robot\"></i>\n </div>\n }\n\n <div class=\"message-bubble\" [class.user-bubble]=\"message.Role === 'user'\" [class.assistant-bubble]=\"message.Role === 'assistant'\" [class.system-bubble]=\"message.Role === 'system'\">\n <div class=\"message-content\">{{ message.Content }}</div>\n <div class=\"message-timestamp\">{{ FormatTimestamp(message.Timestamp) }}</div>\n </div>\n\n @if (message.Role === 'user') {\n <div class=\"message-avatar user-avatar\">\n <i class=\"fa-solid fa-user\"></i>\n </div>\n }\n </div>\n }\n\n <!-- Typing Indicator -->\n @if (IsWaitingForResponse) {\n <div class=\"message-wrapper assistant\">\n <div class=\"message-avatar assistant-avatar\">\n <i class=\"fa-solid fa-robot\"></i>\n </div>\n <div class=\"message-bubble assistant-bubble typing-bubble\">\n <div class=\"typing-indicator\">\n <span class=\"dot\"></span>\n <span class=\"dot\"></span>\n <span class=\"dot\"></span>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Chat Input Area -->\n <div class=\"chat-input-area\">\n <div class=\"input-wrapper\">\n <textarea\n #chatInput\n class=\"chat-textarea\"\n [(ngModel)]=\"InputText\"\n (keydown)=\"OnInputKeydown($event)\"\n (input)=\"OnInputChange()\"\n [disabled]=\"IsWaitingForResponse\"\n placeholder=\"Ask the AI assistant...\"\n rows=\"1\"></textarea>\n <button\n class=\"send-btn\"\n [class.active]=\"InputText.trim().length > 0 && !IsWaitingForResponse\"\n [disabled]=\"InputText.trim().length === 0 || IsWaitingForResponse\"\n (click)=\"OnSendMessage()\"\n title=\"Send message\">\n <i class=\"fa-solid fa-paper-plane\"></i>\n </button>\n </div>\n <div class=\"input-hint\">\n <span>Press <kbd>Enter</kbd> to send, <kbd>Shift+Enter</kbd> for new line</span>\n </div>\n </div>\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"ai-assistant-panel.component.js","sourceRoot":"","sources":["../../../../src/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.ts","../../../../src/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n OnDestroy,\n OnInit,\n inject,\n} from '@angular/core';\nimport { CompositeKey, LogError } from '@memberjunction/core';\nimport type { UserInfo } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { Subject, Subscription, takeUntil } from 'rxjs';\nimport { MJEnvironmentEntityExtended } from '@memberjunction/core-entities';\nimport type {\n MJConversationEntity,\n MJTaskEntity,\n} from '@memberjunction/core-entities';\nimport type { AppContextSnapshot } from '@memberjunction/ai-core-plus';\nimport { NavigationService } from '@memberjunction/ng-shared';\nimport type { NavigationRequest, PendingAttachment } from '@memberjunction/ng-conversations';\nimport { ComponentStudioStateService, ComponentError } from '../../services/component-studio-state.service';\n\n/**\n * Quick-action shortcut surfaced above the embedded chat. Clicking a\n * shortcut prefills the chat input via the pendingMessage handoff — the\n * same mechanism the empty-state uses to send the first message.\n */\ninterface QuickAction {\n Label: string;\n Icon: string;\n Prompt: string;\n /** When true, the button is disabled unless `state.CurrentError` is set. */\n RequiresError: boolean;\n}\n\n/**\n * Component Studio's right-pane AI assistant.\n *\n * Previously this was a 880-line bespoke chat stub that emitted \"AI\n * assistant coming soon\" — no agent was actually called. This version\n * thin-wraps `<mj-conversation-chat-area>` (the same primitive the main\n * Chat app and the Form Builder cockpit use) so the assistant becomes\n * fully functional with zero duplicated chat plumbing.\n *\n * Domain integration preserved from the old stub:\n * - **Quick-actions bar** (Fix Errors / Improve / Generate / Explain)\n * above the chat — clicking sets `PendingMessage` which the chat-area\n * consumes on the next render, mirroring the empty-state handoff.\n * - **`SendErrorToAI` channel** — when the runtime preview throws, the\n * state service emits a `ComponentError`. We listen and shove a\n * \"Fix this error: …\" message into the same pendingMessage pipe so\n * the user doesn't have to copy/paste error text.\n *\n * Scoping:\n * - `[applicationScope]=\"'Application'\"` + Component Studio app ID →\n * conversations stay out of main chat (per the migration scoping work).\n * - `[defaultAgentId]` → Codesmith Agent so messages route to the code\n * specialist instead of Sage by default. User can still @mention any\n * agent, override via the per-conversation pin, or pick a different\n * agent through the chat header's picker.\n */\n@Component({\n standalone: false,\n selector: 'mj-ai-assistant-panel',\n templateUrl: './ai-assistant-panel.component.html',\n styleUrls: ['./ai-assistant-panel.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AIAssistantPanelComponent extends BaseAngularComponent implements OnInit, OnDestroy {\n\n /** Quick actions surfaced as buttons above the embedded chat. */\n public QuickActions: QuickAction[] = [\n { Label: 'Fix Errors', Icon: 'fa-bug', Prompt: 'Fix this error: ', RequiresError: true },\n { Label: 'Improve Code', Icon: 'fa-magic', Prompt: 'Review and improve the current component code. Suggest optimizations, better patterns, and cleaner structure.', RequiresError: false },\n { Label: 'Generate Code', Icon: 'fa-code', Prompt: 'Generate code for the current component based on its specification.', RequiresError: false },\n { Label: 'Explain', Icon: 'fa-question-circle', Prompt: 'Explain what the current component does, including its structure, data flow, and key behaviors.', RequiresError: false },\n ];\n\n /** Embedded chat state — same shape the Form Builder cockpit uses. */\n public ChatConversation: MJConversationEntity | null = null;\n public ChatConversationId: string | null = null;\n public ChatIsNewConversation = true;\n public PendingMessage: string | null = null;\n public PendingAttachments: PendingAttachment[] | null = null;\n public ChatThreadId: string | null = null;\n public ChatPendingArtifactId: string | null = null;\n public ChatPendingArtifactVersionNumber: number | null = null;\n\n /** Snapshot from NavigationService — drives the agent's app context. */\n public ChatAppContext: AppContextSnapshot | null = null;\n\n /** Codesmith Agent ID resolved from AIEngineBase cache (no RunView). */\n public CodesmithAgentId: string | null = null;\n\n /** Component Studio's Application ID — resolved from Metadata cache. */\n public CockpitApplicationId: string | null = null;\n\n /**\n * EntityID for `MJ: Components`. Stamped on every conversation\n * created from this panel as the `LinkedEntityID`, paired with the\n * currently-selected Component's ID. Enables \"show prior conversations\n * about THIS component\" later. In-memory Metadata lookup; no RunView.\n */\n public ComponentsEntityID: string | null = null;\n\n /**\n * The DB-backed Component ID currently selected — null when the\n * panel has nothing selected, or when the selection is a\n * file-loaded (transient) component that has no persistent DB row\n * to link conversations to. Used as `[linkedRecordId]` on the\n * embedded chat-area. Pairs with {@link ComponentsEntityID}.\n */\n public get LinkedComponentID(): string | null {\n const sel = this.State.SelectedComponent;\n if (!sel) return null;\n // FileLoadedComponent has `isFileLoaded === true` and a lower-case\n // `id`; DbComponentSummary has the canonical `ID`. Discriminate by\n // the flag rather than property presence to keep TS happy.\n if ('isFileLoaded' in sel && sel.isFileLoaded === true) return null;\n return (sel as { ID: string }).ID ?? null;\n }\n\n private static readonly CODESMITH_AGENT_NAME = 'Codesmith Agent';\n private static readonly COCKPIT_APP_NAME = 'Component Studio';\n\n private readonly destroy$ = new Subject<void>();\n private appContextSubscription: Subscription | null = null;\n\n private readonly cdr = inject(ChangeDetectorRef);\n private readonly navigationService = inject(NavigationService);\n\n constructor(public State: ComponentStudioStateService) {\n super();\n }\n\n public get EnvironmentId(): string {\n return MJEnvironmentEntityExtended.DefaultEnvironmentID;\n }\n\n public get CurrentUser(): UserInfo | null {\n return this.ProviderToUse?.CurrentUser ?? null;\n }\n\n public async ngOnInit(): Promise<void> {\n try {\n // Resolve default agent + cockpit app ID from in-memory caches\n // (no RunView round-trips). Both fall back to null cleanly:\n // missing agent → routes through Sage; missing app → safety\n // guard in chat-area demotes scope to 'Global'.\n await AIEngineBase.Instance.Config(false);\n const codesmith = AIEngineBase.Instance.Agents\n ?.find(a => a.Name?.trim().toLowerCase() === AIAssistantPanelComponent.CODESMITH_AGENT_NAME.toLowerCase());\n this.CodesmithAgentId = codesmith?.ID ?? null;\n if (!codesmith) {\n LogError(`AIAssistantPanel: '${AIAssistantPanelComponent.CODESMITH_AGENT_NAME}' not found in AIEngineBase cache`);\n }\n\n const md = this.ProviderToUse;\n const app = md.Applications?.find(\n a => a.Name?.trim().toLowerCase() === AIAssistantPanelComponent.COCKPIT_APP_NAME.toLowerCase()\n );\n this.CockpitApplicationId = app?.ID ?? null;\n // Resolve MJ: Components entity ID for conversation linkage.\n const componentsEntity = md.EntityByName?.('MJ: Components');\n if (!componentsEntity) {\n LogError(`AIAssistantPanel: Entity 'MJ: Components' not found in Metadata cache — conversation linkage will be skipped.`);\n }\n this.ComponentsEntityID = componentsEntity?.ID ?? null;\n\n // Subscribe to the Explorer shell's app-context publisher so\n // the agent sees the same snapshot the floating overlay sees.\n this.appContextSubscription = this.navigationService.AppContextSnapshot$\n .subscribe(snapshot => {\n this.ChatAppContext = snapshot;\n this.cdr.markForCheck();\n });\n\n // Wire the SendErrorToAI channel — when the runtime preview\n // hits an error, push a canned \"Fix this error: …\" message\n // into the chat-area's pendingMessage pipe so the user\n // doesn't have to manually copy the error text.\n this.State.SendErrorToAI\n .pipe(takeUntil(this.destroy$))\n .subscribe(err => this.handleIncomingError(err));\n this.cdr.markForCheck();\n } catch (err) {\n LogError(`AIAssistantPanel.ngOnInit: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n public ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n this.appContextSubscription?.unsubscribe();\n this.appContextSubscription = null;\n }\n\n /** Collapse the right pane (delegated to the parent dashboard). */\n public OnCollapsePanel(): void {\n this.State.IsAIPanelCollapsed = true;\n this.State.StateChanged.emit();\n }\n\n /** Quick-action click — prefill the chat with the canned prompt. */\n public OnQuickAction(action: QuickAction): void {\n if (action.RequiresError && !this.State.CurrentError) return;\n let prompt = action.Prompt;\n if (action.RequiresError && this.State.CurrentError) {\n prompt += `${this.State.CurrentError.type} - ${this.State.CurrentError.message}`;\n }\n this.PendingMessage = prompt;\n this.PendingAttachments = null;\n this.cdr.markForCheck();\n }\n\n public IsQuickActionEnabled(action: QuickAction): boolean {\n return !action.RequiresError || this.State.CurrentError != null;\n }\n\n /** Runtime preview surfaced an error — auto-send \"Fix this error: …\". */\n private handleIncomingError(error: ComponentError): void {\n const details = error.technicalDetails\n ? (typeof error.technicalDetails === 'string'\n ? error.technicalDetails\n : JSON.stringify(error.technicalDetails, null, 2))\n : '';\n this.PendingMessage = `Fix this error: ${error.type} - ${error.message}${details ? '\\n\\nDetails:\\n' + details : ''}`;\n this.PendingAttachments = null;\n this.cdr.markForCheck();\n }\n\n // ── chat-area event wiring ───────────────────────────────────────\n\n public OnConversationCreated(event: {\n conversation: MJConversationEntity;\n pendingMessage?: string;\n pendingAttachments?: PendingAttachment[];\n }): void {\n this.PendingMessage = event.pendingMessage ?? null;\n this.PendingAttachments = (event.pendingAttachments ?? null) as PendingAttachment[] | null;\n this.ChatConversation = event.conversation;\n this.ChatConversationId = event.conversation.ID;\n this.ChatIsNewConversation = false;\n this.cdr.markForCheck();\n }\n\n public OnPendingMessageConsumed(): void {\n this.PendingMessage = null;\n this.PendingAttachments = null;\n this.cdr.markForCheck();\n }\n\n public OnOpenEntityRecord(event: { entityName: string; compositeKey: CompositeKey }): void {\n try {\n this.navigationService.OpenEntityRecord(event.entityName, event.compositeKey);\n } catch (err) {\n LogError(`AIAssistantPanel.OnOpenEntityRecord: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n public OnNavigationRequest(event: NavigationRequest): void {\n void this.navigationService.OpenNavItemByName(event.navItemName, event.params, event.appId);\n }\n\n public OnTaskClicked(task: MJTaskEntity): void {\n try {\n const key = CompositeKey.FromID(task.ID);\n this.navigationService.OpenEntityRecord('MJ: Tasks', key);\n } catch (err) {\n LogError(`AIAssistantPanel.OnTaskClicked: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n public OnArtifactLinkClicked(event: { type: 'conversation' | 'collection'; id: string }): void {\n const navItemName = event.type === 'conversation' ? 'Conversations' : 'Collections';\n const paramKey = event.type === 'conversation' ? 'conversationId' : 'collectionId';\n void this.navigationService.OpenNavItemByName(navItemName, { [paramKey]: event.id });\n }\n\n public OnConversationRenamed(event: { conversationId: string; name: string; description: string }): void {\n if (this.ChatConversation && UUIDsEqual(this.ChatConversation.ID, event.conversationId)) {\n this.ChatConversation.Name = event.name;\n if (event.description !== undefined) {\n this.ChatConversation.Description = event.description;\n }\n this.cdr.markForCheck();\n }\n }\n\n public OnThreadOpened(threadId: string): void {\n this.ChatThreadId = threadId;\n this.cdr.markForCheck();\n }\n\n public OnThreadClosed(): void {\n this.ChatThreadId = null;\n this.cdr.markForCheck();\n }\n\n public OnPendingArtifactConsumed(): void {\n this.ChatPendingArtifactId = null;\n this.ChatPendingArtifactVersionNumber = null;\n this.cdr.markForCheck();\n }\n}\n","<div class=\"ai-assistant-panel\">\n <!-- Header: title + collapse. Style + classes match the prior bespoke\n chat so the panel chrome lines up with the rest of the cockpit. -->\n <div class=\"panel-header\">\n <div class=\"header-title\">\n <i class=\"fa-solid fa-robot\"></i>\n <span>AI Assistant</span>\n </div>\n <button class=\"collapse-btn\" (click)=\"OnCollapsePanel()\" title=\"Collapse panel\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </button>\n </div>\n\n <!-- Quick Actions: clicking a button stuffs the canned prompt into\n `PendingMessage`, which the chat-area below picks up on its next\n render cycle and sends as if the user typed it. Same mechanism the\n SendErrorToAI handler uses. \"Fix Errors\" disables until an error\n has actually been observed in the runtime preview. -->\n <div class=\"quick-actions\">\n @for (action of QuickActions; track action.Label) {\n <button\n class=\"quick-action-btn\"\n [class.disabled]=\"!IsQuickActionEnabled(action)\"\n [disabled]=\"!IsQuickActionEnabled(action)\"\n (click)=\"OnQuickAction(action)\"\n [title]=\"action.Label\">\n <i class=\"fa-solid {{ action.Icon }}\"></i>\n <span>{{ action.Label }}</span>\n </button>\n }\n </div>\n\n <!-- Embedded chat-area — same primitive the main Chat app and the Form\n Builder cockpit use. Conversations here are scoped to the\n Component Studio app so they don't pollute main chat; the default\n agent is Codesmith (resolved at init from the AIEngineBase cache);\n and the conversation-header agent picker stays enabled so the user\n can switch on the fly. -->\n <div class=\"chat-host\">\n @if (CurrentUser) {\n <mj-conversation-chat-area\n [Provider]=\"Provider\"\n [environmentId]=\"EnvironmentId\"\n [currentUser]=\"CurrentUser\"\n [conversationId]=\"ChatConversationId\"\n [conversation]=\"ChatConversation\"\n [isNewConversation]=\"ChatIsNewConversation\"\n [pendingMessage]=\"PendingMessage\"\n [pendingAttachments]=\"PendingAttachments\"\n [threadId]=\"ChatThreadId\"\n [pendingArtifactId]=\"ChatPendingArtifactId\"\n [pendingArtifactVersionNumber]=\"ChatPendingArtifactVersionNumber\"\n [overlayMode]=\"true\"\n [showExportButton]=\"false\"\n [showShareButton]=\"false\"\n [showArtifactIndicator]=\"false\"\n [appContext]=\"$any(ChatAppContext)\"\n [defaultAgentId]=\"CodesmithAgentId\"\n [applicationScope]=\"'Application'\"\n [applicationId]=\"CockpitApplicationId\"\n [linkedEntityId]=\"ComponentsEntityID\"\n [linkedRecordId]=\"LinkedComponentID\"\n [emptyStateGreeting]=\"'How can I help with this component?'\"\n (conversationCreated)=\"OnConversationCreated($event)\"\n (pendingMessageConsumed)=\"OnPendingMessageConsumed()\"\n (openEntityRecord)=\"OnOpenEntityRecord($event)\"\n (navigationRequest)=\"OnNavigationRequest($event)\"\n (taskClicked)=\"OnTaskClicked($event)\"\n (artifactLinkClicked)=\"OnArtifactLinkClicked($event)\"\n (conversationRenamed)=\"OnConversationRenamed($event)\"\n (threadOpened)=\"OnThreadOpened($event)\"\n (threadClosed)=\"OnThreadClosed()\"\n (pendingArtifactConsumed)=\"OnPendingArtifactConsumed()\">\n </mj-conversation-chat-area>\n } @else {\n <div class=\"chat-host__empty\">Loading…</div>\n }\n </div>\n</div>\n"]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { EventEmitter } from '@angular/core';
|
|
2
|
+
import { CdkDragDrop } from '@angular/cdk/drag-drop';
|
|
3
|
+
import type { CuratedFormSchema } from '@memberjunction/interactive-component-types/forms';
|
|
4
|
+
import type { FormCanvasElement, FormCanvasModel, FormCanvasSection } from '../../services/form-canvas-model';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
/**
|
|
7
|
+
* Visual canvas. Owns the drag-drop UX for sections + elements + palette drops.
|
|
8
|
+
*
|
|
9
|
+
* The canvas itself is presentational — the dashboard owns the model and
|
|
10
|
+
* applies changes here via emitted events. This keeps the canvas focused on
|
|
11
|
+
* UI ergonomics while the dashboard handles dirty tracking, code mirror
|
|
12
|
+
* synchronization, and undo (future).
|
|
13
|
+
*/
|
|
14
|
+
export declare class FormBuilderCanvasComponent {
|
|
15
|
+
private _canvas;
|
|
16
|
+
set Canvas(value: FormCanvasModel | null);
|
|
17
|
+
get Canvas(): FormCanvasModel | null;
|
|
18
|
+
Schema: CuratedFormSchema | null;
|
|
19
|
+
SelectedElementId: string | null;
|
|
20
|
+
SelectedSectionId: string | null;
|
|
21
|
+
/** Emitted when the model changes structurally (drop, delete, reorder, etc.). */
|
|
22
|
+
CanvasChanged: EventEmitter<FormCanvasModel>;
|
|
23
|
+
ElementSelected: EventEmitter<{
|
|
24
|
+
sectionId: string;
|
|
25
|
+
elementId: string;
|
|
26
|
+
}>;
|
|
27
|
+
SectionSelected: EventEmitter<string>;
|
|
28
|
+
Deselected: EventEmitter<void>;
|
|
29
|
+
/**
|
|
30
|
+
* IDs of the section drop lists. Computed once per render so `cdkDropList`
|
|
31
|
+
* `connectedTo` can wire every section to every other section, enabling
|
|
32
|
+
* cross-section drag.
|
|
33
|
+
*/
|
|
34
|
+
get sectionListIds(): string[];
|
|
35
|
+
private readonly cdr;
|
|
36
|
+
OnAddSection(): void;
|
|
37
|
+
OnAddStaticElement(sectionId: string, kind: 'static-text' | 'spacer' | 'computed'): void;
|
|
38
|
+
OnDropElement(event: CdkDragDrop<FormCanvasElement[]>, sectionId: string): void;
|
|
39
|
+
OnDropSection(event: CdkDragDrop<FormCanvasSection[]>): void;
|
|
40
|
+
/** Native-DnD fallback for palette → section drop (palette uses HTML5 DnD). */
|
|
41
|
+
OnNativeDragOver(event: DragEvent): void;
|
|
42
|
+
OnNativeDrop(event: DragEvent, sectionId: string): void;
|
|
43
|
+
OnElementClick(sectionId: string, elementId: string, event: Event): void;
|
|
44
|
+
OnSectionHeaderClick(sectionId: string, event: Event): void;
|
|
45
|
+
OnCanvasBackgroundClick(): void;
|
|
46
|
+
OnTitleInput(event: Event): void;
|
|
47
|
+
getLabelForElement(element: FormCanvasElement): string;
|
|
48
|
+
getFieldTypeBadge(element: FormCanvasElement): string | null;
|
|
49
|
+
isFieldUnknown(element: FormCanvasElement): boolean;
|
|
50
|
+
private fieldDisplayName;
|
|
51
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<FormBuilderCanvasComponent, never>;
|
|
52
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<FormBuilderCanvasComponent, "mj-form-builder-canvas", never, { "Canvas": { "alias": "Canvas"; "required": false; }; "Schema": { "alias": "Schema"; "required": false; }; "SelectedElementId": { "alias": "SelectedElementId"; "required": false; }; "SelectedSectionId": { "alias": "SelectedSectionId"; "required": false; }; }, { "CanvasChanged": "CanvasChanged"; "ElementSelected": "ElementSelected"; "SectionSelected": "SectionSelected"; "Deselected": "Deselected"; }, never, never, false, never>;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=form-builder-canvas.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-builder-canvas.component.d.ts","sourceRoot":"","sources":["../../../../src/ComponentStudio/components/form-builder/form-builder-canvas.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,YAAY,EAIf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAsC,MAAM,wBAAwB,CAAC;AACzF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mDAAmD,CAAC;AAC3F,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;;AAG9G;;;;;;;GAOG;AACH,qBAOa,0BAA0B;IACnC,OAAO,CAAC,OAAO,CAAgC;IAC/C,IACI,MAAM,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,EAGvC;IACD,IAAI,MAAM,IAAI,eAAe,GAAG,IAAI,CAEnC;IAEQ,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAQ;IACxC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAQ;IACxC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEjD,iFAAiF;IACvE,aAAa,gCAAuC;IACpD,eAAe;mBAAiC,MAAM;mBAAa,MAAM;OAAM;IAC/E,eAAe,uBAA8B;IAC7C,UAAU,qBAA4B;IAEhD;;;;OAIG;IACH,IAAW,cAAc,IAAI,MAAM,EAAE,CAEpC;IAED,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IAE1C,YAAY,IAAI,IAAI;IASpB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,QAAQ,GAAG,UAAU,GAAG,IAAI;IAexF,aAAa,CAAC,KAAK,EAAE,WAAW,CAAC,iBAAiB,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAoC/E,aAAa,CAAC,KAAK,EAAE,WAAW,CAAC,iBAAiB,EAAE,CAAC,GAAG,IAAI;IAOnE,+EAA+E;IACxE,gBAAgB,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAMxC,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAgBvD,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAKxE,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAK3D,uBAAuB,IAAI,IAAI;IAI/B,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAMhC,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM;IAUtD,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI;IAQ5D,cAAc,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO;IAK1D,OAAO,CAAC,gBAAgB;yCArKf,0BAA0B;2CAA1B,0BAA0B;CAwKtC"}
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import { Component, ChangeDetectionStrategy, ChangeDetectorRef, EventEmitter, Input, Output, inject, } from '@angular/core';
|
|
2
|
+
import { moveItemInArray } from '@angular/cdk/drag-drop';
|
|
3
|
+
import { buildEmptySection, generateCanvasId } from '../../services/form-canvas-model';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
import * as i1 from "@angular/cdk/drag-drop";
|
|
6
|
+
const _forTrack0 = ($index, $item) => $item.id;
|
|
7
|
+
function FormBuilderCanvasComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
8
|
+
i0.ɵɵelementStart(0, "div", 1);
|
|
9
|
+
i0.ɵɵelement(1, "i", 2);
|
|
10
|
+
i0.ɵɵelementStart(2, "h3");
|
|
11
|
+
i0.ɵɵtext(3, "No form loaded");
|
|
12
|
+
i0.ɵɵelementEnd();
|
|
13
|
+
i0.ɵɵelementStart(4, "p");
|
|
14
|
+
i0.ɵɵtext(5, "Pick an entity from the toolbar to start a new form, or select one from the left panel.");
|
|
15
|
+
i0.ɵɵelementEnd()();
|
|
16
|
+
} }
|
|
17
|
+
function FormBuilderCanvasComponent_Conditional_2_For_7_For_15_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
18
|
+
i0.ɵɵelementStart(0, "span", 31);
|
|
19
|
+
i0.ɵɵtext(1);
|
|
20
|
+
i0.ɵɵelementEnd();
|
|
21
|
+
} if (rf & 2) {
|
|
22
|
+
i0.ɵɵadvance();
|
|
23
|
+
i0.ɵɵtextInterpolate(ctx);
|
|
24
|
+
} }
|
|
25
|
+
function FormBuilderCanvasComponent_Conditional_2_For_7_For_15_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
26
|
+
i0.ɵɵelementStart(0, "span", 32);
|
|
27
|
+
i0.ɵɵelement(1, "i", 33);
|
|
28
|
+
i0.ɵɵtext(2, " not in schema ");
|
|
29
|
+
i0.ɵɵelementEnd();
|
|
30
|
+
} }
|
|
31
|
+
function FormBuilderCanvasComponent_Conditional_2_For_7_For_15_Template(rf, ctx) { if (rf & 1) {
|
|
32
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
33
|
+
i0.ɵɵelementStart(0, "div", 26);
|
|
34
|
+
i0.ɵɵlistener("click", function FormBuilderCanvasComponent_Conditional_2_For_7_For_15_Template_div_click_0_listener($event) { const element_r6 = i0.ɵɵrestoreView(_r5).$implicit; const section_r4 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnElementClick(section_r4.id, element_r6.id, $event)); });
|
|
35
|
+
i0.ɵɵelementStart(1, "span", 27);
|
|
36
|
+
i0.ɵɵelement(2, "i", 14);
|
|
37
|
+
i0.ɵɵelementEnd();
|
|
38
|
+
i0.ɵɵelementStart(3, "div", 28)(4, "div", 29);
|
|
39
|
+
i0.ɵɵtext(5);
|
|
40
|
+
i0.ɵɵelementEnd();
|
|
41
|
+
i0.ɵɵelementStart(6, "div", 30);
|
|
42
|
+
i0.ɵɵconditionalCreate(7, FormBuilderCanvasComponent_Conditional_2_For_7_For_15_Conditional_7_Template, 2, 1, "span", 31);
|
|
43
|
+
i0.ɵɵconditionalCreate(8, FormBuilderCanvasComponent_Conditional_2_For_7_For_15_Conditional_8_Template, 3, 0, "span", 32);
|
|
44
|
+
i0.ɵɵelementEnd()()();
|
|
45
|
+
} if (rf & 2) {
|
|
46
|
+
let tmp_25_0;
|
|
47
|
+
const element_r6 = ctx.$implicit;
|
|
48
|
+
const section_r4 = i0.ɵɵnextContext().$implicit;
|
|
49
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
50
|
+
i0.ɵɵclassProp("span-2", element_r6.span === 2 && section_r4.columns === 2)("selected", ctx_r1.SelectedElementId === element_r6.id)("unknown-field", ctx_r1.isFieldUnknown(element_r6));
|
|
51
|
+
i0.ɵɵadvance(5);
|
|
52
|
+
i0.ɵɵtextInterpolate(ctx_r1.getLabelForElement(element_r6));
|
|
53
|
+
i0.ɵɵadvance(2);
|
|
54
|
+
i0.ɵɵconditional((tmp_25_0 = ctx_r1.getFieldTypeBadge(element_r6)) ? 7 : -1, tmp_25_0);
|
|
55
|
+
i0.ɵɵadvance();
|
|
56
|
+
i0.ɵɵconditional(ctx_r1.isFieldUnknown(element_r6) ? 8 : -1);
|
|
57
|
+
} }
|
|
58
|
+
function FormBuilderCanvasComponent_Conditional_2_For_7_ForEmpty_16_Template(rf, ctx) { if (rf & 1) {
|
|
59
|
+
i0.ɵɵelementStart(0, "div", 25);
|
|
60
|
+
i0.ɵɵtext(1, " Drag a field here, or use the buttons above to add static elements. ");
|
|
61
|
+
i0.ɵɵelementEnd();
|
|
62
|
+
} }
|
|
63
|
+
function FormBuilderCanvasComponent_Conditional_2_For_7_Template(rf, ctx) { if (rf & 1) {
|
|
64
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
65
|
+
i0.ɵɵelementStart(0, "div", 11);
|
|
66
|
+
i0.ɵɵlistener("click", function FormBuilderCanvasComponent_Conditional_2_For_7_Template_div_click_0_listener($event) { i0.ɵɵrestoreView(_r3); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
67
|
+
i0.ɵɵelementStart(1, "header", 12);
|
|
68
|
+
i0.ɵɵlistener("click", function FormBuilderCanvasComponent_Conditional_2_For_7_Template_header_click_1_listener($event) { const section_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnSectionHeaderClick(section_r4.id, $event)); });
|
|
69
|
+
i0.ɵɵelementStart(2, "span", 13);
|
|
70
|
+
i0.ɵɵelement(3, "i", 14);
|
|
71
|
+
i0.ɵɵelementEnd();
|
|
72
|
+
i0.ɵɵelementStart(4, "h3", 15);
|
|
73
|
+
i0.ɵɵtext(5);
|
|
74
|
+
i0.ɵɵelementEnd();
|
|
75
|
+
i0.ɵɵelementStart(6, "div", 16)(7, "button", 17);
|
|
76
|
+
i0.ɵɵlistener("click", function FormBuilderCanvasComponent_Conditional_2_For_7_Template_button_click_7_listener($event) { const section_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); ctx_r1.OnAddStaticElement(section_r4.id, "static-text"); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
77
|
+
i0.ɵɵelement(8, "i", 18);
|
|
78
|
+
i0.ɵɵelementEnd();
|
|
79
|
+
i0.ɵɵelementStart(9, "button", 19);
|
|
80
|
+
i0.ɵɵlistener("click", function FormBuilderCanvasComponent_Conditional_2_For_7_Template_button_click_9_listener($event) { const section_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); ctx_r1.OnAddStaticElement(section_r4.id, "computed"); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
81
|
+
i0.ɵɵelement(10, "i", 20);
|
|
82
|
+
i0.ɵɵelementEnd();
|
|
83
|
+
i0.ɵɵelementStart(11, "button", 21);
|
|
84
|
+
i0.ɵɵlistener("click", function FormBuilderCanvasComponent_Conditional_2_For_7_Template_button_click_11_listener($event) { const section_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); ctx_r1.OnAddStaticElement(section_r4.id, "spacer"); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
85
|
+
i0.ɵɵelement(12, "i", 22);
|
|
86
|
+
i0.ɵɵelementEnd()()();
|
|
87
|
+
i0.ɵɵelementStart(13, "div", 23);
|
|
88
|
+
i0.ɵɵlistener("cdkDropListDropped", function FormBuilderCanvasComponent_Conditional_2_For_7_Template_div_cdkDropListDropped_13_listener($event) { const section_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnDropElement($event, section_r4.id)); })("dragover", function FormBuilderCanvasComponent_Conditional_2_For_7_Template_div_dragover_13_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnNativeDragOver($event)); })("drop", function FormBuilderCanvasComponent_Conditional_2_For_7_Template_div_drop_13_listener($event) { const section_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnNativeDrop($event, section_r4.id)); });
|
|
89
|
+
i0.ɵɵrepeaterCreate(14, FormBuilderCanvasComponent_Conditional_2_For_7_For_15_Template, 9, 9, "div", 24, _forTrack0, false, FormBuilderCanvasComponent_Conditional_2_For_7_ForEmpty_16_Template, 2, 0, "div", 25);
|
|
90
|
+
i0.ɵɵelementEnd()();
|
|
91
|
+
} if (rf & 2) {
|
|
92
|
+
const section_r4 = ctx.$implicit;
|
|
93
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
94
|
+
i0.ɵɵclassProp("selected", ctx_r1.SelectedSectionId === section_r4.id);
|
|
95
|
+
i0.ɵɵadvance(5);
|
|
96
|
+
i0.ɵɵtextInterpolate(section_r4.title || "Untitled Section");
|
|
97
|
+
i0.ɵɵadvance(8);
|
|
98
|
+
i0.ɵɵclassProp("cols-2", section_r4.columns === 2);
|
|
99
|
+
i0.ɵɵproperty("id", "section-" + section_r4.id)("cdkDropListConnectedTo", ctx_r1.sectionListIds)("cdkDropListData", section_r4.elements);
|
|
100
|
+
i0.ɵɵadvance();
|
|
101
|
+
i0.ɵɵrepeater(section_r4.elements);
|
|
102
|
+
} }
|
|
103
|
+
function FormBuilderCanvasComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
104
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
105
|
+
i0.ɵɵelementStart(0, "div", 3);
|
|
106
|
+
i0.ɵɵlistener("click", function FormBuilderCanvasComponent_Conditional_2_Template_div_click_0_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
107
|
+
i0.ɵɵelementStart(1, "input", 4);
|
|
108
|
+
i0.ɵɵlistener("input", function FormBuilderCanvasComponent_Conditional_2_Template_input_input_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnTitleInput($event)); });
|
|
109
|
+
i0.ɵɵelementEnd();
|
|
110
|
+
i0.ɵɵelementStart(2, "span", 5);
|
|
111
|
+
i0.ɵɵelement(3, "i", 6);
|
|
112
|
+
i0.ɵɵtext(4);
|
|
113
|
+
i0.ɵɵelementEnd()();
|
|
114
|
+
i0.ɵɵelementStart(5, "div", 7);
|
|
115
|
+
i0.ɵɵlistener("cdkDropListDropped", function FormBuilderCanvasComponent_Conditional_2_Template_div_cdkDropListDropped_5_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDropSection($event)); });
|
|
116
|
+
i0.ɵɵrepeaterCreate(6, FormBuilderCanvasComponent_Conditional_2_For_7_Template, 17, 9, "div", 8, _forTrack0);
|
|
117
|
+
i0.ɵɵelementEnd();
|
|
118
|
+
i0.ɵɵelementStart(8, "button", 9);
|
|
119
|
+
i0.ɵɵlistener("click", function FormBuilderCanvasComponent_Conditional_2_Template_button_click_8_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.OnAddSection(); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
120
|
+
i0.ɵɵelement(9, "i", 10);
|
|
121
|
+
i0.ɵɵtext(10, " Add Section ");
|
|
122
|
+
i0.ɵɵelementEnd();
|
|
123
|
+
} if (rf & 2) {
|
|
124
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
125
|
+
i0.ɵɵadvance();
|
|
126
|
+
i0.ɵɵproperty("value", ctx_r1.Canvas.title ?? "");
|
|
127
|
+
i0.ɵɵadvance(3);
|
|
128
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.Canvas.entityName, " ");
|
|
129
|
+
i0.ɵɵadvance(2);
|
|
130
|
+
i0.ɵɵrepeater(ctx_r1.Canvas.sections);
|
|
131
|
+
} }
|
|
132
|
+
/**
|
|
133
|
+
* Visual canvas. Owns the drag-drop UX for sections + elements + palette drops.
|
|
134
|
+
*
|
|
135
|
+
* The canvas itself is presentational — the dashboard owns the model and
|
|
136
|
+
* applies changes here via emitted events. This keeps the canvas focused on
|
|
137
|
+
* UI ergonomics while the dashboard handles dirty tracking, code mirror
|
|
138
|
+
* synchronization, and undo (future).
|
|
139
|
+
*/
|
|
140
|
+
export class FormBuilderCanvasComponent {
|
|
141
|
+
_canvas = null;
|
|
142
|
+
set Canvas(value) {
|
|
143
|
+
this._canvas = value;
|
|
144
|
+
this.cdr.markForCheck();
|
|
145
|
+
}
|
|
146
|
+
get Canvas() {
|
|
147
|
+
return this._canvas;
|
|
148
|
+
}
|
|
149
|
+
Schema = null;
|
|
150
|
+
SelectedElementId = null;
|
|
151
|
+
SelectedSectionId = null;
|
|
152
|
+
/** Emitted when the model changes structurally (drop, delete, reorder, etc.). */
|
|
153
|
+
CanvasChanged = new EventEmitter();
|
|
154
|
+
ElementSelected = new EventEmitter();
|
|
155
|
+
SectionSelected = new EventEmitter();
|
|
156
|
+
Deselected = new EventEmitter();
|
|
157
|
+
/**
|
|
158
|
+
* IDs of the section drop lists. Computed once per render so `cdkDropList`
|
|
159
|
+
* `connectedTo` can wire every section to every other section, enabling
|
|
160
|
+
* cross-section drag.
|
|
161
|
+
*/
|
|
162
|
+
get sectionListIds() {
|
|
163
|
+
return (this._canvas?.sections ?? []).map(s => `section-${s.id}`);
|
|
164
|
+
}
|
|
165
|
+
cdr = inject(ChangeDetectorRef);
|
|
166
|
+
OnAddSection() {
|
|
167
|
+
if (!this._canvas)
|
|
168
|
+
return;
|
|
169
|
+
const next = {
|
|
170
|
+
...this._canvas,
|
|
171
|
+
sections: [...this._canvas.sections, buildEmptySection()],
|
|
172
|
+
};
|
|
173
|
+
this.CanvasChanged.emit(next);
|
|
174
|
+
}
|
|
175
|
+
OnAddStaticElement(sectionId, kind) {
|
|
176
|
+
if (!this._canvas)
|
|
177
|
+
return;
|
|
178
|
+
const next = mutateSection(this._canvas, sectionId, s => ({
|
|
179
|
+
...s,
|
|
180
|
+
elements: [...s.elements, {
|
|
181
|
+
id: generateCanvasId(kind),
|
|
182
|
+
type: kind,
|
|
183
|
+
text: kind === 'static-text' ? 'Static text' : undefined,
|
|
184
|
+
expression: kind === 'computed' ? 'record?.ID' : undefined,
|
|
185
|
+
label: kind === 'computed' ? 'Computed' : undefined,
|
|
186
|
+
}],
|
|
187
|
+
}));
|
|
188
|
+
this.CanvasChanged.emit(next);
|
|
189
|
+
}
|
|
190
|
+
OnDropElement(event, sectionId) {
|
|
191
|
+
if (!this._canvas)
|
|
192
|
+
return;
|
|
193
|
+
// Internal reorder within the same section.
|
|
194
|
+
if (event.previousContainer === event.container) {
|
|
195
|
+
const next = mutateSection(this._canvas, sectionId, s => {
|
|
196
|
+
const elements = [...s.elements];
|
|
197
|
+
moveItemInArray(elements, event.previousIndex, event.currentIndex);
|
|
198
|
+
return { ...s, elements };
|
|
199
|
+
});
|
|
200
|
+
this.CanvasChanged.emit(next);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
// Cross-section move: extract from source, insert into target.
|
|
204
|
+
const sourceId = event.previousContainer.id.replace('section-', '');
|
|
205
|
+
const sourceSection = this._canvas.sections.find(s => s.id === sourceId);
|
|
206
|
+
if (!sourceSection)
|
|
207
|
+
return;
|
|
208
|
+
const moved = sourceSection.elements[event.previousIndex];
|
|
209
|
+
if (!moved)
|
|
210
|
+
return;
|
|
211
|
+
const next = {
|
|
212
|
+
...this._canvas,
|
|
213
|
+
sections: this._canvas.sections.map(s => {
|
|
214
|
+
if (s.id === sourceId) {
|
|
215
|
+
return { ...s, elements: s.elements.filter((_, i) => i !== event.previousIndex) };
|
|
216
|
+
}
|
|
217
|
+
if (s.id === sectionId) {
|
|
218
|
+
const elements = [...s.elements];
|
|
219
|
+
elements.splice(event.currentIndex, 0, moved);
|
|
220
|
+
return { ...s, elements };
|
|
221
|
+
}
|
|
222
|
+
return s;
|
|
223
|
+
}),
|
|
224
|
+
};
|
|
225
|
+
this.CanvasChanged.emit(next);
|
|
226
|
+
}
|
|
227
|
+
OnDropSection(event) {
|
|
228
|
+
if (!this._canvas)
|
|
229
|
+
return;
|
|
230
|
+
const sections = [...this._canvas.sections];
|
|
231
|
+
moveItemInArray(sections, event.previousIndex, event.currentIndex);
|
|
232
|
+
this.CanvasChanged.emit({ ...this._canvas, sections });
|
|
233
|
+
}
|
|
234
|
+
/** Native-DnD fallback for palette → section drop (palette uses HTML5 DnD). */
|
|
235
|
+
OnNativeDragOver(event) {
|
|
236
|
+
if (event.dataTransfer?.types.includes('text/x-mj-form-field')) {
|
|
237
|
+
event.preventDefault();
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
OnNativeDrop(event, sectionId) {
|
|
241
|
+
const fieldName = event.dataTransfer?.getData('text/x-mj-form-field');
|
|
242
|
+
if (!fieldName || !this._canvas)
|
|
243
|
+
return;
|
|
244
|
+
event.preventDefault();
|
|
245
|
+
const next = mutateSection(this._canvas, sectionId, s => ({
|
|
246
|
+
...s,
|
|
247
|
+
elements: [...s.elements, {
|
|
248
|
+
id: generateCanvasId('field'),
|
|
249
|
+
type: 'field',
|
|
250
|
+
fieldName,
|
|
251
|
+
span: 1,
|
|
252
|
+
}],
|
|
253
|
+
}));
|
|
254
|
+
this.CanvasChanged.emit(next);
|
|
255
|
+
}
|
|
256
|
+
OnElementClick(sectionId, elementId, event) {
|
|
257
|
+
event.stopPropagation();
|
|
258
|
+
this.ElementSelected.emit({ sectionId, elementId });
|
|
259
|
+
}
|
|
260
|
+
OnSectionHeaderClick(sectionId, event) {
|
|
261
|
+
event.stopPropagation();
|
|
262
|
+
this.SectionSelected.emit(sectionId);
|
|
263
|
+
}
|
|
264
|
+
OnCanvasBackgroundClick() {
|
|
265
|
+
this.Deselected.emit();
|
|
266
|
+
}
|
|
267
|
+
OnTitleInput(event) {
|
|
268
|
+
if (!this._canvas)
|
|
269
|
+
return;
|
|
270
|
+
const v = event.target.value;
|
|
271
|
+
this.CanvasChanged.emit({ ...this._canvas, title: v });
|
|
272
|
+
}
|
|
273
|
+
getLabelForElement(element) {
|
|
274
|
+
if (element.type === 'static-text')
|
|
275
|
+
return element.text ?? 'Static text';
|
|
276
|
+
if (element.type === 'spacer')
|
|
277
|
+
return 'Spacer';
|
|
278
|
+
if (element.type === 'computed')
|
|
279
|
+
return element.label ?? 'Computed';
|
|
280
|
+
if (element.type === 'field' && element.fieldName) {
|
|
281
|
+
return element.label ?? this.fieldDisplayName(element.fieldName);
|
|
282
|
+
}
|
|
283
|
+
return element.fieldName ?? '(unknown)';
|
|
284
|
+
}
|
|
285
|
+
getFieldTypeBadge(element) {
|
|
286
|
+
if (element.type === 'field' && element.fieldName) {
|
|
287
|
+
const f = this.Schema?.fields.find(fld => fld.name === element.fieldName);
|
|
288
|
+
return f?.type ?? null;
|
|
289
|
+
}
|
|
290
|
+
return element.type;
|
|
291
|
+
}
|
|
292
|
+
isFieldUnknown(element) {
|
|
293
|
+
if (element.type !== 'field' || !element.fieldName)
|
|
294
|
+
return false;
|
|
295
|
+
return !this.Schema?.fields.some(f => f.name === element.fieldName);
|
|
296
|
+
}
|
|
297
|
+
fieldDisplayName(name) {
|
|
298
|
+
return this.Schema?.fields.find(f => f.name === name)?.displayName ?? name;
|
|
299
|
+
}
|
|
300
|
+
static ɵfac = function FormBuilderCanvasComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || FormBuilderCanvasComponent)(); };
|
|
301
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: FormBuilderCanvasComponent, selectors: [["mj-form-builder-canvas"]], inputs: { Canvas: "Canvas", Schema: "Schema", SelectedElementId: "SelectedElementId", SelectedSectionId: "SelectedSectionId" }, outputs: { CanvasChanged: "CanvasChanged", ElementSelected: "ElementSelected", SectionSelected: "SectionSelected", Deselected: "Deselected" }, standalone: false, decls: 3, vars: 1, consts: [[1, "canvas-root", 3, "click"], [1, "canvas-empty"], [1, "fa-solid", "fa-table-list"], [1, "canvas-title-row", 3, "click"], ["type", "text", "placeholder", "Untitled form", 1, "canvas-title", 3, "input", "value"], [1, "canvas-entity-badge"], [1, "fa-solid", "fa-table"], ["cdkDropList", "", "cdkDropListOrientation", "vertical", 1, "canvas-sections-host", 3, "cdkDropListDropped"], ["cdkDrag", "", 1, "canvas-section", 3, "selected"], [1, "add-section-btn", 3, "click"], [1, "fa-solid", "fa-plus"], ["cdkDrag", "", 1, "canvas-section", 3, "click"], [1, "section-header", 3, "click"], ["cdkDragHandle", "", "title", "Drag to reorder", 1, "section-drag-handle"], [1, "fa-solid", "fa-grip-vertical"], [1, "section-title"], [1, "section-actions"], ["title", "Add static text", 1, "mini-btn", 3, "click"], [1, "fa-solid", "fa-font"], ["title", "Add computed field", 1, "mini-btn", 3, "click"], [1, "fa-solid", "fa-calculator"], ["title", "Add spacer", 1, "mini-btn", 3, "click"], [1, "fa-solid", "fa-arrows-up-down"], ["cdkDropList", "", 1, "section-grid", 3, "cdkDropListDropped", "dragover", "drop", "id", "cdkDropListConnectedTo", "cdkDropListData"], ["cdkDrag", "", 1, "canvas-element", 3, "span-2", "selected", "unknown-field"], [1, "section-drop-empty"], ["cdkDrag", "", 1, "canvas-element", 3, "click"], ["cdkDragHandle", "", "title", "Drag to move", 1, "element-drag-handle"], [1, "element-body"], [1, "element-label"], [1, "element-meta"], [1, "element-type-badge"], ["title", "Field not in current schema \u2014 will be skipped at code generation", 1, "element-warn"], [1, "fa-solid", "fa-triangle-exclamation"]], template: function FormBuilderCanvasComponent_Template(rf, ctx) { if (rf & 1) {
|
|
302
|
+
i0.ɵɵelementStart(0, "div", 0);
|
|
303
|
+
i0.ɵɵlistener("click", function FormBuilderCanvasComponent_Template_div_click_0_listener() { return ctx.OnCanvasBackgroundClick(); });
|
|
304
|
+
i0.ɵɵconditionalCreate(1, FormBuilderCanvasComponent_Conditional_1_Template, 6, 0, "div", 1)(2, FormBuilderCanvasComponent_Conditional_2_Template, 11, 2);
|
|
305
|
+
i0.ɵɵelementEnd();
|
|
306
|
+
} if (rf & 2) {
|
|
307
|
+
i0.ɵɵadvance();
|
|
308
|
+
i0.ɵɵconditional(!ctx.Canvas ? 1 : 2);
|
|
309
|
+
} }, dependencies: [i1.CdkDropList, i1.CdkDrag, i1.CdkDragHandle], styles: ["[_nghost-%COMP%] { display: block; height: 100%; overflow: hidden; }\n\n.canvas-root[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n padding: 20px 28px;\n overflow-y: auto;\n background: var(--mj-bg-page);\n gap: 16px;\n}\n\n.canvas-empty[_ngcontent-%COMP%] {\n margin: auto;\n text-align: center;\n max-width: 380px;\n color: var(--mj-text-muted);\n}\n.canvas-empty[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 36px; margin-bottom: 12px; color: var(--mj-text-disabled); }\n.canvas-empty[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { margin: 0 0 6px; font-size: 16px; color: var(--mj-text-primary); }\n.canvas-empty[_ngcontent-%COMP%] p[_ngcontent-%COMP%] { margin: 0; font-size: 13px; line-height: 1.5; }\n\n.canvas-title-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding-bottom: 4px;\n flex-shrink: 0;\n}\n.canvas-title[_ngcontent-%COMP%] {\n flex: 1;\n border: 1px solid transparent;\n background: transparent;\n color: var(--mj-text-primary);\n font-size: 22px;\n font-weight: 600;\n padding: 6px 8px;\n border-radius: 4px;\n}\n.canvas-title[_ngcontent-%COMP%]:hover, .canvas-title[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface);\n outline: none;\n}\n.canvas-entity-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--mj-brand-primary);\n border-radius: 999px;\n font-size: 12px;\n}\n\n.canvas-sections-host[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 14px; }\n\n.canvas-section[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow: hidden;\n transition: border-color 0.1s;\n}\n.canvas-section.selected[_ngcontent-%COMP%] { border-color: var(--mj-brand-primary); }\n\n.section-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n}\n.section-header[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-hover); }\n.section-drag-handle[_ngcontent-%COMP%], .element-drag-handle[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n cursor: grab;\n padding: 2px 4px;\n}\n.section-drag-handle[_ngcontent-%COMP%]:hover, .element-drag-handle[_ngcontent-%COMP%]:hover { color: var(--mj-text-secondary); }\n.section-title[_ngcontent-%COMP%] {\n flex: 1;\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-text-secondary);\n}\n.section-actions[_ngcontent-%COMP%] { display: flex; gap: 4px; }\n.mini-btn[_ngcontent-%COMP%] {\n background: transparent;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n padding: 4px 8px;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 11px;\n}\n.mini-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-strong);\n}\n\n.section-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr;\n gap: 10px;\n padding: 12px;\n min-height: 60px;\n}\n.section-grid.cols-2[_ngcontent-%COMP%] { grid-template-columns: 1fr 1fr; }\n\n.section-drop-empty[_ngcontent-%COMP%] {\n grid-column: 1 / -1;\n padding: 18px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 12px;\n border: 1px dashed var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface-card);\n}\n\n.canvas-element[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n transition: border-color 0.1s, background 0.1s;\n}\n.canvas-element[_ngcontent-%COMP%]:hover { border-color: var(--mj-border-strong); background: var(--mj-bg-surface-hover); }\n.canvas-element.selected[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n}\n.canvas-element.unknown-field[_ngcontent-%COMP%] { border-color: var(--mj-status-warning); }\n.canvas-element.span-2[_ngcontent-%COMP%] { grid-column: span 2; }\n\n.element-body[_ngcontent-%COMP%] { flex: 1; min-width: 0; }\n.element-label[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.element-meta[_ngcontent-%COMP%] { display: flex; gap: 6px; margin-top: 3px; flex-wrap: wrap; }\n.element-type-badge[_ngcontent-%COMP%] {\n padding: 1px 6px;\n font-size: 10px;\n border-radius: 999px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n.element-warn[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-status-warning-text);\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.add-section-btn[_ngcontent-%COMP%] {\n align-self: flex-start;\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 8px 14px;\n border: 1px dashed var(--mj-border-strong);\n border-radius: 6px;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 13px;\n cursor: pointer;\n transition: border-color 0.1s, background 0.1s;\n}\n.add-section-btn[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 4%, transparent);\n}\n\n\n\n.cdk-drag-preview[_ngcontent-%COMP%] {\n box-shadow: 0 5px 16px rgba(0,0,0,0.2);\n border-radius: 4px;\n}\n.cdk-drag-placeholder[_ngcontent-%COMP%] {\n opacity: 0.4;\n background: var(--mj-bg-surface-sunken);\n border: 1px dashed var(--mj-brand-primary);\n min-height: 36px;\n border-radius: 4px;\n}\n.cdk-drag-animating[_ngcontent-%COMP%] { transition: transform 200ms cubic-bezier(0, 0, 0.2, 1); }\n.section-grid.cdk-drop-list-dragging[_ngcontent-%COMP%] .canvas-element[_ngcontent-%COMP%]:not(.cdk-drag-placeholder) {\n transition: transform 200ms cubic-bezier(0, 0, 0.2, 1);\n}"], changeDetection: 0 });
|
|
310
|
+
}
|
|
311
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(FormBuilderCanvasComponent, [{
|
|
312
|
+
type: Component,
|
|
313
|
+
args: [{ standalone: false, selector: 'mj-form-builder-canvas', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"canvas-root\" (click)=\"OnCanvasBackgroundClick()\">\n\n @if (!Canvas) {\n <div class=\"canvas-empty\">\n <i class=\"fa-solid fa-table-list\"></i>\n <h3>No form loaded</h3>\n <p>Pick an entity from the toolbar to start a new form, or select one from the left panel.</p>\n </div>\n } @else {\n <div class=\"canvas-title-row\" (click)=\"$event.stopPropagation()\">\n <input class=\"canvas-title\" type=\"text\"\n placeholder=\"Untitled form\"\n [value]=\"Canvas.title ?? ''\" (input)=\"OnTitleInput($event)\" />\n <span class=\"canvas-entity-badge\">\n <i class=\"fa-solid fa-table\"></i> {{ Canvas.entityName }}\n </span>\n </div>\n\n <div cdkDropList\n cdkDropListOrientation=\"vertical\"\n (cdkDropListDropped)=\"OnDropSection($event)\"\n class=\"canvas-sections-host\">\n\n @for (section of Canvas.sections; track section.id) {\n <div class=\"canvas-section\"\n cdkDrag\n [class.selected]=\"SelectedSectionId === section.id\"\n (click)=\"$event.stopPropagation()\">\n\n <header class=\"section-header\" (click)=\"OnSectionHeaderClick(section.id, $event)\">\n <span class=\"section-drag-handle\" cdkDragHandle title=\"Drag to reorder\">\n <i class=\"fa-solid fa-grip-vertical\"></i>\n </span>\n <h3 class=\"section-title\">{{ section.title || 'Untitled Section' }}</h3>\n <div class=\"section-actions\">\n <button class=\"mini-btn\" title=\"Add static text\"\n (click)=\"OnAddStaticElement(section.id, 'static-text'); $event.stopPropagation()\">\n <i class=\"fa-solid fa-font\"></i>\n </button>\n <button class=\"mini-btn\" title=\"Add computed field\"\n (click)=\"OnAddStaticElement(section.id, 'computed'); $event.stopPropagation()\">\n <i class=\"fa-solid fa-calculator\"></i>\n </button>\n <button class=\"mini-btn\" title=\"Add spacer\"\n (click)=\"OnAddStaticElement(section.id, 'spacer'); $event.stopPropagation()\">\n <i class=\"fa-solid fa-arrows-up-down\"></i>\n </button>\n </div>\n </header>\n\n <div class=\"section-grid\"\n [class.cols-2]=\"section.columns === 2\"\n cdkDropList\n [id]=\"'section-' + section.id\"\n [cdkDropListConnectedTo]=\"sectionListIds\"\n [cdkDropListData]=\"section.elements\"\n (cdkDropListDropped)=\"OnDropElement($event, section.id)\"\n (dragover)=\"OnNativeDragOver($event)\"\n (drop)=\"OnNativeDrop($event, section.id)\">\n\n @for (element of section.elements; track element.id) {\n <div class=\"canvas-element\"\n cdkDrag\n [class.span-2]=\"element.span === 2 && section.columns === 2\"\n [class.selected]=\"SelectedElementId === element.id\"\n [class.unknown-field]=\"isFieldUnknown(element)\"\n (click)=\"OnElementClick(section.id, element.id, $event)\">\n <span class=\"element-drag-handle\" cdkDragHandle title=\"Drag to move\">\n <i class=\"fa-solid fa-grip-vertical\"></i>\n </span>\n <div class=\"element-body\">\n <div class=\"element-label\">{{ getLabelForElement(element) }}</div>\n <div class=\"element-meta\">\n @if (getFieldTypeBadge(element); as badge) {\n <span class=\"element-type-badge\">{{ badge }}</span>\n }\n @if (isFieldUnknown(element)) {\n <span class=\"element-warn\"\n title=\"Field not in current schema \u2014 will be skipped at code generation\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i> not in schema\n </span>\n }\n </div>\n </div>\n </div>\n } @empty {\n <div class=\"section-drop-empty\">\n Drag a field here, or use the buttons above to add static elements.\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <button class=\"add-section-btn\" (click)=\"OnAddSection(); $event.stopPropagation()\">\n <i class=\"fa-solid fa-plus\"></i> Add Section\n </button>\n }\n</div>\n", styles: [":host { display: block; height: 100%; overflow: hidden; }\n\n.canvas-root {\n display: flex;\n flex-direction: column;\n height: 100%;\n padding: 20px 28px;\n overflow-y: auto;\n background: var(--mj-bg-page);\n gap: 16px;\n}\n\n.canvas-empty {\n margin: auto;\n text-align: center;\n max-width: 380px;\n color: var(--mj-text-muted);\n}\n.canvas-empty i { font-size: 36px; margin-bottom: 12px; color: var(--mj-text-disabled); }\n.canvas-empty h3 { margin: 0 0 6px; font-size: 16px; color: var(--mj-text-primary); }\n.canvas-empty p { margin: 0; font-size: 13px; line-height: 1.5; }\n\n.canvas-title-row {\n display: flex;\n align-items: center;\n gap: 12px;\n padding-bottom: 4px;\n flex-shrink: 0;\n}\n.canvas-title {\n flex: 1;\n border: 1px solid transparent;\n background: transparent;\n color: var(--mj-text-primary);\n font-size: 22px;\n font-weight: 600;\n padding: 6px 8px;\n border-radius: 4px;\n}\n.canvas-title:hover, .canvas-title:focus {\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface);\n outline: none;\n}\n.canvas-entity-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--mj-brand-primary);\n border-radius: 999px;\n font-size: 12px;\n}\n\n.canvas-sections-host { display: flex; flex-direction: column; gap: 14px; }\n\n.canvas-section {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow: hidden;\n transition: border-color 0.1s;\n}\n.canvas-section.selected { border-color: var(--mj-brand-primary); }\n\n.section-header {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n}\n.section-header:hover { background: var(--mj-bg-surface-hover); }\n.section-drag-handle, .element-drag-handle {\n color: var(--mj-text-disabled);\n cursor: grab;\n padding: 2px 4px;\n}\n.section-drag-handle:hover, .element-drag-handle:hover { color: var(--mj-text-secondary); }\n.section-title {\n flex: 1;\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-text-secondary);\n}\n.section-actions { display: flex; gap: 4px; }\n.mini-btn {\n background: transparent;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n padding: 4px 8px;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 11px;\n}\n.mini-btn:hover {\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-strong);\n}\n\n.section-grid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 10px;\n padding: 12px;\n min-height: 60px;\n}\n.section-grid.cols-2 { grid-template-columns: 1fr 1fr; }\n\n.section-drop-empty {\n grid-column: 1 / -1;\n padding: 18px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 12px;\n border: 1px dashed var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface-card);\n}\n\n.canvas-element {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n transition: border-color 0.1s, background 0.1s;\n}\n.canvas-element:hover { border-color: var(--mj-border-strong); background: var(--mj-bg-surface-hover); }\n.canvas-element.selected {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n}\n.canvas-element.unknown-field { border-color: var(--mj-status-warning); }\n.canvas-element.span-2 { grid-column: span 2; }\n\n.element-body { flex: 1; min-width: 0; }\n.element-label {\n font-size: 13px;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.element-meta { display: flex; gap: 6px; margin-top: 3px; flex-wrap: wrap; }\n.element-type-badge {\n padding: 1px 6px;\n font-size: 10px;\n border-radius: 999px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n.element-warn {\n font-size: 11px;\n color: var(--mj-status-warning-text);\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.add-section-btn {\n align-self: flex-start;\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 8px 14px;\n border: 1px dashed var(--mj-border-strong);\n border-radius: 6px;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 13px;\n cursor: pointer;\n transition: border-color 0.1s, background 0.1s;\n}\n.add-section-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 4%, transparent);\n}\n\n/* CDK drag-drop styling */\n.cdk-drag-preview {\n box-shadow: 0 5px 16px rgba(0,0,0,0.2);\n border-radius: 4px;\n}\n.cdk-drag-placeholder {\n opacity: 0.4;\n background: var(--mj-bg-surface-sunken);\n border: 1px dashed var(--mj-brand-primary);\n min-height: 36px;\n border-radius: 4px;\n}\n.cdk-drag-animating { transition: transform 200ms cubic-bezier(0, 0, 0.2, 1); }\n.section-grid.cdk-drop-list-dragging .canvas-element:not(.cdk-drag-placeholder) {\n transition: transform 200ms cubic-bezier(0, 0, 0.2, 1);\n}\n"] }]
|
|
314
|
+
}], null, { Canvas: [{
|
|
315
|
+
type: Input
|
|
316
|
+
}], Schema: [{
|
|
317
|
+
type: Input
|
|
318
|
+
}], SelectedElementId: [{
|
|
319
|
+
type: Input
|
|
320
|
+
}], SelectedSectionId: [{
|
|
321
|
+
type: Input
|
|
322
|
+
}], CanvasChanged: [{
|
|
323
|
+
type: Output
|
|
324
|
+
}], ElementSelected: [{
|
|
325
|
+
type: Output
|
|
326
|
+
}], SectionSelected: [{
|
|
327
|
+
type: Output
|
|
328
|
+
}], Deselected: [{
|
|
329
|
+
type: Output
|
|
330
|
+
}] }); })();
|
|
331
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(FormBuilderCanvasComponent, { className: "FormBuilderCanvasComponent", filePath: "src/ComponentStudio/components/form-builder/form-builder-canvas.component.ts", lineNumber: 30 }); })();
|
|
332
|
+
/** Helper: replace one section in the model, leaving others untouched. */
|
|
333
|
+
function mutateSection(canvas, sectionId, fn) {
|
|
334
|
+
return {
|
|
335
|
+
...canvas,
|
|
336
|
+
sections: canvas.sections.map(s => s.id === sectionId ? fn(s) : s),
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
//# sourceMappingURL=form-builder-canvas.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-builder-canvas.component.js","sourceRoot":"","sources":["../../../../src/ComponentStudio/components/form-builder/form-builder-canvas.component.ts","../../../../src/ComponentStudio/components/form-builder/form-builder-canvas.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n EventEmitter,\n Input,\n Output,\n inject,\n} from '@angular/core';\nimport { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';\nimport type { CuratedFormSchema } from '@memberjunction/interactive-component-types/forms';\nimport type { FormCanvasElement, FormCanvasModel, FormCanvasSection } from '../../services/form-canvas-model';\nimport { buildEmptySection, generateCanvasId } from '../../services/form-canvas-model';\n\n/**\n * Visual canvas. Owns the drag-drop UX for sections + elements + palette drops.\n *\n * The canvas itself is presentational — the dashboard owns the model and\n * applies changes here via emitted events. This keeps the canvas focused on\n * UI ergonomics while the dashboard handles dirty tracking, code mirror\n * synchronization, and undo (future).\n */\n@Component({\n standalone: false,\n selector: 'mj-form-builder-canvas',\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './form-builder-canvas.component.html',\n styleUrls: ['./form-builder-canvas.component.css'],\n})\nexport class FormBuilderCanvasComponent {\n private _canvas: FormCanvasModel | null = null;\n @Input()\n set Canvas(value: FormCanvasModel | null) {\n this._canvas = value;\n this.cdr.markForCheck();\n }\n get Canvas(): FormCanvasModel | null {\n return this._canvas;\n }\n\n @Input() Schema: CuratedFormSchema | null = null;\n @Input() SelectedElementId: string | null = null;\n @Input() SelectedSectionId: string | null = null;\n\n /** Emitted when the model changes structurally (drop, delete, reorder, etc.). */\n @Output() CanvasChanged = new EventEmitter<FormCanvasModel>();\n @Output() ElementSelected = new EventEmitter<{ sectionId: string; elementId: string }>();\n @Output() SectionSelected = new EventEmitter<string>();\n @Output() Deselected = new EventEmitter<void>();\n\n /**\n * IDs of the section drop lists. Computed once per render so `cdkDropList`\n * `connectedTo` can wire every section to every other section, enabling\n * cross-section drag.\n */\n public get sectionListIds(): string[] {\n return (this._canvas?.sections ?? []).map(s => `section-${s.id}`);\n }\n\n private readonly cdr = inject(ChangeDetectorRef);\n\n public OnAddSection(): void {\n if (!this._canvas) return;\n const next: FormCanvasModel = {\n ...this._canvas,\n sections: [...this._canvas.sections, buildEmptySection()],\n };\n this.CanvasChanged.emit(next);\n }\n\n public OnAddStaticElement(sectionId: string, kind: 'static-text' | 'spacer' | 'computed'): void {\n if (!this._canvas) return;\n const next = mutateSection(this._canvas, sectionId, s => ({\n ...s,\n elements: [...s.elements, {\n id: generateCanvasId(kind),\n type: kind,\n text: kind === 'static-text' ? 'Static text' : undefined,\n expression: kind === 'computed' ? 'record?.ID' : undefined,\n label: kind === 'computed' ? 'Computed' : undefined,\n }],\n }));\n this.CanvasChanged.emit(next);\n }\n\n public OnDropElement(event: CdkDragDrop<FormCanvasElement[]>, sectionId: string): void {\n if (!this._canvas) return;\n // Internal reorder within the same section.\n if (event.previousContainer === event.container) {\n const next = mutateSection(this._canvas, sectionId, s => {\n const elements = [...s.elements];\n moveItemInArray(elements, event.previousIndex, event.currentIndex);\n return { ...s, elements };\n });\n this.CanvasChanged.emit(next);\n return;\n }\n // Cross-section move: extract from source, insert into target.\n const sourceId = event.previousContainer.id.replace('section-', '');\n const sourceSection = this._canvas.sections.find(s => s.id === sourceId);\n if (!sourceSection) return;\n const moved = sourceSection.elements[event.previousIndex];\n if (!moved) return;\n\n const next: FormCanvasModel = {\n ...this._canvas,\n sections: this._canvas.sections.map(s => {\n if (s.id === sourceId) {\n return { ...s, elements: s.elements.filter((_, i) => i !== event.previousIndex) };\n }\n if (s.id === sectionId) {\n const elements = [...s.elements];\n elements.splice(event.currentIndex, 0, moved);\n return { ...s, elements };\n }\n return s;\n }),\n };\n this.CanvasChanged.emit(next);\n }\n\n public OnDropSection(event: CdkDragDrop<FormCanvasSection[]>): void {\n if (!this._canvas) return;\n const sections = [...this._canvas.sections];\n moveItemInArray(sections, event.previousIndex, event.currentIndex);\n this.CanvasChanged.emit({ ...this._canvas, sections });\n }\n\n /** Native-DnD fallback for palette → section drop (palette uses HTML5 DnD). */\n public OnNativeDragOver(event: DragEvent): void {\n if (event.dataTransfer?.types.includes('text/x-mj-form-field')) {\n event.preventDefault();\n }\n }\n\n public OnNativeDrop(event: DragEvent, sectionId: string): void {\n const fieldName = event.dataTransfer?.getData('text/x-mj-form-field');\n if (!fieldName || !this._canvas) return;\n event.preventDefault();\n const next = mutateSection(this._canvas, sectionId, s => ({\n ...s,\n elements: [...s.elements, {\n id: generateCanvasId('field'),\n type: 'field',\n fieldName,\n span: 1,\n }],\n }));\n this.CanvasChanged.emit(next);\n }\n\n public OnElementClick(sectionId: string, elementId: string, event: Event): void {\n event.stopPropagation();\n this.ElementSelected.emit({ sectionId, elementId });\n }\n\n public OnSectionHeaderClick(sectionId: string, event: Event): void {\n event.stopPropagation();\n this.SectionSelected.emit(sectionId);\n }\n\n public OnCanvasBackgroundClick(): void {\n this.Deselected.emit();\n }\n\n public OnTitleInput(event: Event): void {\n if (!this._canvas) return;\n const v = (event.target as HTMLInputElement).value;\n this.CanvasChanged.emit({ ...this._canvas, title: v });\n }\n\n public getLabelForElement(element: FormCanvasElement): string {\n if (element.type === 'static-text') return element.text ?? 'Static text';\n if (element.type === 'spacer') return 'Spacer';\n if (element.type === 'computed') return element.label ?? 'Computed';\n if (element.type === 'field' && element.fieldName) {\n return element.label ?? this.fieldDisplayName(element.fieldName);\n }\n return element.fieldName ?? '(unknown)';\n }\n\n public getFieldTypeBadge(element: FormCanvasElement): string | null {\n if (element.type === 'field' && element.fieldName) {\n const f = this.Schema?.fields.find(fld => fld.name === element.fieldName);\n return f?.type ?? null;\n }\n return element.type;\n }\n\n public isFieldUnknown(element: FormCanvasElement): boolean {\n if (element.type !== 'field' || !element.fieldName) return false;\n return !this.Schema?.fields.some(f => f.name === element.fieldName);\n }\n\n private fieldDisplayName(name: string): string {\n return this.Schema?.fields.find(f => f.name === name)?.displayName ?? name;\n }\n}\n\n/** Helper: replace one section in the model, leaving others untouched. */\nfunction mutateSection(\n canvas: FormCanvasModel,\n sectionId: string,\n fn: (s: FormCanvasSection) => FormCanvasSection,\n): FormCanvasModel {\n return {\n ...canvas,\n sections: canvas.sections.map(s => s.id === sectionId ? fn(s) : s),\n };\n}\n","<div class=\"canvas-root\" (click)=\"OnCanvasBackgroundClick()\">\n\n @if (!Canvas) {\n <div class=\"canvas-empty\">\n <i class=\"fa-solid fa-table-list\"></i>\n <h3>No form loaded</h3>\n <p>Pick an entity from the toolbar to start a new form, or select one from the left panel.</p>\n </div>\n } @else {\n <div class=\"canvas-title-row\" (click)=\"$event.stopPropagation()\">\n <input class=\"canvas-title\" type=\"text\"\n placeholder=\"Untitled form\"\n [value]=\"Canvas.title ?? ''\" (input)=\"OnTitleInput($event)\" />\n <span class=\"canvas-entity-badge\">\n <i class=\"fa-solid fa-table\"></i> {{ Canvas.entityName }}\n </span>\n </div>\n\n <div cdkDropList\n cdkDropListOrientation=\"vertical\"\n (cdkDropListDropped)=\"OnDropSection($event)\"\n class=\"canvas-sections-host\">\n\n @for (section of Canvas.sections; track section.id) {\n <div class=\"canvas-section\"\n cdkDrag\n [class.selected]=\"SelectedSectionId === section.id\"\n (click)=\"$event.stopPropagation()\">\n\n <header class=\"section-header\" (click)=\"OnSectionHeaderClick(section.id, $event)\">\n <span class=\"section-drag-handle\" cdkDragHandle title=\"Drag to reorder\">\n <i class=\"fa-solid fa-grip-vertical\"></i>\n </span>\n <h3 class=\"section-title\">{{ section.title || 'Untitled Section' }}</h3>\n <div class=\"section-actions\">\n <button class=\"mini-btn\" title=\"Add static text\"\n (click)=\"OnAddStaticElement(section.id, 'static-text'); $event.stopPropagation()\">\n <i class=\"fa-solid fa-font\"></i>\n </button>\n <button class=\"mini-btn\" title=\"Add computed field\"\n (click)=\"OnAddStaticElement(section.id, 'computed'); $event.stopPropagation()\">\n <i class=\"fa-solid fa-calculator\"></i>\n </button>\n <button class=\"mini-btn\" title=\"Add spacer\"\n (click)=\"OnAddStaticElement(section.id, 'spacer'); $event.stopPropagation()\">\n <i class=\"fa-solid fa-arrows-up-down\"></i>\n </button>\n </div>\n </header>\n\n <div class=\"section-grid\"\n [class.cols-2]=\"section.columns === 2\"\n cdkDropList\n [id]=\"'section-' + section.id\"\n [cdkDropListConnectedTo]=\"sectionListIds\"\n [cdkDropListData]=\"section.elements\"\n (cdkDropListDropped)=\"OnDropElement($event, section.id)\"\n (dragover)=\"OnNativeDragOver($event)\"\n (drop)=\"OnNativeDrop($event, section.id)\">\n\n @for (element of section.elements; track element.id) {\n <div class=\"canvas-element\"\n cdkDrag\n [class.span-2]=\"element.span === 2 && section.columns === 2\"\n [class.selected]=\"SelectedElementId === element.id\"\n [class.unknown-field]=\"isFieldUnknown(element)\"\n (click)=\"OnElementClick(section.id, element.id, $event)\">\n <span class=\"element-drag-handle\" cdkDragHandle title=\"Drag to move\">\n <i class=\"fa-solid fa-grip-vertical\"></i>\n </span>\n <div class=\"element-body\">\n <div class=\"element-label\">{{ getLabelForElement(element) }}</div>\n <div class=\"element-meta\">\n @if (getFieldTypeBadge(element); as badge) {\n <span class=\"element-type-badge\">{{ badge }}</span>\n }\n @if (isFieldUnknown(element)) {\n <span class=\"element-warn\"\n title=\"Field not in current schema — will be skipped at code generation\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i> not in schema\n </span>\n }\n </div>\n </div>\n </div>\n } @empty {\n <div class=\"section-drop-empty\">\n Drag a field here, or use the buttons above to add static elements.\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <button class=\"add-section-btn\" (click)=\"OnAddSection(); $event.stopPropagation()\">\n <i class=\"fa-solid fa-plus\"></i> Add Section\n </button>\n }\n</div>\n"]}
|