@memberjunction/ng-dashboards 5.8.0 → 5.10.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 (84) hide show
  1. package/dist/AI/components/models/model-management.component.d.ts +2 -0
  2. package/dist/AI/components/models/model-management.component.d.ts.map +1 -1
  3. package/dist/AI/components/models/model-management.component.js +44 -2
  4. package/dist/AI/components/models/model-management.component.js.map +1 -1
  5. package/dist/DashboardBrowser/dashboard-browser-resource.component.d.ts.map +1 -1
  6. package/dist/DashboardBrowser/dashboard-browser-resource.component.js +15 -12
  7. package/dist/DashboardBrowser/dashboard-browser-resource.component.js.map +1 -1
  8. package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts.map +1 -1
  9. package/dist/DataExplorer/components/view-selector/view-selector.component.js +16 -22
  10. package/dist/DataExplorer/components/view-selector/view-selector.component.js.map +1 -1
  11. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  12. package/dist/DataExplorer/data-explorer-dashboard.component.js +31 -11
  13. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  14. package/dist/Home/home-dashboard.component.d.ts.map +1 -1
  15. package/dist/Home/home-dashboard.component.js +10 -7
  16. package/dist/Home/home-dashboard.component.js.map +1 -1
  17. package/dist/Integration/components/activity/activity.component.d.ts +96 -0
  18. package/dist/Integration/components/activity/activity.component.d.ts.map +1 -0
  19. package/dist/Integration/components/activity/activity.component.js +961 -0
  20. package/dist/Integration/components/activity/activity.component.js.map +1 -0
  21. package/dist/Integration/components/connections/connections.component.d.ts +194 -0
  22. package/dist/Integration/components/connections/connections.component.d.ts.map +1 -0
  23. package/dist/Integration/components/connections/connections.component.js +2368 -0
  24. package/dist/Integration/components/connections/connections.component.js.map +1 -0
  25. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.d.ts +213 -15
  26. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.d.ts.map +1 -1
  27. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +2093 -187
  28. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -1
  29. package/dist/Integration/components/overview/overview.component.d.ts +60 -0
  30. package/dist/Integration/components/overview/overview.component.d.ts.map +1 -0
  31. package/dist/Integration/components/overview/overview.component.js +628 -0
  32. package/dist/Integration/components/overview/overview.component.js.map +1 -0
  33. package/dist/Integration/components/pipelines/pipelines.component.d.ts +203 -0
  34. package/dist/Integration/components/pipelines/pipelines.component.d.ts.map +1 -0
  35. package/dist/Integration/components/pipelines/pipelines.component.js +2057 -0
  36. package/dist/Integration/components/pipelines/pipelines.component.js.map +1 -0
  37. package/dist/Integration/components/schedules/schedules.component.d.ts +110 -0
  38. package/dist/Integration/components/schedules/schedules.component.d.ts.map +1 -0
  39. package/dist/Integration/components/schedules/schedules.component.js +842 -0
  40. package/dist/Integration/components/schedules/schedules.component.js.map +1 -0
  41. package/dist/Integration/components/visual-editor/visual-editor.component.d.ts +141 -0
  42. package/dist/Integration/components/visual-editor/visual-editor.component.d.ts.map +1 -0
  43. package/dist/Integration/components/visual-editor/visual-editor.component.js +1538 -0
  44. package/dist/Integration/components/visual-editor/visual-editor.component.js.map +1 -0
  45. package/dist/Integration/components/widgets/run-history-panel.component.js +3 -2
  46. package/dist/Integration/components/widgets/run-history-panel.component.js.map +1 -1
  47. package/dist/Integration/index.d.ts +5 -3
  48. package/dist/Integration/index.d.ts.map +1 -1
  49. package/dist/Integration/index.js +11 -7
  50. package/dist/Integration/index.js.map +1 -1
  51. package/dist/Integration/integration.module.d.ts +20 -16
  52. package/dist/Integration/integration.module.d.ts.map +1 -1
  53. package/dist/Integration/integration.module.js +40 -21
  54. package/dist/Integration/integration.module.js.map +1 -1
  55. package/dist/Integration/services/integration-data.service.d.ts +123 -9
  56. package/dist/Integration/services/integration-data.service.d.ts.map +1 -1
  57. package/dist/Integration/services/integration-data.service.js +385 -68
  58. package/dist/Integration/services/integration-data.service.js.map +1 -1
  59. package/dist/QueryBrowser/query-browser-resource.component.d.ts +27 -4
  60. package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
  61. package/dist/QueryBrowser/query-browser-resource.component.js +338 -144
  62. package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
  63. package/dist/__tests__/integration-data-service.test.js.map +1 -1
  64. package/dist/__tests__/mapping-validation.test.d.ts +2 -0
  65. package/dist/__tests__/mapping-validation.test.d.ts.map +1 -0
  66. package/dist/__tests__/mapping-validation.test.js +170 -0
  67. package/dist/__tests__/mapping-validation.test.js.map +1 -0
  68. package/package.json +40 -38
  69. package/dist/Integration/components/connection-studio/connection-studio.component.d.ts +0 -81
  70. package/dist/Integration/components/connection-studio/connection-studio.component.d.ts.map +0 -1
  71. package/dist/Integration/components/connection-studio/connection-studio.component.js +0 -960
  72. package/dist/Integration/components/connection-studio/connection-studio.component.js.map +0 -1
  73. package/dist/Integration/components/control-tower/control-tower.component.d.ts +0 -43
  74. package/dist/Integration/components/control-tower/control-tower.component.d.ts.map +0 -1
  75. package/dist/Integration/components/control-tower/control-tower.component.js +0 -446
  76. package/dist/Integration/components/control-tower/control-tower.component.js.map +0 -1
  77. package/dist/Integration/components/sync-activity/sync-activity.component.d.ts +0 -65
  78. package/dist/Integration/components/sync-activity/sync-activity.component.d.ts.map +0 -1
  79. package/dist/Integration/components/sync-activity/sync-activity.component.js +0 -671
  80. package/dist/Integration/components/sync-activity/sync-activity.component.js.map +0 -1
  81. package/dist/__tests__/connection-studio.test.d.ts +0 -2
  82. package/dist/__tests__/connection-studio.test.d.ts.map +0 -1
  83. package/dist/__tests__/connection-studio.test.js +0 -186
  84. package/dist/__tests__/connection-studio.test.js.map +0 -1
