@memberjunction/ng-dashboards 5.40.1 → 5.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/AI/components/analytics/ai-analytics-resource.component.d.ts +38 -4
  2. package/dist/AI/components/analytics/ai-analytics-resource.component.d.ts.map +1 -1
  3. package/dist/AI/components/analytics/ai-analytics-resource.component.js +148 -20
  4. package/dist/AI/components/analytics/ai-analytics-resource.component.js.map +1 -1
  5. package/dist/AI/components/analytics/realtime/realtime-management-data.d.ts +216 -0
  6. package/dist/AI/components/analytics/realtime/realtime-management-data.d.ts.map +1 -0
  7. package/dist/AI/components/analytics/realtime/realtime-management-data.js +313 -0
  8. package/dist/AI/components/analytics/realtime/realtime-management-data.js.map +1 -0
  9. package/dist/AI/components/analytics/realtime/realtime-management.component.d.ts +103 -0
  10. package/dist/AI/components/analytics/realtime/realtime-management.component.d.ts.map +1 -0
  11. package/dist/AI/components/analytics/realtime/realtime-management.component.js +1060 -0
  12. package/dist/AI/components/analytics/realtime/realtime-management.component.js.map +1 -0
  13. package/dist/AI/components/analytics/realtime/realtime-overview.component.d.ts +87 -0
  14. package/dist/AI/components/analytics/realtime/realtime-overview.component.d.ts.map +1 -0
  15. package/dist/AI/components/analytics/realtime/realtime-overview.component.js +710 -0
  16. package/dist/AI/components/analytics/realtime/realtime-overview.component.js.map +1 -0
  17. package/dist/AI/components/analytics/realtime/realtime-session-data.d.ts +127 -0
  18. package/dist/AI/components/analytics/realtime/realtime-session-data.d.ts.map +1 -0
  19. package/dist/AI/components/analytics/realtime/realtime-session-data.js +233 -0
  20. package/dist/AI/components/analytics/realtime/realtime-session-data.js.map +1 -0
  21. package/dist/AI/components/analytics/realtime/realtime-sessions.component.d.ts +94 -0
  22. package/dist/AI/components/analytics/realtime/realtime-sessions.component.d.ts.map +1 -0
  23. package/dist/AI/components/analytics/realtime/realtime-sessions.component.js +728 -0
  24. package/dist/AI/components/analytics/realtime/realtime-sessions.component.js.map +1 -0
  25. package/dist/AI/components/autotagging/tabs/sources-tab.component.js +2 -2
  26. package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -1
  27. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
  28. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +4 -1
  29. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
  30. package/dist/AI/components/tags/tags-resource.component.js +2 -2
  31. package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
  32. package/dist/AI/components/vectors/vector-management-resource.component.js +2 -2
  33. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  34. package/dist/AI/index.d.ts +5 -0
  35. package/dist/AI/index.d.ts.map +1 -1
  36. package/dist/AI/index.js +7 -0
  37. package/dist/AI/index.js.map +1 -1
  38. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +5 -5
  39. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
  40. package/dist/MCP/mcp-dashboard.component.d.ts +16 -2
  41. package/dist/MCP/mcp-dashboard.component.d.ts.map +1 -1
  42. package/dist/MCP/mcp-dashboard.component.js +33 -4
  43. package/dist/MCP/mcp-dashboard.component.js.map +1 -1
  44. package/dist/ai-dashboards.module.d.ts +22 -19
  45. package/dist/ai-dashboards.module.d.ts.map +1 -1
  46. package/dist/ai-dashboards.module.js +18 -0
  47. package/dist/ai-dashboards.module.js.map +1 -1
  48. package/package.json +55 -55
