@memberjunction/ng-dashboards 5.11.0 → 5.13.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/dist/AI/components/agents/agent-configuration.component.d.ts +34 -2
- package/dist/AI/components/agents/agent-configuration.component.d.ts.map +1 -1
- package/dist/AI/components/agents/agent-configuration.component.js +586 -223
- package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
- package/dist/AI/components/agents/agent-editor.component.js +2 -2
- package/dist/AI/components/agents/agent-filter-panel.component.d.ts +8 -0
- package/dist/AI/components/agents/agent-filter-panel.component.d.ts.map +1 -1
- package/dist/AI/components/agents/agent-filter-panel.component.js +85 -52
- package/dist/AI/components/agents/agent-filter-panel.component.js.map +1 -1
- package/dist/AI/components/charts/performance-heatmap.component.d.ts +1 -0
- package/dist/AI/components/charts/performance-heatmap.component.d.ts.map +1 -1
- package/dist/AI/components/charts/performance-heatmap.component.js +27 -5
- package/dist/AI/components/charts/performance-heatmap.component.js.map +1 -1
- package/dist/AI/components/charts/time-series-chart.component.d.ts +5 -0
- package/dist/AI/components/charts/time-series-chart.component.d.ts.map +1 -1
- package/dist/AI/components/charts/time-series-chart.component.js +23 -8
- package/dist/AI/components/charts/time-series-chart.component.js.map +1 -1
- package/dist/AI/components/execution-monitoring.component.js +2 -2
- package/dist/AI/components/execution-monitoring.component.js.map +1 -1
- package/dist/AI/components/models/model-management.component.js +2 -2
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js +2 -2
- package/dist/AI/components/prompts/prompt-filter-panel.component.js +2 -2
- package/dist/AI/components/prompts/prompt-management.component.js +3 -3
- package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-version-control.component.js +2 -2
- package/dist/AI/components/requests/agent-requests-resource.component.d.ts +83 -0
- package/dist/AI/components/requests/agent-requests-resource.component.d.ts.map +1 -0
- package/dist/AI/components/requests/agent-requests-resource.component.js +547 -0
- package/dist/AI/components/requests/agent-requests-resource.component.js.map +1 -0
- package/dist/AI/components/system/system-config-filter-panel.component.js +2 -2
- package/dist/AI/components/system/system-configuration.component.js +2 -2
- package/dist/AI/components/widgets/kpi-card.component.js +7 -7
- package/dist/AI/components/widgets/kpi-card.component.js.map +1 -1
- package/dist/AI/components/widgets/live-execution-widget.component.d.ts.map +1 -1
- package/dist/AI/components/widgets/live-execution-widget.component.js +6 -6
- package/dist/AI/components/widgets/live-execution-widget.component.js.map +1 -1
- package/dist/AI/index.d.ts +1 -0
- package/dist/AI/index.d.ts.map +1 -1
- package/dist/AI/index.js +2 -0
- package/dist/AI/index.js.map +1 -1
- package/dist/APIKeys/api-applications-panel.component.js +3 -3
- package/dist/APIKeys/api-applications-panel.component.js.map +1 -1
- package/dist/APIKeys/api-key-create-dialog.component.js +3 -3
- package/dist/APIKeys/api-key-create-dialog.component.js.map +1 -1
- package/dist/APIKeys/api-key-edit-panel.component.js +1 -1
- package/dist/APIKeys/api-key-edit-panel.component.js.map +1 -1
- package/dist/APIKeys/api-key-list.component.js +3 -3
- package/dist/APIKeys/api-key-list.component.js.map +1 -1
- package/dist/APIKeys/api-keys-resource.component.js +1 -1
- package/dist/APIKeys/api-keys-resource.component.js.map +1 -1
- package/dist/APIKeys/api-scopes-panel.component.js +2 -2
- package/dist/APIKeys/api-usage-panel.component.js +2 -2
- package/dist/Actions/components/actions-overview.component.js +2 -2
- package/dist/Actions/components/execution-monitoring.component.js +2 -2
- package/dist/Actions/components/explorer/action-breadcrumb.component.js +2 -2
- package/dist/Actions/components/explorer/action-card.component.js +2 -2
- package/dist/Actions/components/explorer/action-explorer.component.js +2 -2
- package/dist/Actions/components/explorer/action-list-item.component.js +2 -2
- package/dist/Actions/components/explorer/action-toolbar.component.js +2 -2
- package/dist/Actions/components/explorer/action-tree-panel.component.js +2 -2
- package/dist/Actions/components/explorer/new-action-panel.component.js +2 -2
- package/dist/Actions/components/explorer/new-action-panel.component.js.map +1 -1
- package/dist/Actions/components/explorer/new-category-panel.component.js +2 -2
- package/dist/Actions/components/explorer/new-category-panel.component.js.map +1 -1
- package/dist/Communication/communication-dashboard.component.js +2 -2
- package/dist/Communication/communication-logs-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-logs-resource.component.js +3 -3
- package/dist/Communication/communication-logs-resource.component.js.map +1 -1
- package/dist/Communication/communication-monitor-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-monitor-resource.component.js +5 -5
- package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
- package/dist/Communication/communication-providers-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-providers-resource.component.js +3 -3
- package/dist/Communication/communication-providers-resource.component.js.map +1 -1
- package/dist/Communication/communication-runs-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-runs-resource.component.js +3 -3
- package/dist/Communication/communication-runs-resource.component.js.map +1 -1
- package/dist/Communication/communication-templates-resource.component.js +2 -2
- package/dist/Communication/communication-templates-resource.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.js +2 -2
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +2 -2
- package/dist/ComponentStudio/components/artifact-load-dialog.component.js +2 -2
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.js +2 -2
- package/dist/ComponentStudio/components/browser/component-browser.component.js +2 -2
- package/dist/ComponentStudio/components/editors/code-editor-panel.component.js +2 -2
- package/dist/ComponentStudio/components/editors/code-editor-panel.component.js.map +1 -1
- package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js +2 -2
- package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js.map +1 -1
- package/dist/ComponentStudio/components/editors/requirements-editor.component.js +2 -2
- package/dist/ComponentStudio/components/editors/requirements-editor.component.js.map +1 -1
- package/dist/ComponentStudio/components/editors/spec-editor.component.js +2 -2
- package/dist/ComponentStudio/components/editors/spec-editor.component.js.map +1 -1
- package/dist/ComponentStudio/components/new-component-dialog/new-component-dialog.component.js +2 -2
- package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.js +2 -2
- package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.js.map +1 -1
- package/dist/ComponentStudio/components/text-import-dialog.component.js +2 -2
- package/dist/ComponentStudio/components/text-import-dialog.component.js.map +1 -1
- package/dist/ComponentStudio/components/workspace/component-preview.component.js +2 -2
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.js +2 -2
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.js.map +1 -1
- package/dist/Credentials/components/credentials-audit-resource.component.js +9 -9
- package/dist/Credentials/components/credentials-audit-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-categories-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-categories-resource.component.js +11 -3
- package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-list-resource.component.js +2 -2
- package/dist/Credentials/components/credentials-overview-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-overview-resource.component.js +12 -11
- package/dist/Credentials/components/credentials-overview-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-types-resource.component.js +9 -9
- package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
- package/dist/Credentials/credentials-dashboard.component.js +2 -2
- package/dist/DashboardBrowser/dashboard-browser-resource.component.js +2 -2
- package/dist/DashboardBrowser/dashboard-share-dialog.component.js +2 -2
- package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js +2 -2
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js +2 -2
- package/dist/DataExplorer/components/view-selector/view-selector.component.js +2 -2
- package/dist/DataExplorer/data-explorer-dashboard.component.js +4 -4
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/Home/home-dashboard.component.js +2 -2
- package/dist/Integration/components/activity/activity.component.d.ts +1 -1
- package/dist/Integration/components/activity/activity.component.d.ts.map +1 -1
- package/dist/Integration/components/activity/activity.component.js +5 -5
- package/dist/Integration/components/activity/activity.component.js.map +1 -1
- package/dist/Integration/components/connections/connections.component.d.ts +31 -2
- package/dist/Integration/components/connections/connections.component.d.ts.map +1 -1
- package/dist/Integration/components/connections/connections.component.js +753 -412
- package/dist/Integration/components/connections/connections.component.js.map +1 -1
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +3 -3
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -1
- package/dist/Integration/components/overview/overview.component.d.ts +0 -1
- package/dist/Integration/components/overview/overview.component.d.ts.map +1 -1
- package/dist/Integration/components/overview/overview.component.js +3 -6
- package/dist/Integration/components/overview/overview.component.js.map +1 -1
- package/dist/Integration/components/pipelines/pipelines.component.js +3 -3
- package/dist/Integration/components/pipelines/pipelines.component.js.map +1 -1
- package/dist/Integration/components/schedules/schedules.component.d.ts +20 -0
- package/dist/Integration/components/schedules/schedules.component.d.ts.map +1 -1
- package/dist/Integration/components/schedules/schedules.component.js +97 -5
- package/dist/Integration/components/schedules/schedules.component.js.map +1 -1
- package/dist/Integration/components/visual-editor/visual-editor.component.js +2 -2
- package/dist/Integration/components/widgets/integration-card.component.d.ts.map +1 -1
- package/dist/Integration/components/widgets/integration-card.component.js +5 -1
- package/dist/Integration/components/widgets/integration-card.component.js.map +1 -1
- package/dist/Integration/components/widgets/run-history-panel.component.js +2 -2
- package/dist/Integration/components/widgets/run-history-panel.component.js.map +1 -1
- package/dist/Integration/integration.module.d.ts +2 -1
- package/dist/Integration/integration.module.d.ts.map +1 -1
- package/dist/Integration/integration.module.js +7 -3
- package/dist/Integration/integration.module.js.map +1 -1
- package/dist/Integration/services/integration-data.service.d.ts +27 -2
- package/dist/Integration/services/integration-data.service.d.ts.map +1 -1
- package/dist/Integration/services/integration-data.service.js +107 -4
- package/dist/Integration/services/integration-data.service.js.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.js +25 -24
- package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-categories-resource.component.js +2 -2
- package/dist/Lists/components/lists-categories-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-my-lists-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-my-lists-resource.component.js +26 -25
- package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-operations-resource.component.js +2 -2
- package/dist/Lists/components/lists-operations-resource.component.js.map +1 -1
- package/dist/Lists/components/venn-diagram/venn-diagram.component.js +3 -3
- package/dist/Lists/components/venn-diagram/venn-diagram.component.js.map +1 -1
- package/dist/MCP/components/mcp-connection-dialog.component.js +2 -2
- package/dist/MCP/components/mcp-log-detail-panel.component.js +2 -2
- package/dist/MCP/components/mcp-log-detail-panel.component.js.map +1 -1
- package/dist/MCP/components/mcp-server-dialog.component.js +2 -2
- package/dist/MCP/components/mcp-test-tool-dialog.component.js +2 -2
- package/dist/MCP/components/mcp-test-tool-dialog.component.js.map +1 -1
- package/dist/MCP/mcp-dashboard.component.js +2 -2
- package/dist/MCP/mcp-filter-panel.component.js +2 -2
- package/dist/QueryBrowser/query-browser-resource.component.js +7 -7
- package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
- package/dist/Scheduling/components/index.d.ts +0 -1
- package/dist/Scheduling/components/index.d.ts.map +1 -1
- package/dist/Scheduling/components/index.js +0 -1
- package/dist/Scheduling/components/index.js.map +1 -1
- package/dist/Scheduling/components/scheduling-activity.component.js +2 -2
- package/dist/Scheduling/components/scheduling-jobs.component.d.ts +6 -9
- package/dist/Scheduling/components/scheduling-jobs.component.d.ts.map +1 -1
- package/dist/Scheduling/components/scheduling-jobs.component.js +118 -110
- package/dist/Scheduling/components/scheduling-jobs.component.js.map +1 -1
- package/dist/Scheduling/components/scheduling-overview.component.js +3 -3
- package/dist/Scheduling/components/scheduling-overview.component.js.map +1 -1
- package/dist/Scheduling/scheduling-dashboard.component.js +2 -2
- package/dist/SystemDiagnostics/system-diagnostics.component.js +4 -4
- package/dist/SystemDiagnostics/system-diagnostics.component.js.map +1 -1
- package/dist/Testing/components/testing-analytics.component.js +2 -2
- package/dist/Testing/components/testing-analytics.component.js.map +1 -1
- package/dist/Testing/components/testing-dashboard-tab.component.js +4 -4
- package/dist/Testing/components/testing-dashboard-tab.component.js.map +1 -1
- package/dist/Testing/components/testing-explorer.component.js +2 -2
- package/dist/Testing/components/testing-explorer.component.js.map +1 -1
- package/dist/Testing/components/testing-review.component.d.ts.map +1 -1
- package/dist/Testing/components/testing-review.component.js +5 -5
- package/dist/Testing/components/testing-review.component.js.map +1 -1
- package/dist/Testing/components/testing-runs.component.js +2 -2
- package/dist/Testing/components/testing-runs.component.js.map +1 -1
- package/dist/Testing/components/widgets/oracle-breakdown-table.component.js +2 -2
- package/dist/Testing/components/widgets/oracle-breakdown-table.component.js.map +1 -1
- package/dist/Testing/components/widgets/suite-tree.component.js +4 -4
- package/dist/Testing/components/widgets/suite-tree.component.js.map +1 -1
- package/dist/Testing/components/widgets/test-run-detail-panel.component.js +2 -2
- package/dist/Testing/components/widgets/test-run-detail-panel.component.js.map +1 -1
- package/dist/Testing/testing-dashboard.component.js +2 -2
- package/dist/VersionHistory/components/diff-resource.component.js +2 -2
- package/dist/VersionHistory/components/graph-resource.component.js +2 -2
- package/dist/VersionHistory/components/labels-resource.component.js +3 -3
- package/dist/VersionHistory/components/labels-resource.component.js.map +1 -1
- package/dist/VersionHistory/components/restore-resource.component.js +3 -3
- package/dist/VersionHistory/components/restore-resource.component.js.map +1 -1
- package/dist/__tests__/integration-data-service.test.js +1 -0
- package/dist/__tests__/integration-data-service.test.js.map +1 -1
- package/dist/module.d.ts +52 -49
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +25 -6
- package/dist/module.js.map +1 -1
- package/dist/public-api.d.ts +1 -1
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -1
- package/dist/public-api.js.map +1 -1
- package/package.json +42 -40
- package/dist/Scheduling/components/job-slideout.component.d.ts +0 -45
- package/dist/Scheduling/components/job-slideout.component.d.ts.map +0 -1
- package/dist/Scheduling/components/job-slideout.component.js +0 -459
- package/dist/Scheduling/components/job-slideout.component.js.map +0 -1
|
@@ -466,11 +466,11 @@ export class ActionToolbarComponent {
|
|
|
466
466
|
i0.ɵɵproperty("fillMode", "flat");
|
|
467
467
|
i0.ɵɵadvance(2);
|
|
468
468
|
i0.ɵɵproperty("fillMode", "solid")("themeColor", "primary");
|
|
469
|
-
} }, dependencies: [i2.TextBoxComponent, i2.TextBoxSuffixTemplateDirective, i2.TextBoxPrefixTemplateDirective, i3.ButtonComponent, i3.ChipComponent], styles: [".action-toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 20px;\n background: var(--
|
|
469
|
+
} }, dependencies: [i2.TextBoxComponent, i2.TextBoxSuffixTemplateDirective, i2.TextBoxPrefixTemplateDirective, i3.ButtonComponent, i3.ChipComponent], styles: [".action-toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 20px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.toolbar-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 0;\n flex-wrap: wrap;\n}\n\n.toolbar-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n}\n\n\n\n.search-container[_ngcontent-%COMP%] {\n min-width: 200px;\n max-width: 320px;\n flex: 1;\n}\n\n.search-container[_ngcontent-%COMP%] kendo-textbox[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.search-container[_ngcontent-%COMP%] i.fa-search[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n\n\n.dropdown-container[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.dropdown-container[_ngcontent-%COMP%] > button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dropdown-container[_ngcontent-%COMP%] > button.active[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.dropdown-container[_ngcontent-%COMP%] > button[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:last-child {\n font-size: 10px;\n margin-left: 4px;\n}\n\n.filter-badge[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n padding: 2px 6px;\n border-radius: 10px;\n min-width: 18px;\n text-align: center;\n}\n\n\n\n.dropdown-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 100;\n min-width: 220px;\n padding: 8px 0;\n}\n\n.dropdown-menu.sort-menu[_ngcontent-%COMP%] {\n right: 0;\n left: auto;\n}\n\n\n\n.dropdown-section[_ngcontent-%COMP%] {\n padding: 8px 12px;\n}\n\n.dropdown-section[_ngcontent-%COMP%]:not(:last-child) {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.section-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--mj-text-muted);\n letter-spacing: 0.5px;\n}\n\n.section-header[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n font-size: 11px;\n padding: 2px 6px;\n}\n\n.filter-options[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.filter-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 4px;\n cursor: pointer;\n transition: background 0.15s ease;\n font-size: 13px;\n}\n\n.filter-option[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.filter-option.selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.filter-option[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n display: none;\n}\n\n.filter-option[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 13px;\n width: 18px;\n color: var(--mj-text-muted);\n}\n\n.filter-option.selected[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.status-dot[_ngcontent-%COMP%] {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n}\n\n.status-dot[data-status=\"Active\"][_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n}\n\n.status-dot[data-status=\"Pending\"][_ngcontent-%COMP%] {\n background: var(--mj-status-warning);\n}\n\n.status-dot[data-status=\"Disabled\"][_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n}\n\n.dropdown-footer[_ngcontent-%COMP%] {\n padding: 8px 12px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.dropdown-footer[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n\n\n.sort-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 8px 12px;\n border: none;\n background: transparent;\n cursor: pointer;\n font-size: 13px;\n text-align: left;\n transition: background 0.15s ease;\n}\n\n.sort-option[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.sort-option.selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.sort-option[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:first-child {\n width: 18px;\n color: var(--mj-text-muted);\n}\n\n.sort-option.selected[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:first-child {\n color: var(--mj-brand-primary);\n}\n\n.sort-option[_ngcontent-%COMP%] .direction-icon[_ngcontent-%COMP%] {\n margin-left: auto;\n font-size: 11px;\n}\n\n\n\n.active-filters[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.active-filters[_ngcontent-%COMP%] kendo-chip[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n\n\n.results-count[_ngcontent-%COMP%] {\n display: flex;\n align-items: baseline;\n gap: 4px;\n font-size: 13px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.results-count[_ngcontent-%COMP%] .count[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-primary);\n font-size: 14px;\n}\n\n.results-count[_ngcontent-%COMP%] .of-total[_ngcontent-%COMP%] {\n opacity: 0.7;\n}\n\n\n\n.view-toggle[_ngcontent-%COMP%] {\n display: flex;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n overflow: hidden;\n}\n\n.view-toggle[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n border-radius: 0;\n border: none;\n min-width: 36px;\n}\n\n.view-toggle[_ngcontent-%COMP%] button[_ngcontent-%COMP%]:not(:last-child) {\n border-right: 1px solid var(--mj-border-default);\n}\n\n\n\n@media (max-width: 1024px) {\n .action-toolbar[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: stretch;\n }\n\n .toolbar-left[_ngcontent-%COMP%], \n .toolbar-right[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: flex-start;\n }\n\n .search-container[_ngcontent-%COMP%] {\n max-width: none;\n flex: 1;\n }\n}\n\n@media (max-width: 640px) {\n .toolbar-right[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n }\n\n .results-count[_ngcontent-%COMP%] {\n order: -1;\n width: 100%;\n }\n}"], changeDetection: 0 });
|
|
470
470
|
}
|
|
471
471
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ActionToolbarComponent, [{
|
|
472
472
|
type: Component,
|
|
473
|
-
args: [{ standalone: false, selector: 'mj-action-toolbar', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"action-toolbar\">\n <div class=\"toolbar-left\">\n <!-- Search -->\n <div class=\"search-container\">\n <kendo-textbox\n [placeholder]=\"'Search actions...'\"\n [value]=\"Filters.searchTerm\"\n (valueChange)=\"onSearchInput($event)\">\n <ng-template kendoTextBoxPrefixTemplate>\n <i class=\"fa-solid fa-search\"></i>\n </ng-template>\n @if (Filters.searchTerm) {\n <ng-template kendoTextBoxSuffixTemplate>\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n (click)=\"clearSearch()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </ng-template>\n }\n </kendo-textbox>\n </div>\n\n <!-- Filters Dropdown -->\n <div class=\"dropdown-container\" (clickOutside)=\"ShowFiltersDropdown = false\">\n <button kendoButton\n [fillMode]=\"'outline'\"\n [class.active]=\"hasActiveFilters()\"\n (click)=\"toggleFiltersDropdown()\">\n <i class=\"fa-solid fa-filter\"></i>\n Filters\n @if (getActiveFilterCount() > 0) {\n <span class=\"filter-badge\">{{ getActiveFilterCount() }}</span>\n }\n <i [class]=\"ShowFiltersDropdown ? 'fa-solid fa-chevron-up' : 'fa-solid fa-chevron-down'\"></i>\n </button>\n\n @if (ShowFiltersDropdown) {\n <div class=\"dropdown-menu filters-menu\">\n <div class=\"dropdown-section\">\n <div class=\"section-header\">\n <span>Status</span>\n @if (Filters.statuses.length > 0) {\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n (click)=\"StateService.setStatusFilter([])\">\n Clear\n </button>\n }\n </div>\n <div class=\"filter-options\">\n @for (status of StatusOptions; track status.value) {\n <label class=\"filter-option\" [class.selected]=\"isStatusSelected(status.value)\">\n <input type=\"checkbox\"\n [checked]=\"isStatusSelected(status.value)\"\n (change)=\"toggleStatus(status.value)\">\n <span class=\"status-dot\" [attr.data-status]=\"status.value\"></span>\n {{ status.label }}\n </label>\n }\n </div>\n </div>\n\n <div class=\"dropdown-section\">\n <div class=\"section-header\">\n <span>Type</span>\n @if (Filters.types.length > 0) {\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n (click)=\"StateService.setTypeFilter([])\">\n Clear\n </button>\n }\n </div>\n <div class=\"filter-options\">\n @for (type of TypeOptions; track type.value) {\n <label class=\"filter-option\" [class.selected]=\"isTypeSelected(type.value)\">\n <input type=\"checkbox\"\n [checked]=\"isTypeSelected(type.value)\"\n (change)=\"toggleType(type.value)\">\n <i [class]=\"type.icon\"></i>\n {{ type.label }}\n </label>\n }\n </div>\n </div>\n\n @if (hasActiveFilters()) {\n <div class=\"dropdown-footer\">\n <button kendoButton\n [fillMode]=\"'flat'\"\n [themeColor]=\"'error'\"\n (click)=\"clearFilters()\">\n <i class=\"fa-solid fa-times\"></i>\n Clear All Filters\n </button>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Active Filter Chips -->\n @if (hasActiveFilters()) {\n <div class=\"active-filters\">\n @for (status of Filters.statuses; track status) {\n <kendo-chip\n [removable]=\"true\"\n [size]=\"'small'\"\n (remove)=\"toggleStatus(status)\">\n Status: {{ status }}\n </kendo-chip>\n }\n @for (type of Filters.types; track type) {\n <kendo-chip\n [removable]=\"true\"\n [size]=\"'small'\"\n (remove)=\"toggleType(type)\">\n Type: {{ type === 'Generated' ? 'AI Generated' : type }}\n </kendo-chip>\n }\n </div>\n }\n </div>\n\n <div class=\"toolbar-right\">\n <!-- Results Count -->\n <div class=\"results-count\">\n <span class=\"count\">{{ FilteredCount }}</span>\n @if (FilteredCount !== TotalCount) {\n <span class=\"of-total\">of {{ TotalCount }}</span>\n }\n <span class=\"label\">actions</span>\n </div>\n\n <!-- Sort Dropdown -->\n <div class=\"dropdown-container\" (clickOutside)=\"ShowSortDropdown = false\">\n <button kendoButton\n [fillMode]=\"'outline'\"\n (click)=\"toggleSortDropdown()\">\n <i [class]=\"getSortIcon()\"></i>\n {{ getSortLabel() }}\n <i [class]=\"ShowSortDropdown ? 'fa-solid fa-chevron-up' : 'fa-solid fa-chevron-down'\"></i>\n </button>\n\n @if (ShowSortDropdown) {\n <div class=\"dropdown-menu sort-menu\">\n @for (option of SortOptions; track option.field) {\n <button class=\"sort-option\"\n [class.selected]=\"SortField === option.field\"\n (click)=\"setSortField(option.field)\">\n <i [class]=\"option.icon\"></i>\n {{ option.label }}\n @if (SortField === option.field) {\n <i [class]=\"SortDirection === 'asc' ? 'fa-solid fa-arrow-up' : 'fa-solid fa-arrow-down'\" class=\"direction-icon\"></i>\n }\n </button>\n }\n </div>\n }\n </div>\n\n <!-- View Mode Toggle -->\n <div class=\"view-toggle\">\n <button kendoButton\n [fillMode]=\"ViewMode === 'card' ? 'solid' : 'outline'\"\n [themeColor]=\"ViewMode === 'card' ? 'primary' : 'base'\"\n title=\"Card View\"\n (click)=\"setViewMode('card')\">\n <i class=\"fa-solid fa-grip\"></i>\n </button>\n <button kendoButton\n [fillMode]=\"ViewMode === 'list' ? 'solid' : 'outline'\"\n [themeColor]=\"ViewMode === 'list' ? 'primary' : 'base'\"\n title=\"List View\"\n (click)=\"setViewMode('list')\">\n <i class=\"fa-solid fa-list\"></i>\n </button>\n <button kendoButton\n [fillMode]=\"ViewMode === 'compact' ? 'solid' : 'outline'\"\n [themeColor]=\"ViewMode === 'compact' ? 'primary' : 'base'\"\n title=\"Compact View\"\n (click)=\"setViewMode('compact')\">\n <i class=\"fa-solid fa-bars\"></i>\n </button>\n </div>\n\n <!-- Refresh Button -->\n <button kendoButton\n [fillMode]=\"'flat'\"\n title=\"Refresh\"\n (click)=\"onRefresh()\">\n <i class=\"fa-solid fa-refresh\"></i>\n </button>\n\n <!-- New Action Button -->\n <button kendoButton\n [fillMode]=\"'solid'\"\n [themeColor]=\"'primary'\"\n (click)=\"onNewAction()\">\n <i class=\"fa-solid fa-plus\"></i>\n New Action\n </button>\n </div>\n</div>\n", styles: [".action-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 20px;\n background: var(--kendo-color-surface);\n border-bottom: 1px solid var(--kendo-color-border);\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.toolbar-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 0;\n flex-wrap: wrap;\n}\n\n.toolbar-right {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n}\n\n/* Search */\n.search-container {\n min-width: 200px;\n max-width: 320px;\n flex: 1;\n}\n\n.search-container kendo-textbox {\n width: 100%;\n}\n\n.search-container i.fa-search {\n font-size: 13px;\n color: var(--kendo-color-subtle);\n}\n\n/* Dropdown Container */\n.dropdown-container {\n position: relative;\n}\n\n.dropdown-container > button {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dropdown-container > button.active {\n border-color: var(--kendo-color-primary);\n background: var(--kendo-color-primary-subtle);\n}\n\n.dropdown-container > button i:last-child {\n font-size: 10px;\n margin-left: 4px;\n}\n\n.filter-badge {\n background: var(--kendo-color-primary);\n color: white;\n font-size: 10px;\n font-weight: 600;\n padding: 2px 6px;\n border-radius: 10px;\n min-width: 18px;\n text-align: center;\n}\n\n/* Dropdown Menu */\n.dropdown-menu {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n background: var(--kendo-color-surface);\n border: 1px solid var(--kendo-color-border);\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 100;\n min-width: 220px;\n padding: 8px 0;\n}\n\n.dropdown-menu.sort-menu {\n right: 0;\n left: auto;\n}\n\n/* Dropdown Section */\n.dropdown-section {\n padding: 8px 12px;\n}\n\n.dropdown-section:not(:last-child) {\n border-bottom: 1px solid var(--kendo-color-border);\n}\n\n.section-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--kendo-color-subtle);\n letter-spacing: 0.5px;\n}\n\n.section-header button {\n font-size: 11px;\n padding: 2px 6px;\n}\n\n.filter-options {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.filter-option {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 4px;\n cursor: pointer;\n transition: background 0.15s ease;\n font-size: 13px;\n}\n\n.filter-option:hover {\n background: var(--kendo-color-base-hover);\n}\n\n.filter-option.selected {\n background: var(--kendo-color-primary-subtle);\n}\n\n.filter-option input[type=\"checkbox\"] {\n display: none;\n}\n\n.filter-option i {\n font-size: 13px;\n width: 18px;\n color: var(--kendo-color-subtle);\n}\n\n.filter-option.selected i {\n color: var(--kendo-color-primary);\n}\n\n.status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n}\n\n.status-dot[data-status=\"Active\"] {\n background: var(--kendo-color-success);\n}\n\n.status-dot[data-status=\"Pending\"] {\n background: var(--kendo-color-warning);\n}\n\n.status-dot[data-status=\"Disabled\"] {\n background: var(--kendo-color-error);\n}\n\n.dropdown-footer {\n padding: 8px 12px;\n border-top: 1px solid var(--kendo-color-border);\n}\n\n.dropdown-footer button {\n width: 100%;\n}\n\n/* Sort Options */\n.sort-option {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 8px 12px;\n border: none;\n background: transparent;\n cursor: pointer;\n font-size: 13px;\n text-align: left;\n transition: background 0.15s ease;\n}\n\n.sort-option:hover {\n background: var(--kendo-color-base-hover);\n}\n\n.sort-option.selected {\n background: var(--kendo-color-primary-subtle);\n color: var(--kendo-color-primary);\n}\n\n.sort-option i:first-child {\n width: 18px;\n color: var(--kendo-color-subtle);\n}\n\n.sort-option.selected i:first-child {\n color: var(--kendo-color-primary);\n}\n\n.sort-option .direction-icon {\n margin-left: auto;\n font-size: 11px;\n}\n\n/* Active Filters */\n.active-filters {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.active-filters kendo-chip {\n font-size: 12px;\n}\n\n/* Results Count */\n.results-count {\n display: flex;\n align-items: baseline;\n gap: 4px;\n font-size: 13px;\n color: var(--kendo-color-subtle);\n white-space: nowrap;\n}\n\n.results-count .count {\n font-weight: 600;\n color: var(--kendo-color-on-app-surface);\n font-size: 14px;\n}\n\n.results-count .of-total {\n opacity: 0.7;\n}\n\n/* View Toggle */\n.view-toggle {\n display: flex;\n border: 1px solid var(--kendo-color-border);\n border-radius: 4px;\n overflow: hidden;\n}\n\n.view-toggle button {\n border-radius: 0;\n border: none;\n min-width: 36px;\n}\n\n.view-toggle button:not(:last-child) {\n border-right: 1px solid var(--kendo-color-border);\n}\n\n/* Responsive */\n@media (max-width: 1024px) {\n .action-toolbar {\n flex-direction: column;\n align-items: stretch;\n }\n\n .toolbar-left,\n .toolbar-right {\n width: 100%;\n justify-content: flex-start;\n }\n\n .search-container {\n max-width: none;\n flex: 1;\n }\n}\n\n@media (max-width: 640px) {\n .toolbar-right {\n flex-wrap: wrap;\n }\n\n .results-count {\n order: -1;\n width: 100%;\n }\n}\n"] }]
|
|
473
|
+
args: [{ standalone: false, selector: 'mj-action-toolbar', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"action-toolbar\">\n <div class=\"toolbar-left\">\n <!-- Search -->\n <div class=\"search-container\">\n <kendo-textbox\n [placeholder]=\"'Search actions...'\"\n [value]=\"Filters.searchTerm\"\n (valueChange)=\"onSearchInput($event)\">\n <ng-template kendoTextBoxPrefixTemplate>\n <i class=\"fa-solid fa-search\"></i>\n </ng-template>\n @if (Filters.searchTerm) {\n <ng-template kendoTextBoxSuffixTemplate>\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n (click)=\"clearSearch()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </ng-template>\n }\n </kendo-textbox>\n </div>\n\n <!-- Filters Dropdown -->\n <div class=\"dropdown-container\" (clickOutside)=\"ShowFiltersDropdown = false\">\n <button kendoButton\n [fillMode]=\"'outline'\"\n [class.active]=\"hasActiveFilters()\"\n (click)=\"toggleFiltersDropdown()\">\n <i class=\"fa-solid fa-filter\"></i>\n Filters\n @if (getActiveFilterCount() > 0) {\n <span class=\"filter-badge\">{{ getActiveFilterCount() }}</span>\n }\n <i [class]=\"ShowFiltersDropdown ? 'fa-solid fa-chevron-up' : 'fa-solid fa-chevron-down'\"></i>\n </button>\n\n @if (ShowFiltersDropdown) {\n <div class=\"dropdown-menu filters-menu\">\n <div class=\"dropdown-section\">\n <div class=\"section-header\">\n <span>Status</span>\n @if (Filters.statuses.length > 0) {\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n (click)=\"StateService.setStatusFilter([])\">\n Clear\n </button>\n }\n </div>\n <div class=\"filter-options\">\n @for (status of StatusOptions; track status.value) {\n <label class=\"filter-option\" [class.selected]=\"isStatusSelected(status.value)\">\n <input type=\"checkbox\"\n [checked]=\"isStatusSelected(status.value)\"\n (change)=\"toggleStatus(status.value)\">\n <span class=\"status-dot\" [attr.data-status]=\"status.value\"></span>\n {{ status.label }}\n </label>\n }\n </div>\n </div>\n\n <div class=\"dropdown-section\">\n <div class=\"section-header\">\n <span>Type</span>\n @if (Filters.types.length > 0) {\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n (click)=\"StateService.setTypeFilter([])\">\n Clear\n </button>\n }\n </div>\n <div class=\"filter-options\">\n @for (type of TypeOptions; track type.value) {\n <label class=\"filter-option\" [class.selected]=\"isTypeSelected(type.value)\">\n <input type=\"checkbox\"\n [checked]=\"isTypeSelected(type.value)\"\n (change)=\"toggleType(type.value)\">\n <i [class]=\"type.icon\"></i>\n {{ type.label }}\n </label>\n }\n </div>\n </div>\n\n @if (hasActiveFilters()) {\n <div class=\"dropdown-footer\">\n <button kendoButton\n [fillMode]=\"'flat'\"\n [themeColor]=\"'error'\"\n (click)=\"clearFilters()\">\n <i class=\"fa-solid fa-times\"></i>\n Clear All Filters\n </button>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Active Filter Chips -->\n @if (hasActiveFilters()) {\n <div class=\"active-filters\">\n @for (status of Filters.statuses; track status) {\n <kendo-chip\n [removable]=\"true\"\n [size]=\"'small'\"\n (remove)=\"toggleStatus(status)\">\n Status: {{ status }}\n </kendo-chip>\n }\n @for (type of Filters.types; track type) {\n <kendo-chip\n [removable]=\"true\"\n [size]=\"'small'\"\n (remove)=\"toggleType(type)\">\n Type: {{ type === 'Generated' ? 'AI Generated' : type }}\n </kendo-chip>\n }\n </div>\n }\n </div>\n\n <div class=\"toolbar-right\">\n <!-- Results Count -->\n <div class=\"results-count\">\n <span class=\"count\">{{ FilteredCount }}</span>\n @if (FilteredCount !== TotalCount) {\n <span class=\"of-total\">of {{ TotalCount }}</span>\n }\n <span class=\"label\">actions</span>\n </div>\n\n <!-- Sort Dropdown -->\n <div class=\"dropdown-container\" (clickOutside)=\"ShowSortDropdown = false\">\n <button kendoButton\n [fillMode]=\"'outline'\"\n (click)=\"toggleSortDropdown()\">\n <i [class]=\"getSortIcon()\"></i>\n {{ getSortLabel() }}\n <i [class]=\"ShowSortDropdown ? 'fa-solid fa-chevron-up' : 'fa-solid fa-chevron-down'\"></i>\n </button>\n\n @if (ShowSortDropdown) {\n <div class=\"dropdown-menu sort-menu\">\n @for (option of SortOptions; track option.field) {\n <button class=\"sort-option\"\n [class.selected]=\"SortField === option.field\"\n (click)=\"setSortField(option.field)\">\n <i [class]=\"option.icon\"></i>\n {{ option.label }}\n @if (SortField === option.field) {\n <i [class]=\"SortDirection === 'asc' ? 'fa-solid fa-arrow-up' : 'fa-solid fa-arrow-down'\" class=\"direction-icon\"></i>\n }\n </button>\n }\n </div>\n }\n </div>\n\n <!-- View Mode Toggle -->\n <div class=\"view-toggle\">\n <button kendoButton\n [fillMode]=\"ViewMode === 'card' ? 'solid' : 'outline'\"\n [themeColor]=\"ViewMode === 'card' ? 'primary' : 'base'\"\n title=\"Card View\"\n (click)=\"setViewMode('card')\">\n <i class=\"fa-solid fa-grip\"></i>\n </button>\n <button kendoButton\n [fillMode]=\"ViewMode === 'list' ? 'solid' : 'outline'\"\n [themeColor]=\"ViewMode === 'list' ? 'primary' : 'base'\"\n title=\"List View\"\n (click)=\"setViewMode('list')\">\n <i class=\"fa-solid fa-list\"></i>\n </button>\n <button kendoButton\n [fillMode]=\"ViewMode === 'compact' ? 'solid' : 'outline'\"\n [themeColor]=\"ViewMode === 'compact' ? 'primary' : 'base'\"\n title=\"Compact View\"\n (click)=\"setViewMode('compact')\">\n <i class=\"fa-solid fa-bars\"></i>\n </button>\n </div>\n\n <!-- Refresh Button -->\n <button kendoButton\n [fillMode]=\"'flat'\"\n title=\"Refresh\"\n (click)=\"onRefresh()\">\n <i class=\"fa-solid fa-refresh\"></i>\n </button>\n\n <!-- New Action Button -->\n <button kendoButton\n [fillMode]=\"'solid'\"\n [themeColor]=\"'primary'\"\n (click)=\"onNewAction()\">\n <i class=\"fa-solid fa-plus\"></i>\n New Action\n </button>\n </div>\n</div>\n", styles: [".action-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 20px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.toolbar-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 0;\n flex-wrap: wrap;\n}\n\n.toolbar-right {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n}\n\n/* Search */\n.search-container {\n min-width: 200px;\n max-width: 320px;\n flex: 1;\n}\n\n.search-container kendo-textbox {\n width: 100%;\n}\n\n.search-container i.fa-search {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n/* Dropdown Container */\n.dropdown-container {\n position: relative;\n}\n\n.dropdown-container > button {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dropdown-container > button.active {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.dropdown-container > button i:last-child {\n font-size: 10px;\n margin-left: 4px;\n}\n\n.filter-badge {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n padding: 2px 6px;\n border-radius: 10px;\n min-width: 18px;\n text-align: center;\n}\n\n/* Dropdown Menu */\n.dropdown-menu {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 100;\n min-width: 220px;\n padding: 8px 0;\n}\n\n.dropdown-menu.sort-menu {\n right: 0;\n left: auto;\n}\n\n/* Dropdown Section */\n.dropdown-section {\n padding: 8px 12px;\n}\n\n.dropdown-section:not(:last-child) {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.section-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--mj-text-muted);\n letter-spacing: 0.5px;\n}\n\n.section-header button {\n font-size: 11px;\n padding: 2px 6px;\n}\n\n.filter-options {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.filter-option {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 4px;\n cursor: pointer;\n transition: background 0.15s ease;\n font-size: 13px;\n}\n\n.filter-option:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.filter-option.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.filter-option input[type=\"checkbox\"] {\n display: none;\n}\n\n.filter-option i {\n font-size: 13px;\n width: 18px;\n color: var(--mj-text-muted);\n}\n\n.filter-option.selected i {\n color: var(--mj-brand-primary);\n}\n\n.status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n}\n\n.status-dot[data-status=\"Active\"] {\n background: var(--mj-status-success);\n}\n\n.status-dot[data-status=\"Pending\"] {\n background: var(--mj-status-warning);\n}\n\n.status-dot[data-status=\"Disabled\"] {\n background: var(--mj-status-error);\n}\n\n.dropdown-footer {\n padding: 8px 12px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.dropdown-footer button {\n width: 100%;\n}\n\n/* Sort Options */\n.sort-option {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 8px 12px;\n border: none;\n background: transparent;\n cursor: pointer;\n font-size: 13px;\n text-align: left;\n transition: background 0.15s ease;\n}\n\n.sort-option:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.sort-option.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.sort-option i:first-child {\n width: 18px;\n color: var(--mj-text-muted);\n}\n\n.sort-option.selected i:first-child {\n color: var(--mj-brand-primary);\n}\n\n.sort-option .direction-icon {\n margin-left: auto;\n font-size: 11px;\n}\n\n/* Active Filters */\n.active-filters {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.active-filters kendo-chip {\n font-size: 12px;\n}\n\n/* Results Count */\n.results-count {\n display: flex;\n align-items: baseline;\n gap: 4px;\n font-size: 13px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.results-count .count {\n font-weight: 600;\n color: var(--mj-text-primary);\n font-size: 14px;\n}\n\n.results-count .of-total {\n opacity: 0.7;\n}\n\n/* View Toggle */\n.view-toggle {\n display: flex;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n overflow: hidden;\n}\n\n.view-toggle button {\n border-radius: 0;\n border: none;\n min-width: 36px;\n}\n\n.view-toggle button:not(:last-child) {\n border-right: 1px solid var(--mj-border-default);\n}\n\n/* Responsive */\n@media (max-width: 1024px) {\n .action-toolbar {\n flex-direction: column;\n align-items: stretch;\n }\n\n .toolbar-left,\n .toolbar-right {\n width: 100%;\n justify-content: flex-start;\n }\n\n .search-container {\n max-width: none;\n flex: 1;\n }\n}\n\n@media (max-width: 640px) {\n .toolbar-right {\n flex-wrap: wrap;\n }\n\n .results-count {\n order: -1;\n width: 100%;\n }\n}\n"] }]
|
|
474
474
|
}], () => [{ type: i1.ActionExplorerStateService }, { type: i0.ChangeDetectorRef }], { TotalCount: [{
|
|
475
475
|
type: Input
|
|
476
476
|
}], FilteredCount: [{
|
|
@@ -429,11 +429,11 @@ export class ActionTreePanelComponent {
|
|
|
429
429
|
i0.ɵɵconditionalCreate(0, ActionTreePanelComponent_Conditional_0_Template, 35, 23, "div", 1)(1, ActionTreePanelComponent_Conditional_1_Template, 5, 4, "div", 2);
|
|
430
430
|
} if (rf & 2) {
|
|
431
431
|
i0.ɵɵconditional(!ctx.IsCollapsed ? 0 : 1);
|
|
432
|
-
} }, dependencies: [i2.NgTemplateOutlet, i3.TextBoxComponent, i3.TextBoxSuffixTemplateDirective, i3.TextBoxPrefixTemplateDirective, i4.ButtonComponent], styles: [".tree-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--
|
|
432
|
+
} }, dependencies: [i2.NgTemplateOutlet, i3.TextBoxComponent, i3.TextBoxSuffixTemplateDirective, i3.TextBoxPrefixTemplateDirective, i4.ButtonComponent], styles: [".tree-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-card);\n border-right: 1px solid var(--mj-border-default);\n position: relative;\n min-width: 180px;\n max-width: 450px;\n}\n\n.tree-header[_ngcontent-%COMP%] {\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.tree-header[_ngcontent-%COMP%] .header-content[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 12px;\n}\n\n.tree-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.tree-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.tree-header[_ngcontent-%COMP%] .header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 2px;\n}\n\n.tree-header[_ngcontent-%COMP%] .header-actions[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n padding: 4px;\n min-width: 28px;\n height: 28px;\n}\n\n.tree-header[_ngcontent-%COMP%] .header-actions[_ngcontent-%COMP%] button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.tree-search[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.tree-search[_ngcontent-%COMP%] kendo-textbox[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.tree-search[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.tree-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 8px 0;\n}\n\n.tree-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 8px 12px;\n cursor: pointer;\n transition: all 0.15s ease;\n gap: 8px;\n position: relative;\n color: var(--mj-text-primary);\n}\n\n.tree-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n padding-right: 40px; \n\n}\n\n.tree-item[_ngcontent-%COMP%]:hover .item-count[_ngcontent-%COMP%] {\n display: none; \n\n}\n\n.tree-item.selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.tree-item.selected[_ngcontent-%COMP%] .item-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.tree-item.root-item[_ngcontent-%COMP%], \n.tree-item.uncategorized-item[_ngcontent-%COMP%] {\n padding-left: 16px;\n margin-bottom: 4px;\n}\n\n.tree-item.root-item[_ngcontent-%COMP%] {\n font-weight: 600;\n}\n\n.tree-item.uncategorized-item[_ngcontent-%COMP%] {\n opacity: 0.8;\n}\n\n.tree-item.uncategorized-item[_ngcontent-%COMP%] .item-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n\n.tree-node[_ngcontent-%COMP%] {\n padding-left: calc(var(--level, 0) * 16px);\n}\n\n.expand-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n padding: 0;\n border: none;\n background: transparent;\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\n\n.expand-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-active);\n}\n\n.expand-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n.expand-placeholder[_ngcontent-%COMP%] {\n width: 20px;\n flex-shrink: 0;\n}\n\n.item-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n flex-shrink: 0;\n}\n\n.item-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-status-warning);\n}\n\n.item-name[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 13px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.item-count[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 8px;\n border-radius: 10px;\n flex-shrink: 0;\n}\n\n.tree-item.selected[_ngcontent-%COMP%] .item-count[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.item-actions[_ngcontent-%COMP%] {\n display: none;\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n}\n\n.tree-item[_ngcontent-%COMP%]:hover .item-actions[_ngcontent-%COMP%] {\n display: flex;\n}\n\n.item-actions[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n padding: 2px;\n min-width: 24px;\n height: 24px;\n}\n\n.item-actions[_ngcontent-%COMP%] button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n.tree-children[_ngcontent-%COMP%] {\n \n\n}\n\n.tree-footer[_ngcontent-%COMP%] {\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.new-category-btn[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n\n\n.resize-handle[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n right: 0;\n width: 4px;\n height: 100%;\n cursor: ew-resize;\n background: transparent;\n transition: background 0.15s ease;\n z-index: 10;\n}\n\n.resize-handle[_ngcontent-%COMP%]:hover, \n.resize-handle[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary);\n}\n\n\n\n.tree-panel-collapsed[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 8px 4px;\n background: var(--mj-bg-surface-card);\n border-right: 1px solid var(--mj-border-default);\n width: 44px;\n gap: 4px;\n}\n\n.tree-panel-collapsed[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n padding: 8px;\n}\n\n.tree-panel-collapsed[_ngcontent-%COMP%] button.selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n\n\n.tree-content[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 6px;\n}\n\n.tree-content[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.tree-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: var(--mj-border-default);\n border-radius: 3px;\n}\n\n.tree-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-muted);\n}\n\n\n\n@media (max-width: 768px) {\n .tree-panel[_ngcontent-%COMP%] {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n z-index: 100;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);\n }\n}"], changeDetection: 0 });
|
|
433
433
|
}
|
|
434
434
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ActionTreePanelComponent, [{
|
|
435
435
|
type: Component,
|
|
436
|
-
args: [{ standalone: false, selector: 'mj-action-tree-panel', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (!IsCollapsed) {\n <div class=\"tree-panel\" [style.width.px]=\"TreeWidth\">\n <div class=\"tree-header\">\n <div class=\"header-content\">\n <h3><i class=\"fa-solid fa-folder-tree\"></i> Categories</h3>\n <div class=\"header-actions\">\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n title=\"Expand All\"\n (click)=\"expandAll()\">\n <i class=\"fa-solid fa-angles-down\"></i>\n </button>\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n title=\"Collapse All\"\n (click)=\"collapseAll()\">\n <i class=\"fa-solid fa-angles-up\"></i>\n </button>\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n title=\"Collapse Panel\"\n (click)=\"toggleCollapse()\">\n <i class=\"fa-solid fa-chevron-left\"></i>\n </button>\n </div>\n </div>\n\n <div class=\"tree-search\">\n <kendo-textbox\n [placeholder]=\"'Filter categories...'\"\n [value]=\"SearchTerm\"\n (valueChange)=\"onSearchChange($event)\"\n [size]=\"'small'\">\n <ng-template kendoTextBoxPrefixTemplate>\n <i class=\"fa-solid fa-search\"></i>\n </ng-template>\n @if (SearchTerm) {\n <ng-template kendoTextBoxSuffixTemplate>\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n (click)=\"onSearchChange('')\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </ng-template>\n }\n </kendo-textbox>\n </div>\n </div>\n\n <div class=\"tree-content\">\n <!-- All Categories -->\n <div class=\"tree-item root-item\"\n [class.selected]=\"isSelected('all')\"\n (click)=\"selectCategory('all')\">\n <span class=\"item-icon\">\n <i class=\"fa-solid fa-layer-group\"></i>\n </span>\n <span class=\"item-name\">All Actions</span>\n <span class=\"item-count\">{{ getTotalActionCount() }}</span>\n </div>\n\n <!-- Uncategorized -->\n @if (getUncategorizedCount() > 0) {\n <div class=\"tree-item uncategorized-item\"\n [class.selected]=\"isSelected('uncategorized')\"\n (click)=\"selectCategory('uncategorized')\">\n <span class=\"item-icon\">\n <i class=\"fa-solid fa-inbox\"></i>\n </span>\n <span class=\"item-name\">Uncategorized</span>\n <span class=\"item-count\">{{ getUncategorizedCount() }}</span>\n </div>\n }\n\n <!-- Category Tree -->\n <div class=\"tree-categories\">\n <ng-container *ngTemplateOutlet=\"categoryTreeTemplate; context: { nodes: FilteredTree }\"></ng-container>\n </div>\n\n <ng-template #categoryTreeTemplate let-nodes=\"nodes\">\n @for (node of nodes; track node.category.ID) {\n <div class=\"tree-node\" [style.--level]=\"node.level\">\n <div class=\"tree-item\"\n [class.selected]=\"isSelected(node.category.ID)\"\n [class.has-children]=\"node.children.length > 0\"\n (click)=\"selectCategory(node.category.ID)\">\n\n @if (node.children.length > 0) {\n <button class=\"expand-btn\"\n (click)=\"toggleExpanded(node.category.ID, $event)\"\n [title]=\"isExpanded(node.category.ID) ? 'Collapse' : 'Expand'\">\n <i [class]=\"isExpanded(node.category.ID) ? 'fa-solid fa-chevron-down' : 'fa-solid fa-chevron-right'\"></i>\n </button>\n } @else {\n <span class=\"expand-placeholder\"></span>\n }\n\n <span class=\"item-icon\">\n <i [class]=\"isExpanded(node.category.ID) ? 'fa-solid fa-folder-open' : 'fa-solid fa-folder'\"></i>\n </span>\n <span class=\"item-name\" [title]=\"node.category.Name\">{{ node.category.Name }}</span>\n <span class=\"item-count\" [title]=\"node.totalActionCount + ' total actions'\">{{ node.totalActionCount }}</span>\n\n <div class=\"item-actions\">\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n title=\"Add Subcategory\"\n (click)=\"onNewCategory(node.category.ID, $event)\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n </div>\n </div>\n\n @if (node.children.length > 0 && isExpanded(node.category.ID)) {\n <div class=\"tree-children\">\n <ng-container *ngTemplateOutlet=\"categoryTreeTemplate; context: { nodes: node.children }\"></ng-container>\n </div>\n }\n </div>\n }\n </ng-template>\n </div>\n\n <div class=\"tree-footer\">\n <button kendoButton\n [fillMode]=\"'outline'\"\n [themeColor]=\"'primary'\"\n [size]=\"'small'\"\n class=\"new-category-btn\"\n (click)=\"onNewCategory(null, $event)\">\n <i class=\"fa-solid fa-plus\"></i>\n New Category\n </button>\n </div>\n\n <!-- Resize Handle -->\n <div class=\"resize-handle\"\n (mousedown)=\"onResizeStart($event)\"\n title=\"Drag to resize\">\n </div>\n </div>\n} @else {\n <!-- Collapsed State -->\n <div class=\"tree-panel-collapsed\">\n <button kendoButton\n [fillMode]=\"'flat'\"\n title=\"Expand Category Panel\"\n (click)=\"toggleCollapse()\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </button>\n <button kendoButton\n [fillMode]=\"'flat'\"\n title=\"All Actions\"\n [class.selected]=\"isSelected('all')\"\n (click)=\"selectCategory('all')\">\n <i class=\"fa-solid fa-layer-group\"></i>\n </button>\n </div>\n}\n", styles: [".tree-panel {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--kendo-color-surface);\n border-right: 1px solid var(--kendo-color-border);\n position: relative;\n min-width: 180px;\n max-width: 450px;\n}\n\n.tree-header {\n padding: 12px 16px;\n border-bottom: 1px solid var(--kendo-color-border);\n flex-shrink: 0;\n}\n\n.tree-header .header-content {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 12px;\n}\n\n.tree-header h3 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--kendo-color-on-app-surface);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.tree-header h3 i {\n color: var(--kendo-color-primary);\n}\n\n.tree-header .header-actions {\n display: flex;\n gap: 2px;\n}\n\n.tree-header .header-actions button {\n padding: 4px;\n min-width: 28px;\n height: 28px;\n}\n\n.tree-header .header-actions button i {\n font-size: 12px;\n}\n\n.tree-search {\n width: 100%;\n}\n\n.tree-search kendo-textbox {\n width: 100%;\n}\n\n.tree-search i {\n font-size: 12px;\n color: var(--kendo-color-subtle);\n}\n\n.tree-content {\n flex: 1;\n overflow-y: auto;\n padding: 8px 0;\n}\n\n.tree-item {\n display: flex;\n align-items: center;\n padding: 8px 12px;\n cursor: pointer;\n transition: all 0.15s ease;\n gap: 8px;\n position: relative;\n}\n\n.tree-item:hover {\n background: var(--kendo-color-base-hover);\n padding-right: 40px; /* Make room for the action button */\n}\n\n.tree-item:hover .item-count {\n display: none; /* Hide count when action button is visible */\n}\n\n.tree-item.selected {\n background: var(--kendo-color-primary-subtle);\n color: var(--kendo-color-primary);\n}\n\n.tree-item.selected .item-icon i {\n color: var(--kendo-color-primary);\n}\n\n.tree-item.root-item,\n.tree-item.uncategorized-item {\n padding-left: 16px;\n margin-bottom: 4px;\n}\n\n.tree-item.root-item {\n font-weight: 600;\n}\n\n.tree-item.uncategorized-item {\n opacity: 0.8;\n}\n\n.tree-item.uncategorized-item .item-icon i {\n color: var(--kendo-color-warning);\n}\n\n.tree-node {\n padding-left: calc(var(--level, 0) * 16px);\n}\n\n.expand-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n padding: 0;\n border: none;\n background: transparent;\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\n\n.expand-btn:hover {\n background: var(--kendo-color-base-active);\n}\n\n.expand-btn i {\n font-size: 10px;\n color: var(--kendo-color-subtle);\n}\n\n.expand-placeholder {\n width: 20px;\n flex-shrink: 0;\n}\n\n.item-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n flex-shrink: 0;\n}\n\n.item-icon i {\n font-size: 14px;\n color: var(--kendo-color-warning);\n}\n\n.item-name {\n flex: 1;\n font-size: 13px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.item-count {\n font-size: 11px;\n color: var(--kendo-color-subtle);\n background: var(--kendo-color-base-subtle);\n padding: 2px 8px;\n border-radius: 10px;\n flex-shrink: 0;\n}\n\n.tree-item.selected .item-count {\n background: var(--kendo-color-primary);\n color: white;\n}\n\n.item-actions {\n display: none;\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n}\n\n.tree-item:hover .item-actions {\n display: flex;\n}\n\n.item-actions button {\n padding: 2px;\n min-width: 24px;\n height: 24px;\n}\n\n.item-actions button i {\n font-size: 10px;\n}\n\n.tree-children {\n /* Children are indented via --level CSS variable */\n}\n\n.tree-footer {\n padding: 12px 16px;\n border-top: 1px solid var(--kendo-color-border);\n flex-shrink: 0;\n}\n\n.new-category-btn {\n width: 100%;\n}\n\n/* Resize Handle */\n.resize-handle {\n position: absolute;\n top: 0;\n right: 0;\n width: 4px;\n height: 100%;\n cursor: ew-resize;\n background: transparent;\n transition: background 0.15s ease;\n z-index: 10;\n}\n\n.resize-handle:hover,\n.resize-handle:active {\n background: var(--kendo-color-primary);\n}\n\n/* Collapsed State */\n.tree-panel-collapsed {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 8px 4px;\n background: var(--kendo-color-surface);\n border-right: 1px solid var(--kendo-color-border);\n width: 44px;\n gap: 4px;\n}\n\n.tree-panel-collapsed button {\n padding: 8px;\n}\n\n.tree-panel-collapsed button.selected {\n background: var(--kendo-color-primary-subtle);\n color: var(--kendo-color-primary);\n}\n\n/* Scrollbar Styling */\n.tree-content::-webkit-scrollbar {\n width: 6px;\n}\n\n.tree-content::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.tree-content::-webkit-scrollbar-thumb {\n background: var(--kendo-color-border);\n border-radius: 3px;\n}\n\n.tree-content::-webkit-scrollbar-thumb:hover {\n background: var(--kendo-color-subtle);\n}\n\n/* Mobile Responsiveness */\n@media (max-width: 768px) {\n .tree-panel {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n z-index: 100;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);\n }\n}\n"] }]
|
|
436
|
+
args: [{ standalone: false, selector: 'mj-action-tree-panel', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (!IsCollapsed) {\n <div class=\"tree-panel\" [style.width.px]=\"TreeWidth\">\n <div class=\"tree-header\">\n <div class=\"header-content\">\n <h3><i class=\"fa-solid fa-folder-tree\"></i> Categories</h3>\n <div class=\"header-actions\">\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n title=\"Expand All\"\n (click)=\"expandAll()\">\n <i class=\"fa-solid fa-angles-down\"></i>\n </button>\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n title=\"Collapse All\"\n (click)=\"collapseAll()\">\n <i class=\"fa-solid fa-angles-up\"></i>\n </button>\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n title=\"Collapse Panel\"\n (click)=\"toggleCollapse()\">\n <i class=\"fa-solid fa-chevron-left\"></i>\n </button>\n </div>\n </div>\n\n <div class=\"tree-search\">\n <kendo-textbox\n [placeholder]=\"'Filter categories...'\"\n [value]=\"SearchTerm\"\n (valueChange)=\"onSearchChange($event)\"\n [size]=\"'small'\">\n <ng-template kendoTextBoxPrefixTemplate>\n <i class=\"fa-solid fa-search\"></i>\n </ng-template>\n @if (SearchTerm) {\n <ng-template kendoTextBoxSuffixTemplate>\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n (click)=\"onSearchChange('')\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </ng-template>\n }\n </kendo-textbox>\n </div>\n </div>\n\n <div class=\"tree-content\">\n <!-- All Categories -->\n <div class=\"tree-item root-item\"\n [class.selected]=\"isSelected('all')\"\n (click)=\"selectCategory('all')\">\n <span class=\"item-icon\">\n <i class=\"fa-solid fa-layer-group\"></i>\n </span>\n <span class=\"item-name\">All Actions</span>\n <span class=\"item-count\">{{ getTotalActionCount() }}</span>\n </div>\n\n <!-- Uncategorized -->\n @if (getUncategorizedCount() > 0) {\n <div class=\"tree-item uncategorized-item\"\n [class.selected]=\"isSelected('uncategorized')\"\n (click)=\"selectCategory('uncategorized')\">\n <span class=\"item-icon\">\n <i class=\"fa-solid fa-inbox\"></i>\n </span>\n <span class=\"item-name\">Uncategorized</span>\n <span class=\"item-count\">{{ getUncategorizedCount() }}</span>\n </div>\n }\n\n <!-- Category Tree -->\n <div class=\"tree-categories\">\n <ng-container *ngTemplateOutlet=\"categoryTreeTemplate; context: { nodes: FilteredTree }\"></ng-container>\n </div>\n\n <ng-template #categoryTreeTemplate let-nodes=\"nodes\">\n @for (node of nodes; track node.category.ID) {\n <div class=\"tree-node\" [style.--level]=\"node.level\">\n <div class=\"tree-item\"\n [class.selected]=\"isSelected(node.category.ID)\"\n [class.has-children]=\"node.children.length > 0\"\n (click)=\"selectCategory(node.category.ID)\">\n\n @if (node.children.length > 0) {\n <button class=\"expand-btn\"\n (click)=\"toggleExpanded(node.category.ID, $event)\"\n [title]=\"isExpanded(node.category.ID) ? 'Collapse' : 'Expand'\">\n <i [class]=\"isExpanded(node.category.ID) ? 'fa-solid fa-chevron-down' : 'fa-solid fa-chevron-right'\"></i>\n </button>\n } @else {\n <span class=\"expand-placeholder\"></span>\n }\n\n <span class=\"item-icon\">\n <i [class]=\"isExpanded(node.category.ID) ? 'fa-solid fa-folder-open' : 'fa-solid fa-folder'\"></i>\n </span>\n <span class=\"item-name\" [title]=\"node.category.Name\">{{ node.category.Name }}</span>\n <span class=\"item-count\" [title]=\"node.totalActionCount + ' total actions'\">{{ node.totalActionCount }}</span>\n\n <div class=\"item-actions\">\n <button kendoButton\n [fillMode]=\"'flat'\"\n [size]=\"'small'\"\n title=\"Add Subcategory\"\n (click)=\"onNewCategory(node.category.ID, $event)\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n </div>\n </div>\n\n @if (node.children.length > 0 && isExpanded(node.category.ID)) {\n <div class=\"tree-children\">\n <ng-container *ngTemplateOutlet=\"categoryTreeTemplate; context: { nodes: node.children }\"></ng-container>\n </div>\n }\n </div>\n }\n </ng-template>\n </div>\n\n <div class=\"tree-footer\">\n <button kendoButton\n [fillMode]=\"'outline'\"\n [themeColor]=\"'primary'\"\n [size]=\"'small'\"\n class=\"new-category-btn\"\n (click)=\"onNewCategory(null, $event)\">\n <i class=\"fa-solid fa-plus\"></i>\n New Category\n </button>\n </div>\n\n <!-- Resize Handle -->\n <div class=\"resize-handle\"\n (mousedown)=\"onResizeStart($event)\"\n title=\"Drag to resize\">\n </div>\n </div>\n} @else {\n <!-- Collapsed State -->\n <div class=\"tree-panel-collapsed\">\n <button kendoButton\n [fillMode]=\"'flat'\"\n title=\"Expand Category Panel\"\n (click)=\"toggleCollapse()\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </button>\n <button kendoButton\n [fillMode]=\"'flat'\"\n title=\"All Actions\"\n [class.selected]=\"isSelected('all')\"\n (click)=\"selectCategory('all')\">\n <i class=\"fa-solid fa-layer-group\"></i>\n </button>\n </div>\n}\n", styles: [".tree-panel {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-card);\n border-right: 1px solid var(--mj-border-default);\n position: relative;\n min-width: 180px;\n max-width: 450px;\n}\n\n.tree-header {\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.tree-header .header-content {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 12px;\n}\n\n.tree-header h3 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.tree-header h3 i {\n color: var(--mj-brand-primary);\n}\n\n.tree-header .header-actions {\n display: flex;\n gap: 2px;\n}\n\n.tree-header .header-actions button {\n padding: 4px;\n min-width: 28px;\n height: 28px;\n}\n\n.tree-header .header-actions button i {\n font-size: 12px;\n}\n\n.tree-search {\n width: 100%;\n}\n\n.tree-search kendo-textbox {\n width: 100%;\n}\n\n.tree-search i {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.tree-content {\n flex: 1;\n overflow-y: auto;\n padding: 8px 0;\n}\n\n.tree-item {\n display: flex;\n align-items: center;\n padding: 8px 12px;\n cursor: pointer;\n transition: all 0.15s ease;\n gap: 8px;\n position: relative;\n color: var(--mj-text-primary);\n}\n\n.tree-item:hover {\n background: var(--mj-bg-surface-hover);\n padding-right: 40px; /* Make room for the action button */\n}\n\n.tree-item:hover .item-count {\n display: none; /* Hide count when action button is visible */\n}\n\n.tree-item.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.tree-item.selected .item-icon i {\n color: var(--mj-brand-primary);\n}\n\n.tree-item.root-item,\n.tree-item.uncategorized-item {\n padding-left: 16px;\n margin-bottom: 4px;\n}\n\n.tree-item.root-item {\n font-weight: 600;\n}\n\n.tree-item.uncategorized-item {\n opacity: 0.8;\n}\n\n.tree-item.uncategorized-item .item-icon i {\n color: var(--mj-status-warning);\n}\n\n.tree-node {\n padding-left: calc(var(--level, 0) * 16px);\n}\n\n.expand-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n padding: 0;\n border: none;\n background: transparent;\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\n\n.expand-btn:hover {\n background: var(--mj-bg-surface-active);\n}\n\n.expand-btn i {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n.expand-placeholder {\n width: 20px;\n flex-shrink: 0;\n}\n\n.item-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n flex-shrink: 0;\n}\n\n.item-icon i {\n font-size: 14px;\n color: var(--mj-status-warning);\n}\n\n.item-name {\n flex: 1;\n font-size: 13px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.item-count {\n font-size: 11px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 8px;\n border-radius: 10px;\n flex-shrink: 0;\n}\n\n.tree-item.selected .item-count {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.item-actions {\n display: none;\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n}\n\n.tree-item:hover .item-actions {\n display: flex;\n}\n\n.item-actions button {\n padding: 2px;\n min-width: 24px;\n height: 24px;\n}\n\n.item-actions button i {\n font-size: 10px;\n}\n\n.tree-children {\n /* Children are indented via --level CSS variable */\n}\n\n.tree-footer {\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.new-category-btn {\n width: 100%;\n}\n\n/* Resize Handle */\n.resize-handle {\n position: absolute;\n top: 0;\n right: 0;\n width: 4px;\n height: 100%;\n cursor: ew-resize;\n background: transparent;\n transition: background 0.15s ease;\n z-index: 10;\n}\n\n.resize-handle:hover,\n.resize-handle:active {\n background: var(--mj-brand-primary);\n}\n\n/* Collapsed State */\n.tree-panel-collapsed {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 8px 4px;\n background: var(--mj-bg-surface-card);\n border-right: 1px solid var(--mj-border-default);\n width: 44px;\n gap: 4px;\n}\n\n.tree-panel-collapsed button {\n padding: 8px;\n}\n\n.tree-panel-collapsed button.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n/* Scrollbar Styling */\n.tree-content::-webkit-scrollbar {\n width: 6px;\n}\n\n.tree-content::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.tree-content::-webkit-scrollbar-thumb {\n background: var(--mj-border-default);\n border-radius: 3px;\n}\n\n.tree-content::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-muted);\n}\n\n/* Mobile Responsiveness */\n@media (max-width: 768px) {\n .tree-panel {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n z-index: 100;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);\n }\n}\n"] }]
|
|
437
437
|
}], () => [{ type: i1.ActionExplorerStateService }, { type: i0.ChangeDetectorRef }], { Categories: [{
|
|
438
438
|
type: Input
|
|
439
439
|
}], Actions: [{
|
|
@@ -322,7 +322,7 @@ export class NewActionPanelComponent {
|
|
|
322
322
|
i0.ɵɵconditionalCreate(0, NewActionPanelComponent_Conditional_0_Template, 40, 24, "div", 0);
|
|
323
323
|
} if (rf & 2) {
|
|
324
324
|
i0.ɵɵconditional(ctx.IsOpen ? 0 : -1);
|
|
325
|
-
} }, dependencies: [i3.NgControlStatus, i3.MaxLengthValidator, i3.NgModel, i4.DropDownListComponent, i5.TextBoxComponent, i5.TextAreaComponent, i6.ButtonComponent], styles: [".panel-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background:
|
|
325
|
+
} }, dependencies: [i3.NgControlStatus, i3.MaxLengthValidator, i3.NgModel, i4.DropDownListComponent, i5.TextBoxComponent, i5.TextAreaComponent, i6.ButtonComponent], styles: [".panel-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 1000;\n display: flex;\n justify-content: flex-end;\n}\n\n.slide-panel[_ngcontent-%COMP%] {\n width: 500px;\n max-width: 100%;\n height: 100%;\n background: var(--mj-bg-surface-card);\n box-shadow: -4px 0 24px rgba(0, 0, 0, 0.15);\n display: flex;\n flex-direction: column;\n}\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 20px 24px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.panel-header[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 10px;\n color: var(--mj-text-primary);\n}\n\n.panel-header[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.panel-content[_ngcontent-%COMP%] {\n flex: 1;\n padding: 24px;\n overflow-y: auto;\n}\n\n.error-banner[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n border-radius: 8px;\n margin-bottom: 20px;\n font-size: 14px;\n}\n\n.error-banner[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.form-group[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n}\n\n.form-label[_ngcontent-%COMP%] {\n display: block;\n margin-bottom: 8px;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.form-label.required[_ngcontent-%COMP%]::after {\n content: ' *';\n color: var(--mj-status-error);\n}\n\n\n\n.type-selector[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.type-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 14px 16px;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n background: var(--mj-bg-surface-card);\n cursor: pointer;\n transition: all 0.2s ease;\n text-align: left;\n}\n\n.type-option[_ngcontent-%COMP%]:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n background: var(--mj-bg-surface-hover);\n}\n\n.type-option.selected[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.type-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n border-radius: 10px;\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.type-option.selected[_ngcontent-%COMP%] .type-icon[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n}\n\n.type-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 18px;\n color: var(--mj-text-muted);\n}\n\n.type-option.selected[_ngcontent-%COMP%] .type-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-inverse);\n}\n\n.type-info[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.type-label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.type-description[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.check-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n\n\n.form-group[_ngcontent-%COMP%] kendo-textbox[_ngcontent-%COMP%], \n.form-group[_ngcontent-%COMP%] kendo-textarea[_ngcontent-%COMP%], \n.form-group[_ngcontent-%COMP%] kendo-dropdownlist[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.form-group[_ngcontent-%COMP%] kendo-textbox.invalid[_ngcontent-%COMP%], \n.form-group[_ngcontent-%COMP%] kendo-textarea.invalid[_ngcontent-%COMP%], \n.form-group[_ngcontent-%COMP%] kendo-dropdownlist.invalid[_ngcontent-%COMP%] {\n border-color: var(--mj-status-error);\n}\n\n.error-text[_ngcontent-%COMP%] {\n display: block;\n margin-top: 4px;\n font-size: 12px;\n color: var(--mj-status-error);\n}\n\n\n\n.info-box[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n padding: 14px 16px;\n background: color-mix(in srgb, var(--mj-status-info) 10%, var(--mj-bg-surface));\n border-radius: 8px;\n margin-top: 24px;\n}\n\n.info-box[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-info);\n font-size: 16px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.info-box[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n color: var(--mj-text-primary);\n line-height: 1.5;\n}\n\n.panel-footer[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n padding: 16px 24px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n}\n\n.panel-footer[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n\n\n@media (max-width: 520px) {\n .slide-panel[_ngcontent-%COMP%] {\n width: 100%;\n }\n}"], data: { animation: [
|
|
326
326
|
trigger('slideIn', [
|
|
327
327
|
transition(':enter', [
|
|
328
328
|
style({ transform: 'translateX(100%)', opacity: 0 }),
|
|
@@ -346,7 +346,7 @@ export class NewActionPanelComponent {
|
|
|
346
346
|
animate('200ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))
|
|
347
347
|
])
|
|
348
348
|
])
|
|
349
|
-
], template: "@if (IsOpen) {\n <div class=\"panel-backdrop\" (click)=\"onBackdropClick($event)\">\n <div class=\"slide-panel\" @slideIn>\n <div class=\"panel-header\">\n <h2>\n <i class=\"fa-solid fa-bolt\"></i>\n New Action\n </h2>\n <button kendoButton\n [fillMode]=\"'flat'\"\n (click)=\"onClose()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"panel-content\">\n @if (Errors['general']) {\n <div class=\"error-banner\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n {{ Errors['general'] }}\n </div>\n }\n\n <!-- Action Type Selection -->\n <div class=\"form-group\">\n <label class=\"form-label required\">Action Type</label>\n <div class=\"type-selector\">\n @for (option of TypeOptions; track option.value) {\n <button class=\"type-option\"\n [class.selected]=\"Type === option.value\"\n (click)=\"selectType(option.value)\">\n <div class=\"type-icon\">\n <i [class]=\"option.icon\"></i>\n </div>\n <div class=\"type-info\">\n <span class=\"type-label\">{{ option.label }}</span>\n <span class=\"type-description\">{{ option.description }}</span>\n </div>\n @if (Type === option.value) {\n <i class=\"fa-solid fa-check check-icon\"></i>\n }\n </button>\n }\n </div>\n </div>\n\n <div class=\"form-group\">\n <label for=\"actionName\" class=\"form-label required\">\n Action Name\n </label>\n <kendo-textbox\n id=\"actionName\"\n [(ngModel)]=\"Name\"\n [placeholder]=\"'Enter action name'\"\n [maxlength]=\"425\"\n [class.invalid]=\"Errors['name']\">\n </kendo-textbox>\n @if (Errors['name']) {\n <span class=\"error-text\">{{ Errors['name'] }}</span>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"actionDescription\" class=\"form-label\">\n Description\n </label>\n <kendo-textarea\n id=\"actionDescription\"\n [(ngModel)]=\"Description\"\n [placeholder]=\"'Describe what this action does'\"\n [rows]=\"3\">\n </kendo-textarea>\n </div>\n\n <div class=\"form-group\">\n <label for=\"actionCategory\" class=\"form-label required\">\n Category\n </label>\n <kendo-dropdownlist\n id=\"actionCategory\"\n [(ngModel)]=\"CategoryID\"\n [data]=\"getCategoryOptions()\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n [class.invalid]=\"Errors['category']\">\n </kendo-dropdownlist>\n @if (Errors['category']) {\n <span class=\"error-text\">{{ Errors['category'] }}</span>\n }\n </div>\n\n <div class=\"info-box\">\n <i class=\"fa-solid fa-info-circle\"></i>\n <p>\n After creating the action, you'll be taken to the full action editor\n where you can configure parameters, code, and other settings.\n </p>\n </div>\n </div>\n\n <div class=\"panel-footer\">\n <button kendoButton\n [fillMode]=\"'solid'\"\n [themeColor]=\"'primary'\"\n [disabled]=\"IsSaving\"\n (click)=\"onSave()\">\n @if (IsSaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Creating...\n } @else {\n <i class=\"fa-solid fa-check\"></i>\n Create Action\n }\n </button>\n <button kendoButton\n [fillMode]=\"'outline'\"\n [disabled]=\"IsSaving\"\n (click)=\"onClose()\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n}\n", styles: [".panel-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background:
|
|
349
|
+
], template: "@if (IsOpen) {\n <div class=\"panel-backdrop\" (click)=\"onBackdropClick($event)\">\n <div class=\"slide-panel\" @slideIn>\n <div class=\"panel-header\">\n <h2>\n <i class=\"fa-solid fa-bolt\"></i>\n New Action\n </h2>\n <button kendoButton\n [fillMode]=\"'flat'\"\n (click)=\"onClose()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"panel-content\">\n @if (Errors['general']) {\n <div class=\"error-banner\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n {{ Errors['general'] }}\n </div>\n }\n\n <!-- Action Type Selection -->\n <div class=\"form-group\">\n <label class=\"form-label required\">Action Type</label>\n <div class=\"type-selector\">\n @for (option of TypeOptions; track option.value) {\n <button class=\"type-option\"\n [class.selected]=\"Type === option.value\"\n (click)=\"selectType(option.value)\">\n <div class=\"type-icon\">\n <i [class]=\"option.icon\"></i>\n </div>\n <div class=\"type-info\">\n <span class=\"type-label\">{{ option.label }}</span>\n <span class=\"type-description\">{{ option.description }}</span>\n </div>\n @if (Type === option.value) {\n <i class=\"fa-solid fa-check check-icon\"></i>\n }\n </button>\n }\n </div>\n </div>\n\n <div class=\"form-group\">\n <label for=\"actionName\" class=\"form-label required\">\n Action Name\n </label>\n <kendo-textbox\n id=\"actionName\"\n [(ngModel)]=\"Name\"\n [placeholder]=\"'Enter action name'\"\n [maxlength]=\"425\"\n [class.invalid]=\"Errors['name']\">\n </kendo-textbox>\n @if (Errors['name']) {\n <span class=\"error-text\">{{ Errors['name'] }}</span>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"actionDescription\" class=\"form-label\">\n Description\n </label>\n <kendo-textarea\n id=\"actionDescription\"\n [(ngModel)]=\"Description\"\n [placeholder]=\"'Describe what this action does'\"\n [rows]=\"3\">\n </kendo-textarea>\n </div>\n\n <div class=\"form-group\">\n <label for=\"actionCategory\" class=\"form-label required\">\n Category\n </label>\n <kendo-dropdownlist\n id=\"actionCategory\"\n [(ngModel)]=\"CategoryID\"\n [data]=\"getCategoryOptions()\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n [class.invalid]=\"Errors['category']\">\n </kendo-dropdownlist>\n @if (Errors['category']) {\n <span class=\"error-text\">{{ Errors['category'] }}</span>\n }\n </div>\n\n <div class=\"info-box\">\n <i class=\"fa-solid fa-info-circle\"></i>\n <p>\n After creating the action, you'll be taken to the full action editor\n where you can configure parameters, code, and other settings.\n </p>\n </div>\n </div>\n\n <div class=\"panel-footer\">\n <button kendoButton\n [fillMode]=\"'solid'\"\n [themeColor]=\"'primary'\"\n [disabled]=\"IsSaving\"\n (click)=\"onSave()\">\n @if (IsSaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Creating...\n } @else {\n <i class=\"fa-solid fa-check\"></i>\n Create Action\n }\n </button>\n <button kendoButton\n [fillMode]=\"'outline'\"\n [disabled]=\"IsSaving\"\n (click)=\"onClose()\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n}\n", styles: [".panel-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 1000;\n display: flex;\n justify-content: flex-end;\n}\n\n.slide-panel {\n width: 500px;\n max-width: 100%;\n height: 100%;\n background: var(--mj-bg-surface-card);\n box-shadow: -4px 0 24px rgba(0, 0, 0, 0.15);\n display: flex;\n flex-direction: column;\n}\n\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 20px 24px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.panel-header h2 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 10px;\n color: var(--mj-text-primary);\n}\n\n.panel-header h2 i {\n color: var(--mj-brand-primary);\n}\n\n.panel-content {\n flex: 1;\n padding: 24px;\n overflow-y: auto;\n}\n\n.error-banner {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n border-radius: 8px;\n margin-bottom: 20px;\n font-size: 14px;\n}\n\n.error-banner i {\n font-size: 16px;\n}\n\n.form-group {\n margin-bottom: 20px;\n}\n\n.form-label {\n display: block;\n margin-bottom: 8px;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.form-label.required::after {\n content: ' *';\n color: var(--mj-status-error);\n}\n\n/* Type Selector */\n.type-selector {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.type-option {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 14px 16px;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n background: var(--mj-bg-surface-card);\n cursor: pointer;\n transition: all 0.2s ease;\n text-align: left;\n}\n\n.type-option:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n background: var(--mj-bg-surface-hover);\n}\n\n.type-option.selected {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.type-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n border-radius: 10px;\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.type-option.selected .type-icon {\n background: var(--mj-brand-primary);\n}\n\n.type-icon i {\n font-size: 18px;\n color: var(--mj-text-muted);\n}\n\n.type-option.selected .type-icon i {\n color: var(--mj-text-inverse);\n}\n\n.type-info {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.type-label {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.type-description {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.check-icon {\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n/* Form Fields */\n.form-group kendo-textbox,\n.form-group kendo-textarea,\n.form-group kendo-dropdownlist {\n width: 100%;\n}\n\n.form-group kendo-textbox.invalid,\n.form-group kendo-textarea.invalid,\n.form-group kendo-dropdownlist.invalid {\n border-color: var(--mj-status-error);\n}\n\n.error-text {\n display: block;\n margin-top: 4px;\n font-size: 12px;\n color: var(--mj-status-error);\n}\n\n/* Info Box */\n.info-box {\n display: flex;\n gap: 12px;\n padding: 14px 16px;\n background: color-mix(in srgb, var(--mj-status-info) 10%, var(--mj-bg-surface));\n border-radius: 8px;\n margin-top: 24px;\n}\n\n.info-box i {\n color: var(--mj-status-info);\n font-size: 16px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.info-box p {\n margin: 0;\n font-size: 13px;\n color: var(--mj-text-primary);\n line-height: 1.5;\n}\n\n.panel-footer {\n display: flex;\n gap: 12px;\n padding: 16px 24px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n}\n\n.panel-footer button {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* Mobile */\n@media (max-width: 520px) {\n .slide-panel {\n width: 100%;\n }\n}\n"] }]
|
|
350
350
|
}], () => [{ type: i1.ActionExplorerStateService }, { type: i2.NavigationService }, { type: i0.ChangeDetectorRef }], { Categories: [{
|
|
351
351
|
type: Input
|
|
352
352
|
}], PreselectedCategoryId: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"new-action-panel.component.js","sourceRoot":"","sources":["../../../../src/Actions/components/explorer/new-action-panel.component.ts","../../../../src/Actions/components/explorer/new-action-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnInit,\n OnDestroy,\n ChangeDetectionStrategy,\n ChangeDetectorRef\n} from '@angular/core';\nimport { trigger, transition, style, animate } from '@angular/animations';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { Metadata, LogError, CompositeKey } from '@memberjunction/core';\nimport { MJActionCategoryEntity, MJActionEntity } from '@memberjunction/core-entities';\nimport { NavigationService } from '@memberjunction/ng-shared';\nimport { ActionExplorerStateService } from '../../services/action-explorer-state.service';\nimport { UUIDsEqual } from '@memberjunction/global';\n\ntype ActionType = 'Custom' | 'Generated';\n\n@Component({\n standalone: false,\n selector: 'mj-new-action-panel',\n templateUrl: './new-action-panel.component.html',\n styleUrls: ['./new-action-panel.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n animations: [\n trigger('slideIn', [\n transition(':enter', [\n style({ transform: 'translateX(100%)', opacity: 0 }),\n animate('250ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))\n ]),\n transition(':leave', [\n animate('200ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))\n ])\n ])\n ]\n})\nexport class NewActionPanelComponent implements OnInit, OnDestroy {\n @Input() Categories: MJActionCategoryEntity[] = [];\n @Input() PreselectedCategoryId: string | null = null;\n @Output() ActionCreated = new EventEmitter<MJActionEntity>();\n @Output() Close = new EventEmitter<void>();\n\n public IsOpen = false;\n public IsSaving = false;\n\n // Form fields\n public Name = '';\n public Description = '';\n public CategoryID: string | null = null;\n public Type: ActionType = 'Custom';\n\n // Validation\n public Errors: { [key: string]: string } = {};\n\n public TypeOptions: Array<{ value: ActionType; label: string; icon: string; description: string }> = [\n {\n value: 'Custom',\n label: 'Custom Action',\n icon: 'fa-solid fa-code',\n description: 'Write your own action code with full control'\n },\n {\n value: 'Generated',\n label: 'AI Generated',\n icon: 'fa-solid fa-robot',\n description: 'Let AI generate the action code from a prompt'\n }\n ];\n\n private destroy$ = new Subject<void>();\n\n constructor(\n public StateService: ActionExplorerStateService,\n private navigationService: NavigationService,\n private cdr: ChangeDetectorRef\n ) {}\n\n ngOnInit(): void {\n this.StateService.NewActionPanelOpen$.pipe(\n takeUntil(this.destroy$)\n ).subscribe(isOpen => {\n this.IsOpen = isOpen;\n if (isOpen) {\n this.resetForm();\n }\n this.cdr.markForCheck();\n });\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n private resetForm(): void {\n this.Name = '';\n this.Description = '';\n this.CategoryID = this.PreselectedCategoryId || (this.StateService.SelectedCategoryId !== 'all' && this.StateService.SelectedCategoryId !== 'uncategorized'\n ? this.StateService.SelectedCategoryId\n : null);\n this.Type = 'Custom';\n this.Errors = {};\n this.IsSaving = false;\n }\n\n public onClose(): void {\n this.StateService.closeNewActionPanel();\n this.Close.emit();\n }\n\n public onBackdropClick(event: MouseEvent): void {\n if ((event.target as HTMLElement).classList.contains('panel-backdrop')) {\n this.onClose();\n }\n }\n\n public validate(): boolean {\n this.Errors = {};\n\n if (!this.Name || this.Name.trim().length === 0) {\n this.Errors['name'] = 'Action name is required';\n } else if (this.Name.trim().length < 3) {\n this.Errors['name'] = 'Action name must be at least 3 characters';\n } else if (this.Name.trim().length > 425) {\n this.Errors['name'] = 'Action name must be less than 425 characters';\n }\n\n if (!this.CategoryID) {\n this.Errors['category'] = 'Please select a category';\n }\n\n return Object.keys(this.Errors).length === 0;\n }\n\n public async onSave(): Promise<void> {\n if (!this.validate()) {\n this.cdr.markForCheck();\n return;\n }\n\n this.IsSaving = true;\n this.cdr.markForCheck();\n\n try {\n const md = new Metadata();\n const action = await md.GetEntityObject<MJActionEntity>('MJ: Actions');\n\n action.Name = this.Name.trim();\n action.Description = this.Description.trim() || null;\n action.CategoryID = this.CategoryID!;\n action.Type = this.Type;\n action.Status = 'Pending'; // New actions start as pending\n\n const saved = await action.Save();\n\n if (saved) {\n this.ActionCreated.emit(action);\n this.StateService.closeNewActionPanel();\n\n // Open the full action record for editing\n const key = new CompositeKey([{ FieldName: 'ID', Value: action.ID }]);\n this.navigationService.OpenEntityRecord('MJ: Actions', key);\n } else {\n this.Errors['general'] = 'Failed to save action. Please try again.';\n }\n } catch (error) {\n LogError('Failed to create action', undefined, error);\n this.Errors['general'] = 'An error occurred while creating the action.';\n } finally {\n this.IsSaving = false;\n this.cdr.markForCheck();\n }\n }\n\n public selectType(type: ActionType): void {\n this.Type = type;\n }\n\n public getCategoryOptions(): Array<{ text: string; value: string }> {\n const options: Array<{ text: string; value: string }> = [];\n\n // Sort categories by path for easier selection\n const sortedCategories = [...this.Categories].sort((a, b) =>\n this.getCategoryPath(a).localeCompare(this.getCategoryPath(b))\n );\n\n sortedCategories.forEach(category => {\n options.push({\n text: this.getCategoryPath(category),\n value: category.ID\n });\n });\n\n return options;\n }\n\n private getCategoryPath(category: MJActionCategoryEntity): string {\n const path: string[] = [category.Name];\n let currentParentId = category.ParentID;\n\n while (currentParentId) {\n const parent = this.Categories.find(c => UUIDsEqual(c.ID, currentParentId));\n if (parent) {\n path.unshift(parent.Name);\n currentParentId = parent.ParentID || null;\n } else {\n break;\n }\n }\n\n return path.join(' / ');\n }\n}\n","@if (IsOpen) {\n <div class=\"panel-backdrop\" (click)=\"onBackdropClick($event)\">\n <div class=\"slide-panel\" @slideIn>\n <div class=\"panel-header\">\n <h2>\n <i class=\"fa-solid fa-bolt\"></i>\n New Action\n </h2>\n <button kendoButton\n [fillMode]=\"'flat'\"\n (click)=\"onClose()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"panel-content\">\n @if (Errors['general']) {\n <div class=\"error-banner\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n {{ Errors['general'] }}\n </div>\n }\n\n <!-- Action Type Selection -->\n <div class=\"form-group\">\n <label class=\"form-label required\">Action Type</label>\n <div class=\"type-selector\">\n @for (option of TypeOptions; track option.value) {\n <button class=\"type-option\"\n [class.selected]=\"Type === option.value\"\n (click)=\"selectType(option.value)\">\n <div class=\"type-icon\">\n <i [class]=\"option.icon\"></i>\n </div>\n <div class=\"type-info\">\n <span class=\"type-label\">{{ option.label }}</span>\n <span class=\"type-description\">{{ option.description }}</span>\n </div>\n @if (Type === option.value) {\n <i class=\"fa-solid fa-check check-icon\"></i>\n }\n </button>\n }\n </div>\n </div>\n\n <div class=\"form-group\">\n <label for=\"actionName\" class=\"form-label required\">\n Action Name\n </label>\n <kendo-textbox\n id=\"actionName\"\n [(ngModel)]=\"Name\"\n [placeholder]=\"'Enter action name'\"\n [maxlength]=\"425\"\n [class.invalid]=\"Errors['name']\">\n </kendo-textbox>\n @if (Errors['name']) {\n <span class=\"error-text\">{{ Errors['name'] }}</span>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"actionDescription\" class=\"form-label\">\n Description\n </label>\n <kendo-textarea\n id=\"actionDescription\"\n [(ngModel)]=\"Description\"\n [placeholder]=\"'Describe what this action does'\"\n [rows]=\"3\">\n </kendo-textarea>\n </div>\n\n <div class=\"form-group\">\n <label for=\"actionCategory\" class=\"form-label required\">\n Category\n </label>\n <kendo-dropdownlist\n id=\"actionCategory\"\n [(ngModel)]=\"CategoryID\"\n [data]=\"getCategoryOptions()\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n [class.invalid]=\"Errors['category']\">\n </kendo-dropdownlist>\n @if (Errors['category']) {\n <span class=\"error-text\">{{ Errors['category'] }}</span>\n }\n </div>\n\n <div class=\"info-box\">\n <i class=\"fa-solid fa-info-circle\"></i>\n <p>\n After creating the action, you'll be taken to the full action editor\n where you can configure parameters, code, and other settings.\n </p>\n </div>\n </div>\n\n <div class=\"panel-footer\">\n <button kendoButton\n [fillMode]=\"'solid'\"\n [themeColor]=\"'primary'\"\n [disabled]=\"IsSaving\"\n (click)=\"onSave()\">\n @if (IsSaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Creating...\n } @else {\n <i class=\"fa-solid fa-check\"></i>\n Create Action\n }\n </button>\n <button kendoButton\n [fillMode]=\"'outline'\"\n [disabled]=\"IsSaving\"\n (click)=\"onClose()\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n}\n"]}
|
|
1
|
+
{"version":3,"file":"new-action-panel.component.js","sourceRoot":"","sources":["../../../../src/Actions/components/explorer/new-action-panel.component.ts","../../../../src/Actions/components/explorer/new-action-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnInit,\n OnDestroy,\n ChangeDetectionStrategy,\n ChangeDetectorRef\n} from '@angular/core';\nimport { trigger, transition, style, animate } from '@angular/animations';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { Metadata, LogError, CompositeKey } from '@memberjunction/core';\nimport { MJActionCategoryEntity, MJActionEntity } from '@memberjunction/core-entities';\nimport { NavigationService } from '@memberjunction/ng-shared';\nimport { ActionExplorerStateService } from '../../services/action-explorer-state.service';\nimport { UUIDsEqual } from '@memberjunction/global';\n\ntype ActionType = 'Custom' | 'Generated';\n\n@Component({\n standalone: false,\n selector: 'mj-new-action-panel',\n templateUrl: './new-action-panel.component.html',\n styleUrls: ['./new-action-panel.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n animations: [\n trigger('slideIn', [\n transition(':enter', [\n style({ transform: 'translateX(100%)', opacity: 0 }),\n animate('250ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))\n ]),\n transition(':leave', [\n animate('200ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))\n ])\n ])\n ]\n})\nexport class NewActionPanelComponent implements OnInit, OnDestroy {\n @Input() Categories: MJActionCategoryEntity[] = [];\n @Input() PreselectedCategoryId: string | null = null;\n @Output() ActionCreated = new EventEmitter<MJActionEntity>();\n @Output() Close = new EventEmitter<void>();\n\n public IsOpen = false;\n public IsSaving = false;\n\n // Form fields\n public Name = '';\n public Description = '';\n public CategoryID: string | null = null;\n public Type: ActionType = 'Custom';\n\n // Validation\n public Errors: { [key: string]: string } = {};\n\n public TypeOptions: Array<{ value: ActionType; label: string; icon: string; description: string }> = [\n {\n value: 'Custom',\n label: 'Custom Action',\n icon: 'fa-solid fa-code',\n description: 'Write your own action code with full control'\n },\n {\n value: 'Generated',\n label: 'AI Generated',\n icon: 'fa-solid fa-robot',\n description: 'Let AI generate the action code from a prompt'\n }\n ];\n\n private destroy$ = new Subject<void>();\n\n constructor(\n public StateService: ActionExplorerStateService,\n private navigationService: NavigationService,\n private cdr: ChangeDetectorRef\n ) {}\n\n ngOnInit(): void {\n this.StateService.NewActionPanelOpen$.pipe(\n takeUntil(this.destroy$)\n ).subscribe(isOpen => {\n this.IsOpen = isOpen;\n if (isOpen) {\n this.resetForm();\n }\n this.cdr.markForCheck();\n });\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n private resetForm(): void {\n this.Name = '';\n this.Description = '';\n this.CategoryID = this.PreselectedCategoryId || (this.StateService.SelectedCategoryId !== 'all' && this.StateService.SelectedCategoryId !== 'uncategorized'\n ? this.StateService.SelectedCategoryId\n : null);\n this.Type = 'Custom';\n this.Errors = {};\n this.IsSaving = false;\n }\n\n public onClose(): void {\n this.StateService.closeNewActionPanel();\n this.Close.emit();\n }\n\n public onBackdropClick(event: MouseEvent): void {\n if ((event.target as HTMLElement).classList.contains('panel-backdrop')) {\n this.onClose();\n }\n }\n\n public validate(): boolean {\n this.Errors = {};\n\n if (!this.Name || this.Name.trim().length === 0) {\n this.Errors['name'] = 'Action name is required';\n } else if (this.Name.trim().length < 3) {\n this.Errors['name'] = 'Action name must be at least 3 characters';\n } else if (this.Name.trim().length > 425) {\n this.Errors['name'] = 'Action name must be less than 425 characters';\n }\n\n if (!this.CategoryID) {\n this.Errors['category'] = 'Please select a category';\n }\n\n return Object.keys(this.Errors).length === 0;\n }\n\n public async onSave(): Promise<void> {\n if (!this.validate()) {\n this.cdr.markForCheck();\n return;\n }\n\n this.IsSaving = true;\n this.cdr.markForCheck();\n\n try {\n const md = new Metadata();\n const action = await md.GetEntityObject<MJActionEntity>('MJ: Actions');\n\n action.Name = this.Name.trim();\n action.Description = this.Description.trim() || null;\n action.CategoryID = this.CategoryID!;\n action.Type = this.Type;\n action.Status = 'Pending'; // New actions start as pending\n\n const saved = await action.Save();\n\n if (saved) {\n this.ActionCreated.emit(action);\n this.StateService.closeNewActionPanel();\n\n // Open the full action record for editing\n const key = new CompositeKey([{ FieldName: 'ID', Value: action.ID }]);\n this.navigationService.OpenEntityRecord('MJ: Actions', key);\n } else {\n this.Errors['general'] = 'Failed to save action. Please try again.';\n }\n } catch (error) {\n LogError('Failed to create action', undefined, error);\n this.Errors['general'] = 'An error occurred while creating the action.';\n } finally {\n this.IsSaving = false;\n this.cdr.markForCheck();\n }\n }\n\n public selectType(type: ActionType): void {\n this.Type = type;\n }\n\n public getCategoryOptions(): Array<{ text: string; value: string }> {\n const options: Array<{ text: string; value: string }> = [];\n\n // Sort categories by path for easier selection\n const sortedCategories = [...this.Categories].sort((a, b) =>\n this.getCategoryPath(a).localeCompare(this.getCategoryPath(b))\n );\n\n sortedCategories.forEach(category => {\n options.push({\n text: this.getCategoryPath(category),\n value: category.ID\n });\n });\n\n return options;\n }\n\n private getCategoryPath(category: MJActionCategoryEntity): string {\n const path: string[] = [category.Name];\n let currentParentId = category.ParentID;\n\n while (currentParentId) {\n const parent = this.Categories.find(c => UUIDsEqual(c.ID, currentParentId));\n if (parent) {\n path.unshift(parent.Name);\n currentParentId = parent.ParentID || null;\n } else {\n break;\n }\n }\n\n return path.join(' / ');\n }\n}\n","@if (IsOpen) {\n <div class=\"panel-backdrop\" (click)=\"onBackdropClick($event)\">\n <div class=\"slide-panel\" @slideIn>\n <div class=\"panel-header\">\n <h2>\n <i class=\"fa-solid fa-bolt\"></i>\n New Action\n </h2>\n <button kendoButton\n [fillMode]=\"'flat'\"\n (click)=\"onClose()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"panel-content\">\n @if (Errors['general']) {\n <div class=\"error-banner\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n {{ Errors['general'] }}\n </div>\n }\n\n <!-- Action Type Selection -->\n <div class=\"form-group\">\n <label class=\"form-label required\">Action Type</label>\n <div class=\"type-selector\">\n @for (option of TypeOptions; track option.value) {\n <button class=\"type-option\"\n [class.selected]=\"Type === option.value\"\n (click)=\"selectType(option.value)\">\n <div class=\"type-icon\">\n <i [class]=\"option.icon\"></i>\n </div>\n <div class=\"type-info\">\n <span class=\"type-label\">{{ option.label }}</span>\n <span class=\"type-description\">{{ option.description }}</span>\n </div>\n @if (Type === option.value) {\n <i class=\"fa-solid fa-check check-icon\"></i>\n }\n </button>\n }\n </div>\n </div>\n\n <div class=\"form-group\">\n <label for=\"actionName\" class=\"form-label required\">\n Action Name\n </label>\n <kendo-textbox\n id=\"actionName\"\n [(ngModel)]=\"Name\"\n [placeholder]=\"'Enter action name'\"\n [maxlength]=\"425\"\n [class.invalid]=\"Errors['name']\">\n </kendo-textbox>\n @if (Errors['name']) {\n <span class=\"error-text\">{{ Errors['name'] }}</span>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"actionDescription\" class=\"form-label\">\n Description\n </label>\n <kendo-textarea\n id=\"actionDescription\"\n [(ngModel)]=\"Description\"\n [placeholder]=\"'Describe what this action does'\"\n [rows]=\"3\">\n </kendo-textarea>\n </div>\n\n <div class=\"form-group\">\n <label for=\"actionCategory\" class=\"form-label required\">\n Category\n </label>\n <kendo-dropdownlist\n id=\"actionCategory\"\n [(ngModel)]=\"CategoryID\"\n [data]=\"getCategoryOptions()\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n [class.invalid]=\"Errors['category']\">\n </kendo-dropdownlist>\n @if (Errors['category']) {\n <span class=\"error-text\">{{ Errors['category'] }}</span>\n }\n </div>\n\n <div class=\"info-box\">\n <i class=\"fa-solid fa-info-circle\"></i>\n <p>\n After creating the action, you'll be taken to the full action editor\n where you can configure parameters, code, and other settings.\n </p>\n </div>\n </div>\n\n <div class=\"panel-footer\">\n <button kendoButton\n [fillMode]=\"'solid'\"\n [themeColor]=\"'primary'\"\n [disabled]=\"IsSaving\"\n (click)=\"onSave()\">\n @if (IsSaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Creating...\n } @else {\n <i class=\"fa-solid fa-check\"></i>\n Create Action\n }\n </button>\n <button kendoButton\n [fillMode]=\"'outline'\"\n [disabled]=\"IsSaving\"\n (click)=\"onClose()\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n}\n"]}
|
|
@@ -245,7 +245,7 @@ export class NewCategoryPanelComponent {
|
|
|
245
245
|
i0.ɵɵconditionalCreate(0, NewCategoryPanelComponent_Conditional_0_Template, 31, 22, "div", 0);
|
|
246
246
|
} if (rf & 2) {
|
|
247
247
|
i0.ɵɵconditional(ctx.IsOpen ? 0 : -1);
|
|
248
|
-
} }, dependencies: [i2.NgControlStatus, i2.MaxLengthValidator, i2.NgModel, i3.DropDownListComponent, i4.TextBoxComponent, i4.TextAreaComponent, i5.ButtonComponent], styles: [".panel-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background:
|
|
248
|
+
} }, dependencies: [i2.NgControlStatus, i2.MaxLengthValidator, i2.NgModel, i3.DropDownListComponent, i4.TextBoxComponent, i4.TextAreaComponent, i5.ButtonComponent], styles: [".panel-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 1000;\n display: flex;\n justify-content: flex-end;\n}\n\n.slide-panel[_ngcontent-%COMP%] {\n width: 450px;\n max-width: 100%;\n height: 100%;\n background: var(--mj-bg-surface-card);\n box-shadow: -4px 0 24px rgba(0, 0, 0, 0.15);\n display: flex;\n flex-direction: column;\n}\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 20px 24px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.panel-header[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 10px;\n color: var(--mj-text-primary);\n}\n\n.panel-header[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.panel-content[_ngcontent-%COMP%] {\n flex: 1;\n padding: 24px;\n overflow-y: auto;\n}\n\n.error-banner[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n border-radius: 8px;\n margin-bottom: 20px;\n font-size: 14px;\n}\n\n.error-banner[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.form-group[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n}\n\n.form-label[_ngcontent-%COMP%] {\n display: block;\n margin-bottom: 6px;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.form-label.required[_ngcontent-%COMP%]::after {\n content: ' *';\n color: var(--mj-status-error);\n}\n\n.form-group[_ngcontent-%COMP%] kendo-textbox[_ngcontent-%COMP%], \n.form-group[_ngcontent-%COMP%] kendo-textarea[_ngcontent-%COMP%], \n.form-group[_ngcontent-%COMP%] kendo-dropdownlist[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.form-group[_ngcontent-%COMP%] kendo-textbox.invalid[_ngcontent-%COMP%], \n.form-group[_ngcontent-%COMP%] kendo-textarea.invalid[_ngcontent-%COMP%] {\n border-color: var(--mj-status-error);\n}\n\n.error-text[_ngcontent-%COMP%] {\n display: block;\n margin-top: 4px;\n font-size: 12px;\n color: var(--mj-status-error);\n}\n\n.help-text[_ngcontent-%COMP%] {\n display: block;\n margin-top: 4px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.panel-footer[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n padding: 16px 24px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n}\n\n.panel-footer[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n\n\n@media (max-width: 480px) {\n .slide-panel[_ngcontent-%COMP%] {\n width: 100%;\n }\n}"], data: { animation: [
|
|
249
249
|
trigger('slideIn', [
|
|
250
250
|
transition(':enter', [
|
|
251
251
|
style({ transform: 'translateX(100%)', opacity: 0 }),
|
|
@@ -269,7 +269,7 @@ export class NewCategoryPanelComponent {
|
|
|
269
269
|
animate('200ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))
|
|
270
270
|
])
|
|
271
271
|
])
|
|
272
|
-
], template: "@if (IsOpen) {\n <div class=\"panel-backdrop\" (click)=\"onBackdropClick($event)\">\n <div class=\"slide-panel\" @slideIn>\n <div class=\"panel-header\">\n <h2>\n <i class=\"fa-solid fa-folder-plus\"></i>\n New Category\n </h2>\n <button kendoButton\n [fillMode]=\"'flat'\"\n (click)=\"onClose()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"panel-content\">\n @if (Errors['general']) {\n <div class=\"error-banner\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n {{ Errors['general'] }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"categoryName\" class=\"form-label required\">\n Category Name\n </label>\n <kendo-textbox\n id=\"categoryName\"\n [(ngModel)]=\"Name\"\n [placeholder]=\"'Enter category name'\"\n [maxlength]=\"200\"\n [class.invalid]=\"Errors['name']\">\n </kendo-textbox>\n @if (Errors['name']) {\n <span class=\"error-text\">{{ Errors['name'] }}</span>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"categoryDescription\" class=\"form-label\">\n Description\n </label>\n <kendo-textarea\n id=\"categoryDescription\"\n [(ngModel)]=\"Description\"\n [placeholder]=\"'Optional description for this category'\"\n [rows]=\"3\"\n [maxlength]=\"1000\">\n </kendo-textarea>\n </div>\n\n <div class=\"form-group\">\n <label for=\"categoryParent\" class=\"form-label\">\n Parent Category\n </label>\n <kendo-dropdownlist\n id=\"categoryParent\"\n [(ngModel)]=\"ParentID\"\n [data]=\"getParentOptions()\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\">\n </kendo-dropdownlist>\n <span class=\"help-text\">\n Leave empty to create a root-level category\n </span>\n </div>\n </div>\n\n <div class=\"panel-footer\">\n <button kendoButton\n [fillMode]=\"'solid'\"\n [themeColor]=\"'primary'\"\n [disabled]=\"IsSaving\"\n (click)=\"onSave()\">\n @if (IsSaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Creating...\n } @else {\n <i class=\"fa-solid fa-check\"></i>\n Create Category\n }\n </button>\n <button kendoButton\n [fillMode]=\"'outline'\"\n [disabled]=\"IsSaving\"\n (click)=\"onClose()\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n}\n", styles: [".panel-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background:
|
|
272
|
+
], template: "@if (IsOpen) {\n <div class=\"panel-backdrop\" (click)=\"onBackdropClick($event)\">\n <div class=\"slide-panel\" @slideIn>\n <div class=\"panel-header\">\n <h2>\n <i class=\"fa-solid fa-folder-plus\"></i>\n New Category\n </h2>\n <button kendoButton\n [fillMode]=\"'flat'\"\n (click)=\"onClose()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"panel-content\">\n @if (Errors['general']) {\n <div class=\"error-banner\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n {{ Errors['general'] }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"categoryName\" class=\"form-label required\">\n Category Name\n </label>\n <kendo-textbox\n id=\"categoryName\"\n [(ngModel)]=\"Name\"\n [placeholder]=\"'Enter category name'\"\n [maxlength]=\"200\"\n [class.invalid]=\"Errors['name']\">\n </kendo-textbox>\n @if (Errors['name']) {\n <span class=\"error-text\">{{ Errors['name'] }}</span>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"categoryDescription\" class=\"form-label\">\n Description\n </label>\n <kendo-textarea\n id=\"categoryDescription\"\n [(ngModel)]=\"Description\"\n [placeholder]=\"'Optional description for this category'\"\n [rows]=\"3\"\n [maxlength]=\"1000\">\n </kendo-textarea>\n </div>\n\n <div class=\"form-group\">\n <label for=\"categoryParent\" class=\"form-label\">\n Parent Category\n </label>\n <kendo-dropdownlist\n id=\"categoryParent\"\n [(ngModel)]=\"ParentID\"\n [data]=\"getParentOptions()\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\">\n </kendo-dropdownlist>\n <span class=\"help-text\">\n Leave empty to create a root-level category\n </span>\n </div>\n </div>\n\n <div class=\"panel-footer\">\n <button kendoButton\n [fillMode]=\"'solid'\"\n [themeColor]=\"'primary'\"\n [disabled]=\"IsSaving\"\n (click)=\"onSave()\">\n @if (IsSaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Creating...\n } @else {\n <i class=\"fa-solid fa-check\"></i>\n Create Category\n }\n </button>\n <button kendoButton\n [fillMode]=\"'outline'\"\n [disabled]=\"IsSaving\"\n (click)=\"onClose()\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n}\n", styles: [".panel-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 1000;\n display: flex;\n justify-content: flex-end;\n}\n\n.slide-panel {\n width: 450px;\n max-width: 100%;\n height: 100%;\n background: var(--mj-bg-surface-card);\n box-shadow: -4px 0 24px rgba(0, 0, 0, 0.15);\n display: flex;\n flex-direction: column;\n}\n\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 20px 24px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.panel-header h2 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 10px;\n color: var(--mj-text-primary);\n}\n\n.panel-header h2 i {\n color: var(--mj-brand-primary);\n}\n\n.panel-content {\n flex: 1;\n padding: 24px;\n overflow-y: auto;\n}\n\n.error-banner {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n border-radius: 8px;\n margin-bottom: 20px;\n font-size: 14px;\n}\n\n.error-banner i {\n font-size: 16px;\n}\n\n.form-group {\n margin-bottom: 20px;\n}\n\n.form-label {\n display: block;\n margin-bottom: 6px;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.form-label.required::after {\n content: ' *';\n color: var(--mj-status-error);\n}\n\n.form-group kendo-textbox,\n.form-group kendo-textarea,\n.form-group kendo-dropdownlist {\n width: 100%;\n}\n\n.form-group kendo-textbox.invalid,\n.form-group kendo-textarea.invalid {\n border-color: var(--mj-status-error);\n}\n\n.error-text {\n display: block;\n margin-top: 4px;\n font-size: 12px;\n color: var(--mj-status-error);\n}\n\n.help-text {\n display: block;\n margin-top: 4px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.panel-footer {\n display: flex;\n gap: 12px;\n padding: 16px 24px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n}\n\n.panel-footer button {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* Mobile */\n@media (max-width: 480px) {\n .slide-panel {\n width: 100%;\n }\n}\n"] }]
|
|
273
273
|
}], () => [{ type: i1.ActionExplorerStateService }, { type: i0.ChangeDetectorRef }], { Categories: [{
|
|
274
274
|
type: Input
|
|
275
275
|
}], PreselectedParentId: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"new-category-panel.component.js","sourceRoot":"","sources":["../../../../src/Actions/components/explorer/new-category-panel.component.ts","../../../../src/Actions/components/explorer/new-category-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnInit,\n OnDestroy,\n ChangeDetectionStrategy,\n ChangeDetectorRef\n} from '@angular/core';\nimport { trigger, transition, style, animate } from '@angular/animations';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { Metadata, LogError } from '@memberjunction/core';\nimport { MJActionCategoryEntity } from '@memberjunction/core-entities';\nimport { ActionExplorerStateService } from '../../services/action-explorer-state.service';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n@Component({\n standalone: false,\n selector: 'mj-new-category-panel',\n templateUrl: './new-category-panel.component.html',\n styleUrls: ['./new-category-panel.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n animations: [\n trigger('slideIn', [\n transition(':enter', [\n style({ transform: 'translateX(100%)', opacity: 0 }),\n animate('250ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))\n ]),\n transition(':leave', [\n animate('200ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))\n ])\n ])\n ]\n})\nexport class NewCategoryPanelComponent implements OnInit, OnDestroy {\n @Input() Categories: MJActionCategoryEntity[] = [];\n @Input() PreselectedParentId: string | null = null;\n @Output() CategoryCreated = new EventEmitter<MJActionCategoryEntity>();\n @Output() Close = new EventEmitter<void>();\n\n public IsOpen = false;\n public IsSaving = false;\n\n // Form fields\n public Name = '';\n public Description = '';\n public ParentID: string | null = null;\n\n // Validation\n public Errors: { [key: string]: string } = {};\n\n private destroy$ = new Subject<void>();\n\n constructor(\n public StateService: ActionExplorerStateService,\n private cdr: ChangeDetectorRef\n ) {}\n\n ngOnInit(): void {\n this.StateService.NewCategoryPanelOpen$.pipe(\n takeUntil(this.destroy$)\n ).subscribe(isOpen => {\n this.IsOpen = isOpen;\n if (isOpen) {\n this.resetForm();\n if (this.PreselectedParentId) {\n this.ParentID = this.PreselectedParentId;\n }\n }\n this.cdr.markForCheck();\n });\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n private resetForm(): void {\n this.Name = '';\n this.Description = '';\n this.ParentID = this.PreselectedParentId;\n this.Errors = {};\n this.IsSaving = false;\n }\n\n public onClose(): void {\n this.StateService.closeNewCategoryPanel();\n this.Close.emit();\n }\n\n public onBackdropClick(event: MouseEvent): void {\n if ((event.target as HTMLElement).classList.contains('panel-backdrop')) {\n this.onClose();\n }\n }\n\n public validate(): boolean {\n this.Errors = {};\n\n if (!this.Name || this.Name.trim().length === 0) {\n this.Errors['name'] = 'Category name is required';\n } else if (this.Name.trim().length < 2) {\n this.Errors['name'] = 'Category name must be at least 2 characters';\n } else if (this.Name.trim().length > 200) {\n this.Errors['name'] = 'Category name must be less than 200 characters';\n }\n\n // Check for duplicate names within same parent\n const existingCategory = this.Categories.find(c =>\n c.Name.toLowerCase() === this.Name.trim().toLowerCase() &&\n (c.ParentID || null) === (this.ParentID || null)\n );\n if (existingCategory) {\n this.Errors['name'] = 'A category with this name already exists at this level';\n }\n\n return Object.keys(this.Errors).length === 0;\n }\n\n public async onSave(): Promise<void> {\n if (!this.validate()) {\n this.cdr.markForCheck();\n return;\n }\n\n this.IsSaving = true;\n this.cdr.markForCheck();\n\n try {\n const md = new Metadata();\n const category = await md.GetEntityObject<MJActionCategoryEntity>('MJ: Action Categories');\n\n category.Name = this.Name.trim();\n category.Description = this.Description.trim() || null;\n category.ParentID = this.ParentID || null;\n\n const saved = await category.Save();\n\n if (saved) {\n this.CategoryCreated.emit(category);\n this.StateService.closeNewCategoryPanel();\n } else {\n this.Errors['general'] = 'Failed to save category. Please try again.';\n }\n } catch (error) {\n LogError('Failed to create category', undefined, error);\n this.Errors['general'] = 'An error occurred while creating the category.';\n } finally {\n this.IsSaving = false;\n this.cdr.markForCheck();\n }\n }\n\n public getParentOptions(): Array<{ text: string; value: string | null }> {\n const options: Array<{ text: string; value: string | null }> = [\n { text: '(No Parent - Root Category)', value: null }\n ];\n\n // Sort categories by name for easier selection\n const sortedCategories = [...this.Categories].sort((a, b) =>\n a.Name.localeCompare(b.Name)\n );\n\n sortedCategories.forEach(category => {\n options.push({\n text: this.getCategoryPath(category),\n value: category.ID\n });\n });\n\n return options;\n }\n\n private getCategoryPath(category: MJActionCategoryEntity): string {\n const path: string[] = [category.Name];\n let currentParentId = category.ParentID;\n\n while (currentParentId) {\n const parent = this.Categories.find(c => UUIDsEqual(c.ID, currentParentId));\n if (parent) {\n path.unshift(parent.Name);\n currentParentId = parent.ParentID || null;\n } else {\n break;\n }\n }\n\n return path.join(' / ');\n }\n}\n","@if (IsOpen) {\n <div class=\"panel-backdrop\" (click)=\"onBackdropClick($event)\">\n <div class=\"slide-panel\" @slideIn>\n <div class=\"panel-header\">\n <h2>\n <i class=\"fa-solid fa-folder-plus\"></i>\n New Category\n </h2>\n <button kendoButton\n [fillMode]=\"'flat'\"\n (click)=\"onClose()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"panel-content\">\n @if (Errors['general']) {\n <div class=\"error-banner\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n {{ Errors['general'] }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"categoryName\" class=\"form-label required\">\n Category Name\n </label>\n <kendo-textbox\n id=\"categoryName\"\n [(ngModel)]=\"Name\"\n [placeholder]=\"'Enter category name'\"\n [maxlength]=\"200\"\n [class.invalid]=\"Errors['name']\">\n </kendo-textbox>\n @if (Errors['name']) {\n <span class=\"error-text\">{{ Errors['name'] }}</span>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"categoryDescription\" class=\"form-label\">\n Description\n </label>\n <kendo-textarea\n id=\"categoryDescription\"\n [(ngModel)]=\"Description\"\n [placeholder]=\"'Optional description for this category'\"\n [rows]=\"3\"\n [maxlength]=\"1000\">\n </kendo-textarea>\n </div>\n\n <div class=\"form-group\">\n <label for=\"categoryParent\" class=\"form-label\">\n Parent Category\n </label>\n <kendo-dropdownlist\n id=\"categoryParent\"\n [(ngModel)]=\"ParentID\"\n [data]=\"getParentOptions()\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\">\n </kendo-dropdownlist>\n <span class=\"help-text\">\n Leave empty to create a root-level category\n </span>\n </div>\n </div>\n\n <div class=\"panel-footer\">\n <button kendoButton\n [fillMode]=\"'solid'\"\n [themeColor]=\"'primary'\"\n [disabled]=\"IsSaving\"\n (click)=\"onSave()\">\n @if (IsSaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Creating...\n } @else {\n <i class=\"fa-solid fa-check\"></i>\n Create Category\n }\n </button>\n <button kendoButton\n [fillMode]=\"'outline'\"\n [disabled]=\"IsSaving\"\n (click)=\"onClose()\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n}\n"]}
|
|
1
|
+
{"version":3,"file":"new-category-panel.component.js","sourceRoot":"","sources":["../../../../src/Actions/components/explorer/new-category-panel.component.ts","../../../../src/Actions/components/explorer/new-category-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnInit,\n OnDestroy,\n ChangeDetectionStrategy,\n ChangeDetectorRef\n} from '@angular/core';\nimport { trigger, transition, style, animate } from '@angular/animations';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { Metadata, LogError } from '@memberjunction/core';\nimport { MJActionCategoryEntity } from '@memberjunction/core-entities';\nimport { ActionExplorerStateService } from '../../services/action-explorer-state.service';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n@Component({\n standalone: false,\n selector: 'mj-new-category-panel',\n templateUrl: './new-category-panel.component.html',\n styleUrls: ['./new-category-panel.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n animations: [\n trigger('slideIn', [\n transition(':enter', [\n style({ transform: 'translateX(100%)', opacity: 0 }),\n animate('250ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))\n ]),\n transition(':leave', [\n animate('200ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))\n ])\n ])\n ]\n})\nexport class NewCategoryPanelComponent implements OnInit, OnDestroy {\n @Input() Categories: MJActionCategoryEntity[] = [];\n @Input() PreselectedParentId: string | null = null;\n @Output() CategoryCreated = new EventEmitter<MJActionCategoryEntity>();\n @Output() Close = new EventEmitter<void>();\n\n public IsOpen = false;\n public IsSaving = false;\n\n // Form fields\n public Name = '';\n public Description = '';\n public ParentID: string | null = null;\n\n // Validation\n public Errors: { [key: string]: string } = {};\n\n private destroy$ = new Subject<void>();\n\n constructor(\n public StateService: ActionExplorerStateService,\n private cdr: ChangeDetectorRef\n ) {}\n\n ngOnInit(): void {\n this.StateService.NewCategoryPanelOpen$.pipe(\n takeUntil(this.destroy$)\n ).subscribe(isOpen => {\n this.IsOpen = isOpen;\n if (isOpen) {\n this.resetForm();\n if (this.PreselectedParentId) {\n this.ParentID = this.PreselectedParentId;\n }\n }\n this.cdr.markForCheck();\n });\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n private resetForm(): void {\n this.Name = '';\n this.Description = '';\n this.ParentID = this.PreselectedParentId;\n this.Errors = {};\n this.IsSaving = false;\n }\n\n public onClose(): void {\n this.StateService.closeNewCategoryPanel();\n this.Close.emit();\n }\n\n public onBackdropClick(event: MouseEvent): void {\n if ((event.target as HTMLElement).classList.contains('panel-backdrop')) {\n this.onClose();\n }\n }\n\n public validate(): boolean {\n this.Errors = {};\n\n if (!this.Name || this.Name.trim().length === 0) {\n this.Errors['name'] = 'Category name is required';\n } else if (this.Name.trim().length < 2) {\n this.Errors['name'] = 'Category name must be at least 2 characters';\n } else if (this.Name.trim().length > 200) {\n this.Errors['name'] = 'Category name must be less than 200 characters';\n }\n\n // Check for duplicate names within same parent\n const existingCategory = this.Categories.find(c =>\n c.Name.toLowerCase() === this.Name.trim().toLowerCase() &&\n (c.ParentID || null) === (this.ParentID || null)\n );\n if (existingCategory) {\n this.Errors['name'] = 'A category with this name already exists at this level';\n }\n\n return Object.keys(this.Errors).length === 0;\n }\n\n public async onSave(): Promise<void> {\n if (!this.validate()) {\n this.cdr.markForCheck();\n return;\n }\n\n this.IsSaving = true;\n this.cdr.markForCheck();\n\n try {\n const md = new Metadata();\n const category = await md.GetEntityObject<MJActionCategoryEntity>('MJ: Action Categories');\n\n category.Name = this.Name.trim();\n category.Description = this.Description.trim() || null;\n category.ParentID = this.ParentID || null;\n\n const saved = await category.Save();\n\n if (saved) {\n this.CategoryCreated.emit(category);\n this.StateService.closeNewCategoryPanel();\n } else {\n this.Errors['general'] = 'Failed to save category. Please try again.';\n }\n } catch (error) {\n LogError('Failed to create category', undefined, error);\n this.Errors['general'] = 'An error occurred while creating the category.';\n } finally {\n this.IsSaving = false;\n this.cdr.markForCheck();\n }\n }\n\n public getParentOptions(): Array<{ text: string; value: string | null }> {\n const options: Array<{ text: string; value: string | null }> = [\n { text: '(No Parent - Root Category)', value: null }\n ];\n\n // Sort categories by name for easier selection\n const sortedCategories = [...this.Categories].sort((a, b) =>\n a.Name.localeCompare(b.Name)\n );\n\n sortedCategories.forEach(category => {\n options.push({\n text: this.getCategoryPath(category),\n value: category.ID\n });\n });\n\n return options;\n }\n\n private getCategoryPath(category: MJActionCategoryEntity): string {\n const path: string[] = [category.Name];\n let currentParentId = category.ParentID;\n\n while (currentParentId) {\n const parent = this.Categories.find(c => UUIDsEqual(c.ID, currentParentId));\n if (parent) {\n path.unshift(parent.Name);\n currentParentId = parent.ParentID || null;\n } else {\n break;\n }\n }\n\n return path.join(' / ');\n }\n}\n","@if (IsOpen) {\n <div class=\"panel-backdrop\" (click)=\"onBackdropClick($event)\">\n <div class=\"slide-panel\" @slideIn>\n <div class=\"panel-header\">\n <h2>\n <i class=\"fa-solid fa-folder-plus\"></i>\n New Category\n </h2>\n <button kendoButton\n [fillMode]=\"'flat'\"\n (click)=\"onClose()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"panel-content\">\n @if (Errors['general']) {\n <div class=\"error-banner\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n {{ Errors['general'] }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"categoryName\" class=\"form-label required\">\n Category Name\n </label>\n <kendo-textbox\n id=\"categoryName\"\n [(ngModel)]=\"Name\"\n [placeholder]=\"'Enter category name'\"\n [maxlength]=\"200\"\n [class.invalid]=\"Errors['name']\">\n </kendo-textbox>\n @if (Errors['name']) {\n <span class=\"error-text\">{{ Errors['name'] }}</span>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"categoryDescription\" class=\"form-label\">\n Description\n </label>\n <kendo-textarea\n id=\"categoryDescription\"\n [(ngModel)]=\"Description\"\n [placeholder]=\"'Optional description for this category'\"\n [rows]=\"3\"\n [maxlength]=\"1000\">\n </kendo-textarea>\n </div>\n\n <div class=\"form-group\">\n <label for=\"categoryParent\" class=\"form-label\">\n Parent Category\n </label>\n <kendo-dropdownlist\n id=\"categoryParent\"\n [(ngModel)]=\"ParentID\"\n [data]=\"getParentOptions()\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\">\n </kendo-dropdownlist>\n <span class=\"help-text\">\n Leave empty to create a root-level category\n </span>\n </div>\n </div>\n\n <div class=\"panel-footer\">\n <button kendoButton\n [fillMode]=\"'solid'\"\n [themeColor]=\"'primary'\"\n [disabled]=\"IsSaving\"\n (click)=\"onSave()\">\n @if (IsSaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Creating...\n } @else {\n <i class=\"fa-solid fa-check\"></i>\n Create Category\n }\n </button>\n <button kendoButton\n [fillMode]=\"'outline'\"\n [disabled]=\"IsSaving\"\n (click)=\"onClose()\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n}\n"]}
|