@memberjunction/ng-dashboards 5.10.1 → 5.12.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.
Files changed (231) hide show
  1. package/dist/AI/components/agents/agent-configuration.component.d.ts +34 -2
  2. package/dist/AI/components/agents/agent-configuration.component.d.ts.map +1 -1
  3. package/dist/AI/components/agents/agent-configuration.component.js +586 -223
  4. package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
  5. package/dist/AI/components/agents/agent-editor.component.js +2 -2
  6. package/dist/AI/components/agents/agent-filter-panel.component.d.ts +8 -0
  7. package/dist/AI/components/agents/agent-filter-panel.component.d.ts.map +1 -1
  8. package/dist/AI/components/agents/agent-filter-panel.component.js +85 -52
  9. package/dist/AI/components/agents/agent-filter-panel.component.js.map +1 -1
  10. package/dist/AI/components/charts/performance-heatmap.component.d.ts +1 -0
  11. package/dist/AI/components/charts/performance-heatmap.component.d.ts.map +1 -1
  12. package/dist/AI/components/charts/performance-heatmap.component.js +27 -5
  13. package/dist/AI/components/charts/performance-heatmap.component.js.map +1 -1
  14. package/dist/AI/components/charts/time-series-chart.component.d.ts +5 -0
  15. package/dist/AI/components/charts/time-series-chart.component.d.ts.map +1 -1
  16. package/dist/AI/components/charts/time-series-chart.component.js +23 -8
  17. package/dist/AI/components/charts/time-series-chart.component.js.map +1 -1
  18. package/dist/AI/components/execution-monitoring.component.js +2 -2
  19. package/dist/AI/components/execution-monitoring.component.js.map +1 -1
  20. package/dist/AI/components/models/model-management.component.js +2 -2
  21. package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js +2 -2
  22. package/dist/AI/components/prompts/prompt-filter-panel.component.js +2 -2
  23. package/dist/AI/components/prompts/prompt-management.component.js +3 -3
  24. package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
  25. package/dist/AI/components/prompts/prompt-version-control.component.js +2 -2
  26. package/dist/AI/components/requests/agent-requests-resource.component.d.ts +83 -0
  27. package/dist/AI/components/requests/agent-requests-resource.component.d.ts.map +1 -0
  28. package/dist/AI/components/requests/agent-requests-resource.component.js +547 -0
  29. package/dist/AI/components/requests/agent-requests-resource.component.js.map +1 -0
  30. package/dist/AI/components/system/system-config-filter-panel.component.js +2 -2
  31. package/dist/AI/components/system/system-configuration.component.js +2 -2
  32. package/dist/AI/components/widgets/kpi-card.component.js +7 -7
  33. package/dist/AI/components/widgets/kpi-card.component.js.map +1 -1
  34. package/dist/AI/components/widgets/live-execution-widget.component.d.ts.map +1 -1
  35. package/dist/AI/components/widgets/live-execution-widget.component.js +6 -6
  36. package/dist/AI/components/widgets/live-execution-widget.component.js.map +1 -1
  37. package/dist/AI/index.d.ts +1 -0
  38. package/dist/AI/index.d.ts.map +1 -1
  39. package/dist/AI/index.js +2 -0
  40. package/dist/AI/index.js.map +1 -1
  41. package/dist/APIKeys/api-applications-panel.component.js +3 -3
  42. package/dist/APIKeys/api-applications-panel.component.js.map +1 -1
  43. package/dist/APIKeys/api-key-create-dialog.component.js +3 -3
  44. package/dist/APIKeys/api-key-create-dialog.component.js.map +1 -1
  45. package/dist/APIKeys/api-key-edit-panel.component.js +1 -1
  46. package/dist/APIKeys/api-key-edit-panel.component.js.map +1 -1
  47. package/dist/APIKeys/api-key-list.component.js +3 -3
  48. package/dist/APIKeys/api-key-list.component.js.map +1 -1
  49. package/dist/APIKeys/api-keys-resource.component.js +1 -1
  50. package/dist/APIKeys/api-keys-resource.component.js.map +1 -1
  51. package/dist/APIKeys/api-scopes-panel.component.js +2 -2
  52. package/dist/APIKeys/api-usage-panel.component.js +2 -2
  53. package/dist/Actions/components/actions-overview.component.js +2 -2
  54. package/dist/Actions/components/execution-monitoring.component.js +2 -2
  55. package/dist/Actions/components/explorer/action-breadcrumb.component.js +2 -2
  56. package/dist/Actions/components/explorer/action-card.component.js +2 -2
  57. package/dist/Actions/components/explorer/action-explorer.component.js +2 -2
  58. package/dist/Actions/components/explorer/action-list-item.component.js +2 -2
  59. package/dist/Actions/components/explorer/action-toolbar.component.js +2 -2
  60. package/dist/Actions/components/explorer/action-tree-panel.component.js +2 -2
  61. package/dist/Actions/components/explorer/new-action-panel.component.js +2 -2
  62. package/dist/Actions/components/explorer/new-action-panel.component.js.map +1 -1
  63. package/dist/Actions/components/explorer/new-category-panel.component.js +2 -2
  64. package/dist/Actions/components/explorer/new-category-panel.component.js.map +1 -1
  65. package/dist/Communication/communication-dashboard.component.js +2 -2
  66. package/dist/Communication/communication-logs-resource.component.d.ts.map +1 -1
  67. package/dist/Communication/communication-logs-resource.component.js +3 -3
  68. package/dist/Communication/communication-logs-resource.component.js.map +1 -1
  69. package/dist/Communication/communication-monitor-resource.component.d.ts.map +1 -1
  70. package/dist/Communication/communication-monitor-resource.component.js +5 -5
  71. package/dist/Communication/communication-monitor-resource.component.js.map +1 -1
  72. package/dist/Communication/communication-providers-resource.component.d.ts.map +1 -1
  73. package/dist/Communication/communication-providers-resource.component.js +3 -3
  74. package/dist/Communication/communication-providers-resource.component.js.map +1 -1
  75. package/dist/Communication/communication-runs-resource.component.d.ts.map +1 -1
  76. package/dist/Communication/communication-runs-resource.component.js +3 -3
  77. package/dist/Communication/communication-runs-resource.component.js.map +1 -1
  78. package/dist/Communication/communication-templates-resource.component.js +2 -2
  79. package/dist/Communication/communication-templates-resource.component.js.map +1 -1
  80. package/dist/ComponentStudio/component-studio-dashboard.component.js +2 -2
  81. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +2 -2
  82. package/dist/ComponentStudio/components/artifact-load-dialog.component.js +2 -2
  83. package/dist/ComponentStudio/components/artifact-selection-dialog.component.js +2 -2
  84. package/dist/ComponentStudio/components/browser/component-browser.component.js +2 -2
  85. package/dist/ComponentStudio/components/editors/code-editor-panel.component.js +2 -2
  86. package/dist/ComponentStudio/components/editors/code-editor-panel.component.js.map +1 -1
  87. package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js +2 -2
  88. package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js.map +1 -1
  89. package/dist/ComponentStudio/components/editors/requirements-editor.component.js +2 -2
  90. package/dist/ComponentStudio/components/editors/requirements-editor.component.js.map +1 -1
  91. package/dist/ComponentStudio/components/editors/spec-editor.component.js +2 -2
  92. package/dist/ComponentStudio/components/editors/spec-editor.component.js.map +1 -1
  93. package/dist/ComponentStudio/components/new-component-dialog/new-component-dialog.component.js +2 -2
  94. package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.js +2 -2
  95. package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.js.map +1 -1
  96. package/dist/ComponentStudio/components/text-import-dialog.component.js +2 -2
  97. package/dist/ComponentStudio/components/text-import-dialog.component.js.map +1 -1
  98. package/dist/ComponentStudio/components/workspace/component-preview.component.js +2 -2
  99. package/dist/ComponentStudio/components/workspace/editor-tabs.component.js +2 -2
  100. package/dist/ComponentStudio/components/workspace/editor-tabs.component.js.map +1 -1
  101. package/dist/Credentials/components/credentials-audit-resource.component.js +9 -9
  102. package/dist/Credentials/components/credentials-audit-resource.component.js.map +1 -1
  103. package/dist/Credentials/components/credentials-categories-resource.component.d.ts.map +1 -1
  104. package/dist/Credentials/components/credentials-categories-resource.component.js +11 -3
  105. package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
  106. package/dist/Credentials/components/credentials-list-resource.component.js +2 -2
  107. package/dist/Credentials/components/credentials-overview-resource.component.d.ts.map +1 -1
  108. package/dist/Credentials/components/credentials-overview-resource.component.js +12 -11
  109. package/dist/Credentials/components/credentials-overview-resource.component.js.map +1 -1
  110. package/dist/Credentials/components/credentials-types-resource.component.js +9 -9
  111. package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
  112. package/dist/Credentials/credentials-dashboard.component.js +2 -2
  113. package/dist/DashboardBrowser/dashboard-browser-resource.component.js +2 -2
  114. package/dist/DashboardBrowser/dashboard-share-dialog.component.js +2 -2
  115. package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js +2 -2
  116. package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js +2 -2
  117. package/dist/DataExplorer/components/view-selector/view-selector.component.js +2 -2
  118. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +6 -2
  119. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  120. package/dist/DataExplorer/data-explorer-dashboard.component.js +26 -8
  121. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  122. package/dist/Home/home-dashboard.component.js +2 -2
  123. package/dist/Integration/components/activity/activity.component.d.ts +1 -1
  124. package/dist/Integration/components/activity/activity.component.d.ts.map +1 -1
  125. package/dist/Integration/components/activity/activity.component.js +5 -5
  126. package/dist/Integration/components/activity/activity.component.js.map +1 -1
  127. package/dist/Integration/components/connections/connections.component.d.ts +31 -2
  128. package/dist/Integration/components/connections/connections.component.d.ts.map +1 -1
  129. package/dist/Integration/components/connections/connections.component.js +753 -412
  130. package/dist/Integration/components/connections/connections.component.js.map +1 -1
  131. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +3 -3
  132. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -1
  133. package/dist/Integration/components/overview/overview.component.d.ts +0 -1
  134. package/dist/Integration/components/overview/overview.component.d.ts.map +1 -1
  135. package/dist/Integration/components/overview/overview.component.js +3 -6
  136. package/dist/Integration/components/overview/overview.component.js.map +1 -1
  137. package/dist/Integration/components/pipelines/pipelines.component.js +3 -3
  138. package/dist/Integration/components/pipelines/pipelines.component.js.map +1 -1
  139. package/dist/Integration/components/schedules/schedules.component.d.ts +20 -0
  140. package/dist/Integration/components/schedules/schedules.component.d.ts.map +1 -1
  141. package/dist/Integration/components/schedules/schedules.component.js +97 -5
  142. package/dist/Integration/components/schedules/schedules.component.js.map +1 -1
  143. package/dist/Integration/components/visual-editor/visual-editor.component.js +2 -2
  144. package/dist/Integration/components/widgets/integration-card.component.d.ts.map +1 -1
  145. package/dist/Integration/components/widgets/integration-card.component.js +5 -1
  146. package/dist/Integration/components/widgets/integration-card.component.js.map +1 -1
  147. package/dist/Integration/components/widgets/run-history-panel.component.js +2 -2
  148. package/dist/Integration/components/widgets/run-history-panel.component.js.map +1 -1
  149. package/dist/Integration/integration.module.d.ts +2 -1
  150. package/dist/Integration/integration.module.d.ts.map +1 -1
  151. package/dist/Integration/integration.module.js +7 -3
  152. package/dist/Integration/integration.module.js.map +1 -1
  153. package/dist/Integration/services/integration-data.service.d.ts +27 -2
  154. package/dist/Integration/services/integration-data.service.d.ts.map +1 -1
  155. package/dist/Integration/services/integration-data.service.js +107 -4
  156. package/dist/Integration/services/integration-data.service.js.map +1 -1
  157. package/dist/Lists/components/lists-browse-resource.component.js +2 -2
  158. package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
  159. package/dist/Lists/components/lists-categories-resource.component.js +2 -2
  160. package/dist/Lists/components/lists-categories-resource.component.js.map +1 -1
  161. package/dist/Lists/components/lists-my-lists-resource.component.js +2 -2
  162. package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
  163. package/dist/Lists/components/lists-operations-resource.component.js +2 -2
  164. package/dist/Lists/components/lists-operations-resource.component.js.map +1 -1
  165. package/dist/Lists/components/venn-diagram/venn-diagram.component.js +3 -3
  166. package/dist/Lists/components/venn-diagram/venn-diagram.component.js.map +1 -1
  167. package/dist/MCP/components/mcp-connection-dialog.component.js +2 -2
  168. package/dist/MCP/components/mcp-log-detail-panel.component.js +2 -2
  169. package/dist/MCP/components/mcp-log-detail-panel.component.js.map +1 -1
  170. package/dist/MCP/components/mcp-server-dialog.component.js +2 -2
  171. package/dist/MCP/components/mcp-test-tool-dialog.component.js +2 -2
  172. package/dist/MCP/components/mcp-test-tool-dialog.component.js.map +1 -1
  173. package/dist/MCP/mcp-dashboard.component.js +2 -2
  174. package/dist/MCP/mcp-filter-panel.component.js +2 -2
  175. package/dist/QueryBrowser/query-browser-resource.component.d.ts +55 -1
  176. package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
  177. package/dist/QueryBrowser/query-browser-resource.component.js +664 -199
  178. package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
  179. package/dist/Scheduling/components/index.d.ts +0 -1
  180. package/dist/Scheduling/components/index.d.ts.map +1 -1
  181. package/dist/Scheduling/components/index.js +0 -1
  182. package/dist/Scheduling/components/index.js.map +1 -1
  183. package/dist/Scheduling/components/scheduling-activity.component.js +2 -2
  184. package/dist/Scheduling/components/scheduling-jobs.component.d.ts +6 -9
  185. package/dist/Scheduling/components/scheduling-jobs.component.d.ts.map +1 -1
  186. package/dist/Scheduling/components/scheduling-jobs.component.js +118 -110
  187. package/dist/Scheduling/components/scheduling-jobs.component.js.map +1 -1
  188. package/dist/Scheduling/components/scheduling-overview.component.js +3 -3
  189. package/dist/Scheduling/components/scheduling-overview.component.js.map +1 -1
  190. package/dist/Scheduling/scheduling-dashboard.component.js +2 -2
  191. package/dist/SystemDiagnostics/system-diagnostics.component.js +4 -4
  192. package/dist/SystemDiagnostics/system-diagnostics.component.js.map +1 -1
  193. package/dist/Testing/components/testing-analytics.component.js +2 -2
  194. package/dist/Testing/components/testing-analytics.component.js.map +1 -1
  195. package/dist/Testing/components/testing-dashboard-tab.component.js +4 -4
  196. package/dist/Testing/components/testing-dashboard-tab.component.js.map +1 -1
  197. package/dist/Testing/components/testing-explorer.component.js +2 -2
  198. package/dist/Testing/components/testing-explorer.component.js.map +1 -1
  199. package/dist/Testing/components/testing-review.component.d.ts.map +1 -1
  200. package/dist/Testing/components/testing-review.component.js +5 -5
  201. package/dist/Testing/components/testing-review.component.js.map +1 -1
  202. package/dist/Testing/components/testing-runs.component.js +2 -2
  203. package/dist/Testing/components/testing-runs.component.js.map +1 -1
  204. package/dist/Testing/components/widgets/oracle-breakdown-table.component.js +2 -2
  205. package/dist/Testing/components/widgets/oracle-breakdown-table.component.js.map +1 -1
  206. package/dist/Testing/components/widgets/suite-tree.component.js +4 -4
  207. package/dist/Testing/components/widgets/suite-tree.component.js.map +1 -1
  208. package/dist/Testing/components/widgets/test-run-detail-panel.component.js +2 -2
  209. package/dist/Testing/components/widgets/test-run-detail-panel.component.js.map +1 -1
  210. package/dist/Testing/testing-dashboard.component.js +2 -2
  211. package/dist/VersionHistory/components/diff-resource.component.js +2 -2
  212. package/dist/VersionHistory/components/graph-resource.component.js +2 -2
  213. package/dist/VersionHistory/components/labels-resource.component.js +3 -3
  214. package/dist/VersionHistory/components/labels-resource.component.js.map +1 -1
  215. package/dist/VersionHistory/components/restore-resource.component.js +3 -3
  216. package/dist/VersionHistory/components/restore-resource.component.js.map +1 -1
  217. package/dist/__tests__/integration-data-service.test.js +1 -0
  218. package/dist/__tests__/integration-data-service.test.js.map +1 -1
  219. package/dist/module.d.ts +52 -49
  220. package/dist/module.d.ts.map +1 -1
  221. package/dist/module.js +25 -6
  222. package/dist/module.js.map +1 -1
  223. package/dist/public-api.d.ts +1 -1
  224. package/dist/public-api.d.ts.map +1 -1
  225. package/dist/public-api.js +1 -1
  226. package/dist/public-api.js.map +1 -1
  227. package/package.json +42 -40
  228. package/dist/Scheduling/components/job-slideout.component.d.ts +0 -45
  229. package/dist/Scheduling/components/job-slideout.component.d.ts.map +0 -1
  230. package/dist/Scheduling/components/job-slideout.component.js +0 -459
  231. package/dist/Scheduling/components/job-slideout.component.js.map +0 -1