@@ -0,0 +1,313 @@
1
+ /**
2
+ * @fileoverview Shared data layer for the **Realtime management** section.
3
+ *
4
+ * Distinct from `realtime-session-data.ts` (which powers the operational
5
+ * *analytics* on voice sessions), this module loads the whole realtime + bridge
6
+ * **management** surface described in §11b of the Realtime Bridges architecture:
7
+ * bridge providers, agent identities, channels, provider→channel contributions,
8
+ * co-agent pairings, live + historical session bridges, and bridge
9
+ * participants. Everything loads in one batched `RunViews` call and is folded
10
+ * into per-surface view models client-side.
11
+ *
12
+ * The pure aggregation in {@link BucketSessionBridgesByDay} +
13
+ * {@link SummarizeBridgesByProvider} / {@link SummarizeBridgesByStatus} is
14
+ * extracted here (no Angular, no `RunView`) so it can be unit-tested in
15
+ * isolation — see `realtime-management-data.spec.ts`.
16
+ */
17
+ import { RunView } from '@memberjunction/core';
18
+ import { NormalizeUUID } from '@memberjunction/global';
19
+ // ─────────────────────────────────────────────────────────────────────────────
20
+ // Constants
21
+ // ─────────────────────────────────────────────────────────────────────────────
22
+ const PROVIDER_FIELDS = ['ID', 'Name', 'Description', 'BridgeType', 'DriverClass', 'Status', 'SupportedFeatures'];
23
+ const IDENTITY_FIELDS = ['ID', 'AgentID', 'Agent', 'ProviderID', 'Provider', 'IdentityType', 'IdentityValue', 'DisplayName', 'IsActive'];
24
+ const CHANNEL_FIELDS = ['ID', 'Name', 'Description', 'TransportType', 'ServerPluginClass', 'ClientPluginClass', 'IsActive'];
25
+ const PROVIDER_CHANNEL_FIELDS = ['ID', 'ProviderID', 'Provider', 'ChannelID', 'Channel', 'IsDefault', 'Sequence'];
26
+ const COAGENT_FIELDS = ['ID', 'CoAgentID', 'CoAgent', 'TargetAgentID', 'TargetAgent', 'TargetAgentTypeID', 'TargetAgentType', 'Type', 'IsDefault', 'Sequence', 'Status'];
27
+ const BRIDGE_FIELDS = ['ID', 'AgentSessionID', 'ProviderID', 'Provider', 'Direction', 'JoinMethod', 'TurnMode', 'Address', 'Status', 'ScheduledStartTime', 'ConnectedAt', 'DisconnectedAt', 'CloseReason', 'HostInstanceID', '__mj_CreatedAt'];
28
+ const PARTICIPANT_FIELDS = ['ID', 'SessionBridgeID', 'DisplayName', 'Role', 'UserID', 'User', 'IsAgent', 'JoinedAt', 'LeftAt'];
29
+ const SESSION_LITE_FIELDS = ['ID', 'Agent', 'User', 'Status', '__mj_CreatedAt'];
30
+ /** Bridge statuses that mean "still on the call/meeting". */
31
+ const LIVE_BRIDGE_STATUSES = new Set(['Pending', 'Scheduled', 'Connecting', 'Connected', 'Disconnecting']);
32
+ /** Supported time-range keys → milliseconds (history window; live is never filtered out). */
33
+ const TIME_RANGE_MS = {
34
+ '24h': 86_400_000,
35
+ '7d': 604_800_000,
36
+ '30d': 2_592_000_000
37
+ };
38
+ /** History-window range → milliseconds (local to this module). */
39
+ function timeRangeToMs(range) {
40
+ return TIME_RANGE_MS[range] ?? TIME_RANGE_MS['7d'];
41
+ }
42
+ // ─────────────────────────────────────────────────────────────────────────────
43
+ // Loading + aggregation
44
+ // ─────────────────────────────────────────────────────────────────────────────
45
+ /**
46
+ * Loads the full management surface in one batched `RunViews` call, then folds
47
+ * everything into per-surface view models. History is windowed by `timeRange`;
48
+ * live bridges are always included regardless of age.
49
+ */
50
+ export async function LoadRealtimeManagementDataset(provider, timeRange) {
51
+ const windowMs = timeRangeToMs(timeRange);
52
+ const now = Date.now();
53
+ const windowStart = new Date(now - windowMs);
54
+ const rv = RunView.FromMetadataProvider(provider);
55
+ const [providerResult, identityResult, channelResult, providerChannelResult, coAgentResult, bridgeResult, participantResult, sessionResult] = await rv.RunViews([
56
+ { EntityName: 'MJ: AI Bridge Providers', Fields: PROVIDER_FIELDS, OrderBy: 'Name', ResultType: 'simple' },
57
+ { EntityName: 'MJ: AI Bridge Agent Identities', Fields: IDENTITY_FIELDS, OrderBy: 'Provider, IdentityValue', ResultType: 'simple' },
58
+ { EntityName: 'MJ: AI Agent Channels', Fields: CHANNEL_FIELDS, OrderBy: 'Name', ResultType: 'simple' },
59
+ { EntityName: 'MJ: AI Bridge Provider Channels', Fields: PROVIDER_CHANNEL_FIELDS, OrderBy: 'Provider, Sequence', ResultType: 'simple' },
60
+ { EntityName: 'MJ: AI Agent Co Agents', Fields: COAGENT_FIELDS, OrderBy: 'CoAgent, Sequence', ResultType: 'simple' },
61
+ {
62
+ EntityName: 'MJ: AI Agent Session Bridges',
63
+ ExtraFilter: `__mj_CreatedAt >= '${windowStart.toISOString()}' OR Status IN ('Pending','Scheduled','Connecting','Connected','Disconnecting')`,
64
+ Fields: BRIDGE_FIELDS,
65
+ OrderBy: '__mj_CreatedAt DESC',
66
+ ResultType: 'simple'
67
+ },
68
+ { EntityName: 'MJ: AI Agent Session Bridge Participants', Fields: PARTICIPANT_FIELDS, ResultType: 'simple' },
69
+ {
70
+ EntityName: 'MJ: AI Agent Sessions',
71
+ ExtraFilter: `__mj_CreatedAt >= '${windowStart.toISOString()}' OR Status IN ('Active','Idle')`,
72
+ Fields: SESSION_LITE_FIELDS,
73
+ ResultType: 'simple'
74
+ }
75
+ ]);
76
+ const providers = (providerResult?.Success ? providerResult.Results : []);
77
+ const identities = (identityResult?.Success ? identityResult.Results : []);
78
+ const channels = (channelResult?.Success ? channelResult.Results : []);
79
+ const providerChannels = (providerChannelResult?.Success ? providerChannelResult.Results : []);
80
+ const coAgents = (coAgentResult?.Success ? coAgentResult.Results : []);
81
+ const bridges = (bridgeResult?.Success ? bridgeResult.Results : []);
82
+ const participants = (participantResult?.Success ? participantResult.Results : []);
83
+ const sessions = (sessionResult?.Success ? sessionResult.Results : []);
84
+ const providerChannelMap = groupBy(providerChannels, pc => pc.ProviderID);
85
+ const providerRollups = providers.map(p => buildProviderRollup(p, providerChannelMap));
86
+ const sessionMap = new Map(sessions.map(s => [NormalizeUUID(s.ID), s]));
87
+ const participantCountMap = countBy(participants, p => p.SessionBridgeID);
88
+ const bridgeRollups = bridges.map(b => buildBridgeRollup(b, sessionMap, participantCountMap, now));
89
+ const liveBridges = bridgeRollups.filter(b => b.IsLive);
90
+ const historyBridges = bridgeRollups.filter(b => !b.IsLive);
91
+ return {
92
+ Providers: providerRollups,
93
+ Identities: identities,
94
+ Channels: channels,
95
+ ProviderChannels: providerChannels,
96
+ CoAgents: coAgents,
97
+ LiveBridges: liveBridges,
98
+ HistoryBridges: historyBridges,
99
+ AllBridges: bridgeRollups,
100
+ WindowStart: windowStart,
101
+ WindowMs: windowMs
102
+ };
103
+ }
104
+ function buildProviderRollup(record, providerChannelMap) {
105
+ const features = parseFeatures(record.SupportedFeatures);
106
+ const channels = (providerChannelMap.get(NormalizeUUID(record.ID)) ?? [])
107
+ .slice()
108
+ .sort((a, b) => a.Sequence - b.Sequence);
109
+ return {
110
+ Record: record,
111
+ Features: features,
112
+ FeatureCount: features ? countTrueFlags(features) : 0,
113
+ Channels: channels
114
+ };
115
+ }
116
+ function buildBridgeRollup(record, sessionMap, participantCountMap, now) {
117
+ const session = sessionMap.get(NormalizeUUID(record.AgentSessionID)) ?? null;
118
+ const startedAt = new Date(record.__mj_CreatedAt);
119
+ const isLive = LIVE_BRIDGE_STATUSES.has(record.Status);
120
+ let durationMs = 0;
121
+ if (record.ConnectedAt) {
122
+ const end = record.DisconnectedAt ? new Date(record.DisconnectedAt).getTime() : now;
123
+ durationMs = Math.max(0, end - new Date(record.ConnectedAt).getTime());
124
+ }
125
+ return {
126
+ Record: record,
127
+ Session: session,
128
+ AgentName: session?.Agent ?? 'Unknown agent',
129
+ UserName: session?.User ?? '—',
130
+ ParticipantCount: participantCountMap.get(NormalizeUUID(record.ID)) ?? 0,
131
+ StartedAt: startedAt,
132
+ DurationMs: durationMs,
133
+ IsLive: isLive
134
+ };
135
+ }
136
+ /** Parses the `SupportedFeatures` JSON string into the typed interface. */
137
+ function parseFeatures(raw) {
138
+ if (!raw)
139
+ return null;
140
+ try {
141
+ const parsed = JSON.parse(raw);
142
+ return parsed && typeof parsed === 'object' ? parsed : null;
143
+ }
144
+ catch {
145
+ return null;
146
+ }
147
+ }
148
+ /** Counts `true` boolean flags on a features object. */
149
+ function countTrueFlags(features) {
150
+ return Object.values(features).filter(v => v === true).length;
151
+ }
152
+ function groupBy(rows, keyOf) {
153
+ const map = new Map();
154
+ for (const row of rows) {
155
+ const key = NormalizeUUID(keyOf(row));
156
+ const list = map.get(key);
157
+ if (list)
158
+ list.push(row);
159
+ else
160
+ map.set(key, [row]);
161
+ }
162
+ return map;
163
+ }
164
+ function countBy(rows, keyOf) {
165
+ const map = new Map();
166
+ for (const row of rows) {
167
+ const key = NormalizeUUID(keyOf(row));
168
+ map.set(key, (map.get(key) ?? 0) + 1);
169
+ }
170
+ return map;
171
+ }
172
+ /**
173
+ * Buckets session bridges by their local calendar day across `[windowStart, now]`,
174
+ * emitting one bucket **per day in the window** (including zero-count days) so the
175
+ * resulting series is dense and renderable as bars without gaps.
176
+ *
177
+ * Pure + deterministic given its inputs — `now` is injected for testability.
178
+ *
179
+ * @param bridges the bridge rollups to bucket (uses each `StartedAt`)
180
+ * @param windowStart inclusive start of the window
181
+ * @param now the window end (exclusive upper edge is `now`'s day + 1)
182
+ * @returns one bucket per day, oldest → newest
183
+ */
184
+ export function BucketSessionBridgesByDay(bridges, windowStart, now) {
185
+ const startDay = startOfDay(windowStart);
186
+ const endDay = startOfDay(now);
187
+ if (endDay.getTime() < startDay.getTime())
188
+ return [];
189
+ // Seed every day in [startDay, endDay] with a zero count.
190
+ const buckets = new Map();
191
+ for (let d = new Date(startDay); d.getTime() <= endDay.getTime(); d = addDays(d, 1)) {
192
+ const label = toDayLabel(d);
193
+ buckets.set(label, { Date: new Date(d), Label: label, Count: 0 });
194
+ }
195
+ for (const bridge of bridges) {
196
+ const day = startOfDay(bridge.StartedAt);
197
+ if (day.getTime() < startDay.getTime() || day.getTime() > endDay.getTime())
198
+ continue;
199
+ const bucket = buckets.get(toDayLabel(day));
200
+ if (bucket)
201
+ bucket.Count++;
202
+ }
203
+ return Array.from(buckets.values()).sort((a, b) => a.Date.getTime() - b.Date.getTime());
204
+ }
205
+ /** Aggregates bridge rollups into count-by-provider slices, descending by count. */
206
+ export function SummarizeBridgesByProvider(bridges) {
207
+ return summarizeBy(bridges, b => b.Record.Provider || 'Unknown');
208
+ }
209
+ /** Aggregates bridge rollups into count-by-status slices, descending by count. */
210
+ export function SummarizeBridgesByStatus(bridges) {
211
+ return summarizeBy(bridges, b => b.Record.Status);
212
+ }
213
+ /** Aggregates bridge rollups into count-by-agent slices, descending by count. */
214
+ export function SummarizeBridgesByAgent(bridges) {
215
+ return summarizeBy(bridges, b => b.AgentName || 'Unknown agent');
216
+ }
217
+ function summarizeBy(bridges, labelOf) {
218
+ const counts = new Map();
219
+ for (const bridge of bridges) {
220
+ const label = labelOf(bridge);
221
+ counts.set(label, (counts.get(label) ?? 0) + 1);
222
+ }
223
+ return Array.from(counts.entries())
224
+ .map(([Label, Count]) => ({ Label, Count }))
225
+ .sort((a, b) => b.Count - a.Count || a.Label.localeCompare(b.Label));
226
+ }
227
+ function startOfDay(date) {
228
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
229
+ }
230
+ function addDays(date, days) {
231
+ const next = new Date(date);
232
+ next.setDate(next.getDate() + days);
233
+ return next;
234
+ }
235
+ function toDayLabel(date) {
236
+ const y = date.getFullYear();
237
+ const m = (date.getMonth() + 1).toString().padStart(2, '0');
238
+ const d = date.getDate().toString().padStart(2, '0');
239
+ return `${y}-${m}-${d}`;
240
+ }
241
+ // ─────────────────────────────────────────────────────────────────────────────
242
+ // Formatting helpers (shared by the section's sub-tabs)
243
+ // ─────────────────────────────────────────────────────────────────────────────
244
+ /** Font Awesome icon for a bridge type. */
245
+ export function BridgeTypeIcon(type) {
246
+ return type === 'Telephony' ? 'fa-solid fa-phone' : 'fa-solid fa-video';
247
+ }
248
+ /** Font Awesome icon for an identity type. */
249
+ export function IdentityTypeIcon(type) {
250
+ switch (type) {
251
+ case 'Email': return 'fa-solid fa-envelope';
252
+ case 'PhoneNumber': return 'fa-solid fa-phone';
253
+ default: return 'fa-solid fa-id-badge';
254
+ }
255
+ }
256
+ /** Font Awesome icon for a channel transport type. */
257
+ export function TransportTypeIcon(type) {
258
+ switch (type) {
259
+ case 'WebRTC': return 'fa-solid fa-tower-broadcast';
260
+ case 'WebSocket': return 'fa-solid fa-plug';
261
+ default: return 'fa-solid fa-satellite-dish';
262
+ }
263
+ }
264
+ /**
265
+ * Builds the prioritized capability chips for a provider's feature set. Returns
266
+ * the highest-signal capabilities first (media, then join methods, then
267
+ * signals), so the grid can render a few and show "+N" for the remainder.
268
+ */
269
+ export function BuildCapabilityChips(features) {
270
+ if (!features)
271
+ return [];
272
+ const chips = [];
273
+ const add = (flag, icon, label) => {
274
+ if (flag)
275
+ chips.push({ Icon: icon, Label: label });
276
+ };
277
+ add(features.AudioIn || features.AudioOut, 'fa-solid fa-microphone-lines', 'Audio');
278
+ add(features.VideoIn || features.VideoOut, 'fa-solid fa-video', 'Video');
279
+ add(features.ScreenIn || features.ScreenOut, 'fa-solid fa-display', 'Screen');
280
+ add(features.SpeakerDiarization, 'fa-solid fa-user-group', 'Diarization');
281
+ add(features.InviteJoin, 'fa-solid fa-calendar-check', 'Invite/Calendar');
282
+ add(features.OnDemandJoin, 'fa-solid fa-bolt', 'On-demand');
283
+ add(features.ScheduledJoin, 'fa-solid fa-clock', 'Scheduled');
284
+ add(features.InboundRouting, 'fa-solid fa-arrow-right-to-bracket', 'Inbound');
285
+ add(features.OutboundDial, 'fa-solid fa-phone-volume', 'Outbound dial');
286
+ add(features.DTMF, 'fa-solid fa-hashtag', 'DTMF');
287
+ add(features.CallTransfer, 'fa-solid fa-arrow-right-arrow-left', 'Transfer');
288
+ add(features.Recording, 'fa-solid fa-circle-dot', 'Recording');
289
+ return chips;
290
+ }
291
+ /** Formats a duration as m:ss (or h:mm:ss past the hour). */
292
+ export function FormatBridgeDuration(ms) {
293
+ if (ms <= 0)
294
+ return '—';
295
+ const totalSeconds = Math.floor(ms / 1000);
296
+ const seconds = totalSeconds % 60;
297
+ const minutes = Math.floor(totalSeconds / 60) % 60;
298
+ const hours = Math.floor(totalSeconds / 3600);
299
+ const pad = (n) => n.toString().padStart(2, '0');
300
+ return hours > 0 ? `${hours}:${pad(minutes)}:${pad(seconds)}` : `${minutes}:${pad(seconds)}`;
301
+ }
302
+ /** Today → "3:40 pm", yesterday → "Yesterday", else "M/d". */
303
+ export function FormatBridgeStart(date) {
304
+ const now = new Date();
305
+ const startToday = new Date(now.getFullYear(), now.getMonth(), now.getDate());
306
+ const startYesterday = new Date(startToday.getTime() - 86_400_000);
307
+ if (date >= startToday)
308
+ return date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }).toLowerCase();
309
+ if (date >= startYesterday)
310
+ return 'Yesterday';
311
+ return date.toLocaleDateString([], { month: 'numeric', day: 'numeric' });
312
+ }
313
+ //# sourceMappingURL=realtime-management-data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-management-data.js","sourceRoot":"","sources":["../../../../../src/AI/components/analytics/realtime/realtime-management-data.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Shared data layer for the **Realtime management** section.\n *\n * Distinct from `realtime-session-data.ts` (which powers the operational\n * *analytics* on voice sessions), this module loads the whole realtime + bridge\n * **management** surface described in §11b of the Realtime Bridges architecture:\n * bridge providers, agent identities, channels, provider→channel contributions,\n * co-agent pairings, live + historical session bridges, and bridge\n * participants. Everything loads in one batched `RunViews` call and is folded\n * into per-surface view models client-side.\n *\n * The pure aggregation in {@link BucketSessionBridgesByDay} +\n * {@link SummarizeBridgesByProvider} / {@link SummarizeBridgesByStatus} is\n * extracted here (no Angular, no `RunView`) so it can be unit-tested in\n * isolation — see `realtime-management-data.spec.ts`.\n */\n\nimport { IMetadataProvider, RunView } from '@memberjunction/core';\nimport { NormalizeUUID } from '@memberjunction/global';\nimport type {\n MJAIBridgeProviderEntity_IBridgeProviderFeatures\n} from '@memberjunction/core-entities';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Raw row shapes (ResultType: 'simple', narrowed Fields)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** A bridge provider registry row (`MJ: AI Bridge Providers`). */\nexport interface BridgeProviderRecord {\n ID: string;\n Name: string;\n Description: string | null;\n BridgeType: 'Meeting' | 'Telephony';\n DriverClass: string;\n Status: 'Active' | 'Disabled';\n /** Raw `SupportedFeatures` JSON string (parsed client-side, see {@link parseFeatures}). */\n SupportedFeatures: string | null;\n}\n\n/** A bridge agent-identity row (`MJ: AI Bridge Agent Identities`). */\nexport interface BridgeAgentIdentityRecord {\n ID: string;\n AgentID: string;\n Agent: string | null;\n ProviderID: string;\n Provider: string;\n IdentityType: 'AccountID' | 'Email' | 'PhoneNumber';\n IdentityValue: string;\n DisplayName: string | null;\n IsActive: boolean;\n}\n\n/** An agent-channel registry row (`MJ: AI Agent Channels`). */\nexport interface AgentChannelRecord {\n ID: string;\n Name: string;\n Description: string | null;\n TransportType: 'PubSub' | 'WebRTC' | 'WebSocket';\n ServerPluginClass: string;\n ClientPluginClass: string;\n IsActive: boolean;\n}\n\n/** A provider→channel contribution row (`MJ: AI Bridge Provider Channels`). */\nexport interface BridgeProviderChannelRecord {\n ID: string;\n ProviderID: string;\n Provider: string;\n ChannelID: string;\n Channel: string;\n IsDefault: boolean;\n Sequence: number;\n}\n\n/** A co-agent pairing row (`MJ: AI Agent Co Agents`). */\nexport interface AgentCoAgentRecord {\n ID: string;\n CoAgentID: string;\n CoAgent: string | null;\n TargetAgentID: string | null;\n TargetAgent: string | null;\n TargetAgentTypeID: string | null;\n TargetAgentType: string | null;\n Type: 'CoAgent' | 'Delegate' | 'Fallback' | 'Observer' | 'Peer' | 'Reviewer';\n IsDefault: boolean;\n Sequence: number;\n Status: 'Active' | 'Disabled';\n}\n\n/** A session-bridge row (`MJ: AI Agent Session Bridges`). */\nexport interface SessionBridgeRecord {\n ID: string;\n AgentSessionID: string;\n ProviderID: string;\n Provider: string;\n Direction: 'Inbound' | 'Outbound';\n JoinMethod: 'InMeetingCommand' | 'InboundRoute' | 'Invite' | 'NativeInvite' | 'OnDemand' | 'Scheduled';\n TurnMode: 'Active' | 'Hybrid' | 'Passive';\n Address: string | null;\n Status: 'Connected' | 'Connecting' | 'Disconnected' | 'Disconnecting' | 'Failed' | 'Pending' | 'Scheduled';\n ScheduledStartTime: string | null;\n ConnectedAt: string | null;\n DisconnectedAt: string | null;\n CloseReason: 'Error' | 'Explicit' | 'HostEnded' | 'Janitor' | 'Shutdown' | null;\n HostInstanceID: string | null;\n __mj_CreatedAt: string;\n}\n\n/** A bridge participant row (`MJ: AI Agent Session Bridge Participants`). */\nexport interface SessionBridgeParticipantRecord {\n ID: string;\n SessionBridgeID: string;\n DisplayName: string | null;\n Role: 'Agent' | 'CoHost' | 'Host' | 'Participant';\n UserID: string | null;\n User: string | null;\n IsAgent: boolean;\n JoinedAt: string | null;\n LeftAt: string | null;\n}\n\n/** The session a bridge attaches to (`MJ: AI Agent Sessions`, narrowed). */\nexport interface SessionLiteRecord {\n ID: string;\n Agent: string | null;\n User: string;\n Status: 'Active' | 'Idle' | 'Closed';\n __mj_CreatedAt: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Aggregated view models\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** A provider plus its parsed capability summary and contributed channels. */\nexport interface BridgeProviderRollup {\n Record: BridgeProviderRecord;\n /** Parsed `SupportedFeatures` JSON; `null` when unset/unparseable. */\n Features: MJAIBridgeProviderEntity_IBridgeProviderFeatures | null;\n /** Count of `true` capability flags. */\n FeatureCount: number;\n /** Channels this provider contributes (sorted by Sequence). */\n Channels: BridgeProviderChannelRecord[];\n}\n\n/** A session bridge joined with its session + participant count. */\nexport interface SessionBridgeRollup {\n Record: SessionBridgeRecord;\n /** The attached session, when found in the loaded window. */\n Session: SessionLiteRecord | null;\n AgentName: string;\n UserName: string;\n ParticipantCount: number;\n StartedAt: Date;\n /** ConnectedAt → (DisconnectedAt ?? now) for connected; else 0. */\n DurationMs: number;\n /** True when the bridge is live (Connecting / Connected). */\n IsLive: boolean;\n}\n\n/** A complete load pass of the management surface. */\nexport interface RealtimeManagementDataset {\n Providers: BridgeProviderRollup[];\n Identities: BridgeAgentIdentityRecord[];\n Channels: AgentChannelRecord[];\n ProviderChannels: BridgeProviderChannelRecord[];\n CoAgents: AgentCoAgentRecord[];\n /** Live session bridges (Connecting / Connected), newest first. */\n LiveBridges: SessionBridgeRollup[];\n /** Closed/terminal session bridges in the window, newest first. */\n HistoryBridges: SessionBridgeRollup[];\n /** Every bridge rollup loaded (live + history), for metrics. */\n AllBridges: SessionBridgeRollup[];\n WindowStart: Date;\n WindowMs: number;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Constants\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst PROVIDER_FIELDS = ['ID', 'Name', 'Description', 'BridgeType', 'DriverClass', 'Status', 'SupportedFeatures'];\nconst IDENTITY_FIELDS = ['ID', 'AgentID', 'Agent', 'ProviderID', 'Provider', 'IdentityType', 'IdentityValue', 'DisplayName', 'IsActive'];\nconst CHANNEL_FIELDS = ['ID', 'Name', 'Description', 'TransportType', 'ServerPluginClass', 'ClientPluginClass', 'IsActive'];\nconst PROVIDER_CHANNEL_FIELDS = ['ID', 'ProviderID', 'Provider', 'ChannelID', 'Channel', 'IsDefault', 'Sequence'];\nconst COAGENT_FIELDS = ['ID', 'CoAgentID', 'CoAgent', 'TargetAgentID', 'TargetAgent', 'TargetAgentTypeID', 'TargetAgentType', 'Type', 'IsDefault', 'Sequence', 'Status'];\nconst BRIDGE_FIELDS = ['ID', 'AgentSessionID', 'ProviderID', 'Provider', 'Direction', 'JoinMethod', 'TurnMode', 'Address', 'Status', 'ScheduledStartTime', 'ConnectedAt', 'DisconnectedAt', 'CloseReason', 'HostInstanceID', '__mj_CreatedAt'];\nconst PARTICIPANT_FIELDS = ['ID', 'SessionBridgeID', 'DisplayName', 'Role', 'UserID', 'User', 'IsAgent', 'JoinedAt', 'LeftAt'];\nconst SESSION_LITE_FIELDS = ['ID', 'Agent', 'User', 'Status', '__mj_CreatedAt'];\n\n/** Bridge statuses that mean \"still on the call/meeting\". */\nconst LIVE_BRIDGE_STATUSES = new Set(['Pending', 'Scheduled', 'Connecting', 'Connected', 'Disconnecting']);\n\n/** Supported time-range keys → milliseconds (history window; live is never filtered out). */\nconst TIME_RANGE_MS: Record<string, number> = {\n '24h': 86_400_000,\n '7d': 604_800_000,\n '30d': 2_592_000_000\n};\n\n/** History-window range → milliseconds (local to this module). */\nfunction timeRangeToMs(range: string): number {\n return TIME_RANGE_MS[range] ?? TIME_RANGE_MS['7d'];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Loading + aggregation\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Loads the full management surface in one batched `RunViews` call, then folds\n * everything into per-surface view models. History is windowed by `timeRange`;\n * live bridges are always included regardless of age.\n */\nexport async function LoadRealtimeManagementDataset(\n provider: IMetadataProvider,\n timeRange: string\n): Promise<RealtimeManagementDataset> {\n const windowMs = timeRangeToMs(timeRange);\n const now = Date.now();\n const windowStart = new Date(now - windowMs);\n\n const rv = RunView.FromMetadataProvider(provider);\n const [\n providerResult, identityResult, channelResult, providerChannelResult,\n coAgentResult, bridgeResult, participantResult, sessionResult\n ] = await rv.RunViews([\n { EntityName: 'MJ: AI Bridge Providers', Fields: PROVIDER_FIELDS, OrderBy: 'Name', ResultType: 'simple' },\n { EntityName: 'MJ: AI Bridge Agent Identities', Fields: IDENTITY_FIELDS, OrderBy: 'Provider, IdentityValue', ResultType: 'simple' },\n { EntityName: 'MJ: AI Agent Channels', Fields: CHANNEL_FIELDS, OrderBy: 'Name', ResultType: 'simple' },\n { EntityName: 'MJ: AI Bridge Provider Channels', Fields: PROVIDER_CHANNEL_FIELDS, OrderBy: 'Provider, Sequence', ResultType: 'simple' },\n { EntityName: 'MJ: AI Agent Co Agents', Fields: COAGENT_FIELDS, OrderBy: 'CoAgent, Sequence', ResultType: 'simple' },\n {\n EntityName: 'MJ: AI Agent Session Bridges',\n ExtraFilter: `__mj_CreatedAt >= '${windowStart.toISOString()}' OR Status IN ('Pending','Scheduled','Connecting','Connected','Disconnecting')`,\n Fields: BRIDGE_FIELDS,\n OrderBy: '__mj_CreatedAt DESC',\n ResultType: 'simple'\n },\n { EntityName: 'MJ: AI Agent Session Bridge Participants', Fields: PARTICIPANT_FIELDS, ResultType: 'simple' },\n {\n EntityName: 'MJ: AI Agent Sessions',\n ExtraFilter: `__mj_CreatedAt >= '${windowStart.toISOString()}' OR Status IN ('Active','Idle')`,\n Fields: SESSION_LITE_FIELDS,\n ResultType: 'simple'\n }\n ]);\n\n const providers = (providerResult?.Success ? providerResult.Results : []) as BridgeProviderRecord[];\n const identities = (identityResult?.Success ? identityResult.Results : []) as BridgeAgentIdentityRecord[];\n const channels = (channelResult?.Success ? channelResult.Results : []) as AgentChannelRecord[];\n const providerChannels = (providerChannelResult?.Success ? providerChannelResult.Results : []) as BridgeProviderChannelRecord[];\n const coAgents = (coAgentResult?.Success ? coAgentResult.Results : []) as AgentCoAgentRecord[];\n const bridges = (bridgeResult?.Success ? bridgeResult.Results : []) as SessionBridgeRecord[];\n const participants = (participantResult?.Success ? participantResult.Results : []) as SessionBridgeParticipantRecord[];\n const sessions = (sessionResult?.Success ? sessionResult.Results : []) as SessionLiteRecord[];\n\n const providerChannelMap = groupBy(providerChannels, pc => pc.ProviderID);\n const providerRollups = providers.map(p => buildProviderRollup(p, providerChannelMap));\n\n const sessionMap = new Map(sessions.map(s => [NormalizeUUID(s.ID), s]));\n const participantCountMap = countBy(participants, p => p.SessionBridgeID);\n const bridgeRollups = bridges.map(b => buildBridgeRollup(b, sessionMap, participantCountMap, now));\n\n const liveBridges = bridgeRollups.filter(b => b.IsLive);\n const historyBridges = bridgeRollups.filter(b => !b.IsLive);\n\n return {\n Providers: providerRollups,\n Identities: identities,\n Channels: channels,\n ProviderChannels: providerChannels,\n CoAgents: coAgents,\n LiveBridges: liveBridges,\n HistoryBridges: historyBridges,\n AllBridges: bridgeRollups,\n WindowStart: windowStart,\n WindowMs: windowMs\n };\n}\n\nfunction buildProviderRollup(\n record: BridgeProviderRecord,\n providerChannelMap: Map<string, BridgeProviderChannelRecord[]>\n): BridgeProviderRollup {\n const features = parseFeatures(record.SupportedFeatures);\n const channels = (providerChannelMap.get(NormalizeUUID(record.ID)) ?? [])\n .slice()\n .sort((a, b) => a.Sequence - b.Sequence);\n return {\n Record: record,\n Features: features,\n FeatureCount: features ? countTrueFlags(features) : 0,\n Channels: channels\n };\n}\n\nfunction buildBridgeRollup(\n record: SessionBridgeRecord,\n sessionMap: Map<string, SessionLiteRecord>,\n participantCountMap: Map<string, number>,\n now: number\n): SessionBridgeRollup {\n const session = sessionMap.get(NormalizeUUID(record.AgentSessionID)) ?? null;\n const startedAt = new Date(record.__mj_CreatedAt);\n const isLive = LIVE_BRIDGE_STATUSES.has(record.Status);\n let durationMs = 0;\n if (record.ConnectedAt) {\n const end = record.DisconnectedAt ? new Date(record.DisconnectedAt).getTime() : now;\n durationMs = Math.max(0, end - new Date(record.ConnectedAt).getTime());\n }\n return {\n Record: record,\n Session: session,\n AgentName: session?.Agent ?? 'Unknown agent',\n UserName: session?.User ?? '—',\n ParticipantCount: participantCountMap.get(NormalizeUUID(record.ID)) ?? 0,\n StartedAt: startedAt,\n DurationMs: durationMs,\n IsLive: isLive\n };\n}\n\n/** Parses the `SupportedFeatures` JSON string into the typed interface. */\nfunction parseFeatures(raw: string | null): MJAIBridgeProviderEntity_IBridgeProviderFeatures | null {\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as MJAIBridgeProviderEntity_IBridgeProviderFeatures;\n return parsed && typeof parsed === 'object' ? parsed : null;\n } catch {\n return null;\n }\n}\n\n/** Counts `true` boolean flags on a features object. */\nfunction countTrueFlags(features: MJAIBridgeProviderEntity_IBridgeProviderFeatures): number {\n return Object.values(features).filter(v => v === true).length;\n}\n\nfunction groupBy<T>(rows: T[], keyOf: (row: T) => string): Map<string, T[]> {\n const map = new Map<string, T[]>();\n for (const row of rows) {\n const key = NormalizeUUID(keyOf(row));\n const list = map.get(key);\n if (list) list.push(row);\n else map.set(key, [row]);\n }\n return map;\n}\n\nfunction countBy<T>(rows: T[], keyOf: (row: T) => string): Map<string, number> {\n const map = new Map<string, number>();\n for (const row of rows) {\n const key = NormalizeUUID(keyOf(row));\n map.set(key, (map.get(key) ?? 0) + 1);\n }\n return map;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Pure metrics aggregation (unit-tested in realtime-management-data.spec.ts)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** One day bucket for the sessions-over-time metric. */\nexport interface SessionBridgeDayBucket {\n /** Local-midnight Date for the bucket. */\n Date: Date;\n /** YYYY-MM-DD label. */\n Label: string;\n Count: number;\n}\n\n/** One labeled aggregate slice (provider, status, etc.) with a count. */\nexport interface MetricSlice {\n Label: string;\n Count: number;\n}\n\n/**\n * Buckets session bridges by their local calendar day across `[windowStart, now]`,\n * emitting one bucket **per day in the window** (including zero-count days) so the\n * resulting series is dense and renderable as bars without gaps.\n *\n * Pure + deterministic given its inputs — `now` is injected for testability.\n *\n * @param bridges the bridge rollups to bucket (uses each `StartedAt`)\n * @param windowStart inclusive start of the window\n * @param now the window end (exclusive upper edge is `now`'s day + 1)\n * @returns one bucket per day, oldest → newest\n */\nexport function BucketSessionBridgesByDay(\n bridges: SessionBridgeRollup[],\n windowStart: Date,\n now: Date\n): SessionBridgeDayBucket[] {\n const startDay = startOfDay(windowStart);\n const endDay = startOfDay(now);\n if (endDay.getTime() < startDay.getTime()) return [];\n\n // Seed every day in [startDay, endDay] with a zero count.\n const buckets = new Map<string, SessionBridgeDayBucket>();\n for (let d = new Date(startDay); d.getTime() <= endDay.getTime(); d = addDays(d, 1)) {\n const label = toDayLabel(d);\n buckets.set(label, { Date: new Date(d), Label: label, Count: 0 });\n }\n\n for (const bridge of bridges) {\n const day = startOfDay(bridge.StartedAt);\n if (day.getTime() < startDay.getTime() || day.getTime() > endDay.getTime()) continue;\n const bucket = buckets.get(toDayLabel(day));\n if (bucket) bucket.Count++;\n }\n\n return Array.from(buckets.values()).sort((a, b) => a.Date.getTime() - b.Date.getTime());\n}\n\n/** Aggregates bridge rollups into count-by-provider slices, descending by count. */\nexport function SummarizeBridgesByProvider(bridges: SessionBridgeRollup[]): MetricSlice[] {\n return summarizeBy(bridges, b => b.Record.Provider || 'Unknown');\n}\n\n/** Aggregates bridge rollups into count-by-status slices, descending by count. */\nexport function SummarizeBridgesByStatus(bridges: SessionBridgeRollup[]): MetricSlice[] {\n return summarizeBy(bridges, b => b.Record.Status);\n}\n\n/** Aggregates bridge rollups into count-by-agent slices, descending by count. */\nexport function SummarizeBridgesByAgent(bridges: SessionBridgeRollup[]): MetricSlice[] {\n return summarizeBy(bridges, b => b.AgentName || 'Unknown agent');\n}\n\nfunction summarizeBy(bridges: SessionBridgeRollup[], labelOf: (b: SessionBridgeRollup) => string): MetricSlice[] {\n const counts = new Map<string, number>();\n for (const bridge of bridges) {\n const label = labelOf(bridge);\n counts.set(label, (counts.get(label) ?? 0) + 1);\n }\n return Array.from(counts.entries())\n .map(([Label, Count]) => ({ Label, Count }))\n .sort((a, b) => b.Count - a.Count || a.Label.localeCompare(b.Label));\n}\n\nfunction startOfDay(date: Date): Date {\n return new Date(date.getFullYear(), date.getMonth(), date.getDate());\n}\n\nfunction addDays(date: Date, days: number): Date {\n const next = new Date(date);\n next.setDate(next.getDate() + days);\n return next;\n}\n\nfunction toDayLabel(date: Date): string {\n const y = date.getFullYear();\n const m = (date.getMonth() + 1).toString().padStart(2, '0');\n const d = date.getDate().toString().padStart(2, '0');\n return `${y}-${m}-${d}`;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Formatting helpers (shared by the section's sub-tabs)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Font Awesome icon for a bridge type. */\nexport function BridgeTypeIcon(type: BridgeProviderRecord['BridgeType']): string {\n return type === 'Telephony' ? 'fa-solid fa-phone' : 'fa-solid fa-video';\n}\n\n/** Font Awesome icon for an identity type. */\nexport function IdentityTypeIcon(type: BridgeAgentIdentityRecord['IdentityType']): string {\n switch (type) {\n case 'Email': return 'fa-solid fa-envelope';\n case 'PhoneNumber': return 'fa-solid fa-phone';\n default: return 'fa-solid fa-id-badge';\n }\n}\n\n/** Font Awesome icon for a channel transport type. */\nexport function TransportTypeIcon(type: AgentChannelRecord['TransportType']): string {\n switch (type) {\n case 'WebRTC': return 'fa-solid fa-tower-broadcast';\n case 'WebSocket': return 'fa-solid fa-plug';\n default: return 'fa-solid fa-satellite-dish';\n }\n}\n\n/**\n * A compact, human-readable summary of a provider's top capabilities — a few\n * key icons + label pairs derived from the parsed features, capped for density.\n */\nexport interface CapabilityChip {\n Icon: string;\n Label: string;\n}\n\n/**\n * Builds the prioritized capability chips for a provider's feature set. Returns\n * the highest-signal capabilities first (media, then join methods, then\n * signals), so the grid can render a few and show \"+N\" for the remainder.\n */\nexport function BuildCapabilityChips(\n features: MJAIBridgeProviderEntity_IBridgeProviderFeatures | null\n): CapabilityChip[] {\n if (!features) return [];\n const chips: CapabilityChip[] = [];\n const add = (flag: boolean | undefined, icon: string, label: string) => {\n if (flag) chips.push({ Icon: icon, Label: label });\n };\n add(features.AudioIn || features.AudioOut, 'fa-solid fa-microphone-lines', 'Audio');\n add(features.VideoIn || features.VideoOut, 'fa-solid fa-video', 'Video');\n add(features.ScreenIn || features.ScreenOut, 'fa-solid fa-display', 'Screen');\n add(features.SpeakerDiarization, 'fa-solid fa-user-group', 'Diarization');\n add(features.InviteJoin, 'fa-solid fa-calendar-check', 'Invite/Calendar');\n add(features.OnDemandJoin, 'fa-solid fa-bolt', 'On-demand');\n add(features.ScheduledJoin, 'fa-solid fa-clock', 'Scheduled');\n add(features.InboundRouting, 'fa-solid fa-arrow-right-to-bracket', 'Inbound');\n add(features.OutboundDial, 'fa-solid fa-phone-volume', 'Outbound dial');\n add(features.DTMF, 'fa-solid fa-hashtag', 'DTMF');\n add(features.CallTransfer, 'fa-solid fa-arrow-right-arrow-left', 'Transfer');\n add(features.Recording, 'fa-solid fa-circle-dot', 'Recording');\n return chips;\n}\n\n/** Formats a duration as m:ss (or h:mm:ss past the hour). */\nexport function FormatBridgeDuration(ms: number): string {\n if (ms <= 0) return '—';\n const totalSeconds = Math.floor(ms / 1000);\n const seconds = totalSeconds % 60;\n const minutes = Math.floor(totalSeconds / 60) % 60;\n const hours = Math.floor(totalSeconds / 3600);\n const pad = (n: number) => n.toString().padStart(2, '0');\n return hours > 0 ? `${hours}:${pad(minutes)}:${pad(seconds)}` : `${minutes}:${pad(seconds)}`;\n}\n\n/** Today → \"3:40 pm\", yesterday → \"Yesterday\", else \"M/d\". */\nexport function FormatBridgeStart(date: Date): string {\n const now = new Date();\n const startToday = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const startYesterday = new Date(startToday.getTime() - 86_400_000);\n if (date >= startToday) return date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }).toLowerCase();\n if (date >= startYesterday) return 'Yesterday';\n return date.toLocaleDateString([], { month: 'numeric', day: 'numeric' });\n}\n"]}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * @fileoverview Realtime management section — the whole realtime + bridge
3
+ * surface (§11b of the Realtime Bridges architecture) in one place.
4
+ *
5
+ * Hosts an internal sub-tab rail across seven surfaces:
6
+ * 1. Live Sessions — active session bridges (Connecting/Connected) joined
7
+ * with their session: agent, provider, turn mode,
8
+ * participant count, started-at.
9
+ * 2. Bridge Providers — the platform registry with a compact capability
10
+ * summary derived from `SupportedFeaturesObject`.
11
+ * 3. Agent Identities — which agents are reachable where (mailboxes, numbers).
12
+ * 4. Channels — the `MJ: AI Agent Channels` registry + which providers
13
+ * contribute them.
14
+ * 5. Co-Agents — the `MJ: AI Agent Co Agents` pairing registry.
15
+ * 6. Session History — closed/terminal session bridges with close reason.
16
+ * 7. Metrics — client-side aggregates (by provider / status / agent;
17
+ * bridges-over-time bucketed per day).
18
+ *
19
+ * Read-only for v1. Data loads once per `TimeRange` change via one batched
20
+ * `RunViews` in {@link LoadRealtimeManagementDataset}; everything else is
21
+ * in-memory aggregation. The selected sub-tab persists via `UserInfoEngine`
22
+ * under `mj.realtimeDashboard.subTab`.
23
+ */
24
+ import { OnInit } from '@angular/core';
25
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
26
+ import { BridgeProviderRollup, SessionBridgeRollup, BridgeAgentIdentityRecord, AgentChannelRecord, BridgeProviderChannelRecord, AgentCoAgentRecord, SessionBridgeDayBucket, MetricSlice, CapabilityChip, BridgeTypeIcon, IdentityTypeIcon, TransportTypeIcon, FormatBridgeDuration, FormatBridgeStart } from './realtime-management-data';
27
+ import * as i0 from "@angular/core";
28
+ /** The seven management sub-tabs. */
29
+ type RealtimeSubTab = 'live-sessions' | 'providers' | 'identities' | 'channels' | 'co-agents' | 'history' | 'metrics';
30
+ interface SubTabDef {
31
+ Key: RealtimeSubTab;
32
+ Label: string;
33
+ Icon: string;
34
+ }
35
+ export declare class RealtimeManagementComponent extends BaseAngularComponent implements OnInit {
36
+ private _timeRange;
37
+ set TimeRange(value: string);
38
+ get TimeRange(): string;
39
+ private initialized;
40
+ private cdr;
41
+ private dataset;
42
+ IsLoading: boolean;
43
+ ActiveSubTab: RealtimeSubTab;
44
+ readonly SubTabs: SubTabDef[];
45
+ LiveBridges: SessionBridgeRollup[];
46
+ HistoryBridges: SessionBridgeRollup[];
47
+ Providers: BridgeProviderRollup[];
48
+ Identities: BridgeAgentIdentityRecord[];
49
+ Channels: AgentChannelRecord[];
50
+ ProviderChannels: BridgeProviderChannelRecord[];
51
+ CoAgents: AgentCoAgentRecord[];
52
+ DayBuckets: SessionBridgeDayBucket[];
53
+ ByProvider: MetricSlice[];
54
+ ByStatus: MetricSlice[];
55
+ ByAgent: MetricSlice[];
56
+ private capabilityChips;
57
+ ngOnInit(): Promise<void>;
58
+ SelectSubTab(key: RealtimeSubTab): void;
59
+ /** Reloads the whole management surface for the current time range. */
60
+ LoadData(): Promise<void>;
61
+ private applyDataset;
62
+ /** Opens the AIAgentSession record behind a bridge via the shared record-open path. */
63
+ OpenSession(sessionId: string): void;
64
+ /** Opens a bridge provider record. */
65
+ OpenProvider(providerId: string): void;
66
+ /** First N capability chips for a provider (kept compact in the grid). */
67
+ CapabilityChipsFor(providerId: string, limit?: number): CapabilityChip[];
68
+ /** Count of capability chips beyond the displayed `limit` (for a "+N" pill). */
69
+ CapabilityOverflowFor(providerId: string, limit?: number): number;
70
+ /** Providers contributing a given channel (for the Channels grid). */
71
+ ProvidersForChannel(channelId: string): BridgeProviderChannelRecord[];
72
+ /** Human-readable pairing target — a specific agent or a whole agent type. */
73
+ CoAgentTargetLabel(row: AgentCoAgentRecord): string;
74
+ /** Max count across day buckets (for bar height scaling); min 1 to avoid /0. */
75
+ get MaxDayCount(): number;
76
+ /** Bar height percentage for a day bucket. */
77
+ DayBarHeight(count: number): number;
78
+ /** Max slice count (for horizontal bar scaling); min 1. */
79
+ maxSlice(slices: MetricSlice[]): number;
80
+ /** Bar width percentage for a metric slice. */
81
+ SliceBarWidth(slices: MetricSlice[], count: number): number;
82
+ get LiveCount(): number;
83
+ get HistoryCount(): number;
84
+ get ActiveProviderCount(): number;
85
+ get ActiveIdentityCount(): number;
86
+ get ActiveCoAgentCount(): number;
87
+ BridgeTypeIcon: typeof BridgeTypeIcon;
88
+ IdentityTypeIcon: typeof IdentityTypeIcon;
89
+ TransportTypeIcon: typeof TransportTypeIcon;
90
+ FormatBridgeDuration: typeof FormatBridgeDuration;
91
+ FormatBridgeStart: typeof FormatBridgeStart;
92
+ /** CSS class for a bridge status pill. */
93
+ BridgeStatusClass(status: string): string;
94
+ /** CSS class for a session-bridge close-reason pill. */
95
+ CloseReasonClass(reason: string | null): string;
96
+ private loadPrefs;
97
+ private savePrefs;
98
+ static ɵfac: i0.ɵɵFactoryDeclaration<RealtimeManagementComponent, never>;
99
+ static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeManagementComponent, "app-realtime-management", never, { "TimeRange": { "alias": "TimeRange"; "required": false; }; }, {}, never, never, false, never>;
100
+ }
101
+ export declare function LoadRealtimeManagement(): void;
102
+ export {};
103
+ //# sourceMappingURL=realtime-management.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-management.component.d.ts","sourceRoot":"","sources":["../../../../../src/AI/components/analytics/realtime/realtime-management.component.ts"],"names":[],"mappings":"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"}