@memberjunction/ng-dashboards 5.7.0 → 5.8.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 (53) hide show
  1. package/dist/Integration/components/connection-studio/connection-studio.component.d.ts +81 -0
  2. package/dist/Integration/components/connection-studio/connection-studio.component.d.ts.map +1 -0
  3. package/dist/Integration/components/connection-studio/connection-studio.component.js +960 -0
  4. package/dist/Integration/components/connection-studio/connection-studio.component.js.map +1 -0
  5. package/dist/Integration/components/control-tower/control-tower.component.d.ts +43 -0
  6. package/dist/Integration/components/control-tower/control-tower.component.d.ts.map +1 -0
  7. package/dist/Integration/components/control-tower/control-tower.component.js +446 -0
  8. package/dist/Integration/components/control-tower/control-tower.component.js.map +1 -0
  9. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.d.ts +43 -0
  10. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.d.ts.map +1 -0
  11. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +467 -0
  12. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -0
  13. package/dist/Integration/components/sync-activity/sync-activity.component.d.ts +65 -0
  14. package/dist/Integration/components/sync-activity/sync-activity.component.d.ts.map +1 -0
  15. package/dist/Integration/components/sync-activity/sync-activity.component.js +671 -0
  16. package/dist/Integration/components/sync-activity/sync-activity.component.js.map +1 -0
  17. package/dist/Integration/components/widgets/integration-card.component.d.ts +22 -0
  18. package/dist/Integration/components/widgets/integration-card.component.d.ts.map +1 -0
  19. package/dist/Integration/components/widgets/integration-card.component.js +262 -0
  20. package/dist/Integration/components/widgets/integration-card.component.js.map +1 -0
  21. package/dist/Integration/components/widgets/run-history-panel.component.d.ts +29 -0
  22. package/dist/Integration/components/widgets/run-history-panel.component.d.ts.map +1 -0
  23. package/dist/Integration/components/widgets/run-history-panel.component.js +398 -0
  24. package/dist/Integration/components/widgets/run-history-panel.component.js.map +1 -0
  25. package/dist/Integration/index.d.ts +9 -0
  26. package/dist/Integration/index.d.ts.map +1 -0
  27. package/dist/Integration/index.js +16 -0
  28. package/dist/Integration/index.js.map +1 -0
  29. package/dist/Integration/integration.module.d.ts +22 -0
  30. package/dist/Integration/integration.module.d.ts.map +1 -0
  31. package/dist/Integration/integration.module.js +88 -0
  32. package/dist/Integration/integration.module.js.map +1 -0
  33. package/dist/Integration/services/integration-data.service.d.ts +154 -0
  34. package/dist/Integration/services/integration-data.service.d.ts.map +1 -0
  35. package/dist/Integration/services/integration-data.service.js +292 -0
  36. package/dist/Integration/services/integration-data.service.js.map +1 -0
  37. package/dist/__tests__/connection-studio.test.d.ts +2 -0
  38. package/dist/__tests__/connection-studio.test.d.ts.map +1 -0
  39. package/dist/__tests__/connection-studio.test.js +186 -0
  40. package/dist/__tests__/connection-studio.test.js.map +1 -0
  41. package/dist/__tests__/integration-data-service.test.d.ts +2 -0
  42. package/dist/__tests__/integration-data-service.test.d.ts.map +1 -0
  43. package/dist/__tests__/integration-data-service.test.js +131 -0
  44. package/dist/__tests__/integration-data-service.test.js.map +1 -0
  45. package/dist/module.d.ts +2 -1
  46. package/dist/module.d.ts.map +1 -1
  47. package/dist/module.js +17 -6
  48. package/dist/module.js.map +1 -1
  49. package/dist/public-api.d.ts +2 -1
  50. package/dist/public-api.d.ts.map +1 -1
  51. package/dist/public-api.js +3 -1
  52. package/dist/public-api.js.map +1 -1
  53. package/package.json +40 -39