@@ -0,0 +1,628 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { ChangeDetectorRef, Component, inject } from '@angular/core';
8
+ import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
9
+ import { RunView } from '@memberjunction/core';
10
+ import { BaseResourceComponent } from '@memberjunction/ng-shared';
11
+ import { IntegrationDataService, ResolveIntegrationIcon } from '../../services/integration-data.service';
12
+ import * as i0 from "@angular/core";
13
+ import * as i1 from "@memberjunction/ng-shared-generic";
14
+ import * as i2 from "@angular/common";
15
+ const _forTrack0 = ($index, $item) => $item.Integration.ID;
16
+ const _forTrack1 = ($index, $item) => $item.ID;
17
+ const _forTrack2 = ($index, $item) => $item.Date;
18
+ const _forTrack3 = ($index, $item) => $item.RunID;
19
+ function OverviewComponent_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
20
+ i0.ɵɵelement(0, "i", 5);
21
+ } }
22
+ function OverviewComponent_Conditional_1_Conditional_2_Template(rf, ctx) { if (rf & 1) {
23
+ i0.ɵɵelement(0, "i", 6);
24
+ } }
25
+ function OverviewComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
26
+ const _r1 = i0.ɵɵgetCurrentView();
27
+ i0.ɵɵelementStart(0, "div", 4);
28
+ i0.ɵɵconditionalCreate(1, OverviewComponent_Conditional_1_Conditional_1_Template, 1, 0, "i", 5)(2, OverviewComponent_Conditional_1_Conditional_2_Template, 1, 0, "i", 6);
29
+ i0.ɵɵelementStart(3, "span", 7);
30
+ i0.ɵɵtext(4);
31
+ i0.ɵɵelementEnd();
32
+ i0.ɵɵelementStart(5, "button", 8);
33
+ i0.ɵɵlistener("click", function OverviewComponent_Conditional_1_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.DismissNotification()); });
34
+ i0.ɵɵelement(6, "i", 9);
35
+ i0.ɵɵelementEnd()();
36
+ } if (rf & 2) {
37
+ const ctx_r1 = i0.ɵɵnextContext();
38
+ i0.ɵɵclassProp("notification-success", ctx_r1.Notification.Type === "success")("notification-error", ctx_r1.Notification.Type === "error");
39
+ i0.ɵɵadvance();
40
+ i0.ɵɵconditional(ctx_r1.Notification.Type === "success" ? 1 : 2);
41
+ i0.ɵɵadvance(3);
42
+ i0.ɵɵtextInterpolate(ctx_r1.Notification.Message);
43
+ } }
44
+ function OverviewComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
45
+ i0.ɵɵelement(0, "mj-loading", 2);
46
+ } }
47
+ function OverviewComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
48
+ i0.ɵɵelementStart(0, "div", 3);
49
+ i0.ɵɵelement(1, "i", 10);
50
+ i0.ɵɵelementStart(2, "h3");
51
+ i0.ɵɵtext(3, "No Integrations Configured");
52
+ i0.ɵɵelementEnd();
53
+ i0.ɵɵelementStart(4, "p");
54
+ i0.ɵɵtext(5, "Set up your first integration using the Connection Studio to start syncing data.");
55
+ i0.ɵɵelementEnd()();
56
+ } }
57
+ function OverviewComponent_Conditional_4_Conditional_30_Template(rf, ctx) { if (rf & 1) {
58
+ i0.ɵɵelement(0, "span", 26);
59
+ } }
60
+ function OverviewComponent_Conditional_4_For_53_Conditional_11_Template(rf, ctx) { if (rf & 1) {
61
+ i0.ɵɵelement(0, "span", 51);
62
+ } }
63
+ function OverviewComponent_Conditional_4_For_53_For_48_Template(rf, ctx) { if (rf & 1) {
64
+ i0.ɵɵelement(0, "span", 50);
65
+ } if (rf & 2) {
66
+ const run_r4 = ctx.$implicit;
67
+ const ctx_r1 = i0.ɵɵnextContext(3);
68
+ i0.ɵɵclassMap(ctx_r1.GetSparklineDotClass(run_r4));
69
+ i0.ɵɵproperty("title", run_r4.Status + " - " + (run_r4.StartedAt ?? "N/A"));
70
+ } }
71
+ function OverviewComponent_Conditional_4_For_53_Conditional_49_Template(rf, ctx) { if (rf & 1) {
72
+ i0.ɵɵelementStart(0, "span", 67);
73
+ i0.ɵɵtext(1, "No runs");
74
+ i0.ɵɵelementEnd();
75
+ } }
76
+ function OverviewComponent_Conditional_4_For_53_Conditional_51_Template(rf, ctx) { if (rf & 1) {
77
+ i0.ɵɵelementStart(0, "button", 69);
78
+ i0.ɵɵelement(1, "i", 71);
79
+ i0.ɵɵtext(2, " Running... ");
80
+ i0.ɵɵelementEnd();
81
+ } }
82
+ function OverviewComponent_Conditional_4_For_53_Conditional_52_Template(rf, ctx) { if (rf & 1) {
83
+ const _r5 = i0.ɵɵgetCurrentView();
84
+ i0.ɵɵelementStart(0, "button", 72);
85
+ i0.ɵɵlistener("click", function OverviewComponent_Conditional_4_For_53_Conditional_52_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r5); const summary_r6 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.RunSync(summary_r6.Integration.ID)); });
86
+ i0.ɵɵelement(1, "i", 73);
87
+ i0.ɵɵtext(2, " Sync Now ");
88
+ i0.ɵɵelementEnd();
89
+ } if (rf & 2) {
90
+ const summary_r6 = i0.ɵɵnextContext().$implicit;
91
+ const ctx_r1 = i0.ɵɵnextContext(2);
92
+ i0.ɵɵproperty("disabled", !summary_r6.Integration.IsActive || ctx_r1.RunningIntegrationID !== null);
93
+ } }
94
+ function OverviewComponent_Conditional_4_For_53_Template(rf, ctx) { if (rf & 1) {
95
+ i0.ɵɵelementStart(0, "div")(1, "div", 44)(2, "div", 45)(3, "div", 46);
96
+ i0.ɵɵelement(4, "i");
97
+ i0.ɵɵelementEnd();
98
+ i0.ɵɵelementStart(5, "div", 47)(6, "span", 48);
99
+ i0.ɵɵtext(7);
100
+ i0.ɵɵelementEnd();
101
+ i0.ɵɵelementStart(8, "span", 49);
102
+ i0.ɵɵtext(9);
103
+ i0.ɵɵelementEnd()()();
104
+ i0.ɵɵelementStart(10, "div", 50);
105
+ i0.ɵɵconditionalCreate(11, OverviewComponent_Conditional_4_For_53_Conditional_11_Template, 1, 0, "span", 51);
106
+ i0.ɵɵelementEnd()();
107
+ i0.ɵɵelementStart(12, "div", 52)(13, "div", 53);
108
+ i0.ɵɵelement(14, "i");
109
+ i0.ɵɵelementEnd();
110
+ i0.ɵɵelementStart(15, "div", 54);
111
+ i0.ɵɵelement(16, "div", 55);
112
+ i0.ɵɵelementStart(17, "span", 56);
113
+ i0.ɵɵtext(18);
114
+ i0.ɵɵelementEnd();
115
+ i0.ɵɵelement(19, "div", 55);
116
+ i0.ɵɵelementEnd();
117
+ i0.ɵɵelementStart(20, "div", 57);
118
+ i0.ɵɵelement(21, "i", 58);
119
+ i0.ɵɵelementEnd()();
120
+ i0.ɵɵelementStart(22, "div", 59)(23, "div", 60)(24, "span", 61);
121
+ i0.ɵɵtext(25, "Last sync");
122
+ i0.ɵɵelementEnd();
123
+ i0.ɵɵelementStart(26, "span", 62);
124
+ i0.ɵɵtext(27);
125
+ i0.ɵɵelementEnd()();
126
+ i0.ɵɵelementStart(28, "div", 60)(29, "span", 61);
127
+ i0.ɵɵtext(30, "Records");
128
+ i0.ɵɵelementEnd();
129
+ i0.ɵɵelementStart(31, "span", 62);
130
+ i0.ɵɵtext(32);
131
+ i0.ɵɵelementEnd()();
132
+ i0.ɵɵelementStart(33, "div", 60)(34, "span", 61);
133
+ i0.ɵɵtext(35, "Duration");
134
+ i0.ɵɵelementEnd();
135
+ i0.ɵɵelementStart(36, "span", 62);
136
+ i0.ɵɵtext(37);
137
+ i0.ɵɵelementEnd()();
138
+ i0.ɵɵelementStart(38, "div", 60)(39, "span", 61);
139
+ i0.ɵɵtext(40, "Errors");
140
+ i0.ɵɵelementEnd();
141
+ i0.ɵɵelementStart(41, "span", 62);
142
+ i0.ɵɵtext(42);
143
+ i0.ɵɵelementEnd()()();
144
+ i0.ɵɵelementStart(43, "div", 63)(44, "span", 64);
145
+ i0.ɵɵtext(45, "Recent runs");
146
+ i0.ɵɵelementEnd();
147
+ i0.ɵɵelementStart(46, "div", 65);
148
+ i0.ɵɵrepeaterCreate(47, OverviewComponent_Conditional_4_For_53_For_48_Template, 1, 3, "span", 66, _forTrack1);
149
+ i0.ɵɵconditionalCreate(49, OverviewComponent_Conditional_4_For_53_Conditional_49_Template, 2, 0, "span", 67);
150
+ i0.ɵɵelementEnd()();
151
+ i0.ɵɵelementStart(50, "div", 68);
152
+ i0.ɵɵconditionalCreate(51, OverviewComponent_Conditional_4_For_53_Conditional_51_Template, 3, 0, "button", 69)(52, OverviewComponent_Conditional_4_For_53_Conditional_52_Template, 3, 1, "button", 70);
153
+ i0.ɵɵelementEnd()();
154
+ } if (rf & 2) {
155
+ const summary_r6 = ctx.$implicit;
156
+ const ctx_r1 = i0.ɵɵnextContext(2);
157
+ i0.ɵɵclassMap(ctx_r1.GetCardBorderClass(summary_r6.StatusColor));
158
+ i0.ɵɵadvance(4);
159
+ i0.ɵɵclassMap(ctx_r1.GetIntegrationIcon(summary_r6));
160
+ i0.ɵɵadvance(3);
161
+ i0.ɵɵtextInterpolate(summary_r6.Integration.Name);
162
+ i0.ɵɵadvance(2);
163
+ i0.ɵɵtextInterpolate((summary_r6.SourceType == null ? null : summary_r6.SourceType.Name) ?? "Custom");
164
+ i0.ɵɵadvance();
165
+ i0.ɵɵclassMap(ctx_r1.GetStatusDotClass(summary_r6.StatusColor));
166
+ i0.ɵɵproperty("title", ctx_r1.GetStatusLabel(summary_r6.StatusColor));
167
+ i0.ɵɵadvance();
168
+ i0.ɵɵconditional((summary_r6.LatestRun == null ? null : summary_r6.LatestRun.Status) === "In Progress" ? 11 : -1);
169
+ i0.ɵɵadvance(3);
170
+ i0.ɵɵclassMap(ctx_r1.GetIntegrationIcon(summary_r6));
171
+ i0.ɵɵadvance(4);
172
+ i0.ɵɵtextInterpolate1("", ctx_r1.GetEntityMapCount(summary_r6.Integration.ID), " maps");
173
+ i0.ɵɵadvance(9);
174
+ i0.ɵɵtextInterpolate(summary_r6.RelativeTime);
175
+ i0.ɵɵadvance(5);
176
+ i0.ɵɵtextInterpolate(ctx_r1.FormatNumber((summary_r6.LatestRun == null ? null : summary_r6.LatestRun.TotalRecords) ?? 0));
177
+ i0.ɵɵadvance(5);
178
+ i0.ɵɵtextInterpolate(ctx_r1.FormatDuration(summary_r6.DurationMs));
179
+ i0.ɵɵadvance(4);
180
+ i0.ɵɵclassProp("stat-error", summary_r6.TotalErrors > 0);
181
+ i0.ɵɵadvance();
182
+ i0.ɵɵtextInterpolate1(" ", summary_r6.TotalErrors, " ");
183
+ i0.ɵɵadvance(5);
184
+ i0.ɵɵrepeater(summary_r6.RecentRuns);
185
+ i0.ɵɵadvance(2);
186
+ i0.ɵɵconditional(summary_r6.RecentRuns.length === 0 ? 49 : -1);
187
+ i0.ɵɵadvance(2);
188
+ i0.ɵɵconditional(ctx_r1.IsRunning(summary_r6.Integration.ID) ? 51 : 52);
189
+ } }
190
+ function OverviewComponent_Conditional_4_Conditional_59_Template(rf, ctx) { if (rf & 1) {
191
+ i0.ɵɵelementStart(0, "p", 39);
192
+ i0.ɵɵtext(1, "No data available.");
193
+ i0.ɵɵelementEnd();
194
+ } }
195
+ function OverviewComponent_Conditional_4_Conditional_60_For_2_Template(rf, ctx) { if (rf & 1) {
196
+ i0.ɵɵelementStart(0, "div", 74)(1, "div", 75);
197
+ i0.ɵɵtext(2);
198
+ i0.ɵɵelementEnd();
199
+ i0.ɵɵelement(3, "div", 76);
200
+ i0.ɵɵelementStart(4, "div", 77);
201
+ i0.ɵɵtext(5);
202
+ i0.ɵɵelementEnd()();
203
+ } if (rf & 2) {
204
+ const day_r7 = ctx.$implicit;
205
+ const ctx_r1 = i0.ɵɵnextContext(3);
206
+ i0.ɵɵadvance(2);
207
+ i0.ɵɵtextInterpolate(ctx_r1.FormatNumber(day_r7.Records));
208
+ i0.ɵɵadvance();
209
+ i0.ɵɵstyleProp("height", ctx_r1.BarHeight(day_r7.Records), "%");
210
+ i0.ɵɵadvance(2);
211
+ i0.ɵɵtextInterpolate(day_r7.Label);
212
+ } }
213
+ function OverviewComponent_Conditional_4_Conditional_60_Template(rf, ctx) { if (rf & 1) {
214
+ i0.ɵɵelementStart(0, "div", 40);
215
+ i0.ɵɵrepeaterCreate(1, OverviewComponent_Conditional_4_Conditional_60_For_2_Template, 6, 4, "div", 74, _forTrack2);
216
+ i0.ɵɵelementEnd();
217
+ } if (rf & 2) {
218
+ const ctx_r1 = i0.ɵɵnextContext(2);
219
+ i0.ɵɵadvance();
220
+ i0.ɵɵrepeater(ctx_r1.DailyCounts);
221
+ } }
222
+ function OverviewComponent_Conditional_4_Conditional_65_Template(rf, ctx) { if (rf & 1) {
223
+ i0.ɵɵelementStart(0, "p", 39);
224
+ i0.ɵɵtext(1, "No recent activity.");
225
+ i0.ɵɵelementEnd();
226
+ } }
227
+ function OverviewComponent_Conditional_4_Conditional_66_For_2_Template(rf, ctx) { if (rf & 1) {
228
+ i0.ɵɵelementStart(0, "div", 78);
229
+ i0.ɵɵelement(1, "i");
230
+ i0.ɵɵelementStart(2, "div", 79)(3, "span", 80);
231
+ i0.ɵɵtext(4);
232
+ i0.ɵɵelementEnd();
233
+ i0.ɵɵelementStart(5, "span", 81);
234
+ i0.ɵɵtext(6);
235
+ i0.ɵɵpipe(7, "number");
236
+ i0.ɵɵelementEnd()();
237
+ i0.ɵɵelementStart(8, "span", 82);
238
+ i0.ɵɵtext(9);
239
+ i0.ɵɵelementEnd()();
240
+ } if (rf & 2) {
241
+ const item_r8 = ctx.$implicit;
242
+ const ctx_r1 = i0.ɵɵnextContext(3);
243
+ i0.ɵɵadvance();
244
+ i0.ɵɵclassMap(ctx_r1.ActivityStatusIcon(item_r8.Status));
245
+ i0.ɵɵclassProp("feed-icon-green", item_r8.StatusColor === "green")("feed-icon-red", item_r8.StatusColor === "red")("feed-icon-amber", item_r8.StatusColor === "amber");
246
+ i0.ɵɵadvance(3);
247
+ i0.ɵɵtextInterpolate(item_r8.IntegrationName);
248
+ i0.ɵɵadvance(2);
249
+ i0.ɵɵtextInterpolate2("", i0.ɵɵpipeBind1(7, 14, item_r8.TotalRecords), " records \u00B7 ", item_r8.RelativeTime);
250
+ i0.ɵɵadvance(2);
251
+ i0.ɵɵclassMap("feed-badge-" + item_r8.StatusColor);
252
+ i0.ɵɵadvance();
253
+ i0.ɵɵtextInterpolate1(" ", item_r8.Status, " ");
254
+ } }
255
+ function OverviewComponent_Conditional_4_Conditional_66_Template(rf, ctx) { if (rf & 1) {
256
+ i0.ɵɵelementStart(0, "div", 43);
257
+ i0.ɵɵrepeaterCreate(1, OverviewComponent_Conditional_4_Conditional_66_For_2_Template, 10, 16, "div", 78, _forTrack3);
258
+ i0.ɵɵelementEnd();
259
+ } if (rf & 2) {
260
+ const ctx_r1 = i0.ɵɵnextContext(2);
261
+ i0.ɵɵadvance();
262
+ i0.ɵɵrepeater(ctx_r1.ActivityFeed);
263
+ } }
264
+ function OverviewComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
265
+ const _r3 = i0.ɵɵgetCurrentView();
266
+ i0.ɵɵelementStart(0, "div", 11)(1, "div", 12)(2, "div", 13);
267
+ i0.ɵɵelement(3, "i", 14);
268
+ i0.ɵɵelementEnd();
269
+ i0.ɵɵelementStart(4, "div", 15)(5, "span", 16);
270
+ i0.ɵɵtext(6);
271
+ i0.ɵɵelementEnd();
272
+ i0.ɵɵelementStart(7, "span", 17);
273
+ i0.ɵɵtext(8, "Total Pipelines");
274
+ i0.ɵɵelementEnd()()();
275
+ i0.ɵɵelementStart(9, "div", 12)(10, "div", 18);
276
+ i0.ɵɵelement(11, "i", 19);
277
+ i0.ɵɵelementEnd();
278
+ i0.ɵɵelementStart(12, "div", 15)(13, "span", 16);
279
+ i0.ɵɵtext(14);
280
+ i0.ɵɵelementEnd();
281
+ i0.ɵɵelementStart(15, "span", 17);
282
+ i0.ɵɵtext(16, "Records Today");
283
+ i0.ɵɵelementEnd()()();
284
+ i0.ɵɵelementStart(17, "div", 12)(18, "div", 20)(19, "div", 21)(20, "span", 22);
285
+ i0.ɵɵtext(21);
286
+ i0.ɵɵelementEnd()()();
287
+ i0.ɵɵelementStart(22, "div", 15)(23, "span", 23);
288
+ i0.ɵɵtext(24);
289
+ i0.ɵɵelementEnd();
290
+ i0.ɵɵelementStart(25, "span", 17);
291
+ i0.ɵɵtext(26, "Success Rate");
292
+ i0.ɵɵelementEnd()()();
293
+ i0.ɵɵelementStart(27, "div", 12)(28, "div", 24);
294
+ i0.ɵɵelement(29, "i", 25);
295
+ i0.ɵɵconditionalCreate(30, OverviewComponent_Conditional_4_Conditional_30_Template, 1, 0, "span", 26);
296
+ i0.ɵɵelementEnd();
297
+ i0.ɵɵelementStart(31, "div", 15)(32, "span", 16);
298
+ i0.ɵɵtext(33);
299
+ i0.ɵɵelementEnd();
300
+ i0.ɵɵelementStart(34, "span", 17);
301
+ i0.ɵɵtext(35, "Active Now");
302
+ i0.ɵɵelementEnd()()();
303
+ i0.ɵɵelementStart(36, "div", 12)(37, "div", 27);
304
+ i0.ɵɵelement(38, "i", 28);
305
+ i0.ɵɵelementEnd();
306
+ i0.ɵɵelementStart(39, "div", 15)(40, "span", 16);
307
+ i0.ɵɵtext(41);
308
+ i0.ɵɵelementEnd();
309
+ i0.ɵɵelementStart(42, "span", 17);
310
+ i0.ɵɵtext(43, "Avg Duration");
311
+ i0.ɵɵelementEnd()()()();
312
+ i0.ɵɵelementStart(44, "div", 29)(45, "h3");
313
+ i0.ɵɵelement(46, "i", 30);
314
+ i0.ɵɵtext(47, " Pipeline Health");
315
+ i0.ɵɵelementEnd();
316
+ i0.ɵɵelementStart(48, "button", 31);
317
+ i0.ɵɵlistener("click", function OverviewComponent_Conditional_4_Template_button_click_48_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Refresh()); });
318
+ i0.ɵɵelement(49, "i", 32);
319
+ i0.ɵɵtext(50, " Refresh ");
320
+ i0.ɵɵelementEnd()();
321
+ i0.ɵɵelementStart(51, "div", 33);
322
+ i0.ɵɵrepeaterCreate(52, OverviewComponent_Conditional_4_For_53_Template, 53, 21, "div", 34, _forTrack0);
323
+ i0.ɵɵelementEnd();
324
+ i0.ɵɵelementStart(54, "div", 35)(55, "div", 36)(56, "h3", 37);
325
+ i0.ɵɵelement(57, "i", 38);
326
+ i0.ɵɵtext(58, " Records Synced (7 days)");
327
+ i0.ɵɵelementEnd();
328
+ i0.ɵɵconditionalCreate(59, OverviewComponent_Conditional_4_Conditional_59_Template, 2, 0, "p", 39)(60, OverviewComponent_Conditional_4_Conditional_60_Template, 3, 0, "div", 40);
329
+ i0.ɵɵelementEnd();
330
+ i0.ɵɵelementStart(61, "div", 41)(62, "h3", 37);
331
+ i0.ɵɵelement(63, "i", 42);
332
+ i0.ɵɵtext(64, " Recent Activity");
333
+ i0.ɵɵelementEnd();
334
+ i0.ɵɵconditionalCreate(65, OverviewComponent_Conditional_4_Conditional_65_Template, 2, 0, "p", 39)(66, OverviewComponent_Conditional_4_Conditional_66_Template, 3, 0, "div", 43);
335
+ i0.ɵɵelementEnd()();
336
+ } if (rf & 2) {
337
+ const ctx_r1 = i0.ɵɵnextContext();
338
+ i0.ɵɵadvance(6);
339
+ i0.ɵɵtextInterpolate(ctx_r1.KPIs.TotalIntegrations);
340
+ i0.ɵɵadvance(8);
341
+ i0.ɵɵtextInterpolate(ctx_r1.FormatNumber(ctx_r1.KPIs.RecordsSyncedToday));
342
+ i0.ɵɵadvance(4);
343
+ i0.ɵɵstyleProp("background", ctx_r1.SuccessRateGradient);
344
+ i0.ɵɵadvance(3);
345
+ i0.ɵɵtextInterpolate1("", ctx_r1.SuccessRate, "%");
346
+ i0.ɵɵadvance(3);
347
+ i0.ɵɵtextInterpolate1("", ctx_r1.SuccessRate, "%");
348
+ i0.ɵɵadvance(6);
349
+ i0.ɵɵconditional(ctx_r1.ActiveCount > 0 ? 30 : -1);
350
+ i0.ɵɵadvance(3);
351
+ i0.ɵɵtextInterpolate(ctx_r1.ActiveCount);
352
+ i0.ɵɵadvance(8);
353
+ i0.ɵɵtextInterpolate(ctx_r1.FormatDuration(ctx_r1.KPIs.AverageSyncDurationMs));
354
+ i0.ɵɵadvance(11);
355
+ i0.ɵɵrepeater(ctx_r1.Summaries);
356
+ i0.ɵɵadvance(7);
357
+ i0.ɵɵconditional(ctx_r1.DailyCounts.length === 0 ? 59 : 60);
358
+ i0.ɵɵadvance(6);
359
+ i0.ɵɵconditional(ctx_r1.ActivityFeed.length === 0 ? 65 : 66);
360
+ } }
361
+ let OverviewComponent = class OverviewComponent extends BaseResourceComponent {
362
+ Summaries = [];
363
+ KPIs = {
364
+ TotalIntegrations: 0,
365
+ ActiveSyncs: 0,
366
+ RecordsSyncedToday: 0,
367
+ ErrorRate: 0,
368
+ AverageSyncDurationMs: null
369
+ };
370
+ ActivityFeed = [];
371
+ DailyCounts = [];
372
+ EntityMapCounts = new Map();
373
+ IsLoading = false;
374
+ RunningIntegrationID = null;
375
+ Notification = null;
376
+ dataService = inject(IntegrationDataService);
377
+ cdr = inject(ChangeDetectorRef);
378
+ notificationTimer = null;
379
+ async ngOnInit() {
380
+ await this.LoadData();
381
+ }
382
+ ngOnDestroy() {
383
+ this.clearNotificationTimer();
384
+ }
385
+ // ---------------------------------------------------------------------------
386
+ // Data Loading
387
+ // ---------------------------------------------------------------------------
388
+ async LoadData() {
389
+ this.IsLoading = true;
390
+ this.cdr.detectChanges();
391
+ try {
392
+ const provider = this.RunViewToUse;
393
+ const [summaries, activityFeed, dailyCounts] = await Promise.all([
394
+ this.dataService.LoadIntegrationSummaries(provider),
395
+ this.dataService.LoadRecentRuns(10, provider),
396
+ this.dataService.LoadDailyRecordCounts(7, provider)
397
+ ]);
398
+ this.Summaries = summaries;
399
+ this.KPIs = this.dataService.ComputeKPIs(summaries);
400
+ this.ActivityFeed = activityFeed;
401
+ this.DailyCounts = dailyCounts;
402
+ await this.loadEntityMapCounts(summaries, provider);
403
+ }
404
+ catch (err) {
405
+ console.error('[IntegrationOverview] Failed to load data:', err);
406
+ }
407
+ finally {
408
+ this.IsLoading = false;
409
+ this.cdr.detectChanges();
410
+ }
411
+ }
412
+ async Refresh() {
413
+ await this.LoadData();
414
+ }
415
+ // ---------------------------------------------------------------------------
416
+ // Sync Actions
417
+ // ---------------------------------------------------------------------------
418
+ async RunSync(integrationID) {
419
+ if (this.RunningIntegrationID)
420
+ return;
421
+ this.RunningIntegrationID = integrationID;
422
+ this.dismissNotification();
423
+ this.cdr.detectChanges();
424
+ try {
425
+ const result = await this.dataService.RunSync(integrationID);
426
+ if (result.Success) {
427
+ this.showNotification('success', result.Message || 'Sync started successfully');
428
+ await this.LoadData();
429
+ }
430
+ else {
431
+ this.showNotification('error', result.Message || 'Sync failed');
432
+ }
433
+ }
434
+ catch (err) {
435
+ const error = err;
436
+ this.showNotification('error', `Unexpected error: ${error.message}`);
437
+ console.error('[IntegrationOverview] RunSync error:', err);
438
+ }
439
+ finally {
440
+ this.RunningIntegrationID = null;
441
+ this.cdr.detectChanges();
442
+ }
443
+ }
444
+ IsRunning(integrationID) {
445
+ return UUIDsEqual(this.RunningIntegrationID, integrationID);
446
+ }
447
+ // ---------------------------------------------------------------------------
448
+ // KPI Helpers
449
+ // ---------------------------------------------------------------------------
450
+ get SuccessRate() {
451
+ if (this.KPIs.ErrorRate == null)
452
+ return 100;
453
+ return Math.round((100 - this.KPIs.ErrorRate) * 10) / 10;
454
+ }
455
+ get SuccessRateGradient() {
456
+ const pct = this.SuccessRate;
457
+ const angle = (pct / 100) * 360;
458
+ return `conic-gradient(#10b981 ${angle}deg, #e5e7eb ${angle}deg)`;
459
+ }
460
+ get ActiveCount() {
461
+ return this.KPIs.ActiveSyncs;
462
+ }
463
+ FormatDuration(ms) {
464
+ return this.dataService.FormatDuration(ms);
465
+ }
466
+ FormatNumber(value) {
467
+ if (value >= 1_000_000)
468
+ return `${(value / 1_000_000).toFixed(1)}M`;
469
+ if (value >= 1_000)
470
+ return `${(value / 1_000).toFixed(1)}K`;
471
+ return value.toLocaleString();
472
+ }
473
+ // ---------------------------------------------------------------------------
474
+ // Pipeline Card Helpers
475
+ // ---------------------------------------------------------------------------
476
+ GetIntegrationIcon(summary) {
477
+ if (summary.SourceType?.IconClass) {
478
+ return summary.SourceType.IconClass;
479
+ }
480
+ return this.resolveIconByName(summary.Integration.Integration ?? summary.Integration.Name);
481
+ }
482
+ GetStatusDotClass(color) {
483
+ return `status-dot status-dot-${color}`;
484
+ }
485
+ GetStatusLabel(color) {
486
+ if (color === 'green')
487
+ return 'Healthy';
488
+ if (color === 'amber')
489
+ return 'Warning';
490
+ if (color === 'red')
491
+ return 'Error';
492
+ return 'Inactive';
493
+ }
494
+ GetEntityMapCount(integrationID) {
495
+ for (const [key, value] of this.EntityMapCounts) {
496
+ if (UUIDsEqual(key, integrationID))
497
+ return value;
498
+ }
499
+ return 0;
500
+ }
501
+ GetSparklineDotClass(run) {
502
+ if (run.Status === 'Success')
503
+ return 'spark-dot spark-green';
504
+ if (run.Status === 'Failed')
505
+ return 'spark-dot spark-red';
506
+ if (run.Status === 'In Progress' || run.Status === 'Pending')
507
+ return 'spark-dot spark-amber';
508
+ return 'spark-dot spark-gray';
509
+ }
510
+ GetCardBorderClass(color) {
511
+ return color === 'red' ? 'pipeline-card pipeline-card-error' : 'pipeline-card';
512
+ }
513
+ // ---------------------------------------------------------------------------
514
+ // Bar Chart Helpers
515
+ // ---------------------------------------------------------------------------
516
+ get MaxDailyRecords() {
517
+ if (this.DailyCounts.length === 0)
518
+ return 1;
519
+ const maxVal = Math.max(...this.DailyCounts.map(d => d.Records));
520
+ return maxVal > 0 ? maxVal : 1;
521
+ }
522
+ BarHeight(records) {
523
+ return Math.max((records / this.MaxDailyRecords) * 100, 2);
524
+ }
525
+ // ---------------------------------------------------------------------------
526
+ // Activity Feed Helpers
527
+ // ---------------------------------------------------------------------------
528
+ ActivityStatusIcon(status) {
529
+ if (status === 'Success')
530
+ return 'fa-solid fa-circle-check';
531
+ if (status === 'Failed')
532
+ return 'fa-solid fa-circle-xmark';
533
+ if (status === 'In Progress')
534
+ return 'fa-solid fa-spinner fa-spin';
535
+ return 'fa-solid fa-clock';
536
+ }
537
+ // ---------------------------------------------------------------------------
538
+ // Notification Management
539
+ // ---------------------------------------------------------------------------
540
+ DismissNotification() {
541
+ this.dismissNotification();
542
+ this.cdr.detectChanges();
543
+ }
544
+ // ---------------------------------------------------------------------------
545
+ // Resource Overrides
546
+ // ---------------------------------------------------------------------------
547
+ async GetResourceDisplayName(_data) {
548
+ return 'Overview';
549
+ }
550
+ async GetResourceIconClass(_data) {
551
+ return 'fa-solid fa-gauge-high';
552
+ }
553
+ // ---------------------------------------------------------------------------
554
+ // Private Helpers
555
+ // ---------------------------------------------------------------------------
556
+ async loadEntityMapCounts(summaries, provider) {
557
+ if (summaries.length === 0)
558
+ return;
559
+ const allMaps = await this.loadAllEntityMaps(provider);
560
+ this.EntityMapCounts = this.countMapsByIntegration(allMaps);
561
+ }
562
+ async loadAllEntityMaps(provider) {
563
+ const rv = new RunView(provider ?? null);
564
+ const result = await rv.RunView({
565
+ EntityName: 'MJ: Company Integration Entity Maps',
566
+ ExtraFilter: '',
567
+ OrderBy: 'CompanyIntegrationID',
568
+ Fields: ['ID', 'CompanyIntegrationID'],
569
+ ResultType: 'simple'
570
+ });
571
+ return result.Results;
572
+ }
573
+ countMapsByIntegration(maps) {
574
+ const counts = new Map();
575
+ for (const map of maps) {
576
+ const current = counts.get(map.CompanyIntegrationID) ?? 0;
577
+ counts.set(map.CompanyIntegrationID, current + 1);
578
+ }
579
+ return counts;
580
+ }
581
+ resolveIconByName(name) {
582
+ return ResolveIntegrationIcon(name);
583
+ }
584
+ showNotification(type, message) {
585
+ this.clearNotificationTimer();
586
+ this.Notification = { Type: type, Message: message };
587
+ this.notificationTimer = setTimeout(() => {
588
+ this.Notification = null;
589
+ this.cdr.detectChanges();
590
+ }, 5000);
591
+ }
592
+ dismissNotification() {
593
+ this.clearNotificationTimer();
594
+ this.Notification = null;
595
+ }
596
+ clearNotificationTimer() {
597
+ if (this.notificationTimer) {
598
+ clearTimeout(this.notificationTimer);
599
+ this.notificationTimer = null;
600
+ }
601
+ }
602
+ static ɵfac = /*@__PURE__*/ (() => { let ɵOverviewComponent_BaseFactory; return function OverviewComponent_Factory(__ngFactoryType__) { return (ɵOverviewComponent_BaseFactory || (ɵOverviewComponent_BaseFactory = i0.ɵɵgetInheritedFactory(OverviewComponent)))(__ngFactoryType__ || OverviewComponent); }; })();
603
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: OverviewComponent, selectors: [["app-integration-overview"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 5, vars: 2, consts: [[1, "overview"], [1, "notification", 3, "notification-success", "notification-error"], ["text", "Loading integrations...", "size", "medium"], [1, "empty-state"], [1, "notification"], [1, "fa-solid", "fa-circle-check"], [1, "fa-solid", "fa-circle-xmark"], [1, "notification-message"], [1, "notification-dismiss", 3, "click"], [1, "fa-solid", "fa-times"], [1, "fa-solid", "fa-plug-circle-xmark"], [1, "metric-strip"], [1, "metric-card"], [1, "metric-icon", "metric-icon-blue"], [1, "fa-solid", "fa-diagram-project"], [1, "metric-body"], [1, "metric-value"], [1, "metric-label"], [1, "metric-icon", "metric-icon-green"], [1, "fa-solid", "fa-database"], [1, "metric-ring"], [1, "metric-ring-inner"], [1, "metric-ring-value"], [1, "metric-value", "metric-value-indigo"], [1, "metric-icon", "metric-icon-emerald"], [1, "fa-solid", "fa-bolt"], [1, "pulse-dot"], [1, "metric-icon", "metric-icon-orange"], [1, "fa-solid", "fa-clock"], [1, "section-heading"], [1, "fa-solid", "fa-heart-pulse"], [1, "refresh-btn", 3, "click"], [1, "fa-solid", "fa-arrows-rotate"], [1, "pipeline-grid"], [3, "class"], [1, "bottom-split"], [1, "chart-panel"], [1, "panel-title"], [1, "fa-solid", "fa-chart-bar"], [1, "empty-hint"], [1, "bar-chart"], [1, "feed-panel"], [1, "fa-solid", "fa-stream"], [1, "feed-list"], [1, "card-header"], [1, "card-header-left"], [1, "card-icon-wrap"], [1, "card-title-wrap"], [1, "card-title"], [1, "card-subtitle"], [3, "title"], [1, "dot-pulse"], [1, "pipeline-flow"], [1, "flow-node"], [1, "flow-arrow"], [1, "flow-line"], [1, "flow-count"], [1, "flow-node", "flow-node-mj"], [1, "fa-solid", "fa-layer-group"], [1, "card-stats"], [1, "stat-item"], [1, "stat-label"], [1, "stat-value"], [1, "sparkline-row"], [1, "sparkline-label"], [1, "sparkline-dots"], [3, "class", "title"], [1, "sparkline-none"], [1, "card-footer"], ["disabled", "", 1, "btn-sync", "btn-sync-disabled"], [1, "btn-sync", 3, "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "btn-sync", 3, "click", "disabled"], [1, "fa-solid", "fa-play"], [1, "bar-column"], [1, "bar-count"], [1, "bar-fill"], [1, "bar-day"], [1, "feed-item"], [1, "feed-details"], [1, "feed-name"], [1, "feed-meta"], [1, "feed-badge"]], template: function OverviewComponent_Template(rf, ctx) { if (rf & 1) {
604
+ i0.ɵɵelementStart(0, "div", 0);
605
+ i0.ɵɵconditionalCreate(1, OverviewComponent_Conditional_1_Template, 7, 6, "div", 1);
606
+ i0.ɵɵconditionalCreate(2, OverviewComponent_Conditional_2_Template, 1, 0, "mj-loading", 2)(3, OverviewComponent_Conditional_3_Template, 6, 0, "div", 3)(4, OverviewComponent_Conditional_4_Template, 67, 11);
607
+ i0.ɵɵelementEnd();
608
+ } if (rf & 2) {
609
+ i0.ɵɵadvance();
610
+ i0.ɵɵconditional(ctx.Notification ? 1 : -1);
611
+ i0.ɵɵadvance();
612
+ 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}"] });
614
+ };
615
+ OverviewComponent = __decorate([
616
+ RegisterClass(BaseResourceComponent, 'IntegrationOverview')
617
+ ], OverviewComponent);
618
+ export { OverviewComponent };
619
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(OverviewComponent, [{
620
+ 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"] }]
622
+ }], null, null); })();
623
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(OverviewComponent, { className: "OverviewComponent", filePath: "src/Integration/components/overview/overview.component.ts", lineNumber: 30 }); })();
624
+ export function LoadOverviewComponent() {
625
+ // Tree-shaking prevention: importing this module causes
626
+ // @RegisterClass decorators to fire, registering components.
627
+ }
628
+ //# sourceMappingURL=overview.component.js.map