@memberjunction/ng-dashboards 6.1.0-edge.2 → 6.1.0-edge.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +180 -4
- package/README.md +1 -1
- package/dist/AI/components/analytics/realtime/realtime-transcripts-data.d.ts.map +1 -1
- package/dist/AI/components/analytics/realtime/realtime-transcripts-data.js +4 -4
- package/dist/AI/components/analytics/realtime/realtime-transcripts-data.js.map +1 -1
- package/dist/DatabaseDesigner/services/database-designer.engine.d.ts.map +1 -1
- package/dist/DatabaseDesigner/services/database-designer.engine.js +5 -9
- package/dist/DatabaseDesigner/services/database-designer.engine.js.map +1 -1
- package/dist/Integration/components/activity/activity.component.d.ts +7 -1
- package/dist/Integration/components/activity/activity.component.d.ts.map +1 -1
- package/dist/Integration/components/activity/activity.component.js +2 -2
- package/dist/Integration/components/activity/activity.component.js.map +1 -1
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.d.ts.map +1 -1
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +3 -0
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -1
- package/dist/Integration/components/overview/overview.component.d.ts.map +1 -1
- package/dist/Integration/components/overview/overview.component.js +2 -1
- package/dist/Integration/components/overview/overview.component.js.map +1 -1
- package/dist/Integration/components/widgets/integration-card.component.d.ts.map +1 -1
- package/dist/Integration/components/widgets/integration-card.component.js +8 -7
- package/dist/Integration/components/widgets/integration-card.component.js.map +1 -1
- package/dist/Integration/components/widgets/run-history-panel.component.d.ts +1 -1
- package/dist/Integration/components/widgets/run-history-panel.component.d.ts.map +1 -1
- package/dist/Integration/components/widgets/run-history-panel.component.js +6 -0
- package/dist/Integration/components/widgets/run-history-panel.component.js.map +1 -1
- package/dist/Integration/services/integration-data.service.d.ts +13 -3
- package/dist/Integration/services/integration-data.service.d.ts.map +1 -1
- package/dist/Integration/services/integration-data.service.js +13 -2
- package/dist/Integration/services/integration-data.service.js.map +1 -1
- package/dist/Workflows/components/workflow-run-debug-state.d.ts +41 -0
- package/dist/Workflows/components/workflow-run-debug-state.d.ts.map +1 -0
- package/dist/Workflows/components/workflow-run-debug-state.js +78 -0
- package/dist/Workflows/components/workflow-run-debug-state.js.map +1 -0
- package/dist/Workflows/components/workflow-run-layout.d.ts +83 -0
- package/dist/Workflows/components/workflow-run-layout.d.ts.map +1 -0
- package/dist/Workflows/components/workflow-run-layout.js +133 -0
- package/dist/Workflows/components/workflow-run-layout.js.map +1 -0
- package/dist/Workflows/components/workflow-runs-resource.component.d.ts +146 -3
- package/dist/Workflows/components/workflow-runs-resource.component.d.ts.map +1 -1
- package/dist/Workflows/components/workflow-runs-resource.component.js +1271 -125
- package/dist/Workflows/components/workflow-runs-resource.component.js.map +1 -1
- package/dist/workflows-dashboards.module.d.ts +2 -1
- package/dist/workflows-dashboards.module.d.ts.map +1 -1
- package/dist/workflows-dashboards.module.js +6 -2
- package/dist/workflows-dashboards.module.js.map +1 -1
- package/package.json +64 -64
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overview.component.d.ts","sourceRoot":"","sources":["../../../../src/Integration/components/overview/overview.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,MAAM,EAAE,SAAS,EAAE,aAAa,EAAU,MAAM,eAAe,CAAC;AAGvG,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAGL,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAEjB,MAAM,yCAAyC,CAAC;;AAYjD,KAAK,eAAe,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAE1D,UAAU,kBAAkB;IAC1B,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAOa,iBAAkB,SAAQ,qBAAsB,YAAW,MAAM,EAAE,SAAS,EAAE,aAAa;IAEtG,SAAS,EAAE,kBAAkB,EAAE,CAAM;IACrC,IAAI,EAAE,eAAe,CAMnB;IACF,YAAY,EAAE,gBAAgB,EAAE,CAAM;IACtC,WAAW,EAAE,gBAAgB,EAAE,CAAM;IACrC,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAa;IAEjD,SAAS,UAAS;IAClB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC3C,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAQ;IAE/C,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,iBAAiB,CAA8C;IAEjE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAO/B,WAAW,IAAI,IAAI;IASb,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBzB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAe9B,eAAe,IAAI,IAAI;IAKvB,OAAO,CAAC,gBAAgB;IA4BxB,OAAO,CAAC,kBAAkB;IA0B1B,yEAAyE;YAC3D,iBAAiB;IAY/B,uEAAuE;IACvE,OAAO,CAAC,yBAAyB;IAiBjC,+DAA+D;IAC/D,OAAO,CAAC,kBAAkB;IAI1B,8EAA8E;IAC9E,OAAO,CAAC,oBAAoB;IAYtB,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBnD,SAAS,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO;IAQzC,IAAI,WAAW,IAAI,MAAM,CAGxB;IAED,IAAI,mBAAmB,IAAI,MAAM,CAIhC;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM;IAIzC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAUnC,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM;IAUvD,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAIjD,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAO9C,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM;IAOhD,oBAAoB,CAAC,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"overview.component.d.ts","sourceRoot":"","sources":["../../../../src/Integration/components/overview/overview.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,MAAM,EAAE,SAAS,EAAE,aAAa,EAAU,MAAM,eAAe,CAAC;AAGvG,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAGL,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAEjB,MAAM,yCAAyC,CAAC;;AAYjD,KAAK,eAAe,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAE1D,UAAU,kBAAkB;IAC1B,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAOa,iBAAkB,SAAQ,qBAAsB,YAAW,MAAM,EAAE,SAAS,EAAE,aAAa;IAEtG,SAAS,EAAE,kBAAkB,EAAE,CAAM;IACrC,IAAI,EAAE,eAAe,CAMnB;IACF,YAAY,EAAE,gBAAgB,EAAE,CAAM;IACtC,WAAW,EAAE,gBAAgB,EAAE,CAAM;IACrC,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAa;IAEjD,SAAS,UAAS;IAClB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC3C,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAQ;IAE/C,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,iBAAiB,CAA8C;IAEjE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAO/B,WAAW,IAAI,IAAI;IASb,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBzB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAe9B,eAAe,IAAI,IAAI;IAKvB,OAAO,CAAC,gBAAgB;IA4BxB,OAAO,CAAC,kBAAkB;IA0B1B,yEAAyE;YAC3D,iBAAiB;IAY/B,uEAAuE;IACvE,OAAO,CAAC,yBAAyB;IAiBjC,+DAA+D;IAC/D,OAAO,CAAC,kBAAkB;IAI1B,8EAA8E;IAC9E,OAAO,CAAC,oBAAoB;IAYtB,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBnD,SAAS,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO;IAQzC,IAAI,WAAW,IAAI,MAAM,CAGxB;IAED,IAAI,mBAAmB,IAAI,MAAM,CAIhC;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM;IAIzC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAUnC,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM;IAUvD,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAIjD,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAO9C,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM;IAOhD,oBAAoB,CAAC,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;IAQrD,mBAAmB,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM;IAKnD,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAQlD,IAAI,eAAe,IAAI,MAAM,CAI5B;IAED,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAQlC,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAW1C,mBAAmB,IAAI,IAAI;IASrB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAI5D,oBAAoB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;YAQlD,mBAAmB;YASnB,iBAAiB;IAc/B,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,sBAAsB;yCApYnB,iBAAiB;2CAAjB,iBAAiB;CA0Y7B;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C"}
|
|
@@ -621,7 +621,8 @@ let OverviewComponent = class OverviewComponent extends BaseResourceComponent {
|
|
|
621
621
|
return 'spark-dot spark-green';
|
|
622
622
|
if (run.Status === 'Failed')
|
|
623
623
|
return 'spark-dot spark-red';
|
|
624
|
-
|
|
624
|
+
// 'Queued' joins the work-outstanding states; 'Cancelled' falls through to neutral gray below.
|
|
625
|
+
if (run.Status === 'In Progress' || run.Status === 'Pending' || run.Status === 'Queued')
|
|
625
626
|
return 'spark-dot spark-amber';
|
|
626
627
|
return 'spark-dot spark-gray';
|
|
627
628
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overview.component.js","sourceRoot":"","sources":["../../../../src/Integration/components/overview/overview.component.ts","../../../../src/Integration/components/overview/overview.component.html"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectorRef, Component, OnInit, OnDestroy, AfterViewInit, inject } from '@angular/core';\nimport { RegisterClass, UUIDsEqual } from '@memberjunction/global';\nimport { RunView, IRunViewProvider } from '@memberjunction/core';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { ResourceData } from '@memberjunction/core-entities';\nimport {\n IntegrationDataService,\n ResolveIntegrationIcon,\n IntegrationSummary,\n IntegrationKPIs,\n IntegrationRunRow,\n ActivityFeedItem,\n DailyRecordCount,\n EntityMapRow\n} from '../../services/integration-data.service';\nimport {\n buildOverviewAgentContext,\n resolveIntegrationSurface,\n navLabelForSurface,\n resolveIntegrationRecord,\n buildIntegrationNotFoundError,\n NamedIntegrationRecord,\n} from '../../integration-agent-context';\nimport { CompositeKey } from '@memberjunction/core';\nimport { AgentToolResult, validateStringParam } from '../../../shared/agent-tool-validation';\n\ntype StatusColorType = 'green' | 'amber' | 'red' | 'gray';\n\ninterface NotificationBanner {\n Type: 'success' | 'error';\n Message: string;\n}\n\n@RegisterClass(BaseResourceComponent, 'IntegrationOverview')\n@Component({\n standalone: false,\n selector: 'app-integration-overview',\n templateUrl: './overview.component.html',\n styleUrls: ['./overview.component.css']\n})\nexport class OverviewComponent extends BaseResourceComponent implements OnInit, OnDestroy, AfterViewInit {\n\n Summaries: IntegrationSummary[] = [];\n KPIs: IntegrationKPIs = {\n TotalIntegrations: 0,\n ActiveSyncs: 0,\n RecordsSyncedToday: 0,\n ErrorRate: 0,\n AverageSyncDurationMs: null\n };\n ActivityFeed: ActivityFeedItem[] = [];\n DailyCounts: DailyRecordCount[] = [];\n EntityMapCounts: Map<string, number> = new Map();\n\n IsLoading = false;\n RunningIntegrationID: string | null = null;\n Notification: NotificationBanner | null = null;\n\n private dataService = inject(IntegrationDataService);\n private cdr = inject(ChangeDetectorRef);\n private notificationTimer: ReturnType<typeof setTimeout> | null = null;\n\n async ngOnInit(): Promise<void> {\n super.ngOnInit();\n this.dataService.Provider = this.ProviderToUse;\n await this.LoadData();\n this.NotifyLoadComplete();\n }\n\n ngOnDestroy(): void {\n super.ngOnDestroy();\n this.clearNotificationTimer();\n }\n\n // ---------------------------------------------------------------------------\n // Data Loading\n // ---------------------------------------------------------------------------\n\n async LoadData(): Promise<void> {\n this.IsLoading = true;\n this.cdr.detectChanges();\n try {\n const provider = this.RunViewToUse;\n const [summaries, activityFeed, dailyCounts] = await Promise.all([\n this.dataService.LoadIntegrationSummaries(provider),\n this.dataService.LoadRecentRuns(10, provider),\n this.dataService.LoadDailyRecordCounts(7, provider)\n ]);\n this.Summaries = summaries;\n this.KPIs = this.dataService.ComputeKPIs(summaries);\n this.ActivityFeed = activityFeed;\n this.DailyCounts = dailyCounts;\n await this.loadEntityMapCounts(summaries, provider);\n } catch (err) {\n console.error('[IntegrationOverview] Failed to load data:', err);\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n this.emitAgentContext();\n }\n }\n\n async Refresh(): Promise<void> {\n await this.LoadData();\n }\n\n // ---------------------------------------------------------------------------\n // AI Agent Context & Client Tools\n //\n // 🔒 SAFETY BOUNDARY: The Overview surface exposes ONLY navigational and\n // read-only refresh tools to the agent. It deliberately does NOT expose\n // RunSync() — that triggers a LIVE external sync against a third-party system\n // and must remain user-driven. Edit-mapping, update-schedule, and\n // change-credentials are likewise never exposed. The agent observes KPIs and\n // can navigate / refresh; the user performs every mutating action from the UI.\n // ---------------------------------------------------------------------------\n\n ngAfterViewInit(): void {\n this.emitAgentContext();\n this.registerAgentTools();\n }\n\n private emitAgentContext(): void {\n const context = buildOverviewAgentContext({\n KPIs: {\n TotalIntegrations: this.KPIs.TotalIntegrations,\n ActiveSyncs: this.KPIs.ActiveSyncs,\n RecordsSyncedToday: this.KPIs.RecordsSyncedToday,\n SyncErrorRate: this.KPIs.ErrorRate,\n PipelineCount: this.computePipelineCount(),\n ScheduledSyncCount: 0,\n },\n IsLoading: this.IsLoading,\n SuccessRate: this.SuccessRate,\n HealthyCount: this.countByStatusColor('green'),\n WarningCount: this.countByStatusColor('amber'),\n ErrorCount: this.countByStatusColor('red'),\n InactiveCount: this.countByStatusColor('gray'),\n AverageSyncDurationMs: this.KPIs.AverageSyncDurationMs,\n VisibleIntegrationNames: this.Summaries.map(s => s.Integration.Name),\n ActivityFeedCount: this.ActivityFeed.length,\n RecentActivity: this.ActivityFeed.map(a => ({\n Integration: a.IntegrationName,\n Status: a.Status,\n When: a.RelativeTime,\n })),\n });\n this.navigationService.SetAgentContext(this, context);\n }\n\n private registerAgentTools(): void {\n this.navigationService.SetAgentClientTools(this, [\n {\n Name: 'SwitchIntegrationSurface',\n Description: 'Switch to a different Integration surface. Valid surfaces: Overview, Connections, Activity, Schedules.',\n ParameterSchema: { type: 'object', properties: { surface: { type: 'string' } }, required: ['surface'] },\n Handler: async (params: Record<string, unknown>) => this.toolSwitchSurface(params),\n },\n {\n Name: 'OpenIntegrationRecord',\n Description: 'Open a company-integration record in a tab for viewing. Accepts the integration ID or name (exact or partial).',\n ParameterSchema: { type: 'object', properties: { integration: { type: 'string' } }, required: ['integration'] },\n Handler: async (params: Record<string, unknown>) => this.toolOpenIntegrationRecord(params),\n },\n {\n Name: 'RefreshIntegrationData',\n Description: 'Reload the Integration overview KPIs, pipeline cards, and recent activity.',\n ParameterSchema: { type: 'object', properties: {} },\n Handler: async () => {\n await this.LoadData();\n return { Success: true };\n },\n },\n ]);\n }\n\n /** Resolve a requested surface and route to it via NavigationService. */\n private async toolSwitchSurface(params: Record<string, unknown>): Promise<AgentToolResult> {\n const surface = resolveIntegrationSurface(params['surface']);\n if (!surface) {\n return { Success: false, ErrorMessage: 'Invalid surface. Expected one of: Overview, Connections, Activity, Schedules.' };\n }\n const tabId = await this.navigationService.OpenNavItemByName(navLabelForSurface(surface));\n if (!tabId) {\n return { Success: false, ErrorMessage: `Could not open the \"${surface}\" surface.` };\n }\n return { Success: true };\n }\n\n /** Open a company-integration record (read-only nav) by id or name. */\n private toolOpenIntegrationRecord(params: Record<string, unknown>): AgentToolResult {\n const check = validateStringParam(params['integration'], 'integration');\n if (!check.ok) {\n return check.result;\n }\n const candidates: NamedIntegrationRecord[] = this.Summaries.map(s => ({\n ID: s.Integration.ID,\n Name: s.Integration.Name,\n }));\n const match = resolveIntegrationRecord(check.value, candidates);\n if (!match) {\n return { Success: false, ErrorMessage: buildIntegrationNotFoundError(check.value, candidates, 'integration') };\n }\n this.navigationService.OpenEntityRecord('MJ: Company Integrations', CompositeKey.FromID(match.ID));\n return { Success: true };\n }\n\n /** Count of integrations whose health-status color matches. */\n private countByStatusColor(color: StatusColorType): number {\n return this.Summaries.filter(s => s.StatusColor === color).length;\n }\n\n /** Count of entity-map \"pipelines\" (enabled maps) across all integrations. */\n private computePipelineCount(): number {\n let total = 0;\n for (const value of this.EntityMapCounts.values()) {\n total += value;\n }\n return total;\n }\n\n // ---------------------------------------------------------------------------\n // Sync Actions\n // ---------------------------------------------------------------------------\n\n async RunSync(integrationID: string): Promise<void> {\n if (this.RunningIntegrationID) return;\n this.RunningIntegrationID = integrationID;\n this.dismissNotification();\n this.cdr.detectChanges();\n\n try {\n const result = await this.dataService.RunSync(integrationID);\n if (result.Success) {\n this.showNotification('success', result.Message || 'Sync started successfully');\n await this.LoadData();\n } else {\n this.showNotification('error', result.Message || 'Sync failed');\n }\n } catch (err) {\n const error = err as Error;\n this.showNotification('error', `Unexpected error: ${error.message}`);\n console.error('[IntegrationOverview] RunSync error:', err);\n } finally {\n this.RunningIntegrationID = null;\n this.cdr.detectChanges();\n }\n }\n\n IsRunning(integrationID: string): boolean {\n return UUIDsEqual(this.RunningIntegrationID, integrationID);\n }\n\n // ---------------------------------------------------------------------------\n // KPI Helpers\n // ---------------------------------------------------------------------------\n\n get SuccessRate(): number {\n if (this.KPIs.ErrorRate == null) return 100;\n return Math.round((100 - this.KPIs.ErrorRate) * 10) / 10;\n }\n\n get SuccessRateGradient(): string {\n const pct = this.SuccessRate;\n const angle = (pct / 100) * 360;\n return `conic-gradient(#10b981 ${angle}deg, #e5e7eb ${angle}deg)`;\n }\n\n get ActiveCount(): number {\n return this.KPIs.ActiveSyncs;\n }\n\n FormatDuration(ms: number | null): string {\n return this.dataService.FormatDuration(ms);\n }\n\n FormatNumber(value: number): string {\n if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}M`;\n if (value >= 1_000) return `${(value / 1_000).toFixed(1)}K`;\n return value.toLocaleString();\n }\n\n // ---------------------------------------------------------------------------\n // Pipeline Card Helpers\n // ---------------------------------------------------------------------------\n\n GetIntegrationIcon(summary: IntegrationSummary): string {\n if (summary.SourceType?.IconClass) {\n return summary.SourceType.IconClass;\n }\n return ResolveIntegrationIcon(\n summary.Integration.Integration ?? summary.Integration.Name,\n summary.Icon\n );\n }\n\n GetStatusDotClass(color: StatusColorType): string {\n return `status-dot status-dot-${color}`;\n }\n\n GetStatusLabel(color: StatusColorType): string {\n if (color === 'green') return 'Healthy';\n if (color === 'amber') return 'Warning';\n if (color === 'red') return 'Error';\n return 'Inactive';\n }\n\n GetEntityMapCount(integrationID: string): number {\n for (const [key, value] of this.EntityMapCounts) {\n if (UUIDsEqual(key, integrationID)) return value;\n }\n return 0;\n }\n\n GetSparklineDotClass(run: { Status: string }): string {\n if (run.Status === 'Success') return 'spark-dot spark-green';\n if (run.Status === 'Failed') return 'spark-dot spark-red';\n if (run.Status === 'In Progress' || run.Status === 'Pending') return 'spark-dot spark-amber';\n return 'spark-dot spark-gray';\n }\n\n GetSparklineTooltip(run: IntegrationRunRow): string {\n const when = run.StartedAt ? new Date(run.StartedAt).toLocaleString() : 'N/A';\n return `${run.Status} - ${when}`;\n }\n\n GetCardBorderClass(color: StatusColorType): string {\n return color === 'red' ? 'pipeline-card pipeline-card-error' : 'pipeline-card';\n }\n\n // ---------------------------------------------------------------------------\n // Bar Chart Helpers\n // ---------------------------------------------------------------------------\n\n get MaxDailyRecords(): number {\n if (this.DailyCounts.length === 0) return 1;\n const maxVal = Math.max(...this.DailyCounts.map(d => d.Records));\n return maxVal > 0 ? maxVal : 1;\n }\n\n BarHeight(records: number): number {\n return Math.max((records / this.MaxDailyRecords) * 100, 2);\n }\n\n // ---------------------------------------------------------------------------\n // Activity Feed Helpers\n // ---------------------------------------------------------------------------\n\n ActivityStatusIcon(status: string): string {\n if (status === 'Success') return 'fa-solid fa-circle-check';\n if (status === 'Failed') return 'fa-solid fa-circle-xmark';\n if (status === 'In Progress') return 'fa-solid fa-spinner fa-spin';\n return 'fa-solid fa-clock';\n }\n\n // ---------------------------------------------------------------------------\n // Notification Management\n // ---------------------------------------------------------------------------\n\n DismissNotification(): void {\n this.dismissNotification();\n this.cdr.detectChanges();\n }\n\n // ---------------------------------------------------------------------------\n // Resource Overrides\n // ---------------------------------------------------------------------------\n\n async GetResourceDisplayName(_data: ResourceData): Promise<string> {\n return 'Overview';\n }\n\n async GetResourceIconClass(_data: ResourceData): Promise<string> {\n return 'fa-solid fa-gauge-high';\n }\n\n // ---------------------------------------------------------------------------\n // Private Helpers\n // ---------------------------------------------------------------------------\n\n private async loadEntityMapCounts(\n summaries: IntegrationSummary[],\n provider: IRunViewProvider | null\n ): Promise<void> {\n if (summaries.length === 0) return;\n const allMaps = await this.loadAllEntityMaps(provider);\n this.EntityMapCounts = this.countMapsByIntegration(allMaps);\n }\n\n private async loadAllEntityMaps(\n provider: IRunViewProvider | null\n ): Promise<EntityMapRow[]> {\n const rv = new RunView(provider ?? null);\n const result = await rv.RunView<EntityMapRow>({\n EntityName: 'MJ: Company Integration Entity Maps',\n ExtraFilter: '',\n OrderBy: 'CompanyIntegrationID',\n Fields: ['ID', 'CompanyIntegrationID'],\n ResultType: 'simple'\n });\n return result.Results;\n }\n\n private countMapsByIntegration(maps: EntityMapRow[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const map of maps) {\n const current = counts.get(map.CompanyIntegrationID) ?? 0;\n counts.set(map.CompanyIntegrationID, current + 1);\n }\n return counts;\n }\n\n\n private showNotification(type: 'success' | 'error', message: string): void {\n this.clearNotificationTimer();\n this.Notification = { Type: type, Message: message };\n this.notificationTimer = setTimeout(() => {\n this.Notification = null;\n this.cdr.detectChanges();\n }, 5000);\n }\n\n private dismissNotification(): void {\n this.clearNotificationTimer();\n this.Notification = null;\n }\n\n private clearNotificationTimer(): void {\n if (this.notificationTimer) {\n clearTimeout(this.notificationTimer);\n this.notificationTimer = null;\n }\n }\n}\n\nexport function LoadOverviewComponent(): void {\n // Tree-shaking prevention: importing this module causes\n // @RegisterClass decorators to fire, registering components.\n}\n","<mj-page-layout>\n <mj-page-header\n Title=\"Integration Overview\"\n Icon=\"fa-solid fa-gauge-high\"\n Subtitle=\"Health, throughput, and activity across all integrations\">\n @if (Summaries.length > 0) {\n <div meta>\n <mj-stat-badge [Count]=\"KPIs.TotalIntegrations\" Label=\"integrations\"></mj-stat-badge>\n </div>\n }\n <div actions>\n <mj-refresh-button [Loading]=\"IsLoading\" (Clicked)=\"Refresh()\"></mj-refresh-button>\n </div>\n </mj-page-header>\n\n <mj-page-body>\n<div class=\"overview\">\n <!-- Notification Banner -->\n @if (Notification) {\n <div class=\"notification\" [class.notification-success]=\"Notification.Type === 'success'\"\n [class.notification-error]=\"Notification.Type === 'error'\">\n @if (Notification.Type === 'success') {\n <i class=\"fa-solid fa-circle-check\"></i>\n } @else {\n <i class=\"fa-solid fa-circle-xmark\"></i>\n }\n <span class=\"notification-message\">{{ Notification.Message }}</span>\n <button class=\"notification-dismiss\" (click)=\"DismissNotification()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n\n @if (IsLoading) {\n <mj-loading text=\"Loading integrations...\" size=\"medium\"></mj-loading>\n } @else if (Summaries.length === 0) {\n <mj-empty-state Icon=\"fa-solid fa-plug-circle-xmark\"\n Title=\"No Integrations Configured\"\n Message=\"Set up your first integration using the Connection Studio to start syncing data.\" />\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]=\"GetSparklineTooltip(run)\"></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 · {{ 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 </mj-page-body>\n</mj-page-layout>\n"]}
|
|
1
|
+
{"version":3,"file":"overview.component.js","sourceRoot":"","sources":["../../../../src/Integration/components/overview/overview.component.ts","../../../../src/Integration/components/overview/overview.component.html"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectorRef, Component, OnInit, OnDestroy, AfterViewInit, inject } from '@angular/core';\nimport { RegisterClass, UUIDsEqual } from '@memberjunction/global';\nimport { RunView, IRunViewProvider } from '@memberjunction/core';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { ResourceData } from '@memberjunction/core-entities';\nimport {\n IntegrationDataService,\n ResolveIntegrationIcon,\n IntegrationSummary,\n IntegrationKPIs,\n IntegrationRunRow,\n ActivityFeedItem,\n DailyRecordCount,\n EntityMapRow\n} from '../../services/integration-data.service';\nimport {\n buildOverviewAgentContext,\n resolveIntegrationSurface,\n navLabelForSurface,\n resolveIntegrationRecord,\n buildIntegrationNotFoundError,\n NamedIntegrationRecord,\n} from '../../integration-agent-context';\nimport { CompositeKey } from '@memberjunction/core';\nimport { AgentToolResult, validateStringParam } from '../../../shared/agent-tool-validation';\n\ntype StatusColorType = 'green' | 'amber' | 'red' | 'gray';\n\ninterface NotificationBanner {\n Type: 'success' | 'error';\n Message: string;\n}\n\n@RegisterClass(BaseResourceComponent, 'IntegrationOverview')\n@Component({\n standalone: false,\n selector: 'app-integration-overview',\n templateUrl: './overview.component.html',\n styleUrls: ['./overview.component.css']\n})\nexport class OverviewComponent extends BaseResourceComponent implements OnInit, OnDestroy, AfterViewInit {\n\n Summaries: IntegrationSummary[] = [];\n KPIs: IntegrationKPIs = {\n TotalIntegrations: 0,\n ActiveSyncs: 0,\n RecordsSyncedToday: 0,\n ErrorRate: 0,\n AverageSyncDurationMs: null\n };\n ActivityFeed: ActivityFeedItem[] = [];\n DailyCounts: DailyRecordCount[] = [];\n EntityMapCounts: Map<string, number> = new Map();\n\n IsLoading = false;\n RunningIntegrationID: string | null = null;\n Notification: NotificationBanner | null = null;\n\n private dataService = inject(IntegrationDataService);\n private cdr = inject(ChangeDetectorRef);\n private notificationTimer: ReturnType<typeof setTimeout> | null = null;\n\n async ngOnInit(): Promise<void> {\n super.ngOnInit();\n this.dataService.Provider = this.ProviderToUse;\n await this.LoadData();\n this.NotifyLoadComplete();\n }\n\n ngOnDestroy(): void {\n super.ngOnDestroy();\n this.clearNotificationTimer();\n }\n\n // ---------------------------------------------------------------------------\n // Data Loading\n // ---------------------------------------------------------------------------\n\n async LoadData(): Promise<void> {\n this.IsLoading = true;\n this.cdr.detectChanges();\n try {\n const provider = this.RunViewToUse;\n const [summaries, activityFeed, dailyCounts] = await Promise.all([\n this.dataService.LoadIntegrationSummaries(provider),\n this.dataService.LoadRecentRuns(10, provider),\n this.dataService.LoadDailyRecordCounts(7, provider)\n ]);\n this.Summaries = summaries;\n this.KPIs = this.dataService.ComputeKPIs(summaries);\n this.ActivityFeed = activityFeed;\n this.DailyCounts = dailyCounts;\n await this.loadEntityMapCounts(summaries, provider);\n } catch (err) {\n console.error('[IntegrationOverview] Failed to load data:', err);\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n this.emitAgentContext();\n }\n }\n\n async Refresh(): Promise<void> {\n await this.LoadData();\n }\n\n // ---------------------------------------------------------------------------\n // AI Agent Context & Client Tools\n //\n // 🔒 SAFETY BOUNDARY: The Overview surface exposes ONLY navigational and\n // read-only refresh tools to the agent. It deliberately does NOT expose\n // RunSync() — that triggers a LIVE external sync against a third-party system\n // and must remain user-driven. Edit-mapping, update-schedule, and\n // change-credentials are likewise never exposed. The agent observes KPIs and\n // can navigate / refresh; the user performs every mutating action from the UI.\n // ---------------------------------------------------------------------------\n\n ngAfterViewInit(): void {\n this.emitAgentContext();\n this.registerAgentTools();\n }\n\n private emitAgentContext(): void {\n const context = buildOverviewAgentContext({\n KPIs: {\n TotalIntegrations: this.KPIs.TotalIntegrations,\n ActiveSyncs: this.KPIs.ActiveSyncs,\n RecordsSyncedToday: this.KPIs.RecordsSyncedToday,\n SyncErrorRate: this.KPIs.ErrorRate,\n PipelineCount: this.computePipelineCount(),\n ScheduledSyncCount: 0,\n },\n IsLoading: this.IsLoading,\n SuccessRate: this.SuccessRate,\n HealthyCount: this.countByStatusColor('green'),\n WarningCount: this.countByStatusColor('amber'),\n ErrorCount: this.countByStatusColor('red'),\n InactiveCount: this.countByStatusColor('gray'),\n AverageSyncDurationMs: this.KPIs.AverageSyncDurationMs,\n VisibleIntegrationNames: this.Summaries.map(s => s.Integration.Name),\n ActivityFeedCount: this.ActivityFeed.length,\n RecentActivity: this.ActivityFeed.map(a => ({\n Integration: a.IntegrationName,\n Status: a.Status,\n When: a.RelativeTime,\n })),\n });\n this.navigationService.SetAgentContext(this, context);\n }\n\n private registerAgentTools(): void {\n this.navigationService.SetAgentClientTools(this, [\n {\n Name: 'SwitchIntegrationSurface',\n Description: 'Switch to a different Integration surface. Valid surfaces: Overview, Connections, Activity, Schedules.',\n ParameterSchema: { type: 'object', properties: { surface: { type: 'string' } }, required: ['surface'] },\n Handler: async (params: Record<string, unknown>) => this.toolSwitchSurface(params),\n },\n {\n Name: 'OpenIntegrationRecord',\n Description: 'Open a company-integration record in a tab for viewing. Accepts the integration ID or name (exact or partial).',\n ParameterSchema: { type: 'object', properties: { integration: { type: 'string' } }, required: ['integration'] },\n Handler: async (params: Record<string, unknown>) => this.toolOpenIntegrationRecord(params),\n },\n {\n Name: 'RefreshIntegrationData',\n Description: 'Reload the Integration overview KPIs, pipeline cards, and recent activity.',\n ParameterSchema: { type: 'object', properties: {} },\n Handler: async () => {\n await this.LoadData();\n return { Success: true };\n },\n },\n ]);\n }\n\n /** Resolve a requested surface and route to it via NavigationService. */\n private async toolSwitchSurface(params: Record<string, unknown>): Promise<AgentToolResult> {\n const surface = resolveIntegrationSurface(params['surface']);\n if (!surface) {\n return { Success: false, ErrorMessage: 'Invalid surface. Expected one of: Overview, Connections, Activity, Schedules.' };\n }\n const tabId = await this.navigationService.OpenNavItemByName(navLabelForSurface(surface));\n if (!tabId) {\n return { Success: false, ErrorMessage: `Could not open the \"${surface}\" surface.` };\n }\n return { Success: true };\n }\n\n /** Open a company-integration record (read-only nav) by id or name. */\n private toolOpenIntegrationRecord(params: Record<string, unknown>): AgentToolResult {\n const check = validateStringParam(params['integration'], 'integration');\n if (!check.ok) {\n return check.result;\n }\n const candidates: NamedIntegrationRecord[] = this.Summaries.map(s => ({\n ID: s.Integration.ID,\n Name: s.Integration.Name,\n }));\n const match = resolveIntegrationRecord(check.value, candidates);\n if (!match) {\n return { Success: false, ErrorMessage: buildIntegrationNotFoundError(check.value, candidates, 'integration') };\n }\n this.navigationService.OpenEntityRecord('MJ: Company Integrations', CompositeKey.FromID(match.ID));\n return { Success: true };\n }\n\n /** Count of integrations whose health-status color matches. */\n private countByStatusColor(color: StatusColorType): number {\n return this.Summaries.filter(s => s.StatusColor === color).length;\n }\n\n /** Count of entity-map \"pipelines\" (enabled maps) across all integrations. */\n private computePipelineCount(): number {\n let total = 0;\n for (const value of this.EntityMapCounts.values()) {\n total += value;\n }\n return total;\n }\n\n // ---------------------------------------------------------------------------\n // Sync Actions\n // ---------------------------------------------------------------------------\n\n async RunSync(integrationID: string): Promise<void> {\n if (this.RunningIntegrationID) return;\n this.RunningIntegrationID = integrationID;\n this.dismissNotification();\n this.cdr.detectChanges();\n\n try {\n const result = await this.dataService.RunSync(integrationID);\n if (result.Success) {\n this.showNotification('success', result.Message || 'Sync started successfully');\n await this.LoadData();\n } else {\n this.showNotification('error', result.Message || 'Sync failed');\n }\n } catch (err) {\n const error = err as Error;\n this.showNotification('error', `Unexpected error: ${error.message}`);\n console.error('[IntegrationOverview] RunSync error:', err);\n } finally {\n this.RunningIntegrationID = null;\n this.cdr.detectChanges();\n }\n }\n\n IsRunning(integrationID: string): boolean {\n return UUIDsEqual(this.RunningIntegrationID, integrationID);\n }\n\n // ---------------------------------------------------------------------------\n // KPI Helpers\n // ---------------------------------------------------------------------------\n\n get SuccessRate(): number {\n if (this.KPIs.ErrorRate == null) return 100;\n return Math.round((100 - this.KPIs.ErrorRate) * 10) / 10;\n }\n\n get SuccessRateGradient(): string {\n const pct = this.SuccessRate;\n const angle = (pct / 100) * 360;\n return `conic-gradient(#10b981 ${angle}deg, #e5e7eb ${angle}deg)`;\n }\n\n get ActiveCount(): number {\n return this.KPIs.ActiveSyncs;\n }\n\n FormatDuration(ms: number | null): string {\n return this.dataService.FormatDuration(ms);\n }\n\n FormatNumber(value: number): string {\n if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}M`;\n if (value >= 1_000) return `${(value / 1_000).toFixed(1)}K`;\n return value.toLocaleString();\n }\n\n // ---------------------------------------------------------------------------\n // Pipeline Card Helpers\n // ---------------------------------------------------------------------------\n\n GetIntegrationIcon(summary: IntegrationSummary): string {\n if (summary.SourceType?.IconClass) {\n return summary.SourceType.IconClass;\n }\n return ResolveIntegrationIcon(\n summary.Integration.Integration ?? summary.Integration.Name,\n summary.Icon\n );\n }\n\n GetStatusDotClass(color: StatusColorType): string {\n return `status-dot status-dot-${color}`;\n }\n\n GetStatusLabel(color: StatusColorType): string {\n if (color === 'green') return 'Healthy';\n if (color === 'amber') return 'Warning';\n if (color === 'red') return 'Error';\n return 'Inactive';\n }\n\n GetEntityMapCount(integrationID: string): number {\n for (const [key, value] of this.EntityMapCounts) {\n if (UUIDsEqual(key, integrationID)) return value;\n }\n return 0;\n }\n\n GetSparklineDotClass(run: { Status: string }): string {\n if (run.Status === 'Success') return 'spark-dot spark-green';\n if (run.Status === 'Failed') return 'spark-dot spark-red';\n // 'Queued' joins the work-outstanding states; 'Cancelled' falls through to neutral gray below.\n if (run.Status === 'In Progress' || run.Status === 'Pending' || run.Status === 'Queued') return 'spark-dot spark-amber';\n return 'spark-dot spark-gray';\n }\n\n GetSparklineTooltip(run: IntegrationRunRow): string {\n const when = run.StartedAt ? new Date(run.StartedAt).toLocaleString() : 'N/A';\n return `${run.Status} - ${when}`;\n }\n\n GetCardBorderClass(color: StatusColorType): string {\n return color === 'red' ? 'pipeline-card pipeline-card-error' : 'pipeline-card';\n }\n\n // ---------------------------------------------------------------------------\n // Bar Chart Helpers\n // ---------------------------------------------------------------------------\n\n get MaxDailyRecords(): number {\n if (this.DailyCounts.length === 0) return 1;\n const maxVal = Math.max(...this.DailyCounts.map(d => d.Records));\n return maxVal > 0 ? maxVal : 1;\n }\n\n BarHeight(records: number): number {\n return Math.max((records / this.MaxDailyRecords) * 100, 2);\n }\n\n // ---------------------------------------------------------------------------\n // Activity Feed Helpers\n // ---------------------------------------------------------------------------\n\n ActivityStatusIcon(status: string): string {\n if (status === 'Success') return 'fa-solid fa-circle-check';\n if (status === 'Failed') return 'fa-solid fa-circle-xmark';\n if (status === 'In Progress') return 'fa-solid fa-spinner fa-spin';\n return 'fa-solid fa-clock';\n }\n\n // ---------------------------------------------------------------------------\n // Notification Management\n // ---------------------------------------------------------------------------\n\n DismissNotification(): void {\n this.dismissNotification();\n this.cdr.detectChanges();\n }\n\n // ---------------------------------------------------------------------------\n // Resource Overrides\n // ---------------------------------------------------------------------------\n\n async GetResourceDisplayName(_data: ResourceData): Promise<string> {\n return 'Overview';\n }\n\n async GetResourceIconClass(_data: ResourceData): Promise<string> {\n return 'fa-solid fa-gauge-high';\n }\n\n // ---------------------------------------------------------------------------\n // Private Helpers\n // ---------------------------------------------------------------------------\n\n private async loadEntityMapCounts(\n summaries: IntegrationSummary[],\n provider: IRunViewProvider | null\n ): Promise<void> {\n if (summaries.length === 0) return;\n const allMaps = await this.loadAllEntityMaps(provider);\n this.EntityMapCounts = this.countMapsByIntegration(allMaps);\n }\n\n private async loadAllEntityMaps(\n provider: IRunViewProvider | null\n ): Promise<EntityMapRow[]> {\n const rv = new RunView(provider ?? null);\n const result = await rv.RunView<EntityMapRow>({\n EntityName: 'MJ: Company Integration Entity Maps',\n ExtraFilter: '',\n OrderBy: 'CompanyIntegrationID',\n Fields: ['ID', 'CompanyIntegrationID'],\n ResultType: 'simple'\n });\n return result.Results;\n }\n\n private countMapsByIntegration(maps: EntityMapRow[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const map of maps) {\n const current = counts.get(map.CompanyIntegrationID) ?? 0;\n counts.set(map.CompanyIntegrationID, current + 1);\n }\n return counts;\n }\n\n\n private showNotification(type: 'success' | 'error', message: string): void {\n this.clearNotificationTimer();\n this.Notification = { Type: type, Message: message };\n this.notificationTimer = setTimeout(() => {\n this.Notification = null;\n this.cdr.detectChanges();\n }, 5000);\n }\n\n private dismissNotification(): void {\n this.clearNotificationTimer();\n this.Notification = null;\n }\n\n private clearNotificationTimer(): void {\n if (this.notificationTimer) {\n clearTimeout(this.notificationTimer);\n this.notificationTimer = null;\n }\n }\n}\n\nexport function LoadOverviewComponent(): void {\n // Tree-shaking prevention: importing this module causes\n // @RegisterClass decorators to fire, registering components.\n}\n","<mj-page-layout>\n <mj-page-header\n Title=\"Integration Overview\"\n Icon=\"fa-solid fa-gauge-high\"\n Subtitle=\"Health, throughput, and activity across all integrations\">\n @if (Summaries.length > 0) {\n <div meta>\n <mj-stat-badge [Count]=\"KPIs.TotalIntegrations\" Label=\"integrations\"></mj-stat-badge>\n </div>\n }\n <div actions>\n <mj-refresh-button [Loading]=\"IsLoading\" (Clicked)=\"Refresh()\"></mj-refresh-button>\n </div>\n </mj-page-header>\n\n <mj-page-body>\n<div class=\"overview\">\n <!-- Notification Banner -->\n @if (Notification) {\n <div class=\"notification\" [class.notification-success]=\"Notification.Type === 'success'\"\n [class.notification-error]=\"Notification.Type === 'error'\">\n @if (Notification.Type === 'success') {\n <i class=\"fa-solid fa-circle-check\"></i>\n } @else {\n <i class=\"fa-solid fa-circle-xmark\"></i>\n }\n <span class=\"notification-message\">{{ Notification.Message }}</span>\n <button class=\"notification-dismiss\" (click)=\"DismissNotification()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n\n @if (IsLoading) {\n <mj-loading text=\"Loading integrations...\" size=\"medium\"></mj-loading>\n } @else if (Summaries.length === 0) {\n <mj-empty-state Icon=\"fa-solid fa-plug-circle-xmark\"\n Title=\"No Integrations Configured\"\n Message=\"Set up your first integration using the Connection Studio to start syncing data.\" />\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]=\"GetSparklineTooltip(run)\"></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 · {{ 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 </mj-page-body>\n</mj-page-layout>\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration-card.component.d.ts","sourceRoot":"","sources":["../../../../src/Integration/components/widgets/integration-card.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAA0B,MAAM,yCAAyC,CAAC;;AAErG,
|
|
1
|
+
{"version":3,"file":"integration-card.component.d.ts","sourceRoot":"","sources":["../../../../src/Integration/components/widgets/integration-card.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAA0B,MAAM,yCAAyC,CAAC;;AAErG,qBAwMa,wBAAwB;IAC1B,OAAO,EAAG,kBAAkB,CAAC;IAC7B,QAAQ,EAAE,OAAO,CAAS;IAC1B,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAQ;IAC5C,WAAW,uBAA8B;IACzC,YAAY,uBAA8B;IAEpD,IAAI,eAAe,IAAI,MAAM,CAQ5B;IAED,IAAI,WAAW,IAAI,MAAM,CAMxB;IAED,IAAI,iBAAiB,IAAI,OAAO,CAG/B;IAED,IAAI,iBAAiB,IAAI,MAAM,CAQ9B;IAED,IAAI,eAAe,IAAI,MAAM,CAG5B;IAED,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAIvC,aAAa,IAAI,IAAI;IAIrB,cAAc,IAAI,IAAI;yCArDX,wBAAwB;2CAAxB,wBAAwB;CAwDpC"}
|
|
@@ -43,7 +43,7 @@ function IntegrationCardComponent_Conditional_21_For_5_Template(rf, ctx) { if (r
|
|
|
43
43
|
const run_r2 = ctx.$implicit;
|
|
44
44
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
45
45
|
i0.ɵɵstyleProp("height", ctx_r0.SparkBarHeight(run_r2.TotalRecords), "%");
|
|
46
|
-
i0.ɵɵclassProp("spark-success", run_r2.Status === "Success")("spark-failed", run_r2.Status === "Failed")("spark-pending", run_r2.Status !== "Success" && run_r2.Status !== "Failed");
|
|
46
|
+
i0.ɵɵclassProp("spark-success", run_r2.Status === "Success")("spark-failed", run_r2.Status === "Failed")("spark-cancelled", run_r2.Status === "Cancelled")("spark-pending", run_r2.Status !== "Success" && run_r2.Status !== "Failed" && run_r2.Status !== "Cancelled");
|
|
47
47
|
i0.ɵɵproperty("title", run_r2.TotalRecords + " records - " + run_r2.Status);
|
|
48
48
|
} }
|
|
49
49
|
function IntegrationCardComponent_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
@@ -51,7 +51,7 @@ function IntegrationCardComponent_Conditional_21_Template(rf, ctx) { if (rf & 1)
|
|
|
51
51
|
i0.ɵɵtext(2, "Recent syncs");
|
|
52
52
|
i0.ɵɵelementEnd();
|
|
53
53
|
i0.ɵɵelementStart(3, "div", 22);
|
|
54
|
-
i0.ɵɵrepeaterCreate(4, IntegrationCardComponent_Conditional_21_For_5_Template, 1,
|
|
54
|
+
i0.ɵɵrepeaterCreate(4, IntegrationCardComponent_Conditional_21_For_5_Template, 1, 11, "div", 23, _forTrack0);
|
|
55
55
|
i0.ɵɵelementEnd()();
|
|
56
56
|
} if (rf & 2) {
|
|
57
57
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -109,7 +109,7 @@ export class IntegrationCardComponent {
|
|
|
109
109
|
this.ExpandToggle.emit(this.Summary.Integration.ID);
|
|
110
110
|
}
|
|
111
111
|
static ɵfac = function IntegrationCardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || IntegrationCardComponent)(); };
|
|
112
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: IntegrationCardComponent, selectors: [["app-integration-card"]], inputs: { Summary: "Summary", Expanded: "Expanded", ViewProvider: "ViewProvider" }, outputs: { RunNowClick: "RunNowClick", ExpandToggle: "ExpandToggle" }, standalone: false, decls: 29, vars: 22, consts: [[1, "integration-card"], [1, "card-header"], [1, "source-icon"], [1, "card-title-area"], [1, "card-title"], [1, "source-type-label"], [1, "status-area"], [1, "status-indicator"], [1, "status-chip"], [1, "card-body"], [1, "stat-row"], [1, "stat-label"], [1, "stat-value"], [1, "sparkline-row"], [1, "card-footer"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click", "disabled"], [1, "fa-solid", "fa-play"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click"], [1, "fa-solid"], [1, "stat-value", "error-value"], [1, "error-badge"], [1, "sparkline-label"], [1, "sparkline"], [1, "spark-bar", 3, "height", "spark-success", "spark-failed", "spark-pending", "title"], [1, "spark-bar", 3, "title"]], template: function IntegrationCardComponent_Template(rf, ctx) { if (rf & 1) {
|
|
112
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: IntegrationCardComponent, selectors: [["app-integration-card"]], inputs: { Summary: "Summary", Expanded: "Expanded", ViewProvider: "ViewProvider" }, outputs: { RunNowClick: "RunNowClick", ExpandToggle: "ExpandToggle" }, standalone: false, decls: 29, vars: 22, consts: [[1, "integration-card"], [1, "card-header"], [1, "source-icon"], [1, "card-title-area"], [1, "card-title"], [1, "source-type-label"], [1, "status-area"], [1, "status-indicator"], [1, "status-chip"], [1, "card-body"], [1, "stat-row"], [1, "stat-label"], [1, "stat-value"], [1, "sparkline-row"], [1, "card-footer"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click", "disabled"], [1, "fa-solid", "fa-play"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click"], [1, "fa-solid"], [1, "stat-value", "error-value"], [1, "error-badge"], [1, "sparkline-label"], [1, "sparkline"], [1, "spark-bar", 3, "height", "spark-success", "spark-failed", "spark-cancelled", "spark-pending", "title"], [1, "spark-bar", 3, "title"]], template: function IntegrationCardComponent_Template(rf, ctx) { if (rf & 1) {
|
|
113
113
|
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2);
|
|
114
114
|
i0.ɵɵelement(3, "i");
|
|
115
115
|
i0.ɵɵelementEnd();
|
|
@@ -171,7 +171,7 @@ export class IntegrationCardComponent {
|
|
|
171
171
|
i0.ɵɵproperty("disabled", !ctx.Summary.Integration.IsActive);
|
|
172
172
|
i0.ɵɵadvance(4);
|
|
173
173
|
i0.ɵɵclassProp("fa-chevron-down", !ctx.Expanded)("fa-chevron-up", ctx.Expanded);
|
|
174
|
-
} }, dependencies: [i1.MJButtonDirective, i2.DecimalPipe], styles: [".integration-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 16px;\n transition: box-shadow 0.2s;\n }\n .integration-card[_ngcontent-%COMP%]:hover { box-shadow: var(--mj-shadow-md); }\n .integration-card.inactive[_ngcontent-%COMP%] { opacity: 0.6; }\n\n .card-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 12px;\n }\n .source-icon[_ngcontent-%COMP%] {\n width: 40px; height: 40px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n display: flex; align-items: center; justify-content: center;\n font-size: 18px; color: var(--mj-brand-primary);\n }\n .card-title-area[_ngcontent-%COMP%] { flex: 1; min-width: 0; }\n .card-title[_ngcontent-%COMP%] {\n margin: 0; font-size: 14px; font-weight: 600;\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .source-type-label[_ngcontent-%COMP%] { font-size: 12px; color: var(--mj-text-muted); }\n\n .status-area[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n }\n\n .status-indicator[_ngcontent-%COMP%] {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n display: inline-block;\n }\n .indicator-green[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n .indicator-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n .indicator-red[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n .indicator-gray[_ngcontent-%COMP%] { background: var(--mj-text-disabled); }\n\n .status-indicator.pulsing[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_pulse 1.5s ease-in-out infinite;\n }\n @keyframes _ngcontent-%COMP%_pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(1.3); }\n }\n\n .status-chip[_ngcontent-%COMP%] {\n font-size: 11px; font-weight: 600; padding: 3px 8px;\n border-radius: 12px; text-transform: uppercase; white-space: nowrap;\n }\n .status-green[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n .status-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n .status-red[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n .status-gray[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n .card-body[_ngcontent-%COMP%] { margin-bottom: 12px; }\n .stat-row[_ngcontent-%COMP%] {\n display: flex; justify-content: space-between;\n padding: 4px 0; font-size: 13px;\n }\n .stat-label[_ngcontent-%COMP%] { color: var(--mj-text-secondary); }\n .stat-value[_ngcontent-%COMP%] { font-weight: 500; }\n .error-value[_ngcontent-%COMP%] { color: var(--mj-status-error-text); }\n .error-badge[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n padding: 1px 8px;\n border-radius: 10px;\n font-size: 12px;\n font-weight: 700;\n }\n\n \n\n .sparkline-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n padding: 8px 0;\n border-top: 1px solid var(--mj-border-subtle);\n margin-bottom: 4px;\n }\n .sparkline-label[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-disabled);\n white-space: nowrap;\n }\n .sparkline[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n gap: 3px;\n height: 24px;\n flex: 1;\n }\n .spark-bar[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 2px;\n border-radius: 2px 2px 0 0;\n transition: height 0.3s ease;\n }\n .spark-success[_ngcontent-%COMP%] { background: var(--mj-brand-primary); }\n .spark-failed[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n .spark-pending[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n\n .card-footer[_ngcontent-%COMP%] {\n display: flex; justify-content: space-between;\n border-top: 1px solid var(--mj-border-subtle); padding-top: 8px;\n }"] });
|
|
174
|
+
} }, dependencies: [i1.MJButtonDirective, i2.DecimalPipe], styles: [".integration-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 16px;\n transition: box-shadow 0.2s;\n }\n .integration-card[_ngcontent-%COMP%]:hover { box-shadow: var(--mj-shadow-md); }\n .integration-card.inactive[_ngcontent-%COMP%] { opacity: 0.6; }\n\n .card-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 12px;\n }\n .source-icon[_ngcontent-%COMP%] {\n width: 40px; height: 40px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n display: flex; align-items: center; justify-content: center;\n font-size: 18px; color: var(--mj-brand-primary);\n }\n .card-title-area[_ngcontent-%COMP%] { flex: 1; min-width: 0; }\n .card-title[_ngcontent-%COMP%] {\n margin: 0; font-size: 14px; font-weight: 600;\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .source-type-label[_ngcontent-%COMP%] { font-size: 12px; color: var(--mj-text-muted); }\n\n .status-area[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n }\n\n .status-indicator[_ngcontent-%COMP%] {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n display: inline-block;\n }\n .indicator-green[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n .indicator-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n .indicator-red[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n .indicator-gray[_ngcontent-%COMP%] { background: var(--mj-text-disabled); }\n\n .status-indicator.pulsing[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_pulse 1.5s ease-in-out infinite;\n }\n @keyframes _ngcontent-%COMP%_pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(1.3); }\n }\n\n .status-chip[_ngcontent-%COMP%] {\n font-size: 11px; font-weight: 600; padding: 3px 8px;\n border-radius: 12px; text-transform: uppercase; white-space: nowrap;\n }\n .status-green[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n .status-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n .status-red[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n .status-gray[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n .card-body[_ngcontent-%COMP%] { margin-bottom: 12px; }\n .stat-row[_ngcontent-%COMP%] {\n display: flex; justify-content: space-between;\n padding: 4px 0; font-size: 13px;\n }\n .stat-label[_ngcontent-%COMP%] { color: var(--mj-text-secondary); }\n .stat-value[_ngcontent-%COMP%] { font-weight: 500; }\n .error-value[_ngcontent-%COMP%] { color: var(--mj-status-error-text); }\n .error-badge[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n padding: 1px 8px;\n border-radius: 10px;\n font-size: 12px;\n font-weight: 700;\n }\n\n \n\n .sparkline-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n padding: 8px 0;\n border-top: 1px solid var(--mj-border-subtle);\n margin-bottom: 4px;\n }\n .sparkline-label[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-disabled);\n white-space: nowrap;\n }\n .sparkline[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n gap: 3px;\n height: 24px;\n flex: 1;\n }\n .spark-bar[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 2px;\n border-radius: 2px 2px 0 0;\n transition: height 0.3s ease;\n }\n .spark-success[_ngcontent-%COMP%] { background: var(--mj-brand-primary); }\n .spark-failed[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n .spark-pending[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n \n\n .spark-cancelled[_ngcontent-%COMP%] { background: var(--mj-text-muted); }\n\n .card-footer[_ngcontent-%COMP%] {\n display: flex; justify-content: space-between;\n border-top: 1px solid var(--mj-border-subtle); padding-top: 8px;\n }"] });
|
|
175
175
|
}
|
|
176
176
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(IntegrationCardComponent, [{
|
|
177
177
|
type: Component,
|
|
@@ -229,7 +229,8 @@ export class IntegrationCardComponent {
|
|
|
229
229
|
[style.height.%]="SparkBarHeight(run.TotalRecords)"
|
|
230
230
|
[class.spark-success]="run.Status === 'Success'"
|
|
231
231
|
[class.spark-failed]="run.Status === 'Failed'"
|
|
232
|
-
[class.spark-
|
|
232
|
+
[class.spark-cancelled]="run.Status === 'Cancelled'"
|
|
233
|
+
[class.spark-pending]="run.Status !== 'Success' && run.Status !== 'Failed' && run.Status !== 'Cancelled'"
|
|
233
234
|
[title]="run.TotalRecords + ' records - ' + run.Status">
|
|
234
235
|
</div>
|
|
235
236
|
}
|
|
@@ -248,7 +249,7 @@ export class IntegrationCardComponent {
|
|
|
248
249
|
</button>
|
|
249
250
|
</div>
|
|
250
251
|
</div>
|
|
251
|
-
`, styles: ["\n .integration-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 16px;\n transition: box-shadow 0.2s;\n }\n .integration-card:hover { box-shadow: var(--mj-shadow-md); }\n .integration-card.inactive { opacity: 0.6; }\n\n .card-header {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 12px;\n }\n .source-icon {\n width: 40px; height: 40px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n display: flex; align-items: center; justify-content: center;\n font-size: 18px; color: var(--mj-brand-primary);\n }\n .card-title-area { flex: 1; min-width: 0; }\n .card-title {\n margin: 0; font-size: 14px; font-weight: 600;\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .source-type-label { font-size: 12px; color: var(--mj-text-muted); }\n\n .status-area {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n }\n\n .status-indicator {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n display: inline-block;\n }\n .indicator-green { background: var(--mj-status-success); }\n .indicator-amber { background: var(--mj-status-warning); }\n .indicator-red { background: var(--mj-status-error); }\n .indicator-gray { background: var(--mj-text-disabled); }\n\n .status-indicator.pulsing {\n animation: pulse 1.5s ease-in-out infinite;\n }\n @keyframes pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(1.3); }\n }\n\n .status-chip {\n font-size: 11px; font-weight: 600; padding: 3px 8px;\n border-radius: 12px; text-transform: uppercase; white-space: nowrap;\n }\n .status-green { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n .status-amber { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n .status-red { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n .status-gray { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n .card-body { margin-bottom: 12px; }\n .stat-row {\n display: flex; justify-content: space-between;\n padding: 4px 0; font-size: 13px;\n }\n .stat-label { color: var(--mj-text-secondary); }\n .stat-value { font-weight: 500; }\n .error-value { color: var(--mj-status-error-text); }\n .error-badge {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n padding: 1px 8px;\n border-radius: 10px;\n font-size: 12px;\n font-weight: 700;\n }\n\n /* Sparkline */\n .sparkline-row {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n padding: 8px 0;\n border-top: 1px solid var(--mj-border-subtle);\n margin-bottom: 4px;\n }\n .sparkline-label {\n font-size: 11px;\n color: var(--mj-text-disabled);\n white-space: nowrap;\n }\n .sparkline {\n display: flex;\n align-items: flex-end;\n gap: 3px;\n height: 24px;\n flex: 1;\n }\n .spark-bar {\n flex: 1;\n min-height: 2px;\n border-radius: 2px 2px 0 0;\n transition: height 0.3s ease;\n }\n .spark-success { background: var(--mj-brand-primary); }\n .spark-failed { background: var(--mj-status-error); }\n .spark-pending { background: var(--mj-status-warning); }\n\n .card-footer {\n display: flex; justify-content: space-between;\n border-top: 1px solid var(--mj-border-subtle); padding-top: 8px;\n }\n "] }]
|
|
252
|
+
`, styles: ["\n .integration-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 16px;\n transition: box-shadow 0.2s;\n }\n .integration-card:hover { box-shadow: var(--mj-shadow-md); }\n .integration-card.inactive { opacity: 0.6; }\n\n .card-header {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 12px;\n }\n .source-icon {\n width: 40px; height: 40px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n display: flex; align-items: center; justify-content: center;\n font-size: 18px; color: var(--mj-brand-primary);\n }\n .card-title-area { flex: 1; min-width: 0; }\n .card-title {\n margin: 0; font-size: 14px; font-weight: 600;\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .source-type-label { font-size: 12px; color: var(--mj-text-muted); }\n\n .status-area {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n }\n\n .status-indicator {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n display: inline-block;\n }\n .indicator-green { background: var(--mj-status-success); }\n .indicator-amber { background: var(--mj-status-warning); }\n .indicator-red { background: var(--mj-status-error); }\n .indicator-gray { background: var(--mj-text-disabled); }\n\n .status-indicator.pulsing {\n animation: pulse 1.5s ease-in-out infinite;\n }\n @keyframes pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(1.3); }\n }\n\n .status-chip {\n font-size: 11px; font-weight: 600; padding: 3px 8px;\n border-radius: 12px; text-transform: uppercase; white-space: nowrap;\n }\n .status-green { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n .status-amber { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n .status-red { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n .status-gray { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n .card-body { margin-bottom: 12px; }\n .stat-row {\n display: flex; justify-content: space-between;\n padding: 4px 0; font-size: 13px;\n }\n .stat-label { color: var(--mj-text-secondary); }\n .stat-value { font-weight: 500; }\n .error-value { color: var(--mj-status-error-text); }\n .error-badge {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n padding: 1px 8px;\n border-radius: 10px;\n font-size: 12px;\n font-weight: 700;\n }\n\n /* Sparkline */\n .sparkline-row {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n padding: 8px 0;\n border-top: 1px solid var(--mj-border-subtle);\n margin-bottom: 4px;\n }\n .sparkline-label {\n font-size: 11px;\n color: var(--mj-text-disabled);\n white-space: nowrap;\n }\n .sparkline {\n display: flex;\n align-items: flex-end;\n gap: 3px;\n height: 24px;\n flex: 1;\n }\n .spark-bar {\n flex: 1;\n min-height: 2px;\n border-radius: 2px 2px 0 0;\n transition: height 0.3s ease;\n }\n .spark-success { background: var(--mj-brand-primary); }\n .spark-failed { background: var(--mj-status-error); }\n .spark-pending { background: var(--mj-status-warning); }\n /* Cancelled: neutral. Warning-coloured would read as \"still working\", error-coloured as a defect. */\n .spark-cancelled { background: var(--mj-text-muted); }\n\n .card-footer {\n display: flex; justify-content: space-between;\n border-top: 1px solid var(--mj-border-subtle); padding-top: 8px;\n }\n "] }]
|
|
252
253
|
}], null, { Summary: [{
|
|
253
254
|
type: Input
|
|
254
255
|
}], Expanded: [{
|
|
@@ -260,5 +261,5 @@ export class IntegrationCardComponent {
|
|
|
260
261
|
}], ExpandToggle: [{
|
|
261
262
|
type: Output
|
|
262
263
|
}] }); })();
|
|
263
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(IntegrationCardComponent, { className: "IntegrationCardComponent", filePath: "src/Integration/components/widgets/integration-card.component.ts", lineNumber:
|
|
264
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(IntegrationCardComponent, { className: "IntegrationCardComponent", filePath: "src/Integration/components/widgets/integration-card.component.ts", lineNumber: 205 }); })();
|
|
264
265
|
//# sourceMappingURL=integration-card.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration-card.component.js","sourceRoot":"","sources":["../../../../src/Integration/components/widgets/integration-card.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEvE,OAAO,EAAsB,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;;;;;;IA+BzF,AADF,+BAAsB,eACK;IAAA,8BAAc;IAAA,iBAAO;IAC9C,gCAAyB;IAAA,YAA6C;;IACxE,AADwE,iBAAO,EACzE;IAEJ,AADF,+BAAsB,eACK;IAAA,wBAAQ;IAAA,iBAAO;IACxC,gCAAyB;IAAA,aAAuB;IAClD,AADkD,iBAAO,EACnD;;;IALqB,eAA6C;IAA7C,iFAA6C;IAI7C,eAAuB;IAAvB,8CAAuB;;;IAKhD,AADF,+BAAsB,eACK;IAAA,sBAAM;IAAA,iBAAO;IAEpC,AADF,gCAAqC,eACT;IAAA,YAAyB;IAEvD,AADE,AADqD,iBAAO,EACrD,EACH;;;IAFwB,eAAyB;IAAzB,gDAAyB;;;IAYnD,0BAMM;;;;IALD,yEAAmD;IAGnD,AADA,AADA,4DAAgD,4CACF,4EAC6B;IAC3E,2EAAuD;;;IARhE,AADF,+BAA2B,eACK;IAAA,4BAAY;IAAA,iBAAO;IACjD,+BAAuB;IACrB,2GAQC;IAEL,AADE,iBAAM,EACF;;;IAVF,eAQC;IARD,wCAQC;;AAyIb,MAAM,OAAO,wBAAwB;IAC1B,OAAO,CAAsB;IAC7B,QAAQ,GAAY,KAAK,CAAC;IAC1B,YAAY,GAA4B,IAAI,CAAC;IAC5C,WAAW,GAAG,IAAI,YAAY,EAAU,CAAC;IACzC,YAAY,GAAG,IAAI,YAAY,EAAU,CAAC;IAEpD,IAAI,eAAe;QACjB,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,SAAS,EAAE,CAAC;YACvC,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC;QAC3C,CAAC;QACD,OAAO,sBAAsB,CAC3B,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,WAAW,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EACrE,IAAI,CAAC,OAAO,CAAC,IAAI,CAClB,CAAC;IACJ,CAAC;IAED,IAAI,WAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;QACvC,IAAI,KAAK,KAAK,OAAO;YAAE,OAAO,SAAS,CAAC;QACxC,IAAI,KAAK,KAAK,OAAO;YAAE,OAAO,SAAS,CAAC;QACxC,IAAI,KAAK,KAAK,KAAK;YAAE,OAAO,QAAQ,CAAC;QACrC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,IAAI,iBAAiB;QACnB,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,KAAK,aAAa;eAClD,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,KAAK,SAAS,CAAC;IACpD,CAAC;IAED,IAAI,iBAAiB;QACnB,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QACnC,IAAI,EAAE,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;QAC5B,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;QAC3C,IAAI,YAAY,GAAG,EAAE;YAAE,OAAO,GAAG,YAAY,GAAG,CAAC;QACjD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,YAAY,GAAG,EAAE,CAAC;QAClC,OAAO,GAAG,OAAO,KAAK,OAAO,GAAG,CAAC;IACnC,CAAC;IAED,IAAI,eAAe;QACjB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;QAC7E,OAAO,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC;IAED,cAAc,CAAC,OAAe;QAC5B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,aAAa;QACX,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,cAAc;QACZ,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACtD,CAAC;kHAvDU,wBAAwB;6DAAxB,wBAAwB;YA/L7B,AADF,AADF,8BAA+E,aACpD,aACE;YACvB,oBAAiC;YACnC,iBAAM;YAEJ,AADF,8BAA6B,YACJ;YAAA,YAA8B;YAAA,iBAAK;YAC1D,+BAAgC;YAAA,YAA2C;YAC7E,AAD6E,iBAAO,EAC9E;YACN,8BAAyB;YACvB,2BACiD;YACjD,gCAAoE;YAClE,aACF;YAEJ,AADE,AADE,iBAAO,EACH,EACF;YAIF,AADF,AADF,+BAAuB,eACC,gBACK;YAAA,yBAAQ;YAAA,iBAAO;YACxC,iCAAyB;YAAA,aAA0B;YACrD,AADqD,iBAAO,EACtD;YACN,mFAAyB;YAUzB,6FAA+B;YAQjC,iBAAM;YAGN,6FAAqC;YAkBnC,AADF,gCAAyB,kBAEsD;YAArE,sGAAS,mBAAe,IAAC;YAC/B,yBAAgC;YAAC,0BACnC;YAAA,iBAAS;YACT,mCAAqE;YAA3B,sGAAS,oBAAgB,IAAC;YAClE,yBAA6F;YAC7F,0BACF;YAEJ,AADE,AADE,iBAAS,EACL,EACF;;YAvEwB,6DAAgD;YAGrE,eAAyB;YAAzB,kCAAyB;YAGL,eAA8B;YAA9B,kDAA8B;YACrB,eAA2C;YAA3C,wGAA2C;YAG5C,eAA4C;YAA5C,qDAA4C;YACrE,gDAAmC;YACf,cAAyC;YAAzC,kDAAyC;YACjE,cACF;YADE,gDACF;YAOyB,eAA0B;YAA1B,8CAA0B;YAErD,cASC;YATD,iDASC;YACD,cAOC;YAPD,uDAOC;YAIH,cAeC;YAfD,6DAeC;YAImC,eAA0C;YAA1C,4DAA0C;YAItD,eAAmC;YAAC,AAApC,gDAAmC,+BAAiC;;;iFA8HrF,wBAAwB;cArMpC,SAAS;6BACI,KAAK,YACP,sBAAsB,YACtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyET;;kBA0HA,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBACL,MAAM;;kBACN,MAAM;;kFALI,wBAAwB","sourcesContent":["import { Component, Input, Output, EventEmitter } from '@angular/core';\nimport { IRunViewProvider } from '@memberjunction/core';\nimport { IntegrationSummary, ResolveIntegrationIcon } from '../../services/integration-data.service';\n\n@Component({\n standalone: false,\n selector: 'app-integration-card',\n template: `\n <div class=\"integration-card\" [class.inactive]=\"!Summary.Integration.IsActive\">\n <div class=\"card-header\">\n <div class=\"source-icon\">\n <i [class]=\"SourceIconClass\"></i>\n </div>\n <div class=\"card-title-area\">\n <h3 class=\"card-title\">{{ Summary.Integration.Name }}</h3>\n <span class=\"source-type-label\">{{ Summary.SourceType?.Name ?? 'Unknown' }}</span>\n </div>\n <div class=\"status-area\">\n <span class=\"status-indicator\" [class]=\"'indicator-' + Summary.StatusColor\"\n [class.pulsing]=\"IsActivelySyncing\"></span>\n <span class=\"status-chip\" [class]=\"'status-' + Summary.StatusColor\">\n {{ StatusLabel }}\n </span>\n </div>\n </div>\n\n <div class=\"card-body\">\n <div class=\"stat-row\">\n <span class=\"stat-label\">Last Run</span>\n <span class=\"stat-value\">{{ Summary.RelativeTime }}</span>\n </div>\n @if (Summary.LatestRun) {\n <div class=\"stat-row\">\n <span class=\"stat-label\">Records Synced</span>\n <span class=\"stat-value\">{{ Summary.LatestRun.TotalRecords | number }}</span>\n </div>\n <div class=\"stat-row\">\n <span class=\"stat-label\">Duration</span>\n <span class=\"stat-value\">{{ FormattedDuration }}</span>\n </div>\n }\n @if (Summary.TotalErrors > 0) {\n <div class=\"stat-row\">\n <span class=\"stat-label\">Errors</span>\n <span class=\"stat-value error-value\">\n <span class=\"error-badge\">{{ Summary.TotalErrors }}</span>\n </span>\n </div>\n }\n </div>\n\n <!-- Sparkline: records synced for last 5 runs -->\n @if (Summary.RecentRuns.length > 1) {\n <div class=\"sparkline-row\">\n <span class=\"sparkline-label\">Recent syncs</span>\n <div class=\"sparkline\">\n @for (run of Summary.RecentRuns; track run.ID) {\n <div class=\"spark-bar\"\n [style.height.%]=\"SparkBarHeight(run.TotalRecords)\"\n [class.spark-success]=\"run.Status === 'Success'\"\n [class.spark-failed]=\"run.Status === 'Failed'\"\n [class.spark-pending]=\"run.Status !== 'Success' && run.Status !== 'Failed'\"\n [title]=\"run.TotalRecords + ' records - ' + run.Status\">\n </div>\n }\n </div>\n </div>\n }\n\n <div class=\"card-footer\">\n <button mjButton variant=\"primary\" size=\"sm\"\n (click)=\"OnRunNowClick()\" [disabled]=\"!Summary.Integration.IsActive\">\n <i class=\"fa-solid fa-play\"></i> Run Now\n </button>\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"OnExpandToggle()\">\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!Expanded\" [class.fa-chevron-up]=\"Expanded\"></i>\n History\n </button>\n </div>\n </div>\n `,\n styles: [`\n .integration-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 16px;\n transition: box-shadow 0.2s;\n }\n .integration-card:hover { box-shadow: var(--mj-shadow-md); }\n .integration-card.inactive { opacity: 0.6; }\n\n .card-header {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 12px;\n }\n .source-icon {\n width: 40px; height: 40px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n display: flex; align-items: center; justify-content: center;\n font-size: 18px; color: var(--mj-brand-primary);\n }\n .card-title-area { flex: 1; min-width: 0; }\n .card-title {\n margin: 0; font-size: 14px; font-weight: 600;\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .source-type-label { font-size: 12px; color: var(--mj-text-muted); }\n\n .status-area {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n }\n\n .status-indicator {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n display: inline-block;\n }\n .indicator-green { background: var(--mj-status-success); }\n .indicator-amber { background: var(--mj-status-warning); }\n .indicator-red { background: var(--mj-status-error); }\n .indicator-gray { background: var(--mj-text-disabled); }\n\n .status-indicator.pulsing {\n animation: pulse 1.5s ease-in-out infinite;\n }\n @keyframes pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(1.3); }\n }\n\n .status-chip {\n font-size: 11px; font-weight: 600; padding: 3px 8px;\n border-radius: 12px; text-transform: uppercase; white-space: nowrap;\n }\n .status-green { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n .status-amber { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n .status-red { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n .status-gray { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n .card-body { margin-bottom: 12px; }\n .stat-row {\n display: flex; justify-content: space-between;\n padding: 4px 0; font-size: 13px;\n }\n .stat-label { color: var(--mj-text-secondary); }\n .stat-value { font-weight: 500; }\n .error-value { color: var(--mj-status-error-text); }\n .error-badge {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n padding: 1px 8px;\n border-radius: 10px;\n font-size: 12px;\n font-weight: 700;\n }\n\n /* Sparkline */\n .sparkline-row {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n padding: 8px 0;\n border-top: 1px solid var(--mj-border-subtle);\n margin-bottom: 4px;\n }\n .sparkline-label {\n font-size: 11px;\n color: var(--mj-text-disabled);\n white-space: nowrap;\n }\n .sparkline {\n display: flex;\n align-items: flex-end;\n gap: 3px;\n height: 24px;\n flex: 1;\n }\n .spark-bar {\n flex: 1;\n min-height: 2px;\n border-radius: 2px 2px 0 0;\n transition: height 0.3s ease;\n }\n .spark-success { background: var(--mj-brand-primary); }\n .spark-failed { background: var(--mj-status-error); }\n .spark-pending { background: var(--mj-status-warning); }\n\n .card-footer {\n display: flex; justify-content: space-between;\n border-top: 1px solid var(--mj-border-subtle); padding-top: 8px;\n }\n `]\n})\nexport class IntegrationCardComponent {\n @Input() Summary!: IntegrationSummary;\n @Input() Expanded: boolean = false;\n @Input() ViewProvider: IRunViewProvider | null = null;\n @Output() RunNowClick = new EventEmitter<string>();\n @Output() ExpandToggle = new EventEmitter<string>();\n\n get SourceIconClass(): string {\n if (this.Summary.SourceType?.IconClass) {\n return this.Summary.SourceType.IconClass;\n }\n return ResolveIntegrationIcon(\n this.Summary.Integration.Integration ?? this.Summary.Integration.Name,\n this.Summary.Icon\n );\n }\n\n get StatusLabel(): string {\n const color = this.Summary.StatusColor;\n if (color === 'green') return 'Healthy';\n if (color === 'amber') return 'Warning';\n if (color === 'red') return 'Failed';\n return 'Inactive';\n }\n\n get IsActivelySyncing(): boolean {\n return this.Summary.LatestRun?.Status === 'In Progress'\n || this.Summary.LatestRun?.Status === 'Pending';\n }\n\n get FormattedDuration(): string {\n const ms = this.Summary.DurationMs;\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 return `${minutes}m ${seconds}s`;\n }\n\n get MaxSparkRecords(): number {\n const maxVal = Math.max(...this.Summary.RecentRuns.map(r => r.TotalRecords));\n return maxVal > 0 ? maxVal : 1;\n }\n\n SparkBarHeight(records: number): number {\n return Math.max((records / this.MaxSparkRecords) * 100, 8);\n }\n\n OnRunNowClick(): void {\n this.RunNowClick.emit(this.Summary.Integration.ID);\n }\n\n OnExpandToggle(): void {\n this.ExpandToggle.emit(this.Summary.Integration.ID);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"integration-card.component.js","sourceRoot":"","sources":["../../../../src/Integration/components/widgets/integration-card.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter } from '@angular/core';\nimport { IRunViewProvider } from '@memberjunction/core';\nimport { IntegrationSummary, ResolveIntegrationIcon } from '../../services/integration-data.service';\n\n@Component({\n standalone: false,\n selector: 'app-integration-card',\n template: `\n <div class=\"integration-card\" [class.inactive]=\"!Summary.Integration.IsActive\">\n <div class=\"card-header\">\n <div class=\"source-icon\">\n <i [class]=\"SourceIconClass\"></i>\n </div>\n <div class=\"card-title-area\">\n <h3 class=\"card-title\">{{ Summary.Integration.Name }}</h3>\n <span class=\"source-type-label\">{{ Summary.SourceType?.Name ?? 'Unknown' }}</span>\n </div>\n <div class=\"status-area\">\n <span class=\"status-indicator\" [class]=\"'indicator-' + Summary.StatusColor\"\n [class.pulsing]=\"IsActivelySyncing\"></span>\n <span class=\"status-chip\" [class]=\"'status-' + Summary.StatusColor\">\n {{ StatusLabel }}\n </span>\n </div>\n </div>\n\n <div class=\"card-body\">\n <div class=\"stat-row\">\n <span class=\"stat-label\">Last Run</span>\n <span class=\"stat-value\">{{ Summary.RelativeTime }}</span>\n </div>\n @if (Summary.LatestRun) {\n <div class=\"stat-row\">\n <span class=\"stat-label\">Records Synced</span>\n <span class=\"stat-value\">{{ Summary.LatestRun.TotalRecords | number }}</span>\n </div>\n <div class=\"stat-row\">\n <span class=\"stat-label\">Duration</span>\n <span class=\"stat-value\">{{ FormattedDuration }}</span>\n </div>\n }\n @if (Summary.TotalErrors > 0) {\n <div class=\"stat-row\">\n <span class=\"stat-label\">Errors</span>\n <span class=\"stat-value error-value\">\n <span class=\"error-badge\">{{ Summary.TotalErrors }}</span>\n </span>\n </div>\n }\n </div>\n\n <!-- Sparkline: records synced for last 5 runs -->\n @if (Summary.RecentRuns.length > 1) {\n <div class=\"sparkline-row\">\n <span class=\"sparkline-label\">Recent syncs</span>\n <div class=\"sparkline\">\n @for (run of Summary.RecentRuns; track run.ID) {\n <div class=\"spark-bar\"\n [style.height.%]=\"SparkBarHeight(run.TotalRecords)\"\n [class.spark-success]=\"run.Status === 'Success'\"\n [class.spark-failed]=\"run.Status === 'Failed'\"\n [class.spark-cancelled]=\"run.Status === 'Cancelled'\"\n [class.spark-pending]=\"run.Status !== 'Success' && run.Status !== 'Failed' && run.Status !== 'Cancelled'\"\n [title]=\"run.TotalRecords + ' records - ' + run.Status\">\n </div>\n }\n </div>\n </div>\n }\n\n <div class=\"card-footer\">\n <button mjButton variant=\"primary\" size=\"sm\"\n (click)=\"OnRunNowClick()\" [disabled]=\"!Summary.Integration.IsActive\">\n <i class=\"fa-solid fa-play\"></i> Run Now\n </button>\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"OnExpandToggle()\">\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!Expanded\" [class.fa-chevron-up]=\"Expanded\"></i>\n History\n </button>\n </div>\n </div>\n `,\n styles: [`\n .integration-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 16px;\n transition: box-shadow 0.2s;\n }\n .integration-card:hover { box-shadow: var(--mj-shadow-md); }\n .integration-card.inactive { opacity: 0.6; }\n\n .card-header {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 12px;\n }\n .source-icon {\n width: 40px; height: 40px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n display: flex; align-items: center; justify-content: center;\n font-size: 18px; color: var(--mj-brand-primary);\n }\n .card-title-area { flex: 1; min-width: 0; }\n .card-title {\n margin: 0; font-size: 14px; font-weight: 600;\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .source-type-label { font-size: 12px; color: var(--mj-text-muted); }\n\n .status-area {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n }\n\n .status-indicator {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n display: inline-block;\n }\n .indicator-green { background: var(--mj-status-success); }\n .indicator-amber { background: var(--mj-status-warning); }\n .indicator-red { background: var(--mj-status-error); }\n .indicator-gray { background: var(--mj-text-disabled); }\n\n .status-indicator.pulsing {\n animation: pulse 1.5s ease-in-out infinite;\n }\n @keyframes pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(1.3); }\n }\n\n .status-chip {\n font-size: 11px; font-weight: 600; padding: 3px 8px;\n border-radius: 12px; text-transform: uppercase; white-space: nowrap;\n }\n .status-green { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n .status-amber { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n .status-red { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n .status-gray { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n .card-body { margin-bottom: 12px; }\n .stat-row {\n display: flex; justify-content: space-between;\n padding: 4px 0; font-size: 13px;\n }\n .stat-label { color: var(--mj-text-secondary); }\n .stat-value { font-weight: 500; }\n .error-value { color: var(--mj-status-error-text); }\n .error-badge {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n padding: 1px 8px;\n border-radius: 10px;\n font-size: 12px;\n font-weight: 700;\n }\n\n /* Sparkline */\n .sparkline-row {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n padding: 8px 0;\n border-top: 1px solid var(--mj-border-subtle);\n margin-bottom: 4px;\n }\n .sparkline-label {\n font-size: 11px;\n color: var(--mj-text-disabled);\n white-space: nowrap;\n }\n .sparkline {\n display: flex;\n align-items: flex-end;\n gap: 3px;\n height: 24px;\n flex: 1;\n }\n .spark-bar {\n flex: 1;\n min-height: 2px;\n border-radius: 2px 2px 0 0;\n transition: height 0.3s ease;\n }\n .spark-success { background: var(--mj-brand-primary); }\n .spark-failed { background: var(--mj-status-error); }\n .spark-pending { background: var(--mj-status-warning); }\n /* Cancelled: neutral. Warning-coloured would read as \"still working\", error-coloured as a defect. */\n .spark-cancelled { background: var(--mj-text-muted); }\n\n .card-footer {\n display: flex; justify-content: space-between;\n border-top: 1px solid var(--mj-border-subtle); padding-top: 8px;\n }\n `]\n})\nexport class IntegrationCardComponent {\n @Input() Summary!: IntegrationSummary;\n @Input() Expanded: boolean = false;\n @Input() ViewProvider: IRunViewProvider | null = null;\n @Output() RunNowClick = new EventEmitter<string>();\n @Output() ExpandToggle = new EventEmitter<string>();\n\n get SourceIconClass(): string {\n if (this.Summary.SourceType?.IconClass) {\n return this.Summary.SourceType.IconClass;\n }\n return ResolveIntegrationIcon(\n this.Summary.Integration.Integration ?? this.Summary.Integration.Name,\n this.Summary.Icon\n );\n }\n\n get StatusLabel(): string {\n const color = this.Summary.StatusColor;\n if (color === 'green') return 'Healthy';\n if (color === 'amber') return 'Warning';\n if (color === 'red') return 'Failed';\n return 'Inactive';\n }\n\n get IsActivelySyncing(): boolean {\n return this.Summary.LatestRun?.Status === 'In Progress'\n || this.Summary.LatestRun?.Status === 'Pending';\n }\n\n get FormattedDuration(): string {\n const ms = this.Summary.DurationMs;\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 return `${minutes}m ${seconds}s`;\n }\n\n get MaxSparkRecords(): number {\n const maxVal = Math.max(...this.Summary.RecentRuns.map(r => r.TotalRecords));\n return maxVal > 0 ? maxVal : 1;\n }\n\n SparkBarHeight(records: number): number {\n return Math.max((records / this.MaxSparkRecords) * 100, 8);\n }\n\n OnRunNowClick(): void {\n this.RunNowClick.emit(this.Summary.Integration.ID);\n }\n\n OnExpandToggle(): void {\n this.ExpandToggle.emit(this.Summary.Integration.ID);\n }\n}\n"]}
|
|
@@ -2,7 +2,7 @@ import { OnChanges, SimpleChanges } from '@angular/core';
|
|
|
2
2
|
import { IRunViewProvider } from '@memberjunction/core';
|
|
3
3
|
import { IntegrationRunRow, RunDetailRow } from '../../services/integration-data.service';
|
|
4
4
|
import * as i0 from "@angular/core";
|
|
5
|
-
type RunStatusColorType = 'amber' | 'green' | 'red';
|
|
5
|
+
type RunStatusColorType = 'amber' | 'green' | 'red' | 'gray';
|
|
6
6
|
export declare class RunHistoryPanelComponent implements OnChanges {
|
|
7
7
|
CompanyIntegrationID: string | null;
|
|
8
8
|
ViewProvider: IRunViewProvider | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-history-panel.component.d.ts","sourceRoot":"","sources":["../../../../src/Integration/components/widgets/run-history-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,SAAS,EAAE,aAAa,EAAU,MAAM,eAAe,CAAC;AAEnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAA0B,iBAAiB,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;;AAElH,KAAK,kBAAkB,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"run-history-panel.component.d.ts","sourceRoot":"","sources":["../../../../src/Integration/components/widgets/run-history-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,SAAS,EAAE,aAAa,EAAU,MAAM,eAAe,CAAC;AAEnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAA0B,iBAAiB,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;;AAElH,KAAK,kBAAkB,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAE7D,qBA0La,wBAAyB,YAAW,SAAS;IAC/C,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC3C,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAQ;IAEtD,IAAI,EAAE,iBAAiB,EAAE,CAAM;IAC/B,UAAU,EAAE,YAAY,EAAE,CAAM;IAChC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAQ;IACpC,SAAS,UAAS;IAClB,gBAAgB,UAAS;IACzB,YAAY,UAAS;IAErB,OAAO,CAAC,WAAW,CAAkC;IAErD,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAMnC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAezB,UAAU,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBvD,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIlC,WAAW,CAAC,GAAG,EAAE,iBAAiB,GAAG,kBAAkB;IAQvD,UAAU,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM;IAS1C,UAAU,CAAC,OAAO,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,GAAG,MAAM;IASjD,cAAc,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM;IAM9C,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;yCAxFvB,wBAAwB;2CAAxB,wBAAwB;CA4FpC"}
|
|
@@ -245,6 +245,9 @@ export class RunHistoryPanelComponent {
|
|
|
245
245
|
return 'green';
|
|
246
246
|
if (run.Status === 'Failed')
|
|
247
247
|
return 'red';
|
|
248
|
+
// Deliberately stopped — not a defect (red) and not still working (amber).
|
|
249
|
+
if (run.Status === 'Cancelled')
|
|
250
|
+
return 'gray';
|
|
248
251
|
return 'amber';
|
|
249
252
|
}
|
|
250
253
|
StatusIcon(run) {
|
|
@@ -252,8 +255,11 @@ export class RunHistoryPanelComponent {
|
|
|
252
255
|
return 'fa-solid fa-circle-check';
|
|
253
256
|
if (run.Status === 'Failed')
|
|
254
257
|
return 'fa-solid fa-circle-xmark';
|
|
258
|
+
if (run.Status === 'Cancelled')
|
|
259
|
+
return 'fa-solid fa-ban';
|
|
255
260
|
if (run.Status === 'In Progress')
|
|
256
261
|
return 'fa-solid fa-spinner fa-spin';
|
|
262
|
+
// 'Queued' / 'Pending' — waiting to be picked up.
|
|
257
263
|
return 'fa-solid fa-clock';
|
|
258
264
|
}
|
|
259
265
|
FormatDate(dateStr) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-history-panel.component.js","sourceRoot":"","sources":["../../../../src/Integration/components/widgets/run-history-panel.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, OnChanges, SimpleChanges, inject } from '@angular/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { IRunViewProvider } from '@memberjunction/core';\nimport { IntegrationDataService, IntegrationRunRow, RunDetailRow } from '../../services/integration-data.service';\n\ntype RunStatusColorType = 'amber' | 'green' | 'red';\n\n@Component({\n standalone: false,\n selector: 'app-run-history-panel',\n template: `\n @if (IsLoading) {\n <div class=\"history-loading\">\n <mj-loading text=\"Loading run history...\" size=\"small\"></mj-loading>\n </div>\n } @else if (Runs.length === 0) {\n <mj-empty-state class=\"history-empty\" Size=\"compact\"\n Icon=\"fa-solid fa-clock-rotate-left\"\n Title=\"No runs recorded yet\" />\n } @else {\n <div class=\"history-panel\">\n <table class=\"history-table\">\n <thead>\n <tr>\n <th>Started</th>\n <th>Status</th>\n <th>Duration</th>\n <th>Records</th>\n <th>Run By</th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n @for (run of Runs; track run.ID) {\n <tr class=\"run-row\" [class.selected]=\"IsSelectedRun(run.ID)\"\n (click)=\"OnRunClick(run)\">\n <td>{{ FormatDate(run.StartedAt) }}</td>\n <td>\n <span class=\"run-status-chip\" [class]=\"'chip-' + StatusColor(run)\">\n <i [class]=\"StatusIcon(run)\"></i>\n {{ run.Status }}\n </span>\n </td>\n <td class=\"duration-cell\">{{ FormatDuration(run) }}</td>\n <td>{{ run.TotalRecords | number }}</td>\n <td>{{ run.RunByUser }}</td>\n <td>\n <i class=\"fa-solid fa-chevron-right detail-arrow\"\n [class.rotated]=\"IsSelectedRun(run.ID)\"></i>\n </td>\n </tr>\n @if (IsSelectedRun(run.ID) && IsLoadingDetails) {\n <tr class=\"detail-row\">\n <td colspan=\"6\">\n <mj-loading text=\"Loading details...\" size=\"small\"></mj-loading>\n </td>\n </tr>\n }\n @if (IsSelectedRun(run.ID) && !IsLoadingDetails && RunDetails.length > 0) {\n <tr class=\"detail-row\">\n <td colspan=\"6\">\n <div class=\"detail-panel\">\n <h4>Entity Breakdown</h4>\n <table class=\"detail-table\">\n <thead>\n <tr>\n <th>Entity</th>\n <th>Processed</th>\n <th>Created</th>\n <th>Updated</th>\n <th>Errors</th>\n </tr>\n </thead>\n <tbody>\n @for (detail of RunDetails; track detail.EntityID) {\n <tr>\n <td>{{ detail.Entity }}</td>\n <td>{{ detail.RecordsProcessed | number }}</td>\n <td>{{ detail.RecordsCreated | number }}</td>\n <td>{{ detail.RecordsUpdated | number }}</td>\n <td [class.error-count]=\"detail.RecordsErrored > 0\">\n {{ detail.RecordsErrored | number }}\n </td>\n </tr>\n }\n </tbody>\n </table>\n\n <!-- Error details expandable -->\n @if (run.ErrorLog) {\n <div class=\"error-details-section\">\n <button class=\"error-toggle\" (click)=\"ToggleErrorLog($event)\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n Error Details\n <i class=\"fa-solid fa-chevron-down toggle-icon\"\n [class.rotated]=\"ShowErrorLog\"></i>\n </button>\n @if (ShowErrorLog) {\n <pre class=\"error-log\">{{ run.ErrorLog }}</pre>\n }\n </div>\n }\n </div>\n </td>\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n }\n `,\n styles: [`\n .history-loading, .history-empty {\n padding: 24px; text-align: center; color: var(--mj-text-muted);\n }\n .history-empty i { font-size: 24px; margin-bottom: 8px; display: block; }\n\n .history-panel { margin-top: 8px; }\n\n .history-table {\n width: 100%; border-collapse: collapse; font-size: 13px;\n }\n .history-table th {\n text-align: left; padding: 6px 8px;\n border-bottom: 2px solid var(--mj-border-default); color: var(--mj-text-secondary); font-weight: 600;\n }\n .run-row { cursor: pointer; }\n .run-row:hover { background: var(--mj-bg-surface-sunken); }\n .run-row.selected { background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface)); }\n .run-row td { padding: 6px 8px; border-bottom: 1px solid var(--mj-border-default); }\n\n /* Status Chips with icon */\n .run-status-chip {\n font-size: 11px; font-weight: 600; padding: 3px 8px;\n border-radius: 10px; display: inline-flex; align-items: center; gap: 4px;\n white-space: nowrap;\n }\n .chip-green { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n .chip-amber { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n .chip-red { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n\n .duration-cell {\n font-variant-numeric: tabular-nums;\n color: var(--mj-text-secondary);\n }\n\n .detail-arrow { transition: transform 0.2s; font-size: 11px; color: var(--mj-text-muted); }\n .detail-arrow.rotated { transform: rotate(90deg); }\n\n .detail-row td { padding: 0; }\n .detail-panel {\n padding: 12px 16px; background: var(--mj-bg-surface-sunken);\n border-left: 3px solid var(--mj-brand-primary);\n }\n .detail-panel h4 { margin: 0 0 8px 0; font-size: 13px; }\n\n .detail-table {\n width: 100%; border-collapse: collapse; font-size: 12px;\n }\n .detail-table th {\n text-align: left; padding: 4px 6px; color: var(--mj-text-muted); font-weight: 500;\n }\n .detail-table td { padding: 4px 6px; }\n .error-count { color: var(--mj-status-error-text); font-weight: 600; }\n\n /* Error Details */\n .error-details-section {\n margin-top: 12px;\n border-top: 1px solid var(--mj-border-default);\n padding-top: 8px;\n }\n .error-toggle {\n background: none; border: none; cursor: pointer;\n font-size: 12px; font-weight: 600; color: var(--mj-status-error-text);\n display: flex; align-items: center; gap: 6px;\n padding: 4px 0;\n }\n .error-toggle:hover { text-decoration: underline; }\n .toggle-icon {\n transition: transform 0.2s; font-size: 10px;\n }\n .toggle-icon.rotated { transform: rotate(180deg); }\n .error-log {\n margin: 8px 0 0 0; padding: 10px;\n background: var(--mj-status-error-bg); border: 1px solid var(--mj-status-error-border);\n border-radius: 4px; font-size: 11px;\n white-space: pre-wrap; word-break: break-word;\n max-height: 200px; overflow-y: auto;\n color: var(--mj-status-error-text);\n }\n `]\n})\nexport class RunHistoryPanelComponent implements OnChanges {\n @Input() CompanyIntegrationID: string | null = null;\n @Input() ViewProvider: IRunViewProvider | null = null;\n\n Runs: IntegrationRunRow[] = [];\n RunDetails: RunDetailRow[] = [];\n SelectedRunID: string | null = null;\n IsLoading = false;\n IsLoadingDetails = false;\n ShowErrorLog = false;\n\n private dataService = inject(IntegrationDataService);\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['CompanyIntegrationID'] && this.CompanyIntegrationID) {\n this.LoadRuns();\n }\n }\n\n async LoadRuns(): Promise<void> {\n if (!this.CompanyIntegrationID) return;\n this.IsLoading = true;\n this.SelectedRunID = null;\n this.RunDetails = [];\n this.ShowErrorLog = false;\n try {\n this.Runs = await this.dataService.LoadRunHistory(\n this.CompanyIntegrationID, 10, this.ViewProvider\n );\n } finally {\n this.IsLoading = false;\n }\n }\n\n async OnRunClick(run: IntegrationRunRow): Promise<void> {\n if (UUIDsEqual(this.SelectedRunID, run.ID)) {\n this.SelectedRunID = null;\n this.RunDetails = [];\n this.ShowErrorLog = false;\n return;\n }\n this.SelectedRunID = run.ID;\n this.IsLoadingDetails = true;\n this.RunDetails = [];\n this.ShowErrorLog = false;\n try {\n this.RunDetails = await this.dataService.LoadRunDetails(run.ID, this.ViewProvider);\n } finally {\n this.IsLoadingDetails = false;\n }\n }\n\n IsSelectedRun(id: string): boolean {\n return UUIDsEqual(this.SelectedRunID, id);\n }\n\n StatusColor(run: IntegrationRunRow): RunStatusColorType {\n if (run.Status === 'Success') return 'green';\n if (run.Status === 'Failed') return 'red';\n return 'amber';\n }\n\n StatusIcon(run: IntegrationRunRow): string {\n if (run.Status === 'Success') return 'fa-solid fa-circle-check';\n if (run.Status === 'Failed') return 'fa-solid fa-circle-xmark';\n if (run.Status === 'In Progress') return 'fa-solid fa-spinner fa-spin';\n return 'fa-solid fa-clock';\n }\n\n FormatDate(dateStr: Date | string | null): string {\n if (!dateStr) return '--';\n const d = new Date(dateStr);\n return d.toLocaleString(undefined, {\n month: 'short', day: 'numeric',\n hour: '2-digit', minute: '2-digit'\n });\n }\n\n FormatDuration(run: IntegrationRunRow): string {\n if (!run.StartedAt || !run.EndedAt) return '--';\n const ms = new Date(run.EndedAt).getTime() - new Date(run.StartedAt).getTime();\n return this.dataService.FormatDuration(ms);\n }\n\n ToggleErrorLog(event: Event): void {\n event.stopPropagation();\n this.ShowErrorLog = !this.ShowErrorLog;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"run-history-panel.component.js","sourceRoot":"","sources":["../../../../src/Integration/components/widgets/run-history-panel.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, OnChanges, SimpleChanges, inject } from '@angular/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { IRunViewProvider } from '@memberjunction/core';\nimport { IntegrationDataService, IntegrationRunRow, RunDetailRow } from '../../services/integration-data.service';\n\ntype RunStatusColorType = 'amber' | 'green' | 'red' | 'gray';\n\n@Component({\n standalone: false,\n selector: 'app-run-history-panel',\n template: `\n @if (IsLoading) {\n <div class=\"history-loading\">\n <mj-loading text=\"Loading run history...\" size=\"small\"></mj-loading>\n </div>\n } @else if (Runs.length === 0) {\n <mj-empty-state class=\"history-empty\" Size=\"compact\"\n Icon=\"fa-solid fa-clock-rotate-left\"\n Title=\"No runs recorded yet\" />\n } @else {\n <div class=\"history-panel\">\n <table class=\"history-table\">\n <thead>\n <tr>\n <th>Started</th>\n <th>Status</th>\n <th>Duration</th>\n <th>Records</th>\n <th>Run By</th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n @for (run of Runs; track run.ID) {\n <tr class=\"run-row\" [class.selected]=\"IsSelectedRun(run.ID)\"\n (click)=\"OnRunClick(run)\">\n <td>{{ FormatDate(run.StartedAt) }}</td>\n <td>\n <span class=\"run-status-chip\" [class]=\"'chip-' + StatusColor(run)\">\n <i [class]=\"StatusIcon(run)\"></i>\n {{ run.Status }}\n </span>\n </td>\n <td class=\"duration-cell\">{{ FormatDuration(run) }}</td>\n <td>{{ run.TotalRecords | number }}</td>\n <td>{{ run.RunByUser }}</td>\n <td>\n <i class=\"fa-solid fa-chevron-right detail-arrow\"\n [class.rotated]=\"IsSelectedRun(run.ID)\"></i>\n </td>\n </tr>\n @if (IsSelectedRun(run.ID) && IsLoadingDetails) {\n <tr class=\"detail-row\">\n <td colspan=\"6\">\n <mj-loading text=\"Loading details...\" size=\"small\"></mj-loading>\n </td>\n </tr>\n }\n @if (IsSelectedRun(run.ID) && !IsLoadingDetails && RunDetails.length > 0) {\n <tr class=\"detail-row\">\n <td colspan=\"6\">\n <div class=\"detail-panel\">\n <h4>Entity Breakdown</h4>\n <table class=\"detail-table\">\n <thead>\n <tr>\n <th>Entity</th>\n <th>Processed</th>\n <th>Created</th>\n <th>Updated</th>\n <th>Errors</th>\n </tr>\n </thead>\n <tbody>\n @for (detail of RunDetails; track detail.EntityID) {\n <tr>\n <td>{{ detail.Entity }}</td>\n <td>{{ detail.RecordsProcessed | number }}</td>\n <td>{{ detail.RecordsCreated | number }}</td>\n <td>{{ detail.RecordsUpdated | number }}</td>\n <td [class.error-count]=\"detail.RecordsErrored > 0\">\n {{ detail.RecordsErrored | number }}\n </td>\n </tr>\n }\n </tbody>\n </table>\n\n <!-- Error details expandable -->\n @if (run.ErrorLog) {\n <div class=\"error-details-section\">\n <button class=\"error-toggle\" (click)=\"ToggleErrorLog($event)\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n Error Details\n <i class=\"fa-solid fa-chevron-down toggle-icon\"\n [class.rotated]=\"ShowErrorLog\"></i>\n </button>\n @if (ShowErrorLog) {\n <pre class=\"error-log\">{{ run.ErrorLog }}</pre>\n }\n </div>\n }\n </div>\n </td>\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n }\n `,\n styles: [`\n .history-loading, .history-empty {\n padding: 24px; text-align: center; color: var(--mj-text-muted);\n }\n .history-empty i { font-size: 24px; margin-bottom: 8px; display: block; }\n\n .history-panel { margin-top: 8px; }\n\n .history-table {\n width: 100%; border-collapse: collapse; font-size: 13px;\n }\n .history-table th {\n text-align: left; padding: 6px 8px;\n border-bottom: 2px solid var(--mj-border-default); color: var(--mj-text-secondary); font-weight: 600;\n }\n .run-row { cursor: pointer; }\n .run-row:hover { background: var(--mj-bg-surface-sunken); }\n .run-row.selected { background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface)); }\n .run-row td { padding: 6px 8px; border-bottom: 1px solid var(--mj-border-default); }\n\n /* Status Chips with icon */\n .run-status-chip {\n font-size: 11px; font-weight: 600; padding: 3px 8px;\n border-radius: 10px; display: inline-flex; align-items: center; gap: 4px;\n white-space: nowrap;\n }\n .chip-green { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n .chip-amber { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n .chip-red { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n\n .duration-cell {\n font-variant-numeric: tabular-nums;\n color: var(--mj-text-secondary);\n }\n\n .detail-arrow { transition: transform 0.2s; font-size: 11px; color: var(--mj-text-muted); }\n .detail-arrow.rotated { transform: rotate(90deg); }\n\n .detail-row td { padding: 0; }\n .detail-panel {\n padding: 12px 16px; background: var(--mj-bg-surface-sunken);\n border-left: 3px solid var(--mj-brand-primary);\n }\n .detail-panel h4 { margin: 0 0 8px 0; font-size: 13px; }\n\n .detail-table {\n width: 100%; border-collapse: collapse; font-size: 12px;\n }\n .detail-table th {\n text-align: left; padding: 4px 6px; color: var(--mj-text-muted); font-weight: 500;\n }\n .detail-table td { padding: 4px 6px; }\n .error-count { color: var(--mj-status-error-text); font-weight: 600; }\n\n /* Error Details */\n .error-details-section {\n margin-top: 12px;\n border-top: 1px solid var(--mj-border-default);\n padding-top: 8px;\n }\n .error-toggle {\n background: none; border: none; cursor: pointer;\n font-size: 12px; font-weight: 600; color: var(--mj-status-error-text);\n display: flex; align-items: center; gap: 6px;\n padding: 4px 0;\n }\n .error-toggle:hover { text-decoration: underline; }\n .toggle-icon {\n transition: transform 0.2s; font-size: 10px;\n }\n .toggle-icon.rotated { transform: rotate(180deg); }\n .error-log {\n margin: 8px 0 0 0; padding: 10px;\n background: var(--mj-status-error-bg); border: 1px solid var(--mj-status-error-border);\n border-radius: 4px; font-size: 11px;\n white-space: pre-wrap; word-break: break-word;\n max-height: 200px; overflow-y: auto;\n color: var(--mj-status-error-text);\n }\n `]\n})\nexport class RunHistoryPanelComponent implements OnChanges {\n @Input() CompanyIntegrationID: string | null = null;\n @Input() ViewProvider: IRunViewProvider | null = null;\n\n Runs: IntegrationRunRow[] = [];\n RunDetails: RunDetailRow[] = [];\n SelectedRunID: string | null = null;\n IsLoading = false;\n IsLoadingDetails = false;\n ShowErrorLog = false;\n\n private dataService = inject(IntegrationDataService);\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['CompanyIntegrationID'] && this.CompanyIntegrationID) {\n this.LoadRuns();\n }\n }\n\n async LoadRuns(): Promise<void> {\n if (!this.CompanyIntegrationID) return;\n this.IsLoading = true;\n this.SelectedRunID = null;\n this.RunDetails = [];\n this.ShowErrorLog = false;\n try {\n this.Runs = await this.dataService.LoadRunHistory(\n this.CompanyIntegrationID, 10, this.ViewProvider\n );\n } finally {\n this.IsLoading = false;\n }\n }\n\n async OnRunClick(run: IntegrationRunRow): Promise<void> {\n if (UUIDsEqual(this.SelectedRunID, run.ID)) {\n this.SelectedRunID = null;\n this.RunDetails = [];\n this.ShowErrorLog = false;\n return;\n }\n this.SelectedRunID = run.ID;\n this.IsLoadingDetails = true;\n this.RunDetails = [];\n this.ShowErrorLog = false;\n try {\n this.RunDetails = await this.dataService.LoadRunDetails(run.ID, this.ViewProvider);\n } finally {\n this.IsLoadingDetails = false;\n }\n }\n\n IsSelectedRun(id: string): boolean {\n return UUIDsEqual(this.SelectedRunID, id);\n }\n\n StatusColor(run: IntegrationRunRow): RunStatusColorType {\n if (run.Status === 'Success') return 'green';\n if (run.Status === 'Failed') return 'red';\n // Deliberately stopped — not a defect (red) and not still working (amber).\n if (run.Status === 'Cancelled') return 'gray';\n return 'amber';\n }\n\n StatusIcon(run: IntegrationRunRow): string {\n if (run.Status === 'Success') return 'fa-solid fa-circle-check';\n if (run.Status === 'Failed') return 'fa-solid fa-circle-xmark';\n if (run.Status === 'Cancelled') return 'fa-solid fa-ban';\n if (run.Status === 'In Progress') return 'fa-solid fa-spinner fa-spin';\n // 'Queued' / 'Pending' — waiting to be picked up.\n return 'fa-solid fa-clock';\n }\n\n FormatDate(dateStr: Date | string | null): string {\n if (!dateStr) return '--';\n const d = new Date(dateStr);\n return d.toLocaleString(undefined, {\n month: 'short', day: 'numeric',\n hour: '2-digit', minute: '2-digit'\n });\n }\n\n FormatDuration(run: IntegrationRunRow): string {\n if (!run.StartedAt || !run.EndedAt) return '--';\n const ms = new Date(run.EndedAt).getTime() - new Date(run.StartedAt).getTime();\n return this.dataService.FormatDuration(ms);\n }\n\n ToggleErrorLog(event: Event): void {\n event.stopPropagation();\n this.ShowErrorLog = !this.ShowErrorLog;\n }\n}\n"]}
|