@@ -0,0 +1,154 @@
1
+ import { IRunViewProvider } from '@memberjunction/core';
2
+ import * as i0 from "@angular/core";
3
+ /**
4
+ * Simple row types for read-only data loaded via ResultType: 'simple'
5
+ */
6
+ export interface IntegrationRow {
7
+ ID: string;
8
+ Name: string;
9
+ IsActive: boolean | null;
10
+ LastRunID: string | null;
11
+ LastRunStartedAt: string | null;
12
+ LastRunEndedAt: string | null;
13
+ Company: string;
14
+ Integration: string;
15
+ DriverClassName: string | null;
16
+ }
17
+ export interface IntegrationRunRow {
18
+ ID: string;
19
+ CompanyIntegrationID: string;
20
+ StartedAt: string | null;
21
+ EndedAt: string | null;
22
+ TotalRecords: number;
23
+ Status: 'Failed' | 'In Progress' | 'Pending' | 'Success';
24
+ ErrorLog: string | null;
25
+ Integration: string;
26
+ Company: string;
27
+ RunByUser: string;
28
+ }
29
+ export interface SourceTypeRow {
30
+ ID: string;
31
+ Name: string;
32
+ Description: string | null;
33
+ DriverClass: string;
34
+ IconClass: string | null;
35
+ Status: 'Active' | 'Inactive';
36
+ }
37
+ export interface EntityMapRow {
38
+ ID: string;
39
+ CompanyIntegrationID: string;
40
+ ExternalObjectName: string;
41
+ ExternalObjectLabel: string | null;
42
+ EntityID: string;
43
+ SyncDirection: 'Bidirectional' | 'Pull' | 'Push';
44
+ SyncEnabled: boolean;
45
+ MatchStrategy: string | null;
46
+ ConflictResolution: 'DestWins' | 'Manual' | 'MostRecent' | 'SourceWins';
47
+ Priority: number;
48
+ DeleteBehavior: 'DoNothing' | 'HardDelete' | 'SoftDelete';
49
+ Status: 'Active' | 'Inactive';
50
+ Entity: string;
51
+ }
52
+ export interface FieldMapRow {
53
+ ID: string;
54
+ EntityMapID: string;
55
+ SourceFieldName: string;
56
+ SourceFieldLabel: string | null;
57
+ DestinationFieldName: string;
58
+ DestinationFieldLabel: string | null;
59
+ Direction: 'Both' | 'DestToSource' | 'SourceToDest';
60
+ TransformPipeline: string | null;
61
+ IsKeyField: boolean;
62
+ IsRequired: boolean;
63
+ DefaultValue: string | null;
64
+ Priority: number;
65
+ Status: 'Active' | 'Inactive';
66
+ }
67
+ export interface RunDetailRow {
68
+ ID: string;
69
+ CompanyIntegrationRunID: string;
70
+ EntityID: string;
71
+ RecordsProcessed: number;
72
+ RecordsCreated: number;
73
+ RecordsUpdated: number;
74
+ RecordsDeleted: number;
75
+ RecordsErrored: number;
76
+ RecordsSkipped: number;
77
+ Entity: string;
78
+ }
79
+ /** Master integration definition (e.g., "HubSpot", "Salesforce") */
80
+ export interface IntegrationDefinitionRow {
81
+ ID: string;
82
+ Name: string;
83
+ Description: string | null;
84
+ ClassName: string | null;
85
+ ImportPath: string | null;
86
+ NavigationBaseURL: string | null;
87
+ BatchMaxRequestCount: number;
88
+ BatchRequestWaitTime: number;
89
+ CredentialTypeID: string | null;
90
+ }
91
+ /** Aggregated summary for a single integration, used by the Control Tower UI */
92
+ export interface IntegrationSummary {
93
+ Integration: IntegrationRow;
94
+ SourceType: SourceTypeRow | null;
95
+ LatestRun: IntegrationRunRow | null;
96
+ RecentRuns: IntegrationRunRow[];
97
+ StatusColor: 'green' | 'amber' | 'red' | 'gray';
98
+ RelativeTime: string;
99
+ TotalRecordsSyncedToday: number;
100
+ TotalErrors: number;
101
+ DurationMs: number | null;
102
+ }
103
+ /** KPI data for the Control Tower top strip */
104
+ export interface IntegrationKPIs {
105
+ TotalIntegrations: number;
106
+ ActiveSyncs: number;
107
+ RecordsSyncedToday: number;
108
+ ErrorRate: number;
109
+ AverageSyncDurationMs: number | null;
110
+ }
111
+ /** Activity feed item for the Control Tower bottom section */
112
+ export interface ActivityFeedItem {
113
+ RunID: string;
114
+ IntegrationName: string;
115
+ Status: 'Failed' | 'In Progress' | 'Pending' | 'Success';
116
+ StatusColor: 'amber' | 'green' | 'red';
117
+ StartedAt: string | null;
118
+ RelativeTime: string;
119
+ TotalRecords: number;
120
+ RunByUser: string;
121
+ }
122
+ /** Daily record count for the bar chart */
123
+ export interface DailyRecordCount {
124
+ Date: string;
125
+ Label: string;
126
+ Records: number;
127
+ }
128
+ export declare class IntegrationDataService {
129
+ LoadIntegrationSummaries(provider?: IRunViewProvider | null): Promise<IntegrationSummary[]>;
130
+ LoadEntityMaps(companyIntegrationID: string, provider?: IRunViewProvider | null): Promise<EntityMapRow[]>;
131
+ LoadFieldMaps(entityMapID: string, provider?: IRunViewProvider | null): Promise<FieldMapRow[]>;
132
+ LoadRunHistory(companyIntegrationID: string, limit?: number, provider?: IRunViewProvider | null): Promise<IntegrationRunRow[]>;
133
+ LoadRunDetails(runID: string, provider?: IRunViewProvider | null): Promise<RunDetailRow[]>;
134
+ LoadIntegrationDefinitions(provider?: IRunViewProvider | null): Promise<IntegrationDefinitionRow[]>;
135
+ LoadSourceTypes(provider?: IRunViewProvider | null): Promise<SourceTypeRow[]>;
136
+ LoadRecentRuns(limit?: number, provider?: IRunViewProvider | null): Promise<ActivityFeedItem[]>;
137
+ LoadDailyRecordCounts(days?: number, provider?: IRunViewProvider | null): Promise<DailyRecordCount[]>;
138
+ ComputeKPIs(summaries: IntegrationSummary[]): IntegrationKPIs;
139
+ FormatDuration(ms: number | null): string;
140
+ ComputeRelativeTime(dateStr: string | null): string;
141
+ private createRunView;
142
+ private buildSummary;
143
+ private buildActivityFeedItem;
144
+ private runStatusColor;
145
+ private computeRecordsSyncedToday;
146
+ private computeDuration;
147
+ private aggregateDailyCounts;
148
+ private computeStatusColor;
149
+ private isStale;
150
+ private computeRelativeTime;
151
+ static ɵfac: i0.ɵɵFactoryDeclaration<IntegrationDataService, never>;
152
+ static ɵprov: i0.ɵɵInjectableDeclaration<IntegrationDataService>;
153
+ }
154
+ //# sourceMappingURL=integration-data.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration-data.service.d.ts","sourceRoot":"","sources":["../../../src/Integration/services/integration-data.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,292 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { RunView } from '@memberjunction/core';
3
+ import { UUIDsEqual } from '@memberjunction/global';
4
+ import * as i0 from "@angular/core";
5
+ export class IntegrationDataService {
6
+ async LoadIntegrationSummaries(provider) {
7
+ const rv = this.createRunView(provider);
8
+ const [integrationsResult, runsResult] = await rv.RunViews([
9
+ {
10
+ EntityName: 'MJ: Company Integrations',
11
+ ExtraFilter: '',
12
+ OrderBy: 'Name',
13
+ Fields: ['ID', 'Name', 'IsActive', 'LastRunID',
14
+ 'LastRunStartedAt', 'LastRunEndedAt', 'Company', 'Integration',
15
+ 'DriverClassName'],
16
+ ResultType: 'simple'
17
+ },
18
+ {
19
+ EntityName: 'MJ: Company Integration Runs',
20
+ ExtraFilter: '',
21
+ OrderBy: 'StartedAt DESC',
22
+ Fields: ['ID', 'CompanyIntegrationID', 'StartedAt', 'EndedAt', 'TotalRecords',
23
+ 'Status', 'ErrorLog', 'Integration', 'Company', 'RunByUser'],
24
+ ResultType: 'simple'
25
+ }
26
+ ]);
27
+ const integrations = integrationsResult.Results;
28
+ const runs = runsResult.Results;
29
+ return integrations.map(integration => this.buildSummary(integration, runs));
30
+ }
31
+ async LoadEntityMaps(companyIntegrationID, provider) {
32
+ const rv = this.createRunView(provider);
33
+ const result = await rv.RunView({
34
+ EntityName: 'MJ: Company Integration Entity Maps',
35
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}'`,
36
+ OrderBy: 'Priority, ExternalObjectName',
37
+ Fields: ['ID', 'CompanyIntegrationID', 'ExternalObjectName', 'ExternalObjectLabel',
38
+ 'EntityID', 'SyncDirection', 'SyncEnabled', 'MatchStrategy',
39
+ 'ConflictResolution', 'Priority', 'DeleteBehavior', 'Status', 'Entity'],
40
+ ResultType: 'simple'
41
+ });
42
+ return result.Results;
43
+ }
44
+ async LoadFieldMaps(entityMapID, provider) {
45
+ const rv = this.createRunView(provider);
46
+ const result = await rv.RunView({
47
+ EntityName: 'MJ: Company Integration Field Maps',
48
+ ExtraFilter: `EntityMapID='${entityMapID}'`,
49
+ OrderBy: 'Priority, SourceFieldName',
50
+ Fields: ['ID', 'EntityMapID', 'SourceFieldName', 'SourceFieldLabel',
51
+ 'DestinationFieldName', 'DestinationFieldLabel', 'Direction',
52
+ 'TransformPipeline', 'IsKeyField', 'IsRequired', 'DefaultValue',
53
+ 'Priority', 'Status'],
54
+ ResultType: 'simple'
55
+ });
56
+ return result.Results;
57
+ }
58
+ async LoadRunHistory(companyIntegrationID, limit = 10, provider) {
59
+ const rv = this.createRunView(provider);
60
+ const result = await rv.RunView({
61
+ EntityName: 'MJ: Company Integration Runs',
62
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}'`,
63
+ OrderBy: 'StartedAt DESC',
64
+ MaxRows: limit,
65
+ Fields: ['ID', 'CompanyIntegrationID', 'StartedAt', 'EndedAt', 'TotalRecords',
66
+ 'Status', 'ErrorLog', 'Integration', 'Company', 'RunByUser'],
67
+ ResultType: 'simple'
68
+ });
69
+ return result.Results;
70
+ }
71
+ async LoadRunDetails(runID, provider) {
72
+ const rv = this.createRunView(provider);
73
+ const result = await rv.RunView({
74
+ EntityName: 'MJ: Company Integration Run Details',
75
+ ExtraFilter: `CompanyIntegrationRunID='${runID}'`,
76
+ OrderBy: 'Entity',
77
+ Fields: ['ID', 'CompanyIntegrationRunID', 'EntityID', 'RecordsProcessed',
78
+ 'RecordsCreated', 'RecordsUpdated', 'RecordsDeleted',
79
+ 'RecordsErrored', 'RecordsSkipped', 'Entity'],
80
+ ResultType: 'simple'
81
+ });
82
+ return result.Results;
83
+ }
84
+ async LoadIntegrationDefinitions(provider) {
85
+ const rv = this.createRunView(provider);
86
+ const result = await rv.RunView({
87
+ EntityName: 'MJ: Integrations',
88
+ ExtraFilter: '',
89
+ OrderBy: 'Name',
90
+ Fields: ['ID', 'Name', 'Description', 'ClassName', 'ImportPath',
91
+ 'NavigationBaseURL', 'BatchMaxRequestCount', 'BatchRequestWaitTime',
92
+ 'CredentialTypeID'],
93
+ ResultType: 'simple'
94
+ });
95
+ return result.Results;
96
+ }
97
+ async LoadSourceTypes(provider) {
98
+ const rv = this.createRunView(provider);
99
+ const result = await rv.RunView({
100
+ EntityName: 'MJ: Integration Source Types',
101
+ ExtraFilter: 'Status=\'Active\'',
102
+ OrderBy: 'Name',
103
+ Fields: ['ID', 'Name', 'Description', 'DriverClass', 'IconClass', 'Status'],
104
+ ResultType: 'simple'
105
+ });
106
+ return result.Results;
107
+ }
108
+ async LoadRecentRuns(limit = 20, provider) {
109
+ const rv = this.createRunView(provider);
110
+ const result = await rv.RunView({
111
+ EntityName: 'MJ: Company Integration Runs',
112
+ ExtraFilter: '',
113
+ OrderBy: 'StartedAt DESC',
114
+ MaxRows: limit,
115
+ Fields: ['ID', 'CompanyIntegrationID', 'StartedAt', 'EndedAt', 'TotalRecords',
116
+ 'Status', 'ErrorLog', 'Integration', 'Company', 'RunByUser'],
117
+ ResultType: 'simple'
118
+ });
119
+ return result.Results.map(run => this.buildActivityFeedItem(run));
120
+ }
121
+ async LoadDailyRecordCounts(days = 7, provider) {
122
+ const rv = this.createRunView(provider);
123
+ const cutoffDate = new Date();
124
+ cutoffDate.setDate(cutoffDate.getDate() - days);
125
+ const cutoffStr = cutoffDate.toISOString().split('T')[0];
126
+ const result = await rv.RunView({
127
+ EntityName: 'MJ: Company Integration Runs',
128
+ ExtraFilter: `StartedAt >= '${cutoffStr}'`,
129
+ OrderBy: 'StartedAt ASC',
130
+ Fields: ['ID', 'CompanyIntegrationID', 'StartedAt', 'EndedAt', 'TotalRecords',
131
+ 'Status', 'ErrorLog', 'Integration', 'Company', 'RunByUser'],
132
+ ResultType: 'simple'
133
+ });
134
+ return this.aggregateDailyCounts(result.Results, days);
135
+ }
136
+ ComputeKPIs(summaries) {
137
+ const totalIntegrations = summaries.length;
138
+ const activeSyncs = summaries.filter(s => s.LatestRun?.Status === 'In Progress' || s.LatestRun?.Status === 'Pending').length;
139
+ const recordsSyncedToday = summaries.reduce((acc, s) => acc + s.TotalRecordsSyncedToday, 0);
140
+ const totalRuns = summaries.reduce((acc, s) => acc + s.RecentRuns.length, 0);
141
+ const totalErrors = summaries.reduce((acc, s) => acc + s.TotalErrors, 0);
142
+ const errorRate = totalRuns > 0 ? (totalErrors / totalRuns) * 100 : 0;
143
+ const durationsMs = summaries
144
+ .filter(s => s.DurationMs != null)
145
+ .map(s => s.DurationMs);
146
+ const averageSyncDurationMs = durationsMs.length > 0
147
+ ? durationsMs.reduce((a, b) => a + b, 0) / durationsMs.length
148
+ : null;
149
+ return {
150
+ TotalIntegrations: totalIntegrations,
151
+ ActiveSyncs: activeSyncs,
152
+ RecordsSyncedToday: recordsSyncedToday,
153
+ ErrorRate: Math.round(errorRate * 10) / 10,
154
+ AverageSyncDurationMs: averageSyncDurationMs
155
+ };
156
+ }
157
+ FormatDuration(ms) {
158
+ if (ms == null)
159
+ return '--';
160
+ const totalSeconds = Math.floor(ms / 1000);
161
+ if (totalSeconds < 60)
162
+ return `${totalSeconds}s`;
163
+ const minutes = Math.floor(totalSeconds / 60);
164
+ const seconds = totalSeconds % 60;
165
+ if (minutes < 60)
166
+ return `${minutes}m ${seconds}s`;
167
+ const hours = Math.floor(minutes / 60);
168
+ const remainingMinutes = minutes % 60;
169
+ return `${hours}h ${remainingMinutes}m`;
170
+ }
171
+ ComputeRelativeTime(dateStr) {
172
+ return this.computeRelativeTime(dateStr);
173
+ }
174
+ createRunView(provider) {
175
+ return new RunView(provider ?? null);
176
+ }
177
+ buildSummary(integration, allRuns) {
178
+ const integrationRuns = allRuns.filter(r => UUIDsEqual(r.CompanyIntegrationID, integration.ID));
179
+ const latestRun = integrationRuns.length > 0 ? integrationRuns[0] : null;
180
+ const recentRuns = integrationRuns.slice(0, 5);
181
+ const statusColor = this.computeStatusColor(latestRun, integration.IsActive);
182
+ const relativeTime = this.computeRelativeTime(latestRun?.StartedAt ?? null);
183
+ const totalRecordsSyncedToday = this.computeRecordsSyncedToday(integrationRuns);
184
+ const totalErrors = integrationRuns.filter(r => r.Status === 'Failed').length;
185
+ const durationMs = this.computeDuration(latestRun);
186
+ return {
187
+ Integration: integration,
188
+ SourceType: null,
189
+ LatestRun: latestRun,
190
+ RecentRuns: recentRuns,
191
+ StatusColor: statusColor,
192
+ RelativeTime: relativeTime,
193
+ TotalRecordsSyncedToday: totalRecordsSyncedToday,
194
+ TotalErrors: totalErrors,
195
+ DurationMs: durationMs
196
+ };
197
+ }
198
+ buildActivityFeedItem(run) {
199
+ return {
200
+ RunID: run.ID,
201
+ IntegrationName: run.Integration,
202
+ Status: run.Status,
203
+ StatusColor: this.runStatusColor(run),
204
+ StartedAt: run.StartedAt,
205
+ RelativeTime: this.computeRelativeTime(run.StartedAt),
206
+ TotalRecords: run.TotalRecords,
207
+ RunByUser: run.RunByUser
208
+ };
209
+ }
210
+ runStatusColor(run) {
211
+ if (run.Status === 'Failed')
212
+ return 'red';
213
+ if (run.Status === 'Success')
214
+ return 'green';
215
+ return 'amber';
216
+ }
217
+ computeRecordsSyncedToday(runs) {
218
+ const todayStart = new Date();
219
+ todayStart.setHours(0, 0, 0, 0);
220
+ return runs
221
+ .filter(r => r.StartedAt && new Date(r.StartedAt) >= todayStart)
222
+ .reduce((acc, r) => acc + r.TotalRecords, 0);
223
+ }
224
+ computeDuration(run) {
225
+ if (!run?.StartedAt || !run?.EndedAt)
226
+ return null;
227
+ return new Date(run.EndedAt).getTime() - new Date(run.StartedAt).getTime();
228
+ }
229
+ aggregateDailyCounts(runs, days) {
230
+ const result = [];
231
+ const today = new Date();
232
+ for (let i = days - 1; i >= 0; i--) {
233
+ const date = new Date(today);
234
+ date.setDate(date.getDate() - i);
235
+ const dateStr = date.toISOString().split('T')[0];
236
+ const label = date.toLocaleDateString(undefined, { weekday: 'short' });
237
+ const dayRecords = runs
238
+ .filter(r => r.StartedAt && r.StartedAt.startsWith(dateStr))
239
+ .reduce((acc, r) => acc + r.TotalRecords, 0);
240
+ result.push({ Date: dateStr, Label: label, Records: dayRecords });
241
+ }
242
+ return result;
243
+ }
244
+ computeStatusColor(latestRun, isActive) {
245
+ if (!isActive)
246
+ return 'gray';
247
+ if (!latestRun)
248
+ return 'gray';
249
+ if (latestRun.Status === 'Failed')
250
+ return 'red';
251
+ if (latestRun.Status === 'In Progress' || latestRun.Status === 'Pending')
252
+ return 'amber';
253
+ if (latestRun.Status === 'Success') {
254
+ return this.isStale(latestRun.StartedAt) ? 'amber' : 'green';
255
+ }
256
+ return 'gray';
257
+ }
258
+ isStale(startedAt) {
259
+ if (!startedAt)
260
+ return true;
261
+ const runDate = new Date(startedAt);
262
+ const hoursAgo = (Date.now() - runDate.getTime()) / (1000 * 60 * 60);
263
+ return hoursAgo > 24;
264
+ }
265
+ computeRelativeTime(dateStr) {
266
+ if (!dateStr)
267
+ return 'Never run';
268
+ const date = new Date(dateStr);
269
+ const diffMs = Date.now() - date.getTime();
270
+ const diffMinutes = Math.floor(diffMs / (1000 * 60));
271
+ if (diffMinutes < 1)
272
+ return 'Just now';
273
+ if (diffMinutes < 60)
274
+ return `${diffMinutes}m ago`;
275
+ const diffHours = Math.floor(diffMinutes / 60);
276
+ if (diffHours < 24)
277
+ return `${diffHours}h ago`;
278
+ const diffDays = Math.floor(diffHours / 24);
279
+ if (diffDays < 30)
280
+ return `${diffDays}d ago`;
281
+ return date.toLocaleDateString();
282
+ }
283
+ static ɵfac = function IntegrationDataService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || IntegrationDataService)(); };
284
+ static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: IntegrationDataService, factory: IntegrationDataService.ɵfac, providedIn: 'root' });
285
+ }
286
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(IntegrationDataService, [{
287
+ type: Injectable,
288
+ args: [{
289
+ providedIn: 'root'
290
+ }]
291
+ }], null, null); })();
292
+ //# sourceMappingURL=integration-data.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration-data.service.js","sourceRoot":"","sources":["../../../src/Integration/services/integration-data.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { RunView, IRunViewProvider } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n/**\n * Simple row types for read-only data loaded via ResultType: 'simple'\n */\nexport interface IntegrationRow {\n ID: string;\n Name: string;\n IsActive: boolean | null;\n LastRunID: string | null;\n LastRunStartedAt: string | null;\n LastRunEndedAt: string | null;\n Company: string;\n Integration: string;\n DriverClassName: string | null;\n}\n\nexport interface IntegrationRunRow {\n ID: string;\n CompanyIntegrationID: string;\n StartedAt: string | null;\n EndedAt: string | null;\n TotalRecords: number;\n Status: 'Failed' | 'In Progress' | 'Pending' | 'Success';\n ErrorLog: string | null;\n Integration: string;\n Company: string;\n RunByUser: string;\n}\n\nexport interface SourceTypeRow {\n ID: string;\n Name: string;\n Description: string | null;\n DriverClass: string;\n IconClass: string | null;\n Status: 'Active' | 'Inactive';\n}\n\nexport interface EntityMapRow {\n ID: string;\n CompanyIntegrationID: string;\n ExternalObjectName: string;\n ExternalObjectLabel: string | null;\n EntityID: string;\n SyncDirection: 'Bidirectional' | 'Pull' | 'Push';\n SyncEnabled: boolean;\n MatchStrategy: string | null;\n ConflictResolution: 'DestWins' | 'Manual' | 'MostRecent' | 'SourceWins';\n Priority: number;\n DeleteBehavior: 'DoNothing' | 'HardDelete' | 'SoftDelete';\n Status: 'Active' | 'Inactive';\n Entity: string;\n}\n\nexport interface FieldMapRow {\n ID: string;\n EntityMapID: string;\n SourceFieldName: string;\n SourceFieldLabel: string | null;\n DestinationFieldName: string;\n DestinationFieldLabel: string | null;\n Direction: 'Both' | 'DestToSource' | 'SourceToDest';\n TransformPipeline: string | null;\n IsKeyField: boolean;\n IsRequired: boolean;\n DefaultValue: string | null;\n Priority: number;\n Status: 'Active' | 'Inactive';\n}\n\nexport interface RunDetailRow {\n ID: string;\n CompanyIntegrationRunID: string;\n EntityID: string;\n RecordsProcessed: number;\n RecordsCreated: number;\n RecordsUpdated: number;\n RecordsDeleted: number;\n RecordsErrored: number;\n RecordsSkipped: number;\n Entity: string;\n}\n\n/** Master integration definition (e.g., \"HubSpot\", \"Salesforce\") */\nexport interface IntegrationDefinitionRow {\n ID: string;\n Name: string;\n Description: string | null;\n ClassName: string | null;\n ImportPath: string | null;\n NavigationBaseURL: string | null;\n BatchMaxRequestCount: number;\n BatchRequestWaitTime: number;\n CredentialTypeID: string | null;\n}\n\n/** Aggregated summary for a single integration, used by the Control Tower UI */\nexport interface IntegrationSummary {\n Integration: IntegrationRow;\n SourceType: SourceTypeRow | null;\n LatestRun: IntegrationRunRow | null;\n RecentRuns: IntegrationRunRow[];\n StatusColor: 'green' | 'amber' | 'red' | 'gray';\n RelativeTime: string;\n TotalRecordsSyncedToday: number;\n TotalErrors: number;\n DurationMs: number | null;\n}\n\n/** KPI data for the Control Tower top strip */\nexport interface IntegrationKPIs {\n TotalIntegrations: number;\n ActiveSyncs: number;\n RecordsSyncedToday: number;\n ErrorRate: number;\n AverageSyncDurationMs: number | null;\n}\n\n/** Activity feed item for the Control Tower bottom section */\nexport interface ActivityFeedItem {\n RunID: string;\n IntegrationName: string;\n Status: 'Failed' | 'In Progress' | 'Pending' | 'Success';\n StatusColor: 'amber' | 'green' | 'red';\n StartedAt: string | null;\n RelativeTime: string;\n TotalRecords: number;\n RunByUser: string;\n}\n\n/** Daily record count for the bar chart */\nexport interface DailyRecordCount {\n Date: string;\n Label: string;\n Records: number;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class IntegrationDataService {\n\n async LoadIntegrationSummaries(provider?: IRunViewProvider | null): Promise<IntegrationSummary[]> {\n const rv = this.createRunView(provider);\n const [integrationsResult, runsResult] = await rv.RunViews([\n {\n EntityName: 'MJ: Company Integrations',\n ExtraFilter: '',\n OrderBy: 'Name',\n Fields: ['ID', 'Name', 'IsActive', 'LastRunID',\n 'LastRunStartedAt', 'LastRunEndedAt', 'Company', 'Integration',\n 'DriverClassName'],\n ResultType: 'simple'\n },\n {\n EntityName: 'MJ: Company Integration Runs',\n ExtraFilter: '',\n OrderBy: 'StartedAt DESC',\n Fields: ['ID', 'CompanyIntegrationID', 'StartedAt', 'EndedAt', 'TotalRecords',\n 'Status', 'ErrorLog', 'Integration', 'Company', 'RunByUser'],\n ResultType: 'simple'\n }\n ]);\n\n const integrations = integrationsResult.Results as IntegrationRow[];\n const runs = runsResult.Results as IntegrationRunRow[];\n\n return integrations.map(integration => this.buildSummary(integration, runs));\n }\n\n async LoadEntityMaps(companyIntegrationID: string, provider?: IRunViewProvider | null): Promise<EntityMapRow[]> {\n const rv = this.createRunView(provider);\n const result = await rv.RunView<EntityMapRow>({\n EntityName: 'MJ: Company Integration Entity Maps',\n ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}'`,\n OrderBy: 'Priority, ExternalObjectName',\n Fields: ['ID', 'CompanyIntegrationID', 'ExternalObjectName', 'ExternalObjectLabel',\n 'EntityID', 'SyncDirection', 'SyncEnabled', 'MatchStrategy',\n 'ConflictResolution', 'Priority', 'DeleteBehavior', 'Status', 'Entity'],\n ResultType: 'simple'\n });\n return result.Results;\n }\n\n async LoadFieldMaps(entityMapID: string, provider?: IRunViewProvider | null): Promise<FieldMapRow[]> {\n const rv = this.createRunView(provider);\n const result = await rv.RunView<FieldMapRow>({\n EntityName: 'MJ: Company Integration Field Maps',\n ExtraFilter: `EntityMapID='${entityMapID}'`,\n OrderBy: 'Priority, SourceFieldName',\n Fields: ['ID', 'EntityMapID', 'SourceFieldName', 'SourceFieldLabel',\n 'DestinationFieldName', 'DestinationFieldLabel', 'Direction',\n 'TransformPipeline', 'IsKeyField', 'IsRequired', 'DefaultValue',\n 'Priority', 'Status'],\n ResultType: 'simple'\n });\n return result.Results;\n }\n\n async LoadRunHistory(companyIntegrationID: string, limit: number = 10, provider?: IRunViewProvider | null): Promise<IntegrationRunRow[]> {\n const rv = this.createRunView(provider);\n const result = await rv.RunView<IntegrationRunRow>({\n EntityName: 'MJ: Company Integration Runs',\n ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}'`,\n OrderBy: 'StartedAt DESC',\n MaxRows: limit,\n Fields: ['ID', 'CompanyIntegrationID', 'StartedAt', 'EndedAt', 'TotalRecords',\n 'Status', 'ErrorLog', 'Integration', 'Company', 'RunByUser'],\n ResultType: 'simple'\n });\n return result.Results;\n }\n\n async LoadRunDetails(runID: string, provider?: IRunViewProvider | null): Promise<RunDetailRow[]> {\n const rv = this.createRunView(provider);\n const result = await rv.RunView<RunDetailRow>({\n EntityName: 'MJ: Company Integration Run Details',\n ExtraFilter: `CompanyIntegrationRunID='${runID}'`,\n OrderBy: 'Entity',\n Fields: ['ID', 'CompanyIntegrationRunID', 'EntityID', 'RecordsProcessed',\n 'RecordsCreated', 'RecordsUpdated', 'RecordsDeleted',\n 'RecordsErrored', 'RecordsSkipped', 'Entity'],\n ResultType: 'simple'\n });\n return result.Results;\n }\n\n async LoadIntegrationDefinitions(provider?: IRunViewProvider | null): Promise<IntegrationDefinitionRow[]> {\n const rv = this.createRunView(provider);\n const result = await rv.RunView<IntegrationDefinitionRow>({\n EntityName: 'MJ: Integrations',\n ExtraFilter: '',\n OrderBy: 'Name',\n Fields: ['ID', 'Name', 'Description', 'ClassName', 'ImportPath',\n 'NavigationBaseURL', 'BatchMaxRequestCount', 'BatchRequestWaitTime',\n 'CredentialTypeID'],\n ResultType: 'simple'\n });\n return result.Results;\n }\n\n async LoadSourceTypes(provider?: IRunViewProvider | null): Promise<SourceTypeRow[]> {\n const rv = this.createRunView(provider);\n const result = await rv.RunView<SourceTypeRow>({\n EntityName: 'MJ: Integration Source Types',\n ExtraFilter: 'Status=\\'Active\\'',\n OrderBy: 'Name',\n Fields: ['ID', 'Name', 'Description', 'DriverClass', 'IconClass', 'Status'],\n ResultType: 'simple'\n });\n return result.Results;\n }\n\n async LoadRecentRuns(limit: number = 20, provider?: IRunViewProvider | null): Promise<ActivityFeedItem[]> {\n const rv = this.createRunView(provider);\n const result = await rv.RunView<IntegrationRunRow>({\n EntityName: 'MJ: Company Integration Runs',\n ExtraFilter: '',\n OrderBy: 'StartedAt DESC',\n MaxRows: limit,\n Fields: ['ID', 'CompanyIntegrationID', 'StartedAt', 'EndedAt', 'TotalRecords',\n 'Status', 'ErrorLog', 'Integration', 'Company', 'RunByUser'],\n ResultType: 'simple'\n });\n return result.Results.map(run => this.buildActivityFeedItem(run));\n }\n\n async LoadDailyRecordCounts(days: number = 7, provider?: IRunViewProvider | null): Promise<DailyRecordCount[]> {\n const rv = this.createRunView(provider);\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - days);\n const cutoffStr = cutoffDate.toISOString().split('T')[0];\n\n const result = await rv.RunView<IntegrationRunRow>({\n EntityName: 'MJ: Company Integration Runs',\n ExtraFilter: `StartedAt >= '${cutoffStr}'`,\n OrderBy: 'StartedAt ASC',\n Fields: ['ID', 'CompanyIntegrationID', 'StartedAt', 'EndedAt', 'TotalRecords',\n 'Status', 'ErrorLog', 'Integration', 'Company', 'RunByUser'],\n ResultType: 'simple'\n });\n\n return this.aggregateDailyCounts(result.Results, days);\n }\n\n ComputeKPIs(summaries: IntegrationSummary[]): IntegrationKPIs {\n const totalIntegrations = summaries.length;\n const activeSyncs = summaries.filter(\n s => s.LatestRun?.Status === 'In Progress' || s.LatestRun?.Status === 'Pending'\n ).length;\n const recordsSyncedToday = summaries.reduce((acc, s) => acc + s.TotalRecordsSyncedToday, 0);\n\n const totalRuns = summaries.reduce((acc, s) => acc + s.RecentRuns.length, 0);\n const totalErrors = summaries.reduce((acc, s) => acc + s.TotalErrors, 0);\n const errorRate = totalRuns > 0 ? (totalErrors / totalRuns) * 100 : 0;\n\n const durationsMs = summaries\n .filter(s => s.DurationMs != null)\n .map(s => s.DurationMs as number);\n const averageSyncDurationMs = durationsMs.length > 0\n ? durationsMs.reduce((a, b) => a + b, 0) / durationsMs.length\n : null;\n\n return {\n TotalIntegrations: totalIntegrations,\n ActiveSyncs: activeSyncs,\n RecordsSyncedToday: recordsSyncedToday,\n ErrorRate: Math.round(errorRate * 10) / 10,\n AverageSyncDurationMs: averageSyncDurationMs\n };\n }\n\n FormatDuration(ms: number | null): string {\n if (ms == null) return '--';\n const totalSeconds = Math.floor(ms / 1000);\n if (totalSeconds < 60) return `${totalSeconds}s`;\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n if (minutes < 60) return `${minutes}m ${seconds}s`;\n const hours = Math.floor(minutes / 60);\n const remainingMinutes = minutes % 60;\n return `${hours}h ${remainingMinutes}m`;\n }\n\n ComputeRelativeTime(dateStr: string | null): string {\n return this.computeRelativeTime(dateStr);\n }\n\n private createRunView(provider?: IRunViewProvider | null): RunView {\n return new RunView(provider ?? null);\n }\n\n private buildSummary(\n integration: IntegrationRow,\n allRuns: IntegrationRunRow[]\n ): IntegrationSummary {\n const integrationRuns = allRuns.filter(r => UUIDsEqual(r.CompanyIntegrationID, integration.ID));\n const latestRun = integrationRuns.length > 0 ? integrationRuns[0] : null;\n const recentRuns = integrationRuns.slice(0, 5);\n const statusColor = this.computeStatusColor(latestRun, integration.IsActive);\n const relativeTime = this.computeRelativeTime(latestRun?.StartedAt ?? null);\n const totalRecordsSyncedToday = this.computeRecordsSyncedToday(integrationRuns);\n const totalErrors = integrationRuns.filter(r => r.Status === 'Failed').length;\n const durationMs = this.computeDuration(latestRun);\n\n return {\n Integration: integration,\n SourceType: null,\n LatestRun: latestRun,\n RecentRuns: recentRuns,\n StatusColor: statusColor,\n RelativeTime: relativeTime,\n TotalRecordsSyncedToday: totalRecordsSyncedToday,\n TotalErrors: totalErrors,\n DurationMs: durationMs\n };\n }\n\n private buildActivityFeedItem(run: IntegrationRunRow): ActivityFeedItem {\n return {\n RunID: run.ID,\n IntegrationName: run.Integration,\n Status: run.Status,\n StatusColor: this.runStatusColor(run),\n StartedAt: run.StartedAt,\n RelativeTime: this.computeRelativeTime(run.StartedAt),\n TotalRecords: run.TotalRecords,\n RunByUser: run.RunByUser\n };\n }\n\n private runStatusColor(run: IntegrationRunRow): 'amber' | 'green' | 'red' {\n if (run.Status === 'Failed') return 'red';\n if (run.Status === 'Success') return 'green';\n return 'amber';\n }\n\n private computeRecordsSyncedToday(runs: IntegrationRunRow[]): number {\n const todayStart = new Date();\n todayStart.setHours(0, 0, 0, 0);\n return runs\n .filter(r => r.StartedAt && new Date(r.StartedAt) >= todayStart)\n .reduce((acc, r) => acc + r.TotalRecords, 0);\n }\n\n private computeDuration(run: IntegrationRunRow | null): number | null {\n if (!run?.StartedAt || !run?.EndedAt) return null;\n return new Date(run.EndedAt).getTime() - new Date(run.StartedAt).getTime();\n }\n\n private aggregateDailyCounts(runs: IntegrationRunRow[], days: number): DailyRecordCount[] {\n const result: DailyRecordCount[] = [];\n const today = new Date();\n\n for (let i = days - 1; i >= 0; i--) {\n const date = new Date(today);\n date.setDate(date.getDate() - i);\n const dateStr = date.toISOString().split('T')[0];\n const label = date.toLocaleDateString(undefined, { weekday: 'short' });\n\n const dayRecords = runs\n .filter(r => r.StartedAt && r.StartedAt.startsWith(dateStr))\n .reduce((acc, r) => acc + r.TotalRecords, 0);\n\n result.push({ Date: dateStr, Label: label, Records: dayRecords });\n }\n return result;\n }\n\n private computeStatusColor(\n latestRun: IntegrationRunRow | null,\n isActive: boolean | null\n ): 'green' | 'amber' | 'red' | 'gray' {\n if (!isActive) return 'gray';\n if (!latestRun) return 'gray';\n if (latestRun.Status === 'Failed') return 'red';\n if (latestRun.Status === 'In Progress' || latestRun.Status === 'Pending') return 'amber';\n if (latestRun.Status === 'Success') {\n return this.isStale(latestRun.StartedAt) ? 'amber' : 'green';\n }\n return 'gray';\n }\n\n private isStale(startedAt: string | null): boolean {\n if (!startedAt) return true;\n const runDate = new Date(startedAt);\n const hoursAgo = (Date.now() - runDate.getTime()) / (1000 * 60 * 60);\n return hoursAgo > 24;\n }\n\n private computeRelativeTime(dateStr: string | null): string {\n if (!dateStr) return 'Never run';\n const date = new Date(dateStr);\n const diffMs = Date.now() - date.getTime();\n const diffMinutes = Math.floor(diffMs / (1000 * 60));\n\n if (diffMinutes < 1) return 'Just now';\n if (diffMinutes < 60) return `${diffMinutes}m ago`;\n const diffHours = Math.floor(diffMinutes / 60);\n if (diffHours < 24) return `${diffHours}h ago`;\n const diffDays = Math.floor(diffHours / 24);\n if (diffDays < 30) return `${diffDays}d ago`;\n return date.toLocaleDateString();\n }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=connection-studio.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-studio.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/connection-studio.test.ts"],"names":[],"mappings":""}