@@ -48,7 +48,6 @@ export declare class OverviewComponent extends BaseResourceComponent implements
48
48
  private loadEntityMapCounts;
49
49
  private loadAllEntityMaps;
50
50
  private countMapsByIntegration;
51
- private resolveIconByName;
52
51
  private showNotification;
53
52
  private dismissNotification;
54
53
  private clearNotificationTimer;
@@ -1 +1 @@
1
- {"version":3,"file":"overview.component.d.ts","sourceRoot":"","sources":["../../../../src/Integration/components/overview/overview.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,MAAM,EAAE,SAAS,EAAU,MAAM,eAAe,CAAC;AAGxF,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAGL,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAEjB,MAAM,yCAAyC,CAAC;;AAEjD,KAAK,eAAe,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAE1D,UAAU,kBAAkB;IAC1B,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAOa,iBAAkB,SAAQ,qBAAsB,YAAW,MAAM,EAAE,SAAS;IAEvF,SAAS,EAAE,kBAAkB,EAAE,CAAM;IACrC,IAAI,EAAE,eAAe,CAMnB;IACF,YAAY,EAAE,gBAAgB,EAAE,CAAM;IACtC,WAAW,EAAE,gBAAgB,EAAE,CAAM;IACrC,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAa;IAEjD,SAAS,UAAS;IAClB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC3C,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAQ;IAE/C,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,iBAAiB,CAA8C;IAEjE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,WAAW,IAAI,IAAI;IAQb,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBzB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQxB,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBnD,SAAS,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO;IAQzC,IAAI,WAAW,IAAI,MAAM,CAGxB;IAED,IAAI,mBAAmB,IAAI,MAAM,CAIhC;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM;IAIzC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAUnC,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM;IAOvD,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAIjD,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAO9C,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM;IAOhD,oBAAoB,CAAC,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;IAOrD,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAQlD,IAAI,eAAe,IAAI,MAAM,CAI5B;IAED,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAQlC,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAW1C,mBAAmB,IAAI,IAAI;IASrB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAI5D,oBAAoB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;YAQlD,mBAAmB;YASnB,iBAAiB;IAc/B,OAAO,CAAC,sBAAsB;IAS9B,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,sBAAsB;yCAtQnB,iBAAiB;2CAAjB,iBAAiB;CA4Q7B;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C"}
1
+ {"version":3,"file":"overview.component.d.ts","sourceRoot":"","sources":["../../../../src/Integration/components/overview/overview.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,MAAM,EAAE,SAAS,EAAU,MAAM,eAAe,CAAC;AAGxF,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAGL,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAEjB,MAAM,yCAAyC,CAAC;;AAEjD,KAAK,eAAe,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAE1D,UAAU,kBAAkB;IAC1B,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAOa,iBAAkB,SAAQ,qBAAsB,YAAW,MAAM,EAAE,SAAS;IAEvF,SAAS,EAAE,kBAAkB,EAAE,CAAM;IACrC,IAAI,EAAE,eAAe,CAMnB;IACF,YAAY,EAAE,gBAAgB,EAAE,CAAM;IACtC,WAAW,EAAE,gBAAgB,EAAE,CAAM;IACrC,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAa;IAEjD,SAAS,UAAS;IAClB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC3C,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAQ;IAE/C,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,iBAAiB,CAA8C;IAEjE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,WAAW,IAAI,IAAI;IAQb,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBzB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQxB,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBnD,SAAS,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO;IAQzC,IAAI,WAAW,IAAI,MAAM,CAGxB;IAED,IAAI,mBAAmB,IAAI,MAAM,CAIhC;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM;IAIzC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAUnC,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM;IAUvD,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAIjD,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAO9C,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM;IAOhD,oBAAoB,CAAC,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;IAOrD,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAQlD,IAAI,eAAe,IAAI,MAAM,CAI5B;IAED,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAQlC,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAW1C,mBAAmB,IAAI,IAAI;IASrB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAI5D,oBAAoB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;YAQlD,mBAAmB;YASnB,iBAAiB;IAc/B,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,sBAAsB;yCAtQnB,iBAAiB;2CAAjB,iBAAiB;CA4Q7B;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C"}
@@ -477,7 +477,7 @@ let OverviewComponent = class OverviewComponent extends BaseResourceComponent {
477
477
  if (summary.SourceType?.IconClass) {
478
478
  return summary.SourceType.IconClass;
479
479
  }
480
- return this.resolveIconByName(summary.Integration.Integration ?? summary.Integration.Name);
480
+ return ResolveIntegrationIcon(summary.Integration.Integration ?? summary.Integration.Name, summary.Icon);
481
481
  }
482
482
  GetStatusDotClass(color) {
483
483
  return `status-dot status-dot-${color}`;
@@ -578,9 +578,6 @@ let OverviewComponent = class OverviewComponent extends BaseResourceComponent {
578
578
  }
579
579
  return counts;
580
580
  }
581
- resolveIconByName(name) {
582
- return ResolveIntegrationIcon(name);
583
- }
584
581
  showNotification(type, message) {
585
582
  this.clearNotificationTimer();
586
583
  this.Notification = { Type: type, Message: message };
@@ -610,7 +607,7 @@ let OverviewComponent = class OverviewComponent extends BaseResourceComponent {
610
607
  i0.ɵɵconditional(ctx.Notification ? 1 : -1);
611
608
  i0.ɵɵadvance();
612
609
  i0.ɵɵconditional(ctx.IsLoading ? 2 : ctx.Summaries.length === 0 ? 3 : 4);
613
- } }, dependencies: [i1.LoadingComponent, i2.DecimalPipe], styles: ["\n\n\n\n.overview[_ngcontent-%COMP%] {\n padding: 28px;\n max-width: 1440px;\n margin: 0 auto;\n background: var(--mj-bg-page);\n min-height: 100%;\n}\n\n\n\n\n\n.notification[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 10px;\n margin-bottom: 20px;\n font-size: 13px;\n font-weight: 500;\n animation: _ngcontent-%COMP%_slideDown 0.25s ease-out;\n}\n.notification[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:first-child { font-size: 16px; }\n.notification-message[_ngcontent-%COMP%] { flex: 1; }\n.notification-success[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-color-success-200);\n}\n.notification-error[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-color-error-700);\n border: 1px solid var(--mj-color-error-200);\n}\n.notification-dismiss[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n color: inherit;\n opacity: 0.5;\n font-size: 14px;\n padding: 4px;\n line-height: 1;\n}\n.notification-dismiss[_ngcontent-%COMP%]:hover { opacity: 1; }\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from { opacity: 0; transform: translateY(-8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n text-align: center;\n padding: 100px 20px;\n color: var(--mj-text-disabled);\n}\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 64px;\n margin-bottom: 20px;\n display: block;\n color: var(--mj-color-neutral-300);\n}\n.empty-state[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 20px;\n color: var(--mj-text-secondary);\n}\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n max-width: 400px;\n margin-inline: auto;\n}\n\n\n\n\n\n.metric-strip[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(5, 1fr);\n gap: 16px;\n margin-bottom: 32px;\n}\n\n.metric-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 18px 16px;\n border-radius: 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n transition: box-shadow 0.2s, transform 0.2s;\n}\n.metric-card[_ngcontent-%COMP%]:hover {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n transform: translateY(-1px);\n}\n\n.metric-icon[_ngcontent-%COMP%] {\n position: relative;\n width: 44px;\n height: 44px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n flex-shrink: 0;\n}\n.metric-icon-blue[_ngcontent-%COMP%] { background: var(--mj-status-info-bg); color: var(--mj-brand-primary); }\n.metric-icon-green[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-color-success-600); }\n.metric-icon-emerald[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-color-success-600); }\n.metric-icon-orange[_ngcontent-%COMP%] { background: var(--mj-color-warning-50); color: var(--mj-color-warning-600); }\n\n.metric-body[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.metric-value[_ngcontent-%COMP%] {\n font-size: 22px;\n font-weight: 700;\n line-height: 1.2;\n color: var(--mj-text-primary);\n}\n.metric-value-indigo[_ngcontent-%COMP%] { color: var(--mj-color-indigo-500); }\n\n.metric-label[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.4px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n\n\n.metric-ring[_ngcontent-%COMP%] {\n width: 44px;\n height: 44px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n.metric-ring-inner[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: var(--mj-bg-surface);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.metric-ring-value[_ngcontent-%COMP%] {\n font-size: 8px;\n font-weight: 700;\n color: var(--mj-color-indigo-500);\n}\n\n\n\n.pulse-dot[_ngcontent-%COMP%] {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--mj-color-success-600);\n animation: _ngcontent-%COMP%_pulse 1.5s ease-in-out infinite;\n}\n\n@keyframes _ngcontent-%COMP%_pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(1.4); }\n}\n\n\n\n\n\n.section-heading[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n}\n.section-heading[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n.section-heading[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 8px;\n color: var(--mj-text-muted);\n}\n\n.refresh-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s, border-color 0.15s;\n}\n.refresh-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-status-info-bg);\n border-color: var(--mj-color-info-200);\n}\n\n.pipeline-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 20px;\n margin-bottom: 32px;\n}\n\n.pipeline-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n transition: box-shadow 0.2s, transform 0.2s;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n.pipeline-card[_ngcontent-%COMP%]:hover {\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1);\n transform: translateY(-2px);\n}\n\n.pipeline-card-error[_ngcontent-%COMP%] {\n border-left: 3px solid var(--mj-status-error);\n}\n\n\n\n.card-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n}\n.card-header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n.card-icon-wrap[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n background: var(--mj-status-info-bg);\n color: var(--mj-brand-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n flex-shrink: 0;\n}\n.card-title-wrap[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.card-title[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.card-subtitle[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-disabled);\n}\n\n\n\n.status-dot[_ngcontent-%COMP%] {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n flex-shrink: 0;\n margin-top: 4px;\n position: relative;\n}\n.status-dot-green[_ngcontent-%COMP%] { background: var(--mj-color-success-600); }\n.status-dot-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.status-dot-red[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n.status-dot-gray[_ngcontent-%COMP%] { background: var(--mj-color-neutral-300); }\n\n.dot-pulse[_ngcontent-%COMP%] {\n position: absolute;\n inset: -3px;\n border-radius: 50%;\n border: 2px solid var(--mj-status-warning);\n animation: _ngcontent-%COMP%_dotPulse 1.5s ease-in-out infinite;\n}\n@keyframes _ngcontent-%COMP%_dotPulse {\n 0%, 100% { opacity: 0.3; transform: scale(1); }\n 50% { opacity: 0; transform: scale(1.6); }\n}\n\n\n\n.pipeline-flow[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0;\n padding: 8px 0;\n}\n.flow-node[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border-radius: 8px;\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n flex-shrink: 0;\n}\n.flow-node-mj[_ngcontent-%COMP%] {\n background: var(--mj-status-info-bg);\n color: var(--mj-brand-primary);\n}\n.flow-arrow[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 0;\n padding: 0 4px;\n}\n.flow-line[_ngcontent-%COMP%] {\n flex: 1;\n height: 2px;\n background: var(--mj-border-default);\n}\n.flow-count[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n padding: 2px 8px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n font-weight: 500;\n}\n\n\n\n.card-stats[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 8px;\n}\n.stat-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n}\n.stat-label[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n margin-bottom: 2px;\n}\n.stat-value[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-color-neutral-700);\n}\n.stat-error[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.sparkline-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.sparkline-label[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n white-space: nowrap;\n}\n.sparkline-dots[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 5px;\n}\n.spark-dot[_ngcontent-%COMP%] {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n display: inline-block;\n}\n.spark-green[_ngcontent-%COMP%] { background: var(--mj-color-success-600); }\n.spark-red[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n.spark-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.spark-gray[_ngcontent-%COMP%] { background: var(--mj-color-neutral-300); }\n.sparkline-none[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-color-neutral-300);\n font-style: italic;\n}\n\n\n\n.card-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n padding-top: 4px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.btn-sync[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s, color 0.15s, border-color 0.15s;\n}\n.btn-sync[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-status-info-bg);\n border-color: var(--mj-color-info-200);\n}\n.btn-sync[_ngcontent-%COMP%]:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.btn-sync-disabled[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n border-color: var(--mj-border-default);\n}\n\n\n\n\n\n.bottom-split[_ngcontent-%COMP%] {\n display: flex;\n gap: 20px;\n}\n\n.panel-title[_ngcontent-%COMP%] {\n margin: 0 0 16px 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 8px;\n color: var(--mj-text-muted);\n}\n\n\n\n.chart-panel[_ngcontent-%COMP%] {\n flex: 6;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n}\n\n.bar-chart[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: 12px;\n height: 200px;\n padding-top: 24px;\n}\n.bar-column[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n height: 100%;\n position: relative;\n}\n.bar-count[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-muted);\n margin-bottom: 4px;\n}\n.bar-fill[_ngcontent-%COMP%] {\n width: 100%;\n max-width: 40px;\n background: linear-gradient(180deg, var(--mj-brand-primary) 0%, var(--mj-color-accent-400) 100%);\n border-radius: 4px 4px 0 0;\n min-height: 2px;\n transition: height 0.3s ease;\n}\n.bar-day[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-disabled);\n margin-top: 6px;\n text-align: center;\n}\n\n\n\n.feed-panel[_ngcontent-%COMP%] {\n flex: 4;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n max-height: 340px;\n overflow-y: auto;\n}\n\n.feed-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.feed-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 10px;\n border-radius: 6px;\n transition: background 0.15s;\n}\n.feed-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-page);\n}\n\n.feed-icon-green[_ngcontent-%COMP%] { color: var(--mj-color-success-600); }\n.feed-icon-red[_ngcontent-%COMP%] { color: var(--mj-color-error-600); }\n.feed-icon-amber[_ngcontent-%COMP%] { color: var(--mj-color-warning-600); }\n\n.feed-details[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.feed-name[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.feed-meta[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-disabled);\n}\n\n.feed-badge[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 10px;\n text-transform: uppercase;\n white-space: nowrap;\n flex-shrink: 0;\n}\n.feed-badge-green[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-color-success-800); }\n.feed-badge-amber[_ngcontent-%COMP%] { background: var(--mj-color-warning-50); color: var(--mj-color-warning-800); }\n.feed-badge-red[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-color-error-700); }\n\n.empty-hint[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n font-size: 13px;\n font-style: italic;\n}\n\n\n\n\n\n@media (max-width: 1200px) {\n .pipeline-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n .metric-strip[_ngcontent-%COMP%] {\n grid-template-columns: repeat(3, 1fr);\n }\n}\n\n@media (max-width: 900px) {\n .pipeline-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n .metric-strip[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n .bottom-split[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n .card-stats[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n}\n\n@media (max-width: 600px) {\n .overview[_ngcontent-%COMP%] {\n padding: 16px;\n }\n .metric-strip[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n}"] });
610
+ } }, dependencies: [i1.LoadingComponent, i2.DecimalPipe], styles: ["\n\n\n\n.overview[_ngcontent-%COMP%] {\n padding: 28px;\n max-width: 1440px;\n margin: 0 auto;\n background: var(--mj-bg-page);\n min-height: 100%;\n}\n\n\n\n\n\n.notification[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 10px;\n margin-bottom: 20px;\n font-size: 13px;\n font-weight: 500;\n animation: _ngcontent-%COMP%_slideDown 0.25s ease-out;\n}\n.notification[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:first-child { font-size: 16px; }\n.notification-message[_ngcontent-%COMP%] { flex: 1; }\n.notification-success[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-color-success-200);\n}\n.notification-error[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-color-error-200);\n}\n.notification-dismiss[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n color: inherit;\n opacity: 0.5;\n font-size: 14px;\n padding: 4px;\n line-height: 1;\n}\n.notification-dismiss[_ngcontent-%COMP%]:hover { opacity: 1; }\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from { opacity: 0; transform: translateY(-8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n text-align: center;\n padding: 100px 20px;\n color: var(--mj-text-disabled);\n}\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 64px;\n margin-bottom: 20px;\n display: block;\n color: var(--mj-color-neutral-300);\n}\n.empty-state[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 20px;\n color: var(--mj-text-secondary);\n}\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n max-width: 400px;\n margin-inline: auto;\n}\n\n\n\n\n\n.metric-strip[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(5, 1fr);\n gap: 16px;\n margin-bottom: 32px;\n}\n\n.metric-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 18px 16px;\n border-radius: 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n transition: box-shadow 0.2s, transform 0.2s;\n}\n.metric-card[_ngcontent-%COMP%]:hover {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n transform: translateY(-1px);\n}\n\n.metric-icon[_ngcontent-%COMP%] {\n position: relative;\n width: 44px;\n height: 44px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n flex-shrink: 0;\n}\n.metric-icon-blue[_ngcontent-%COMP%] { background: var(--mj-status-info-bg); color: var(--mj-brand-primary); }\n.metric-icon-green[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-color-success-600); }\n.metric-icon-emerald[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-color-success-600); }\n.metric-icon-orange[_ngcontent-%COMP%] { background: var(--mj-color-warning-50); color: var(--mj-color-warning-600); }\n\n.metric-body[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.metric-value[_ngcontent-%COMP%] {\n font-size: 22px;\n font-weight: 700;\n line-height: 1.2;\n color: var(--mj-text-primary);\n}\n.metric-value-indigo[_ngcontent-%COMP%] { color: var(--mj-color-indigo-500); }\n\n.metric-label[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.4px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n\n\n.metric-ring[_ngcontent-%COMP%] {\n width: 44px;\n height: 44px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n.metric-ring-inner[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: var(--mj-bg-surface);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.metric-ring-value[_ngcontent-%COMP%] {\n font-size: 8px;\n font-weight: 700;\n color: var(--mj-color-indigo-500);\n}\n\n\n\n.pulse-dot[_ngcontent-%COMP%] {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--mj-color-success-600);\n animation: _ngcontent-%COMP%_pulse 1.5s ease-in-out infinite;\n}\n\n@keyframes _ngcontent-%COMP%_pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(1.4); }\n}\n\n\n\n\n\n.section-heading[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n}\n.section-heading[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n.section-heading[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 8px;\n color: var(--mj-text-muted);\n}\n\n.refresh-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s, border-color 0.15s;\n}\n.refresh-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-status-info-bg);\n border-color: var(--mj-color-info-200);\n}\n\n.pipeline-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 20px;\n margin-bottom: 32px;\n}\n\n.pipeline-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n transition: box-shadow 0.2s, transform 0.2s;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n.pipeline-card[_ngcontent-%COMP%]:hover {\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1);\n transform: translateY(-2px);\n}\n\n.pipeline-card-error[_ngcontent-%COMP%] {\n border-left: 3px solid var(--mj-status-error);\n}\n\n\n\n.card-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n}\n.card-header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n.card-icon-wrap[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n background: var(--mj-status-info-bg);\n color: var(--mj-brand-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n flex-shrink: 0;\n}\n.card-title-wrap[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.card-title[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.card-subtitle[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-disabled);\n}\n\n\n\n.status-dot[_ngcontent-%COMP%] {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n flex-shrink: 0;\n margin-top: 4px;\n position: relative;\n}\n.status-dot-green[_ngcontent-%COMP%] { background: var(--mj-color-success-600); }\n.status-dot-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.status-dot-red[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n.status-dot-gray[_ngcontent-%COMP%] { background: var(--mj-color-neutral-300); }\n\n.dot-pulse[_ngcontent-%COMP%] {\n position: absolute;\n inset: -3px;\n border-radius: 50%;\n border: 2px solid var(--mj-status-warning);\n animation: _ngcontent-%COMP%_dotPulse 1.5s ease-in-out infinite;\n}\n@keyframes _ngcontent-%COMP%_dotPulse {\n 0%, 100% { opacity: 0.3; transform: scale(1); }\n 50% { opacity: 0; transform: scale(1.6); }\n}\n\n\n\n.pipeline-flow[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0;\n padding: 8px 0;\n}\n.flow-node[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border-radius: 8px;\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n flex-shrink: 0;\n}\n.flow-node-mj[_ngcontent-%COMP%] {\n background: var(--mj-status-info-bg);\n color: var(--mj-brand-primary);\n}\n.flow-arrow[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 0;\n padding: 0 4px;\n}\n.flow-line[_ngcontent-%COMP%] {\n flex: 1;\n height: 2px;\n background: var(--mj-border-default);\n}\n.flow-count[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n padding: 2px 8px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n font-weight: 500;\n}\n\n\n\n.card-stats[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 8px;\n}\n.stat-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n}\n.stat-label[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n margin-bottom: 2px;\n}\n.stat-value[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n.stat-error[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.sparkline-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.sparkline-label[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n white-space: nowrap;\n}\n.sparkline-dots[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 5px;\n}\n.spark-dot[_ngcontent-%COMP%] {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n display: inline-block;\n}\n.spark-green[_ngcontent-%COMP%] { background: var(--mj-color-success-600); }\n.spark-red[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n.spark-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.spark-gray[_ngcontent-%COMP%] { background: var(--mj-color-neutral-300); }\n.sparkline-none[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-color-neutral-300);\n font-style: italic;\n}\n\n\n\n.card-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n padding-top: 4px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.btn-sync[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s, color 0.15s, border-color 0.15s;\n}\n.btn-sync[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-status-info-bg);\n border-color: var(--mj-color-info-200);\n}\n.btn-sync[_ngcontent-%COMP%]:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.btn-sync-disabled[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n border-color: var(--mj-border-default);\n}\n\n\n\n\n\n.bottom-split[_ngcontent-%COMP%] {\n display: flex;\n gap: 20px;\n}\n\n.panel-title[_ngcontent-%COMP%] {\n margin: 0 0 16px 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 8px;\n color: var(--mj-text-muted);\n}\n\n\n\n.chart-panel[_ngcontent-%COMP%] {\n flex: 6;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n}\n\n.bar-chart[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: 12px;\n height: 200px;\n padding-top: 24px;\n}\n.bar-column[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n height: 100%;\n position: relative;\n}\n.bar-count[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-muted);\n margin-bottom: 4px;\n}\n.bar-fill[_ngcontent-%COMP%] {\n width: 100%;\n max-width: 40px;\n background: linear-gradient(180deg, var(--mj-brand-primary) 0%, var(--mj-color-accent-400) 100%);\n border-radius: 4px 4px 0 0;\n min-height: 2px;\n transition: height 0.3s ease;\n}\n.bar-day[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-disabled);\n margin-top: 6px;\n text-align: center;\n}\n\n\n\n.feed-panel[_ngcontent-%COMP%] {\n flex: 4;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n max-height: 340px;\n overflow-y: auto;\n}\n\n.feed-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.feed-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 10px;\n border-radius: 6px;\n transition: background 0.15s;\n}\n.feed-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-page);\n}\n\n.feed-icon-green[_ngcontent-%COMP%] { color: var(--mj-color-success-600); }\n.feed-icon-red[_ngcontent-%COMP%] { color: var(--mj-color-error-600); }\n.feed-icon-amber[_ngcontent-%COMP%] { color: var(--mj-color-warning-600); }\n\n.feed-details[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.feed-name[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.feed-meta[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-disabled);\n}\n\n.feed-badge[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 10px;\n text-transform: uppercase;\n white-space: nowrap;\n flex-shrink: 0;\n}\n.feed-badge-green[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-color-success-800); }\n.feed-badge-amber[_ngcontent-%COMP%] { background: var(--mj-color-warning-50); color: var(--mj-color-warning-800); }\n.feed-badge-red[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-status-error); }\n\n.empty-hint[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n font-size: 13px;\n font-style: italic;\n}\n\n\n\n\n\n@media (max-width: 1200px) {\n .pipeline-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n .metric-strip[_ngcontent-%COMP%] {\n grid-template-columns: repeat(3, 1fr);\n }\n}\n\n@media (max-width: 900px) {\n .pipeline-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n .metric-strip[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n .bottom-split[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n .card-stats[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n}\n\n@media (max-width: 600px) {\n .overview[_ngcontent-%COMP%] {\n padding: 16px;\n }\n .metric-strip[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n}"] });
614
611
  };
