@memberjunction/ng-dashboards 5.30.0 → 5.31.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.map +1 -1
- package/dist/AI/components/agents/agent-configuration.component.js +4 -4
- package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
- package/dist/AI/components/agents/agent-editor.component.d.ts +2 -1
- package/dist/AI/components/agents/agent-editor.component.d.ts.map +1 -1
- package/dist/AI/components/agents/agent-editor.component.js +8 -6
- package/dist/AI/components/agents/agent-editor.component.js.map +1 -1
- package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.d.ts +2 -1
- package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.d.ts.map +1 -1
- package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.js +6 -5
- package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.js.map +1 -1
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts +2 -1
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts.map +1 -1
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.js +6 -5
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.js.map +1 -1
- package/dist/AI/components/analytics/error-analysis/error-analysis.component.d.ts +2 -1
- package/dist/AI/components/analytics/error-analysis/error-analysis.component.d.ts.map +1 -1
- package/dist/AI/components/analytics/error-analysis/error-analysis.component.js +6 -5
- package/dist/AI/components/analytics/error-analysis/error-analysis.component.js.map +1 -1
- package/dist/AI/components/analytics/executive-summary/executive-summary.component.d.ts +2 -1
- package/dist/AI/components/analytics/executive-summary/executive-summary.component.d.ts.map +1 -1
- package/dist/AI/components/analytics/executive-summary/executive-summary.component.js +7 -4
- package/dist/AI/components/analytics/executive-summary/executive-summary.component.js.map +1 -1
- package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts +3 -2
- package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts.map +1 -1
- package/dist/AI/components/analytics/model-performance/model-performance.component.js +10 -6
- package/dist/AI/components/analytics/model-performance/model-performance.component.js.map +1 -1
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts +2 -1
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts.map +1 -1
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js +6 -5
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js.map +1 -1
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts +2 -1
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts.map +1 -1
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js +6 -5
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +55 -52
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +15 -15
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
- package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
- package/dist/AI/components/execution-monitoring.component.js +4 -3
- 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/models/model-management.component.js.map +1 -1
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts +2 -1
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts.map +1 -1
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js +10 -8
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-management.component.d.ts.map +1 -1
- package/dist/AI/components/prompts/prompt-management.component.js +2 -2
- package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-version-control.component.d.ts +2 -1
- package/dist/AI/components/prompts/prompt-version-control.component.d.ts.map +1 -1
- package/dist/AI/components/prompts/prompt-version-control.component.js +13 -10
- package/dist/AI/components/prompts/prompt-version-control.component.js.map +1 -1
- package/dist/AI/components/requests/agent-requests-resource.component.js +1 -1
- package/dist/AI/components/requests/agent-requests-resource.component.js.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.d.ts +1181 -0
- package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -0
- package/dist/AI/components/tags/tags-resource.component.js +7487 -0
- package/dist/AI/components/tags/tags-resource.component.js.map +1 -0
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js +25 -21
- package/dist/AI/components/vectors/vector-management-resource.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 +5 -0
- package/dist/AI/index.js.map +1 -1
- package/dist/AI/services/ai-instrumentation.service.d.ts +5 -0
- package/dist/AI/services/ai-instrumentation.service.d.ts.map +1 -1
- package/dist/AI/services/ai-instrumentation.service.js +12 -4
- package/dist/AI/services/ai-instrumentation.service.js.map +1 -1
- package/dist/APIKeys/api-applications-panel.component.d.ts +3 -2
- package/dist/APIKeys/api-applications-panel.component.d.ts.map +1 -1
- package/dist/APIKeys/api-applications-panel.component.js +5 -4
- package/dist/APIKeys/api-applications-panel.component.js.map +1 -1
- package/dist/APIKeys/api-key-create-dialog.component.d.ts +2 -1
- package/dist/APIKeys/api-key-create-dialog.component.d.ts.map +1 -1
- package/dist/APIKeys/api-key-create-dialog.component.js +5 -5
- package/dist/APIKeys/api-key-create-dialog.component.js.map +1 -1
- package/dist/APIKeys/api-key-edit-panel.component.d.ts +3 -2
- package/dist/APIKeys/api-key-edit-panel.component.d.ts.map +1 -1
- package/dist/APIKeys/api-key-edit-panel.component.js +11 -10
- package/dist/APIKeys/api-key-edit-panel.component.js.map +1 -1
- package/dist/APIKeys/api-key-list.component.d.ts +2 -1
- package/dist/APIKeys/api-key-list.component.d.ts.map +1 -1
- package/dist/APIKeys/api-key-list.component.js +6 -5
- package/dist/APIKeys/api-key-list.component.js.map +1 -1
- package/dist/APIKeys/api-keys-resource.component.d.ts.map +1 -1
- package/dist/APIKeys/api-keys-resource.component.js +4 -4
- package/dist/APIKeys/api-keys-resource.component.js.map +1 -1
- package/dist/APIKeys/api-scopes-panel.component.d.ts +3 -2
- package/dist/APIKeys/api-scopes-panel.component.d.ts.map +1 -1
- package/dist/APIKeys/api-scopes-panel.component.js +8 -6
- package/dist/APIKeys/api-scopes-panel.component.js.map +1 -1
- package/dist/APIKeys/api-usage-panel.component.d.ts +3 -2
- package/dist/APIKeys/api-usage-panel.component.d.ts.map +1 -1
- package/dist/APIKeys/api-usage-panel.component.js +10 -8
- package/dist/APIKeys/api-usage-panel.component.js.map +1 -1
- package/dist/Actions/components/actions-list-view.component.d.ts +2 -1
- package/dist/Actions/components/actions-list-view.component.d.ts.map +1 -1
- package/dist/Actions/components/actions-list-view.component.js +6 -5
- package/dist/Actions/components/actions-list-view.component.js.map +1 -1
- package/dist/Actions/components/actions-overview.component.js +2 -2
- package/dist/Actions/components/actions-overview.component.js.map +1 -1
- package/dist/Actions/components/categories-list-view.component.d.ts +2 -1
- package/dist/Actions/components/categories-list-view.component.d.ts.map +1 -1
- package/dist/Actions/components/categories-list-view.component.js +6 -5
- package/dist/Actions/components/categories-list-view.component.js.map +1 -1
- package/dist/Actions/components/execution-monitoring.component.js +1 -1
- package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
- package/dist/Actions/components/explorer/action-card.component.d.ts +2 -1
- package/dist/Actions/components/explorer/action-card.component.d.ts.map +1 -1
- package/dist/Actions/components/explorer/action-card.component.js +6 -4
- package/dist/Actions/components/explorer/action-card.component.js.map +1 -1
- package/dist/Actions/components/explorer/action-explorer.component.js +1 -1
- package/dist/Actions/components/explorer/action-explorer.component.js.map +1 -1
- package/dist/Actions/components/explorer/new-action-panel.component.d.ts +2 -1
- package/dist/Actions/components/explorer/new-action-panel.component.d.ts.map +1 -1
- package/dist/Actions/components/explorer/new-action-panel.component.js +7 -5
- package/dist/Actions/components/explorer/new-action-panel.component.js.map +1 -1
- package/dist/Actions/components/explorer/new-category-panel.component.d.ts +2 -1
- package/dist/Actions/components/explorer/new-category-panel.component.d.ts.map +1 -1
- package/dist/Actions/components/explorer/new-category-panel.component.js +7 -5
- package/dist/Actions/components/explorer/new-category-panel.component.js.map +1 -1
- package/dist/ApplicationRoles/application-roles-resource.component.js +4 -4
- package/dist/ApplicationRoles/application-roles-resource.component.js.map +1 -1
- package/dist/Communication/communication-logs-resource.component.js +1 -1
- package/dist/Communication/communication-logs-resource.component.js.map +1 -1
- package/dist/Communication/communication-monitor-resource.component.js +1 -1
- package/dist/Communication/communication-monitor-resource.component.js.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.js +1 -1
- package/dist/Communication/communication-runs-resource.component.js.map +1 -1
- package/dist/Communication/communication-templates-resource.component.js +3 -3
- package/dist/Communication/communication-templates-resource.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.js +5 -4
- package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts +2 -1
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +6 -4
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js.map +1 -1
- package/dist/ComponentStudio/components/artifact-load-dialog.component.d.ts +11 -2
- package/dist/ComponentStudio/components/artifact-load-dialog.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/artifact-load-dialog.component.js +61 -27
- package/dist/ComponentStudio/components/artifact-load-dialog.component.js.map +1 -1
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.d.ts +4 -2
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.js +19 -11
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.js.map +1 -1
- package/dist/ComponentStudio/components/editors/data-requirements-editor.component.d.ts +4 -2
- package/dist/ComponentStudio/components/editors/data-requirements-editor.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js +11 -3
- package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js.map +1 -1
- package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts +10 -1
- package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/workspace/component-preview.component.js +18 -9
- package/dist/ComponentStudio/components/workspace/component-preview.component.js.map +1 -1
- package/dist/ComponentStudio/services/component-studio-state.service.d.ts +11 -1
- package/dist/ComponentStudio/services/component-studio-state.service.d.ts.map +1 -1
- package/dist/ComponentStudio/services/component-studio-state.service.js +23 -3
- package/dist/ComponentStudio/services/component-studio-state.service.js.map +1 -1
- package/dist/ComponentStudio/services/component-version.service.d.ts +6 -1
- package/dist/ComponentStudio/services/component-version.service.d.ts.map +1 -1
- package/dist/ComponentStudio/services/component-version.service.js +16 -6
- package/dist/ComponentStudio/services/component-version.service.js.map +1 -1
- package/dist/Credentials/components/credentials-audit-resource.component.js +1 -1
- 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 +3 -3
- package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-list-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-list-resource.component.js +3 -3
- package/dist/Credentials/components/credentials-list-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-overview-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-overview-resource.component.js +3 -3
- package/dist/Credentials/components/credentials-overview-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-types-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-types-resource.component.js +3 -3
- package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
- package/dist/Credentials/credentials-dashboard.component.js +1 -1
- package/dist/Credentials/credentials-dashboard.component.js.map +1 -1
- package/dist/DashboardBrowser/dashboard-browser-resource.component.js +13 -13
- package/dist/DashboardBrowser/dashboard-browser-resource.component.js.map +1 -1
- package/dist/DashboardBrowser/dashboard-share-adapter.d.ts +4 -0
- package/dist/DashboardBrowser/dashboard-share-adapter.d.ts.map +1 -1
- package/dist/DashboardBrowser/dashboard-share-adapter.js +5 -2
- package/dist/DashboardBrowser/dashboard-share-adapter.js.map +1 -1
- package/dist/DashboardBrowser/dashboard-share-dialog.component.d.ts +3 -1
- package/dist/DashboardBrowser/dashboard-share-dialog.component.d.ts.map +1 -1
- package/dist/DashboardBrowser/dashboard-share-dialog.component.js +9 -4
- package/dist/DashboardBrowser/dashboard-share-dialog.component.js.map +1 -1
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.d.ts +3 -2
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.d.ts.map +1 -1
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js +7 -6
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js.map +1 -1
- package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts +3 -2
- package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts.map +1 -1
- package/dist/DataExplorer/components/view-selector/view-selector.component.js +6 -5
- package/dist/DataExplorer/components/view-selector/view-selector.component.js.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +10 -9
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/DataExplorer/services/explorer-state.service.d.ts +6 -1
- package/dist/DataExplorer/services/explorer-state.service.d.ts.map +1 -1
- package/dist/DataExplorer/services/explorer-state.service.js +15 -5
- package/dist/DataExplorer/services/explorer-state.service.js.map +1 -1
- package/dist/DatabaseDesigner/components/create-wizard/database-create-wizard.component.d.ts +64 -0
- package/dist/DatabaseDesigner/components/create-wizard/database-create-wizard.component.d.ts.map +1 -0
- package/dist/DatabaseDesigner/components/create-wizard/database-create-wizard.component.js +400 -0
- package/dist/DatabaseDesigner/components/create-wizard/database-create-wizard.component.js.map +1 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-basics.component.d.ts +42 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-basics.component.d.ts.map +1 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-basics.component.js +232 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-basics.component.js.map +1 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-fields.component.d.ts +14 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-fields.component.d.ts.map +1 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-fields.component.js +38 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-fields.component.js.map +1 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-pipeline.component.d.ts +24 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-pipeline.component.d.ts.map +1 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-pipeline.component.js +77 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-pipeline.component.js.map +1 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-relationships.component.d.ts +88 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-relationships.component.d.ts.map +1 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-relationships.component.js +404 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-relationships.component.js.map +1 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-review.component.d.ts +12 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-review.component.d.ts.map +1 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-review.component.js +116 -0
- package/dist/DatabaseDesigner/components/create-wizard/steps/step-review.component.js.map +1 -0
- package/dist/DatabaseDesigner/components/database-designer-dashboard.component.d.ts +55 -0
- package/dist/DatabaseDesigner/components/database-designer-dashboard.component.d.ts.map +1 -0
- package/dist/DatabaseDesigner/components/database-designer-dashboard.component.js +204 -0
- package/dist/DatabaseDesigner/components/database-designer-dashboard.component.js.map +1 -0
- package/dist/DatabaseDesigner/components/entity-list.component.d.ts +61 -0
- package/dist/DatabaseDesigner/components/entity-list.component.d.ts.map +1 -0
- package/dist/DatabaseDesigner/components/entity-list.component.js +485 -0
- package/dist/DatabaseDesigner/components/entity-list.component.js.map +1 -0
- package/dist/DatabaseDesigner/components/modify/database-modify.component.d.ts +52 -0
- package/dist/DatabaseDesigner/components/modify/database-modify.component.d.ts.map +1 -0
- package/dist/DatabaseDesigner/components/modify/database-modify.component.js +320 -0
- package/dist/DatabaseDesigner/components/modify/database-modify.component.js.map +1 -0
- package/dist/DatabaseDesigner/components/shared/database-preview-pane.component.d.ts +79 -0
- package/dist/DatabaseDesigner/components/shared/database-preview-pane.component.d.ts.map +1 -0
- package/dist/DatabaseDesigner/components/shared/database-preview-pane.component.js +378 -0
- package/dist/DatabaseDesigner/components/shared/database-preview-pane.component.js.map +1 -0
- package/dist/DatabaseDesigner/components/shared/entity-fields-grid.component.d.ts +85 -0
- package/dist/DatabaseDesigner/components/shared/entity-fields-grid.component.d.ts.map +1 -0
- package/dist/DatabaseDesigner/components/shared/entity-fields-grid.component.js +429 -0
- package/dist/DatabaseDesigner/components/shared/entity-fields-grid.component.js.map +1 -0
- package/dist/DatabaseDesigner/components/shared/entity-pipeline-panel.component.d.ts +58 -0
- package/dist/DatabaseDesigner/components/shared/entity-pipeline-panel.component.d.ts.map +1 -0
- package/dist/DatabaseDesigner/components/shared/entity-pipeline-panel.component.js +333 -0
- package/dist/DatabaseDesigner/components/shared/entity-pipeline-panel.component.js.map +1 -0
- package/dist/DatabaseDesigner/components/shared/entity-review-panel.component.d.ts +36 -0
- package/dist/DatabaseDesigner/components/shared/entity-review-panel.component.d.ts.map +1 -0
- package/dist/DatabaseDesigner/components/shared/entity-review-panel.component.js +345 -0
- package/dist/DatabaseDesigner/components/shared/entity-review-panel.component.js.map +1 -0
- package/dist/DatabaseDesigner/components/shared/wizard-step-indicator.component.d.ts +13 -0
- package/dist/DatabaseDesigner/components/shared/wizard-step-indicator.component.d.ts.map +1 -0
- package/dist/DatabaseDesigner/components/shared/wizard-step-indicator.component.js +81 -0
- package/dist/DatabaseDesigner/components/shared/wizard-step-indicator.component.js.map +1 -0
- package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts +30 -0
- package/dist/DatabaseDesigner/database-designer-dashboards.module.d.ts.map +1 -0
- package/dist/DatabaseDesigner/database-designer-dashboards.module.js +131 -0
- package/dist/DatabaseDesigner/database-designer-dashboards.module.js.map +1 -0
- package/dist/DatabaseDesigner/database-designer-erd.d.ts +19 -0
- package/dist/DatabaseDesigner/database-designer-erd.d.ts.map +1 -0
- package/dist/DatabaseDesigner/database-designer-erd.js +84 -0
- package/dist/DatabaseDesigner/database-designer-erd.js.map +1 -0
- package/dist/DatabaseDesigner/database-designer.types.d.ts +167 -0
- package/dist/DatabaseDesigner/database-designer.types.d.ts.map +1 -0
- package/dist/DatabaseDesigner/database-designer.types.js +26 -0
- package/dist/DatabaseDesigner/database-designer.types.js.map +1 -0
- package/dist/DatabaseDesigner/services/database-designer.engine.d.ts +94 -0
- package/dist/DatabaseDesigner/services/database-designer.engine.d.ts.map +1 -0
- package/dist/DatabaseDesigner/services/database-designer.engine.js +392 -0
- package/dist/DatabaseDesigner/services/database-designer.engine.js.map +1 -0
- package/dist/DatabaseDesigner/services/database-designer.service.d.ts +78 -0
- package/dist/DatabaseDesigner/services/database-designer.service.d.ts.map +1 -0
- package/dist/DatabaseDesigner/services/database-designer.service.js +273 -0
- package/dist/DatabaseDesigner/services/database-designer.service.js.map +1 -0
- package/dist/DatabaseDesigner/services/entity-wizard-state.service.d.ts +79 -0
- package/dist/DatabaseDesigner/services/entity-wizard-state.service.d.ts.map +1 -0
- package/dist/DatabaseDesigner/services/entity-wizard-state.service.js +204 -0
- package/dist/DatabaseDesigner/services/entity-wizard-state.service.js.map +1 -0
- package/dist/EntityAdmin/entity-admin-dashboard.component.d.ts.map +1 -1
- package/dist/EntityAdmin/entity-admin-dashboard.component.js +2 -2
- package/dist/EntityAdmin/entity-admin-dashboard.component.js.map +1 -1
- package/dist/Home/action-pin-config-dialog.component.d.ts +2 -1
- package/dist/Home/action-pin-config-dialog.component.d.ts.map +1 -1
- package/dist/Home/action-pin-config-dialog.component.js +6 -4
- package/dist/Home/action-pin-config-dialog.component.js.map +1 -1
- package/dist/Home/action-pin-runner-dialog.component.d.ts +2 -1
- package/dist/Home/action-pin-runner-dialog.component.d.ts.map +1 -1
- package/dist/Home/action-pin-runner-dialog.component.js +5 -4
- package/dist/Home/action-pin-runner-dialog.component.js.map +1 -1
- package/dist/Home/home-application.d.ts.map +1 -1
- package/dist/Home/home-application.js +10 -12
- package/dist/Home/home-application.js.map +1 -1
- package/dist/Home/home-dashboard.component.d.ts.map +1 -1
- package/dist/Home/home-dashboard.component.js +3 -3
- package/dist/Home/home-dashboard.component.js.map +1 -1
- package/dist/Integration/components/activity/activity.component.d.ts.map +1 -1
- package/dist/Integration/components/activity/activity.component.js +1 -0
- package/dist/Integration/components/activity/activity.component.js.map +1 -1
- package/dist/Integration/components/connections/connections.component.d.ts.map +1 -1
- package/dist/Integration/components/connections/connections.component.js +11 -10
- package/dist/Integration/components/connections/connections.component.js.map +1 -1
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.d.ts.map +1 -1
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +2 -2
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -1
- package/dist/Integration/components/overview/overview.component.d.ts.map +1 -1
- package/dist/Integration/components/overview/overview.component.js +1 -0
- package/dist/Integration/components/overview/overview.component.js.map +1 -1
- package/dist/Integration/components/pipelines/pipelines.component.d.ts.map +1 -1
- package/dist/Integration/components/pipelines/pipelines.component.js +1 -0
- package/dist/Integration/components/pipelines/pipelines.component.js.map +1 -1
- package/dist/Integration/components/schedules/schedules.component.d.ts.map +1 -1
- package/dist/Integration/components/schedules/schedules.component.js +5 -4
- package/dist/Integration/components/schedules/schedules.component.js.map +1 -1
- package/dist/Integration/services/integration-data.service.d.ts +5 -1
- package/dist/Integration/services/integration-data.service.d.ts.map +1 -1
- package/dist/Integration/services/integration-data.service.js +27 -19
- package/dist/Integration/services/integration-data.service.js.map +1 -1
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +6 -6
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +8 -6
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +6 -6
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js +3 -3
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.js +6 -6
- package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-categories-resource.component.js +4 -4
- package/dist/Lists/components/lists-categories-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-my-lists-resource.component.js +6 -6
- package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-operations-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-operations-resource.component.js +11 -10
- package/dist/Lists/components/lists-operations-resource.component.js.map +1 -1
- package/dist/Lists/services/list-set-operations.service.d.ts +5 -0
- package/dist/Lists/services/list-set-operations.service.d.ts.map +1 -1
- package/dist/Lists/services/list-set-operations.service.js +11 -3
- package/dist/Lists/services/list-set-operations.service.js.map +1 -1
- package/dist/MCP/components/mcp-connection-dialog.component.d.ts +2 -1
- package/dist/MCP/components/mcp-connection-dialog.component.d.ts.map +1 -1
- package/dist/MCP/components/mcp-connection-dialog.component.js +8 -6
- package/dist/MCP/components/mcp-connection-dialog.component.js.map +1 -1
- package/dist/MCP/components/mcp-server-dialog.component.d.ts +2 -1
- package/dist/MCP/components/mcp-server-dialog.component.d.ts.map +1 -1
- package/dist/MCP/components/mcp-server-dialog.component.js +7 -5
- package/dist/MCP/components/mcp-server-dialog.component.js.map +1 -1
- package/dist/MCP/mcp-dashboard.component.d.ts.map +1 -1
- package/dist/MCP/mcp-dashboard.component.js +12 -12
- package/dist/MCP/mcp-dashboard.component.js.map +1 -1
- package/dist/Permissions/permissions-shared.d.ts +3 -3
- package/dist/Permissions/permissions-shared.d.ts.map +1 -1
- package/dist/Permissions/permissions-shared.js +5 -5
- package/dist/Permissions/permissions-shared.js.map +1 -1
- package/dist/Permissions/resource-access-resource.component.js +1 -1
- package/dist/Permissions/resource-access-resource.component.js.map +1 -1
- package/dist/Permissions/user-access-resource.component.js +1 -2
- package/dist/Permissions/user-access-resource.component.js.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.js +2 -2
- package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
- package/dist/Scheduling/scheduling-dashboard.component.d.ts.map +1 -1
- package/dist/Scheduling/scheduling-dashboard.component.js +1 -0
- package/dist/Scheduling/scheduling-dashboard.component.js.map +1 -1
- package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts +5 -0
- package/dist/Scheduling/services/scheduling-instrumentation.service.d.ts.map +1 -1
- package/dist/Scheduling/services/scheduling-instrumentation.service.js +21 -13
- package/dist/Scheduling/services/scheduling-instrumentation.service.js.map +1 -1
- package/dist/SystemDiagnostics/system-diagnostics.component.d.ts.map +1 -1
- package/dist/SystemDiagnostics/system-diagnostics.component.js +2 -2
- package/dist/SystemDiagnostics/system-diagnostics.component.js.map +1 -1
- package/dist/Testing/components/testing-explorer.component.d.ts +2 -1
- package/dist/Testing/components/testing-explorer.component.d.ts.map +1 -1
- package/dist/Testing/components/testing-explorer.component.js +9 -7
- package/dist/Testing/components/testing-explorer.component.js.map +1 -1
- package/dist/Testing/services/testing-instrumentation.service.d.ts +6 -1
- package/dist/Testing/services/testing-instrumentation.service.d.ts.map +1 -1
- package/dist/Testing/services/testing-instrumentation.service.js +21 -11
- package/dist/Testing/services/testing-instrumentation.service.js.map +1 -1
- package/dist/Testing/testing-dashboard.component.d.ts +3 -1
- package/dist/Testing/testing-dashboard.component.d.ts.map +1 -1
- package/dist/Testing/testing-dashboard.component.js +15 -11
- package/dist/Testing/testing-dashboard.component.js.map +1 -1
- package/dist/VersionHistory/components/diff-resource.component.d.ts.map +1 -1
- package/dist/VersionHistory/components/diff-resource.component.js +5 -5
- package/dist/VersionHistory/components/diff-resource.component.js.map +1 -1
- package/dist/VersionHistory/components/graph-resource.component.d.ts.map +1 -1
- package/dist/VersionHistory/components/graph-resource.component.js +1 -2
- package/dist/VersionHistory/components/graph-resource.component.js.map +1 -1
- package/dist/VersionHistory/components/labels-resource.component.d.ts.map +1 -1
- 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 +1 -1
- package/dist/VersionHistory/components/restore-resource.component.js.map +1 -1
- package/dist/ai-dashboards.module.d.ts +35 -34
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +6 -0
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/module.d.ts +13 -12
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +7 -0
- package/dist/module.js.map +1 -1
- package/dist/public-api.d.ts +3 -1
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +3 -1
- package/dist/public-api.js.map +1 -1
- package/dist/shared/entity-field-display.d.ts +4 -3
- package/dist/shared/entity-field-display.d.ts.map +1 -1
- package/dist/shared/entity-field-display.js +9 -9
- package/dist/shared/entity-field-display.js.map +1 -1
- package/package.json +52 -51
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"communication-monitor-resource.component.js","sourceRoot":"","sources":["../../src/Communication/communication-monitor-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';\nimport { ResourceData, MJCommunicationLogEntity, MJCommunicationProviderEntity } from '@memberjunction/core-entities';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { RunView } from '@memberjunction/core';\n\ninterface ProviderHealth {\n Name: string;\n Type: string;\n SentCount: number;\n SuccessRate: number;\n IsActive: boolean;\n IconClass: string;\n ColorClass: string;\n}\n\ninterface ChannelBreakdown {\n Name: string;\n IconClass: string;\n Count: number;\n Percentage: number;\n ColorClass: string;\n}\n\ninterface HourlyBucket {\n timestamp: Date;\n executions: number;\n errors: number;\n cost: number;\n tokens: number;\n avgTime: number;\n}\n@RegisterClass(BaseResourceComponent, 'CommunicationMonitorResource')\n@Component({\n standalone: false,\n selector: 'mj-communication-monitor-resource',\n template: `\n <div class=\"monitor-wrapper\">\n <div class=\"monitor-container\">\n <!-- KPI STRIP -->\n <div class=\"kpi-strip\">\n <div class=\"kpi-card sent\">\n <div class=\"kpi-icon\"><i class=\"fa-solid fa-paper-plane\"></i></div>\n <div class=\"kpi-body\">\n <span class=\"kpi-label\">Total Sent</span>\n <span class=\"kpi-value\">{{stats.totalSent | number}}</span>\n <span class=\"kpi-delta\" [class]=\"stats.totalSent > 0 ? 'up' : 'neutral'\">\n <i class=\"fa-solid\" [class.fa-arrow-up]=\"stats.totalSent > 0\" [class.fa-minus]=\"stats.totalSent === 0\"></i>\n Last 24 hours\n </span>\n </div>\n </div>\n <div class=\"kpi-card delivered\">\n <div class=\"kpi-icon\"><i class=\"fa-solid fa-check-double\"></i></div>\n <div class=\"kpi-body\">\n <span class=\"kpi-label\">Delivery Rate</span>\n <span class=\"kpi-value\">{{stats.deliveryRate}}%</span>\n <div class=\"delivery-bar\">\n <div class=\"delivery-fill\" [style.width.%]=\"stats.deliveryRate\"></div>\n </div>\n </div>\n </div>\n <div class=\"kpi-card pending\">\n <div class=\"kpi-icon\"><i class=\"fa-solid fa-clock\"></i></div>\n <div class=\"kpi-body\">\n <span class=\"kpi-label\">Pending</span>\n <span class=\"kpi-value\">{{stats.pending | number}}</span>\n <span class=\"kpi-delta neutral\">\n <i class=\"fa-solid fa-minus\"></i> Awaiting provider\n </span>\n </div>\n </div>\n <div class=\"kpi-card failed\">\n <div class=\"kpi-icon\"><i class=\"fa-solid fa-circle-exclamation\"></i></div>\n <div class=\"kpi-body\">\n <span class=\"kpi-label\">Failed</span>\n <span class=\"kpi-value\">{{stats.failed | number}}</span>\n <span class=\"kpi-delta\" [class]=\"stats.failed > 0 ? 'down' : 'neutral'\">\n <i class=\"fa-solid\" [class.fa-arrow-up]=\"stats.failed > 0\" [class.fa-minus]=\"stats.failed === 0\"></i>\n {{stats.failed > 0 ? 'Requires attention' : 'No failures'}}\n </span>\n </div>\n </div>\n </div>\n \n <!-- CHARTS + ACTIVITY ROW -->\n <div class=\"content-grid\">\n <div class=\"card\">\n <div class=\"card-header\">\n <h3><i class=\"fa-solid fa-chart-bar\"></i> Delivery Volume</h3>\n </div>\n <div class=\"chart-container-inner\">\n <app-time-series-chart\n [data]=\"chartData\"\n [showLegend]=\"true\"\n [showControls]=\"false\"\n [config]=\"chartConfig\">\n </app-time-series-chart>\n </div>\n </div>\n \n <div class=\"card\">\n <div class=\"card-header\">\n <h3><i class=\"fa-solid fa-bolt\"></i> Recent Activity</h3>\n </div>\n <div class=\"card-body no-padding\">\n <div class=\"activity-feed\">\n @for (log of recentLogs; track log) {\n <div class=\"activity-item\">\n <div class=\"activity-icon\" [ngClass]=\"getActivityIconClass(log)\">\n <i [class]=\"getActivityIcon(log)\"></i>\n </div>\n <div class=\"activity-body\">\n <span class=\"activity-title\">{{log.CommunicationProviderMessageType || 'Message'}}</span>\n <span class=\"activity-meta\">{{log.CommunicationProvider}} • {{log.MessageDate | date:'shortTime'}}</span>\n </div>\n <span class=\"activity-status\" [ngClass]=\"log.Status.toLowerCase()\">\n {{log.Status}}\n </span>\n </div>\n }\n @if (recentLogs.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-inbox\"></i>\n <p>No recent activity</p>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n \n <!-- PROVIDER HEALTH + CHANNEL BREAKDOWN -->\n <div class=\"content-grid\">\n <div class=\"card\">\n <div class=\"card-header\">\n <h3><i class=\"fa-solid fa-heart-pulse\"></i> Provider Health</h3>\n </div>\n <div class=\"card-body no-padding\">\n <div class=\"provider-health-list\">\n @for (provider of providerHealth; track provider) {\n <div class=\"provider-row\">\n <div class=\"provider-status-dot\" [class.active]=\"provider.IsActive\"></div>\n <div class=\"provider-logo\" [ngClass]=\"provider.ColorClass\">\n <i [class]=\"provider.IconClass\"></i>\n </div>\n <div class=\"provider-info\">\n <div class=\"provider-name\">{{provider.Name}}</div>\n <div class=\"provider-type\">{{provider.Type}} • {{provider.SentCount}} sent today</div>\n </div>\n <div class=\"provider-health-bar\">\n <div class=\"provider-health-fill\" [ngClass]=\"getHealthClass(provider.SuccessRate)\" [style.width.%]=\"provider.SuccessRate\"></div>\n </div>\n <span class=\"provider-rate\" [ngClass]=\"getHealthClass(provider.SuccessRate)\">{{provider.SuccessRate}}%</span>\n </div>\n }\n @if (providerHealth.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-server\"></i>\n <p>No providers configured</p>\n </div>\n }\n </div>\n </div>\n </div>\n \n <div class=\"card\">\n <div class=\"card-header\">\n <h3><i class=\"fa-solid fa-layer-group\"></i> Channel Breakdown</h3>\n </div>\n <div class=\"card-body no-padding\">\n <div class=\"channel-breakdown\">\n @for (channel of channelBreakdown; track channel) {\n <div class=\"channel-row\">\n <div class=\"channel-icon\" [ngClass]=\"channel.ColorClass\">\n <i [class]=\"channel.IconClass\"></i>\n </div>\n <div class=\"channel-info\">\n <div class=\"channel-name\">{{channel.Name}}</div>\n <div class=\"channel-count\">{{channel.Count | number}} messages</div>\n </div>\n <div class=\"channel-bar-wrapper\">\n <div class=\"channel-bar-fill\" [style.width.%]=\"channel.Percentage\" [style.background]=\"channel.ColorClass === 'email' ? 'var(--mj-brand-primary)' : 'var(--mj-status-success)'\"></div>\n </div>\n <span class=\"channel-pct\">{{channel.Percentage}}%</span>\n </div>\n }\n @if (channelBreakdown.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-layer-group\"></i>\n <p>No channel data available</p>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n `,\n styles: [`\n .monitor-wrapper {\n height: 100%;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n }\n .monitor-container {\n padding: 24px;\n min-height: 100%;\n max-width: 1600px;\n margin: 0 auto;\n }\n\n /* KPI STRIP */\n .kpi-strip {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 16px;\n margin-bottom: 24px;\n }\n .kpi-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n display: flex;\n align-items: flex-start;\n gap: 16px;\n transition: all 0.15s ease;\n position: relative;\n overflow: hidden;\n }\n .kpi-card:hover {\n box-shadow: 0 2px 8px var(--mj-shadow-md);\n border-color: var(--mj-border-strong);\n }\n .kpi-card::before {\n content: '';\n position: absolute;\n top: 0; left: 0; right: 0;\n height: 3px;\n }\n .kpi-card.sent::before { background: var(--mj-brand-primary); }\n .kpi-card.delivered::before { background: var(--mj-status-success); }\n .kpi-card.pending::before { background: var(--mj-status-warning); }\n .kpi-card.failed::before { background: var(--mj-status-error); }\n\n .kpi-icon {\n width: 44px; height: 44px;\n border-radius: 12px;\n display: flex; align-items: center; justify-content: center;\n font-size: 16px; flex-shrink: 0;\n }\n .kpi-card.sent .kpi-icon {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n .kpi-card.delivered .kpi-icon {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n .kpi-card.pending .kpi-icon {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n }\n .kpi-card.failed .kpi-icon {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n\n .kpi-body { flex: 1; display: flex; flex-direction: column; gap: 2px; }\n .kpi-label {\n font-size: 11px; font-weight: 600;\n text-transform: uppercase; letter-spacing: 0.5px;\n color: var(--mj-text-muted);\n }\n .kpi-value {\n font-size: 28px; font-weight: 800;\n color: var(--mj-text-primary);\n letter-spacing: -0.02em; line-height: 1.1;\n }\n .kpi-delta {\n display: inline-flex; align-items: center;\n gap: 4px; font-size: 11px; font-weight: 600;\n margin-top: 4px; padding: 2px 8px;\n border-radius: 10px; width: fit-content;\n }\n .kpi-delta.up {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n .kpi-delta.down {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n .kpi-delta.neutral {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n }\n\n .delivery-bar {\n height: 6px; margin-top: 10px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px; overflow: hidden;\n }\n .delivery-fill {\n height: 100%; border-radius: 3px;\n background: var(--mj-status-success); transition: width 0.6s ease;\n }\n\n /* CONTENT GRID */\n .content-grid {\n display: grid;\n grid-template-columns: 1.6fr 1fr;\n gap: 16px;\n margin-bottom: 16px;\n }\n\n .card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n }\n .card-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n }\n .card-header h3 {\n font-size: 13px; font-weight: 700;\n color: var(--mj-text-primary);\n display: flex; align-items: center; gap: 8px;\n margin: 0;\n }\n .card-header h3 i {\n color: var(--mj-text-muted);\n font-size: 12px;\n }\n .card-body { padding: 16px 20px; }\n .card-body.no-padding { padding: 0; }\n\n .chart-container-inner {\n padding: 16px 20px;\n min-height: 300px;\n }\n\n /* ACTIVITY FEED */\n .activity-feed { max-height: 370px; overflow-y: auto; }\n .activity-item {\n display: flex; align-items: center; gap: 12px;\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n transition: background 0.15s ease; cursor: pointer;\n }\n .activity-item:last-child { border-bottom: none; }\n .activity-item:hover { background: var(--mj-bg-surface-sunken); }\n\n .activity-icon {\n width: 34px; height: 34px;\n border-radius: 8px;\n display: flex; align-items: center; justify-content: center;\n font-size: 12px; flex-shrink: 0;\n }\n .activity-icon.email {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n .activity-icon.sms {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n .activity-icon.error {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n\n .activity-body { flex: 1; min-width: 0; }\n .activity-title {\n font-size: 12px; font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n display: block;\n }\n .activity-meta {\n font-size: 11px; color: var(--mj-text-muted); margin-top: 1px;\n display: block;\n }\n .activity-status {\n font-size: 10px; font-weight: 700;\n text-transform: uppercase; letter-spacing: 0.3px;\n padding: 3px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n .activity-status.complete {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n .activity-status.failed {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n .activity-status.pending {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n }\n\n /* PROVIDER HEALTH */\n .provider-health-list { display: flex; flex-direction: column; }\n .provider-row {\n display: flex; align-items: center; gap: 12px;\n padding: 14px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n transition: background 0.15s ease;\n }\n .provider-row:last-child { border-bottom: none; }\n .provider-row:hover { background: var(--mj-bg-surface-sunken); }\n\n .provider-status-dot {\n width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;\n background: var(--mj-border-strong);\n }\n .provider-status-dot.active { background: var(--mj-status-success); }\n\n .provider-logo {\n width: 36px; height: 36px;\n border-radius: 8px;\n background: var(--mj-bg-surface-sunken);\n display: flex; align-items: center; justify-content: center;\n font-size: 16px; flex-shrink: 0;\n }\n .provider-logo.sendgrid { color: var(--mj-brand-primary); }\n .provider-logo.twilio { color: var(--mj-status-error); }\n .provider-logo.gmail { color: var(--mj-status-error); }\n .provider-logo.msgraph { color: var(--mj-brand-primary); }\n\n .provider-info { flex: 1; }\n .provider-name { font-size: 13px; font-weight: 600; color: var(--mj-text-primary); }\n .provider-type { font-size: 11px; color: var(--mj-text-muted); }\n\n .provider-health-bar {\n width: 80px; height: 6px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px; overflow: hidden;\n }\n .provider-health-fill {\n height: 100%; border-radius: 3px;\n transition: width 0.4s ease;\n }\n .provider-health-fill.excellent { background: var(--mj-status-success); }\n .provider-health-fill.good { background: var(--mj-status-success); }\n .provider-health-fill.warning { background: var(--mj-status-warning); }\n .provider-health-fill.critical { background: var(--mj-status-error); }\n\n .provider-rate {\n font-size: 12px; font-weight: 700;\n min-width: 44px; text-align: right;\n }\n .provider-rate.excellent { color: var(--mj-status-success); }\n .provider-rate.good { color: var(--mj-status-success); }\n .provider-rate.warning { color: var(--mj-status-warning); }\n .provider-rate.critical { color: var(--mj-status-error); }\n\n /* CHANNEL BREAKDOWN */\n .channel-breakdown { display: flex; flex-direction: column; }\n .channel-row {\n display: flex; align-items: center; gap: 12px;\n padding: 14px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n }\n .channel-row:last-child { border-bottom: none; }\n .channel-icon {\n width: 32px; height: 32px;\n border-radius: 8px;\n display: flex; align-items: center; justify-content: center;\n font-size: 13px; flex-shrink: 0;\n }\n .channel-icon.email {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n .channel-icon.sms {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n\n .channel-info { flex: 1; }\n .channel-name { font-size: 12px; font-weight: 600; color: var(--mj-text-primary); }\n .channel-count { font-size: 11px; color: var(--mj-text-muted); }\n\n .channel-bar-wrapper {\n width: 100px; height: 6px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px; overflow: hidden;\n }\n .channel-bar-fill { height: 100%; border-radius: 3px; }\n .channel-pct {\n font-size: 12px; font-weight: 700;\n color: var(--mj-text-primary);\n min-width: 36px; text-align: right;\n }\n\n /* EMPTY STATE */\n .empty-state {\n display: flex; flex-direction: column;\n align-items: center; justify-content: center;\n padding: 40px 0; color: var(--mj-text-muted);\n }\n .empty-state i { font-size: 2rem; margin-bottom: 12px; opacity: 0.5; }\n .empty-state p { margin: 0; font-size: 13px; }\n\n @media (max-width: 1200px) {\n .kpi-strip { grid-template-columns: repeat(2, 1fr); }\n .content-grid { grid-template-columns: 1fr; }\n }\n `]\n})\nexport class CommunicationMonitorResourceComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n public isLoading = false;\n public stats = {\n totalSent: 0,\n deliveryRate: 0,\n pending: 0,\n failed: 0\n };\n public recentLogs: MJCommunicationLogEntity[] = [];\n public chartData: HourlyBucket[] = [];\n public chartConfig = {\n useDualAxis: false,\n showGrid: true,\n showTooltip: true,\n colors: ['#4f6bed', '#cf222e']\n };\n public providerHealth: ProviderHealth[] = [];\n public channelBreakdown: ChannelBreakdown[] = [];\n\n constructor(private cdr: ChangeDetectorRef) {\n super();\n }\n\n async ngOnInit(): Promise<void> {\n super.ngOnInit();\n await this.loadData();\n this.NotifyLoadComplete();\n }\n\n ngOnDestroy(): void {\n super.ngOnDestroy();\n }\n\n public async loadData(): Promise<void> {\n try {\n this.isLoading = true;\n this.cdr.detectChanges();\n\n const rv = new RunView();\n const yesterday = new Date();\n yesterday.setDate(yesterday.getDate() - 1);\n const yesterdayIso = yesterday.toISOString();\n\n const [totalResult, failedResult, pendingResult, recentResult, allLogsResult, providersResult] = await Promise.all([\n rv.RunView({\n EntityName: 'MJ: Communication Logs',\n ExtraFilter: `MessageDate >= '${yesterdayIso}'`,\n ResultType: 'count_only'\n }),\n rv.RunView({\n EntityName: 'MJ: Communication Logs',\n ExtraFilter: `MessageDate >= '${yesterdayIso}' AND Status = 'Failed'`,\n ResultType: 'count_only'\n }),\n rv.RunView({\n EntityName: 'MJ: Communication Logs',\n ExtraFilter: `Status = 'Pending'`,\n ResultType: 'count_only'\n }),\n rv.RunView<MJCommunicationLogEntity>({\n EntityName: 'MJ: Communication Logs',\n OrderBy: 'MessageDate DESC',\n MaxRows: 8,\n ResultType: 'entity_object'\n }),\n rv.RunView<MJCommunicationLogEntity>({\n EntityName: 'MJ: Communication Logs',\n ExtraFilter: `MessageDate >= '${yesterdayIso}'`,\n OrderBy: 'MessageDate ASC',\n ResultType: 'entity_object'\n }),\n rv.RunView<MJCommunicationProviderEntity>({\n EntityName: 'MJ: Communication Providers',\n OrderBy: 'Name ASC',\n ResultType: 'entity_object'\n })\n ]);\n\n if (totalResult.Success) this.stats.totalSent = totalResult.TotalRowCount;\n if (failedResult.Success) this.stats.failed = failedResult.TotalRowCount;\n if (pendingResult.Success) this.stats.pending = pendingResult.TotalRowCount;\n\n this.stats.deliveryRate = this.stats.totalSent > 0\n ? parseFloat(((this.stats.totalSent - this.stats.failed) / this.stats.totalSent * 100).toFixed(1))\n : 100;\n\n if (recentResult.Success) {\n this.recentLogs = recentResult.Results;\n }\n\n if (allLogsResult.Success) {\n this.chartData = this.processTrendData(allLogsResult.Results, yesterday);\n this.channelBreakdown = this.buildChannelBreakdown(allLogsResult.Results);\n }\n\n if (providersResult.Success && allLogsResult.Success) {\n this.providerHealth = this.buildProviderHealth(providersResult.Results, allLogsResult.Results);\n }\n\n } catch (error) {\n console.error('Error loading monitor data:', error);\n } finally {\n this.isLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n public getActivityIconClass(log: MJCommunicationLogEntity): string {\n if (log.Status === 'Failed') return 'error';\n const type = (log.CommunicationProviderMessageType || '').toLowerCase();\n if (type.includes('sms')) return 'sms';\n return 'email';\n }\n\n public getActivityIcon(log: MJCommunicationLogEntity): string {\n if (log.Direction === 'Receiving') return 'fa-solid fa-arrow-down';\n const type = (log.CommunicationProviderMessageType || '').toLowerCase();\n if (type.includes('sms')) return 'fa-solid fa-comment-sms';\n return 'fa-solid fa-envelope';\n }\n\n public getHealthClass(rate: number): string {\n if (rate >= 98) return 'excellent';\n if (rate >= 95) return 'good';\n if (rate >= 85) return 'warning';\n return 'critical';\n }\n\n private processTrendData(logs: MJCommunicationLogEntity[], startTime: Date): HourlyBucket[] {\n const buckets: HourlyBucket[] = [];\n const now = new Date();\n const current = new Date(startTime);\n current.setMinutes(0, 0, 0);\n\n while (current <= now) {\n const bucketStart = new Date(current);\n const bucketEnd = new Date(current.getTime() + 60 * 60 * 1000);\n const bucketLogs = logs.filter(l => {\n const d = new Date(l.MessageDate);\n return d >= bucketStart && d < bucketEnd;\n });\n\n buckets.push({\n timestamp: bucketStart,\n executions: bucketLogs.length,\n errors: bucketLogs.filter(l => l.Status === 'Failed').length,\n cost: 0,\n tokens: 0,\n avgTime: 0\n });\n current.setHours(current.getHours() + 1);\n }\n return buckets;\n }\n\n private buildProviderHealth(providers: MJCommunicationProviderEntity[], logs: MJCommunicationLogEntity[]): ProviderHealth[] {\n return providers.map(p => {\n const providerLogs = logs.filter(l => l.CommunicationProvider === p.Name);\n const sent = providerLogs.length;\n const failed = providerLogs.filter(l => l.Status === 'Failed').length;\n const rate = sent > 0 ? parseFloat(((sent - failed) / sent * 100).toFixed(1)) : 100;\n\n return {\n Name: p.Name,\n Type: this.getProviderType(p.Name),\n SentCount: sent,\n SuccessRate: rate,\n IsActive: p.Status === 'Active',\n IconClass: this.getProviderIconClass(p.Name),\n ColorClass: this.getProviderColorClass(p.Name)\n };\n });\n }\n\n private buildChannelBreakdown(logs: MJCommunicationLogEntity[]): ChannelBreakdown[] {\n const total = logs.length;\n if (total === 0) return [];\n\n const emailLogs = logs.filter(l => {\n const type = (l.CommunicationProviderMessageType || '').toLowerCase();\n return type.includes('email') || (!type.includes('sms'));\n });\n const smsLogs = logs.filter(l => {\n const type = (l.CommunicationProviderMessageType || '').toLowerCase();\n return type.includes('sms');\n });\n\n const channels: ChannelBreakdown[] = [];\n if (emailLogs.length > 0) {\n channels.push({\n Name: 'Email',\n IconClass: 'fa-solid fa-envelope',\n Count: emailLogs.length,\n Percentage: Math.round((emailLogs.length / total) * 100),\n ColorClass: 'email'\n });\n }\n if (smsLogs.length > 0) {\n channels.push({\n Name: 'SMS',\n IconClass: 'fa-solid fa-comment-sms',\n Count: smsLogs.length,\n Percentage: Math.round((smsLogs.length / total) * 100),\n ColorClass: 'sms'\n });\n }\n return channels;\n }\n\n private getProviderType(name: string): string {\n const n = name.toLowerCase();\n if (n.includes('twilio')) return 'SMS';\n return 'Email';\n }\n\n private getProviderIconClass(name: string): string {\n const n = name.toLowerCase();\n if (n.includes('sendgrid')) return 'fa-solid fa-envelope';\n if (n.includes('twilio')) return 'fa-solid fa-comment-sms';\n if (n.includes('gmail') || n.includes('google')) return 'fa-brands fa-google';\n if (n.includes('microsoft') || n.includes('graph') || n.includes('outlook')) return 'fa-brands fa-microsoft';\n return 'fa-solid fa-server';\n }\n\n private getProviderColorClass(name: string): string {\n const n = name.toLowerCase();\n if (n.includes('sendgrid')) return 'sendgrid';\n if (n.includes('twilio')) return 'twilio';\n if (n.includes('gmail') || n.includes('google')) return 'gmail';\n if (n.includes('microsoft') || n.includes('graph') || n.includes('outlook')) return 'msgraph';\n return '';\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n return 'Monitor';\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-chart-line';\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"communication-monitor-resource.component.js","sourceRoot":"","sources":["../../src/Communication/communication-monitor-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';\nimport { ResourceData, MJCommunicationLogEntity, MJCommunicationProviderEntity } from '@memberjunction/core-entities';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { RunView } from '@memberjunction/core';\n\ninterface ProviderHealth {\n Name: string;\n Type: string;\n SentCount: number;\n SuccessRate: number;\n IsActive: boolean;\n IconClass: string;\n ColorClass: string;\n}\n\ninterface ChannelBreakdown {\n Name: string;\n IconClass: string;\n Count: number;\n Percentage: number;\n ColorClass: string;\n}\n\ninterface HourlyBucket {\n timestamp: Date;\n executions: number;\n errors: number;\n cost: number;\n tokens: number;\n avgTime: number;\n}\n@RegisterClass(BaseResourceComponent, 'CommunicationMonitorResource')\n@Component({\n standalone: false,\n selector: 'mj-communication-monitor-resource',\n template: `\n <div class=\"monitor-wrapper\">\n <div class=\"monitor-container\">\n <!-- KPI STRIP -->\n <div class=\"kpi-strip\">\n <div class=\"kpi-card sent\">\n <div class=\"kpi-icon\"><i class=\"fa-solid fa-paper-plane\"></i></div>\n <div class=\"kpi-body\">\n <span class=\"kpi-label\">Total Sent</span>\n <span class=\"kpi-value\">{{stats.totalSent | number}}</span>\n <span class=\"kpi-delta\" [class]=\"stats.totalSent > 0 ? 'up' : 'neutral'\">\n <i class=\"fa-solid\" [class.fa-arrow-up]=\"stats.totalSent > 0\" [class.fa-minus]=\"stats.totalSent === 0\"></i>\n Last 24 hours\n </span>\n </div>\n </div>\n <div class=\"kpi-card delivered\">\n <div class=\"kpi-icon\"><i class=\"fa-solid fa-check-double\"></i></div>\n <div class=\"kpi-body\">\n <span class=\"kpi-label\">Delivery Rate</span>\n <span class=\"kpi-value\">{{stats.deliveryRate}}%</span>\n <div class=\"delivery-bar\">\n <div class=\"delivery-fill\" [style.width.%]=\"stats.deliveryRate\"></div>\n </div>\n </div>\n </div>\n <div class=\"kpi-card pending\">\n <div class=\"kpi-icon\"><i class=\"fa-solid fa-clock\"></i></div>\n <div class=\"kpi-body\">\n <span class=\"kpi-label\">Pending</span>\n <span class=\"kpi-value\">{{stats.pending | number}}</span>\n <span class=\"kpi-delta neutral\">\n <i class=\"fa-solid fa-minus\"></i> Awaiting provider\n </span>\n </div>\n </div>\n <div class=\"kpi-card failed\">\n <div class=\"kpi-icon\"><i class=\"fa-solid fa-circle-exclamation\"></i></div>\n <div class=\"kpi-body\">\n <span class=\"kpi-label\">Failed</span>\n <span class=\"kpi-value\">{{stats.failed | number}}</span>\n <span class=\"kpi-delta\" [class]=\"stats.failed > 0 ? 'down' : 'neutral'\">\n <i class=\"fa-solid\" [class.fa-arrow-up]=\"stats.failed > 0\" [class.fa-minus]=\"stats.failed === 0\"></i>\n {{stats.failed > 0 ? 'Requires attention' : 'No failures'}}\n </span>\n </div>\n </div>\n </div>\n \n <!-- CHARTS + ACTIVITY ROW -->\n <div class=\"content-grid\">\n <div class=\"card\">\n <div class=\"card-header\">\n <h3><i class=\"fa-solid fa-chart-bar\"></i> Delivery Volume</h3>\n </div>\n <div class=\"chart-container-inner\">\n <app-time-series-chart\n [data]=\"chartData\"\n [showLegend]=\"true\"\n [showControls]=\"false\"\n [config]=\"chartConfig\">\n </app-time-series-chart>\n </div>\n </div>\n \n <div class=\"card\">\n <div class=\"card-header\">\n <h3><i class=\"fa-solid fa-bolt\"></i> Recent Activity</h3>\n </div>\n <div class=\"card-body no-padding\">\n <div class=\"activity-feed\">\n @for (log of recentLogs; track log) {\n <div class=\"activity-item\">\n <div class=\"activity-icon\" [ngClass]=\"getActivityIconClass(log)\">\n <i [class]=\"getActivityIcon(log)\"></i>\n </div>\n <div class=\"activity-body\">\n <span class=\"activity-title\">{{log.CommunicationProviderMessageType || 'Message'}}</span>\n <span class=\"activity-meta\">{{log.CommunicationProvider}} • {{log.MessageDate | date:'shortTime'}}</span>\n </div>\n <span class=\"activity-status\" [ngClass]=\"log.Status.toLowerCase()\">\n {{log.Status}}\n </span>\n </div>\n }\n @if (recentLogs.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-inbox\"></i>\n <p>No recent activity</p>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n \n <!-- PROVIDER HEALTH + CHANNEL BREAKDOWN -->\n <div class=\"content-grid\">\n <div class=\"card\">\n <div class=\"card-header\">\n <h3><i class=\"fa-solid fa-heart-pulse\"></i> Provider Health</h3>\n </div>\n <div class=\"card-body no-padding\">\n <div class=\"provider-health-list\">\n @for (provider of providerHealth; track provider) {\n <div class=\"provider-row\">\n <div class=\"provider-status-dot\" [class.active]=\"provider.IsActive\"></div>\n <div class=\"provider-logo\" [ngClass]=\"provider.ColorClass\">\n <i [class]=\"provider.IconClass\"></i>\n </div>\n <div class=\"provider-info\">\n <div class=\"provider-name\">{{provider.Name}}</div>\n <div class=\"provider-type\">{{provider.Type}} • {{provider.SentCount}} sent today</div>\n </div>\n <div class=\"provider-health-bar\">\n <div class=\"provider-health-fill\" [ngClass]=\"getHealthClass(provider.SuccessRate)\" [style.width.%]=\"provider.SuccessRate\"></div>\n </div>\n <span class=\"provider-rate\" [ngClass]=\"getHealthClass(provider.SuccessRate)\">{{provider.SuccessRate}}%</span>\n </div>\n }\n @if (providerHealth.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-server\"></i>\n <p>No providers configured</p>\n </div>\n }\n </div>\n </div>\n </div>\n \n <div class=\"card\">\n <div class=\"card-header\">\n <h3><i class=\"fa-solid fa-layer-group\"></i> Channel Breakdown</h3>\n </div>\n <div class=\"card-body no-padding\">\n <div class=\"channel-breakdown\">\n @for (channel of channelBreakdown; track channel) {\n <div class=\"channel-row\">\n <div class=\"channel-icon\" [ngClass]=\"channel.ColorClass\">\n <i [class]=\"channel.IconClass\"></i>\n </div>\n <div class=\"channel-info\">\n <div class=\"channel-name\">{{channel.Name}}</div>\n <div class=\"channel-count\">{{channel.Count | number}} messages</div>\n </div>\n <div class=\"channel-bar-wrapper\">\n <div class=\"channel-bar-fill\" [style.width.%]=\"channel.Percentage\" [style.background]=\"channel.ColorClass === 'email' ? 'var(--mj-brand-primary)' : 'var(--mj-status-success)'\"></div>\n </div>\n <span class=\"channel-pct\">{{channel.Percentage}}%</span>\n </div>\n }\n @if (channelBreakdown.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-layer-group\"></i>\n <p>No channel data available</p>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n `,\n styles: [`\n .monitor-wrapper {\n height: 100%;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n }\n .monitor-container {\n padding: 24px;\n min-height: 100%;\n max-width: 1600px;\n margin: 0 auto;\n }\n\n /* KPI STRIP */\n .kpi-strip {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 16px;\n margin-bottom: 24px;\n }\n .kpi-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n display: flex;\n align-items: flex-start;\n gap: 16px;\n transition: all 0.15s ease;\n position: relative;\n overflow: hidden;\n }\n .kpi-card:hover {\n box-shadow: 0 2px 8px var(--mj-shadow-md);\n border-color: var(--mj-border-strong);\n }\n .kpi-card::before {\n content: '';\n position: absolute;\n top: 0; left: 0; right: 0;\n height: 3px;\n }\n .kpi-card.sent::before { background: var(--mj-brand-primary); }\n .kpi-card.delivered::before { background: var(--mj-status-success); }\n .kpi-card.pending::before { background: var(--mj-status-warning); }\n .kpi-card.failed::before { background: var(--mj-status-error); }\n\n .kpi-icon {\n width: 44px; height: 44px;\n border-radius: 12px;\n display: flex; align-items: center; justify-content: center;\n font-size: 16px; flex-shrink: 0;\n }\n .kpi-card.sent .kpi-icon {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n .kpi-card.delivered .kpi-icon {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n .kpi-card.pending .kpi-icon {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n }\n .kpi-card.failed .kpi-icon {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n\n .kpi-body { flex: 1; display: flex; flex-direction: column; gap: 2px; }\n .kpi-label {\n font-size: 11px; font-weight: 600;\n text-transform: uppercase; letter-spacing: 0.5px;\n color: var(--mj-text-muted);\n }\n .kpi-value {\n font-size: 28px; font-weight: 800;\n color: var(--mj-text-primary);\n letter-spacing: -0.02em; line-height: 1.1;\n }\n .kpi-delta {\n display: inline-flex; align-items: center;\n gap: 4px; font-size: 11px; font-weight: 600;\n margin-top: 4px; padding: 2px 8px;\n border-radius: 10px; width: fit-content;\n }\n .kpi-delta.up {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n .kpi-delta.down {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n .kpi-delta.neutral {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n }\n\n .delivery-bar {\n height: 6px; margin-top: 10px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px; overflow: hidden;\n }\n .delivery-fill {\n height: 100%; border-radius: 3px;\n background: var(--mj-status-success); transition: width 0.6s ease;\n }\n\n /* CONTENT GRID */\n .content-grid {\n display: grid;\n grid-template-columns: 1.6fr 1fr;\n gap: 16px;\n margin-bottom: 16px;\n }\n\n .card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n }\n .card-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n }\n .card-header h3 {\n font-size: 13px; font-weight: 700;\n color: var(--mj-text-primary);\n display: flex; align-items: center; gap: 8px;\n margin: 0;\n }\n .card-header h3 i {\n color: var(--mj-text-muted);\n font-size: 12px;\n }\n .card-body { padding: 16px 20px; }\n .card-body.no-padding { padding: 0; }\n\n .chart-container-inner {\n padding: 16px 20px;\n min-height: 300px;\n }\n\n /* ACTIVITY FEED */\n .activity-feed { max-height: 370px; overflow-y: auto; }\n .activity-item {\n display: flex; align-items: center; gap: 12px;\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n transition: background 0.15s ease; cursor: pointer;\n }\n .activity-item:last-child { border-bottom: none; }\n .activity-item:hover { background: var(--mj-bg-surface-sunken); }\n\n .activity-icon {\n width: 34px; height: 34px;\n border-radius: 8px;\n display: flex; align-items: center; justify-content: center;\n font-size: 12px; flex-shrink: 0;\n }\n .activity-icon.email {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n .activity-icon.sms {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n .activity-icon.error {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n\n .activity-body { flex: 1; min-width: 0; }\n .activity-title {\n font-size: 12px; font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n display: block;\n }\n .activity-meta {\n font-size: 11px; color: var(--mj-text-muted); margin-top: 1px;\n display: block;\n }\n .activity-status {\n font-size: 10px; font-weight: 700;\n text-transform: uppercase; letter-spacing: 0.3px;\n padding: 3px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n .activity-status.complete {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n .activity-status.failed {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n .activity-status.pending {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n }\n\n /* PROVIDER HEALTH */\n .provider-health-list { display: flex; flex-direction: column; }\n .provider-row {\n display: flex; align-items: center; gap: 12px;\n padding: 14px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n transition: background 0.15s ease;\n }\n .provider-row:last-child { border-bottom: none; }\n .provider-row:hover { background: var(--mj-bg-surface-sunken); }\n\n .provider-status-dot {\n width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;\n background: var(--mj-border-strong);\n }\n .provider-status-dot.active { background: var(--mj-status-success); }\n\n .provider-logo {\n width: 36px; height: 36px;\n border-radius: 8px;\n background: var(--mj-bg-surface-sunken);\n display: flex; align-items: center; justify-content: center;\n font-size: 16px; flex-shrink: 0;\n }\n .provider-logo.sendgrid { color: var(--mj-brand-primary); }\n .provider-logo.twilio { color: var(--mj-status-error); }\n .provider-logo.gmail { color: var(--mj-status-error); }\n .provider-logo.msgraph { color: var(--mj-brand-primary); }\n\n .provider-info { flex: 1; }\n .provider-name { font-size: 13px; font-weight: 600; color: var(--mj-text-primary); }\n .provider-type { font-size: 11px; color: var(--mj-text-muted); }\n\n .provider-health-bar {\n width: 80px; height: 6px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px; overflow: hidden;\n }\n .provider-health-fill {\n height: 100%; border-radius: 3px;\n transition: width 0.4s ease;\n }\n .provider-health-fill.excellent { background: var(--mj-status-success); }\n .provider-health-fill.good { background: var(--mj-status-success); }\n .provider-health-fill.warning { background: var(--mj-status-warning); }\n .provider-health-fill.critical { background: var(--mj-status-error); }\n\n .provider-rate {\n font-size: 12px; font-weight: 700;\n min-width: 44px; text-align: right;\n }\n .provider-rate.excellent { color: var(--mj-status-success); }\n .provider-rate.good { color: var(--mj-status-success); }\n .provider-rate.warning { color: var(--mj-status-warning); }\n .provider-rate.critical { color: var(--mj-status-error); }\n\n /* CHANNEL BREAKDOWN */\n .channel-breakdown { display: flex; flex-direction: column; }\n .channel-row {\n display: flex; align-items: center; gap: 12px;\n padding: 14px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n }\n .channel-row:last-child { border-bottom: none; }\n .channel-icon {\n width: 32px; height: 32px;\n border-radius: 8px;\n display: flex; align-items: center; justify-content: center;\n font-size: 13px; flex-shrink: 0;\n }\n .channel-icon.email {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n .channel-icon.sms {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n\n .channel-info { flex: 1; }\n .channel-name { font-size: 12px; font-weight: 600; color: var(--mj-text-primary); }\n .channel-count { font-size: 11px; color: var(--mj-text-muted); }\n\n .channel-bar-wrapper {\n width: 100px; height: 6px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px; overflow: hidden;\n }\n .channel-bar-fill { height: 100%; border-radius: 3px; }\n .channel-pct {\n font-size: 12px; font-weight: 700;\n color: var(--mj-text-primary);\n min-width: 36px; text-align: right;\n }\n\n /* EMPTY STATE */\n .empty-state {\n display: flex; flex-direction: column;\n align-items: center; justify-content: center;\n padding: 40px 0; color: var(--mj-text-muted);\n }\n .empty-state i { font-size: 2rem; margin-bottom: 12px; opacity: 0.5; }\n .empty-state p { margin: 0; font-size: 13px; }\n\n @media (max-width: 1200px) {\n .kpi-strip { grid-template-columns: repeat(2, 1fr); }\n .content-grid { grid-template-columns: 1fr; }\n }\n `]\n})\nexport class CommunicationMonitorResourceComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n public isLoading = false;\n public stats = {\n totalSent: 0,\n deliveryRate: 0,\n pending: 0,\n failed: 0\n };\n public recentLogs: MJCommunicationLogEntity[] = [];\n public chartData: HourlyBucket[] = [];\n public chartConfig = {\n useDualAxis: false,\n showGrid: true,\n showTooltip: true,\n colors: ['#4f6bed', '#cf222e']\n };\n public providerHealth: ProviderHealth[] = [];\n public channelBreakdown: ChannelBreakdown[] = [];\n\n constructor(private cdr: ChangeDetectorRef) {\n super();\n }\n\n async ngOnInit(): Promise<void> {\n super.ngOnInit();\n await this.loadData();\n this.NotifyLoadComplete();\n }\n\n ngOnDestroy(): void {\n super.ngOnDestroy();\n }\n\n public async loadData(): Promise<void> {\n try {\n this.isLoading = true;\n this.cdr.detectChanges();\n\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const yesterday = new Date();\n yesterday.setDate(yesterday.getDate() - 1);\n const yesterdayIso = yesterday.toISOString();\n\n const [totalResult, failedResult, pendingResult, recentResult, allLogsResult, providersResult] = await Promise.all([\n rv.RunView({\n EntityName: 'MJ: Communication Logs',\n ExtraFilter: `MessageDate >= '${yesterdayIso}'`,\n ResultType: 'count_only'\n }),\n rv.RunView({\n EntityName: 'MJ: Communication Logs',\n ExtraFilter: `MessageDate >= '${yesterdayIso}' AND Status = 'Failed'`,\n ResultType: 'count_only'\n }),\n rv.RunView({\n EntityName: 'MJ: Communication Logs',\n ExtraFilter: `Status = 'Pending'`,\n ResultType: 'count_only'\n }),\n rv.RunView<MJCommunicationLogEntity>({\n EntityName: 'MJ: Communication Logs',\n OrderBy: 'MessageDate DESC',\n MaxRows: 8,\n ResultType: 'entity_object'\n }),\n rv.RunView<MJCommunicationLogEntity>({\n EntityName: 'MJ: Communication Logs',\n ExtraFilter: `MessageDate >= '${yesterdayIso}'`,\n OrderBy: 'MessageDate ASC',\n ResultType: 'entity_object'\n }),\n rv.RunView<MJCommunicationProviderEntity>({\n EntityName: 'MJ: Communication Providers',\n OrderBy: 'Name ASC',\n ResultType: 'entity_object'\n })\n ]);\n\n if (totalResult.Success) this.stats.totalSent = totalResult.TotalRowCount;\n if (failedResult.Success) this.stats.failed = failedResult.TotalRowCount;\n if (pendingResult.Success) this.stats.pending = pendingResult.TotalRowCount;\n\n this.stats.deliveryRate = this.stats.totalSent > 0\n ? parseFloat(((this.stats.totalSent - this.stats.failed) / this.stats.totalSent * 100).toFixed(1))\n : 100;\n\n if (recentResult.Success) {\n this.recentLogs = recentResult.Results;\n }\n\n if (allLogsResult.Success) {\n this.chartData = this.processTrendData(allLogsResult.Results, yesterday);\n this.channelBreakdown = this.buildChannelBreakdown(allLogsResult.Results);\n }\n\n if (providersResult.Success && allLogsResult.Success) {\n this.providerHealth = this.buildProviderHealth(providersResult.Results, allLogsResult.Results);\n }\n\n } catch (error) {\n console.error('Error loading monitor data:', error);\n } finally {\n this.isLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n public getActivityIconClass(log: MJCommunicationLogEntity): string {\n if (log.Status === 'Failed') return 'error';\n const type = (log.CommunicationProviderMessageType || '').toLowerCase();\n if (type.includes('sms')) return 'sms';\n return 'email';\n }\n\n public getActivityIcon(log: MJCommunicationLogEntity): string {\n if (log.Direction === 'Receiving') return 'fa-solid fa-arrow-down';\n const type = (log.CommunicationProviderMessageType || '').toLowerCase();\n if (type.includes('sms')) return 'fa-solid fa-comment-sms';\n return 'fa-solid fa-envelope';\n }\n\n public getHealthClass(rate: number): string {\n if (rate >= 98) return 'excellent';\n if (rate >= 95) return 'good';\n if (rate >= 85) return 'warning';\n return 'critical';\n }\n\n private processTrendData(logs: MJCommunicationLogEntity[], startTime: Date): HourlyBucket[] {\n const buckets: HourlyBucket[] = [];\n const now = new Date();\n const current = new Date(startTime);\n current.setMinutes(0, 0, 0);\n\n while (current <= now) {\n const bucketStart = new Date(current);\n const bucketEnd = new Date(current.getTime() + 60 * 60 * 1000);\n const bucketLogs = logs.filter(l => {\n const d = new Date(l.MessageDate);\n return d >= bucketStart && d < bucketEnd;\n });\n\n buckets.push({\n timestamp: bucketStart,\n executions: bucketLogs.length,\n errors: bucketLogs.filter(l => l.Status === 'Failed').length,\n cost: 0,\n tokens: 0,\n avgTime: 0\n });\n current.setHours(current.getHours() + 1);\n }\n return buckets;\n }\n\n private buildProviderHealth(providers: MJCommunicationProviderEntity[], logs: MJCommunicationLogEntity[]): ProviderHealth[] {\n return providers.map(p => {\n const providerLogs = logs.filter(l => l.CommunicationProvider === p.Name);\n const sent = providerLogs.length;\n const failed = providerLogs.filter(l => l.Status === 'Failed').length;\n const rate = sent > 0 ? parseFloat(((sent - failed) / sent * 100).toFixed(1)) : 100;\n\n return {\n Name: p.Name,\n Type: this.getProviderType(p.Name),\n SentCount: sent,\n SuccessRate: rate,\n IsActive: p.Status === 'Active',\n IconClass: this.getProviderIconClass(p.Name),\n ColorClass: this.getProviderColorClass(p.Name)\n };\n });\n }\n\n private buildChannelBreakdown(logs: MJCommunicationLogEntity[]): ChannelBreakdown[] {\n const total = logs.length;\n if (total === 0) return [];\n\n const emailLogs = logs.filter(l => {\n const type = (l.CommunicationProviderMessageType || '').toLowerCase();\n return type.includes('email') || (!type.includes('sms'));\n });\n const smsLogs = logs.filter(l => {\n const type = (l.CommunicationProviderMessageType || '').toLowerCase();\n return type.includes('sms');\n });\n\n const channels: ChannelBreakdown[] = [];\n if (emailLogs.length > 0) {\n channels.push({\n Name: 'Email',\n IconClass: 'fa-solid fa-envelope',\n Count: emailLogs.length,\n Percentage: Math.round((emailLogs.length / total) * 100),\n ColorClass: 'email'\n });\n }\n if (smsLogs.length > 0) {\n channels.push({\n Name: 'SMS',\n IconClass: 'fa-solid fa-comment-sms',\n Count: smsLogs.length,\n Percentage: Math.round((smsLogs.length / total) * 100),\n ColorClass: 'sms'\n });\n }\n return channels;\n }\n\n private getProviderType(name: string): string {\n const n = name.toLowerCase();\n if (n.includes('twilio')) return 'SMS';\n return 'Email';\n }\n\n private getProviderIconClass(name: string): string {\n const n = name.toLowerCase();\n if (n.includes('sendgrid')) return 'fa-solid fa-envelope';\n if (n.includes('twilio')) return 'fa-solid fa-comment-sms';\n if (n.includes('gmail') || n.includes('google')) return 'fa-brands fa-google';\n if (n.includes('microsoft') || n.includes('graph') || n.includes('outlook')) return 'fa-brands fa-microsoft';\n return 'fa-solid fa-server';\n }\n\n private getProviderColorClass(name: string): string {\n const n = name.toLowerCase();\n if (n.includes('sendgrid')) return 'sendgrid';\n if (n.includes('twilio')) return 'twilio';\n if (n.includes('gmail') || n.includes('google')) return 'gmail';\n if (n.includes('microsoft') || n.includes('graph') || n.includes('outlook')) return 'msgraph';\n return '';\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n return 'Monitor';\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-chart-line';\n }\n}\n"]}
|
|
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { Component } from '@angular/core';
|
|
8
8
|
import { RegisterClass } from '@memberjunction/global';
|
|
9
9
|
import { BaseResourceComponent } from '@memberjunction/ng-shared';
|
|
10
|
-
import {
|
|
10
|
+
import { RunView, CompositeKey } from '@memberjunction/core';
|
|
11
11
|
import * as i0 from "@angular/core";
|
|
12
12
|
import * as i1 from "@memberjunction/ng-shared";
|
|
13
13
|
import * as i2 from "@angular/common";
|
|
@@ -165,7 +165,7 @@ let CommunicationProvidersResourceComponent = class CommunicationProvidersResour
|
|
|
165
165
|
try {
|
|
166
166
|
this.isLoading = true;
|
|
167
167
|
this.cdr.detectChanges();
|
|
168
|
-
const rv =
|
|
168
|
+
const rv = RunView.FromMetadataProvider(this.ProviderToUse);
|
|
169
169
|
const yesterday = new Date();
|
|
170
170
|
yesterday.setDate(yesterday.getDate() - 1);
|
|
171
171
|
const yesterdayIso = yesterday.toISOString();
|
|
@@ -238,7 +238,7 @@ let CommunicationProvidersResourceComponent = class CommunicationProvidersResour
|
|
|
238
238
|
}
|
|
239
239
|
configureProvider(provider) {
|
|
240
240
|
const pk = new CompositeKey();
|
|
241
|
-
pk.LoadFromEntityInfoAndRecord(
|
|
241
|
+
pk.LoadFromEntityInfoAndRecord(this.ProviderToUse.Entities.find(e => e.Name === 'MJ: Communication Providers'), provider);
|
|
242
242
|
this.navService.OpenEntityRecord('MJ: Communication Providers', pk);
|
|
243
243
|
}
|
|
244
244
|
viewProviderLogs(provider) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"communication-providers-resource.component.js","sourceRoot":"","sources":["../../src/Communication/communication-providers-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';\nimport { ResourceData, MJCommunicationProviderEntity, MJCommunicationLogEntity } from '@memberjunction/core-entities';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';\nimport { Metadata, RunView, CompositeKey } from '@memberjunction/core';\n\ninterface ProviderCardData {\n Entity: MJCommunicationProviderEntity;\n SentCount: number;\n SuccessRate: number;\n FailedCount: number;\n IconClass: string;\n LogoClass: string;\n}\n@RegisterClass(BaseResourceComponent, 'CommunicationProvidersResource')\n@Component({\n standalone: false,\n selector: 'mj-communication-providers-resource',\n template: `\n <div class=\"providers-wrapper\">\n <div class=\"providers-header\">\n <div>\n <h2>Communication Providers</h2>\n <p>Manage your messaging service integrations</p>\n </div>\n <button class=\"tb-btn primary\" (click)=\"addNewProvider()\">\n <i class=\"fa-solid fa-plus\"></i> Add Provider\n </button>\n </div>\n \n @if (isLoading) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading providers...\"></mj-loading>\n </div>\n }\n \n @if (!isLoading) {\n <div class=\"providers-grid\">\n @for (card of providerCards; track card) {\n <div class=\"provider-card\" [class.disabled]=\"card.Entity.Status === 'Disabled'\">\n <div class=\"provider-card-header\">\n <div class=\"provider-card-logo\" [ngClass]=\"card.LogoClass\">\n <i [class]=\"card.IconClass\"></i>\n </div>\n <div class=\"provider-card-title\">\n <div class=\"provider-card-name\">{{card.Entity.Name}}</div>\n <div class=\"provider-card-desc\">{{card.Entity.Description || 'No description'}}</div>\n </div>\n <span class=\"provider-card-status\" [ngClass]=\"card.Entity.Status.toLowerCase()\">\n {{card.Entity.Status}}\n </span>\n </div>\n <div class=\"provider-card-body\">\n <div class=\"provider-capabilities\">\n <span class=\"capability-chip\" [class.supported]=\"card.Entity.SupportsSending\" [class.unsupported]=\"!card.Entity.SupportsSending\">\n <i [class]=\"card.Entity.SupportsSending ? 'fa-solid fa-check' : 'fa-solid fa-xmark'\"></i> Sending\n </span>\n <span class=\"capability-chip\" [class.supported]=\"card.Entity.SupportsReceiving\" [class.unsupported]=\"!card.Entity.SupportsReceiving\">\n <i [class]=\"card.Entity.SupportsReceiving ? 'fa-solid fa-check' : 'fa-solid fa-xmark'\"></i> Receiving\n </span>\n @if (card.Entity.SupportsScheduledSending) {\n <span class=\"capability-chip supported\">\n <i class=\"fa-solid fa-check\"></i> Scheduled\n </span>\n }\n @if (card.Entity.SupportsDrafts) {\n <span class=\"capability-chip supported\">\n <i class=\"fa-solid fa-check\"></i> Drafts\n </span>\n }\n @if (card.Entity.SupportsForwarding) {\n <span class=\"capability-chip supported\">\n <i class=\"fa-solid fa-check\"></i> Forward\n </span>\n }\n @if (card.Entity.SupportsReplying) {\n <span class=\"capability-chip supported\">\n <i class=\"fa-solid fa-check\"></i> Reply\n </span>\n }\n </div>\n <div class=\"provider-card-stats\">\n <div class=\"provider-stat\">\n <div class=\"provider-stat-value\">{{card.SentCount}}</div>\n <div class=\"provider-stat-label\">Sent (24h)</div>\n </div>\n <div class=\"provider-stat\">\n <div class=\"provider-stat-value\">{{card.SuccessRate}}%</div>\n <div class=\"provider-stat-label\">Success</div>\n </div>\n <div class=\"provider-stat\">\n <div class=\"provider-stat-value\">{{card.FailedCount}}</div>\n <div class=\"provider-stat-label\">Failed</div>\n </div>\n </div>\n </div>\n <div class=\"provider-card-footer\">\n <button (click)=\"configureProvider(card.Entity)\">\n <i class=\"fa-solid fa-gear\"></i> Configure\n </button>\n <button (click)=\"viewProviderLogs(card.Entity)\">\n <i class=\"fa-solid fa-chart-line\"></i> Analytics\n </button>\n </div>\n </div>\n }\n </div>\n }\n </div>\n `,\n styles: [`\n .providers-wrapper {\n height: 100%;\n padding: 24px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n }\n .providers-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 20px;\n }\n .providers-header h2 {\n margin: 0;\n font-size: 18px;\n font-weight: 800;\n color: var(--mj-text-primary);\n }\n .providers-header p {\n margin: 4px 0 0;\n font-size: 13px;\n color: var(--mj-text-muted);\n }\n\n .tb-btn {\n display: inline-flex; align-items: center;\n gap: 6px; padding: 8px 16px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n font-size: 12px; font-weight: 600;\n cursor: pointer; transition: all 0.15s ease;\n font-family: inherit;\n }\n .tb-btn.primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n }\n .tb-btn.primary:hover { background: var(--mj-brand-primary-hover); }\n\n .loading-state {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 80px 0;\n }\n\n /* GRID */\n .providers-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));\n gap: 16px;\n }\n .provider-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n transition: all 0.15s ease;\n }\n .provider-card:hover {\n box-shadow: 0 2px 8px var(--mj-shadow-md);\n border-color: var(--mj-border-strong);\n }\n .provider-card.disabled { opacity: 0.65; }\n\n .provider-card-header {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 20px 20px 16px;\n }\n .provider-card-logo {\n width: 48px; height: 48px;\n border-radius: 12px;\n display: flex; align-items: center; justify-content: center;\n font-size: 22px; flex-shrink: 0;\n background: var(--mj-bg-surface-sunken);\n }\n .provider-card-logo.sendgrid {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n .provider-card-logo.twilio {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n .provider-card-logo.gmail {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n .provider-card-logo.msgraph {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n .provider-card-title { flex: 1; min-width: 0; }\n .provider-card-name {\n font-size: 15px; font-weight: 700;\n color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .provider-card-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n }\n .provider-card-status {\n font-size: 10px; font-weight: 700;\n text-transform: uppercase; letter-spacing: 0.5px;\n padding: 3px 10px; border-radius: 10px;\n flex-shrink: 0;\n }\n .provider-card-status.active {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n .provider-card-status.disabled {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n }\n\n .provider-card-body { padding: 0 20px 16px; }\n\n .provider-capabilities {\n display: flex; flex-wrap: wrap;\n gap: 6px; margin-bottom: 16px;\n }\n .capability-chip {\n display: inline-flex; align-items: center;\n gap: 4px; padding: 4px 10px;\n border-radius: 12px; font-size: 11px; font-weight: 500;\n }\n .capability-chip.supported {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n .capability-chip.unsupported {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n text-decoration: line-through;\n }\n\n .provider-card-stats {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 12px; padding: 12px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n }\n .provider-stat { text-align: center; }\n .provider-stat-value {\n font-size: 16px; font-weight: 800;\n color: var(--mj-text-primary);\n }\n .provider-stat-label {\n font-size: 10px;\n color: var(--mj-text-muted);\n text-transform: uppercase; letter-spacing: 0.3px;\n }\n\n .provider-card-footer {\n display: flex;\n border-top: 1px solid var(--mj-border-default);\n }\n .provider-card-footer button {\n flex: 1; padding: 12px;\n border: none; background: transparent;\n font-size: 12px; font-weight: 600;\n color: var(--mj-brand-primary);\n cursor: pointer; transition: background 0.15s;\n font-family: inherit;\n display: flex; align-items: center;\n justify-content: center; gap: 6px;\n }\n .provider-card-footer button:hover {\n background: var(--mj-bg-surface-sunken);\n }\n .provider-card-footer button + button {\n border-left: 1px solid var(--mj-border-default);\n }\n `]\n})\nexport class CommunicationProvidersResourceComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n public isLoading = false;\n public providerCards: ProviderCardData[] = [];\n\n constructor(private cdr: ChangeDetectorRef, private navService: NavigationService) {\n super();\n }\n\n async ngOnInit(): Promise<void> {\n super.ngOnInit();\n await this.loadData();\n this.NotifyLoadComplete();\n }\n\n ngOnDestroy(): void {\n super.ngOnDestroy();\n }\n\n public async loadData(): Promise<void> {\n try {\n this.isLoading = true;\n this.cdr.detectChanges();\n\n const rv = new RunView();\n const yesterday = new Date();\n yesterday.setDate(yesterday.getDate() - 1);\n const yesterdayIso = yesterday.toISOString();\n\n const [providersResult, logsResult] = await Promise.all([\n rv.RunView<MJCommunicationProviderEntity>({\n EntityName: 'MJ: Communication Providers',\n OrderBy: 'Name ASC',\n ResultType: 'entity_object'\n }),\n rv.RunView<MJCommunicationLogEntity>({\n EntityName: 'MJ: Communication Logs',\n ExtraFilter: `MessageDate >= '${yesterdayIso}'`,\n ResultType: 'entity_object'\n })\n ]);\n\n if (providersResult.Success) {\n const logs = logsResult.Success ? logsResult.Results : [];\n this.providerCards = providersResult.Results.map(p => this.buildProviderCard(p, logs));\n }\n } catch (error) {\n console.error('Error loading providers:', error);\n } finally {\n this.isLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n private buildProviderCard(provider: MJCommunicationProviderEntity, logs: MJCommunicationLogEntity[]): ProviderCardData {\n const providerLogs = logs.filter(l => l.CommunicationProvider === provider.Name);\n const sent = providerLogs.length;\n const failed = providerLogs.filter(l => l.Status === 'Failed').length;\n const rate = sent > 0 ? parseFloat(((sent - failed) / sent * 100).toFixed(1)) : 100;\n\n return {\n Entity: provider,\n SentCount: sent,\n SuccessRate: rate,\n FailedCount: failed,\n IconClass: this.getProviderIcon(provider.Name),\n LogoClass: this.getProviderLogoClass(provider.Name)\n };\n }\n\n private getProviderIcon(name: string): string {\n const n = name.toLowerCase();\n if (n.includes('sendgrid')) return 'fa-solid fa-envelope';\n if (n.includes('twilio')) return 'fa-solid fa-comment-sms';\n if (n.includes('gmail') || n.includes('google')) return 'fa-brands fa-google';\n if (n.includes('microsoft') || n.includes('graph') || n.includes('outlook')) return 'fa-brands fa-microsoft';\n if (n.includes('aws') || n.includes('ses')) return 'fa-brands fa-aws';\n if (n.includes('slack')) return 'fa-brands fa-slack';\n return 'fa-solid fa-server';\n }\n\n private getProviderLogoClass(name: string): string {\n const n = name.toLowerCase();\n if (n.includes('sendgrid')) return 'sendgrid';\n if (n.includes('twilio')) return 'twilio';\n if (n.includes('gmail') || n.includes('google')) return 'gmail';\n if (n.includes('microsoft') || n.includes('graph') || n.includes('outlook')) return 'msgraph';\n return '';\n }\n\n public configureProvider(provider: MJCommunicationProviderEntity): void {\n const pk = new CompositeKey();\n pk.LoadFromEntityInfoAndRecord(new Metadata().Entities.find(e => e.Name === 'MJ: Communication Providers')!, provider);\n this.navService.OpenEntityRecord('MJ: Communication Providers', pk);\n }\n\n public viewProviderLogs(provider: MJCommunicationProviderEntity): void {\n console.log('View analytics for provider:', provider.Name);\n }\n\n public addNewProvider(): void {\n this.navService.OpenEntityRecord('MJ: Communication Providers', new CompositeKey());\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n return 'Providers';\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-server';\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"communication-providers-resource.component.js","sourceRoot":"","sources":["../../src/Communication/communication-providers-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';\nimport { ResourceData, MJCommunicationProviderEntity, MJCommunicationLogEntity } from '@memberjunction/core-entities';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';\nimport { Metadata, RunView, CompositeKey } from '@memberjunction/core';\n\ninterface ProviderCardData {\n Entity: MJCommunicationProviderEntity;\n SentCount: number;\n SuccessRate: number;\n FailedCount: number;\n IconClass: string;\n LogoClass: string;\n}\n@RegisterClass(BaseResourceComponent, 'CommunicationProvidersResource')\n@Component({\n standalone: false,\n selector: 'mj-communication-providers-resource',\n template: `\n <div class=\"providers-wrapper\">\n <div class=\"providers-header\">\n <div>\n <h2>Communication Providers</h2>\n <p>Manage your messaging service integrations</p>\n </div>\n <button class=\"tb-btn primary\" (click)=\"addNewProvider()\">\n <i class=\"fa-solid fa-plus\"></i> Add Provider\n </button>\n </div>\n \n @if (isLoading) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading providers...\"></mj-loading>\n </div>\n }\n \n @if (!isLoading) {\n <div class=\"providers-grid\">\n @for (card of providerCards; track card) {\n <div class=\"provider-card\" [class.disabled]=\"card.Entity.Status === 'Disabled'\">\n <div class=\"provider-card-header\">\n <div class=\"provider-card-logo\" [ngClass]=\"card.LogoClass\">\n <i [class]=\"card.IconClass\"></i>\n </div>\n <div class=\"provider-card-title\">\n <div class=\"provider-card-name\">{{card.Entity.Name}}</div>\n <div class=\"provider-card-desc\">{{card.Entity.Description || 'No description'}}</div>\n </div>\n <span class=\"provider-card-status\" [ngClass]=\"card.Entity.Status.toLowerCase()\">\n {{card.Entity.Status}}\n </span>\n </div>\n <div class=\"provider-card-body\">\n <div class=\"provider-capabilities\">\n <span class=\"capability-chip\" [class.supported]=\"card.Entity.SupportsSending\" [class.unsupported]=\"!card.Entity.SupportsSending\">\n <i [class]=\"card.Entity.SupportsSending ? 'fa-solid fa-check' : 'fa-solid fa-xmark'\"></i> Sending\n </span>\n <span class=\"capability-chip\" [class.supported]=\"card.Entity.SupportsReceiving\" [class.unsupported]=\"!card.Entity.SupportsReceiving\">\n <i [class]=\"card.Entity.SupportsReceiving ? 'fa-solid fa-check' : 'fa-solid fa-xmark'\"></i> Receiving\n </span>\n @if (card.Entity.SupportsScheduledSending) {\n <span class=\"capability-chip supported\">\n <i class=\"fa-solid fa-check\"></i> Scheduled\n </span>\n }\n @if (card.Entity.SupportsDrafts) {\n <span class=\"capability-chip supported\">\n <i class=\"fa-solid fa-check\"></i> Drafts\n </span>\n }\n @if (card.Entity.SupportsForwarding) {\n <span class=\"capability-chip supported\">\n <i class=\"fa-solid fa-check\"></i> Forward\n </span>\n }\n @if (card.Entity.SupportsReplying) {\n <span class=\"capability-chip supported\">\n <i class=\"fa-solid fa-check\"></i> Reply\n </span>\n }\n </div>\n <div class=\"provider-card-stats\">\n <div class=\"provider-stat\">\n <div class=\"provider-stat-value\">{{card.SentCount}}</div>\n <div class=\"provider-stat-label\">Sent (24h)</div>\n </div>\n <div class=\"provider-stat\">\n <div class=\"provider-stat-value\">{{card.SuccessRate}}%</div>\n <div class=\"provider-stat-label\">Success</div>\n </div>\n <div class=\"provider-stat\">\n <div class=\"provider-stat-value\">{{card.FailedCount}}</div>\n <div class=\"provider-stat-label\">Failed</div>\n </div>\n </div>\n </div>\n <div class=\"provider-card-footer\">\n <button (click)=\"configureProvider(card.Entity)\">\n <i class=\"fa-solid fa-gear\"></i> Configure\n </button>\n <button (click)=\"viewProviderLogs(card.Entity)\">\n <i class=\"fa-solid fa-chart-line\"></i> Analytics\n </button>\n </div>\n </div>\n }\n </div>\n }\n </div>\n `,\n styles: [`\n .providers-wrapper {\n height: 100%;\n padding: 24px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n }\n .providers-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 20px;\n }\n .providers-header h2 {\n margin: 0;\n font-size: 18px;\n font-weight: 800;\n color: var(--mj-text-primary);\n }\n .providers-header p {\n margin: 4px 0 0;\n font-size: 13px;\n color: var(--mj-text-muted);\n }\n\n .tb-btn {\n display: inline-flex; align-items: center;\n gap: 6px; padding: 8px 16px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n font-size: 12px; font-weight: 600;\n cursor: pointer; transition: all 0.15s ease;\n font-family: inherit;\n }\n .tb-btn.primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n }\n .tb-btn.primary:hover { background: var(--mj-brand-primary-hover); }\n\n .loading-state {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 80px 0;\n }\n\n /* GRID */\n .providers-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));\n gap: 16px;\n }\n .provider-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n transition: all 0.15s ease;\n }\n .provider-card:hover {\n box-shadow: 0 2px 8px var(--mj-shadow-md);\n border-color: var(--mj-border-strong);\n }\n .provider-card.disabled { opacity: 0.65; }\n\n .provider-card-header {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 20px 20px 16px;\n }\n .provider-card-logo {\n width: 48px; height: 48px;\n border-radius: 12px;\n display: flex; align-items: center; justify-content: center;\n font-size: 22px; flex-shrink: 0;\n background: var(--mj-bg-surface-sunken);\n }\n .provider-card-logo.sendgrid {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n .provider-card-logo.twilio {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n .provider-card-logo.gmail {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n .provider-card-logo.msgraph {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n .provider-card-title { flex: 1; min-width: 0; }\n .provider-card-name {\n font-size: 15px; font-weight: 700;\n color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .provider-card-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n }\n .provider-card-status {\n font-size: 10px; font-weight: 700;\n text-transform: uppercase; letter-spacing: 0.5px;\n padding: 3px 10px; border-radius: 10px;\n flex-shrink: 0;\n }\n .provider-card-status.active {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n .provider-card-status.disabled {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n }\n\n .provider-card-body { padding: 0 20px 16px; }\n\n .provider-capabilities {\n display: flex; flex-wrap: wrap;\n gap: 6px; margin-bottom: 16px;\n }\n .capability-chip {\n display: inline-flex; align-items: center;\n gap: 4px; padding: 4px 10px;\n border-radius: 12px; font-size: 11px; font-weight: 500;\n }\n .capability-chip.supported {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n .capability-chip.unsupported {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n text-decoration: line-through;\n }\n\n .provider-card-stats {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 12px; padding: 12px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n }\n .provider-stat { text-align: center; }\n .provider-stat-value {\n font-size: 16px; font-weight: 800;\n color: var(--mj-text-primary);\n }\n .provider-stat-label {\n font-size: 10px;\n color: var(--mj-text-muted);\n text-transform: uppercase; letter-spacing: 0.3px;\n }\n\n .provider-card-footer {\n display: flex;\n border-top: 1px solid var(--mj-border-default);\n }\n .provider-card-footer button {\n flex: 1; padding: 12px;\n border: none; background: transparent;\n font-size: 12px; font-weight: 600;\n color: var(--mj-brand-primary);\n cursor: pointer; transition: background 0.15s;\n font-family: inherit;\n display: flex; align-items: center;\n justify-content: center; gap: 6px;\n }\n .provider-card-footer button:hover {\n background: var(--mj-bg-surface-sunken);\n }\n .provider-card-footer button + button {\n border-left: 1px solid var(--mj-border-default);\n }\n `]\n})\nexport class CommunicationProvidersResourceComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n public isLoading = false;\n public providerCards: ProviderCardData[] = [];\n\n constructor(private cdr: ChangeDetectorRef, private navService: NavigationService) {\n super();\n }\n\n async ngOnInit(): Promise<void> {\n super.ngOnInit();\n await this.loadData();\n this.NotifyLoadComplete();\n }\n\n ngOnDestroy(): void {\n super.ngOnDestroy();\n }\n\n public async loadData(): Promise<void> {\n try {\n this.isLoading = true;\n this.cdr.detectChanges();\n\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const yesterday = new Date();\n yesterday.setDate(yesterday.getDate() - 1);\n const yesterdayIso = yesterday.toISOString();\n\n const [providersResult, logsResult] = await Promise.all([\n rv.RunView<MJCommunicationProviderEntity>({\n EntityName: 'MJ: Communication Providers',\n OrderBy: 'Name ASC',\n ResultType: 'entity_object'\n }),\n rv.RunView<MJCommunicationLogEntity>({\n EntityName: 'MJ: Communication Logs',\n ExtraFilter: `MessageDate >= '${yesterdayIso}'`,\n ResultType: 'entity_object'\n })\n ]);\n\n if (providersResult.Success) {\n const logs = logsResult.Success ? logsResult.Results : [];\n this.providerCards = providersResult.Results.map(p => this.buildProviderCard(p, logs));\n }\n } catch (error) {\n console.error('Error loading providers:', error);\n } finally {\n this.isLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n private buildProviderCard(provider: MJCommunicationProviderEntity, logs: MJCommunicationLogEntity[]): ProviderCardData {\n const providerLogs = logs.filter(l => l.CommunicationProvider === provider.Name);\n const sent = providerLogs.length;\n const failed = providerLogs.filter(l => l.Status === 'Failed').length;\n const rate = sent > 0 ? parseFloat(((sent - failed) / sent * 100).toFixed(1)) : 100;\n\n return {\n Entity: provider,\n SentCount: sent,\n SuccessRate: rate,\n FailedCount: failed,\n IconClass: this.getProviderIcon(provider.Name),\n LogoClass: this.getProviderLogoClass(provider.Name)\n };\n }\n\n private getProviderIcon(name: string): string {\n const n = name.toLowerCase();\n if (n.includes('sendgrid')) return 'fa-solid fa-envelope';\n if (n.includes('twilio')) return 'fa-solid fa-comment-sms';\n if (n.includes('gmail') || n.includes('google')) return 'fa-brands fa-google';\n if (n.includes('microsoft') || n.includes('graph') || n.includes('outlook')) return 'fa-brands fa-microsoft';\n if (n.includes('aws') || n.includes('ses')) return 'fa-brands fa-aws';\n if (n.includes('slack')) return 'fa-brands fa-slack';\n return 'fa-solid fa-server';\n }\n\n private getProviderLogoClass(name: string): string {\n const n = name.toLowerCase();\n if (n.includes('sendgrid')) return 'sendgrid';\n if (n.includes('twilio')) return 'twilio';\n if (n.includes('gmail') || n.includes('google')) return 'gmail';\n if (n.includes('microsoft') || n.includes('graph') || n.includes('outlook')) return 'msgraph';\n return '';\n }\n\n public configureProvider(provider: MJCommunicationProviderEntity): void {\n const pk = new CompositeKey();\n pk.LoadFromEntityInfoAndRecord(this.ProviderToUse.Entities.find(e => e.Name === 'MJ: Communication Providers')!, provider);\n this.navService.OpenEntityRecord('MJ: Communication Providers', pk);\n }\n\n public viewProviderLogs(provider: MJCommunicationProviderEntity): void {\n console.log('View analytics for provider:', provider.Name);\n }\n\n public addNewProvider(): void {\n this.navService.OpenEntityRecord('MJ: Communication Providers', new CompositeKey());\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n return 'Providers';\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-server';\n }\n}\n"]}
|
|
@@ -104,7 +104,7 @@ let CommunicationRunsResourceComponent = class CommunicationRunsResourceComponen
|
|
|
104
104
|
try {
|
|
105
105
|
this.isLoading = true;
|
|
106
106
|
this.cdr.detectChanges();
|
|
107
|
-
const rv =
|
|
107
|
+
const rv = RunView.FromMetadataProvider(this.ProviderToUse);
|
|
108
108
|
const yesterday = new Date();
|
|
109
109
|
yesterday.setDate(yesterday.getDate() - 1);
|
|
110
110
|
const yesterdayIso = yesterday.toISOString();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"communication-runs-resource.component.js","sourceRoot":"","sources":["../../src/Communication/communication-runs-resource.component.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,SAAS,EAAwC,MAAM,eAAe,CAAC;AAEhF,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;;;;IAiDzB,4BAAM;IAAA,wBAA0C;IAAC,YAAkC;;IAAA,iBAAO;;;IAAzC,eAAkC;IAAlC,6EAAkC;;;IAIrF,+BAAgC;IAC9B,YACF;IAAA,iBAAM;;;IADJ,cACF;IADE,gDACF;;;IAnBN,+BAAuB;IACrB,0BAA2E;IAGvE,AADF,AADF,+BAA+B,cACC,eACE;IAAA,YAA+B;IAAA,iBAAO;IACpE,gCAAsE;IACpE,YACF;IACF,AADE,iBAAO,EACH;IAEJ,AADF,+BAA4B,WACpB;IAAA,yBAAgC;IAAC,aAAwB;IAAA,iBAAO;IACtE,6BAAM;IAAA,yBAAiC;IAAC,aAAiC;;IAAA,iBAAO;IAChF,2GAAmB;IAGrB,iBAAM;IACN,8GAAoB;IAMxB,AADE,iBAAM,EACF;;;;IArB0B,cAAsC;IAAtC,8DAAsC;IAGlC,eAA+B;IAA/B,yDAA+B;IAC9B,cAAsC;IAAtC,8DAAsC;IACnE,cACF;IADE,8CACF;IAGuC,eAAwB;IAAxB,mDAAwB;IACvB,eAAiC;IAAjC,6EAAiC;IACzE,eAEC;IAFD,0CAEC;IAEH,cAIC;IAJD,2CAIC;;;IAML,+BAAyB;IACvB,uBAAuC;IACvC,yBAAG;IAAA,2CAA2B;IAChC,AADgC,iBAAI,EAC9B;;AAiMb,IAAM,kCAAkC,GAAxC,MAAM,kCAAmC,SAAQ,qBAAqB;IASrD;IARb,IAAI,GAA+B,EAAE,CAAC;IACtC,SAAS,GAAG,KAAK,CAAC;IAClB,OAAO,GAAG;QACb,MAAM,EAAE,CAAC;QACT,SAAS,EAAE,CAAC;QACZ,WAAW,EAAE,CAAC;KACjB,CAAC;IAEF,YAAoB,GAAsB;QACtC,KAAK,EAAE,CAAC;QADQ,QAAG,GAAH,GAAG,CAAmB;IAE1C,CAAC;IAED,KAAK,CAAC,QAAQ;QACV,KAAK,CAAC,QAAQ,EAAE,CAAC;QACjB,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACtB,IAAI,CAAC,kBAAkB,EAAE,CAAC;IAC9B,CAAC;IAED,WAAW;QACP,KAAK,CAAC,WAAW,EAAE,CAAC;IACxB,CAAC;IAEM,KAAK,CAAC,QAAQ;QACjB,IAAI,CAAC;YACD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;YAEzB,MAAM,EAAE,GAAG,IAAI,OAAO,EAAE,CAAC;YACzB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;YAC7B,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;YAC3C,MAAM,YAAY,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;YAE7C,MAAM,CAAC,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,YAAY,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBAChF,EAAE,CAAC,OAAO,CAA2B;oBACjC,UAAU,EAAE,wBAAwB;oBACpC,OAAO,EAAE,gBAAgB;oBACzB,OAAO,EAAE,EAAE;oBACX,UAAU,EAAE,eAAe;iBAC9B,CAAC;gBACF,EAAE,CAAC,OAAO,CAAC;oBACP,UAAU,EAAE,wBAAwB;oBACpC,WAAW,EAAE,wBAAwB;oBACrC,UAAU,EAAE,YAAY;iBAC3B,CAAC;gBACF,EAAE,CAAC,OAAO,CAAC;oBACP,UAAU,EAAE,wBAAwB;oBACpC,WAAW,EAAE,eAAe,YAAY,2BAA2B;oBACnE,UAAU,EAAE,YAAY;iBAC3B,CAAC;gBACF,EAAE,CAAC,OAAO,CAAC;oBACP,UAAU,EAAE,wBAAwB;oBACpC,WAAW,EAAE,eAAe,YAAY,yBAAyB;oBACjE,UAAU,EAAE,YAAY;iBAC3B,CAAC;aACL,CAAC,CAAC;YAEH,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;gBACrB,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC;YACnC,CAAC;YAED,IAAI,YAAY,CAAC,OAAO;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,YAAY,CAAC,aAAa,CAAC;YAC3E,IAAI,eAAe,CAAC,OAAO;gBAAE,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,eAAe,CAAC,aAAa,CAAC;YAEpF,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACxG,IAAI,CAAC,OAAO,CAAC,WAAW,GAAG,cAAc,GAAG,CAAC;gBACzC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,cAAc,CAAC,GAAG,GAAG,CAAC;gBAC7D,CAAC,CAAC,GAAG,CAAC;QAEd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;QAChD,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACvB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAC7B,CAAC;IACL,CAAC;IAEM,cAAc,CAAC,MAAc;QAChC,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QACvC,IAAI,CAAC,KAAK,UAAU;YAAE,OAAO,UAAU,CAAC;QACxC,IAAI,CAAC,KAAK,QAAQ;YAAE,OAAO,QAAQ,CAAC;QACpC,IAAI,CAAC,KAAK,aAAa;YAAE,OAAO,aAAa,CAAC;QAC9C,OAAO,SAAS,CAAC;IACrB,CAAC;IAEM,cAAc,CAAC,MAAc;QAChC,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QACvC,IAAI,CAAC,KAAK,UAAU;YAAE,OAAO,UAAU,CAAC;QACxC,IAAI,CAAC,KAAK,QAAQ;YAAE,OAAO,QAAQ,CAAC;QACpC,IAAI,CAAC,KAAK,aAAa;YAAE,OAAO,aAAa,CAAC;QAC9C,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,sBAAsB,CAAC,IAAkB;QAC3C,OAAO,WAAW,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,IAAkB;QACzC,OAAO,yBAAyB,CAAC;IACrC,CAAC;4HAnGQ,kCAAkC;6DAAlC,kCAAkC;YAzPrC,AADF,AADF,AADF,8BAA0B,aACN,aACS,SACnB;YAAA,uBAAuC;YAAC,wCAAuB;YAAA,iBAAK;YAEtE,AADF,8BAA4B,gBACkB;YAArB,+GAAS,cAAU,IAAC;YACzC,uBAA+D;YAAC,yBAClE;YAEJ,AADE,AADE,iBAAS,EACL,EACF;YAKA,AADF,AADF,AAFF,+BAAkC,cAEN,cACQ,eACF;YAAA,aAAkB;YAAA,iBAAM;YACpD,gCAA4B;YAAA,4BAAW;YACzC,AADyC,iBAAM,EACzC;YAEJ,AADF,gCAAmC,eACL;YAAA,aAAqB;YAAA,iBAAM;YACvD,gCAA4B;YAAA,gCAAe;YAC7C,AAD6C,iBAAM,EAC7C;YAEJ,AADF,gCAAmC,eACL;YAAA,aAAwB;YAAA,iBAAM;YAC1D,gCAA4B;YAAA,6BAAY;YAE5C,AADE,AAD0C,iBAAM,EAC1C,EACF;YAGN,gCAA0B;YACxB,4HAwBC;YAED,uGAAuC;YAS/C,AADE,AADE,AADE,iBAAM,EACF,EACF,EACF;;YA1DkC,eAA4B;YAA5B,yCAA4B;YAQ9B,eAAkB;YAAlB,wCAAkB;YAIlB,eAAqB;YAArB,2CAAqB;YAIrB,eAAwB;YAAxB,uDAAwB;YAOtD,eAwBC;YAxBD,uBAwBC;YAED,eAKC;YALD,mEAKC;;;AAgMA,kCAAkC;IAjQ9C,aAAa,CAAC,qBAAqB,EAAE,2BAA2B,CAAC;GAiQrD,kCAAkC,CAoG9C;;iFApGY,kCAAkC;cAhQ9C,SAAS;6BACI,KAAK,YACL,gCAAgC,YAChC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAkET;;kFA2LQ,kCAAkC","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';\nimport { ResourceData, MJCommunicationRunEntity } from '@memberjunction/core-entities';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { RunView } from '@memberjunction/core';\n@RegisterClass(BaseResourceComponent, 'CommunicationRunsResource')\n@Component({\n standalone: false,\n selector: 'mj-communication-runs-resource',\n template: `\n <div class=\"runs-wrapper\">\n <div class=\"card\">\n <div class=\"card-header\">\n <h3><i class=\"fa-solid fa-play-circle\"></i> Bulk Communication Runs</h3>\n <div class=\"header-actions\">\n <button class=\"tb-btn\" (click)=\"loadData()\">\n <i class=\"fa-solid fa-rotate\" [class.spinning]=\"isLoading\"></i> Refresh\n </button>\n </div>\n </div>\n <div class=\"card-body no-padding\">\n <!-- SUMMARY STATS -->\n <div class=\"runs-summary\">\n <div class=\"run-stat-card info\">\n <div class=\"run-stat-value\">{{summary.active}}</div>\n <div class=\"run-stat-label\">Active Runs</div>\n </div>\n <div class=\"run-stat-card success\">\n <div class=\"run-stat-value\">{{summary.completed}}</div>\n <div class=\"run-stat-label\">Completed (24h)</div>\n </div>\n <div class=\"run-stat-card neutral\">\n <div class=\"run-stat-value\">{{summary.successRate}}%</div>\n <div class=\"run-stat-label\">Success Rate</div>\n </div>\n </div>\n \n <!-- TIMELINE -->\n <div class=\"run-timeline\">\n @for (run of runs; track run) {\n <div class=\"run-entry\">\n <div class=\"run-timeline-dot\" [ngClass]=\"getRunDotClass(run.Status)\"></div>\n <div class=\"run-entry-content\">\n <div class=\"run-entry-header\">\n <span class=\"run-entry-title\">Run #{{run.ID.substring(0, 8)}}</span>\n <span class=\"run-status-badge\" [ngClass]=\"getStatusClass(run.Status)\">\n {{run.Status}}\n </span>\n </div>\n <div class=\"run-entry-meta\">\n <span><i class=\"fa-solid fa-user\"></i> {{run.User || 'System'}}</span>\n <span><i class=\"fa-solid fa-clock\"></i> {{run.StartedAt | date:'medium'}}</span>\n @if (run.EndedAt) {\n <span><i class=\"fa-solid fa-flag-checkered\"></i> {{run.EndedAt | date:'shortTime'}}</span>\n }\n </div>\n @if (run.Comments) {\n <div class=\"run-entry-comments\">\n {{run.Comments}}\n </div>\n }\n </div>\n </div>\n }\n \n @if (runs.length === 0 && !isLoading) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-play-circle\"></i>\n <p>No communication runs found</p>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n `,\n styles: [`\n .runs-wrapper {\n height: 100%;\n padding: 24px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n }\n .card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n }\n .card-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n }\n .card-header h3 {\n font-size: 13px; font-weight: 700;\n color: var(--mj-text-primary);\n display: flex; align-items: center; gap: 8px;\n margin: 0;\n }\n .card-header h3 i {\n color: var(--mj-text-muted); font-size: 12px;\n }\n .header-actions { display: flex; gap: 8px; }\n\n .tb-btn {\n display: inline-flex; align-items: center;\n gap: 6px; padding: 6px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n font-size: 12px; font-weight: 500;\n cursor: pointer; transition: all 0.15s ease;\n font-family: inherit;\n }\n .tb-btn:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-primary);\n }\n .tb-btn i { font-size: 12px; }\n\n @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }\n .spinning { animation: spin 1s linear infinite; }\n\n .card-body.no-padding { padding: 0; }\n\n /* SUMMARY */\n .runs-summary {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n padding: 20px;\n }\n .run-stat-card {\n border-radius: 12px;\n padding: 16px 20px;\n text-align: center;\n }\n .run-stat-card.info {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n }\n .run-stat-card.success {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n }\n .run-stat-card.neutral {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n }\n\n .run-stat-value {\n font-size: 24px; font-weight: 800;\n color: var(--mj-text-primary);\n }\n .run-stat-card.info .run-stat-value { color: var(--mj-brand-primary); }\n .run-stat-card.success .run-stat-value { color: var(--mj-status-success); }\n\n .run-stat-label {\n font-size: 11px; font-weight: 600;\n text-transform: uppercase; letter-spacing: 0.5px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n }\n\n /* TIMELINE */\n .run-timeline { padding: 8px 20px 20px; }\n .run-entry {\n display: flex; gap: 16px;\n padding: 16px 0;\n border-bottom: 1px solid var(--mj-border-default);\n align-items: flex-start;\n }\n .run-entry:last-child { border-bottom: none; }\n\n .run-timeline-dot {\n width: 12px; height: 12px;\n border-radius: 50%;\n margin-top: 4px; flex-shrink: 0;\n }\n .run-timeline-dot.complete { background: var(--mj-status-success); }\n .run-timeline-dot.failed { background: var(--mj-status-error); }\n .run-timeline-dot.in-progress {\n background: var(--mj-brand-primary);\n animation: pulse-dot 1.5s ease-in-out infinite;\n }\n .run-timeline-dot.pending { background: var(--mj-status-warning); }\n\n @keyframes pulse-dot {\n 0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--mj-brand-primary) 40%, transparent); }\n 50% { box-shadow: 0 0 0 6px transparent; }\n }\n\n .run-entry-content { flex: 1; }\n .run-entry-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .run-entry-title {\n font-size: 13px; font-weight: 600;\n color: var(--mj-text-primary);\n }\n .run-status-badge {\n font-size: 10px; font-weight: 700;\n text-transform: uppercase; letter-spacing: 0.3px;\n padding: 3px 8px;\n border-radius: 4px;\n }\n .run-status-badge.complete {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n border: 1px solid color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n }\n .run-status-badge.failed {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 30%, transparent);\n }\n .run-status-badge.pending {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 30%, transparent);\n }\n .run-status-badge.in-progress {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n }\n\n .run-entry-meta {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-top: 4px;\n display: flex; align-items: center; gap: 12px;\n }\n .run-entry-meta span {\n display: flex; align-items: center; gap: 4px;\n }\n .run-entry-meta i { font-size: 10px; }\n\n .run-entry-comments {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 6px;\n font-style: italic;\n }\n\n /* EMPTY STATE */\n .empty-state {\n display: flex; flex-direction: column;\n align-items: center; justify-content: center;\n padding: 48px 0; color: var(--mj-text-muted);\n }\n .empty-state i { font-size: 2rem; margin-bottom: 12px; opacity: 0.5; }\n .empty-state p { margin: 0; font-size: 13px; }\n `]\n})\nexport class CommunicationRunsResourceComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n public runs: MJCommunicationRunEntity[] = [];\n public isLoading = false;\n public summary = {\n active: 0,\n completed: 0,\n successRate: 0\n };\n\n constructor(private cdr: ChangeDetectorRef) {\n super();\n }\n\n async ngOnInit(): Promise<void> {\n super.ngOnInit();\n await this.loadData();\n this.NotifyLoadComplete();\n }\n\n ngOnDestroy(): void {\n super.ngOnDestroy();\n }\n\n public async loadData(): Promise<void> {\n try {\n this.isLoading = true;\n this.cdr.detectChanges();\n\n const rv = new RunView();\n const yesterday = new Date();\n yesterday.setDate(yesterday.getDate() - 1);\n const yesterdayIso = yesterday.toISOString();\n\n const [runsResult, activeResult, completedResult, failedResult] = await Promise.all([\n rv.RunView<MJCommunicationRunEntity>({\n EntityName: 'MJ: Communication Runs',\n OrderBy: 'StartedAt DESC',\n MaxRows: 50,\n ResultType: 'entity_object'\n }),\n rv.RunView({\n EntityName: 'MJ: Communication Runs',\n ExtraFilter: `Status = 'In-Progress'`,\n ResultType: 'count_only'\n }),\n rv.RunView({\n EntityName: 'MJ: Communication Runs',\n ExtraFilter: `EndedAt >= '${yesterdayIso}' AND Status = 'Complete'`,\n ResultType: 'count_only'\n }),\n rv.RunView({\n EntityName: 'MJ: Communication Runs',\n ExtraFilter: `EndedAt >= '${yesterdayIso}' AND Status = 'Failed'`,\n ResultType: 'count_only'\n })\n ]);\n\n if (runsResult.Success) {\n this.runs = runsResult.Results;\n }\n\n if (activeResult.Success) this.summary.active = activeResult.TotalRowCount;\n if (completedResult.Success) this.summary.completed = completedResult.TotalRowCount;\n\n const totalCompleted = this.summary.completed + (failedResult.Success ? failedResult.TotalRowCount : 0);\n this.summary.successRate = totalCompleted > 0\n ? Math.round((this.summary.completed / totalCompleted) * 100)\n : 100;\n\n } catch (error) {\n console.error('Error loading runs:', error);\n } finally {\n this.isLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n public getRunDotClass(status: string): string {\n const s = (status || '').toLowerCase();\n if (s === 'complete') return 'complete';\n if (s === 'failed') return 'failed';\n if (s === 'in-progress') return 'in-progress';\n return 'pending';\n }\n\n public getStatusClass(status: string): string {\n const s = (status || '').toLowerCase();\n if (s === 'complete') return 'complete';\n if (s === 'failed') return 'failed';\n if (s === 'in-progress') return 'in-progress';\n return 'pending';\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n return 'Bulk Runs';\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-play-circle';\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"communication-runs-resource.component.js","sourceRoot":"","sources":["../../src/Communication/communication-runs-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';\nimport { ResourceData, MJCommunicationRunEntity } from '@memberjunction/core-entities';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { RunView } from '@memberjunction/core';\n@RegisterClass(BaseResourceComponent, 'CommunicationRunsResource')\n@Component({\n standalone: false,\n selector: 'mj-communication-runs-resource',\n template: `\n <div class=\"runs-wrapper\">\n <div class=\"card\">\n <div class=\"card-header\">\n <h3><i class=\"fa-solid fa-play-circle\"></i> Bulk Communication Runs</h3>\n <div class=\"header-actions\">\n <button class=\"tb-btn\" (click)=\"loadData()\">\n <i class=\"fa-solid fa-rotate\" [class.spinning]=\"isLoading\"></i> Refresh\n </button>\n </div>\n </div>\n <div class=\"card-body no-padding\">\n <!-- SUMMARY STATS -->\n <div class=\"runs-summary\">\n <div class=\"run-stat-card info\">\n <div class=\"run-stat-value\">{{summary.active}}</div>\n <div class=\"run-stat-label\">Active Runs</div>\n </div>\n <div class=\"run-stat-card success\">\n <div class=\"run-stat-value\">{{summary.completed}}</div>\n <div class=\"run-stat-label\">Completed (24h)</div>\n </div>\n <div class=\"run-stat-card neutral\">\n <div class=\"run-stat-value\">{{summary.successRate}}%</div>\n <div class=\"run-stat-label\">Success Rate</div>\n </div>\n </div>\n \n <!-- TIMELINE -->\n <div class=\"run-timeline\">\n @for (run of runs; track run) {\n <div class=\"run-entry\">\n <div class=\"run-timeline-dot\" [ngClass]=\"getRunDotClass(run.Status)\"></div>\n <div class=\"run-entry-content\">\n <div class=\"run-entry-header\">\n <span class=\"run-entry-title\">Run #{{run.ID.substring(0, 8)}}</span>\n <span class=\"run-status-badge\" [ngClass]=\"getStatusClass(run.Status)\">\n {{run.Status}}\n </span>\n </div>\n <div class=\"run-entry-meta\">\n <span><i class=\"fa-solid fa-user\"></i> {{run.User || 'System'}}</span>\n <span><i class=\"fa-solid fa-clock\"></i> {{run.StartedAt | date:'medium'}}</span>\n @if (run.EndedAt) {\n <span><i class=\"fa-solid fa-flag-checkered\"></i> {{run.EndedAt | date:'shortTime'}}</span>\n }\n </div>\n @if (run.Comments) {\n <div class=\"run-entry-comments\">\n {{run.Comments}}\n </div>\n }\n </div>\n </div>\n }\n \n @if (runs.length === 0 && !isLoading) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-play-circle\"></i>\n <p>No communication runs found</p>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n `,\n styles: [`\n .runs-wrapper {\n height: 100%;\n padding: 24px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n }\n .card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n }\n .card-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n }\n .card-header h3 {\n font-size: 13px; font-weight: 700;\n color: var(--mj-text-primary);\n display: flex; align-items: center; gap: 8px;\n margin: 0;\n }\n .card-header h3 i {\n color: var(--mj-text-muted); font-size: 12px;\n }\n .header-actions { display: flex; gap: 8px; }\n\n .tb-btn {\n display: inline-flex; align-items: center;\n gap: 6px; padding: 6px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n font-size: 12px; font-weight: 500;\n cursor: pointer; transition: all 0.15s ease;\n font-family: inherit;\n }\n .tb-btn:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-primary);\n }\n .tb-btn i { font-size: 12px; }\n\n @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }\n .spinning { animation: spin 1s linear infinite; }\n\n .card-body.no-padding { padding: 0; }\n\n /* SUMMARY */\n .runs-summary {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n padding: 20px;\n }\n .run-stat-card {\n border-radius: 12px;\n padding: 16px 20px;\n text-align: center;\n }\n .run-stat-card.info {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n }\n .run-stat-card.success {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n }\n .run-stat-card.neutral {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n }\n\n .run-stat-value {\n font-size: 24px; font-weight: 800;\n color: var(--mj-text-primary);\n }\n .run-stat-card.info .run-stat-value { color: var(--mj-brand-primary); }\n .run-stat-card.success .run-stat-value { color: var(--mj-status-success); }\n\n .run-stat-label {\n font-size: 11px; font-weight: 600;\n text-transform: uppercase; letter-spacing: 0.5px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n }\n\n /* TIMELINE */\n .run-timeline { padding: 8px 20px 20px; }\n .run-entry {\n display: flex; gap: 16px;\n padding: 16px 0;\n border-bottom: 1px solid var(--mj-border-default);\n align-items: flex-start;\n }\n .run-entry:last-child { border-bottom: none; }\n\n .run-timeline-dot {\n width: 12px; height: 12px;\n border-radius: 50%;\n margin-top: 4px; flex-shrink: 0;\n }\n .run-timeline-dot.complete { background: var(--mj-status-success); }\n .run-timeline-dot.failed { background: var(--mj-status-error); }\n .run-timeline-dot.in-progress {\n background: var(--mj-brand-primary);\n animation: pulse-dot 1.5s ease-in-out infinite;\n }\n .run-timeline-dot.pending { background: var(--mj-status-warning); }\n\n @keyframes pulse-dot {\n 0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--mj-brand-primary) 40%, transparent); }\n 50% { box-shadow: 0 0 0 6px transparent; }\n }\n\n .run-entry-content { flex: 1; }\n .run-entry-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .run-entry-title {\n font-size: 13px; font-weight: 600;\n color: var(--mj-text-primary);\n }\n .run-status-badge {\n font-size: 10px; font-weight: 700;\n text-transform: uppercase; letter-spacing: 0.3px;\n padding: 3px 8px;\n border-radius: 4px;\n }\n .run-status-badge.complete {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n border: 1px solid color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n }\n .run-status-badge.failed {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 30%, transparent);\n }\n .run-status-badge.pending {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 30%, transparent);\n }\n .run-status-badge.in-progress {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n }\n\n .run-entry-meta {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-top: 4px;\n display: flex; align-items: center; gap: 12px;\n }\n .run-entry-meta span {\n display: flex; align-items: center; gap: 4px;\n }\n .run-entry-meta i { font-size: 10px; }\n\n .run-entry-comments {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 6px;\n font-style: italic;\n }\n\n /* EMPTY STATE */\n .empty-state {\n display: flex; flex-direction: column;\n align-items: center; justify-content: center;\n padding: 48px 0; color: var(--mj-text-muted);\n }\n .empty-state i { font-size: 2rem; margin-bottom: 12px; opacity: 0.5; }\n .empty-state p { margin: 0; font-size: 13px; }\n `]\n})\nexport class CommunicationRunsResourceComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n public runs: MJCommunicationRunEntity[] = [];\n public isLoading = false;\n public summary = {\n active: 0,\n completed: 0,\n successRate: 0\n };\n\n constructor(private cdr: ChangeDetectorRef) {\n super();\n }\n\n async ngOnInit(): Promise<void> {\n super.ngOnInit();\n await this.loadData();\n this.NotifyLoadComplete();\n }\n\n ngOnDestroy(): void {\n super.ngOnDestroy();\n }\n\n public async loadData(): Promise<void> {\n try {\n this.isLoading = true;\n this.cdr.detectChanges();\n\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const yesterday = new Date();\n yesterday.setDate(yesterday.getDate() - 1);\n const yesterdayIso = yesterday.toISOString();\n\n const [runsResult, activeResult, completedResult, failedResult] = await Promise.all([\n rv.RunView<MJCommunicationRunEntity>({\n EntityName: 'MJ: Communication Runs',\n OrderBy: 'StartedAt DESC',\n MaxRows: 50,\n ResultType: 'entity_object'\n }),\n rv.RunView({\n EntityName: 'MJ: Communication Runs',\n ExtraFilter: `Status = 'In-Progress'`,\n ResultType: 'count_only'\n }),\n rv.RunView({\n EntityName: 'MJ: Communication Runs',\n ExtraFilter: `EndedAt >= '${yesterdayIso}' AND Status = 'Complete'`,\n ResultType: 'count_only'\n }),\n rv.RunView({\n EntityName: 'MJ: Communication Runs',\n ExtraFilter: `EndedAt >= '${yesterdayIso}' AND Status = 'Failed'`,\n ResultType: 'count_only'\n })\n ]);\n\n if (runsResult.Success) {\n this.runs = runsResult.Results;\n }\n\n if (activeResult.Success) this.summary.active = activeResult.TotalRowCount;\n if (completedResult.Success) this.summary.completed = completedResult.TotalRowCount;\n\n const totalCompleted = this.summary.completed + (failedResult.Success ? failedResult.TotalRowCount : 0);\n this.summary.successRate = totalCompleted > 0\n ? Math.round((this.summary.completed / totalCompleted) * 100)\n : 100;\n\n } catch (error) {\n console.error('Error loading runs:', error);\n } finally {\n this.isLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n public getRunDotClass(status: string): string {\n const s = (status || '').toLowerCase();\n if (s === 'complete') return 'complete';\n if (s === 'failed') return 'failed';\n if (s === 'in-progress') return 'in-progress';\n return 'pending';\n }\n\n public getStatusClass(status: string): string {\n const s = (status || '').toLowerCase();\n if (s === 'complete') return 'complete';\n if (s === 'failed') return 'failed';\n if (s === 'in-progress') return 'in-progress';\n return 'pending';\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n return 'Bulk Runs';\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-play-circle';\n }\n}\n"]}
|
|
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { Component } from '@angular/core';
|
|
8
8
|
import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
|
|
9
9
|
import { BaseResourceComponent } from '@memberjunction/ng-shared';
|
|
10
|
-
import {
|
|
10
|
+
import { RunView, CompositeKey } from '@memberjunction/core';
|
|
11
11
|
import * as i0 from "@angular/core";
|
|
12
12
|
import * as i1 from "@memberjunction/ng-shared";
|
|
13
13
|
import * as i2 from "@memberjunction/ng-shared-generic";
|
|
@@ -164,7 +164,7 @@ let CommunicationTemplatesResourceComponent = class CommunicationTemplatesResour
|
|
|
164
164
|
try {
|
|
165
165
|
this.isLoading = true;
|
|
166
166
|
this.cdr.detectChanges();
|
|
167
|
-
const rv =
|
|
167
|
+
const rv = RunView.FromMetadataProvider(this.ProviderToUse);
|
|
168
168
|
const [templatesResult, contentsResult] = await Promise.all([
|
|
169
169
|
rv.RunView({
|
|
170
170
|
EntityName: 'MJ: Templates',
|
|
@@ -233,7 +233,7 @@ let CommunicationTemplatesResourceComponent = class CommunicationTemplatesResour
|
|
|
233
233
|
}
|
|
234
234
|
openTemplate(template) {
|
|
235
235
|
const pk = new CompositeKey();
|
|
236
|
-
pk.LoadFromEntityInfoAndRecord(
|
|
236
|
+
pk.LoadFromEntityInfoAndRecord(this.ProviderToUse.Entities.find(e => e.Name === 'MJ: Templates'), template);
|
|
237
237
|
this.navService.OpenEntityRecord('MJ: Templates', pk);
|
|
238
238
|
}
|
|
239
239
|
addNewTemplate() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"communication-templates-resource.component.js","sourceRoot":"","sources":["../../src/Communication/communication-templates-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';\nimport { ResourceData, MJTemplateEntity, MJTemplateContentEntity } from '@memberjunction/core-entities';\nimport { RegisterClass , UUIDsEqual } from '@memberjunction/global';\nimport { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';\nimport { Metadata, RunView, CompositeKey } from '@memberjunction/core';\n\ninterface TemplateCardData {\n Entity: MJTemplateEntity;\n ContentTypes: string[];\n LastUpdated: Date | null;\n CategoryName: string;\n}\n@RegisterClass(BaseResourceComponent, 'CommunicationTemplatesResource')\n@Component({\n standalone: false,\n selector: 'mj-communication-templates-resource',\n template: `\n <div class=\"templates-wrapper\">\n <!-- HEADER -->\n <div class=\"templates-header\">\n <div>\n <h2>Communication Templates</h2>\n <p>Manage reusable message templates</p>\n </div>\n <div class=\"header-actions\">\n <div class=\"search-input-wrapper\">\n <i class=\"fa-solid fa-search\"></i>\n <input type=\"text\" placeholder=\"Search templates...\" (input)=\"onSearch($event)\">\n </div>\n <button class=\"tb-btn primary\" (click)=\"addNewTemplate()\">\n <i class=\"fa-solid fa-plus\"></i> New Template\n </button>\n </div>\n </div>\n \n <!-- LOADING -->\n @if (isLoading) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading templates...\"></mj-loading>\n </div>\n }\n \n <!-- CATEGORY FILTERS -->\n @if (!isLoading) {\n <div class=\"category-filters\">\n <div class=\"filter-chip\" [class.active]=\"categoryFilter === ''\"\n (click)=\"onCategoryFilter('')\">\n All ({{allTemplates.length}})\n </div>\n @for (cat of categories; track cat) {\n <div class=\"filter-chip\"\n [class.active]=\"categoryFilter === cat\"\n (click)=\"onCategoryFilter(cat)\">\n {{cat}} ({{getCategoryCount(cat)}})\n </div>\n }\n </div>\n }\n \n <!-- TEMPLATES GRID -->\n @if (!isLoading) {\n <div class=\"templates-grid\">\n @for (card of filteredTemplates; track card) {\n <div class=\"template-card\"\n (click)=\"openTemplate(card.Entity)\">\n <div class=\"template-card-header\">\n <div class=\"template-icon\">\n <i class=\"fa-solid fa-file-lines\"></i>\n </div>\n <div class=\"template-title-area\">\n <div class=\"template-name\">{{card.Entity.Name}}</div>\n <div class=\"template-category\">{{card.CategoryName}}</div>\n </div>\n </div>\n @if (card.Entity.Description) {\n <div class=\"template-description\">\n {{card.Entity.Description}}\n </div>\n }\n <div class=\"template-meta\">\n <div class=\"template-content-types\">\n @for (ct of card.ContentTypes; track ct) {\n <span class=\"content-type-chip\">\n <i [class]=\"getContentTypeIcon(ct)\"></i> {{ct}}\n </span>\n }\n @if (card.ContentTypes.length === 0) {\n <span class=\"content-type-chip empty\">\n No content\n </span>\n }\n </div>\n @if (card.LastUpdated) {\n <div class=\"template-updated\">\n Updated {{card.LastUpdated | date:'mediumDate'}}\n </div>\n }\n </div>\n </div>\n }\n @if (filteredTemplates.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-file-lines\"></i>\n <p>No templates found matching your criteria</p>\n </div>\n }\n </div>\n }\n </div>\n `,\n styles: [`\n .templates-wrapper {\n height: 100%;\n padding: 24px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n }\n\n /* HEADER */\n .templates-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 20px;\n }\n .templates-header h2 {\n margin: 0;\n font-size: 18px;\n font-weight: 800;\n color: var(--mj-text-primary);\n }\n .templates-header p {\n margin: 4px 0 0;\n font-size: 13px;\n color: var(--mj-text-muted);\n }\n .header-actions {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n .search-input-wrapper {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface-card);\n transition: border-color 0.15s, box-shadow 0.15s;\n min-width: 220px;\n }\n .search-input-wrapper:focus-within {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n }\n .search-input-wrapper i { color: var(--mj-text-muted); font-size: 12px; }\n .search-input-wrapper input {\n flex: 1; border: none; outline: none;\n background: transparent; font-size: 12px;\n font-family: inherit; color: var(--mj-text-primary);\n }\n .search-input-wrapper input::placeholder { color: var(--mj-text-muted); }\n\n .tb-btn {\n display: inline-flex; align-items: center;\n gap: 6px; padding: 8px 16px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-muted);\n font-size: 12px; font-weight: 600;\n cursor: pointer; transition: all 0.15s ease;\n font-family: inherit;\n }\n .tb-btn.primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n }\n .tb-btn.primary:hover { filter: brightness(1.1); }\n\n .loading-state {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 80px 0;\n }\n\n /* CATEGORY FILTERS */\n .category-filters {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n margin-bottom: 20px;\n }\n .filter-chip {\n display: inline-flex; align-items: center;\n gap: 4px; padding: 5px 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n background: var(--mj-bg-surface-card);\n font-size: 12px; font-weight: 500;\n color: var(--mj-text-muted);\n cursor: pointer; transition: all 0.15s;\n }\n .filter-chip:hover {\n border-color: var(--mj-border-strong);\n background: var(--mj-bg-surface);\n }\n .filter-chip.active {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n /* GRID */\n .templates-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));\n gap: 16px;\n }\n\n .template-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n .template-card:hover {\n box-shadow: 0 2px 8px var(--mj-shadow-md);\n border-color: var(--mj-border-strong);\n }\n\n .template-card-header {\n display: flex;\n align-items: center;\n gap: 14px;\n margin-bottom: 12px;\n }\n .template-icon {\n width: 40px; height: 40px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n display: flex; align-items: center; justify-content: center;\n font-size: 16px; flex-shrink: 0;\n }\n .template-title-area { flex: 1; min-width: 0; }\n .template-name {\n font-size: 14px; font-weight: 700;\n color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .template-category {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n }\n\n .template-description {\n font-size: 12px;\n color: var(--mj-text-muted);\n line-height: 1.5;\n margin-bottom: 12px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n .template-meta {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .template-content-types {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n }\n .content-type-chip {\n display: inline-flex; align-items: center;\n gap: 4px; padding: 3px 8px;\n border-radius: 10px; font-size: 10px; font-weight: 500;\n background: var(--mj-bg-surface);\n color: var(--mj-text-muted);\n }\n .content-type-chip.empty {\n font-style: italic;\n }\n .template-updated {\n font-size: 10px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n }\n\n /* EMPTY STATE */\n .empty-state {\n grid-column: 1 / -1;\n display: flex; flex-direction: column;\n align-items: center; justify-content: center;\n padding: 64px 0; color: var(--mj-text-muted);\n }\n .empty-state i { font-size: 2rem; margin-bottom: 12px; opacity: 0.5; }\n .empty-state p { margin: 0; font-size: 13px; }\n `]\n})\nexport class CommunicationTemplatesResourceComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n public allTemplates: TemplateCardData[] = [];\n public filteredTemplates: TemplateCardData[] = [];\n public categories: string[] = [];\n public categoryFilter = '';\n public isLoading = false;\n private searchTerm = '';\n\n constructor(private cdr: ChangeDetectorRef, private navService: NavigationService) {\n super();\n }\n\n async ngOnInit(): Promise<void> {\n super.ngOnInit();\n await this.loadData();\n this.NotifyLoadComplete();\n }\n\n ngOnDestroy(): void {\n super.ngOnDestroy();\n }\n\n public async loadData(): Promise<void> {\n try {\n this.isLoading = true;\n this.cdr.detectChanges();\n\n const rv = new RunView();\n const [templatesResult, contentsResult] = await Promise.all([\n rv.RunView<MJTemplateEntity>({\n EntityName: 'MJ: Templates',\n OrderBy: 'Name ASC',\n ResultType: 'entity_object'\n }),\n rv.RunView<MJTemplateContentEntity>({\n EntityName: 'MJ: Template Contents',\n ResultType: 'entity_object'\n })\n ]);\n\n if (templatesResult.Success) {\n const contents = contentsResult.Success ? contentsResult.Results : [];\n this.allTemplates = templatesResult.Results.map(t => this.buildTemplateCard(t, contents));\n this.categories = this.extractCategories(this.allTemplates);\n this.applyFilter();\n }\n } catch (error) {\n console.error('Error loading templates:', error);\n } finally {\n this.isLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n private buildTemplateCard(template: MJTemplateEntity, allContents: MJTemplateContentEntity[]): TemplateCardData {\n const templateContents = allContents.filter(c => UUIDsEqual(c.TemplateID, template.ID));\n const contentTypes = [...new Set(templateContents.map(c => c.TypeID ? 'Content' : 'Text'))];\n const category = template.Category || 'Uncategorized';\n const lastUpdated = template.Get('__mj_UpdatedAt') as Date | null;\n\n return {\n Entity: template,\n ContentTypes: contentTypes.length > 0 ? contentTypes : [],\n LastUpdated: lastUpdated,\n CategoryName: category\n };\n }\n\n private extractCategories(cards: TemplateCardData[]): string[] {\n const cats = new Set(cards.map(c => c.CategoryName));\n return Array.from(cats).sort();\n }\n\n public getCategoryCount(category: string): number {\n return this.allTemplates.filter(t => t.CategoryName === category).length;\n }\n\n public onSearch(event: Event): void {\n this.searchTerm = (event.target as HTMLInputElement).value.toLowerCase();\n this.applyFilter();\n }\n\n public onCategoryFilter(category: string): void {\n this.categoryFilter = category;\n this.applyFilter();\n }\n\n private applyFilter(): void {\n let filtered = this.allTemplates;\n\n if (this.categoryFilter) {\n filtered = filtered.filter(t => t.CategoryName === this.categoryFilter);\n }\n\n if (this.searchTerm) {\n filtered = filtered.filter(t =>\n t.Entity.Name?.toLowerCase().includes(this.searchTerm) ||\n t.Entity.Description?.toLowerCase().includes(this.searchTerm) ||\n t.CategoryName.toLowerCase().includes(this.searchTerm)\n );\n }\n\n this.filteredTemplates = filtered;\n this.cdr.detectChanges();\n }\n\n public openTemplate(template: MJTemplateEntity): void {\n const pk = new CompositeKey();\n pk.LoadFromEntityInfoAndRecord(new Metadata().Entities.find(e => e.Name === 'MJ: Templates')!, template);\n this.navService.OpenEntityRecord('MJ: Templates', pk);\n }\n\n public addNewTemplate(): void {\n this.navService.OpenEntityRecord('MJ: Templates', new CompositeKey());\n }\n\n public getContentTypeIcon(type: string): string {\n const t = type.toLowerCase();\n if (t.includes('html')) return 'fa-solid fa-code';\n if (t.includes('text') || t.includes('plain')) return 'fa-solid fa-align-left';\n if (t.includes('sms')) return 'fa-solid fa-comment-sms';\n return 'fa-solid fa-file';\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n return 'Templates';\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-file-lines';\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"communication-templates-resource.component.js","sourceRoot":"","sources":["../../src/Communication/communication-templates-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';\nimport { ResourceData, MJTemplateEntity, MJTemplateContentEntity } from '@memberjunction/core-entities';\nimport { RegisterClass , UUIDsEqual } from '@memberjunction/global';\nimport { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';\nimport { Metadata, RunView, CompositeKey } from '@memberjunction/core';\n\ninterface TemplateCardData {\n Entity: MJTemplateEntity;\n ContentTypes: string[];\n LastUpdated: Date | null;\n CategoryName: string;\n}\n@RegisterClass(BaseResourceComponent, 'CommunicationTemplatesResource')\n@Component({\n standalone: false,\n selector: 'mj-communication-templates-resource',\n template: `\n <div class=\"templates-wrapper\">\n <!-- HEADER -->\n <div class=\"templates-header\">\n <div>\n <h2>Communication Templates</h2>\n <p>Manage reusable message templates</p>\n </div>\n <div class=\"header-actions\">\n <div class=\"search-input-wrapper\">\n <i class=\"fa-solid fa-search\"></i>\n <input type=\"text\" placeholder=\"Search templates...\" (input)=\"onSearch($event)\">\n </div>\n <button class=\"tb-btn primary\" (click)=\"addNewTemplate()\">\n <i class=\"fa-solid fa-plus\"></i> New Template\n </button>\n </div>\n </div>\n \n <!-- LOADING -->\n @if (isLoading) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading templates...\"></mj-loading>\n </div>\n }\n \n <!-- CATEGORY FILTERS -->\n @if (!isLoading) {\n <div class=\"category-filters\">\n <div class=\"filter-chip\" [class.active]=\"categoryFilter === ''\"\n (click)=\"onCategoryFilter('')\">\n All ({{allTemplates.length}})\n </div>\n @for (cat of categories; track cat) {\n <div class=\"filter-chip\"\n [class.active]=\"categoryFilter === cat\"\n (click)=\"onCategoryFilter(cat)\">\n {{cat}} ({{getCategoryCount(cat)}})\n </div>\n }\n </div>\n }\n \n <!-- TEMPLATES GRID -->\n @if (!isLoading) {\n <div class=\"templates-grid\">\n @for (card of filteredTemplates; track card) {\n <div class=\"template-card\"\n (click)=\"openTemplate(card.Entity)\">\n <div class=\"template-card-header\">\n <div class=\"template-icon\">\n <i class=\"fa-solid fa-file-lines\"></i>\n </div>\n <div class=\"template-title-area\">\n <div class=\"template-name\">{{card.Entity.Name}}</div>\n <div class=\"template-category\">{{card.CategoryName}}</div>\n </div>\n </div>\n @if (card.Entity.Description) {\n <div class=\"template-description\">\n {{card.Entity.Description}}\n </div>\n }\n <div class=\"template-meta\">\n <div class=\"template-content-types\">\n @for (ct of card.ContentTypes; track ct) {\n <span class=\"content-type-chip\">\n <i [class]=\"getContentTypeIcon(ct)\"></i> {{ct}}\n </span>\n }\n @if (card.ContentTypes.length === 0) {\n <span class=\"content-type-chip empty\">\n No content\n </span>\n }\n </div>\n @if (card.LastUpdated) {\n <div class=\"template-updated\">\n Updated {{card.LastUpdated | date:'mediumDate'}}\n </div>\n }\n </div>\n </div>\n }\n @if (filteredTemplates.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-file-lines\"></i>\n <p>No templates found matching your criteria</p>\n </div>\n }\n </div>\n }\n </div>\n `,\n styles: [`\n .templates-wrapper {\n height: 100%;\n padding: 24px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n }\n\n /* HEADER */\n .templates-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 20px;\n }\n .templates-header h2 {\n margin: 0;\n font-size: 18px;\n font-weight: 800;\n color: var(--mj-text-primary);\n }\n .templates-header p {\n margin: 4px 0 0;\n font-size: 13px;\n color: var(--mj-text-muted);\n }\n .header-actions {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n .search-input-wrapper {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface-card);\n transition: border-color 0.15s, box-shadow 0.15s;\n min-width: 220px;\n }\n .search-input-wrapper:focus-within {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n }\n .search-input-wrapper i { color: var(--mj-text-muted); font-size: 12px; }\n .search-input-wrapper input {\n flex: 1; border: none; outline: none;\n background: transparent; font-size: 12px;\n font-family: inherit; color: var(--mj-text-primary);\n }\n .search-input-wrapper input::placeholder { color: var(--mj-text-muted); }\n\n .tb-btn {\n display: inline-flex; align-items: center;\n gap: 6px; padding: 8px 16px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-muted);\n font-size: 12px; font-weight: 600;\n cursor: pointer; transition: all 0.15s ease;\n font-family: inherit;\n }\n .tb-btn.primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n }\n .tb-btn.primary:hover { filter: brightness(1.1); }\n\n .loading-state {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 80px 0;\n }\n\n /* CATEGORY FILTERS */\n .category-filters {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n margin-bottom: 20px;\n }\n .filter-chip {\n display: inline-flex; align-items: center;\n gap: 4px; padding: 5px 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 16px;\n background: var(--mj-bg-surface-card);\n font-size: 12px; font-weight: 500;\n color: var(--mj-text-muted);\n cursor: pointer; transition: all 0.15s;\n }\n .filter-chip:hover {\n border-color: var(--mj-border-strong);\n background: var(--mj-bg-surface);\n }\n .filter-chip.active {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n /* GRID */\n .templates-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));\n gap: 16px;\n }\n\n .template-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n .template-card:hover {\n box-shadow: 0 2px 8px var(--mj-shadow-md);\n border-color: var(--mj-border-strong);\n }\n\n .template-card-header {\n display: flex;\n align-items: center;\n gap: 14px;\n margin-bottom: 12px;\n }\n .template-icon {\n width: 40px; height: 40px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n display: flex; align-items: center; justify-content: center;\n font-size: 16px; flex-shrink: 0;\n }\n .template-title-area { flex: 1; min-width: 0; }\n .template-name {\n font-size: 14px; font-weight: 700;\n color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .template-category {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n }\n\n .template-description {\n font-size: 12px;\n color: var(--mj-text-muted);\n line-height: 1.5;\n margin-bottom: 12px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n .template-meta {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .template-content-types {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n }\n .content-type-chip {\n display: inline-flex; align-items: center;\n gap: 4px; padding: 3px 8px;\n border-radius: 10px; font-size: 10px; font-weight: 500;\n background: var(--mj-bg-surface);\n color: var(--mj-text-muted);\n }\n .content-type-chip.empty {\n font-style: italic;\n }\n .template-updated {\n font-size: 10px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n }\n\n /* EMPTY STATE */\n .empty-state {\n grid-column: 1 / -1;\n display: flex; flex-direction: column;\n align-items: center; justify-content: center;\n padding: 64px 0; color: var(--mj-text-muted);\n }\n .empty-state i { font-size: 2rem; margin-bottom: 12px; opacity: 0.5; }\n .empty-state p { margin: 0; font-size: 13px; }\n `]\n})\nexport class CommunicationTemplatesResourceComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n public allTemplates: TemplateCardData[] = [];\n public filteredTemplates: TemplateCardData[] = [];\n public categories: string[] = [];\n public categoryFilter = '';\n public isLoading = false;\n private searchTerm = '';\n\n constructor(private cdr: ChangeDetectorRef, private navService: NavigationService) {\n super();\n }\n\n async ngOnInit(): Promise<void> {\n super.ngOnInit();\n await this.loadData();\n this.NotifyLoadComplete();\n }\n\n ngOnDestroy(): void {\n super.ngOnDestroy();\n }\n\n public async loadData(): Promise<void> {\n try {\n this.isLoading = true;\n this.cdr.detectChanges();\n\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n const [templatesResult, contentsResult] = await Promise.all([\n rv.RunView<MJTemplateEntity>({\n EntityName: 'MJ: Templates',\n OrderBy: 'Name ASC',\n ResultType: 'entity_object'\n }),\n rv.RunView<MJTemplateContentEntity>({\n EntityName: 'MJ: Template Contents',\n ResultType: 'entity_object'\n })\n ]);\n\n if (templatesResult.Success) {\n const contents = contentsResult.Success ? contentsResult.Results : [];\n this.allTemplates = templatesResult.Results.map(t => this.buildTemplateCard(t, contents));\n this.categories = this.extractCategories(this.allTemplates);\n this.applyFilter();\n }\n } catch (error) {\n console.error('Error loading templates:', error);\n } finally {\n this.isLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n private buildTemplateCard(template: MJTemplateEntity, allContents: MJTemplateContentEntity[]): TemplateCardData {\n const templateContents = allContents.filter(c => UUIDsEqual(c.TemplateID, template.ID));\n const contentTypes = [...new Set(templateContents.map(c => c.TypeID ? 'Content' : 'Text'))];\n const category = template.Category || 'Uncategorized';\n const lastUpdated = template.Get('__mj_UpdatedAt') as Date | null;\n\n return {\n Entity: template,\n ContentTypes: contentTypes.length > 0 ? contentTypes : [],\n LastUpdated: lastUpdated,\n CategoryName: category\n };\n }\n\n private extractCategories(cards: TemplateCardData[]): string[] {\n const cats = new Set(cards.map(c => c.CategoryName));\n return Array.from(cats).sort();\n }\n\n public getCategoryCount(category: string): number {\n return this.allTemplates.filter(t => t.CategoryName === category).length;\n }\n\n public onSearch(event: Event): void {\n this.searchTerm = (event.target as HTMLInputElement).value.toLowerCase();\n this.applyFilter();\n }\n\n public onCategoryFilter(category: string): void {\n this.categoryFilter = category;\n this.applyFilter();\n }\n\n private applyFilter(): void {\n let filtered = this.allTemplates;\n\n if (this.categoryFilter) {\n filtered = filtered.filter(t => t.CategoryName === this.categoryFilter);\n }\n\n if (this.searchTerm) {\n filtered = filtered.filter(t =>\n t.Entity.Name?.toLowerCase().includes(this.searchTerm) ||\n t.Entity.Description?.toLowerCase().includes(this.searchTerm) ||\n t.CategoryName.toLowerCase().includes(this.searchTerm)\n );\n }\n\n this.filteredTemplates = filtered;\n this.cdr.detectChanges();\n }\n\n public openTemplate(template: MJTemplateEntity): void {\n const pk = new CompositeKey();\n pk.LoadFromEntityInfoAndRecord(this.ProviderToUse.Entities.find(e => e.Name === 'MJ: Templates')!, template);\n this.navService.OpenEntityRecord('MJ: Templates', pk);\n }\n\n public addNewTemplate(): void {\n this.navService.OpenEntityRecord('MJ: Templates', new CompositeKey());\n }\n\n public getContentTypeIcon(type: string): string {\n const t = type.toLowerCase();\n if (t.includes('html')) return 'fa-solid fa-code';\n if (t.includes('text') || t.includes('plain')) return 'fa-solid fa-align-left';\n if (t.includes('sms')) return 'fa-solid fa-comment-sms';\n return 'fa-solid fa-file';\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n return 'Templates';\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-file-lines';\n }\n}\n"]}
|