@memberjunction/ng-dashboards 4.0.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -339
- package/dist/AI/components/agents/agent-configuration.component.js +1 -1
- package/dist/AI/components/agents/agent-editor.component.js +1 -1
- package/dist/AI/components/agents/agent-filter-panel.component.js +1 -1
- package/dist/AI/components/charts/performance-heatmap.component.js +1 -1
- package/dist/AI/components/charts/time-series-chart.component.js +1 -1
- package/dist/AI/components/execution-monitoring.component.js +1 -1
- package/dist/AI/components/models/model-management.component.js +1 -1
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js +1 -1
- package/dist/AI/components/prompts/prompt-filter-panel.component.js +1 -1
- package/dist/AI/components/prompts/prompt-management.component.js +1 -1
- package/dist/AI/components/prompts/prompt-version-control.component.js +1 -1
- package/dist/AI/components/system/system-config-filter-panel.component.js +1 -1
- package/dist/AI/components/system/system-configuration.component.js +1 -1
- package/dist/AI/components/widgets/kpi-card.component.js +1 -1
- package/dist/AI/components/widgets/live-execution-widget.component.js +1 -1
- package/dist/APIKeys/api-applications-panel.component.js +1 -1
- package/dist/APIKeys/api-key-create-dialog.component.js +1 -1
- package/dist/APIKeys/api-key-edit-panel.component.js +1 -1
- package/dist/APIKeys/api-key-list.component.js +1 -1
- package/dist/APIKeys/api-keys-resource.component.js +1 -1
- package/dist/APIKeys/api-scopes-panel.component.js +1 -1
- package/dist/APIKeys/api-usage-panel.component.js +1 -1
- package/dist/Actions/components/actions-list-view.component.js +1 -1
- package/dist/Actions/components/actions-overview.component.js +1 -1
- package/dist/Actions/components/categories-list-view.component.js +1 -1
- package/dist/Actions/components/code-management.component.js +1 -1
- package/dist/Actions/components/entity-integration.component.js +1 -1
- package/dist/Actions/components/execution-monitoring.component.js +1 -1
- package/dist/Actions/components/executions-list-view.component.js +1 -1
- package/dist/Actions/components/explorer/action-breadcrumb.component.js +1 -1
- package/dist/Actions/components/explorer/action-card.component.js +1 -1
- package/dist/Actions/components/explorer/action-explorer.component.js +1 -1
- package/dist/Actions/components/explorer/action-list-item.component.js +1 -1
- package/dist/Actions/components/explorer/action-toolbar.component.js +1 -1
- package/dist/Actions/components/explorer/action-tree-panel.component.js +1 -1
- package/dist/Actions/components/explorer/new-action-panel.component.js +1 -1
- package/dist/Actions/components/explorer/new-category-panel.component.js +1 -1
- package/dist/Actions/components/scheduled-actions.component.js +1 -1
- package/dist/Actions/components/security-permissions.component.js +1 -1
- package/dist/Communication/communication-dashboard.component.js +1 -1
- package/dist/Communication/communication-logs-resource.component.js +1 -1
- package/dist/Communication/communication-monitor-resource.component.js +1 -1
- package/dist/Communication/communication-providers-resource.component.js +1 -1
- package/dist/Communication/communication-runs-resource.component.js +1 -1
- package/dist/Communication/communication-templates-resource.component.js +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.js +1 -1
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +1 -1
- package/dist/ComponentStudio/components/artifact-load-dialog.component.js +1 -1
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.js +1 -1
- package/dist/ComponentStudio/components/browser/component-browser.component.js +1 -1
- package/dist/ComponentStudio/components/editors/code-editor-panel.component.js +1 -1
- package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js +1 -1
- package/dist/ComponentStudio/components/editors/requirements-editor.component.js +1 -1
- package/dist/ComponentStudio/components/editors/spec-editor.component.js +1 -1
- package/dist/ComponentStudio/components/new-component-dialog/new-component-dialog.component.js +1 -1
- package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.js +1 -1
- package/dist/ComponentStudio/components/text-import-dialog.component.js +1 -1
- package/dist/ComponentStudio/components/workspace/component-preview.component.js +1 -1
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.js +1 -1
- package/dist/Credentials/components/credentials-audit-resource.component.js +1 -1
- package/dist/Credentials/components/credentials-categories-resource.component.js +1 -1
- package/dist/Credentials/components/credentials-list-resource.component.js +1 -1
- package/dist/Credentials/components/credentials-overview-resource.component.js +1 -1
- package/dist/Credentials/components/credentials-types-resource.component.js +1 -1
- package/dist/Credentials/credentials-dashboard.component.js +1 -1
- package/dist/DashboardBrowser/dashboard-browser-resource.component.js +1 -1
- package/dist/DashboardBrowser/dashboard-share-dialog.component.js +1 -1
- package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js +1 -1
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js +1 -1
- package/dist/DataExplorer/components/view-selector/view-selector.component.js +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +2 -0
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +35 -11
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/DataExplorer/data-explorer-resource.component.js +1 -1
- package/dist/EntityAdmin/entity-admin-dashboard.component.js +1 -1
- package/dist/Home/home-application.d.ts +109 -22
- package/dist/Home/home-application.d.ts.map +1 -1
- package/dist/Home/home-application.js +351 -66
- package/dist/Home/home-application.js.map +1 -1
- package/dist/Home/home-dashboard.component.d.ts +48 -8
- package/dist/Home/home-dashboard.component.d.ts.map +1 -1
- package/dist/Home/home-dashboard.component.js +140 -62
- package/dist/Home/home-dashboard.component.js.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.js +1 -1
- package/dist/Lists/components/lists-categories-resource.component.js +1 -1
- package/dist/Lists/components/lists-my-lists-resource.component.js +1 -1
- package/dist/Lists/components/lists-operations-resource.component.js +1 -1
- package/dist/Lists/components/venn-diagram/venn-diagram.component.js +1 -1
- package/dist/MCP/components/mcp-connection-dialog.component.js +1 -1
- package/dist/MCP/components/mcp-log-detail-panel.component.js +1 -1
- package/dist/MCP/components/mcp-server-dialog.component.js +1 -1
- package/dist/MCP/components/mcp-test-tool-dialog.component.js +1 -1
- package/dist/MCP/mcp-dashboard.component.js +1 -1
- package/dist/MCP/mcp-filter-panel.component.js +1 -1
- package/dist/MCP/mcp-resource.component.js +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.js +1 -1
- package/dist/Scheduling/components/job-slideout.component.js +1 -1
- package/dist/Scheduling/components/scheduling-activity-resource.component.js +1 -1
- package/dist/Scheduling/components/scheduling-activity.component.js +1 -1
- package/dist/Scheduling/components/scheduling-jobs-resource.component.js +1 -1
- package/dist/Scheduling/components/scheduling-jobs.component.js +1 -1
- package/dist/Scheduling/components/scheduling-overview-resource.component.js +1 -1
- package/dist/Scheduling/components/scheduling-overview.component.js +1 -1
- package/dist/Scheduling/scheduling-dashboard.component.js +1 -1
- package/dist/SystemDiagnostics/system-diagnostics.component.js +1 -1
- package/dist/Testing/components/testing-analytics-resource.component.js +1 -1
- package/dist/Testing/components/testing-analytics.component.js +1 -1
- package/dist/Testing/components/testing-dashboard-tab-resource.component.js +1 -1
- package/dist/Testing/components/testing-dashboard-tab.component.js +1 -1
- package/dist/Testing/components/testing-explorer-resource.component.js +1 -1
- package/dist/Testing/components/testing-explorer.component.js +1 -1
- package/dist/Testing/components/testing-review-resource.component.js +1 -1
- package/dist/Testing/components/testing-review.component.js +1 -1
- package/dist/Testing/components/testing-runs-resource.component.js +1 -1
- package/dist/Testing/components/testing-runs.component.js +1 -1
- package/dist/Testing/components/widgets/oracle-breakdown-table.component.js +1 -1
- package/dist/Testing/components/widgets/suite-tree.component.js +2 -2
- package/dist/Testing/components/widgets/test-run-detail-panel.component.js +1 -1
- package/dist/Testing/testing-dashboard.component.js +1 -1
- package/dist/VersionHistory/components/diff-resource.component.js +1 -1
- package/dist/VersionHistory/components/graph-resource.component.js +1 -1
- package/dist/VersionHistory/components/labels-resource.component.js +1 -1
- package/dist/VersionHistory/components/restore-resource.component.js +1 -1
- package/package.json +38 -38
- package/dist/AI/ai-dashboard.component.d.ts +0 -62
- package/dist/AI/ai-dashboard.component.d.ts.map +0 -1
- package/dist/AI/ai-dashboard.component.js +0 -338
- package/dist/AI/ai-dashboard.component.js.map +0 -1
- package/dist/AI/components/models/model-management-v2.component.d.ts +0 -96
- package/dist/AI/components/models/model-management-v2.component.d.ts.map +0 -1
- package/dist/AI/components/models/model-management-v2.component.js +0 -981
- package/dist/AI/components/models/model-management-v2.component.js.map +0 -1
- package/dist/AI/components/prompts/prompt-management-v2.component.d.ts +0 -97
- package/dist/AI/components/prompts/prompt-management-v2.component.d.ts.map +0 -1
- package/dist/AI/components/prompts/prompt-management-v2.component.js +0 -811
- package/dist/AI/components/prompts/prompt-management-v2.component.js.map +0 -1
- package/dist/Actions/actions-management-dashboard.component.d.ts +0 -52
- package/dist/Actions/actions-management-dashboard.component.d.ts.map +0 -1
- package/dist/Actions/actions-management-dashboard.component.js +0 -308
- package/dist/Actions/actions-management-dashboard.component.js.map +0 -1
- package/dist/Credentials/components/credential-category-edit-panel.component.d.ts +0 -44
- package/dist/Credentials/components/credential-category-edit-panel.component.d.ts.map +0 -1
- package/dist/Credentials/components/credential-category-edit-panel.component.js +0 -456
- package/dist/Credentials/components/credential-category-edit-panel.component.js.map +0 -1
- package/dist/Credentials/components/credential-edit-panel.component.d.ts +0 -70
- package/dist/Credentials/components/credential-edit-panel.component.d.ts.map +0 -1
- package/dist/Credentials/components/credential-edit-panel.component.js +0 -694
- package/dist/Credentials/components/credential-edit-panel.component.js.map +0 -1
- package/dist/Credentials/components/credential-type-edit-panel.component.d.ts +0 -56
- package/dist/Credentials/components/credential-type-edit-panel.component.d.ts.map +0 -1
- package/dist/Credentials/components/credential-type-edit-panel.component.js +0 -563
- package/dist/Credentials/components/credential-type-edit-panel.component.js.map +0 -1
- package/dist/DataExplorer/components/view-config-panel/view-config-panel.component.d.ts +0 -245
- package/dist/DataExplorer/components/view-config-panel/view-config-panel.component.d.ts.map +0 -1
- package/dist/DataExplorer/components/view-config-panel/view-config-panel.component.js +0 -1143
- package/dist/DataExplorer/components/view-config-panel/view-config-panel.component.js.map +0 -1
- package/dist/EntityAdmin/components/entity-details.component.d.ts +0 -50
- package/dist/EntityAdmin/components/entity-details.component.d.ts.map +0 -1
- package/dist/EntityAdmin/components/entity-details.component.js +0 -680
- package/dist/EntityAdmin/components/entity-details.component.js.map +0 -1
- package/dist/EntityAdmin/components/entity-filter-panel.component.d.ts +0 -31
- package/dist/EntityAdmin/components/entity-filter-panel.component.d.ts.map +0 -1
- package/dist/EntityAdmin/components/entity-filter-panel.component.js +0 -160
- package/dist/EntityAdmin/components/entity-filter-panel.component.js.map +0 -1
- package/dist/EntityAdmin/components/erd-composite.component.d.ts +0 -73
- package/dist/EntityAdmin/components/erd-composite.component.d.ts.map +0 -1
- package/dist/EntityAdmin/components/erd-composite.component.js +0 -271
- package/dist/EntityAdmin/components/erd-composite.component.js.map +0 -1
- package/dist/EntityAdmin/components/erd-diagram.component.d.ts +0 -47
- package/dist/EntityAdmin/components/erd-diagram.component.d.ts.map +0 -1
- package/dist/EntityAdmin/components/erd-diagram.component.js +0 -618
- package/dist/EntityAdmin/components/erd-diagram.component.js.map +0 -1
- package/dist/Scheduling/components/scheduling-health-resource.component.d.ts +0 -20
- package/dist/Scheduling/components/scheduling-health-resource.component.d.ts.map +0 -1
- package/dist/Scheduling/components/scheduling-health-resource.component.js +0 -55
- package/dist/Scheduling/components/scheduling-health-resource.component.js.map +0 -1
- package/dist/Scheduling/components/scheduling-health.component.d.ts +0 -30
- package/dist/Scheduling/components/scheduling-health.component.d.ts.map +0 -1
- package/dist/Scheduling/components/scheduling-health.component.js +0 -315
- package/dist/Scheduling/components/scheduling-health.component.js.map +0 -1
- package/dist/Scheduling/components/scheduling-history-resource.component.d.ts +0 -20
- package/dist/Scheduling/components/scheduling-history-resource.component.d.ts.map +0 -1
- package/dist/Scheduling/components/scheduling-history-resource.component.js +0 -55
- package/dist/Scheduling/components/scheduling-history-resource.component.js.map +0 -1
- package/dist/Scheduling/components/scheduling-history.component.d.ts +0 -48
- package/dist/Scheduling/components/scheduling-history.component.d.ts.map +0 -1
- package/dist/Scheduling/components/scheduling-history.component.js +0 -377
- package/dist/Scheduling/components/scheduling-history.component.js.map +0 -1
- package/dist/Scheduling/components/scheduling-monitor-resource.component.d.ts +0 -20
- package/dist/Scheduling/components/scheduling-monitor-resource.component.d.ts.map +0 -1
- package/dist/Scheduling/components/scheduling-monitor-resource.component.js +0 -55
- package/dist/Scheduling/components/scheduling-monitor-resource.component.js.map +0 -1
- package/dist/Scheduling/components/scheduling-monitoring.component.d.ts +0 -37
- package/dist/Scheduling/components/scheduling-monitoring.component.d.ts.map +0 -1
- package/dist/Scheduling/components/scheduling-monitoring.component.js +0 -488
- package/dist/Scheduling/components/scheduling-monitoring.component.js.map +0 -1
- package/dist/Scheduling/components/scheduling-types-resource.component.d.ts +0 -20
- package/dist/Scheduling/components/scheduling-types-resource.component.d.ts.map +0 -1
- package/dist/Scheduling/components/scheduling-types-resource.component.js +0 -55
- package/dist/Scheduling/components/scheduling-types-resource.component.js.map +0 -1
- package/dist/Scheduling/components/scheduling-types.component.d.ts +0 -22
- package/dist/Scheduling/components/scheduling-types.component.d.ts.map +0 -1
- package/dist/Scheduling/components/scheduling-types.component.js +0 -165
- package/dist/Scheduling/components/scheduling-types.component.js.map +0 -1
- package/dist/Testing/components/testing-execution-resource.component.d.ts +0 -20
- package/dist/Testing/components/testing-execution-resource.component.d.ts.map +0 -1
- package/dist/Testing/components/testing-execution-resource.component.js +0 -55
- package/dist/Testing/components/testing-execution-resource.component.js.map +0 -1
- package/dist/Testing/components/testing-execution.component.d.ts +0 -71
- package/dist/Testing/components/testing-execution.component.d.ts.map +0 -1
- package/dist/Testing/components/testing-execution.component.js +0 -845
- package/dist/Testing/components/testing-execution.component.js.map +0 -1
- package/dist/Testing/components/testing-feedback-resource.component.d.ts +0 -20
- package/dist/Testing/components/testing-feedback-resource.component.d.ts.map +0 -1
- package/dist/Testing/components/testing-feedback-resource.component.js +0 -55
- package/dist/Testing/components/testing-feedback-resource.component.js.map +0 -1
- package/dist/Testing/components/testing-feedback.component.d.ts +0 -111
- package/dist/Testing/components/testing-feedback.component.d.ts.map +0 -1
- package/dist/Testing/components/testing-feedback.component.js +0 -1486
- package/dist/Testing/components/testing-feedback.component.js.map +0 -1
- package/dist/Testing/components/testing-overview-resource.component.d.ts +0 -20
- package/dist/Testing/components/testing-overview-resource.component.d.ts.map +0 -1
- package/dist/Testing/components/testing-overview-resource.component.js +0 -55
- package/dist/Testing/components/testing-overview-resource.component.js.map +0 -1
- package/dist/Testing/components/testing-overview.component.d.ts +0 -30
- package/dist/Testing/components/testing-overview.component.d.ts.map +0 -1
- package/dist/Testing/components/testing-overview.component.js +0 -361
- package/dist/Testing/components/testing-overview.component.js.map +0 -1
- package/dist/Testing/components/testing-version-comparison.component.d.ts +0 -62
- package/dist/Testing/components/testing-version-comparison.component.d.ts.map +0 -1
- package/dist/Testing/components/testing-version-comparison.component.js +0 -815
- package/dist/Testing/components/testing-version-comparison.component.js.map +0 -1
- package/dist/Testing/components/testing-version-resource.component.d.ts +0 -20
- package/dist/Testing/components/testing-version-resource.component.d.ts.map +0 -1
- package/dist/Testing/components/testing-version-resource.component.js +0 -55
- package/dist/Testing/components/testing-version-resource.component.js.map +0 -1
- package/dist/generic/base-dashboard.d.ts +0 -65
- package/dist/generic/base-dashboard.d.ts.map +0 -1
- package/dist/generic/base-dashboard.js +0 -74
- package/dist/generic/base-dashboard.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,16 +1,91 @@
|
|
|
1
1
|
# @memberjunction/ng-dashboards
|
|
2
2
|
|
|
3
|
-
Angular dashboard components for MemberJunction Explorer, providing
|
|
4
|
-
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
Comprehensive Angular dashboard components for MemberJunction Explorer, providing administrative interfaces for AI operations, entity management, actions, communication, testing, scheduling, credentials, API keys, version history, MCP servers, and more.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This package provides a rich collection of dashboard components registered as `BaseResourceComponent` subclasses. Each dashboard is loaded dynamically within the Explorer shell based on application navigation configuration. Dashboards follow MemberJunction's engine-class pattern for data access (no Angular services for data) and use getter/setter state management for reactivity.
|
|
8
|
+
|
|
9
|
+
```mermaid
|
|
10
|
+
graph TD
|
|
11
|
+
BRC["BaseResourceComponent"] --> AID["AI Dashboard"]
|
|
12
|
+
BRC --> EAD["Entity Admin Dashboard"]
|
|
13
|
+
BRC --> ACT["Actions Dashboard"]
|
|
14
|
+
BRC --> COM["Communication Dashboard"]
|
|
15
|
+
BRC --> TST["Testing Dashboard"]
|
|
16
|
+
BRC --> SCH["Scheduling Dashboard"]
|
|
17
|
+
BRC --> CRD["Credentials Dashboard"]
|
|
18
|
+
BRC --> AK["API Keys Dashboard"]
|
|
19
|
+
BRC --> MCP["MCP Dashboard"]
|
|
20
|
+
BRC --> CS["Component Studio"]
|
|
21
|
+
BRC --> DE["Data Explorer"]
|
|
22
|
+
BRC --> VH["Version History"]
|
|
23
|
+
BRC --> QB["Query Browser"]
|
|
24
|
+
BRC --> DB["Dashboard Browser"]
|
|
25
|
+
BRC --> HD["Home Dashboard"]
|
|
26
|
+
BRC --> LST["Lists Dashboard"]
|
|
27
|
+
|
|
28
|
+
style BRC fill:#7c5295,stroke:#563a6b,color:#fff
|
|
29
|
+
style AID fill:#2d6a9f,stroke:#1a4971,color:#fff
|
|
30
|
+
style EAD fill:#2d6a9f,stroke:#1a4971,color:#fff
|
|
31
|
+
style ACT fill:#2d6a9f,stroke:#1a4971,color:#fff
|
|
32
|
+
style COM fill:#2d8659,stroke:#1a5c3a,color:#fff
|
|
33
|
+
style TST fill:#2d8659,stroke:#1a5c3a,color:#fff
|
|
34
|
+
style SCH fill:#2d8659,stroke:#1a5c3a,color:#fff
|
|
35
|
+
style CRD fill:#b8762f,stroke:#8a5722,color:#fff
|
|
36
|
+
style AK fill:#b8762f,stroke:#8a5722,color:#fff
|
|
37
|
+
style MCP fill:#b8762f,stroke:#8a5722,color:#fff
|
|
38
|
+
style CS fill:#b8762f,stroke:#8a5722,color:#fff
|
|
39
|
+
style DE fill:#2d6a9f,stroke:#1a4971,color:#fff
|
|
40
|
+
style VH fill:#2d8659,stroke:#1a5c3a,color:#fff
|
|
41
|
+
style QB fill:#b8762f,stroke:#8a5722,color:#fff
|
|
42
|
+
style DB fill:#b8762f,stroke:#8a5722,color:#fff
|
|
43
|
+
style HD fill:#7c5295,stroke:#563a6b,color:#fff
|
|
44
|
+
style LST fill:#2d6a9f,stroke:#1a4971,color:#fff
|
|
45
|
+
```
|
|
12
46
|
|
|
13
|
-
|
|
47
|
+
## Dashboards
|
|
48
|
+
|
|
49
|
+
### AI Dashboard
|
|
50
|
+
- **Execution Monitoring**: Real-time AI execution tracking with KPI cards, time-series charts, and performance heatmaps
|
|
51
|
+
- **Prompt Management**: Create, edit, and version AI prompts with model-prompt priority matrix
|
|
52
|
+
- **Agent Configuration**: Configure AI agents with filtering and inline editing
|
|
53
|
+
- **Model Management**: Manage AI model configurations
|
|
54
|
+
- **System Configuration**: System-wide AI settings management
|
|
55
|
+
|
|
56
|
+
### Actions Dashboard
|
|
57
|
+
- **Action Explorer**: Tree-based action browser with category management
|
|
58
|
+
- **Execution Monitoring**: Monitor action execution logs
|
|
59
|
+
- **Scheduled Actions**: Manage scheduled action configurations
|
|
60
|
+
- **Code Management**: View and manage action code
|
|
61
|
+
- **Entity Integration**: Configure entity-action relationships
|
|
62
|
+
- **Security Permissions**: Manage action-level permissions
|
|
63
|
+
|
|
64
|
+
### Data Explorer
|
|
65
|
+
- **Navigation Panel**: Tree-based entity browser
|
|
66
|
+
- **View Selector**: Switch between entity views with filtering
|
|
67
|
+
- **Filter Dialog**: Dynamic filter construction
|
|
68
|
+
|
|
69
|
+
### Communication Dashboard
|
|
70
|
+
- Monitor, logs, providers, runs, and template management for entity communications
|
|
71
|
+
|
|
72
|
+
### Testing Dashboard
|
|
73
|
+
- Test execution, analytics, review, and explorer views for MJ's testing framework
|
|
74
|
+
|
|
75
|
+
### Scheduling Dashboard
|
|
76
|
+
- Overview, jobs, and activity monitoring for scheduled tasks
|
|
77
|
+
|
|
78
|
+
### Component Studio
|
|
79
|
+
- Visual component builder with AI assistant, code editing, specs, and versioning
|
|
80
|
+
|
|
81
|
+
### Additional Dashboards
|
|
82
|
+
- **API Keys**: API key management with scopes, applications, and usage tracking
|
|
83
|
+
- **Credentials**: Credential management with categories, types, and audit
|
|
84
|
+
- **MCP (Model Context Protocol)**: MCP server management and testing
|
|
85
|
+
- **Version History**: Labels, diffs, restore, and graph visualization
|
|
86
|
+
- **Query Browser / Dashboard Browser**: Browse and manage queries and dashboards
|
|
87
|
+
- **Lists**: List management with categories, operations, and Venn diagrams
|
|
88
|
+
- **Home**: Default landing dashboard
|
|
14
89
|
|
|
15
90
|
## Installation
|
|
16
91
|
|
|
@@ -18,350 +93,38 @@ All dashboards extend the `BaseDashboard` class, providing consistent state mana
|
|
|
18
93
|
npm install @memberjunction/ng-dashboards
|
|
19
94
|
```
|
|
20
95
|
|
|
21
|
-
## Dependencies
|
|
22
|
-
|
|
23
|
-
### Peer Dependencies
|
|
24
|
-
- `@angular/common`: 18.0.2
|
|
25
|
-
- `@angular/core`: 18.0.2
|
|
26
|
-
- `@angular/forms`: 18.0.2
|
|
96
|
+
## Key Dependencies
|
|
27
97
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
- `@memberjunction/ng-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
|
|
98
|
+
| Dependency | Purpose |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `@memberjunction/core`, `@memberjunction/core-entities` | Entity metadata and data access |
|
|
101
|
+
| `@memberjunction/ng-base-application` | BaseResourceComponent base |
|
|
102
|
+
| `@memberjunction/ng-shared`, `@memberjunction/ng-shared-generic` | Shared services, loading indicators |
|
|
103
|
+
| `@memberjunction/ng-dashboard-viewer` | Dashboard rendering |
|
|
104
|
+
| `@memberjunction/ng-query-viewer` | Query execution and display |
|
|
105
|
+
| `@progress/kendo-angular-*` | Kendo UI components |
|
|
106
|
+
| `d3` | Data visualization |
|
|
107
|
+
| `codemirror` | Code editing |
|
|
38
108
|
|
|
39
109
|
## Usage
|
|
40
110
|
|
|
41
|
-
### 1. Import the Module
|
|
42
|
-
|
|
43
111
|
```typescript
|
|
44
112
|
import { DashboardsModule } from '@memberjunction/ng-dashboards';
|
|
45
113
|
|
|
46
114
|
@NgModule({
|
|
47
|
-
imports: [
|
|
48
|
-
// ... other imports
|
|
49
|
-
DashboardsModule
|
|
50
|
-
]
|
|
51
|
-
})
|
|
52
|
-
export class YourModule { }
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### 2. Using the AI Dashboard
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
import { Component } from '@angular/core';
|
|
59
|
-
import { DashboardConfig } from '@memberjunction/ng-dashboards';
|
|
60
|
-
|
|
61
|
-
@Component({
|
|
62
|
-
template: `
|
|
63
|
-
<mj-ai-dashboard
|
|
64
|
-
[Config]="dashboardConfig"
|
|
65
|
-
(LoadingComplete)="onLoadingComplete()"
|
|
66
|
-
(Error)="onError($event)"
|
|
67
|
-
(UserStateChanged)="onStateChanged($event)"
|
|
68
|
-
(OpenEntityRecord)="onOpenRecord($event)">
|
|
69
|
-
</mj-ai-dashboard>
|
|
70
|
-
`
|
|
71
|
-
})
|
|
72
|
-
export class AIManagementComponent {
|
|
73
|
-
dashboardConfig: DashboardConfig = {
|
|
74
|
-
dashboard: dashboardEntity, // DashboardEntityExtended instance
|
|
75
|
-
userState: savedUserState // Optional: Previously saved state
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
onLoadingComplete() {
|
|
79
|
-
console.log('AI Dashboard loaded');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
onError(error: Error) {
|
|
83
|
-
console.error('Dashboard error:', error);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
onStateChanged(state: any) {
|
|
87
|
-
// Save user state for persistence
|
|
88
|
-
localStorage.setItem('ai-dashboard-state', JSON.stringify(state));
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
onOpenRecord(event: {EntityName: string, RecordPKey: CompositeKey}) {
|
|
92
|
-
// Handle opening entity records
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### 3. Using the Entity Admin Dashboard
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
@Component({
|
|
101
|
-
template: `
|
|
102
|
-
<mj-entity-admin-dashboard
|
|
103
|
-
[Config]="dashboardConfig"
|
|
104
|
-
(LoadingComplete)="onLoadingComplete()"
|
|
105
|
-
(UserStateChanged)="onStateChanged($event)">
|
|
106
|
-
</mj-entity-admin-dashboard>
|
|
107
|
-
`
|
|
108
|
-
})
|
|
109
|
-
export class EntityAdminComponent {
|
|
110
|
-
dashboardConfig: DashboardConfig = {
|
|
111
|
-
dashboard: dashboardEntity
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### 4. Using the Actions Management Dashboard
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
@Component({
|
|
120
|
-
template: `
|
|
121
|
-
<mj-actions-management-dashboard
|
|
122
|
-
[Config]="dashboardConfig"
|
|
123
|
-
(LoadingComplete)="onLoadingComplete()"
|
|
124
|
-
(UserStateChanged)="onStateChanged($event)">
|
|
125
|
-
</mj-actions-management-dashboard>
|
|
126
|
-
`
|
|
127
|
-
})
|
|
128
|
-
export class ActionsManagementComponent {
|
|
129
|
-
dashboardConfig: DashboardConfig = {
|
|
130
|
-
dashboard: dashboardEntity
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
## API Documentation
|
|
136
|
-
|
|
137
|
-
### BaseDashboard Class
|
|
138
|
-
|
|
139
|
-
All dashboards extend the `BaseDashboard` abstract class, which provides:
|
|
140
|
-
|
|
141
|
-
#### Inputs
|
|
142
|
-
- `Config: DashboardConfig` - Dashboard configuration including entity and optional user state
|
|
143
|
-
|
|
144
|
-
#### Outputs
|
|
145
|
-
- `LoadingComplete: EventEmitter<void>` - Emitted when dashboard has finished loading
|
|
146
|
-
- `Error: EventEmitter<Error>` - Emitted when an error occurs
|
|
147
|
-
- `UserStateChanged: EventEmitter<any>` - Emitted when dashboard state changes (for persistence)
|
|
148
|
-
- `Interaction: EventEmitter<any>` - General interaction events
|
|
149
|
-
- `OpenEntityRecord: EventEmitter<{EntityName: string, RecordPKey: CompositeKey}>` - Request to open an entity record
|
|
150
|
-
|
|
151
|
-
#### Methods
|
|
152
|
-
- `Refresh(): void` - Reload dashboard data
|
|
153
|
-
- `SetVisible(visible: boolean): void` - Notify dashboard of visibility changes
|
|
154
|
-
|
|
155
|
-
### AI Dashboard Components
|
|
156
|
-
|
|
157
|
-
The AI Dashboard includes the following sub-components:
|
|
158
|
-
|
|
159
|
-
- **ModelManagementComponent**: Manage AI models and configurations
|
|
160
|
-
- **PromptManagementComponent**: Create and manage AI prompts
|
|
161
|
-
- **AgentConfigurationComponent**: Configure AI agents
|
|
162
|
-
- **ExecutionMonitoringComponent**: Monitor AI system execution
|
|
163
|
-
- **SystemConfigurationComponent**: Configure system-wide AI settings
|
|
164
|
-
|
|
165
|
-
### Entity Admin Dashboard Components
|
|
166
|
-
|
|
167
|
-
- **ERDCompositeComponent**: Main ERD visualization and management
|
|
168
|
-
- **EntityFilterPanelComponent**: Filter entities by various criteria
|
|
169
|
-
- **EntityDetailsComponent**: Detailed entity information display
|
|
170
|
-
- **ERDDiagramComponent**: Interactive entity relationship diagram
|
|
171
|
-
|
|
172
|
-
### Actions Management Dashboard Components
|
|
173
|
-
|
|
174
|
-
- **ActionsOverviewComponent**: Overview of all system actions
|
|
175
|
-
- **ExecutionMonitoringComponent**: Monitor action executions
|
|
176
|
-
- **ScheduledActionsComponent**: Manage scheduled actions
|
|
177
|
-
- **CodeManagementComponent**: Manage action code
|
|
178
|
-
- **EntityIntegrationComponent**: Configure entity integrations
|
|
179
|
-
- **SecurityPermissionsComponent**: Manage action permissions
|
|
180
|
-
|
|
181
|
-
## Configuration Options
|
|
182
|
-
|
|
183
|
-
### DashboardConfig Interface
|
|
184
|
-
|
|
185
|
-
```typescript
|
|
186
|
-
interface DashboardConfig {
|
|
187
|
-
dashboard: DashboardEntityExtended; // Dashboard entity from MemberJunction
|
|
188
|
-
userState?: any; // Optional saved user state
|
|
189
|
-
}
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
### State Management
|
|
193
|
-
|
|
194
|
-
Each dashboard maintains its own state structure that can be persisted and restored. The state management pattern follows these principles:
|
|
195
|
-
|
|
196
|
-
1. **State Initialization**: When a dashboard loads, the `loadData()` method checks for user state in the `Config` property and applies it
|
|
197
|
-
2. **State Changes**: Components emit state changes via `UserStateChanged` events with debouncing to prevent excessive updates
|
|
198
|
-
3. **State Persistence**: Parent components should listen to `UserStateChanged` events and persist the state as needed
|
|
199
|
-
4. **State Restoration**: Pass previously saved state through the `Config.userState` property when initializing the dashboard
|
|
200
|
-
|
|
201
|
-
#### How State Loading Works
|
|
202
|
-
|
|
203
|
-
When a dashboard component initializes:
|
|
204
|
-
|
|
205
|
-
```typescript
|
|
206
|
-
// In the dashboard's loadData() method
|
|
207
|
-
loadData(): void {
|
|
208
|
-
// Check if we have user state in the Config and apply it
|
|
209
|
-
if (this.Config?.userState) {
|
|
210
|
-
this.loadUserState(this.Config.userState);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Continue with other initialization...
|
|
214
|
-
this.LoadingComplete.emit();
|
|
215
|
-
}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
The `loadUserState()` method then applies the saved state to the component and its sub-components:
|
|
219
|
-
|
|
220
|
-
```typescript
|
|
221
|
-
// Example from AIDashboardComponent
|
|
222
|
-
public loadUserState(state: Partial<AIDashboardState>): void {
|
|
223
|
-
if (state.activeTab) {
|
|
224
|
-
this.activeTab = state.activeTab;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Store sub-component states for when they're rendered
|
|
228
|
-
if (state.executionMonitoringState) {
|
|
229
|
-
this.executionMonitoringState = state.executionMonitoringState;
|
|
230
|
-
}
|
|
231
|
-
// ... other state properties
|
|
232
|
-
}
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
#### AI Dashboard State
|
|
236
|
-
```typescript
|
|
237
|
-
interface AIDashboardState {
|
|
238
|
-
activeTab: string;
|
|
239
|
-
modelManagementState: any;
|
|
240
|
-
promptManagementState: any;
|
|
241
|
-
agentConfigurationState: any;
|
|
242
|
-
executionMonitoringState: ExecutionMonitoringState;
|
|
243
|
-
systemConfigurationState: any;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// ExecutionMonitoringState includes detailed UI state
|
|
247
|
-
interface ExecutionMonitoringState {
|
|
248
|
-
selectedTimeRange: string;
|
|
249
|
-
refreshInterval: number;
|
|
250
|
-
panelStates: {
|
|
251
|
-
cost: boolean;
|
|
252
|
-
efficiency: boolean;
|
|
253
|
-
executions: boolean;
|
|
254
|
-
};
|
|
255
|
-
drillDownTabs: Array<{
|
|
256
|
-
id: string;
|
|
257
|
-
title: string;
|
|
258
|
-
type: string;
|
|
259
|
-
timestamp?: string;
|
|
260
|
-
metric?: string;
|
|
261
|
-
}>;
|
|
262
|
-
activeTabId: string;
|
|
263
|
-
splitterSizes?: number[];
|
|
264
|
-
}
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
#### Entity Admin Dashboard State
|
|
268
|
-
```typescript
|
|
269
|
-
interface DashboardState {
|
|
270
|
-
filterPanelVisible: boolean;
|
|
271
|
-
filterPanelWidth: number;
|
|
272
|
-
filters: any;
|
|
273
|
-
selectedEntityId: string | null;
|
|
274
|
-
zoomLevel: number;
|
|
275
|
-
panPosition: { x: number; y: number };
|
|
276
|
-
fieldsSectionExpanded: boolean;
|
|
277
|
-
relationshipsSectionExpanded: boolean;
|
|
278
|
-
}
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
#### Example: Complete State Management Implementation
|
|
282
|
-
|
|
283
|
-
```typescript
|
|
284
|
-
// Parent component that uses the AI Dashboard
|
|
285
|
-
@Component({
|
|
286
|
-
template: `
|
|
287
|
-
<mj-ai-dashboard
|
|
288
|
-
[Config]="dashboardConfig"
|
|
289
|
-
(UserStateChanged)="onStateChanged($event)">
|
|
290
|
-
</mj-ai-dashboard>
|
|
291
|
-
`
|
|
115
|
+
imports: [DashboardsModule]
|
|
292
116
|
})
|
|
293
|
-
export class
|
|
294
|
-
dashboardConfig: DashboardConfig;
|
|
295
|
-
|
|
296
|
-
ngOnInit() {
|
|
297
|
-
// Load saved state from your persistence layer
|
|
298
|
-
const savedState = this.loadSavedState();
|
|
299
|
-
|
|
300
|
-
// Configure dashboard with saved state
|
|
301
|
-
this.dashboardConfig = {
|
|
302
|
-
dashboard: this.dashboardEntity,
|
|
303
|
-
userState: savedState // This will be applied in loadData()
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
onStateChanged(state: AIDashboardState) {
|
|
308
|
-
// Save state changes with debouncing handled by the dashboard
|
|
309
|
-
this.saveState(state);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
private loadSavedState(): AIDashboardState | null {
|
|
313
|
-
// Load from localStorage, database, or other persistence
|
|
314
|
-
const saved = localStorage.getItem('ai-dashboard-state');
|
|
315
|
-
return saved ? JSON.parse(saved) : null;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
private saveState(state: AIDashboardState): void {
|
|
319
|
-
// Save to your persistence layer
|
|
320
|
-
localStorage.setItem('ai-dashboard-state', JSON.stringify(state));
|
|
321
|
-
}
|
|
322
|
-
}
|
|
117
|
+
export class AppModule {}
|
|
323
118
|
```
|
|
324
119
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
The dashboards are designed to work seamlessly with other MemberJunction packages:
|
|
328
|
-
|
|
329
|
-
1. **Entity System**: Uses `@memberjunction/core-entities` for entity definitions
|
|
330
|
-
2. **Metadata System**: Leverages MemberJunction metadata for dynamic UI generation
|
|
331
|
-
3. **Template System**: Integrates with `@memberjunction/templates-base-types`
|
|
332
|
-
4. **Global Registry**: Uses `@RegisterClass` decorator for component registration
|
|
120
|
+
All dashboard components are registered via `@RegisterClass(BaseResourceComponent, 'ClassName')` and are loaded dynamically based on application navigation configuration. They do not need to be referenced directly in templates.
|
|
333
121
|
|
|
334
|
-
## Build
|
|
335
|
-
|
|
336
|
-
### Building the Package
|
|
122
|
+
## Build
|
|
337
123
|
|
|
338
124
|
```bash
|
|
339
|
-
|
|
340
|
-
npm run build
|
|
341
|
-
|
|
342
|
-
# From the repository root
|
|
343
|
-
turbo build --filter="@memberjunction/ng-dashboards"
|
|
125
|
+
cd packages/Angular/Explorer/dashboards && npm run build
|
|
344
126
|
```
|
|
345
127
|
|
|
346
|
-
### Development Mode
|
|
347
|
-
|
|
348
|
-
The package includes TypeScript configuration for Angular compilation:
|
|
349
|
-
- Uses Angular compiler (`ngc`) for building
|
|
350
|
-
- Outputs to `./dist` directory
|
|
351
|
-
- Generates type definitions
|
|
352
|
-
|
|
353
|
-
## Special Considerations
|
|
354
|
-
|
|
355
|
-
1. **Tree Shaking**: The package includes special tree-shaking prevention calls in `public-api.ts` to ensure all dashboard components are included in builds
|
|
356
|
-
|
|
357
|
-
2. **Icon Libraries**: Uses Font Awesome icons throughout the UI. Ensure Font Awesome is properly configured in your application
|
|
358
|
-
|
|
359
|
-
3. **State Persistence**: Dashboard state changes are emitted via `UserStateChanged` events - implement persistence in the parent component
|
|
360
|
-
|
|
361
|
-
4. **Navigation**: AI and Actions dashboards use bottom navigation patterns with icon-based navigation
|
|
362
|
-
|
|
363
|
-
5. **Responsive Design**: Dashboards are designed to work across different screen sizes with collapsible panels and responsive layouts
|
|
364
|
-
|
|
365
128
|
## License
|
|
366
129
|
|
|
367
|
-
ISC
|
|
130
|
+
ISC
|
|
@@ -1133,5 +1133,5 @@ export { AgentConfigurationComponent };
|
|
|
1133
1133
|
type: Component,
|
|
1134
1134
|
args: [{ standalone: false, selector: 'app-agent-configuration', template: "<div class=\"agent-configuration-container\">\n <!-- Header -->\n <div class=\"dashboard-header\">\n <div class=\"header-info\">\n <h2 class=\"dashboard-title\">\n <i class=\"fa-solid fa-robot\"></i>\n Agent Configuration\n </h2>\n <button \n type=\"button\" \n class=\"filter-toggle-btn\"\n (click)=\"toggleFilterPanel()\"\n title=\"Toggle Filters\">\n <i class=\"fa-solid fa-filter\"></i>\n @if (filterPanelVisible) {\n Hide Filters\n } @else {\n Show Filters\n }\n </button>\n <span class=\"item-count\">{{ filteredAgents.length }} agents</span>\n </div>\n \n <div class=\"header-controls\">\n <div class=\"view-toggle\">\n <button \n type=\"button\" \n class=\"view-btn\"\n [class.active]=\"viewMode === 'grid'\"\n (click)=\"setViewMode('grid')\"\n title=\"Grid View\">\n <i class=\"fa-solid fa-grip\"></i>\n </button>\n <button \n type=\"button\" \n class=\"view-btn\"\n [class.active]=\"viewMode === 'list'\"\n (click)=\"setViewMode('list')\"\n title=\"List View\">\n <i class=\"fa-solid fa-list\"></i>\n </button>\n </div>\n \n <button \n type=\"button\" \n class=\"control-btn primary\"\n (click)=\"createNewAgent()\"\n title=\"Create New Agent\">\n <i class=\"fa-solid fa-plus\"></i>\n New Agent\n </button>\n </div>\n </div>\n\n <!-- Main Content with Splitter -->\n <div class=\"main-content\" >\n <kendo-splitter \n class=\"main-splitter\"\n orientation=\"horizontal\"\n (layoutChange)=\"onMainSplitterChange($event)\"\n >\n \n <!-- Filter Panel (Left) -->\n <kendo-splitter-pane \n [size]=\"filterPanelVisible ? '320px' : '0px'\"\n [collapsible]=\"false\"\n [resizable]=\"filterPanelVisible\"\n [scrollable]=\"false\"\n [hidden]=\"!filterPanelVisible\">\n <mj-agent-filter-panel\n [agents]=\"agents\"\n [filteredAgents]=\"filteredAgents\"\n [filters]=\"currentFilters\"\n (filtersChange)=\"onFiltersChange($event)\"\n (filterChange)=\"onFilterChange()\"\n (resetFilters)=\"onResetFilters()\"\n (closePanel)=\"toggleFilterPanel()\">\n </mj-agent-filter-panel>\n </kendo-splitter-pane>\n \n <!-- Agents List Panel -->\n <kendo-splitter-pane\n [resizable]=\"true\"\n [scrollable]=\"true\">\n <div class=\"agents-content\">\n <!-- Loading State -->\n @if (isLoading) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading agents...\" size=\"large\"></mj-loading>\n </div>\n }\n\n <!-- Agents Display -->\n @if (!isLoading) {\n @if (filteredAgents.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-robot\"></i>\n <h3>No agents found</h3>\n <p>No agents match your current filters. Try adjusting your search criteria or create a new agent.</p>\n <button \n type=\"button\" \n class=\"empty-state-btn\"\n (click)=\"createNewAgent()\">\n <i class=\"fa-solid fa-plus\"></i>\n Create New Agent\n </button>\n </div>\n } @else {\n <!-- Grid View -->\n @if (viewMode === 'grid') {\n <div class=\"agents-grid\">\n @for (agent of filteredAgents; track agent.ID) {\n <div class=\"agent-card\" [class.expanded]=\"expandedAgentId === agent.ID\">\n <!-- Card Header -->\n <div class=\"card-header\" (click)=\"toggleAgentExpansion(agent.ID)\">\n <div class=\"agent-info\">\n <div class=\"agent-icon\" [style.background-color]=\"getAgentIconColor(agent)\">\n @if (hasLogoURL(agent)) {\n <img [src]=\"agent.LogoURL\" [alt]=\"agent.Name + ' logo'\" class=\"agent-logo\">\n } @else {\n <i [class]=\"getAgentIcon(agent)\"></i>\n }\n </div>\n <div class=\"agent-details\">\n <h4 class=\"agent-name\" [innerHTML]=\"agent.Name | highlightSearch:currentFilters.searchTerm\"></h4>\n <div class=\"agent-meta\">\n <span class=\"meta-item type-badge\">\n <i class=\"fa-solid fa-tag\"></i>\n {{ getAgentTypeName(agent) }}\n </span>\n @if (agent.Status) {\n <span class=\"meta-item\" [class]=\"'status-' + agent.Status.toLowerCase()\">\n <i class=\"fa-solid fa-circle\" style=\"font-size: 8px;\"></i>\n {{ agent.Status }}\n </span>\n }\n </div>\n </div>\n </div>\n \n <i class=\"fa-solid fa-chevron-down expand-icon\" \n [class.rotated]=\"expandedAgentId === agent.ID\"></i>\n </div>\n\n <!-- Card Body -->\n <div class=\"card-body\">\n @if (agent.Description) {\n <p class=\"agent-description\" [innerHTML]=\"agent.Description | highlightSearch:currentFilters.searchTerm\"></p>\n } @else {\n <p class=\"agent-description text-muted\">No description provided</p>\n }\n \n <!-- Expandable Content -->\n @if (expandedAgentId === agent.ID) {\n <div class=\"expanded-content\">\n <div class=\"agent-stats\">\n @if (agent.Parent) {\n <div class=\"stat-item\">\n <span class=\"stat-label\">Parent</span>\n <span class=\"stat-value\">{{ agent.Parent }}</span>\n </div>\n }\n <div class=\"stat-item\">\n <span class=\"stat-label\">Context Compression</span>\n <span class=\"stat-value\">\n @if (agent.EnableContextCompression) {\n <i class=\"fa-solid fa-check\" style=\"color: #28a745;\"></i> Enabled\n } @else {\n <i class=\"fa-solid fa-times\" style=\"color: #dc3545;\"></i> Disabled\n }\n </span>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Card Actions -->\n <div class=\"card-actions\">\n @if (UserCanReadAgents) {\n <button\n type=\"button\"\n class=\"action-btn\"\n (click)=\"showAgentDetails(agent, $event)\"\n title=\"View Details\">\n <i class=\"fa-solid fa-eye\"></i>\n Details\n </button>\n }\n\n @if (agent.Status === 'Active' && UserCanReadAgents) {\n <button\n type=\"button\"\n class=\"action-btn action-btn-primary\"\n (click)=\"runAgent(agent); $event.stopPropagation()\"\n title=\"Run Agent\">\n <i class=\"fa-solid fa-play\"></i>\n Run\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n \n <!-- List View -->\n @if (viewMode === 'list') {\n <div class=\"agents-list\">\n <table class=\"agents-table\">\n <thead>\n <tr>\n <th (click)=\"sortBy('Name')\"\n [class.sorted]=\"sortColumn === 'Name'\"\n [class.desc]=\"sortColumn === 'Name' && sortDirection === 'desc'\">\n <span class=\"sort-header\">\n Name\n <i class=\"fa-solid fa-chevron-up sort-icon\"></i>\n </span>\n </th>\n <th>Type</th>\n <th (click)=\"sortBy('Status')\"\n [class.sorted]=\"sortColumn === 'Status'\"\n [class.desc]=\"sortColumn === 'Status' && sortDirection === 'desc'\">\n <span class=\"sort-header\">\n Status\n <i class=\"fa-solid fa-chevron-up sort-icon\"></i>\n </span>\n </th>\n <th>Actions</th>\n </tr>\n </thead>\n <tbody>\n @for (agent of filteredAgents; track agent.ID) {\n <tr>\n <td>\n <div class=\"agent-name-cell\">\n <div class=\"agent-icon-small\" [style.background-color]=\"getAgentIconColor(agent)\">\n @if (hasLogoURL(agent)) {\n <img [src]=\"agent.LogoURL\" [alt]=\"agent.Name + ' logo'\" class=\"agent-logo-small\">\n } @else {\n <i [class]=\"getAgentIcon(agent)\"></i>\n }\n </div>\n <div>\n <div class=\"agent-name\" [innerHTML]=\"agent.Name | highlightSearch:currentFilters.searchTerm\"></div>\n @if (agent.Description) {\n <div class=\"agent-description-small\" [innerHTML]=\"agent.Description | highlightSearch:currentFilters.searchTerm\"></div>\n }\n </div>\n </div>\n </td>\n <td>\n <span class=\"type-badge\">\n {{ getAgentTypeName(agent) }}\n </span>\n </td>\n <td>\n <span class=\"status-badge\" [class]=\"'status-' + (agent.Status || 'unknown').toLowerCase()\">\n {{ agent.Status || 'Unknown' }}\n </span>\n </td>\n <td>\n <div class=\"table-actions\">\n @if (UserCanReadAgents) {\n <button\n type=\"button\"\n class=\"action-btn-small\"\n (click)=\"showAgentDetails(agent)\"\n title=\"View Details\">\n <i class=\"fa-solid fa-eye\"></i>\n </button>\n }\n @if (agent.Status === 'Active' && UserCanReadAgents) {\n <button\n type=\"button\"\n class=\"action-btn-small primary\"\n (click)=\"runAgent(agent)\"\n title=\"Run Agent\">\n <i class=\"fa-solid fa-play\"></i>\n </button>\n }\n </div>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n }\n }\n </div>\n </kendo-splitter-pane>\n </kendo-splitter>\n </div>\n\n <!-- Detail Panel Overlay -->\n @if (detailPanelVisible) {\n <div class=\"detail-panel-overlay\" (click)=\"closeDetailPanel()\"></div>\n }\n\n <!-- Detail Panel -->\n <div class=\"detail-panel\" [class.visible]=\"detailPanelVisible\">\n @if (selectedAgent) {\n <!-- Panel Header -->\n <div class=\"detail-panel-header\">\n <div class=\"detail-panel-title\">\n <div class=\"detail-icon\" [style.background-color]=\"getAgentIconColor(selectedAgent)\">\n @if (hasLogoURL(selectedAgent)) {\n <img [src]=\"selectedAgent.LogoURL\" [alt]=\"selectedAgent.Name + ' logo'\" class=\"detail-logo\">\n } @else {\n <i [class]=\"getAgentIcon(selectedAgent)\"></i>\n }\n </div>\n <div class=\"detail-title-info\">\n <h3>{{ selectedAgent.Name }}</h3>\n <span class=\"detail-subtitle\">{{ getAgentTypeName(selectedAgent) }}</span>\n </div>\n </div>\n <button class=\"detail-panel-close\" (click)=\"closeDetailPanel()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Panel Content -->\n <div class=\"detail-panel-content\">\n <!-- Status and Type Section -->\n <div class=\"detail-section\">\n <div class=\"detail-badges\">\n <span class=\"status-badge\" [class]=\"'status-' + (selectedAgent.Status || 'unknown').toLowerCase()\">\n <i class=\"fa-solid fa-circle\" style=\"font-size: 8px;\"></i>\n {{ selectedAgent.Status || 'Unknown' }}\n </span>\n @if (selectedAgent.ExposeAsAction) {\n <span class=\"feature-badge\">\n <i class=\"fa-solid fa-bolt\"></i>\n Exposed as Action\n </span>\n }\n </div>\n </div>\n\n <!-- Description -->\n @if (selectedAgent.Description) {\n <div class=\"detail-section\">\n <h4 class=\"detail-section-title\">\n <i class=\"fa-solid fa-align-left\"></i>\n Description\n </h4>\n <p class=\"detail-description\">{{ selectedAgent.Description }}</p>\n </div>\n }\n\n <!-- Configuration Details -->\n <div class=\"detail-section\">\n <h4 class=\"detail-section-title\">\n <i class=\"fa-solid fa-cog\"></i>\n Configuration\n </h4>\n <div class=\"detail-grid\">\n <div class=\"detail-item\">\n <span class=\"detail-label\">Execution Mode</span>\n <span class=\"detail-value\">\n <i [class]=\"getExecutionModeIcon(selectedAgent.ExecutionMode)\"></i>\n {{ selectedAgent.ExecutionMode }}\n </span>\n </div>\n @if (getParentAgentName(selectedAgent)) {\n <div class=\"detail-item\">\n <span class=\"detail-label\">Parent Agent</span>\n <span class=\"detail-value\">{{ getParentAgentName(selectedAgent) }}</span>\n </div>\n }\n <div class=\"detail-item\">\n <span class=\"detail-label\">Context Compression</span>\n <span class=\"detail-value\">\n @if (selectedAgent.EnableContextCompression) {\n <i class=\"fa-solid fa-check\" style=\"color: #10b981;\"></i> Enabled\n } @else {\n <i class=\"fa-solid fa-times\" style=\"color: #ef4444;\"></i> Disabled\n }\n </span>\n </div>\n <div class=\"detail-item\">\n <span class=\"detail-label\">Exposed as Action</span>\n <span class=\"detail-value\">\n @if (selectedAgent.ExposeAsAction) {\n <i class=\"fa-solid fa-check\" style=\"color: #10b981;\"></i> Yes\n } @else {\n <i class=\"fa-solid fa-times\" style=\"color: #ef4444;\"></i> No\n }\n </span>\n </div>\n <div class=\"detail-item\">\n <span class=\"detail-label\">Model Selection</span>\n <span class=\"detail-value\">{{ selectedAgent.ModelSelectionMode }}</span>\n </div>\n </div>\n </div>\n\n <!-- Timestamps -->\n <div class=\"detail-section\">\n <h4 class=\"detail-section-title\">\n <i class=\"fa-solid fa-clock\"></i>\n Timestamps\n </h4>\n <div class=\"detail-grid\">\n <div class=\"detail-item\">\n <span class=\"detail-label\">Created</span>\n <span class=\"detail-value\">{{ selectedAgent.__mj_CreatedAt | date:'medium' }}</span>\n </div>\n <div class=\"detail-item\">\n <span class=\"detail-label\">Updated</span>\n <span class=\"detail-value\">{{ selectedAgent.__mj_UpdatedAt | date:'medium' }}</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Panel Actions -->\n <div class=\"detail-panel-actions\">\n @if (selectedAgent.Status === 'Active') {\n <button\n type=\"button\"\n class=\"detail-action-btn secondary\"\n (click)=\"runAgent(selectedAgent)\">\n <i class=\"fa-solid fa-play\"></i>\n Run Agent\n </button>\n }\n <button\n type=\"button\"\n class=\"detail-action-btn primary\"\n (click)=\"openAgentFromPanel()\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n Open Full Record\n </button>\n </div>\n }\n </div>\n</div>\n\n<!-- AI Agent Test Harness - Now handled by service with minimize support -->", styles: ["/* ============================================\n AI Agents Dashboard - World-Class Design\n Clean white header with indigo/purple accents\n ============================================ */\n\n/* Container */\n.agent-configuration-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: linear-gradient(135deg, #f5f7fa 0%, #e4e8ed 100%);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n}\n\n/* Dashboard Header - Clean White Style */\n.dashboard-header {\n background: white;\n padding: 16px 24px;\n border-bottom: 1px solid #e0e6ed;\n display: flex;\n justify-content: space-between;\n align-items: center;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n position: relative;\n z-index: 10;\n}\n\n.header-info {\n display: flex;\n align-items: center;\n gap: 20px;\n}\n\n.dashboard-title {\n margin: 0;\n font-size: 20px;\n font-weight: 700;\n color: #1e293b;\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.dashboard-title i {\n color: #6366f1;\n font-size: 22px;\n}\n\n.filter-toggle-btn {\n background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);\n border: 1px solid #dee2e6;\n padding: 10px 18px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n color: #495057;\n cursor: pointer;\n transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.filter-toggle-btn:hover {\n background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);\n border-color: #ced4da;\n transform: translateY(-1px);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n\n.filter-toggle-btn i {\n color: #6366f1;\n font-size: 14px;\n}\n\n.item-count {\n color: #6c757d;\n font-size: 14px;\n font-weight: 500;\n padding: 6px 12px;\n background: #f8f9fa;\n border-radius: 20px;\n border: 1px solid #e9ecef;\n}\n\n.header-controls {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n/* View Toggle */\n.view-toggle {\n display: flex;\n background: #f8f9fa;\n border-radius: 8px;\n padding: 3px;\n border: 1px solid #dee2e6;\n}\n\n.view-btn {\n background: transparent;\n border: none;\n padding: 8px 14px;\n border-radius: 6px;\n color: #6c757d;\n cursor: pointer;\n transition: all 0.2s ease;\n font-size: 15px;\n}\n\n.view-btn:hover {\n color: #495057;\n}\n\n.view-btn.active {\n background: white;\n color: #6366f1;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n}\n\n.control-btn {\n background: white;\n border: 1px solid #dee2e6;\n padding: 10px 18px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n color: #495057;\n cursor: pointer;\n transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.control-btn:hover {\n background: #f8f9fa;\n border-color: #ced4da;\n transform: translateY(-1px);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n}\n\n.control-btn i {\n font-size: 14px;\n}\n\n.control-btn.primary {\n background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);\n border-color: #4f46e5;\n color: white;\n}\n\n.control-btn.primary:hover {\n background: linear-gradient(135deg, #4f46e5 0%, #4338ca 100%);\n box-shadow: 0 4px 12px rgba(99, 102, 241, 0.35);\n}\n\n/* Main Content */\n.main-content {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.main-splitter {\n flex: 1;\n min-height: 0;\n}\n\n/* Splitter Styling */\nkendo-splitter {\n background: transparent;\n}\n\n:host ::ng-deep .k-splitter {\n border: none;\n background: transparent;\n}\n\n:host ::ng-deep .k-splitbar {\n background: #e5e7eb;\n width: 6px;\n}\n\n:host ::ng-deep .k-splitbar:hover {\n background: #c7d2fe;\n}\n\n:host ::ng-deep .k-pane {\n overflow: hidden;\n}\n\n/* Filter Panel Styles - used by child component */\n\n/* Agents Content */\n.agents-content {\n height: 100%;\n overflow-y: auto;\n padding: 28px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 50%, #e8f0fe 100%);\n}\n\n/* Grid View */\n.agents-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));\n gap: 24px;\n}\n\n.agent-card {\n background: white;\n border-radius: 16px;\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03);\n border: 1px solid #e2e8f0;\n transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n position: relative;\n}\n\n.agent-card::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 4px;\n background: linear-gradient(90deg, #6366f1 0%, #8b5cf6 50%, #a78bfa 100%);\n opacity: 0;\n transition: opacity 0.3s ease;\n}\n\n.agent-card:hover {\n box-shadow: 0 20px 40px -15px rgba(99, 102, 241, 0.25);\n transform: translateY(-4px);\n border-color: #c7d2fe;\n}\n\n.agent-card:hover::before {\n opacity: 1;\n}\n\n.agent-card.expanded {\n box-shadow: 0 25px 50px -12px rgba(99, 102, 241, 0.3);\n border-color: #a5b4fc;\n}\n\n.agent-card.expanded::before {\n opacity: 1;\n}\n\n.card-header {\n padding: 24px;\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n cursor: pointer;\n user-select: none;\n border-bottom: 1px solid #f1f5f9;\n transition: background-color 0.2s;\n}\n\n.card-header:hover {\n background-color: #fafbfc;\n}\n\n.agent-info {\n display: flex;\n gap: 18px;\n flex: 1;\n}\n\n.agent-icon {\n width: 56px;\n height: 56px;\n border-radius: 14px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);\n box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);\n}\n\n.agent-icon i {\n color: white;\n font-size: 24px;\n}\n\n.agent-icon .agent-logo {\n width: 100%;\n height: 100%;\n object-fit: cover;\n border-radius: 14px;\n}\n\n.agent-details {\n flex: 1;\n min-width: 0;\n}\n\n.agent-name {\n margin: 0;\n font-size: 18px;\n font-weight: 700;\n color: #1e293b;\n margin-bottom: 8px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.agent-meta {\n display: flex;\n gap: 14px;\n flex-wrap: wrap;\n}\n\n.meta-item {\n font-size: 13px;\n color: #64748b;\n display: flex;\n align-items: center;\n gap: 6px;\n background: #f1f5f9;\n padding: 4px 10px;\n border-radius: 6px;\n}\n\n.meta-item i {\n font-size: 11px;\n color: #6366f1;\n}\n\n.meta-item.status-active {\n color: #059669;\n background: #d1fae5;\n}\n\n.meta-item.status-active i {\n color: #059669;\n}\n\n.meta-item.status-pending {\n color: #d97706;\n background: #fef3c7;\n}\n\n.meta-item.status-pending i {\n color: #d97706;\n}\n\n.meta-item.status-disabled,\n.meta-item.status-inactive {\n color: #64748b;\n background: #e2e8f0;\n}\n\n.meta-item.status-disabled i,\n.meta-item.status-inactive i {\n color: #64748b;\n}\n\n/* Type Badge - for Agent Type display */\n.type-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border-radius: 6px;\n font-size: 12px;\n font-weight: 600;\n background: linear-gradient(135deg, #eef2ff 0%, #e0e7ff 100%);\n color: #4f46e5;\n border: 1px solid #c7d2fe;\n}\n\n.type-badge i {\n font-size: 11px;\n color: #6366f1;\n}\n\n/* Type badge in meta context (grid view) */\n.meta-item.type-badge {\n background: linear-gradient(135deg, #eef2ff 0%, #e0e7ff 100%);\n color: #4f46e5;\n border: 1px solid #c7d2fe;\n}\n\n.meta-item.type-badge i {\n color: #6366f1;\n}\n\n.expand-icon {\n font-size: 16px;\n color: #94a3b8;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 8px;\n border-radius: 8px;\n}\n\n.expand-icon:hover {\n color: #6366f1;\n background: #f1f5f9;\n}\n\n.expand-icon.rotated {\n transform: rotate(180deg);\n color: #6366f1;\n}\n\n.card-body {\n padding: 0 24px 24px 24px;\n}\n\n.agent-description {\n margin: 18px 0 0 0;\n font-size: 14px;\n line-height: 1.7;\n color: #64748b;\n}\n\n.agent-description.text-muted {\n font-style: italic;\n color: #94a3b8;\n}\n\n/* Expanded Content */\n.expanded-content {\n margin-top: 20px;\n padding-top: 20px;\n border-top: 1px solid #e2e8f0;\n animation: slideDown 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-12px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.agent-stats {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n gap: 18px;\n}\n\n.stat-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 16px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border-radius: 12px;\n border: 1px solid #e2e8f0;\n}\n\n.stat-label {\n font-size: 11px;\n font-weight: 700;\n color: #64748b;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.stat-value {\n font-size: 15px;\n color: #1e293b;\n font-weight: 600;\n}\n\n/* Card Actions */\n.card-actions {\n padding: 18px 24px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border-top: 1px solid #e2e8f0;\n display: flex;\n gap: 12px;\n justify-content: flex-end;\n}\n\n.action-btn {\n background: white;\n border: 2px solid #e2e8f0;\n padding: 10px 20px;\n border-radius: 10px;\n font-size: 13px;\n font-weight: 600;\n color: #475569;\n cursor: pointer;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.action-btn:hover {\n background: #f8fafc;\n border-color: #6366f1;\n color: #6366f1;\n transform: translateY(-1px);\n}\n\n.action-btn-primary {\n background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);\n border-color: transparent;\n color: white;\n box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);\n}\n\n.action-btn-primary:hover {\n background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);\n transform: translateY(-2px);\n box-shadow: 0 6px 16px rgba(99, 102, 241, 0.4);\n}\n\n/* List View */\n.agents-list {\n background: white;\n border-radius: 16px;\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);\n border: 1px solid #e2e8f0;\n overflow: hidden;\n}\n\n.agents-table {\n width: 100%;\n border-collapse: collapse;\n}\n\n.agents-table thead {\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border-bottom: 2px solid #e2e8f0;\n}\n\n.agents-table th {\n padding: 16px 20px;\n text-align: left;\n font-size: 12px;\n font-weight: 700;\n color: #475569;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n cursor: pointer;\n user-select: none;\n transition: all 0.2s ease;\n}\n\n.agents-table th:hover {\n background: #e2e8f0;\n color: #6366f1;\n}\n\n.agents-table th.sorted {\n color: #6366f1;\n background: linear-gradient(135deg, #eef2ff 0%, #e0e7ff 100%);\n}\n\n.sort-header {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.sort-icon {\n font-size: 10px;\n color: #94a3b8;\n transition: all 0.2s ease;\n}\n\n.agents-table th:hover .sort-icon {\n color: #6366f1;\n}\n\n.agents-table th.sorted .sort-icon {\n color: #6366f1;\n}\n\n.agents-table th.sorted.desc .sort-icon {\n transform: rotate(180deg);\n}\n\n.agents-table tbody tr {\n border-bottom: 1px solid #f1f5f9;\n transition: background-color 0.2s;\n}\n\n.agents-table tbody tr:last-child {\n border-bottom: none;\n}\n\n.agents-table tbody tr:hover {\n background: linear-gradient(135deg, #fafbfc 0%, #f8fafc 100%);\n}\n\n.agents-table td {\n padding: 18px 20px;\n font-size: 14px;\n color: #475569;\n}\n\n.agent-name-cell {\n display: flex;\n align-items: center;\n gap: 14px;\n}\n\n.agent-icon-small {\n width: 42px;\n height: 42px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);\n box-shadow: 0 2px 8px rgba(99, 102, 241, 0.25);\n}\n\n.agent-icon-small i {\n color: white;\n font-size: 18px;\n}\n\n.agent-icon-small .agent-logo-small {\n width: 100%;\n height: 100%;\n object-fit: cover;\n border-radius: 10px;\n}\n\n.agent-name-cell .agent-name {\n font-weight: 600;\n color: #1e293b;\n margin-bottom: 0;\n white-space: normal;\n}\n\n.agent-description-small {\n font-size: 13px;\n color: #64748b;\n margin-top: 4px;\n line-height: 1.4;\n}\n\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n border-radius: 20px;\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.status-badge i {\n font-size: 8px;\n}\n\n.status-badge.status-active {\n background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);\n color: #047857;\n}\n\n.status-badge.status-pending {\n background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);\n color: #b45309;\n}\n\n.status-badge.status-disabled,\n.status-badge.status-inactive {\n background: linear-gradient(135deg, #e2e8f0 0%, #cbd5e1 100%);\n color: #475569;\n}\n\n.status-badge.status-unknown {\n background: #f1f5f9;\n color: #64748b;\n}\n\n.execution-mode {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #475569;\n}\n\n.execution-mode i {\n color: #6366f1;\n}\n\n.table-actions {\n display: flex;\n gap: 10px;\n}\n\n.action-btn-small {\n background: white;\n border: 2px solid #e2e8f0;\n padding: 8px 12px;\n border-radius: 8px;\n font-size: 13px;\n color: #475569;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.action-btn-small:hover {\n background: #f8fafc;\n border-color: #6366f1;\n color: #6366f1;\n}\n\n.action-btn-small.primary {\n background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);\n border-color: transparent;\n color: white;\n box-shadow: 0 2px 8px rgba(99, 102, 241, 0.25);\n}\n\n.action-btn-small.primary:hover {\n background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);\n box-shadow: 0 4px 12px rgba(99, 102, 241, 0.35);\n}\n\n/* Empty State */\n.empty-state {\n text-align: center;\n padding: 100px 32px;\n color: #64748b;\n}\n\n.empty-state i {\n font-size: 80px;\n background: linear-gradient(135deg, #c7d2fe 0%, #ddd6fe 100%);\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n background-clip: text;\n margin-bottom: 28px;\n display: block;\n}\n\n.empty-state h3 {\n color: #1e293b;\n font-size: 24px;\n font-weight: 700;\n margin: 0 0 12px 0;\n}\n\n.empty-state p {\n font-size: 16px;\n line-height: 1.6;\n max-width: 420px;\n margin: 0 auto 32px;\n color: #64748b;\n}\n\n.empty-state-btn {\n background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);\n color: white;\n border: none;\n padding: 14px 28px;\n border-radius: 12px;\n font-size: 15px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: inline-flex;\n align-items: center;\n gap: 10px;\n box-shadow: 0 4px 15px rgba(99, 102, 241, 0.3);\n}\n\n.empty-state-btn:hover {\n transform: translateY(-2px);\n box-shadow: 0 8px 25px rgba(99, 102, 241, 0.4);\n}\n\n/* Loading State */\n.loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 400px;\n}\n\n/* Responsive Design */\n@media (max-width: 768px) {\n .dashboard-header {\n flex-direction: column;\n gap: 16px;\n align-items: stretch;\n padding: 16px 20px;\n }\n\n .header-info {\n flex-wrap: wrap;\n justify-content: center;\n }\n\n .header-controls {\n justify-content: center;\n }\n\n .agents-content {\n padding: 16px;\n }\n\n .agents-grid {\n grid-template-columns: 1fr;\n gap: 16px;\n }\n\n .agent-stats {\n grid-template-columns: 1fr;\n }\n\n .card-header {\n padding: 18px;\n }\n\n .card-body {\n padding: 0 18px 18px 18px;\n }\n\n .card-actions {\n padding: 14px 18px;\n flex-wrap: wrap;\n }\n}\n\n/* =============================================\n Detail Panel - Slide-in Overlay\n ============================================= */\n\n.detail-panel-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(15, 23, 42, 0.4);\n backdrop-filter: blur(4px);\n z-index: 1000;\n animation: fadeIn 0.25s ease-out;\n}\n\n@keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.detail-panel {\n position: fixed;\n top: 0;\n right: -480px;\n width: 480px;\n height: 100vh;\n background: white;\n box-shadow: -8px 0 32px rgba(0, 0, 0, 0.15);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n transition: right 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n}\n\n.detail-panel.visible {\n right: 0;\n}\n\n/* Detail Panel Header */\n.detail-panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 24px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border-bottom: 1px solid #e2e8f0;\n flex-shrink: 0;\n}\n\n.detail-panel-title {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.detail-icon {\n width: 56px;\n height: 56px;\n border-radius: 14px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);\n box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);\n}\n\n.detail-icon i {\n color: white;\n font-size: 24px;\n}\n\n.detail-icon .detail-logo {\n width: 100%;\n height: 100%;\n object-fit: cover;\n border-radius: 14px;\n}\n\n.detail-title-info h3 {\n margin: 0 0 4px 0;\n font-size: 20px;\n font-weight: 700;\n color: #1e293b;\n}\n\n.detail-subtitle {\n font-size: 13px;\n color: #64748b;\n font-weight: 500;\n}\n\n.detail-panel-close {\n background: white;\n border: 1px solid #e2e8f0;\n width: 40px;\n height: 40px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.2s ease;\n color: #64748b;\n}\n\n.detail-panel-close:hover {\n background: #f8fafc;\n border-color: #cbd5e1;\n color: #1e293b;\n}\n\n/* Detail Panel Content */\n.detail-panel-content {\n flex: 1;\n overflow-y: auto;\n padding: 24px;\n}\n\n.detail-section {\n margin-bottom: 28px;\n}\n\n.detail-section:last-child {\n margin-bottom: 0;\n}\n\n.detail-badges {\n display: flex;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.feature-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n border-radius: 20px;\n font-size: 12px;\n font-weight: 600;\n background: linear-gradient(135deg, #eef2ff 0%, #e0e7ff 100%);\n color: #4f46e5;\n}\n\n.feature-badge i {\n font-size: 11px;\n}\n\n.detail-section-title {\n margin: 0 0 16px 0;\n font-size: 12px;\n font-weight: 700;\n color: #64748b;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.detail-section-title i {\n color: #6366f1;\n font-size: 14px;\n}\n\n.detail-description {\n margin: 0;\n font-size: 14px;\n line-height: 1.7;\n color: #475569;\n}\n\n.detail-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 16px;\n}\n\n.detail-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 14px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border-radius: 12px;\n border: 1px solid #e2e8f0;\n}\n\n.detail-label {\n font-size: 11px;\n font-weight: 700;\n color: #64748b;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.detail-value {\n font-size: 14px;\n color: #1e293b;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.detail-value i {\n font-size: 13px;\n}\n\n.detail-code-block {\n background: #1e293b;\n color: #e2e8f0;\n padding: 16px;\n border-radius: 10px;\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n font-size: 13px;\n line-height: 1.6;\n overflow-x: auto;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n/* Detail Panel Actions */\n.detail-panel-actions {\n padding: 20px 24px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border-top: 1px solid #e2e8f0;\n display: flex;\n gap: 12px;\n flex-shrink: 0;\n}\n\n.detail-action-btn {\n flex: 1;\n padding: 14px 20px;\n border-radius: 12px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n}\n\n.detail-action-btn.secondary {\n background: white;\n border: 2px solid #e2e8f0;\n color: #475569;\n}\n\n.detail-action-btn.secondary:hover {\n border-color: #6366f1;\n color: #6366f1;\n background: #fafbff;\n}\n\n.detail-action-btn.primary {\n background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);\n border: 2px solid transparent;\n color: white;\n box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);\n}\n\n.detail-action-btn.primary:hover {\n background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);\n transform: translateY(-1px);\n box-shadow: 0 6px 16px rgba(99, 102, 241, 0.4);\n}\n\n/* Detail Panel Responsive */\n@media (max-width: 520px) {\n .detail-panel {\n width: 100%;\n right: -100%;\n }\n\n .detail-grid {\n grid-template-columns: 1fr;\n }\n}\n\n/* Search Highlight */\n:host ::ng-deep .search-highlight,\n.search-highlight {\n background-color: #fef08a;\n padding: 1px 2px;\n border-radius: 2px;\n font-weight: inherit;\n}\n"] }]
|
|
1135
1135
|
}], () => [{ type: i1.AITestHarnessDialogService }, { type: i2.CreateAgentService }, { type: i3.NavigationService }, { type: i0.ChangeDetectorRef }], null); })();
|
|
1136
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AgentConfigurationComponent, { className: "AgentConfigurationComponent", filePath: "src/
|
|
1136
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AgentConfigurationComponent, { className: "AgentConfigurationComponent", filePath: "src/AI/components/agents/agent-configuration.component.ts", lineNumber: 44 }); })();
|
|
1137
1137
|
//# sourceMappingURL=agent-configuration.component.js.map
|
|
@@ -796,5 +796,5 @@ export class AgentEditorComponent {
|
|
|
796
796
|
type: ViewChild,
|
|
797
797
|
args: ['hierarchyChart', { static: false }]
|
|
798
798
|
}] }); })();
|
|
799
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AgentEditorComponent, { className: "AgentEditorComponent", filePath: "src/
|
|
799
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AgentEditorComponent, { className: "AgentEditorComponent", filePath: "src/AI/components/agents/agent-editor.component.ts", lineNumber: 31 }); })();
|
|
800
800
|
//# sourceMappingURL=agent-editor.component.js.map
|
|
@@ -248,5 +248,5 @@ export class AgentFilterPanelComponent {
|
|
|
248
248
|
}], closePanel: [{
|
|
249
249
|
type: Output
|
|
250
250
|
}] }); })();
|
|
251
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AgentFilterPanelComponent, { className: "AgentFilterPanelComponent", filePath: "src/
|
|
251
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AgentFilterPanelComponent, { className: "AgentFilterPanelComponent", filePath: "src/AI/components/agents/agent-filter-panel.component.ts", lineNumber: 21 }); })();
|
|
252
252
|
//# sourceMappingURL=agent-filter-panel.component.js.map
|
|
@@ -422,5 +422,5 @@ export class PerformanceHeatmapComponent {
|
|
|
422
422
|
type: ViewChild,
|
|
423
423
|
args: ['legendGradient', { static: true }]
|
|
424
424
|
}] }); })();
|
|
425
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PerformanceHeatmapComponent, { className: "PerformanceHeatmapComponent", filePath: "src/
|
|
425
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PerformanceHeatmapComponent, { className: "PerformanceHeatmapComponent", filePath: "src/AI/components/charts/performance-heatmap.component.ts", lineNumber: 227 }); })();
|
|
426
426
|
//# sourceMappingURL=performance-heatmap.component.js.map
|
|
@@ -596,5 +596,5 @@ export class TimeSeriesChartComponent {
|
|
|
596
596
|
type: ViewChild,
|
|
597
597
|
args: ['tooltip', { static: true }]
|
|
598
598
|
}] }); })();
|
|
599
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TimeSeriesChartComponent, { className: "TimeSeriesChartComponent", filePath: "src/
|
|
599
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TimeSeriesChartComponent, { className: "TimeSeriesChartComponent", filePath: "src/AI/components/charts/time-series-chart.component.ts", lineNumber: 205 }); })();
|
|
600
600
|
//# sourceMappingURL=time-series-chart.component.js.map
|