615
612
  OverviewComponent = __decorate([
616
613
  RegisterClass(BaseResourceComponent, 'IntegrationOverview')
@@ -618,7 +615,7 @@ OverviewComponent = __decorate([
618
615
  export { OverviewComponent };
619
616
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(OverviewComponent, [{
620
617
  type: Component,
621
- args: [{ standalone: false, selector: 'app-integration-overview', template: "<div class=\"overview\">\n <!-- Notification Banner -->\n @if (Notification) {\n <div class=\"notification\" [class.notification-success]=\"Notification.Type === 'success'\"\n [class.notification-error]=\"Notification.Type === 'error'\">\n @if (Notification.Type === 'success') {\n <i class=\"fa-solid fa-circle-check\"></i>\n } @else {\n <i class=\"fa-solid fa-circle-xmark\"></i>\n }\n <span class=\"notification-message\">{{ Notification.Message }}</span>\n <button class=\"notification-dismiss\" (click)=\"DismissNotification()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n\n @if (IsLoading) {\n <mj-loading text=\"Loading integrations...\" size=\"medium\"></mj-loading>\n } @else if (Summaries.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-plug-circle-xmark\"></i>\n <h3>No Integrations Configured</h3>\n <p>Set up your first integration using the Connection Studio to start syncing data.</p>\n </div>\n } @else {\n <!-- ====================================================================\n SECTION 1: Metric Strip\n ==================================================================== -->\n <div class=\"metric-strip\">\n <!-- Total Pipelines -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-blue\">\n <i class=\"fa-solid fa-diagram-project\"></i>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ KPIs.TotalIntegrations }}</span>\n <span class=\"metric-label\">Total Pipelines</span>\n </div>\n </div>\n\n <!-- Records Today -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-green\">\n <i class=\"fa-solid fa-database\"></i>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ FormatNumber(KPIs.RecordsSyncedToday) }}</span>\n <span class=\"metric-label\">Records Today</span>\n </div>\n </div>\n\n <!-- Success Rate (with conic gradient ring) -->\n <div class=\"metric-card\">\n <div class=\"metric-ring\" [style.background]=\"SuccessRateGradient\">\n <div class=\"metric-ring-inner\">\n <span class=\"metric-ring-value\">{{ SuccessRate }}%</span>\n </div>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value metric-value-indigo\">{{ SuccessRate }}%</span>\n <span class=\"metric-label\">Success Rate</span>\n </div>\n </div>\n\n <!-- Active Now -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-emerald\">\n <i class=\"fa-solid fa-bolt\"></i>\n @if (ActiveCount > 0) {\n <span class=\"pulse-dot\"></span>\n }\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ ActiveCount }}</span>\n <span class=\"metric-label\">Active Now</span>\n </div>\n </div>\n\n <!-- Avg Duration -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-orange\">\n <i class=\"fa-solid fa-clock\"></i>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ FormatDuration(KPIs.AverageSyncDurationMs) }}</span>\n <span class=\"metric-label\">Avg Duration</span>\n </div>\n </div>\n </div>\n\n <!-- ====================================================================\n SECTION 2: Pipeline Health Grid\n ==================================================================== -->\n <div class=\"section-heading\">\n <h3><i class=\"fa-solid fa-heart-pulse\"></i> Pipeline Health</h3>\n <button class=\"refresh-btn\" (click)=\"Refresh()\">\n <i class=\"fa-solid fa-arrows-rotate\"></i> Refresh\n </button>\n </div>\n\n <div class=\"pipeline-grid\">\n @for (summary of Summaries; track summary.Integration.ID) {\n <div [class]=\"GetCardBorderClass(summary.StatusColor)\">\n <!-- Card Header -->\n <div class=\"card-header\">\n <div class=\"card-header-left\">\n <div class=\"card-icon-wrap\">\n <i [class]=\"GetIntegrationIcon(summary)\"></i>\n </div>\n <div class=\"card-title-wrap\">\n <span class=\"card-title\">{{ summary.Integration.Name }}</span>\n <span class=\"card-subtitle\">{{ summary.SourceType?.Name ?? 'Custom' }}</span>\n </div>\n </div>\n <div [class]=\"GetStatusDotClass(summary.StatusColor)\"\n [title]=\"GetStatusLabel(summary.StatusColor)\">\n @if (summary.LatestRun?.Status === 'In Progress') {\n <span class=\"dot-pulse\"></span>\n }\n </div>\n </div>\n\n <!-- Pipeline Flow Visual -->\n <div class=\"pipeline-flow\">\n <div class=\"flow-node\">\n <i [class]=\"GetIntegrationIcon(summary)\"></i>\n </div>\n <div class=\"flow-arrow\">\n <div class=\"flow-line\"></div>\n <span class=\"flow-count\">{{ GetEntityMapCount(summary.Integration.ID) }} maps</span>\n <div class=\"flow-line\"></div>\n </div>\n <div class=\"flow-node flow-node-mj\">\n <i class=\"fa-solid fa-layer-group\"></i>\n </div>\n </div>\n\n <!-- Stats Row -->\n <div class=\"card-stats\">\n <div class=\"stat-item\">\n <span class=\"stat-label\">Last sync</span>\n <span class=\"stat-value\">{{ summary.RelativeTime }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Records</span>\n <span class=\"stat-value\">{{ FormatNumber(summary.LatestRun?.TotalRecords ?? 0) }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Duration</span>\n <span class=\"stat-value\">{{ FormatDuration(summary.DurationMs) }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Errors</span>\n <span class=\"stat-value\" [class.stat-error]=\"summary.TotalErrors > 0\">\n {{ summary.TotalErrors }}\n </span>\n </div>\n </div>\n\n <!-- Sparkline (last 5 runs) -->\n <div class=\"sparkline-row\">\n <span class=\"sparkline-label\">Recent runs</span>\n <div class=\"sparkline-dots\">\n @for (run of summary.RecentRuns; track run.ID) {\n <span [class]=\"GetSparklineDotClass(run)\"\n [title]=\"run.Status + ' - ' + (run.StartedAt ?? 'N/A')\"></span>\n }\n @if (summary.RecentRuns.length === 0) {\n <span class=\"sparkline-none\">No runs</span>\n }\n </div>\n </div>\n\n <!-- Card Footer -->\n <div class=\"card-footer\">\n @if (IsRunning(summary.Integration.ID)) {\n <button class=\"btn-sync btn-sync-disabled\" disabled>\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Running...\n </button>\n } @else {\n <button class=\"btn-sync\"\n (click)=\"RunSync(summary.Integration.ID)\"\n [disabled]=\"!summary.Integration.IsActive || RunningIntegrationID !== null\">\n <i class=\"fa-solid fa-play\"></i> Sync Now\n </button>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- ====================================================================\n SECTION 3: Bottom - Bar Chart & Activity Feed\n ==================================================================== -->\n <div class=\"bottom-split\">\n <!-- Bar Chart (left, 60%) -->\n <div class=\"chart-panel\">\n <h3 class=\"panel-title\"><i class=\"fa-solid fa-chart-bar\"></i> Records Synced (7 days)</h3>\n @if (DailyCounts.length === 0) {\n <p class=\"empty-hint\">No data available.</p>\n } @else {\n <div class=\"bar-chart\">\n @for (day of DailyCounts; track day.Date) {\n <div class=\"bar-column\">\n <div class=\"bar-count\">{{ FormatNumber(day.Records) }}</div>\n <div class=\"bar-fill\" [style.height.%]=\"BarHeight(day.Records)\"></div>\n <div class=\"bar-day\">{{ day.Label }}</div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Activity Feed (right, 40%) -->\n <div class=\"feed-panel\">\n <h3 class=\"panel-title\"><i class=\"fa-solid fa-stream\"></i> Recent Activity</h3>\n @if (ActivityFeed.length === 0) {\n <p class=\"empty-hint\">No recent activity.</p>\n } @else {\n <div class=\"feed-list\">\n @for (item of ActivityFeed; track item.RunID) {\n <div class=\"feed-item\">\n <i [class]=\"ActivityStatusIcon(item.Status)\"\n [class.feed-icon-green]=\"item.StatusColor === 'green'\"\n [class.feed-icon-red]=\"item.StatusColor === 'red'\"\n [class.feed-icon-amber]=\"item.StatusColor === 'amber'\">\n </i>\n <div class=\"feed-details\">\n <span class=\"feed-name\">{{ item.IntegrationName }}</span>\n <span class=\"feed-meta\">{{ item.TotalRecords | number }} records &middot; {{ item.RelativeTime }}</span>\n </div>\n <span class=\"feed-badge\" [class]=\"'feed-badge-' + item.StatusColor\">\n {{ item.Status }}\n </span>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n</div>\n", styles: ["/* ==========================================================================\n Integration Overview - Root\n ========================================================================== */\n.overview {\n padding: 28px;\n max-width: 1440px;\n margin: 0 auto;\n background: var(--mj-bg-page);\n min-height: 100%;\n}\n\n/* ==========================================================================\n Notification Banner\n ========================================================================== */\n.notification {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 10px;\n margin-bottom: 20px;\n font-size: 13px;\n font-weight: 500;\n animation: slideDown 0.25s ease-out;\n}\n.notification i:first-child { font-size: 16px; }\n.notification-message { flex: 1; }\n.notification-success {\n background: var(--mj-status-success-bg);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-color-success-200);\n}\n.notification-error {\n background: var(--mj-status-error-bg);\n color: var(--mj-color-error-700);\n border: 1px solid var(--mj-color-error-200);\n}\n.notification-dismiss {\n background: none;\n border: none;\n cursor: pointer;\n color: inherit;\n opacity: 0.5;\n font-size: 14px;\n padding: 4px;\n line-height: 1;\n}\n.notification-dismiss:hover { opacity: 1; }\n\n@keyframes slideDown {\n from { opacity: 0; transform: translateY(-8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* ==========================================================================\n Empty State\n ========================================================================== */\n.empty-state {\n text-align: center;\n padding: 100px 20px;\n color: var(--mj-text-disabled);\n}\n.empty-state i {\n font-size: 64px;\n margin-bottom: 20px;\n display: block;\n color: var(--mj-color-neutral-300);\n}\n.empty-state h3 {\n margin: 0 0 8px 0;\n font-size: 20px;\n color: var(--mj-text-secondary);\n}\n.empty-state p {\n margin: 0;\n font-size: 14px;\n max-width: 400px;\n margin-inline: auto;\n}\n\n/* ==========================================================================\n SECTION 1: Metric Strip\n ========================================================================== */\n.metric-strip {\n display: grid;\n grid-template-columns: repeat(5, 1fr);\n gap: 16px;\n margin-bottom: 32px;\n}\n\n.metric-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 18px 16px;\n border-radius: 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n transition: box-shadow 0.2s, transform 0.2s;\n}\n.metric-card:hover {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n transform: translateY(-1px);\n}\n\n.metric-icon {\n position: relative;\n width: 44px;\n height: 44px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n flex-shrink: 0;\n}\n.metric-icon-blue { background: var(--mj-status-info-bg); color: var(--mj-brand-primary); }\n.metric-icon-green { background: var(--mj-status-success-bg); color: var(--mj-color-success-600); }\n.metric-icon-emerald { background: var(--mj-status-success-bg); color: var(--mj-color-success-600); }\n.metric-icon-orange { background: var(--mj-color-warning-50); color: var(--mj-color-warning-600); }\n\n.metric-body {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.metric-value {\n font-size: 22px;\n font-weight: 700;\n line-height: 1.2;\n color: var(--mj-text-primary);\n}\n.metric-value-indigo { color: var(--mj-color-indigo-500); }\n\n.metric-label {\n font-size: 11px;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.4px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Conic gradient ring for success rate */\n.metric-ring {\n width: 44px;\n height: 44px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n.metric-ring-inner {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: var(--mj-bg-surface);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.metric-ring-value {\n font-size: 8px;\n font-weight: 700;\n color: var(--mj-color-indigo-500);\n}\n\n/* Pulse dot for active syncs */\n.pulse-dot {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--mj-color-success-600);\n animation: pulse 1.5s ease-in-out infinite;\n}\n\n@keyframes pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(1.4); }\n}\n\n/* ==========================================================================\n SECTION 2: Pipeline Health Grid\n ========================================================================== */\n.section-heading {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n}\n.section-heading h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n.section-heading h3 i {\n margin-right: 8px;\n color: var(--mj-text-muted);\n}\n\n.refresh-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s, border-color 0.15s;\n}\n.refresh-btn:hover {\n background: var(--mj-status-info-bg);\n border-color: var(--mj-color-info-200);\n}\n\n.pipeline-grid {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 20px;\n margin-bottom: 32px;\n}\n\n.pipeline-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n transition: box-shadow 0.2s, transform 0.2s;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n.pipeline-card:hover {\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1);\n transform: translateY(-2px);\n}\n\n.pipeline-card-error {\n border-left: 3px solid var(--mj-status-error);\n}\n\n/* Card Header */\n.card-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n}\n.card-header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n.card-icon-wrap {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n background: var(--mj-status-info-bg);\n color: var(--mj-brand-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n flex-shrink: 0;\n}\n.card-title-wrap {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.card-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.card-subtitle {\n font-size: 11px;\n color: var(--mj-text-disabled);\n}\n\n/* Status Dot */\n.status-dot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n flex-shrink: 0;\n margin-top: 4px;\n position: relative;\n}\n.status-dot-green { background: var(--mj-color-success-600); }\n.status-dot-amber { background: var(--mj-status-warning); }\n.status-dot-red { background: var(--mj-status-error); }\n.status-dot-gray { background: var(--mj-color-neutral-300); }\n\n.dot-pulse {\n position: absolute;\n inset: -3px;\n border-radius: 50%;\n border: 2px solid var(--mj-status-warning);\n animation: dotPulse 1.5s ease-in-out infinite;\n}\n@keyframes dotPulse {\n 0%, 100% { opacity: 0.3; transform: scale(1); }\n 50% { opacity: 0; transform: scale(1.6); }\n}\n\n/* Pipeline Flow Visual */\n.pipeline-flow {\n display: flex;\n align-items: center;\n gap: 0;\n padding: 8px 0;\n}\n.flow-node {\n width: 36px;\n height: 36px;\n border-radius: 8px;\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n flex-shrink: 0;\n}\n.flow-node-mj {\n background: var(--mj-status-info-bg);\n color: var(--mj-brand-primary);\n}\n.flow-arrow {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 0;\n padding: 0 4px;\n}\n.flow-line {\n flex: 1;\n height: 2px;\n background: var(--mj-border-default);\n}\n.flow-count {\n font-size: 10px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n padding: 2px 8px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n font-weight: 500;\n}\n\n/* Card Stats */\n.card-stats {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 8px;\n}\n.stat-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n}\n.stat-label {\n font-size: 10px;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n margin-bottom: 2px;\n}\n.stat-value {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-color-neutral-700);\n}\n.stat-error {\n color: var(--mj-status-error);\n}\n\n/* Sparkline Row */\n.sparkline-row {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.sparkline-label {\n font-size: 10px;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n white-space: nowrap;\n}\n.sparkline-dots {\n display: flex;\n align-items: center;\n gap: 5px;\n}\n.spark-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n display: inline-block;\n}\n.spark-green { background: var(--mj-color-success-600); }\n.spark-red { background: var(--mj-status-error); }\n.spark-amber { background: var(--mj-status-warning); }\n.spark-gray { background: var(--mj-color-neutral-300); }\n.sparkline-none {\n font-size: 10px;\n color: var(--mj-color-neutral-300);\n font-style: italic;\n}\n\n/* Card Footer */\n.card-footer {\n display: flex;\n justify-content: flex-end;\n padding-top: 4px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.btn-sync {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s, color 0.15s, border-color 0.15s;\n}\n.btn-sync:hover:not(:disabled) {\n background: var(--mj-status-info-bg);\n border-color: var(--mj-color-info-200);\n}\n.btn-sync:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.btn-sync-disabled {\n color: var(--mj-text-disabled);\n border-color: var(--mj-border-default);\n}\n\n/* ==========================================================================\n SECTION 3: Bottom Split - Chart + Feed\n ========================================================================== */\n.bottom-split {\n display: flex;\n gap: 20px;\n}\n\n.panel-title {\n margin: 0 0 16px 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n.panel-title i {\n margin-right: 8px;\n color: var(--mj-text-muted);\n}\n\n/* Bar Chart Panel (left, 60%) */\n.chart-panel {\n flex: 6;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n}\n\n.bar-chart {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: 12px;\n height: 200px;\n padding-top: 24px;\n}\n.bar-column {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n height: 100%;\n position: relative;\n}\n.bar-count {\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-muted);\n margin-bottom: 4px;\n}\n.bar-fill {\n width: 100%;\n max-width: 40px;\n background: linear-gradient(180deg, var(--mj-brand-primary) 0%, var(--mj-color-accent-400) 100%);\n border-radius: 4px 4px 0 0;\n min-height: 2px;\n transition: height 0.3s ease;\n}\n.bar-day {\n font-size: 11px;\n color: var(--mj-text-disabled);\n margin-top: 6px;\n text-align: center;\n}\n\n/* Activity Feed Panel (right, 40%) */\n.feed-panel {\n flex: 4;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n max-height: 340px;\n overflow-y: auto;\n}\n\n.feed-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.feed-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 10px;\n border-radius: 6px;\n transition: background 0.15s;\n}\n.feed-item:hover {\n background: var(--mj-bg-page);\n}\n\n.feed-icon-green { color: var(--mj-color-success-600); }\n.feed-icon-red { color: var(--mj-color-error-600); }\n.feed-icon-amber { color: var(--mj-color-warning-600); }\n\n.feed-details {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.feed-name {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.feed-meta {\n font-size: 11px;\n color: var(--mj-text-disabled);\n}\n\n.feed-badge {\n font-size: 10px;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 10px;\n text-transform: uppercase;\n white-space: nowrap;\n flex-shrink: 0;\n}\n.feed-badge-green { background: var(--mj-status-success-bg); color: var(--mj-color-success-800); }\n.feed-badge-amber { background: var(--mj-color-warning-50); color: var(--mj-color-warning-800); }\n.feed-badge-red { background: var(--mj-status-error-bg); color: var(--mj-color-error-700); }\n\n.empty-hint {\n color: var(--mj-text-disabled);\n font-size: 13px;\n font-style: italic;\n}\n\n/* ==========================================================================\n Responsive\n ========================================================================== */\n@media (max-width: 1200px) {\n .pipeline-grid {\n grid-template-columns: repeat(2, 1fr);\n }\n .metric-strip {\n grid-template-columns: repeat(3, 1fr);\n }\n}\n\n@media (max-width: 900px) {\n .pipeline-grid {\n grid-template-columns: 1fr;\n }\n .metric-strip {\n grid-template-columns: repeat(2, 1fr);\n }\n .bottom-split {\n flex-direction: column;\n }\n .card-stats {\n grid-template-columns: repeat(2, 1fr);\n }\n}\n\n@media (max-width: 600px) {\n .overview {\n padding: 16px;\n }\n .metric-strip {\n grid-template-columns: 1fr;\n }\n}\n"] }]
618
+ args: [{ standalone: false, selector: 'app-integration-overview', template: "<div class=\"overview\">\n <!-- Notification Banner -->\n @if (Notification) {\n <div class=\"notification\" [class.notification-success]=\"Notification.Type === 'success'\"\n [class.notification-error]=\"Notification.Type === 'error'\">\n @if (Notification.Type === 'success') {\n <i class=\"fa-solid fa-circle-check\"></i>\n } @else {\n <i class=\"fa-solid fa-circle-xmark\"></i>\n }\n <span class=\"notification-message\">{{ Notification.Message }}</span>\n <button class=\"notification-dismiss\" (click)=\"DismissNotification()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n\n @if (IsLoading) {\n <mj-loading text=\"Loading integrations...\" size=\"medium\"></mj-loading>\n } @else if (Summaries.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-plug-circle-xmark\"></i>\n <h3>No Integrations Configured</h3>\n <p>Set up your first integration using the Connection Studio to start syncing data.</p>\n </div>\n } @else {\n <!-- ====================================================================\n SECTION 1: Metric Strip\n ==================================================================== -->\n <div class=\"metric-strip\">\n <!-- Total Pipelines -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-blue\">\n <i class=\"fa-solid fa-diagram-project\"></i>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ KPIs.TotalIntegrations }}</span>\n <span class=\"metric-label\">Total Pipelines</span>\n </div>\n </div>\n\n <!-- Records Today -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-green\">\n <i class=\"fa-solid fa-database\"></i>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ FormatNumber(KPIs.RecordsSyncedToday) }}</span>\n <span class=\"metric-label\">Records Today</span>\n </div>\n </div>\n\n <!-- Success Rate (with conic gradient ring) -->\n <div class=\"metric-card\">\n <div class=\"metric-ring\" [style.background]=\"SuccessRateGradient\">\n <div class=\"metric-ring-inner\">\n <span class=\"metric-ring-value\">{{ SuccessRate }}%</span>\n </div>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value metric-value-indigo\">{{ SuccessRate }}%</span>\n <span class=\"metric-label\">Success Rate</span>\n </div>\n </div>\n\n <!-- Active Now -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-emerald\">\n <i class=\"fa-solid fa-bolt\"></i>\n @if (ActiveCount > 0) {\n <span class=\"pulse-dot\"></span>\n }\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ ActiveCount }}</span>\n <span class=\"metric-label\">Active Now</span>\n </div>\n </div>\n\n <!-- Avg Duration -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-orange\">\n <i class=\"fa-solid fa-clock\"></i>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ FormatDuration(KPIs.AverageSyncDurationMs) }}</span>\n <span class=\"metric-label\">Avg Duration</span>\n </div>\n </div>\n </div>\n\n <!-- ====================================================================\n SECTION 2: Pipeline Health Grid\n ==================================================================== -->\n <div class=\"section-heading\">\n <h3><i class=\"fa-solid fa-heart-pulse\"></i> Pipeline Health</h3>\n <button class=\"refresh-btn\" (click)=\"Refresh()\">\n <i class=\"fa-solid fa-arrows-rotate\"></i> Refresh\n </button>\n </div>\n\n <div class=\"pipeline-grid\">\n @for (summary of Summaries; track summary.Integration.ID) {\n <div [class]=\"GetCardBorderClass(summary.StatusColor)\">\n <!-- Card Header -->\n <div class=\"card-header\">\n <div class=\"card-header-left\">\n <div class=\"card-icon-wrap\">\n <i [class]=\"GetIntegrationIcon(summary)\"></i>\n </div>\n <div class=\"card-title-wrap\">\n <span class=\"card-title\">{{ summary.Integration.Name }}</span>\n <span class=\"card-subtitle\">{{ summary.SourceType?.Name ?? 'Custom' }}</span>\n </div>\n </div>\n <div [class]=\"GetStatusDotClass(summary.StatusColor)\"\n [title]=\"GetStatusLabel(summary.StatusColor)\">\n @if (summary.LatestRun?.Status === 'In Progress') {\n <span class=\"dot-pulse\"></span>\n }\n </div>\n </div>\n\n <!-- Pipeline Flow Visual -->\n <div class=\"pipeline-flow\">\n <div class=\"flow-node\">\n <i [class]=\"GetIntegrationIcon(summary)\"></i>\n </div>\n <div class=\"flow-arrow\">\n <div class=\"flow-line\"></div>\n <span class=\"flow-count\">{{ GetEntityMapCount(summary.Integration.ID) }} maps</span>\n <div class=\"flow-line\"></div>\n </div>\n <div class=\"flow-node flow-node-mj\">\n <i class=\"fa-solid fa-layer-group\"></i>\n </div>\n </div>\n\n <!-- Stats Row -->\n <div class=\"card-stats\">\n <div class=\"stat-item\">\n <span class=\"stat-label\">Last sync</span>\n <span class=\"stat-value\">{{ summary.RelativeTime }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Records</span>\n <span class=\"stat-value\">{{ FormatNumber(summary.LatestRun?.TotalRecords ?? 0) }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Duration</span>\n <span class=\"stat-value\">{{ FormatDuration(summary.DurationMs) }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Errors</span>\n <span class=\"stat-value\" [class.stat-error]=\"summary.TotalErrors > 0\">\n {{ summary.TotalErrors }}\n </span>\n </div>\n </div>\n\n <!-- Sparkline (last 5 runs) -->\n <div class=\"sparkline-row\">\n <span class=\"sparkline-label\">Recent runs</span>\n <div class=\"sparkline-dots\">\n @for (run of summary.RecentRuns; track run.ID) {\n <span [class]=\"GetSparklineDotClass(run)\"\n [title]=\"run.Status + ' - ' + (run.StartedAt ?? 'N/A')\"></span>\n }\n @if (summary.RecentRuns.length === 0) {\n <span class=\"sparkline-none\">No runs</span>\n }\n </div>\n </div>\n\n <!-- Card Footer -->\n <div class=\"card-footer\">\n @if (IsRunning(summary.Integration.ID)) {\n <button class=\"btn-sync btn-sync-disabled\" disabled>\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Running...\n </button>\n } @else {\n <button class=\"btn-sync\"\n (click)=\"RunSync(summary.Integration.ID)\"\n [disabled]=\"!summary.Integration.IsActive || RunningIntegrationID !== null\">\n <i class=\"fa-solid fa-play\"></i> Sync Now\n </button>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- ====================================================================\n SECTION 3: Bottom - Bar Chart & Activity Feed\n ==================================================================== -->\n <div class=\"bottom-split\">\n <!-- Bar Chart (left, 60%) -->\n <div class=\"chart-panel\">\n <h3 class=\"panel-title\"><i class=\"fa-solid fa-chart-bar\"></i> Records Synced (7 days)</h3>\n @if (DailyCounts.length === 0) {\n <p class=\"empty-hint\">No data available.</p>\n } @else {\n <div class=\"bar-chart\">\n @for (day of DailyCounts; track day.Date) {\n <div class=\"bar-column\">\n <div class=\"bar-count\">{{ FormatNumber(day.Records) }}</div>\n <div class=\"bar-fill\" [style.height.%]=\"BarHeight(day.Records)\"></div>\n <div class=\"bar-day\">{{ day.Label }}</div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Activity Feed (right, 40%) -->\n <div class=\"feed-panel\">\n <h3 class=\"panel-title\"><i class=\"fa-solid fa-stream\"></i> Recent Activity</h3>\n @if (ActivityFeed.length === 0) {\n <p class=\"empty-hint\">No recent activity.</p>\n } @else {\n <div class=\"feed-list\">\n @for (item of ActivityFeed; track item.RunID) {\n <div class=\"feed-item\">\n <i [class]=\"ActivityStatusIcon(item.Status)\"\n [class.feed-icon-green]=\"item.StatusColor === 'green'\"\n [class.feed-icon-red]=\"item.StatusColor === 'red'\"\n [class.feed-icon-amber]=\"item.StatusColor === 'amber'\">\n </i>\n <div class=\"feed-details\">\n <span class=\"feed-name\">{{ item.IntegrationName }}</span>\n <span class=\"feed-meta\">{{ item.TotalRecords | number }} records &middot; {{ item.RelativeTime }}</span>\n </div>\n <span class=\"feed-badge\" [class]=\"'feed-badge-' + item.StatusColor\">\n {{ item.Status }}\n </span>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n</div>\n", styles: ["/* ==========================================================================\n Integration Overview - Root\n ========================================================================== */\n.overview {\n padding: 28px;\n max-width: 1440px;\n margin: 0 auto;\n background: var(--mj-bg-page);\n min-height: 100%;\n}\n\n/* ==========================================================================\n Notification Banner\n ========================================================================== */\n.notification {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 10px;\n margin-bottom: 20px;\n font-size: 13px;\n font-weight: 500;\n animation: slideDown 0.25s ease-out;\n}\n.notification i:first-child { font-size: 16px; }\n.notification-message { flex: 1; }\n.notification-success {\n background: var(--mj-status-success-bg);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-color-success-200);\n}\n.notification-error {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-color-error-200);\n}\n.notification-dismiss {\n background: none;\n border: none;\n cursor: pointer;\n color: inherit;\n opacity: 0.5;\n font-size: 14px;\n padding: 4px;\n line-height: 1;\n}\n.notification-dismiss:hover { opacity: 1; }\n\n@keyframes slideDown {\n from { opacity: 0; transform: translateY(-8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* ==========================================================================\n Empty State\n ========================================================================== */\n.empty-state {\n text-align: center;\n padding: 100px 20px;\n color: var(--mj-text-disabled);\n}\n.empty-state i {\n font-size: 64px;\n margin-bottom: 20px;\n display: block;\n color: var(--mj-color-neutral-300);\n}\n.empty-state h3 {\n margin: 0 0 8px 0;\n font-size: 20px;\n color: var(--mj-text-secondary);\n}\n.empty-state p {\n margin: 0;\n font-size: 14px;\n max-width: 400px;\n margin-inline: auto;\n}\n\n/* ==========================================================================\n SECTION 1: Metric Strip\n ========================================================================== */\n.metric-strip {\n display: grid;\n grid-template-columns: repeat(5, 1fr);\n gap: 16px;\n margin-bottom: 32px;\n}\n\n.metric-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 18px 16px;\n border-radius: 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n transition: box-shadow 0.2s, transform 0.2s;\n}\n.metric-card:hover {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n transform: translateY(-1px);\n}\n\n.metric-icon {\n position: relative;\n width: 44px;\n height: 44px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n flex-shrink: 0;\n}\n.metric-icon-blue { background: var(--mj-status-info-bg); color: var(--mj-brand-primary); }\n.metric-icon-green { background: var(--mj-status-success-bg); color: var(--mj-color-success-600); }\n.metric-icon-emerald { background: var(--mj-status-success-bg); color: var(--mj-color-success-600); }\n.metric-icon-orange { background: var(--mj-color-warning-50); color: var(--mj-color-warning-600); }\n\n.metric-body {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.metric-value {\n font-size: 22px;\n font-weight: 700;\n line-height: 1.2;\n color: var(--mj-text-primary);\n}\n.metric-value-indigo { color: var(--mj-color-indigo-500); }\n\n.metric-label {\n font-size: 11px;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.4px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Conic gradient ring for success rate */\n.metric-ring {\n width: 44px;\n height: 44px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n.metric-ring-inner {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: var(--mj-bg-surface);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.metric-ring-value {\n font-size: 8px;\n font-weight: 700;\n color: var(--mj-color-indigo-500);\n}\n\n/* Pulse dot for active syncs */\n.pulse-dot {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--mj-color-success-600);\n animation: pulse 1.5s ease-in-out infinite;\n}\n\n@keyframes pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(1.4); }\n}\n\n/* ==========================================================================\n SECTION 2: Pipeline Health Grid\n ========================================================================== */\n.section-heading {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n}\n.section-heading h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n.section-heading h3 i {\n margin-right: 8px;\n color: var(--mj-text-muted);\n}\n\n.refresh-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s, border-color 0.15s;\n}\n.refresh-btn:hover {\n background: var(--mj-status-info-bg);\n border-color: var(--mj-color-info-200);\n}\n\n.pipeline-grid {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 20px;\n margin-bottom: 32px;\n}\n\n.pipeline-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n transition: box-shadow 0.2s, transform 0.2s;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n.pipeline-card:hover {\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1);\n transform: translateY(-2px);\n}\n\n.pipeline-card-error {\n border-left: 3px solid var(--mj-status-error);\n}\n\n/* Card Header */\n.card-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n}\n.card-header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n.card-icon-wrap {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n background: var(--mj-status-info-bg);\n color: var(--mj-brand-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n flex-shrink: 0;\n}\n.card-title-wrap {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.card-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.card-subtitle {\n font-size: 11px;\n color: var(--mj-text-disabled);\n}\n\n/* Status Dot */\n.status-dot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n flex-shrink: 0;\n margin-top: 4px;\n position: relative;\n}\n.status-dot-green { background: var(--mj-color-success-600); }\n.status-dot-amber { background: var(--mj-status-warning); }\n.status-dot-red { background: var(--mj-status-error); }\n.status-dot-gray { background: var(--mj-color-neutral-300); }\n\n.dot-pulse {\n position: absolute;\n inset: -3px;\n border-radius: 50%;\n border: 2px solid var(--mj-status-warning);\n animation: dotPulse 1.5s ease-in-out infinite;\n}\n@keyframes dotPulse {\n 0%, 100% { opacity: 0.3; transform: scale(1); }\n 50% { opacity: 0; transform: scale(1.6); }\n}\n\n/* Pipeline Flow Visual */\n.pipeline-flow {\n display: flex;\n align-items: center;\n gap: 0;\n padding: 8px 0;\n}\n.flow-node {\n width: 36px;\n height: 36px;\n border-radius: 8px;\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n flex-shrink: 0;\n}\n.flow-node-mj {\n background: var(--mj-status-info-bg);\n color: var(--mj-brand-primary);\n}\n.flow-arrow {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 0;\n padding: 0 4px;\n}\n.flow-line {\n flex: 1;\n height: 2px;\n background: var(--mj-border-default);\n}\n.flow-count {\n font-size: 10px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n padding: 2px 8px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n font-weight: 500;\n}\n\n/* Card Stats */\n.card-stats {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 8px;\n}\n.stat-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n}\n.stat-label {\n font-size: 10px;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n margin-bottom: 2px;\n}\n.stat-value {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n.stat-error {\n color: var(--mj-status-error);\n}\n\n/* Sparkline Row */\n.sparkline-row {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.sparkline-label {\n font-size: 10px;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n white-space: nowrap;\n}\n.sparkline-dots {\n display: flex;\n align-items: center;\n gap: 5px;\n}\n.spark-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n display: inline-block;\n}\n.spark-green { background: var(--mj-color-success-600); }\n.spark-red { background: var(--mj-status-error); }\n.spark-amber { background: var(--mj-status-warning); }\n.spark-gray { background: var(--mj-color-neutral-300); }\n.sparkline-none {\n font-size: 10px;\n color: var(--mj-color-neutral-300);\n font-style: italic;\n}\n\n/* Card Footer */\n.card-footer {\n display: flex;\n justify-content: flex-end;\n padding-top: 4px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.btn-sync {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s, color 0.15s, border-color 0.15s;\n}\n.btn-sync:hover:not(:disabled) {\n background: var(--mj-status-info-bg);\n border-color: var(--mj-color-info-200);\n}\n.btn-sync:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.btn-sync-disabled {\n color: var(--mj-text-disabled);\n border-color: var(--mj-border-default);\n}\n\n/* ==========================================================================\n SECTION 3: Bottom Split - Chart + Feed\n ========================================================================== */\n.bottom-split {\n display: flex;\n gap: 20px;\n}\n\n.panel-title {\n margin: 0 0 16px 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n.panel-title i {\n margin-right: 8px;\n color: var(--mj-text-muted);\n}\n\n/* Bar Chart Panel (left, 60%) */\n.chart-panel {\n flex: 6;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n}\n\n.bar-chart {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: 12px;\n height: 200px;\n padding-top: 24px;\n}\n.bar-column {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n height: 100%;\n position: relative;\n}\n.bar-count {\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-muted);\n margin-bottom: 4px;\n}\n.bar-fill {\n width: 100%;\n max-width: 40px;\n background: linear-gradient(180deg, var(--mj-brand-primary) 0%, var(--mj-color-accent-400) 100%);\n border-radius: 4px 4px 0 0;\n min-height: 2px;\n transition: height 0.3s ease;\n}\n.bar-day {\n font-size: 11px;\n color: var(--mj-text-disabled);\n margin-top: 6px;\n text-align: center;\n}\n\n/* Activity Feed Panel (right, 40%) */\n.feed-panel {\n flex: 4;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n max-height: 340px;\n overflow-y: auto;\n}\n\n.feed-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.feed-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 10px;\n border-radius: 6px;\n transition: background 0.15s;\n}\n.feed-item:hover {\n background: var(--mj-bg-page);\n}\n\n.feed-icon-green { color: var(--mj-color-success-600); }\n.feed-icon-red { color: var(--mj-color-error-600); }\n.feed-icon-amber { color: var(--mj-color-warning-600); }\n\n.feed-details {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.feed-name {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.feed-meta {\n font-size: 11px;\n color: var(--mj-text-disabled);\n}\n\n.feed-badge {\n font-size: 10px;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 10px;\n text-transform: uppercase;\n white-space: nowrap;\n flex-shrink: 0;\n}\n.feed-badge-green { background: var(--mj-status-success-bg); color: var(--mj-color-success-800); }\n.feed-badge-amber { background: var(--mj-color-warning-50); color: var(--mj-color-warning-800); }\n.feed-badge-red { background: var(--mj-status-error-bg); color: var(--mj-status-error); }\n\n.empty-hint {\n color: var(--mj-text-disabled);\n font-size: 13px;\n font-style: italic;\n}\n\n/* ==========================================================================\n Responsive\n ========================================================================== */\n@media (max-width: 1200px) {\n .pipeline-grid {\n grid-template-columns: repeat(2, 1fr);\n }\n .metric-strip {\n grid-template-columns: repeat(3, 1fr);\n }\n}\n\n@media (max-width: 900px) {\n .pipeline-grid {\n grid-template-columns: 1fr;\n }\n .metric-strip {\n grid-template-columns: repeat(2, 1fr);\n }\n .bottom-split {\n flex-direction: column;\n }\n .card-stats {\n grid-template-columns: repeat(2, 1fr);\n }\n}\n\n@media (max-width: 600px) {\n .overview {\n padding: 16px;\n }\n .metric-strip {\n grid-template-columns: 1fr;\n }\n}\n"] }]
622
619
  }], null, null); })();
623
620
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(OverviewComponent, { className: "OverviewComponent", filePath: "src/Integration/components/overview/overview.component.ts", lineNumber: 30 }); })();
624
621
  export function LoadOverviewComponent() {
@@ -1 +1 @@
1
- {"version":3,"file":"overview.component.js","sourceRoot":"","sources":["../../../../src/Integration/components/overview/overview.component.ts","../../../../src/Integration/components/overview/overview.component.html"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectorRef, Component, OnInit, OnDestroy, inject } from '@angular/core';\nimport { RegisterClass, UUIDsEqual } from '@memberjunction/global';\nimport { RunView, IRunViewProvider } from '@memberjunction/core';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { ResourceData } from '@memberjunction/core-entities';\nimport {\n IntegrationDataService,\n ResolveIntegrationIcon,\n IntegrationSummary,\n IntegrationKPIs,\n ActivityFeedItem,\n DailyRecordCount,\n EntityMapRow\n} from '../../services/integration-data.service';\n\ntype StatusColorType = 'green' | 'amber' | 'red' | 'gray';\n\ninterface NotificationBanner {\n Type: 'success' | 'error';\n Message: string;\n}\n\n@RegisterClass(BaseResourceComponent, 'IntegrationOverview')\n@Component({\n standalone: false,\n selector: 'app-integration-overview',\n templateUrl: './overview.component.html',\n styleUrls: ['./overview.component.css']\n})\nexport class OverviewComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n\n Summaries: IntegrationSummary[] = [];\n KPIs: IntegrationKPIs = {\n TotalIntegrations: 0,\n ActiveSyncs: 0,\n RecordsSyncedToday: 0,\n ErrorRate: 0,\n AverageSyncDurationMs: null\n };\n ActivityFeed: ActivityFeedItem[] = [];\n DailyCounts: DailyRecordCount[] = [];\n EntityMapCounts: Map<string, number> = new Map();\n\n IsLoading = false;\n RunningIntegrationID: string | null = null;\n Notification: NotificationBanner | null = null;\n\n private dataService = inject(IntegrationDataService);\n private cdr = inject(ChangeDetectorRef);\n private notificationTimer: ReturnType<typeof setTimeout> | null = null;\n\n async ngOnInit(): Promise<void> {\n await this.LoadData();\n }\n\n ngOnDestroy(): void {\n this.clearNotificationTimer();\n }\n\n // ---------------------------------------------------------------------------\n // Data Loading\n // ---------------------------------------------------------------------------\n\n async LoadData(): Promise<void> {\n this.IsLoading = true;\n this.cdr.detectChanges();\n try {\n const provider = this.RunViewToUse;\n const [summaries, activityFeed, dailyCounts] = await Promise.all([\n this.dataService.LoadIntegrationSummaries(provider),\n this.dataService.LoadRecentRuns(10, provider),\n this.dataService.LoadDailyRecordCounts(7, provider)\n ]);\n this.Summaries = summaries;\n this.KPIs = this.dataService.ComputeKPIs(summaries);\n this.ActivityFeed = activityFeed;\n this.DailyCounts = dailyCounts;\n await this.loadEntityMapCounts(summaries, provider);\n } catch (err) {\n console.error('[IntegrationOverview] Failed to load data:', err);\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n async Refresh(): Promise<void> {\n await this.LoadData();\n }\n\n // ---------------------------------------------------------------------------\n // Sync Actions\n // ---------------------------------------------------------------------------\n\n async RunSync(integrationID: string): Promise<void> {\n if (this.RunningIntegrationID) return;\n this.RunningIntegrationID = integrationID;\n this.dismissNotification();\n this.cdr.detectChanges();\n\n try {\n const result = await this.dataService.RunSync(integrationID);\n if (result.Success) {\n this.showNotification('success', result.Message || 'Sync started successfully');\n await this.LoadData();\n } else {\n this.showNotification('error', result.Message || 'Sync failed');\n }\n } catch (err) {\n const error = err as Error;\n this.showNotification('error', `Unexpected error: ${error.message}`);\n console.error('[IntegrationOverview] RunSync error:', err);\n } finally {\n this.RunningIntegrationID = null;\n this.cdr.detectChanges();\n }\n }\n\n IsRunning(integrationID: string): boolean {\n return UUIDsEqual(this.RunningIntegrationID, integrationID);\n }\n\n // ---------------------------------------------------------------------------\n // KPI Helpers\n // ---------------------------------------------------------------------------\n\n get SuccessRate(): number {\n if (this.KPIs.ErrorRate == null) return 100;\n return Math.round((100 - this.KPIs.ErrorRate) * 10) / 10;\n }\n\n get SuccessRateGradient(): string {\n const pct = this.SuccessRate;\n const angle = (pct / 100) * 360;\n return `conic-gradient(#10b981 ${angle}deg, #e5e7eb ${angle}deg)`;\n }\n\n get ActiveCount(): number {\n return this.KPIs.ActiveSyncs;\n }\n\n FormatDuration(ms: number | null): string {\n return this.dataService.FormatDuration(ms);\n }\n\n FormatNumber(value: number): string {\n if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}M`;\n if (value >= 1_000) return `${(value / 1_000).toFixed(1)}K`;\n return value.toLocaleString();\n }\n\n // ---------------------------------------------------------------------------\n // Pipeline Card Helpers\n // ---------------------------------------------------------------------------\n\n GetIntegrationIcon(summary: IntegrationSummary): string {\n if (summary.SourceType?.IconClass) {\n return summary.SourceType.IconClass;\n }\n return this.resolveIconByName(summary.Integration.Integration ?? summary.Integration.Name);\n }\n\n GetStatusDotClass(color: StatusColorType): string {\n return `status-dot status-dot-${color}`;\n }\n\n GetStatusLabel(color: StatusColorType): string {\n if (color === 'green') return 'Healthy';\n if (color === 'amber') return 'Warning';\n if (color === 'red') return 'Error';\n return 'Inactive';\n }\n\n GetEntityMapCount(integrationID: string): number {\n for (const [key, value] of this.EntityMapCounts) {\n if (UUIDsEqual(key, integrationID)) return value;\n }\n return 0;\n }\n\n GetSparklineDotClass(run: { Status: string }): string {\n if (run.Status === 'Success') return 'spark-dot spark-green';\n if (run.Status === 'Failed') return 'spark-dot spark-red';\n if (run.Status === 'In Progress' || run.Status === 'Pending') return 'spark-dot spark-amber';\n return 'spark-dot spark-gray';\n }\n\n GetCardBorderClass(color: StatusColorType): string {\n return color === 'red' ? 'pipeline-card pipeline-card-error' : 'pipeline-card';\n }\n\n // ---------------------------------------------------------------------------\n // Bar Chart Helpers\n // ---------------------------------------------------------------------------\n\n get MaxDailyRecords(): number {\n if (this.DailyCounts.length === 0) return 1;\n const maxVal = Math.max(...this.DailyCounts.map(d => d.Records));\n return maxVal > 0 ? maxVal : 1;\n }\n\n BarHeight(records: number): number {\n return Math.max((records / this.MaxDailyRecords) * 100, 2);\n }\n\n // ---------------------------------------------------------------------------\n // Activity Feed Helpers\n // ---------------------------------------------------------------------------\n\n ActivityStatusIcon(status: string): string {\n if (status === 'Success') return 'fa-solid fa-circle-check';\n if (status === 'Failed') return 'fa-solid fa-circle-xmark';\n if (status === 'In Progress') return 'fa-solid fa-spinner fa-spin';\n return 'fa-solid fa-clock';\n }\n\n // ---------------------------------------------------------------------------\n // Notification Management\n // ---------------------------------------------------------------------------\n\n DismissNotification(): void {\n this.dismissNotification();\n this.cdr.detectChanges();\n }\n\n // ---------------------------------------------------------------------------\n // Resource Overrides\n // ---------------------------------------------------------------------------\n\n async GetResourceDisplayName(_data: ResourceData): Promise<string> {\n return 'Overview';\n }\n\n async GetResourceIconClass(_data: ResourceData): Promise<string> {\n return 'fa-solid fa-gauge-high';\n }\n\n // ---------------------------------------------------------------------------\n // Private Helpers\n // ---------------------------------------------------------------------------\n\n private async loadEntityMapCounts(\n summaries: IntegrationSummary[],\n provider: IRunViewProvider | null\n ): Promise<void> {\n if (summaries.length === 0) return;\n const allMaps = await this.loadAllEntityMaps(provider);\n this.EntityMapCounts = this.countMapsByIntegration(allMaps);\n }\n\n private async loadAllEntityMaps(\n provider: IRunViewProvider | null\n ): Promise<EntityMapRow[]> {\n const rv = new RunView(provider ?? null);\n const result = await rv.RunView<EntityMapRow>({\n EntityName: 'MJ: Company Integration Entity Maps',\n ExtraFilter: '',\n OrderBy: 'CompanyIntegrationID',\n Fields: ['ID', 'CompanyIntegrationID'],\n ResultType: 'simple'\n });\n return result.Results;\n }\n\n private countMapsByIntegration(maps: EntityMapRow[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const map of maps) {\n const current = counts.get(map.CompanyIntegrationID) ?? 0;\n counts.set(map.CompanyIntegrationID, current + 1);\n }\n return counts;\n }\n\n private resolveIconByName(name: string): string {\n return ResolveIntegrationIcon(name);\n }\n\n private showNotification(type: 'success' | 'error', message: string): void {\n this.clearNotificationTimer();\n this.Notification = { Type: type, Message: message };\n this.notificationTimer = setTimeout(() => {\n this.Notification = null;\n this.cdr.detectChanges();\n }, 5000);\n }\n\n private dismissNotification(): void {\n this.clearNotificationTimer();\n this.Notification = null;\n }\n\n private clearNotificationTimer(): void {\n if (this.notificationTimer) {\n clearTimeout(this.notificationTimer);\n this.notificationTimer = null;\n }\n }\n}\n\nexport function LoadOverviewComponent(): void {\n // Tree-shaking prevention: importing this module causes\n // @RegisterClass decorators to fire, registering components.\n}\n","<div class=\"overview\">\n <!-- Notification Banner -->\n @if (Notification) {\n <div class=\"notification\" [class.notification-success]=\"Notification.Type === 'success'\"\n [class.notification-error]=\"Notification.Type === 'error'\">\n @if (Notification.Type === 'success') {\n <i class=\"fa-solid fa-circle-check\"></i>\n } @else {\n <i class=\"fa-solid fa-circle-xmark\"></i>\n }\n <span class=\"notification-message\">{{ Notification.Message }}</span>\n <button class=\"notification-dismiss\" (click)=\"DismissNotification()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n\n @if (IsLoading) {\n <mj-loading text=\"Loading integrations...\" size=\"medium\"></mj-loading>\n } @else if (Summaries.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-plug-circle-xmark\"></i>\n <h3>No Integrations Configured</h3>\n <p>Set up your first integration using the Connection Studio to start syncing data.</p>\n </div>\n } @else {\n <!-- ====================================================================\n SECTION 1: Metric Strip\n ==================================================================== -->\n <div class=\"metric-strip\">\n <!-- Total Pipelines -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-blue\">\n <i class=\"fa-solid fa-diagram-project\"></i>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ KPIs.TotalIntegrations }}</span>\n <span class=\"metric-label\">Total Pipelines</span>\n </div>\n </div>\n\n <!-- Records Today -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-green\">\n <i class=\"fa-solid fa-database\"></i>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ FormatNumber(KPIs.RecordsSyncedToday) }}</span>\n <span class=\"metric-label\">Records Today</span>\n </div>\n </div>\n\n <!-- Success Rate (with conic gradient ring) -->\n <div class=\"metric-card\">\n <div class=\"metric-ring\" [style.background]=\"SuccessRateGradient\">\n <div class=\"metric-ring-inner\">\n <span class=\"metric-ring-value\">{{ SuccessRate }}%</span>\n </div>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value metric-value-indigo\">{{ SuccessRate }}%</span>\n <span class=\"metric-label\">Success Rate</span>\n </div>\n </div>\n\n <!-- Active Now -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-emerald\">\n <i class=\"fa-solid fa-bolt\"></i>\n @if (ActiveCount > 0) {\n <span class=\"pulse-dot\"></span>\n }\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ ActiveCount }}</span>\n <span class=\"metric-label\">Active Now</span>\n </div>\n </div>\n\n <!-- Avg Duration -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-orange\">\n <i class=\"fa-solid fa-clock\"></i>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ FormatDuration(KPIs.AverageSyncDurationMs) }}</span>\n <span class=\"metric-label\">Avg Duration</span>\n </div>\n </div>\n </div>\n\n <!-- ====================================================================\n SECTION 2: Pipeline Health Grid\n ==================================================================== -->\n <div class=\"section-heading\">\n <h3><i class=\"fa-solid fa-heart-pulse\"></i> Pipeline Health</h3>\n <button class=\"refresh-btn\" (click)=\"Refresh()\">\n <i class=\"fa-solid fa-arrows-rotate\"></i> Refresh\n </button>\n </div>\n\n <div class=\"pipeline-grid\">\n @for (summary of Summaries; track summary.Integration.ID) {\n <div [class]=\"GetCardBorderClass(summary.StatusColor)\">\n <!-- Card Header -->\n <div class=\"card-header\">\n <div class=\"card-header-left\">\n <div class=\"card-icon-wrap\">\n <i [class]=\"GetIntegrationIcon(summary)\"></i>\n </div>\n <div class=\"card-title-wrap\">\n <span class=\"card-title\">{{ summary.Integration.Name }}</span>\n <span class=\"card-subtitle\">{{ summary.SourceType?.Name ?? 'Custom' }}</span>\n </div>\n </div>\n <div [class]=\"GetStatusDotClass(summary.StatusColor)\"\n [title]=\"GetStatusLabel(summary.StatusColor)\">\n @if (summary.LatestRun?.Status === 'In Progress') {\n <span class=\"dot-pulse\"></span>\n }\n </div>\n </div>\n\n <!-- Pipeline Flow Visual -->\n <div class=\"pipeline-flow\">\n <div class=\"flow-node\">\n <i [class]=\"GetIntegrationIcon(summary)\"></i>\n </div>\n <div class=\"flow-arrow\">\n <div class=\"flow-line\"></div>\n <span class=\"flow-count\">{{ GetEntityMapCount(summary.Integration.ID) }} maps</span>\n <div class=\"flow-line\"></div>\n </div>\n <div class=\"flow-node flow-node-mj\">\n <i class=\"fa-solid fa-layer-group\"></i>\n </div>\n </div>\n\n <!-- Stats Row -->\n <div class=\"card-stats\">\n <div class=\"stat-item\">\n <span class=\"stat-label\">Last sync</span>\n <span class=\"stat-value\">{{ summary.RelativeTime }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Records</span>\n <span class=\"stat-value\">{{ FormatNumber(summary.LatestRun?.TotalRecords ?? 0) }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Duration</span>\n <span class=\"stat-value\">{{ FormatDuration(summary.DurationMs) }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Errors</span>\n <span class=\"stat-value\" [class.stat-error]=\"summary.TotalErrors > 0\">\n {{ summary.TotalErrors }}\n </span>\n </div>\n </div>\n\n <!-- Sparkline (last 5 runs) -->\n <div class=\"sparkline-row\">\n <span class=\"sparkline-label\">Recent runs</span>\n <div class=\"sparkline-dots\">\n @for (run of summary.RecentRuns; track run.ID) {\n <span [class]=\"GetSparklineDotClass(run)\"\n [title]=\"run.Status + ' - ' + (run.StartedAt ?? 'N/A')\"></span>\n }\n @if (summary.RecentRuns.length === 0) {\n <span class=\"sparkline-none\">No runs</span>\n }\n </div>\n </div>\n\n <!-- Card Footer -->\n <div class=\"card-footer\">\n @if (IsRunning(summary.Integration.ID)) {\n <button class=\"btn-sync btn-sync-disabled\" disabled>\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Running...\n </button>\n } @else {\n <button class=\"btn-sync\"\n (click)=\"RunSync(summary.Integration.ID)\"\n [disabled]=\"!summary.Integration.IsActive || RunningIntegrationID !== null\">\n <i class=\"fa-solid fa-play\"></i> Sync Now\n </button>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- ====================================================================\n SECTION 3: Bottom - Bar Chart & Activity Feed\n ==================================================================== -->\n <div class=\"bottom-split\">\n <!-- Bar Chart (left, 60%) -->\n <div class=\"chart-panel\">\n <h3 class=\"panel-title\"><i class=\"fa-solid fa-chart-bar\"></i> Records Synced (7 days)</h3>\n @if (DailyCounts.length === 0) {\n <p class=\"empty-hint\">No data available.</p>\n } @else {\n <div class=\"bar-chart\">\n @for (day of DailyCounts; track day.Date) {\n <div class=\"bar-column\">\n <div class=\"bar-count\">{{ FormatNumber(day.Records) }}</div>\n <div class=\"bar-fill\" [style.height.%]=\"BarHeight(day.Records)\"></div>\n <div class=\"bar-day\">{{ day.Label }}</div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Activity Feed (right, 40%) -->\n <div class=\"feed-panel\">\n <h3 class=\"panel-title\"><i class=\"fa-solid fa-stream\"></i> Recent Activity</h3>\n @if (ActivityFeed.length === 0) {\n <p class=\"empty-hint\">No recent activity.</p>\n } @else {\n <div class=\"feed-list\">\n @for (item of ActivityFeed; track item.RunID) {\n <div class=\"feed-item\">\n <i [class]=\"ActivityStatusIcon(item.Status)\"\n [class.feed-icon-green]=\"item.StatusColor === 'green'\"\n [class.feed-icon-red]=\"item.StatusColor === 'red'\"\n [class.feed-icon-amber]=\"item.StatusColor === 'amber'\">\n </i>\n <div class=\"feed-details\">\n <span class=\"feed-name\">{{ item.IntegrationName }}</span>\n <span class=\"feed-meta\">{{ item.TotalRecords | number }} records &middot; {{ item.RelativeTime }}</span>\n </div>\n <span class=\"feed-badge\" [class]=\"'feed-badge-' + item.StatusColor\">\n {{ item.Status }}\n </span>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n</div>\n"]}
1
+ {"version":3,"file":"overview.component.js","sourceRoot":"","sources":["../../../../src/Integration/components/overview/overview.component.ts","../../../../src/Integration/components/overview/overview.component.html"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectorRef, Component, OnInit, OnDestroy, inject } from '@angular/core';\nimport { RegisterClass, UUIDsEqual } from '@memberjunction/global';\nimport { RunView, IRunViewProvider } from '@memberjunction/core';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { ResourceData } from '@memberjunction/core-entities';\nimport {\n IntegrationDataService,\n ResolveIntegrationIcon,\n IntegrationSummary,\n IntegrationKPIs,\n ActivityFeedItem,\n DailyRecordCount,\n EntityMapRow\n} from '../../services/integration-data.service';\n\ntype StatusColorType = 'green' | 'amber' | 'red' | 'gray';\n\ninterface NotificationBanner {\n Type: 'success' | 'error';\n Message: string;\n}\n\n@RegisterClass(BaseResourceComponent, 'IntegrationOverview')\n@Component({\n standalone: false,\n selector: 'app-integration-overview',\n templateUrl: './overview.component.html',\n styleUrls: ['./overview.component.css']\n})\nexport class OverviewComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n\n Summaries: IntegrationSummary[] = [];\n KPIs: IntegrationKPIs = {\n TotalIntegrations: 0,\n ActiveSyncs: 0,\n RecordsSyncedToday: 0,\n ErrorRate: 0,\n AverageSyncDurationMs: null\n };\n ActivityFeed: ActivityFeedItem[] = [];\n DailyCounts: DailyRecordCount[] = [];\n EntityMapCounts: Map<string, number> = new Map();\n\n IsLoading = false;\n RunningIntegrationID: string | null = null;\n Notification: NotificationBanner | null = null;\n\n private dataService = inject(IntegrationDataService);\n private cdr = inject(ChangeDetectorRef);\n private notificationTimer: ReturnType<typeof setTimeout> | null = null;\n\n async ngOnInit(): Promise<void> {\n await this.LoadData();\n }\n\n ngOnDestroy(): void {\n this.clearNotificationTimer();\n }\n\n // ---------------------------------------------------------------------------\n // Data Loading\n // ---------------------------------------------------------------------------\n\n async LoadData(): Promise<void> {\n this.IsLoading = true;\n this.cdr.detectChanges();\n try {\n const provider = this.RunViewToUse;\n const [summaries, activityFeed, dailyCounts] = await Promise.all([\n this.dataService.LoadIntegrationSummaries(provider),\n this.dataService.LoadRecentRuns(10, provider),\n this.dataService.LoadDailyRecordCounts(7, provider)\n ]);\n this.Summaries = summaries;\n this.KPIs = this.dataService.ComputeKPIs(summaries);\n this.ActivityFeed = activityFeed;\n this.DailyCounts = dailyCounts;\n await this.loadEntityMapCounts(summaries, provider);\n } catch (err) {\n console.error('[IntegrationOverview] Failed to load data:', err);\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n async Refresh(): Promise<void> {\n await this.LoadData();\n }\n\n // ---------------------------------------------------------------------------\n // Sync Actions\n // ---------------------------------------------------------------------------\n\n async RunSync(integrationID: string): Promise<void> {\n if (this.RunningIntegrationID) return;\n this.RunningIntegrationID = integrationID;\n this.dismissNotification();\n this.cdr.detectChanges();\n\n try {\n const result = await this.dataService.RunSync(integrationID);\n if (result.Success) {\n this.showNotification('success', result.Message || 'Sync started successfully');\n await this.LoadData();\n } else {\n this.showNotification('error', result.Message || 'Sync failed');\n }\n } catch (err) {\n const error = err as Error;\n this.showNotification('error', `Unexpected error: ${error.message}`);\n console.error('[IntegrationOverview] RunSync error:', err);\n } finally {\n this.RunningIntegrationID = null;\n this.cdr.detectChanges();\n }\n }\n\n IsRunning(integrationID: string): boolean {\n return UUIDsEqual(this.RunningIntegrationID, integrationID);\n }\n\n // ---------------------------------------------------------------------------\n // KPI Helpers\n // ---------------------------------------------------------------------------\n\n get SuccessRate(): number {\n if (this.KPIs.ErrorRate == null) return 100;\n return Math.round((100 - this.KPIs.ErrorRate) * 10) / 10;\n }\n\n get SuccessRateGradient(): string {\n const pct = this.SuccessRate;\n const angle = (pct / 100) * 360;\n return `conic-gradient(#10b981 ${angle}deg, #e5e7eb ${angle}deg)`;\n }\n\n get ActiveCount(): number {\n return this.KPIs.ActiveSyncs;\n }\n\n FormatDuration(ms: number | null): string {\n return this.dataService.FormatDuration(ms);\n }\n\n FormatNumber(value: number): string {\n if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}M`;\n if (value >= 1_000) return `${(value / 1_000).toFixed(1)}K`;\n return value.toLocaleString();\n }\n\n // ---------------------------------------------------------------------------\n // Pipeline Card Helpers\n // ---------------------------------------------------------------------------\n\n GetIntegrationIcon(summary: IntegrationSummary): string {\n if (summary.SourceType?.IconClass) {\n return summary.SourceType.IconClass;\n }\n return ResolveIntegrationIcon(\n summary.Integration.Integration ?? summary.Integration.Name,\n summary.Icon\n );\n }\n\n GetStatusDotClass(color: StatusColorType): string {\n return `status-dot status-dot-${color}`;\n }\n\n GetStatusLabel(color: StatusColorType): string {\n if (color === 'green') return 'Healthy';\n if (color === 'amber') return 'Warning';\n if (color === 'red') return 'Error';\n return 'Inactive';\n }\n\n GetEntityMapCount(integrationID: string): number {\n for (const [key, value] of this.EntityMapCounts) {\n if (UUIDsEqual(key, integrationID)) return value;\n }\n return 0;\n }\n\n GetSparklineDotClass(run: { Status: string }): string {\n if (run.Status === 'Success') return 'spark-dot spark-green';\n if (run.Status === 'Failed') return 'spark-dot spark-red';\n if (run.Status === 'In Progress' || run.Status === 'Pending') return 'spark-dot spark-amber';\n return 'spark-dot spark-gray';\n }\n\n GetCardBorderClass(color: StatusColorType): string {\n return color === 'red' ? 'pipeline-card pipeline-card-error' : 'pipeline-card';\n }\n\n // ---------------------------------------------------------------------------\n // Bar Chart Helpers\n // ---------------------------------------------------------------------------\n\n get MaxDailyRecords(): number {\n if (this.DailyCounts.length === 0) return 1;\n const maxVal = Math.max(...this.DailyCounts.map(d => d.Records));\n return maxVal > 0 ? maxVal : 1;\n }\n\n BarHeight(records: number): number {\n return Math.max((records / this.MaxDailyRecords) * 100, 2);\n }\n\n // ---------------------------------------------------------------------------\n // Activity Feed Helpers\n // ---------------------------------------------------------------------------\n\n ActivityStatusIcon(status: string): string {\n if (status === 'Success') return 'fa-solid fa-circle-check';\n if (status === 'Failed') return 'fa-solid fa-circle-xmark';\n if (status === 'In Progress') return 'fa-solid fa-spinner fa-spin';\n return 'fa-solid fa-clock';\n }\n\n // ---------------------------------------------------------------------------\n // Notification Management\n // ---------------------------------------------------------------------------\n\n DismissNotification(): void {\n this.dismissNotification();\n this.cdr.detectChanges();\n }\n\n // ---------------------------------------------------------------------------\n // Resource Overrides\n // ---------------------------------------------------------------------------\n\n async GetResourceDisplayName(_data: ResourceData): Promise<string> {\n return 'Overview';\n }\n\n async GetResourceIconClass(_data: ResourceData): Promise<string> {\n return 'fa-solid fa-gauge-high';\n }\n\n // ---------------------------------------------------------------------------\n // Private Helpers\n // ---------------------------------------------------------------------------\n\n private async loadEntityMapCounts(\n summaries: IntegrationSummary[],\n provider: IRunViewProvider | null\n ): Promise<void> {\n if (summaries.length === 0) return;\n const allMaps = await this.loadAllEntityMaps(provider);\n this.EntityMapCounts = this.countMapsByIntegration(allMaps);\n }\n\n private async loadAllEntityMaps(\n provider: IRunViewProvider | null\n ): Promise<EntityMapRow[]> {\n const rv = new RunView(provider ?? null);\n const result = await rv.RunView<EntityMapRow>({\n EntityName: 'MJ: Company Integration Entity Maps',\n ExtraFilter: '',\n OrderBy: 'CompanyIntegrationID',\n Fields: ['ID', 'CompanyIntegrationID'],\n ResultType: 'simple'\n });\n return result.Results;\n }\n\n private countMapsByIntegration(maps: EntityMapRow[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const map of maps) {\n const current = counts.get(map.CompanyIntegrationID) ?? 0;\n counts.set(map.CompanyIntegrationID, current + 1);\n }\n return counts;\n }\n\n\n private showNotification(type: 'success' | 'error', message: string): void {\n this.clearNotificationTimer();\n this.Notification = { Type: type, Message: message };\n this.notificationTimer = setTimeout(() => {\n this.Notification = null;\n this.cdr.detectChanges();\n }, 5000);\n }\n\n private dismissNotification(): void {\n this.clearNotificationTimer();\n this.Notification = null;\n }\n\n private clearNotificationTimer(): void {\n if (this.notificationTimer) {\n clearTimeout(this.notificationTimer);\n this.notificationTimer = null;\n }\n }\n}\n\nexport function LoadOverviewComponent(): void {\n // Tree-shaking prevention: importing this module causes\n // @RegisterClass decorators to fire, registering components.\n}\n","<div class=\"overview\">\n <!-- Notification Banner -->\n @if (Notification) {\n <div class=\"notification\" [class.notification-success]=\"Notification.Type === 'success'\"\n [class.notification-error]=\"Notification.Type === 'error'\">\n @if (Notification.Type === 'success') {\n <i class=\"fa-solid fa-circle-check\"></i>\n } @else {\n <i class=\"fa-solid fa-circle-xmark\"></i>\n }\n <span class=\"notification-message\">{{ Notification.Message }}</span>\n <button class=\"notification-dismiss\" (click)=\"DismissNotification()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n\n @if (IsLoading) {\n <mj-loading text=\"Loading integrations...\" size=\"medium\"></mj-loading>\n } @else if (Summaries.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-plug-circle-xmark\"></i>\n <h3>No Integrations Configured</h3>\n <p>Set up your first integration using the Connection Studio to start syncing data.</p>\n </div>\n } @else {\n <!-- ====================================================================\n SECTION 1: Metric Strip\n ==================================================================== -->\n <div class=\"metric-strip\">\n <!-- Total Pipelines -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-blue\">\n <i class=\"fa-solid fa-diagram-project\"></i>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ KPIs.TotalIntegrations }}</span>\n <span class=\"metric-label\">Total Pipelines</span>\n </div>\n </div>\n\n <!-- Records Today -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-green\">\n <i class=\"fa-solid fa-database\"></i>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ FormatNumber(KPIs.RecordsSyncedToday) }}</span>\n <span class=\"metric-label\">Records Today</span>\n </div>\n </div>\n\n <!-- Success Rate (with conic gradient ring) -->\n <div class=\"metric-card\">\n <div class=\"metric-ring\" [style.background]=\"SuccessRateGradient\">\n <div class=\"metric-ring-inner\">\n <span class=\"metric-ring-value\">{{ SuccessRate }}%</span>\n </div>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value metric-value-indigo\">{{ SuccessRate }}%</span>\n <span class=\"metric-label\">Success Rate</span>\n </div>\n </div>\n\n <!-- Active Now -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-emerald\">\n <i class=\"fa-solid fa-bolt\"></i>\n @if (ActiveCount > 0) {\n <span class=\"pulse-dot\"></span>\n }\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ ActiveCount }}</span>\n <span class=\"metric-label\">Active Now</span>\n </div>\n </div>\n\n <!-- Avg Duration -->\n <div class=\"metric-card\">\n <div class=\"metric-icon metric-icon-orange\">\n <i class=\"fa-solid fa-clock\"></i>\n </div>\n <div class=\"metric-body\">\n <span class=\"metric-value\">{{ FormatDuration(KPIs.AverageSyncDurationMs) }}</span>\n <span class=\"metric-label\">Avg Duration</span>\n </div>\n </div>\n </div>\n\n <!-- ====================================================================\n SECTION 2: Pipeline Health Grid\n ==================================================================== -->\n <div class=\"section-heading\">\n <h3><i class=\"fa-solid fa-heart-pulse\"></i> Pipeline Health</h3>\n <button class=\"refresh-btn\" (click)=\"Refresh()\">\n <i class=\"fa-solid fa-arrows-rotate\"></i> Refresh\n </button>\n </div>\n\n <div class=\"pipeline-grid\">\n @for (summary of Summaries; track summary.Integration.ID) {\n <div [class]=\"GetCardBorderClass(summary.StatusColor)\">\n <!-- Card Header -->\n <div class=\"card-header\">\n <div class=\"card-header-left\">\n <div class=\"card-icon-wrap\">\n <i [class]=\"GetIntegrationIcon(summary)\"></i>\n </div>\n <div class=\"card-title-wrap\">\n <span class=\"card-title\">{{ summary.Integration.Name }}</span>\n <span class=\"card-subtitle\">{{ summary.SourceType?.Name ?? 'Custom' }}</span>\n </div>\n </div>\n <div [class]=\"GetStatusDotClass(summary.StatusColor)\"\n [title]=\"GetStatusLabel(summary.StatusColor)\">\n @if (summary.LatestRun?.Status === 'In Progress') {\n <span class=\"dot-pulse\"></span>\n }\n </div>\n </div>\n\n <!-- Pipeline Flow Visual -->\n <div class=\"pipeline-flow\">\n <div class=\"flow-node\">\n <i [class]=\"GetIntegrationIcon(summary)\"></i>\n </div>\n <div class=\"flow-arrow\">\n <div class=\"flow-line\"></div>\n <span class=\"flow-count\">{{ GetEntityMapCount(summary.Integration.ID) }} maps</span>\n <div class=\"flow-line\"></div>\n </div>\n <div class=\"flow-node flow-node-mj\">\n <i class=\"fa-solid fa-layer-group\"></i>\n </div>\n </div>\n\n <!-- Stats Row -->\n <div class=\"card-stats\">\n <div class=\"stat-item\">\n <span class=\"stat-label\">Last sync</span>\n <span class=\"stat-value\">{{ summary.RelativeTime }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Records</span>\n <span class=\"stat-value\">{{ FormatNumber(summary.LatestRun?.TotalRecords ?? 0) }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Duration</span>\n <span class=\"stat-value\">{{ FormatDuration(summary.DurationMs) }}</span>\n </div>\n <div class=\"stat-item\">\n <span class=\"stat-label\">Errors</span>\n <span class=\"stat-value\" [class.stat-error]=\"summary.TotalErrors > 0\">\n {{ summary.TotalErrors }}\n </span>\n </div>\n </div>\n\n <!-- Sparkline (last 5 runs) -->\n <div class=\"sparkline-row\">\n <span class=\"sparkline-label\">Recent runs</span>\n <div class=\"sparkline-dots\">\n @for (run of summary.RecentRuns; track run.ID) {\n <span [class]=\"GetSparklineDotClass(run)\"\n [title]=\"run.Status + ' - ' + (run.StartedAt ?? 'N/A')\"></span>\n }\n @if (summary.RecentRuns.length === 0) {\n <span class=\"sparkline-none\">No runs</span>\n }\n </div>\n </div>\n\n <!-- Card Footer -->\n <div class=\"card-footer\">\n @if (IsRunning(summary.Integration.ID)) {\n <button class=\"btn-sync btn-sync-disabled\" disabled>\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Running...\n </button>\n } @else {\n <button class=\"btn-sync\"\n (click)=\"RunSync(summary.Integration.ID)\"\n [disabled]=\"!summary.Integration.IsActive || RunningIntegrationID !== null\">\n <i class=\"fa-solid fa-play\"></i> Sync Now\n </button>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- ====================================================================\n SECTION 3: Bottom - Bar Chart & Activity Feed\n ==================================================================== -->\n <div class=\"bottom-split\">\n <!-- Bar Chart (left, 60%) -->\n <div class=\"chart-panel\">\n <h3 class=\"panel-title\"><i class=\"fa-solid fa-chart-bar\"></i> Records Synced (7 days)</h3>\n @if (DailyCounts.length === 0) {\n <p class=\"empty-hint\">No data available.</p>\n } @else {\n <div class=\"bar-chart\">\n @for (day of DailyCounts; track day.Date) {\n <div class=\"bar-column\">\n <div class=\"bar-count\">{{ FormatNumber(day.Records) }}</div>\n <div class=\"bar-fill\" [style.height.%]=\"BarHeight(day.Records)\"></div>\n <div class=\"bar-day\">{{ day.Label }}</div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Activity Feed (right, 40%) -->\n <div class=\"feed-panel\">\n <h3 class=\"panel-title\"><i class=\"fa-solid fa-stream\"></i> Recent Activity</h3>\n @if (ActivityFeed.length === 0) {\n <p class=\"empty-hint\">No recent activity.</p>\n } @else {\n <div class=\"feed-list\">\n @for (item of ActivityFeed; track item.RunID) {\n <div class=\"feed-item\">\n <i [class]=\"ActivityStatusIcon(item.Status)\"\n [class.feed-icon-green]=\"item.StatusColor === 'green'\"\n [class.feed-icon-red]=\"item.StatusColor === 'red'\"\n [class.feed-icon-amber]=\"item.StatusColor === 'amber'\">\n </i>\n <div class=\"feed-details\">\n <span class=\"feed-name\">{{ item.IntegrationName }}</span>\n <span class=\"feed-meta\">{{ item.TotalRecords | number }} records &middot; {{ item.RelativeTime }}</span>\n </div>\n <span class=\"feed-badge\" [class]=\"'feed-badge-' + item.StatusColor\">\n {{ item.Status }}\n </span>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n</div>\n"]}