@edvak99/voice-receptionist-widget 1.1.24 → 1.1.26
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/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-BlOth9CN.mjs +533 -0
- package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-BlOth9CN.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-analytics-page.component-CgvFQGH2.mjs → edvak99-voice-receptionist-widget-analytics-page.component-Cr02cCqy.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-analytics-page.component-CgvFQGH2.mjs.map → edvak99-voice-receptionist-widget-analytics-page.component-Cr02cCqy.mjs.map} +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-IKR5CpVe.mjs +96 -0
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-IKR5CpVe.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-call-history-detail-page.component-B5fFK6Qy.mjs → edvak99-voice-receptionist-widget-call-history-detail-page.component-pRSrt5C2.mjs} +22 -32
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-pRSrt5C2.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-CtdkYCXC.mjs +254 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-CtdkYCXC.mjs.map +1 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-recording-player.component-D9hxkypQ.mjs +110 -0
- package/fesm2022/edvak99-voice-receptionist-widget-call-recording-player.component-D9hxkypQ.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-DheHXZ3u.mjs → edvak99-voice-receptionist-widget-call-review.service-DhLqgadd.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-call-review.service-DheHXZ3u.mjs.map → edvak99-voice-receptionist-widget-call-review.service-DhLqgadd.mjs.map} +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-CoqHpfH4.mjs +311 -0
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-CoqHpfH4.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-DKMxM5TC.mjs → edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-CabSa0_n.mjs} +177 -105
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-CabSa0_n.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-page.component-B4qH9J7y.mjs → edvak99-voice-receptionist-widget-live-calls-page.component-BLJTOY-p.mjs} +4 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-live-calls-page.component-B4qH9J7y.mjs.map → edvak99-voice-receptionist-widget-live-calls-page.component-BLJTOY-p.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-live-monitor-page.component-D-Y1NJfR.mjs → edvak99-voice-receptionist-widget-live-monitor-page.component-MS9bpOBv.mjs} +3 -3
- package/fesm2022/{edvak99-voice-receptionist-widget-live-monitor-page.component-D-Y1NJfR.mjs.map → edvak99-voice-receptionist-widget-live-monitor-page.component-MS9bpOBv.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-outbound-purposes-page.component-Dc9PJDhp.mjs → edvak99-voice-receptionist-widget-outbound-purposes-page.component-Wxq3Aqip.mjs} +4 -4
- package/fesm2022/{edvak99-voice-receptionist-widget-outbound-purposes-page.component-Dc9PJDhp.mjs.map → edvak99-voice-receptionist-widget-outbound-purposes-page.component-Wxq3Aqip.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-task-detail-drawer.component-D3xwM7DS.mjs → edvak99-voice-receptionist-widget-task-detail-drawer.component-CAsLgIJB.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-task-detail-drawer.component-D3xwM7DS.mjs.map → edvak99-voice-receptionist-widget-task-detail-drawer.component-CAsLgIJB.mjs.map} +1 -1
- package/fesm2022/{edvak99-voice-receptionist-widget-tasks-page.component-Clfvj0eo.mjs → edvak99-voice-receptionist-widget-tasks-page.component-9X8YjNaO.mjs} +5 -5
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-9X8YjNaO.mjs.map +1 -0
- package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-BKEN5NGh.mjs → edvak99-voice-receptionist-widget-wizard-page.component-CktmVrGt.mjs} +2 -2
- package/fesm2022/{edvak99-voice-receptionist-widget-wizard-page.component-BKEN5NGh.mjs.map → edvak99-voice-receptionist-widget-wizard-page.component-CktmVrGt.mjs.map} +1 -1
- package/fesm2022/edvak99-voice-receptionist-widget.mjs +1 -1
- package/lib/components/agent-settings-drawer/agent-settings-drawer.component.d.ts +0 -1
- package/lib/components/call-tasks-panel/call-tasks-panel.component.d.ts +3 -4
- package/lib/layout/eds-module-nav.component.d.ts +7 -2
- package/lib/models/ai-receptionist.types.d.ts +4 -4
- package/lib/pages/activities-page/activities-page.component.d.ts +0 -1
- package/lib/pages/audit-page/audit-page.component.d.ts +2 -0
- package/lib/pages/call-history-detail-page/call-history-detail-page.component.d.ts +4 -0
- package/lib/pages/settings-page/settings-page.component.d.ts +11 -12
- package/lib/services/ai-receptionist-api.mappers.d.ts +1 -0
- package/lib/services/ai-receptionist-api.mock.d.ts +1 -1
- package/lib/services/ai-receptionist-api.service.d.ts +3 -2
- package/package.json +1 -1
- package/src/assets/css/_tables.scss +0 -12
- package/src/assets/icons/Headset.svg +5 -0
- package/src/assets/icons/ai_headset.svg +5 -0
- package/styles/embed.scss +0 -96
- package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-8iyWFmmj.mjs +0 -539
- package/fesm2022/edvak99-voice-receptionist-widget-activities-page.component-8iyWFmmj.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-Bhb-n_aA.mjs +0 -89
- package/fesm2022/edvak99-voice-receptionist-widget-audit-page.component-Bhb-n_aA.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-detail-page.component-B5fFK6Qy.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-pZpvcGXo.mjs +0 -254
- package/fesm2022/edvak99-voice-receptionist-widget-call-history-page.component-pZpvcGXo.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-call-recording-player.component-DvPYib0Q.mjs +0 -110
- package/fesm2022/edvak99-voice-receptionist-widget-call-recording-player.component-DvPYib0Q.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-DYr-Wfn9.mjs +0 -311
- package/fesm2022/edvak99-voice-receptionist-widget-dashboard-page.component-DYr-Wfn9.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-DKMxM5TC.mjs.map +0 -1
- package/fesm2022/edvak99-voice-receptionist-widget-tasks-page.component-Clfvj0eo.mjs.map +0 -1
- package/src/assets/icons/ai_headset_badge.svg +0 -25
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, signal, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { DatePipe } from '@angular/common';
|
|
4
|
+
import { FormsModule } from '@angular/forms';
|
|
5
|
+
import { A as AiReceptionistApiService, n as DEFAULT_PAGE_SIZE, o as totalPages, I as IconComponent, g as EdSkeletonComponent, f as EdButtonComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-CabSa0_n.mjs';
|
|
6
|
+
import { S as SmartTooltipDirective } from './edvak99-voice-receptionist-widget-smart-tooltip.directive-ChEdIem3.mjs';
|
|
7
|
+
import { T as TABLE_SKELETON_ROWS } from './edvak99-voice-receptionist-widget-table-skeleton.constants-C1Dg9Z_2.mjs';
|
|
8
|
+
import { E as EdsSearchFieldComponent } from './edvak99-voice-receptionist-widget-eds-search-field.component-BDGCmkoP.mjs';
|
|
9
|
+
|
|
10
|
+
class AuditPageComponent {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.api = inject(AiReceptionistApiService);
|
|
13
|
+
this.pageSize = DEFAULT_PAGE_SIZE;
|
|
14
|
+
this.events = signal([]);
|
|
15
|
+
this.total = signal(0);
|
|
16
|
+
this.page = signal(1);
|
|
17
|
+
this.search = signal('');
|
|
18
|
+
this.actor = signal('');
|
|
19
|
+
this.loading = signal(true);
|
|
20
|
+
this.skeletonRows = TABLE_SKELETON_ROWS;
|
|
21
|
+
}
|
|
22
|
+
ngOnInit() {
|
|
23
|
+
this.load();
|
|
24
|
+
}
|
|
25
|
+
load() {
|
|
26
|
+
this.loading.set(true);
|
|
27
|
+
this.api
|
|
28
|
+
.getAudit(this.search() || undefined, {
|
|
29
|
+
page: this.page(),
|
|
30
|
+
limit: DEFAULT_PAGE_SIZE,
|
|
31
|
+
actor: this.actor() || undefined,
|
|
32
|
+
})
|
|
33
|
+
.subscribe({
|
|
34
|
+
next: ({ items, total, page }) => {
|
|
35
|
+
this.events.set(items);
|
|
36
|
+
this.total.set(total);
|
|
37
|
+
this.page.set(page);
|
|
38
|
+
this.loading.set(false);
|
|
39
|
+
},
|
|
40
|
+
error: () => this.loading.set(false),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
onSearchInput(value) {
|
|
44
|
+
this.search.set(value);
|
|
45
|
+
if (!value.trim())
|
|
46
|
+
this.searchSubmit();
|
|
47
|
+
}
|
|
48
|
+
onActorInput(value) {
|
|
49
|
+
this.actor.set(value);
|
|
50
|
+
if (!value.trim())
|
|
51
|
+
this.searchSubmit();
|
|
52
|
+
}
|
|
53
|
+
displayTarget(raw) {
|
|
54
|
+
const t = String(raw ?? '').trim();
|
|
55
|
+
if (!t || /^https?:\/\//i.test(t) || /^[0-9a-f]{8}-[0-9a-f]{4}-/i.test(t)) {
|
|
56
|
+
return '—';
|
|
57
|
+
}
|
|
58
|
+
return t;
|
|
59
|
+
}
|
|
60
|
+
searchSubmit() {
|
|
61
|
+
this.page.set(1);
|
|
62
|
+
this.load();
|
|
63
|
+
}
|
|
64
|
+
totalPages() {
|
|
65
|
+
return totalPages(this.total(), DEFAULT_PAGE_SIZE);
|
|
66
|
+
}
|
|
67
|
+
prevPage() {
|
|
68
|
+
if (this.page() <= 1)
|
|
69
|
+
return;
|
|
70
|
+
this.page.update((p) => p - 1);
|
|
71
|
+
this.load();
|
|
72
|
+
}
|
|
73
|
+
nextPage() {
|
|
74
|
+
if (this.page() >= this.totalPages())
|
|
75
|
+
return;
|
|
76
|
+
this.page.update((p) => p + 1);
|
|
77
|
+
this.load();
|
|
78
|
+
}
|
|
79
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AuditPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
80
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: AuditPageComponent, isStandalone: true, selector: "eds-audit-page", host: { classAttribute: "block h-full min-h-0" }, ngImport: i0, template: "<div class=\"flex h-full min-h-0 flex-col overflow-hidden bg-lighter p-base audit-page\">\n <header class=\"relative z-10 mb-base shrink-0 bg-lighter\">\n <div>\n <h4>Audit log</h4>\n <p class=\"fs-sm text-light\">Track configuration and agent activity</p>\n </div>\n </header>\n\n <div class=\"mb-base flex shrink-0 flex-wrap items-center gap-sm rounded-md bg-white p-base\">\n <eds-search-field\n inputClass=\"form-input min-w-[180px]\"\n placeholder=\"Search action, target, detail\u2026\"\n [value]=\"search()\"\n (valueChange)=\"onSearchInput($event)\"\n (enter)=\"searchSubmit()\"\n />\n <eds-search-field\n type=\"text\"\n inputClass=\"form-input min-w-[180px]\"\n placeholder=\"Filter by actor\"\n [value]=\"actor()\"\n (valueChange)=\"onActorInput($event)\"\n (enter)=\"searchSubmit()\"\n />\n <ed-button variant=\"primary\" fill size=\"sm\" (click$)=\"searchSubmit()\">\n <ed-icon slot=\"prefix\" name=\"search\" [size]=\"16\" />\n Search\n </ed-button>\n </div>\n\n <div class=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-md bg-white p-base\">\n <div class=\"eds-table-scroll min-h-0 min-w-0 flex-1\">\n <table class=\"table-default eds-sticky-table w-full\" aria-label=\"Audit log\">\n <thead>\n <tr>\n <th>Date</th>\n <th>Actor</th>\n <th>Action</th>\n <th>Target</th>\n <th>Detail</th>\n </tr>\n </thead>\n @if (loading()) {\n <tbody aria-busy=\"true\">\n @for (_ of skeletonRows; track _) {\n <tr>\n <td><ed-skeleton class=\"h-3 w-32\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-24\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-36\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-28\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-48\"></ed-skeleton></td>\n </tr>\n }\n </tbody>\n } @else {\n <tbody>\n @for (event of events(); track event.id) {\n <tr>\n <td class=\"font-['IBM_Plex_Mono'] fs-sm text-light\">{{ event.at | date: 'medium' }}</td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-48 truncate fs-sm text-dark\"\n [smartTooltip]=\"event.actor\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ event.actor }}</span>\n </td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-56 truncate fs-sm font-semibold text-dark\"\n [smartTooltip]=\"event.action\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ event.action }}</span>\n </td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-48 truncate fs-sm text-light\"\n [smartTooltip]=\"displayTarget(event.target)\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ displayTarget(event.target) }}</span>\n </td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-72 truncate\"\n [smartTooltip]=\"event.detail\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ event.detail }}</span>\n </td>\n </tr>\n } @empty {\n <tr class=\"empty-row\">\n <td colspan=\"5\" class=\"py-lg fs-sm text-light\">No events match your filters.</td>\n </tr>\n }\n </tbody>\n }\n </table>\n </div>\n </div>\n\n <footer class=\"mt-base flex shrink-0 items-center justify-between border-t border-light pt-sm\">\n <span class=\"fs-sm text-light\">\n Page {{ page() }} of {{ totalPages() }} \u00B7 {{ total() }} total\n </span>\n <div class=\"flex gap-2\">\n <ed-button variant=\"secondary\" outline size=\"sm\" [disabled]=\"page() <= 1\" (click$)=\"prevPage()\">Previous</ed-button>\n <ed-button variant=\"secondary\" outline size=\"sm\" [disabled]=\"page() >= totalPages()\" (click$)=\"nextPage()\">Next</ed-button>\n </div>\n </footer>\n</div>\n", dependencies: [{ kind: "pipe", type: DatePipe, name: "date" }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: IconComponent, selector: "ed-icon", inputs: ["name", "size", "color", "cssClass", "decorative", "ariaHidden", "ariaLabel", "title", "desc", "focusable", "tabIndex"] }, { kind: "component", type: EdsSearchFieldComponent, selector: "eds-search-field", inputs: ["value", "inputId", "type", "placeholder", "ariaLabel", "inputClass"], outputs: ["valueChange", "enter"] }, { kind: "directive", type: SmartTooltipDirective, selector: "[smartTooltip]", inputs: ["smartTooltip", "tooltipAllowHtml", "tooltipTemplate", "tooltipTemplateContext", "tooltipPlacement", "tooltipTrigger", "tooltipDelayShow", "tooltipDelayHide", "tooltipOffset", "tooltipMaxWidth", "tooltipZIndex", "tooltipClass", "tooltipDisabled", "tooltipArrow", "tooltipHoverIntentMs", "tooltipHoverIntentRadius", "tooltipId", "tooltipRole", "tooltipAnimEnterMs", "tooltipAnimExitMs", "tooltipAnimEasing", "tooltipHoverable", "tooltipHandoffMs", "tooltipOpen", "tooltipOnlyWhenTruncated"] }, { kind: "component", type: EdSkeletonComponent, selector: "ed-skeleton", inputs: ["class"] }, { kind: "component", type: EdButtonComponent, selector: "ed-button", inputs: ["variant", "size", "disabled", "ghost", "outline", "subtle", "fill", "loading", "block", "elevated", "shape", "type", "href", "routerLink", "rel", "target", "download", "ariaLabel"], outputs: ["click$"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
81
|
+
}
|
|
82
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AuditPageComponent, decorators: [{
|
|
83
|
+
type: Component,
|
|
84
|
+
args: [{ selector: 'eds-audit-page', imports: [
|
|
85
|
+
DatePipe,
|
|
86
|
+
FormsModule,
|
|
87
|
+
IconComponent,
|
|
88
|
+
EdsSearchFieldComponent,
|
|
89
|
+
SmartTooltipDirective,
|
|
90
|
+
EdSkeletonComponent,
|
|
91
|
+
EdButtonComponent,
|
|
92
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'block h-full min-h-0' }, template: "<div class=\"flex h-full min-h-0 flex-col overflow-hidden bg-lighter p-base audit-page\">\n <header class=\"relative z-10 mb-base shrink-0 bg-lighter\">\n <div>\n <h4>Audit log</h4>\n <p class=\"fs-sm text-light\">Track configuration and agent activity</p>\n </div>\n </header>\n\n <div class=\"mb-base flex shrink-0 flex-wrap items-center gap-sm rounded-md bg-white p-base\">\n <eds-search-field\n inputClass=\"form-input min-w-[180px]\"\n placeholder=\"Search action, target, detail\u2026\"\n [value]=\"search()\"\n (valueChange)=\"onSearchInput($event)\"\n (enter)=\"searchSubmit()\"\n />\n <eds-search-field\n type=\"text\"\n inputClass=\"form-input min-w-[180px]\"\n placeholder=\"Filter by actor\"\n [value]=\"actor()\"\n (valueChange)=\"onActorInput($event)\"\n (enter)=\"searchSubmit()\"\n />\n <ed-button variant=\"primary\" fill size=\"sm\" (click$)=\"searchSubmit()\">\n <ed-icon slot=\"prefix\" name=\"search\" [size]=\"16\" />\n Search\n </ed-button>\n </div>\n\n <div class=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-md bg-white p-base\">\n <div class=\"eds-table-scroll min-h-0 min-w-0 flex-1\">\n <table class=\"table-default eds-sticky-table w-full\" aria-label=\"Audit log\">\n <thead>\n <tr>\n <th>Date</th>\n <th>Actor</th>\n <th>Action</th>\n <th>Target</th>\n <th>Detail</th>\n </tr>\n </thead>\n @if (loading()) {\n <tbody aria-busy=\"true\">\n @for (_ of skeletonRows; track _) {\n <tr>\n <td><ed-skeleton class=\"h-3 w-32\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-24\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-36\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-28\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-48\"></ed-skeleton></td>\n </tr>\n }\n </tbody>\n } @else {\n <tbody>\n @for (event of events(); track event.id) {\n <tr>\n <td class=\"font-['IBM_Plex_Mono'] fs-sm text-light\">{{ event.at | date: 'medium' }}</td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-48 truncate fs-sm text-dark\"\n [smartTooltip]=\"event.actor\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ event.actor }}</span>\n </td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-56 truncate fs-sm font-semibold text-dark\"\n [smartTooltip]=\"event.action\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ event.action }}</span>\n </td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-48 truncate fs-sm text-light\"\n [smartTooltip]=\"displayTarget(event.target)\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ displayTarget(event.target) }}</span>\n </td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-72 truncate\"\n [smartTooltip]=\"event.detail\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ event.detail }}</span>\n </td>\n </tr>\n } @empty {\n <tr class=\"empty-row\">\n <td colspan=\"5\" class=\"py-lg fs-sm text-light\">No events match your filters.</td>\n </tr>\n }\n </tbody>\n }\n </table>\n </div>\n </div>\n\n <footer class=\"mt-base flex shrink-0 items-center justify-between border-t border-light pt-sm\">\n <span class=\"fs-sm text-light\">\n Page {{ page() }} of {{ totalPages() }} \u00B7 {{ total() }} total\n </span>\n <div class=\"flex gap-2\">\n <ed-button variant=\"secondary\" outline size=\"sm\" [disabled]=\"page() <= 1\" (click$)=\"prevPage()\">Previous</ed-button>\n <ed-button variant=\"secondary\" outline size=\"sm\" [disabled]=\"page() >= totalPages()\" (click$)=\"nextPage()\">Next</ed-button>\n </div>\n </footer>\n</div>\n" }]
|
|
93
|
+
}] });
|
|
94
|
+
|
|
95
|
+
export { AuditPageComponent };
|
|
96
|
+
//# sourceMappingURL=edvak99-voice-receptionist-widget-audit-page.component-IKR5CpVe.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edvak99-voice-receptionist-widget-audit-page.component-IKR5CpVe.mjs","sources":["../../../src/lib/pages/audit-page/audit-page.component.ts","../../../src/lib/pages/audit-page/audit-page.component.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core';\nimport { DatePipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\n\nimport { AuditEvent } from '../../models/ai-receptionist.types';\nimport { DEFAULT_PAGE_SIZE, totalPages as calcTotalPages } from '../../models/pagination';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { EdButtonComponent } from '../../ui/ed-button.component';\nimport { EdSkeletonComponent } from '../../ui/ed-skeleton.component';\n\nimport { SmartTooltipDirective } from '../../shared/smart-tooltip.directive';\nimport { TABLE_SKELETON_ROWS } from '../../shared/table-skeleton.constants';\nimport { IconComponent } from '../../ui/ed-icon.component';\nimport { EdsSearchFieldComponent } from '../../ui/eds-search-field.component';\n\n@Component({\n selector: 'eds-audit-page',\n imports: [\n DatePipe,\n FormsModule,\n IconComponent,\n EdsSearchFieldComponent,\n SmartTooltipDirective,\n EdSkeletonComponent,\n EdButtonComponent,\n ],\n templateUrl: './audit-page.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'block h-full min-h-0' },\n})\nexport class AuditPageComponent implements OnInit {\n private readonly api = inject(AiReceptionistApiService);\n\n protected readonly pageSize = DEFAULT_PAGE_SIZE;\n protected readonly events = signal<AuditEvent[]>([]);\n protected readonly total = signal(0);\n protected readonly page = signal(1);\n protected readonly search = signal('');\n protected readonly actor = signal('');\n protected readonly loading = signal(true);\n protected readonly skeletonRows = TABLE_SKELETON_ROWS;\n\n ngOnInit(): void {\n this.load();\n }\n\n protected load(): void {\n this.loading.set(true);\n this.api\n .getAudit(this.search() || undefined, {\n page: this.page(),\n limit: DEFAULT_PAGE_SIZE,\n actor: this.actor() || undefined,\n })\n .subscribe({\n next: ({ items, total, page }) => {\n this.events.set(items);\n this.total.set(total);\n this.page.set(page);\n this.loading.set(false);\n },\n error: () => this.loading.set(false),\n });\n }\n\n protected onSearchInput(value: string): void {\n this.search.set(value);\n if (!value.trim()) this.searchSubmit();\n }\n\n protected onActorInput(value: string): void {\n this.actor.set(value);\n if (!value.trim()) this.searchSubmit();\n }\n\n protected displayTarget(raw: string | null | undefined): string {\n const t = String(raw ?? '').trim();\n if (!t || /^https?:\\/\\//i.test(t) || /^[0-9a-f]{8}-[0-9a-f]{4}-/i.test(t)) {\n return '—';\n }\n return t;\n }\n\n protected searchSubmit(): void {\n this.page.set(1);\n this.load();\n }\n\n protected totalPages(): number {\n return calcTotalPages(this.total(), DEFAULT_PAGE_SIZE);\n }\n\n protected prevPage(): void {\n if (this.page() <= 1) return;\n this.page.update((p) => p - 1);\n this.load();\n }\n\n protected nextPage(): void {\n if (this.page() >= this.totalPages()) return;\n this.page.update((p) => p + 1);\n this.load();\n }\n}\n","<div class=\"flex h-full min-h-0 flex-col overflow-hidden bg-lighter p-base audit-page\">\n <header class=\"relative z-10 mb-base shrink-0 bg-lighter\">\n <div>\n <h4>Audit log</h4>\n <p class=\"fs-sm text-light\">Track configuration and agent activity</p>\n </div>\n </header>\n\n <div class=\"mb-base flex shrink-0 flex-wrap items-center gap-sm rounded-md bg-white p-base\">\n <eds-search-field\n inputClass=\"form-input min-w-[180px]\"\n placeholder=\"Search action, target, detail…\"\n [value]=\"search()\"\n (valueChange)=\"onSearchInput($event)\"\n (enter)=\"searchSubmit()\"\n />\n <eds-search-field\n type=\"text\"\n inputClass=\"form-input min-w-[180px]\"\n placeholder=\"Filter by actor\"\n [value]=\"actor()\"\n (valueChange)=\"onActorInput($event)\"\n (enter)=\"searchSubmit()\"\n />\n <ed-button variant=\"primary\" fill size=\"sm\" (click$)=\"searchSubmit()\">\n <ed-icon slot=\"prefix\" name=\"search\" [size]=\"16\" />\n Search\n </ed-button>\n </div>\n\n <div class=\"flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden rounded-md bg-white p-base\">\n <div class=\"eds-table-scroll min-h-0 min-w-0 flex-1\">\n <table class=\"table-default eds-sticky-table w-full\" aria-label=\"Audit log\">\n <thead>\n <tr>\n <th>Date</th>\n <th>Actor</th>\n <th>Action</th>\n <th>Target</th>\n <th>Detail</th>\n </tr>\n </thead>\n @if (loading()) {\n <tbody aria-busy=\"true\">\n @for (_ of skeletonRows; track _) {\n <tr>\n <td><ed-skeleton class=\"h-3 w-32\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-24\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-36\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-28\"></ed-skeleton></td>\n <td><ed-skeleton class=\"h-3 w-48\"></ed-skeleton></td>\n </tr>\n }\n </tbody>\n } @else {\n <tbody>\n @for (event of events(); track event.id) {\n <tr>\n <td class=\"font-['IBM_Plex_Mono'] fs-sm text-light\">{{ event.at | date: 'medium' }}</td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-48 truncate fs-sm text-dark\"\n [smartTooltip]=\"event.actor\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ event.actor }}</span>\n </td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-56 truncate fs-sm font-semibold text-dark\"\n [smartTooltip]=\"event.action\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ event.action }}</span>\n </td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-48 truncate fs-sm text-light\"\n [smartTooltip]=\"displayTarget(event.target)\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ displayTarget(event.target) }}</span>\n </td>\n <td>\n <span\n class=\"inline-block min-w-0 max-w-72 truncate\"\n [smartTooltip]=\"event.detail\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ event.detail }}</span>\n </td>\n </tr>\n } @empty {\n <tr class=\"empty-row\">\n <td colspan=\"5\" class=\"py-lg fs-sm text-light\">No events match your filters.</td>\n </tr>\n }\n </tbody>\n }\n </table>\n </div>\n </div>\n\n <footer class=\"mt-base flex shrink-0 items-center justify-between border-t border-light pt-sm\">\n <span class=\"fs-sm text-light\">\n Page {{ page() }} of {{ totalPages() }} · {{ total() }} total\n </span>\n <div class=\"flex gap-2\">\n <ed-button variant=\"secondary\" outline size=\"sm\" [disabled]=\"page() <= 1\" (click$)=\"prevPage()\">Previous</ed-button>\n <ed-button variant=\"secondary\" outline size=\"sm\" [disabled]=\"page() >= totalPages()\" (click$)=\"nextPage()\">Next</ed-button>\n </div>\n </footer>\n</div>\n"],"names":["calcTotalPages"],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, input, output, viewChild, signal, computed, effect, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component
|
|
2
|
+
import { inject, input, output, viewChild, signal, computed, effect, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
4
|
-
import { A as AiReceptionistApiService, T as ToastService, m as toolEventTrackKey, f as EdButtonComponent, I as IconComponent, q as activityTypeLabel, g as EdSkeletonComponent, i as isUnknownCaller } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-
|
|
4
|
+
import { A as AiReceptionistApiService, T as ToastService, m as toolEventTrackKey, f as EdButtonComponent, I as IconComponent, q as activityTypeLabel, g as EdSkeletonComponent, c as callerMetaLine, i as isUnknownCaller, E as EdAvatarComponent, p as EdIconButtonComponent } from './edvak99-voice-receptionist-widget-edvak99-voice-receptionist-widget-CabSa0_n.mjs';
|
|
5
5
|
import { DatePipe } from '@angular/common';
|
|
6
|
-
import { C as CallRecordingPlayerComponent } from './edvak99-voice-receptionist-widget-call-recording-player.component-
|
|
6
|
+
import { C as CallRecordingPlayerComponent } from './edvak99-voice-receptionist-widget-call-recording-player.component-D9hxkypQ.mjs';
|
|
7
7
|
import { S as SmartTooltipDirective } from './edvak99-voice-receptionist-widget-smart-tooltip.directive-ChEdIem3.mjs';
|
|
8
|
-
import { C as CallReviewService } from './edvak99-voice-receptionist-widget-call-review.service-
|
|
8
|
+
import { C as CallReviewService } from './edvak99-voice-receptionist-widget-call-review.service-DhLqgadd.mjs';
|
|
9
9
|
import { i as isNeedsReview } from './edvak99-voice-receptionist-widget-call-review.util-rWIPxDtQ.mjs';
|
|
10
10
|
|
|
11
11
|
/** Parse tool timestamp strings like "1:02" or "0:42" into seconds. */
|
|
@@ -240,7 +240,6 @@ class CallTasksPanelComponent {
|
|
|
240
240
|
this.api = inject(AiReceptionistApiService);
|
|
241
241
|
this.router = inject(Router);
|
|
242
242
|
this.route = inject(ActivatedRoute);
|
|
243
|
-
this.loadSeq = 0;
|
|
244
243
|
this.callId = input.required();
|
|
245
244
|
this.compact = input(false);
|
|
246
245
|
this.activities = signal([]);
|
|
@@ -250,10 +249,6 @@ class CallTasksPanelComponent {
|
|
|
250
249
|
this.previewLimit = PREVIEW_LIMIT;
|
|
251
250
|
this.activityTypeLabel = activityTypeLabel;
|
|
252
251
|
this.previewActivities = computed(() => this.activities().slice(0, PREVIEW_LIMIT));
|
|
253
|
-
effect(() => {
|
|
254
|
-
const id = this.callId().trim();
|
|
255
|
-
untracked(() => this.load(id));
|
|
256
|
-
});
|
|
257
252
|
}
|
|
258
253
|
openActivities() {
|
|
259
254
|
void this.router.navigate(['../activities'], {
|
|
@@ -261,34 +256,20 @@ class CallTasksPanelComponent {
|
|
|
261
256
|
queryParams: { callId: this.callId() },
|
|
262
257
|
});
|
|
263
258
|
}
|
|
264
|
-
|
|
265
|
-
const seq = ++this.loadSeq;
|
|
266
|
-
this.loading.set(true);
|
|
267
|
-
this.activities.set([]);
|
|
268
|
-
this.total.set(0);
|
|
269
|
-
if (!callId) {
|
|
270
|
-
this.loading.set(false);
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
259
|
+
ngOnInit() {
|
|
273
260
|
this.api
|
|
274
261
|
.getActivities({
|
|
275
|
-
callId,
|
|
262
|
+
callId: this.callId(),
|
|
276
263
|
page: 1,
|
|
277
264
|
limit: 50,
|
|
278
265
|
})
|
|
279
266
|
.subscribe({
|
|
280
267
|
next: ({ items, total }) => {
|
|
281
|
-
if (seq !== this.loadSeq)
|
|
282
|
-
return;
|
|
283
268
|
this.activities.set(items);
|
|
284
269
|
this.total.set(total);
|
|
285
270
|
this.loading.set(false);
|
|
286
271
|
},
|
|
287
|
-
error: () =>
|
|
288
|
-
if (seq !== this.loadSeq)
|
|
289
|
-
return;
|
|
290
|
-
this.loading.set(false);
|
|
291
|
-
},
|
|
272
|
+
error: () => this.loading.set(false),
|
|
292
273
|
});
|
|
293
274
|
}
|
|
294
275
|
activitySubline(item) {
|
|
@@ -312,12 +293,12 @@ class CallTasksPanelComponent {
|
|
|
312
293
|
}
|
|
313
294
|
}
|
|
314
295
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CallTasksPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
315
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: CallTasksPanelComponent, isStandalone: true, selector: "eds-call-tasks-panel", inputs: { callId: { classPropertyName: "callId", publicName: "callId", isSignal: true, isRequired: true, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<section class=\"call-tasks rounded-lg border border-base bg-white px-5 py-4 mt-5 shadow-sm\" [class.call-tasks--compact]=\"compact()\">\n <header class=\"mb-4 flex items-center justify-between gap-3\">\n <h4>Activities from this call</h4>\n <button\n type=\"button\"\n class=\"eds-plain-nav call-tasks__all-link fs-sm\"\n (click)=\"openActivities()\"\n >\n View all Activities\n </button>\n </header>\n\n @if (loading()) {\n <ul class=\"call-tasks__list overflow-hidden rounded-lg border border-base\" aria-busy=\"true\">\n @for (_ of listSkeletonRows; track _) {\n <li class=\"call-tasks__item border-b border-base last:border-b-0\">\n <div class=\"call-tasks__row grid w-full grid-cols-[minmax(0,1fr)_auto] items-center gap-3 px-4 py-3\">\n <div class=\"flex min-w-0 flex-col gap-1\">\n <ed-skeleton class=\"h-3 w-40\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-48\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton>\n </div>\n </li>\n }\n </ul>\n } @else
|
|
296
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: CallTasksPanelComponent, isStandalone: true, selector: "eds-call-tasks-panel", inputs: { callId: { classPropertyName: "callId", publicName: "callId", isSignal: true, isRequired: true, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (loading() || activities().length > 0) {\n<section class=\"call-tasks rounded-lg border border-base bg-white px-5 py-4 mt-5 shadow-sm\" [class.call-tasks--compact]=\"compact()\">\n <header class=\"mb-4 flex items-center justify-between gap-3\">\n <h4>Activities from this call</h4>\n <button\n type=\"button\"\n class=\"eds-plain-nav call-tasks__all-link fs-sm\"\n (click)=\"openActivities()\"\n >\n View all Activities\n </button>\n </header>\n\n @if (loading()) {\n <ul class=\"call-tasks__list overflow-hidden rounded-lg border border-base\" aria-busy=\"true\">\n @for (_ of listSkeletonRows; track _) {\n <li class=\"call-tasks__item border-b border-base last:border-b-0\">\n <div class=\"call-tasks__row grid w-full grid-cols-[minmax(0,1fr)_auto] items-center gap-3 px-4 py-3\">\n <div class=\"flex min-w-0 flex-col gap-1\">\n <ed-skeleton class=\"h-3 w-40\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-48\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton>\n </div>\n </li>\n }\n </ul>\n } @else {\n <ul class=\"call-tasks__list overflow-hidden rounded-lg border border-base\">\n @for (item of previewActivities(); track item.id) {\n <li class=\"call-tasks__item border-b border-base last:border-b-0\">\n <div class=\"call-tasks__row grid w-full grid-cols-[minmax(0,1fr)_auto] items-center gap-3 border-none bg-transparent px-4 py-3 text-left font-[inherit]\">\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span\n class=\"call-tasks__title min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap text-sm font-semibold\"\n [smartTooltip]=\"item.title || activityTypeLabel(item.type)\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ item.title || activityTypeLabel(item.type) }}</span>\n <span\n class=\"call-tasks__sub max-w-full overflow-hidden text-ellipsis whitespace-nowrap text-xs\"\n [smartTooltip]=\"activitySubline(item)\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ activitySubline(item) }}</span>\n </div>\n <ed-badge-2 [attr.variant]=\"activityTone(item.type)\">{{ activityTypeLabel(item.type) }}</ed-badge-2>\n </div>\n </li>\n }\n </ul>\n @if (total() > previewLimit) {\n <p class=\"call-tasks__more fs-sm text-light mt-3\">\n +{{ total() - previewLimit }} more \u2014\n <button type=\"button\" class=\"eds-plain-nav call-tasks__all-link\" (click)=\"openActivities()\">\n View all Activities\n </button>\n </p>\n }\n }\n</section>\n}\n", styles: [".call-tasks--compact{margin-top:0;height:100%}.call-tasks__head .eds-h2{margin:0}.call-tasks__all-link{color:var(--eds-text-brand, #2162f0);text-decoration:none;font-weight:500}.call-tasks__all-link:hover{text-decoration:underline}.call-tasks__empty{margin:0;color:var(--eds-text-secondary, #53575c)}.call-tasks__list{list-style:none;margin:0;padding:0}.call-tasks__row--static{cursor:default}.call-tasks__title{color:var(--eds-text-primary, #41464c)}.call-tasks__sub,.call-tasks__more{color:var(--eds-text-secondary, #53575c)}\n"], dependencies: [{ kind: "component", type: EdSkeletonComponent, selector: "ed-skeleton", inputs: ["class"] }, { kind: "directive", type: SmartTooltipDirective, selector: "[smartTooltip]", inputs: ["smartTooltip", "tooltipAllowHtml", "tooltipTemplate", "tooltipTemplateContext", "tooltipPlacement", "tooltipTrigger", "tooltipDelayShow", "tooltipDelayHide", "tooltipOffset", "tooltipMaxWidth", "tooltipZIndex", "tooltipClass", "tooltipDisabled", "tooltipArrow", "tooltipHoverIntentMs", "tooltipHoverIntentRadius", "tooltipId", "tooltipRole", "tooltipAnimEnterMs", "tooltipAnimExitMs", "tooltipAnimEasing", "tooltipHoverable", "tooltipHandoffMs", "tooltipOpen", "tooltipOnlyWhenTruncated"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
316
297
|
}
|
|
317
298
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CallTasksPanelComponent, decorators: [{
|
|
318
299
|
type: Component,
|
|
319
|
-
args: [{ selector: 'eds-call-tasks-panel', imports: [EdSkeletonComponent, SmartTooltipDirective], changeDetection: ChangeDetectionStrategy.OnPush, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "<section class=\"call-tasks rounded-lg border border-base bg-white px-5 py-4 mt-5 shadow-sm\" [class.call-tasks--compact]=\"compact()\">\n <header class=\"mb-4 flex items-center justify-between gap-3\">\n <h4>Activities from this call</h4>\n <button\n type=\"button\"\n class=\"eds-plain-nav call-tasks__all-link fs-sm\"\n (click)=\"openActivities()\"\n >\n View all Activities\n </button>\n </header>\n\n @if (loading()) {\n <ul class=\"call-tasks__list overflow-hidden rounded-lg border border-base\" aria-busy=\"true\">\n @for (_ of listSkeletonRows; track _) {\n <li class=\"call-tasks__item border-b border-base last:border-b-0\">\n <div class=\"call-tasks__row grid w-full grid-cols-[minmax(0,1fr)_auto] items-center gap-3 px-4 py-3\">\n <div class=\"flex min-w-0 flex-col gap-1\">\n <ed-skeleton class=\"h-3 w-40\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-48\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton>\n </div>\n </li>\n }\n </ul>\n } @else
|
|
320
|
-
}]
|
|
300
|
+
args: [{ selector: 'eds-call-tasks-panel', imports: [EdSkeletonComponent, SmartTooltipDirective], changeDetection: ChangeDetectionStrategy.OnPush, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "@if (loading() || activities().length > 0) {\n<section class=\"call-tasks rounded-lg border border-base bg-white px-5 py-4 mt-5 shadow-sm\" [class.call-tasks--compact]=\"compact()\">\n <header class=\"mb-4 flex items-center justify-between gap-3\">\n <h4>Activities from this call</h4>\n <button\n type=\"button\"\n class=\"eds-plain-nav call-tasks__all-link fs-sm\"\n (click)=\"openActivities()\"\n >\n View all Activities\n </button>\n </header>\n\n @if (loading()) {\n <ul class=\"call-tasks__list overflow-hidden rounded-lg border border-base\" aria-busy=\"true\">\n @for (_ of listSkeletonRows; track _) {\n <li class=\"call-tasks__item border-b border-base last:border-b-0\">\n <div class=\"call-tasks__row grid w-full grid-cols-[minmax(0,1fr)_auto] items-center gap-3 px-4 py-3\">\n <div class=\"flex min-w-0 flex-col gap-1\">\n <ed-skeleton class=\"h-3 w-40\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-48\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton>\n </div>\n </li>\n }\n </ul>\n } @else {\n <ul class=\"call-tasks__list overflow-hidden rounded-lg border border-base\">\n @for (item of previewActivities(); track item.id) {\n <li class=\"call-tasks__item border-b border-base last:border-b-0\">\n <div class=\"call-tasks__row grid w-full grid-cols-[minmax(0,1fr)_auto] items-center gap-3 border-none bg-transparent px-4 py-3 text-left font-[inherit]\">\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span\n class=\"call-tasks__title min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap text-sm font-semibold\"\n [smartTooltip]=\"item.title || activityTypeLabel(item.type)\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ item.title || activityTypeLabel(item.type) }}</span>\n <span\n class=\"call-tasks__sub max-w-full overflow-hidden text-ellipsis whitespace-nowrap text-xs\"\n [smartTooltip]=\"activitySubline(item)\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ activitySubline(item) }}</span>\n </div>\n <ed-badge-2 [attr.variant]=\"activityTone(item.type)\">{{ activityTypeLabel(item.type) }}</ed-badge-2>\n </div>\n </li>\n }\n </ul>\n @if (total() > previewLimit) {\n <p class=\"call-tasks__more fs-sm text-light mt-3\">\n +{{ total() - previewLimit }} more \u2014\n <button type=\"button\" class=\"eds-plain-nav call-tasks__all-link\" (click)=\"openActivities()\">\n View all Activities\n </button>\n </p>\n }\n }\n</section>\n}\n", styles: [".call-tasks--compact{margin-top:0;height:100%}.call-tasks__head .eds-h2{margin:0}.call-tasks__all-link{color:var(--eds-text-brand, #2162f0);text-decoration:none;font-weight:500}.call-tasks__all-link:hover{text-decoration:underline}.call-tasks__empty{margin:0;color:var(--eds-text-secondary, #53575c)}.call-tasks__list{list-style:none;margin:0;padding:0}.call-tasks__row--static{cursor:default}.call-tasks__title{color:var(--eds-text-primary, #41464c)}.call-tasks__sub,.call-tasks__more{color:var(--eds-text-secondary, #53575c)}\n"] }]
|
|
301
|
+
}] });
|
|
321
302
|
|
|
322
303
|
/** Known history outcomes from GET /calls/history (HistoryCallDto.outcome). */
|
|
323
304
|
const HISTORY_OUTCOMES = [
|
|
@@ -386,10 +367,17 @@ class CallHistoryDetailPageComponent {
|
|
|
386
367
|
this.isNeedsReview = isNeedsReview;
|
|
387
368
|
this.outcomeTone = outcomeBadgeTone;
|
|
388
369
|
this.outcomeLabel = formatOutcomeLabel;
|
|
370
|
+
this.callerMetaLine = callerMetaLine;
|
|
389
371
|
}
|
|
390
372
|
isUnknownName(name) {
|
|
391
373
|
return isUnknownCaller(name);
|
|
392
374
|
}
|
|
375
|
+
detailAvatarTone(detail) {
|
|
376
|
+
return this.isUnknownName(detail.name) || detail.initials === '?' ? 'gray' : 'brand';
|
|
377
|
+
}
|
|
378
|
+
detailDirectionIcon(detail) {
|
|
379
|
+
return detail.direction === 'inbound' ? 'call_received' : 'call_made';
|
|
380
|
+
}
|
|
393
381
|
ngOnInit() {
|
|
394
382
|
const id = this.route.snapshot.paramMap.get('id') ?? '';
|
|
395
383
|
this.api.getCallDetail(id).subscribe(({ data }) => {
|
|
@@ -434,18 +422,20 @@ class CallHistoryDetailPageComponent {
|
|
|
434
422
|
return `${m}:${s.toString().padStart(2, '0')}`;
|
|
435
423
|
}
|
|
436
424
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CallHistoryDetailPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
437
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: CallHistoryDetailPageComponent, isStandalone: true, selector: "eds-call-history-detail-page", host: { classAttribute: "block h-full min-h-0" }, ngImport: i0, template: "<div class=\"flex h-full min-h-0 flex-col overflow-auto bg-lighter p-base call-history-detail-page\">\n <
|
|
425
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: CallHistoryDetailPageComponent, isStandalone: true, selector: "eds-call-history-detail-page", host: { classAttribute: "block h-full min-h-0" }, ngImport: i0, template: "<div class=\"flex h-full min-h-0 flex-col overflow-auto bg-lighter p-base call-history-detail-page\">\n <div class=\"call-history-detail-page__body flex min-h-0 flex-1 flex-col\">\n\n @if (loading()) {\n <div class=\"flex flex-col gap-4\" aria-busy=\"true\">\n <header class=\"mb-base flex items-center justify-between gap-md rounded-lg bg-white p-sm shadow-sm\">\n <div class=\"flex items-center gap-md\">\n <ed-skeleton class=\"h-5 w-5 !rounded\"></ed-skeleton>\n <div class=\"flex items-center gap-xs\">\n <ed-skeleton class=\"h-9 w-9 !rounded-md\"></ed-skeleton>\n <div class=\"grid gap-2xs\">\n <ed-skeleton class=\"h-4 w-40\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-48\"></ed-skeleton>\n </div>\n </div>\n </div>\n <ed-skeleton class=\"h-8 w-36 !rounded-md\"></ed-skeleton>\n </header>\n <dl class=\"mx-0 mt-0 mb-5 grid grid-cols-2 gap-4\">\n <div class=\"grid gap-2xs\">\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n <ed-skeleton class=\"h-5 w-24 !rounded-full\"></ed-skeleton>\n </div>\n <div class=\"grid gap-2xs\">\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n <ed-skeleton class=\"h-4 w-14\"></ed-skeleton>\n </div>\n </dl>\n <div class=\"grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1fr)_280px]\">\n <div class=\"flex flex-col gap-3 rounded-lg border border-base bg-white p-4\">\n <ed-skeleton class=\"h-4 w-28\"></ed-skeleton>\n @for (_ of detailSkeletonRows; track _) {\n <div class=\"grid gap-2xs\">\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n <ed-skeleton class=\"h-10 w-full max-w-lg !rounded-md\"></ed-skeleton>\n </div>\n }\n </div>\n <div class=\"flex flex-col gap-3 rounded-lg border border-base bg-white p-4\">\n <ed-skeleton class=\"h-4 w-36\"></ed-skeleton>\n @for (_ of listSkeletonRows; track _) {\n <div class=\"flex items-center justify-between gap-3 border-b border-base py-3 last:border-b-0\">\n <div class=\"grid min-w-0 flex-1 gap-2xs\">\n <ed-skeleton class=\"h-3 w-32\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-40\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton>\n </div>\n }\n </div>\n </div>\n </div>\n } @else {\n @if (detail(); as d) {\n <header class=\"mb-base flex shrink-0 flex-wrap items-center justify-between gap-md rounded-lg bg-white p-sm shadow-sm\">\n <div class=\"flex min-w-0 items-center gap-md\">\n <ed-icon-button\n name=\"caret_left\"\n label=\"Go back to call history\"\n size=\"xs\"\n ghost\n (click$)=\"goBack()\"\n />\n <div class=\"flex min-w-0 items-center gap-xs\">\n <ed-avatar\n shape=\"box\"\n size=\"base\"\n [initials]=\"isUnknownName(d.name) ? '?' : d.initials || '?'\"\n [tone]=\"detailAvatarTone(d)\"\n />\n <div class=\"grid min-w-0 gap-2xs\">\n <div class=\"flex min-w-0 flex-wrap items-center gap-xs\">\n <span class=\"truncate text-dark\">{{ d.name }}</span>\n @if (d.reason) {\n <ed-badge-2 variant=\"primary\" pill uppercase>\n <span class=\"inline-flex items-center gap-2xs\">\n <ed-icon [name]=\"detailDirectionIcon(d)\" [size]=\"12\" color=\"currentColor\" />\n <span>{{ d.reason }}</span>\n </span>\n </ed-badge-2>\n }\n <span class=\"inline-flex text-light\" aria-hidden=\"true\">\n <ed-icon name=\"TagSimple\" [size]=\"14\" color=\"currentColor\" />\n </span>\n </div>\n <p class=\"m-0 truncate text-light\">\n {{\n callerMetaLine({\n dob: d.dob,\n age: d.age,\n gender: d.gender,\n phone: d.phone,\n name: d.name,\n })\n }}\n </p>\n </div>\n </div>\n </div>\n\n @if (isNeedsReview(d.review)) {\n <ed-button\n variant=\"primary\"\n fill\n size=\"sm\"\n [disabled]=\"markingReview()\"\n (click$)=\"markReviewed()\"\n >\n <ed-icon slot=\"prefix\" name=\"check_circle\" [size]=\"16\" />\n {{ markingReview() ? 'Saving\u2026' : 'Mark as reviewed' }}\n </ed-button>\n } @else if (d.review === 'reviewed') {\n <ed-badge-2 variant=\"success\" pill uppercase>Reviewed</ed-badge-2>\n }\n </header>\n\n <dl class=\"call-history-detail-page__meta mx-0 mt-0 mb-5 grid shrink-0 grid-cols-2 gap-4 sm:grid-cols-2\">\n <div><dt class=\"fs-sm font-semibold text-light\">Outcome</dt><dd>\n <ed-badge-2 [attr.variant]=\"outcomeTone(d.outcome)\">\n {{ outcomeLabel(d.outcome) }}\n </ed-badge-2>\n </dd></div>\n <div><dt class=\"fs-sm font-semibold text-light\">Duration</dt><dd>{{ d.durationLabel ?? formatDuration(d.duration) }}</dd></div>\n </dl>\n\n <eds-call-conversation-panel\n [callId]=\"d.id\"\n [summary]=\"d.summary\"\n [transcript]=\"d.transcript\"\n [tools]=\"d.tools\"\n [callDurationSec]=\"d.duration\"\n [callerName]=\"d.name\"\n [callerMatched]=\"!isUnknownName(d.name)\"\n (summaryRegenerated)=\"refreshCallDetail()\"\n >\n <eds-call-tasks-panel\n summary-side\n [callId]=\"d.id\"\n [compact]=\"true\"\n />\n </eds-call-conversation-panel>\n } @else {\n <p class=\"fs-sm text-light\">Call not found.</p>\n }\n }\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.call-history-detail-page__back{color:var(--eds-text-secondary)}.call-history-detail-page__body eds-call-conversation-panel{display:flex;flex:1 1 auto;flex-direction:column;min-height:min(60vh,36rem)}.call-history-detail-page__badges{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.call-history-detail-page__meta dd{margin:4px 0 0;font-size:14px}.call-history-detail-page__tabs{display:flex;gap:4px;margin-bottom:16px;border-bottom:1px solid var(--eds-border-default)}.call-history-detail-page__tab{padding:10px 16px;border:none;background:none;font-size:14px;font-weight:500;color:var(--eds-text-secondary);cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px}.call-history-detail-page__tab--active{color:var(--eds-text-brand);border-bottom-color:var(--eds-brand-500)}.call-history-detail-page__panel{padding:20px}@media(max-width:800px){.call-history-detail-page__meta{grid-template-columns:repeat(2,1fr)}}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "ed-icon", inputs: ["name", "size", "color", "cssClass", "decorative", "ariaHidden", "ariaLabel", "title", "desc", "focusable", "tabIndex"] }, { kind: "component", type: EdButtonComponent, selector: "ed-button", inputs: ["variant", "size", "disabled", "ghost", "outline", "subtle", "fill", "loading", "block", "elevated", "shape", "type", "href", "routerLink", "rel", "target", "download", "ariaLabel"], outputs: ["click$"] }, { kind: "component", type: EdAvatarComponent, selector: "ed-avatar", inputs: ["initials", "tone", "shape", "size", "gradient"] }, { kind: "component", type: EdIconButtonComponent, selector: "ed-icon-button", inputs: ["label", "name", "size", "variant", "allowBubble", "ghost", "outline", "solid", "subtle", "shape", "type", "disabled", "loading", "toggle", "pressed", "id", "title", "nameAttr", "value", "autofocus", "tabIndex"], outputs: ["click", "focus", "blur", "click$", "focus$", "blur$"] }, { kind: "component", type: CallConversationPanelComponent, selector: "eds-call-conversation-panel", inputs: ["callId", "summary", "transcript", "tools", "callDurationSec", "allowRegenerate", "callerName", "callerMatched"], outputs: ["summaryRegenerated"] }, { kind: "component", type: CallTasksPanelComponent, selector: "eds-call-tasks-panel", inputs: ["callId", "compact"] }, { kind: "component", type: EdSkeletonComponent, selector: "ed-skeleton", inputs: ["class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
438
426
|
}
|
|
439
427
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CallHistoryDetailPageComponent, decorators: [{
|
|
440
428
|
type: Component,
|
|
441
429
|
args: [{ selector: 'eds-call-history-detail-page', imports: [
|
|
442
430
|
IconComponent,
|
|
443
431
|
EdButtonComponent,
|
|
432
|
+
EdAvatarComponent,
|
|
433
|
+
EdIconButtonComponent,
|
|
444
434
|
CallConversationPanelComponent,
|
|
445
435
|
CallTasksPanelComponent,
|
|
446
436
|
EdSkeletonComponent,
|
|
447
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'block h-full min-h-0' }, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "<div class=\"flex h-full min-h-0 flex-col overflow-auto bg-lighter p-base call-history-detail-page\">\n <
|
|
437
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'block h-full min-h-0' }, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "<div class=\"flex h-full min-h-0 flex-col overflow-auto bg-lighter p-base call-history-detail-page\">\n <div class=\"call-history-detail-page__body flex min-h-0 flex-1 flex-col\">\n\n @if (loading()) {\n <div class=\"flex flex-col gap-4\" aria-busy=\"true\">\n <header class=\"mb-base flex items-center justify-between gap-md rounded-lg bg-white p-sm shadow-sm\">\n <div class=\"flex items-center gap-md\">\n <ed-skeleton class=\"h-5 w-5 !rounded\"></ed-skeleton>\n <div class=\"flex items-center gap-xs\">\n <ed-skeleton class=\"h-9 w-9 !rounded-md\"></ed-skeleton>\n <div class=\"grid gap-2xs\">\n <ed-skeleton class=\"h-4 w-40\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-48\"></ed-skeleton>\n </div>\n </div>\n </div>\n <ed-skeleton class=\"h-8 w-36 !rounded-md\"></ed-skeleton>\n </header>\n <dl class=\"mx-0 mt-0 mb-5 grid grid-cols-2 gap-4\">\n <div class=\"grid gap-2xs\">\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n <ed-skeleton class=\"h-5 w-24 !rounded-full\"></ed-skeleton>\n </div>\n <div class=\"grid gap-2xs\">\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n <ed-skeleton class=\"h-4 w-14\"></ed-skeleton>\n </div>\n </dl>\n <div class=\"grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1fr)_280px]\">\n <div class=\"flex flex-col gap-3 rounded-lg border border-base bg-white p-4\">\n <ed-skeleton class=\"h-4 w-28\"></ed-skeleton>\n @for (_ of detailSkeletonRows; track _) {\n <div class=\"grid gap-2xs\">\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n <ed-skeleton class=\"h-10 w-full max-w-lg !rounded-md\"></ed-skeleton>\n </div>\n }\n </div>\n <div class=\"flex flex-col gap-3 rounded-lg border border-base bg-white p-4\">\n <ed-skeleton class=\"h-4 w-36\"></ed-skeleton>\n @for (_ of listSkeletonRows; track _) {\n <div class=\"flex items-center justify-between gap-3 border-b border-base py-3 last:border-b-0\">\n <div class=\"grid min-w-0 flex-1 gap-2xs\">\n <ed-skeleton class=\"h-3 w-32\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-40\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton>\n </div>\n }\n </div>\n </div>\n </div>\n } @else {\n @if (detail(); as d) {\n <header class=\"mb-base flex shrink-0 flex-wrap items-center justify-between gap-md rounded-lg bg-white p-sm shadow-sm\">\n <div class=\"flex min-w-0 items-center gap-md\">\n <ed-icon-button\n name=\"caret_left\"\n label=\"Go back to call history\"\n size=\"xs\"\n ghost\n (click$)=\"goBack()\"\n />\n <div class=\"flex min-w-0 items-center gap-xs\">\n <ed-avatar\n shape=\"box\"\n size=\"base\"\n [initials]=\"isUnknownName(d.name) ? '?' : d.initials || '?'\"\n [tone]=\"detailAvatarTone(d)\"\n />\n <div class=\"grid min-w-0 gap-2xs\">\n <div class=\"flex min-w-0 flex-wrap items-center gap-xs\">\n <span class=\"truncate text-dark\">{{ d.name }}</span>\n @if (d.reason) {\n <ed-badge-2 variant=\"primary\" pill uppercase>\n <span class=\"inline-flex items-center gap-2xs\">\n <ed-icon [name]=\"detailDirectionIcon(d)\" [size]=\"12\" color=\"currentColor\" />\n <span>{{ d.reason }}</span>\n </span>\n </ed-badge-2>\n }\n <span class=\"inline-flex text-light\" aria-hidden=\"true\">\n <ed-icon name=\"TagSimple\" [size]=\"14\" color=\"currentColor\" />\n </span>\n </div>\n <p class=\"m-0 truncate text-light\">\n {{\n callerMetaLine({\n dob: d.dob,\n age: d.age,\n gender: d.gender,\n phone: d.phone,\n name: d.name,\n })\n }}\n </p>\n </div>\n </div>\n </div>\n\n @if (isNeedsReview(d.review)) {\n <ed-button\n variant=\"primary\"\n fill\n size=\"sm\"\n [disabled]=\"markingReview()\"\n (click$)=\"markReviewed()\"\n >\n <ed-icon slot=\"prefix\" name=\"check_circle\" [size]=\"16\" />\n {{ markingReview() ? 'Saving\u2026' : 'Mark as reviewed' }}\n </ed-button>\n } @else if (d.review === 'reviewed') {\n <ed-badge-2 variant=\"success\" pill uppercase>Reviewed</ed-badge-2>\n }\n </header>\n\n <dl class=\"call-history-detail-page__meta mx-0 mt-0 mb-5 grid shrink-0 grid-cols-2 gap-4 sm:grid-cols-2\">\n <div><dt class=\"fs-sm font-semibold text-light\">Outcome</dt><dd>\n <ed-badge-2 [attr.variant]=\"outcomeTone(d.outcome)\">\n {{ outcomeLabel(d.outcome) }}\n </ed-badge-2>\n </dd></div>\n <div><dt class=\"fs-sm font-semibold text-light\">Duration</dt><dd>{{ d.durationLabel ?? formatDuration(d.duration) }}</dd></div>\n </dl>\n\n <eds-call-conversation-panel\n [callId]=\"d.id\"\n [summary]=\"d.summary\"\n [transcript]=\"d.transcript\"\n [tools]=\"d.tools\"\n [callDurationSec]=\"d.duration\"\n [callerName]=\"d.name\"\n [callerMatched]=\"!isUnknownName(d.name)\"\n (summaryRegenerated)=\"refreshCallDetail()\"\n >\n <eds-call-tasks-panel\n summary-side\n [callId]=\"d.id\"\n [compact]=\"true\"\n />\n </eds-call-conversation-panel>\n } @else {\n <p class=\"fs-sm text-light\">Call not found.</p>\n }\n }\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.call-history-detail-page__back{color:var(--eds-text-secondary)}.call-history-detail-page__body eds-call-conversation-panel{display:flex;flex:1 1 auto;flex-direction:column;min-height:min(60vh,36rem)}.call-history-detail-page__badges{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.call-history-detail-page__meta dd{margin:4px 0 0;font-size:14px}.call-history-detail-page__tabs{display:flex;gap:4px;margin-bottom:16px;border-bottom:1px solid var(--eds-border-default)}.call-history-detail-page__tab{padding:10px 16px;border:none;background:none;font-size:14px;font-weight:500;color:var(--eds-text-secondary);cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px}.call-history-detail-page__tab--active{color:var(--eds-text-brand);border-bottom-color:var(--eds-brand-500)}.call-history-detail-page__panel{padding:20px}@media(max-width:800px){.call-history-detail-page__meta{grid-template-columns:repeat(2,1fr)}}\n"] }]
|
|
448
438
|
}] });
|
|
449
439
|
|
|
450
440
|
export { CallHistoryDetailPageComponent };
|
|
451
|
-
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-history-detail-page.component-
|
|
441
|
+
//# sourceMappingURL=edvak99-voice-receptionist-widget-call-history-detail-page.component-pRSrt5C2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edvak99-voice-receptionist-widget-call-history-detail-page.component-pRSrt5C2.mjs","sources":["../../../src/lib/utils/transcript-timing.util.ts","../../../src/lib/components/call-conversation-panel/call-conversation-panel.component.ts","../../../src/lib/components/call-conversation-panel/call-conversation-panel.component.html","../../../src/lib/components/call-tasks-panel/call-tasks-panel.component.ts","../../../src/lib/components/call-tasks-panel/call-tasks-panel.component.html","../../../src/lib/utils/call-outcome.util.ts","../../../src/lib/pages/call-history-detail-page/call-history-detail-page.component.ts","../../../src/lib/pages/call-history-detail-page/call-history-detail-page.component.html"],"sourcesContent":["import { ToolEvent, TranscriptLine } from '../models/ai-receptionist.types';\n\nexport interface TimedTranscriptLine extends TranscriptLine {\n startSec: number;\n endSec: number;\n index: number;\n}\n\n/** Parse tool timestamp strings like \"1:02\" or \"0:42\" into seconds. */\nexport function parseClockTime(value: string): number | null {\n const trimmed = value?.trim();\n if (!trimmed) return null;\n const parts = trimmed.split(':').map((p) => Number(p));\n if (parts.some((n) => Number.isNaN(n))) return null;\n if (parts.length === 2) return parts[0] * 60 + parts[1];\n if (parts.length === 3) return parts[0] * 3600 + parts[1] * 60 + parts[2];\n return null;\n}\n\nfunction resolveLineStart(line: TranscriptLine): number | null {\n if (line.at != null && line.at >= 0) return line.at;\n const raw = line as TranscriptLine & { offsetSeconds?: number; startTime?: number };\n if (raw.offsetSeconds != null && raw.offsetSeconds >= 0) return raw.offsetSeconds;\n if (raw.startTime != null && raw.startTime >= 0) return raw.startTime;\n return null;\n}\n\n/**\n * Assign start/end seconds to transcript lines for audio sync.\n * Uses explicit `at` when present; otherwise estimates from call duration.\n */\nexport function buildTimedTranscript(\n lines: TranscriptLine[],\n durationSeconds: number,\n): TimedTranscriptLine[] {\n if (!lines.length) return [];\n\n const total = Math.max(durationSeconds, 1);\n const explicit = lines.map((line) => resolveLineStart(line));\n const allExplicit = explicit.every((t) => t != null);\n\n const starts: number[] = new Array(lines.length).fill(0);\n\n if (allExplicit) {\n for (let i = 0; i < lines.length; i += 1) {\n starts[i] = explicit[i]!;\n }\n } else {\n const speakableCount = lines.filter((l) => l.who !== 'system').length;\n const step = total / Math.max(speakableCount, 1);\n let speakableIdx = 0;\n\n for (let i = 0; i < lines.length; i += 1) {\n if (explicit[i] != null) {\n starts[i] = explicit[i]!;\n continue;\n }\n const line = lines[i];\n if (line.who === 'system') {\n starts[i] = i > 0 ? starts[i - 1] : 0;\n continue;\n }\n starts[i] = speakableIdx * step;\n speakableIdx += 1;\n }\n }\n\n return lines.map((line, index) => {\n const startSec = starts[index];\n const nextStart = starts.slice(index + 1).find((s) => s > startSec);\n const endSec = nextStart ?? total;\n return { ...line, startSec, endSec: Math.max(endSec, startSec + 0.5), index };\n });\n}\n\nexport function activeTranscriptIndex(lines: TimedTranscriptLine[], currentSec: number): number {\n if (!lines.length || currentSec < 0) return -1;\n for (let i = lines.length - 1; i >= 0; i -= 1) {\n if (currentSec >= lines[i].startSec) return i;\n }\n return 0;\n}\n\nexport function formatPlaybackTime(seconds: number): string {\n const s = Math.max(0, Math.floor(seconds));\n const m = Math.floor(s / 60);\n const r = s % 60;\n return `${m}:${r.toString().padStart(2, '0')}`;\n}\n\nexport function toolStateClass(state: ToolEvent['state']): string {\n const map: Record<ToolEvent['state'], string> = {\n ok: 'call-conversation__tool--ok',\n warn: 'call-conversation__tool--warn',\n error: 'call-conversation__tool--error',\n active: 'call-conversation__tool--active',\n };\n return map[state] ?? '';\n}\n\nexport function transcriptRoleLabel(\n who: TranscriptLine['who'],\n callerName?: string | null,\n callerMatched?: boolean,\n): string {\n if (who === 'patient') {\n const name = String(callerName ?? '').trim();\n if (!name || callerMatched === false || /^unknown/i.test(name) || name === '?') {\n return 'Unknown caller';\n }\n return name;\n }\n const labels: Record<Exclude<TranscriptLine['who'], 'patient'>, string> = {\n ai: 'AI receptionist',\n staff: 'Staff',\n system: 'System',\n };\n return labels[who] ?? who;\n}\n","import { DatePipe } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n CUSTOM_ELEMENTS_SCHEMA,\n computed,\n effect,\n ElementRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\n\nimport { ToolEvent, TranscriptLine, TranscriptWho } from '../../models/ai-receptionist.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { ToastService } from '../../shared/toast.service';\nimport {\n activeTranscriptIndex,\n buildTimedTranscript,\n formatPlaybackTime,\n TimedTranscriptLine,\n transcriptRoleLabel,\n} from '../../utils/transcript-timing.util';\nimport { toolEventTrackKey } from '../../utils/tool-labels.util';\nimport { EdButtonComponent } from '../../ui/ed-button.component';\n\nimport { CallRecordingPlayerComponent } from '../call-recording-player/call-recording-player.component';\nimport { type BadgeTone } from '../../ui/eds-badge.component';\nimport { IconComponent } from '../../ui/ed-icon.component';\n\n@Component({\n selector: 'eds-call-conversation-panel',\n imports: [\n DatePipe,\n CallRecordingPlayerComponent,\n EdButtonComponent,\n IconComponent,\n ],\n templateUrl: './call-conversation-panel.component.html',\n styleUrl: './call-conversation-panel.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n})\nexport class CallConversationPanelComponent {\n private readonly api = inject(AiReceptionistApiService);\n private readonly toast = inject(ToastService);\n\n readonly callId = input.required<string>();\n readonly summary = input.required<string>();\n readonly transcript = input.required<TranscriptLine[]>();\n readonly tools = input.required<ToolEvent[]>();\n readonly callDurationSec = input(0);\n readonly allowRegenerate = input(true);\n readonly callerName = input<string | null>(null);\n readonly callerMatched = input<boolean | null>(null);\n\n readonly summaryRegenerated = output<void>();\n\n private readonly player = viewChild(CallRecordingPlayerComponent);\n private readonly scrollHost = viewChild<ElementRef<HTMLElement>>('scrollHost');\n\n protected readonly currentTime = signal(0);\n protected readonly playbackDuration = signal(0);\n protected readonly summaryExpanded = signal(false);\n private readonly regeneratedSummary = signal<string | null>(null);\n protected readonly displaySummary = computed(\n () => this.regeneratedSummary() ?? this.summary(),\n );\n protected readonly regenerating = signal(false);\n protected readonly summaryMeta = signal<{\n model?: string;\n generatedAt?: string;\n turnCount?: number;\n } | null>(null);\n\n protected readonly timedLines = computed(() =>\n buildTimedTranscript(\n this.transcript(),\n this.playbackDuration() || this.callDurationSec() || 120,\n ),\n );\n\n protected readonly activeIndex = computed(() =>\n activeTranscriptIndex(this.timedLines(), this.currentTime()),\n );\n\n protected readonly hasExplicitTiming = computed(() =>\n this.transcript().some((line) => line.at != null),\n );\n\n protected readonly formatTime = formatPlaybackTime;\n protected readonly toolTrackKey = toolEventTrackKey;\n\n protected roleLabel(who: TranscriptLine['who']): string {\n return transcriptRoleLabel(who, this.callerName(), this.callerMatched() ?? undefined);\n }\n\n protected speakerIcon(who: TranscriptWho | string): string {\n switch (who) {\n case 'ai':\n return 'graph_new';\n case 'staff':\n return 'Robot';\n case 'patient':\n return 'person';\n default:\n return 'info';\n }\n }\n\n protected toolTone(state: string): BadgeTone {\n switch (state) {\n case 'ok':\n return 'success';\n case 'warn':\n return 'warning';\n case 'error':\n return 'danger';\n case 'active':\n return 'primary';\n default:\n return 'light';\n }\n }\n\n constructor() {\n effect(\n () => {\n this.callId();\n this.regeneratedSummary.set(null);\n },\n { allowSignalWrites: true },\n );\n\n effect(() => {\n const idx = this.activeIndex();\n const host = this.scrollHost()?.nativeElement;\n if (idx < 0 || !host) return;\n const row = host.querySelector(`[data-line-index=\"${idx}\"]`);\n if (row instanceof HTMLElement) {\n row.scrollIntoView({ block: 'nearest', behavior: 'smooth' });\n }\n });\n }\n\n protected onPlaybackTime(sec: number): void {\n this.currentTime.set(sec);\n }\n\n protected onPlaybackDuration(sec: number): void {\n this.playbackDuration.set(sec);\n }\n\n protected seekLine(line: TimedTranscriptLine): void {\n if (line.who === 'system') return;\n this.player()?.seekTo(line.startSec);\n }\n\n protected toggleSummary(): void {\n this.summaryExpanded.update((v) => !v);\n }\n\n protected regenerateSummary(): void {\n if (this.regenerating()) return;\n\n this.regenerating.set(true);\n this.api.regenerateCallSummary(this.callId()).subscribe({\n next: ({ data }) => {\n this.regenerating.set(false);\n this.regeneratedSummary.set(data.summary);\n this.summaryExpanded.set(true);\n this.summaryMeta.set({\n model: data.summaryModel,\n generatedAt: data.summaryGeneratedAt,\n turnCount: data.transcriptTurnCount,\n });\n this.summaryRegenerated.emit();\n this.toast.show('Call summary regenerated', 'success');\n },\n error: (err: { message?: string }) => {\n this.regenerating.set(false);\n this.toast.show(err.message ?? 'Failed to regenerate summary', 'error');\n },\n });\n }\n}\n","<div class=\"flex min-h-0 flex-1 flex-col gap-4\">\n <div class=\"grid shrink-0 grid-cols-1 items-stretch gap-4 lg:grid-cols-2\">\n <section class=\"rounded-lg border border-base bg-white p-4 shadow-sm\">\n <div class=\"flex items-center justify-between gap-3\">\n <button type=\"button\" class=\"flex min-w-0 flex-1 cursor-pointer items-center gap-1 border-none bg-transparent p-0 text-left\" (click)=\"toggleSummary()\">\n <ed-icon [name]=\"summaryExpanded() ? 'expand_less' : 'expand_more'\" [size]=\"20\" />\n <h4 class=\"m-0\">Call summary</h4>\n </button>\n @if (allowRegenerate()) {\n <ed-button\n variant=\"secondary\"\n outline\n size=\"sm\"\n [disabled]=\"regenerating()\"\n (click$)=\"regenerateSummary()\"\n >\n <ed-icon slot=\"prefix\" name=\"refresh\" [size]=\"16\" />\n {{ regenerating() ? 'Regenerating…' : 'Regenerate' }}\n </ed-button>\n }\n </div>\n @if (summaryExpanded() || displaySummary().length < 180) {\n <p class=\"fs-base text-dark mt-3 leading-relaxed\">{{ displaySummary() }}</p>\n } @else {\n <p class=\"fs-base text-dark mt-3 line-clamp-2 leading-relaxed\">\n {{ displaySummary() }}\n </p>\n <button\n type=\"button\"\n class=\"cursor-pointer border-none bg-transparent px-0 pt-1 text-sm text-blue-600\"\n (click)=\"toggleSummary()\"\n >\n Read full summary\n </button>\n }\n @if (summaryMeta(); as meta) {\n <p class=\"fs-sm text-light mt-3 flex flex-wrap gap-3 text-zinc-500\">\n @if (meta.model) {\n <span>Model: {{ meta.model }}</span>\n }\n @if (meta.generatedAt) {\n <span>Generated {{ meta.generatedAt | date: 'medium' }}</span>\n }\n @if (meta.turnCount != null) {\n <span>{{ meta.turnCount }} transcript turns</span>\n }\n </p>\n }\n </section>\n <ng-content select=\"[summary-side]\" />\n </div>\n\n <section class=\"shrink-0 overflow-hidden rounded-lg border border-base bg-white p-0 shadow-sm\">\n <eds-call-recording-player\n [callId]=\"callId()\"\n (currentTimeChange)=\"onPlaybackTime($event)\"\n (durationChange)=\"onPlaybackDuration($event)\"\n />\n </section>\n\n <div class=\"call-conversation-panel__split grid min-h-0 flex-1 grid-cols-1 items-stretch gap-4 lg:grid-cols-[1fr_300px]\">\n <section\n class=\"call-conversation-panel__transcript flex flex-1 flex-col rounded-lg border border-base bg-white p-4 shadow-sm\"\n aria-labelledby=\"call-transcript-title\"\n >\n <header class=\"mb-3 flex shrink-0 items-center justify-between gap-3\">\n <h4 id=\"call-transcript-title\" class=\"m-0\">Transcript</h4>\n @if (playbackDuration() > 0) {\n <span class=\"font-['IBM_Plex_Mono'] fs-sm text-light text-zinc-500\">\n {{ formatTime(currentTime()) }} / {{ formatTime(playbackDuration()) }}\n </span>\n }\n </header>\n\n <div #scrollHost class=\"chat-thread call-conversation-panel__thread flex-1 overflow-auto rounded-xl border border-zinc-200\" role=\"log\">\n @for (line of timedLines(); track line.index) {\n @if (line.who === 'system') {\n <div class=\"chat-row chat-row--system\">\n <div\n class=\"chat-bubble chat-bubble--system inline-flex items-center gap-2\"\n [class.ring-2]=\"line.index === activeIndex()\"\n [class.ring-blue-200]=\"line.index === activeIndex()\"\n [attr.data-line-index]=\"line.index\"\n >\n <ed-icon name=\"info\" [size]=\"14\" />\n <span>{{ line.text }}</span>\n </div>\n </div>\n } @else {\n <article\n class=\"chat-row cursor-pointer border-none bg-transparent p-0\"\n [class.chat-row--caller]=\"line.who === 'patient'\"\n [class.chat-row--ai]=\"line.who === 'ai'\"\n [class.chat-row--staff]=\"line.who === 'staff'\"\n [attr.data-line-index]=\"line.index\"\n [attr.data-who]=\"line.who\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-current]=\"line.index === activeIndex() ? 'true' : null\"\n (click)=\"seekLine(line)\"\n (keyup.enter)=\"seekLine(line)\"\n >\n <div class=\"chat-meta\">\n <span>{{ roleLabel(line.who) }}</span>\n <span class=\"chat-time\">{{ formatTime(line.startSec) }}</span>\n </div>\n <div class=\"chat-bubble-row\">\n <div\n class=\"chat-avatar\"\n [class.chat-avatar--ai]=\"line.who === 'ai'\"\n [class.chat-avatar--staff]=\"line.who === 'staff'\"\n [class.chat-avatar--caller]=\"line.who === 'patient'\"\n >\n <ed-icon [name]=\"speakerIcon(line.who)\" [size]=\"16\" />\n </div>\n <div\n class=\"chat-bubble\"\n [class.chat-bubble--caller]=\"line.who === 'patient'\"\n [class.chat-bubble--ai]=\"line.who === 'ai'\"\n [class.chat-bubble--staff]=\"line.who === 'staff'\"\n [class.ring-2]=\"line.index === activeIndex()\"\n [class.ring-blue-200]=\"line.index === activeIndex()\"\n >\n <p class=\"chat-content\">{{ line.text }}</p>\n </div>\n </div>\n </article>\n }\n } @empty {\n <p class=\"fs-sm text-light py-3 text-zinc-500\">No transcript available for this call.</p>\n }\n </div>\n</section>\n\n <aside class=\"flex min-h-0 flex-col overflow-hidden rounded-lg border border-base bg-white p-4 shadow-sm\" aria-labelledby=\"call-goal-timeline-title\">\n <header class=\"mb-3 flex items-center justify-between gap-3\">\n <h4 id=\"call-goal-timeline-title\" class=\"m-0\">Goal Timeline</h4>\n <span class=\"fs-sm text-light\">{{ tools().length }}</span>\n </header>\n\n <ul class=\"m-0 flex min-h-0 list-none flex-1 flex-col gap-3 overflow-auto p-0\">\n @for (tool of tools(); track toolTrackKey(tool, $index)) {\n <li\n [class]=\"\n 'grid grid-cols-[auto_1fr_auto] items-start gap-3 rounded-md border-l-4 bg-zinc-50 p-3 ' +\n (tool.state === 'ok'\n ? 'border-l-green-500'\n : tool.state === 'warn'\n ? 'border-l-amber-500'\n : tool.state === 'error'\n ? 'border-l-red-500'\n : tool.state === 'active'\n ? 'border-l-blue-600'\n : 'border-l-zinc-400')\n \"\n >\n <span class=\"font-['IBM_Plex_Mono'] fs-sm text-light whitespace-nowrap text-zinc-500\">{{ tool.t }}</span>\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span class=\"fs-sm font-semibold text-dark\">{{ tool.name }}</span>\n <span class=\"fs-sm text-light\">{{ tool.result }}</span>\n </div>\n <ed-badge-2 [attr.variant]=\"toolTone(tool.state)\">{{ tool.state }}</ed-badge-2>\n </li>\n } @empty {\n <li class=\"fs-sm text-light py-3 text-zinc-500\">No goal activity recorded.</li>\n }\n </ul>\n </aside>\n </div>\n</div>\n","import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, computed, inject, input, OnInit, signal } from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\n\nimport { EdSkeletonComponent } from '../../ui/ed-skeleton.component';\n\nimport { SmartTooltipDirective } from '../../shared/smart-tooltip.directive';\nimport { BadgeTone } from '../../ui/eds-badge.component';\nimport {\n AgentActivity,\n activityTypeLabel,\n} from '../../models/agent-activity.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\n\nconst PREVIEW_LIMIT = 4;\n\n@Component({\n selector: 'eds-call-tasks-panel',\n imports: [EdSkeletonComponent, SmartTooltipDirective],\n templateUrl: './call-tasks-panel.component.html',\n styleUrl: './call-tasks-panel.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n})\nexport class CallTasksPanelComponent implements OnInit {\n private readonly api = inject(AiReceptionistApiService);\n private readonly router = inject(Router);\n private readonly route = inject(ActivatedRoute);\n\n readonly callId = input.required<string>();\n readonly compact = input(false);\n\n protected readonly activities = signal<AgentActivity[]>([]);\n protected readonly total = signal(0);\n protected readonly loading = signal(true);\n protected readonly listSkeletonRows = [0, 1, 2] as const;\n protected readonly previewLimit = PREVIEW_LIMIT;\n protected readonly activityTypeLabel = activityTypeLabel;\n\n protected readonly previewActivities = computed(() =>\n this.activities().slice(0, PREVIEW_LIMIT),\n );\n\n protected openActivities(): void {\n void this.router.navigate(['../activities'], {\n relativeTo: this.route,\n queryParams: { callId: this.callId() },\n });\n }\n\n ngOnInit(): void {\n this.api\n .getActivities({\n callId: this.callId(),\n page: 1,\n limit: 50,\n })\n .subscribe({\n next: ({ items, total }) => {\n this.activities.set(items);\n this.total.set(total);\n this.loading.set(false);\n },\n error: () => this.loading.set(false),\n });\n }\n\n protected activitySubline(item: AgentActivity): string {\n const bits = [\n item.patientName,\n item.visitType,\n item.providerName,\n ].filter(Boolean);\n return bits.join(' · ') || item.detail || '—';\n }\n\n protected activityTone(type: string): BadgeTone {\n switch (type) {\n case 'appointment_booked':\n return 'primary';\n case 'patient_created':\n return 'success';\n case 'task_created':\n return 'warning';\n default:\n return 'light';\n }\n }\n}\n","@if (loading() || activities().length > 0) {\n<section class=\"call-tasks rounded-lg border border-base bg-white px-5 py-4 mt-5 shadow-sm\" [class.call-tasks--compact]=\"compact()\">\n <header class=\"mb-4 flex items-center justify-between gap-3\">\n <h4>Activities from this call</h4>\n <button\n type=\"button\"\n class=\"eds-plain-nav call-tasks__all-link fs-sm\"\n (click)=\"openActivities()\"\n >\n View all Activities\n </button>\n </header>\n\n @if (loading()) {\n <ul class=\"call-tasks__list overflow-hidden rounded-lg border border-base\" aria-busy=\"true\">\n @for (_ of listSkeletonRows; track _) {\n <li class=\"call-tasks__item border-b border-base last:border-b-0\">\n <div class=\"call-tasks__row grid w-full grid-cols-[minmax(0,1fr)_auto] items-center gap-3 px-4 py-3\">\n <div class=\"flex min-w-0 flex-col gap-1\">\n <ed-skeleton class=\"h-3 w-40\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-48\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton>\n </div>\n </li>\n }\n </ul>\n } @else {\n <ul class=\"call-tasks__list overflow-hidden rounded-lg border border-base\">\n @for (item of previewActivities(); track item.id) {\n <li class=\"call-tasks__item border-b border-base last:border-b-0\">\n <div class=\"call-tasks__row grid w-full grid-cols-[minmax(0,1fr)_auto] items-center gap-3 border-none bg-transparent px-4 py-3 text-left font-[inherit]\">\n <div class=\"flex min-w-0 flex-col gap-1\">\n <span\n class=\"call-tasks__title min-w-0 max-w-full overflow-hidden text-ellipsis whitespace-nowrap text-sm font-semibold\"\n [smartTooltip]=\"item.title || activityTypeLabel(item.type)\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ item.title || activityTypeLabel(item.type) }}</span>\n <span\n class=\"call-tasks__sub max-w-full overflow-hidden text-ellipsis whitespace-nowrap text-xs\"\n [smartTooltip]=\"activitySubline(item)\"\n [tooltipOnlyWhenTruncated]=\"true\"\n >{{ activitySubline(item) }}</span>\n </div>\n <ed-badge-2 [attr.variant]=\"activityTone(item.type)\">{{ activityTypeLabel(item.type) }}</ed-badge-2>\n </div>\n </li>\n }\n </ul>\n @if (total() > previewLimit) {\n <p class=\"call-tasks__more fs-sm text-light mt-3\">\n +{{ total() - previewLimit }} more —\n <button type=\"button\" class=\"eds-plain-nav call-tasks__all-link\" (click)=\"openActivities()\">\n View all Activities\n </button>\n </p>\n }\n }\n</section>\n}\n","import { BadgeTone } from '../ui/eds-badge.component';\n\n/** Known history outcomes from GET /calls/history (HistoryCallDto.outcome). */\nexport const HISTORY_OUTCOMES = [\n 'completed',\n 'failed',\n 'transferred',\n 'escalated',\n] as const;\n\nexport type HistoryOutcome = (typeof HISTORY_OUTCOMES)[number] | 'custom';\n\nexport function normalizeHistoryOutcome(outcome: string): HistoryOutcome {\n const key = outcome.trim().toLowerCase();\n if ((HISTORY_OUTCOMES as readonly string[]).includes(key)) {\n return key as HistoryOutcome;\n }\n return 'custom';\n}\n\n/** Badge tone for history table / detail — separate from lifecycle or live UI status. */\nexport function outcomeBadgeTone(outcome: string): BadgeTone {\n switch (normalizeHistoryOutcome(outcome)) {\n case 'completed':\n return 'success';\n case 'failed':\n return 'danger';\n case 'transferred':\n return 'opened';\n case 'escalated':\n return 'danger';\n default: {\n const key = outcome.trim().toLowerCase();\n if (key.includes('transfer')) return 'opened';\n if (key.includes('fail') || key.includes('escalat') || key.includes('abandon')) return 'danger';\n if (key.includes('voicemail')) return 'light';\n if (key.includes('complete') || key.includes('book') || key.includes('task')) return 'success';\n return 'primary';\n }\n }\n}\n\nexport function formatOutcomeLabel(outcome: string): string {\n const trimmed = outcome.trim();\n if (!trimmed) return 'Unknown';\n const known = normalizeHistoryOutcome(trimmed);\n if (known === 'custom') return trimmed;\n return known.charAt(0).toUpperCase() + known.slice(1);\n}\n","import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, inject, OnInit, signal } from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\n\nimport { EdButtonComponent } from '../../ui/ed-button.component';\nimport { EdSkeletonComponent } from '../../ui/ed-skeleton.component';\nimport { EdAvatarComponent } from '../../ui/ed-avatar.component';\nimport { EdIconButtonComponent } from '../../ui/ed-icon-button.component';\n\nimport { CallConversationPanelComponent } from '../../components/call-conversation-panel/call-conversation-panel.component';\nimport { CallTasksPanelComponent } from '../../components/call-tasks-panel/call-tasks-panel.component';\nimport { HistoryDetail } from '../../models/ai-receptionist.types';\nimport { AiReceptionistApiService } from '../../services/ai-receptionist-api.service';\nimport { CallReviewService } from '../../services/call-review.service';\nimport { formatOutcomeLabel, outcomeBadgeTone } from '../../utils/call-outcome.util';\nimport {\n isNeedsReview,\n} from '../../utils/call-review.util';\nimport { callerMetaLine, isUnknownCaller } from '../../utils/call-history-display.util';\nimport { IconComponent } from '../../ui/ed-icon.component';\nimport { ToastService } from '../../shared/toast.service';\n\n@Component({\n selector: 'eds-call-history-detail-page',\n imports: [\n IconComponent,\n EdButtonComponent,\n EdAvatarComponent,\n EdIconButtonComponent,\n CallConversationPanelComponent,\n CallTasksPanelComponent,\n EdSkeletonComponent,\n ],\n templateUrl: './call-history-detail-page.component.html',\n styleUrl: './call-history-detail-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'block h-full min-h-0' },\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n})\nexport class CallHistoryDetailPageComponent implements OnInit {\n private readonly api = inject(AiReceptionistApiService);\n private readonly reviewService = inject(CallReviewService);\n private readonly toast = inject(ToastService);\n private readonly route = inject(ActivatedRoute);\n private readonly router = inject(Router);\n\n /** Parent shell route — back targets sibling `history`, not `history/history`. */\n protected readonly historyListLink: string[] = ['history'];\n protected readonly historyListRelativeTo = this.route.parent;\n\n protected readonly detail = signal<HistoryDetail | null>(null);\n protected readonly loading = signal(true);\n protected readonly markingReview = signal(false);\n protected readonly detailSkeletonRows = [0, 1, 2, 3, 4] as const;\n protected readonly listSkeletonRows = [0, 1, 2] as const;\n\n protected isNeedsReview = isNeedsReview;\n protected outcomeTone = outcomeBadgeTone;\n protected outcomeLabel = formatOutcomeLabel;\n protected callerMetaLine = callerMetaLine;\n\n protected isUnknownName(name: string | null | undefined): boolean {\n return isUnknownCaller(name);\n }\n\n protected detailAvatarTone(detail: HistoryDetail): 'gray' | 'brand' {\n return this.isUnknownName(detail.name) || detail.initials === '?' ? 'gray' : 'brand';\n }\n\n protected detailDirectionIcon(detail: HistoryDetail): string {\n return detail.direction === 'inbound' ? 'call_received' : 'call_made';\n }\n\n ngOnInit(): void {\n const id = this.route.snapshot.paramMap.get('id') ?? '';\n this.api.getCallDetail(id).subscribe(({ data }) => {\n this.detail.set(data);\n this.loading.set(false);\n });\n }\n\n protected markReviewed(): void {\n const d = this.detail();\n if (!d || !isNeedsReview(d.review) || this.markingReview()) return;\n\n this.markingReview.set(true);\n const prev = d.review;\n this.detail.update((current) =>\n current ? { ...current, review: 'reviewed' } : current,\n );\n\n this.reviewService.markReviewed(d.id).subscribe({\n next: () => {\n this.markingReview.set(false);\n this.toast.show('Call marked as reviewed', 'success');\n },\n error: () => {\n this.markingReview.set(false);\n this.detail.update((current) =>\n current ? { ...current, review: prev } : current,\n );\n this.toast.show('Failed to mark call as reviewed', 'error');\n },\n });\n }\n\n protected refreshCallDetail(): void {\n const id = this.detail()?.id;\n if (!id) return;\n this.api.getCallDetail(id).subscribe(({ data }) => {\n if (data) this.detail.set(data);\n });\n }\n\n protected goBack(): void {\n void this.router.navigate(this.historyListLink, { relativeTo: this.historyListRelativeTo });\n }\n\n protected formatDuration(sec: number): string {\n const m = Math.floor(sec / 60);\n const s = sec % 60;\n return `${m}:${s.toString().padStart(2, '0')}`;\n }\n}\n","<div class=\"flex h-full min-h-0 flex-col overflow-auto bg-lighter p-base call-history-detail-page\">\n <div class=\"call-history-detail-page__body flex min-h-0 flex-1 flex-col\">\n\n @if (loading()) {\n <div class=\"flex flex-col gap-4\" aria-busy=\"true\">\n <header class=\"mb-base flex items-center justify-between gap-md rounded-lg bg-white p-sm shadow-sm\">\n <div class=\"flex items-center gap-md\">\n <ed-skeleton class=\"h-5 w-5 !rounded\"></ed-skeleton>\n <div class=\"flex items-center gap-xs\">\n <ed-skeleton class=\"h-9 w-9 !rounded-md\"></ed-skeleton>\n <div class=\"grid gap-2xs\">\n <ed-skeleton class=\"h-4 w-40\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-48\"></ed-skeleton>\n </div>\n </div>\n </div>\n <ed-skeleton class=\"h-8 w-36 !rounded-md\"></ed-skeleton>\n </header>\n <dl class=\"mx-0 mt-0 mb-5 grid grid-cols-2 gap-4\">\n <div class=\"grid gap-2xs\">\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n <ed-skeleton class=\"h-5 w-24 !rounded-full\"></ed-skeleton>\n </div>\n <div class=\"grid gap-2xs\">\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n <ed-skeleton class=\"h-4 w-14\"></ed-skeleton>\n </div>\n </dl>\n <div class=\"grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1fr)_280px]\">\n <div class=\"flex flex-col gap-3 rounded-lg border border-base bg-white p-4\">\n <ed-skeleton class=\"h-4 w-28\"></ed-skeleton>\n @for (_ of detailSkeletonRows; track _) {\n <div class=\"grid gap-2xs\">\n <ed-skeleton class=\"h-3 w-16\"></ed-skeleton>\n <ed-skeleton class=\"h-10 w-full max-w-lg !rounded-md\"></ed-skeleton>\n </div>\n }\n </div>\n <div class=\"flex flex-col gap-3 rounded-lg border border-base bg-white p-4\">\n <ed-skeleton class=\"h-4 w-36\"></ed-skeleton>\n @for (_ of listSkeletonRows; track _) {\n <div class=\"flex items-center justify-between gap-3 border-b border-base py-3 last:border-b-0\">\n <div class=\"grid min-w-0 flex-1 gap-2xs\">\n <ed-skeleton class=\"h-3 w-32\"></ed-skeleton>\n <ed-skeleton class=\"h-3 w-40\"></ed-skeleton>\n </div>\n <ed-skeleton class=\"h-5 w-20 !rounded-full\"></ed-skeleton>\n </div>\n }\n </div>\n </div>\n </div>\n } @else {\n @if (detail(); as d) {\n <header class=\"mb-base flex shrink-0 flex-wrap items-center justify-between gap-md rounded-lg bg-white p-sm shadow-sm\">\n <div class=\"flex min-w-0 items-center gap-md\">\n <ed-icon-button\n name=\"caret_left\"\n label=\"Go back to call history\"\n size=\"xs\"\n ghost\n (click$)=\"goBack()\"\n />\n <div class=\"flex min-w-0 items-center gap-xs\">\n <ed-avatar\n shape=\"box\"\n size=\"base\"\n [initials]=\"isUnknownName(d.name) ? '?' : d.initials || '?'\"\n [tone]=\"detailAvatarTone(d)\"\n />\n <div class=\"grid min-w-0 gap-2xs\">\n <div class=\"flex min-w-0 flex-wrap items-center gap-xs\">\n <span class=\"truncate text-dark\">{{ d.name }}</span>\n @if (d.reason) {\n <ed-badge-2 variant=\"primary\" pill uppercase>\n <span class=\"inline-flex items-center gap-2xs\">\n <ed-icon [name]=\"detailDirectionIcon(d)\" [size]=\"12\" color=\"currentColor\" />\n <span>{{ d.reason }}</span>\n </span>\n </ed-badge-2>\n }\n <span class=\"inline-flex text-light\" aria-hidden=\"true\">\n <ed-icon name=\"TagSimple\" [size]=\"14\" color=\"currentColor\" />\n </span>\n </div>\n <p class=\"m-0 truncate text-light\">\n {{\n callerMetaLine({\n dob: d.dob,\n age: d.age,\n gender: d.gender,\n phone: d.phone,\n name: d.name,\n })\n }}\n </p>\n </div>\n </div>\n </div>\n\n @if (isNeedsReview(d.review)) {\n <ed-button\n variant=\"primary\"\n fill\n size=\"sm\"\n [disabled]=\"markingReview()\"\n (click$)=\"markReviewed()\"\n >\n <ed-icon slot=\"prefix\" name=\"check_circle\" [size]=\"16\" />\n {{ markingReview() ? 'Saving…' : 'Mark as reviewed' }}\n </ed-button>\n } @else if (d.review === 'reviewed') {\n <ed-badge-2 variant=\"success\" pill uppercase>Reviewed</ed-badge-2>\n }\n </header>\n\n <dl class=\"call-history-detail-page__meta mx-0 mt-0 mb-5 grid shrink-0 grid-cols-2 gap-4 sm:grid-cols-2\">\n <div><dt class=\"fs-sm font-semibold text-light\">Outcome</dt><dd>\n <ed-badge-2 [attr.variant]=\"outcomeTone(d.outcome)\">\n {{ outcomeLabel(d.outcome) }}\n </ed-badge-2>\n </dd></div>\n <div><dt class=\"fs-sm font-semibold text-light\">Duration</dt><dd>{{ d.durationLabel ?? formatDuration(d.duration) }}</dd></div>\n </dl>\n\n <eds-call-conversation-panel\n [callId]=\"d.id\"\n [summary]=\"d.summary\"\n [transcript]=\"d.transcript\"\n [tools]=\"d.tools\"\n [callDurationSec]=\"d.duration\"\n [callerName]=\"d.name\"\n [callerMatched]=\"!isUnknownName(d.name)\"\n (summaryRegenerated)=\"refreshCallDetail()\"\n >\n <eds-call-tasks-panel\n summary-side\n [callId]=\"d.id\"\n [compact]=\"true\"\n />\n </eds-call-conversation-panel>\n } @else {\n <p class=\"fs-sm text-light\">Call not found.</p>\n }\n }\n </div>\n</div>\n"],"names":[],"mappings":";;;;;;;;;;AAQA;AACM,SAAU,cAAc,CAAC,KAAa,EAAA;AAC1C,IAAA,MAAM,OAAO,GAAG,KAAK,EAAE,IAAI,EAAE;AAC7B,IAAA,IAAI,CAAC,OAAO;AAAE,QAAA,OAAO,IAAI;IACzB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC;AACtD,IAAA,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAAE,QAAA,OAAO,IAAI;AACnD,IAAA,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;AACvD,IAAA,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;AAAE,QAAA,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;AACzE,IAAA,OAAO,IAAI;AACb;AAEA,SAAS,gBAAgB,CAAC,IAAoB,EAAA;IAC5C,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,IAAI,IAAI,CAAC,EAAE,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,EAAE;IACnD,MAAM,GAAG,GAAG,IAAuE;IACnF,IAAI,GAAG,CAAC,aAAa,IAAI,IAAI,IAAI,GAAG,CAAC,aAAa,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC,aAAa;IACjF,IAAI,GAAG,CAAC,SAAS,IAAI,IAAI,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC,SAAS;AACrE,IAAA,OAAO,IAAI;AACb;AAEA;;;AAGG;AACG,SAAU,oBAAoB,CAClC,KAAuB,EACvB,eAAuB,EAAA;IAEvB,IAAI,CAAC,KAAK,CAAC,MAAM;AAAE,QAAA,OAAO,EAAE;IAE5B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC;AAC1C,IAAA,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAC5D,IAAA,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;AAEpD,IAAA,MAAM,MAAM,GAAa,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAExD,IAAI,WAAW,EAAE;AACf,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE;YACxC,MAAM,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAE;QAC1B;IACF;SAAO;AACL,QAAA,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,MAAM;AACrE,QAAA,MAAM,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC;QAChD,IAAI,YAAY,GAAG,CAAC;AAEpB,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE;AACxC,YAAA,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE;gBACvB,MAAM,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAE;gBACxB;YACF;AACA,YAAA,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC;AACrB,YAAA,IAAI,IAAI,CAAC,GAAG,KAAK,QAAQ,EAAE;gBACzB,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;gBACrC;YACF;AACA,YAAA,MAAM,CAAC,CAAC,CAAC,GAAG,YAAY,GAAG,IAAI;YAC/B,YAAY,IAAI,CAAC;QACnB;IACF;IAEA,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,KAAI;AAC/B,QAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC;QAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;AACnE,QAAA,MAAM,MAAM,GAAG,SAAS,IAAI,KAAK;QACjC,OAAO,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AAC/E,IAAA,CAAC,CAAC;AACJ;AAEM,SAAU,qBAAqB,CAAC,KAA4B,EAAE,UAAkB,EAAA;AACpF,IAAA,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,UAAU,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;AAC9C,IAAA,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;AAC7C,QAAA,IAAI,UAAU,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ;AAAE,YAAA,OAAO,CAAC;IAC/C;AACA,IAAA,OAAO,CAAC;AACV;AAEM,SAAU,kBAAkB,CAAC,OAAe,EAAA;AAChD,IAAA,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC;AAC5B,IAAA,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE;AAChB,IAAA,OAAO,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;AAChD;AAEM,SAAU,cAAc,CAAC,KAAyB,EAAA;AACtD,IAAA,MAAM,GAAG,GAAuC;AAC9C,QAAA,EAAE,EAAE,6BAA6B;AACjC,QAAA,IAAI,EAAE,+BAA+B;AACrC,QAAA,KAAK,EAAE,gCAAgC;AACvC,QAAA,MAAM,EAAE,iCAAiC;KAC1C;AACD,IAAA,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE;AACzB;SAEgB,mBAAmB,CACjC,GAA0B,EAC1B,UAA0B,EAC1B,aAAuB,EAAA;AAEvB,IAAA,IAAI,GAAG,KAAK,SAAS,EAAE;QACrB,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;AAC5C,QAAA,IAAI,CAAC,IAAI,IAAI,aAAa,KAAK,KAAK,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,GAAG,EAAE;AAC9E,YAAA,OAAO,gBAAgB;QACzB;AACA,QAAA,OAAO,IAAI;IACb;AACA,IAAA,MAAM,MAAM,GAA8D;AACxE,QAAA,EAAE,EAAE,iBAAiB;AACrB,QAAA,KAAK,EAAE,OAAO;AACd,QAAA,MAAM,EAAE,QAAQ;KACjB;AACD,IAAA,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,GAAG;AAC3B;;MCzEa,8BAA8B,CAAA;AAkD/B,IAAA,SAAS,CAAC,GAA0B,EAAA;AAC5C,QAAA,OAAO,mBAAmB,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,SAAS,CAAC;IACvF;AAEU,IAAA,WAAW,CAAC,GAA2B,EAAA;QAC/C,QAAQ,GAAG;AACT,YAAA,KAAK,IAAI;AACP,gBAAA,OAAO,WAAW;AACpB,YAAA,KAAK,OAAO;AACV,gBAAA,OAAO,OAAO;AAChB,YAAA,KAAK,SAAS;AACZ,gBAAA,OAAO,QAAQ;AACjB,YAAA;AACE,gBAAA,OAAO,MAAM;;IAEnB;AAEU,IAAA,QAAQ,CAAC,KAAa,EAAA;QAC9B,QAAQ,KAAK;AACX,YAAA,KAAK,IAAI;AACP,gBAAA,OAAO,SAAS;AAClB,YAAA,KAAK,MAAM;AACT,gBAAA,OAAO,SAAS;AAClB,YAAA,KAAK,OAAO;AACV,gBAAA,OAAO,QAAQ;AACjB,YAAA,KAAK,QAAQ;AACX,gBAAA,OAAO,SAAS;AAClB,YAAA;AACE,gBAAA,OAAO,OAAO;;IAEpB;AAEA,IAAA,WAAA,GAAA;AAjFiB,QAAA,IAAA,CAAA,GAAG,GAAG,MAAM,CAAC,wBAAwB,CAAC;AACtC,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC;AAEpC,QAAA,IAAA,CAAA,MAAM,GAAG,KAAK,CAAC,QAAQ,EAAU;AACjC,QAAA,IAAA,CAAA,OAAO,GAAG,KAAK,CAAC,QAAQ,EAAU;AAClC,QAAA,IAAA,CAAA,UAAU,GAAG,KAAK,CAAC,QAAQ,EAAoB;AAC/C,QAAA,IAAA,CAAA,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAe;AACrC,QAAA,IAAA,CAAA,eAAe,GAAG,KAAK,CAAC,CAAC,CAAC;AAC1B,QAAA,IAAA,CAAA,eAAe,GAAG,KAAK,CAAC,IAAI,CAAC;AAC7B,QAAA,IAAA,CAAA,UAAU,GAAG,KAAK,CAAgB,IAAI,CAAC;AACvC,QAAA,IAAA,CAAA,aAAa,GAAG,KAAK,CAAiB,IAAI,CAAC;QAE3C,IAAA,CAAA,kBAAkB,GAAG,MAAM,EAAQ;AAE3B,QAAA,IAAA,CAAA,MAAM,GAAG,SAAS,CAAC,4BAA4B,CAAC;AAChD,QAAA,IAAA,CAAA,UAAU,GAAG,SAAS,CAA0B,YAAY,CAAC;AAE3D,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC;AACvB,QAAA,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC;AAC5B,QAAA,IAAA,CAAA,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC;AACjC,QAAA,IAAA,CAAA,kBAAkB,GAAG,MAAM,CAAgB,IAAI,CAAC;AAC9C,QAAA,IAAA,CAAA,cAAc,GAAG,QAAQ,CAC1C,MAAM,IAAI,CAAC,kBAAkB,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,CAClD;AACkB,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC;AAC5B,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAI7B,IAAI,CAAC;QAEI,IAAA,CAAA,UAAU,GAAG,QAAQ,CAAC,MACvC,oBAAoB,CAClB,IAAI,CAAC,UAAU,EAAE,EACjB,IAAI,CAAC,gBAAgB,EAAE,IAAI,IAAI,CAAC,eAAe,EAAE,IAAI,GAAG,CACzD,CACF;AAEkB,QAAA,IAAA,CAAA,WAAW,GAAG,QAAQ,CAAC,MACxC,qBAAqB,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAC7D;QAEkB,IAAA,CAAA,iBAAiB,GAAG,QAAQ,CAAC,MAC9C,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,CAClD;QAEkB,IAAA,CAAA,UAAU,GAAG,kBAAkB;QAC/B,IAAA,CAAA,YAAY,GAAG,iBAAiB;QAmCjD,MAAM,CACJ,MAAK;YACH,IAAI,CAAC,MAAM,EAAE;AACb,YAAA,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC;AACnC,QAAA,CAAC,EACD,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAC5B;QAED,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE;YAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,EAAE,aAAa;AAC7C,YAAA,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI;gBAAE;YACtB,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,CAAA,kBAAA,EAAqB,GAAG,CAAA,EAAA,CAAI,CAAC;AAC5D,YAAA,IAAI,GAAG,YAAY,WAAW,EAAE;AAC9B,gBAAA,GAAG,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;YAC9D;AACF,QAAA,CAAC,CAAC;IACJ;AAEU,IAAA,cAAc,CAAC,GAAW,EAAA;AAClC,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;IAC3B;AAEU,IAAA,kBAAkB,CAAC,GAAW,EAAA;AACtC,QAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC;IAChC;AAEU,IAAA,QAAQ,CAAC,IAAyB,EAAA;AAC1C,QAAA,IAAI,IAAI,CAAC,GAAG,KAAK,QAAQ;YAAE;QAC3B,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;IACtC;IAEU,aAAa,GAAA;AACrB,QAAA,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IACxC;IAEU,iBAAiB,GAAA;QACzB,IAAI,IAAI,CAAC,YAAY,EAAE;YAAE;AAEzB,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAC3B,QAAA,IAAI,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC;AACtD,YAAA,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,KAAI;AACjB,gBAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;gBAC5B,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;AACzC,gBAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC;AAC9B,gBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;oBACnB,KAAK,EAAE,IAAI,CAAC,YAAY;oBACxB,WAAW,EAAE,IAAI,CAAC,kBAAkB;oBACpC,SAAS,EAAE,IAAI,CAAC,mBAAmB;AACpC,iBAAA,CAAC;AACF,gBAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE;gBAC9B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,0BAA0B,EAAE,SAAS,CAAC;YACxD,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,GAAyB,KAAI;AACnC,gBAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;AAC5B,gBAAA,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,8BAA8B,EAAE,OAAO,CAAC;YACzE,CAAC;AACF,SAAA,CAAC;IACJ;+GA7IW,8BAA8B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;mGAA9B,8BAA8B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,6BAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,eAAA,EAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,eAAA,EAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,QAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAeL,4BAA4B,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,EAAA,EAAA,YAAA,EAAA,YAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,YAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC5DlE,siPA0KA,EAAA,MAAA,EAAA,CAAA,84EAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EDvII,QAAQ,EAAA,IAAA,EAAA,MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACR,4BAA4B,EAAA,QAAA,EAAA,2BAAA,EAAA,MAAA,EAAA,CAAA,QAAA,CAAA,EAAA,OAAA,EAAA,CAAA,mBAAA,EAAA,gBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAC5B,iBAAiB,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,MAAA,EAAA,UAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,MAAA,EAAA,SAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,MAAA,EAAA,MAAA,EAAA,YAAA,EAAA,KAAA,EAAA,QAAA,EAAA,UAAA,EAAA,WAAA,CAAA,EAAA,OAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACjB,aAAa,EAAA,QAAA,EAAA,SAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,OAAA,EAAA,UAAA,EAAA,YAAA,EAAA,YAAA,EAAA,WAAA,EAAA,OAAA,EAAA,MAAA,EAAA,WAAA,EAAA,UAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAOJ,8BAA8B,EAAA,UAAA,EAAA,CAAA;kBAb1C,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,6BAA6B,EAAA,OAAA,EAC9B;wBACP,QAAQ;wBACR,4BAA4B;wBAC5B,iBAAiB;wBACjB,aAAa;AACd,qBAAA,EAAA,eAAA,EAGgB,uBAAuB,CAAC,MAAM,EAAA,OAAA,EACtC,CAAC,sBAAsB,CAAC,EAAA,QAAA,EAAA,siPAAA,EAAA,MAAA,EAAA,CAAA,84EAAA,CAAA,EAAA;;;AE9BnC,MAAM,aAAa,GAAG,CAAC;MAUV,uBAAuB,CAAA;AARpC,IAAA,WAAA,GAAA;AASmB,QAAA,IAAA,CAAA,GAAG,GAAG,MAAM,CAAC,wBAAwB,CAAC;AACtC,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACvB,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC;AAEtC,QAAA,IAAA,CAAA,MAAM,GAAG,KAAK,CAAC,QAAQ,EAAU;AACjC,QAAA,IAAA,CAAA,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC;AAEZ,QAAA,IAAA,CAAA,UAAU,GAAG,MAAM,CAAkB,EAAE,CAAC;AACxC,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC;AACjB,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC;QACtB,IAAA,CAAA,gBAAgB,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAU;QACrC,IAAA,CAAA,YAAY,GAAG,aAAa;QAC5B,IAAA,CAAA,iBAAiB,GAAG,iBAAiB;AAErC,QAAA,IAAA,CAAA,iBAAiB,GAAG,QAAQ,CAAC,MAC9C,IAAI,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,CAC1C;AA+CF,IAAA;IA7CW,cAAc,GAAA;QACtB,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,eAAe,CAAC,EAAE;YAC3C,UAAU,EAAE,IAAI,CAAC,KAAK;YACtB,WAAW,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE;AACvC,SAAA,CAAC;IACJ;IAEA,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC;AACF,aAAA,aAAa,CAAC;AACb,YAAA,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE;AACrB,YAAA,IAAI,EAAE,CAAC;AACP,YAAA,KAAK,EAAE,EAAE;SACV;AACA,aAAA,SAAS,CAAC;YACT,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAI;AACzB,gBAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1B,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AACrB,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YACzB,CAAC;YACD,KAAK,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AACrC,SAAA,CAAC;IACN;AAEU,IAAA,eAAe,CAAC,IAAmB,EAAA;AAC3C,QAAA,MAAM,IAAI,GAAG;AACX,YAAA,IAAI,CAAC,WAAW;AAChB,YAAA,IAAI,CAAC,SAAS;AACd,YAAA,IAAI,CAAC,YAAY;AAClB,SAAA,CAAC,MAAM,CAAC,OAAO,CAAC;AACjB,QAAA,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG;IAC/C;AAEU,IAAA,YAAY,CAAC,IAAY,EAAA;QACjC,QAAQ,IAAI;AACV,YAAA,KAAK,oBAAoB;AACvB,gBAAA,OAAO,SAAS;AAClB,YAAA,KAAK,iBAAiB;AACpB,gBAAA,OAAO,SAAS;AAClB,YAAA,KAAK,cAAc;AACjB,gBAAA,OAAO,SAAS;AAClB,YAAA;AACE,gBAAA,OAAO,OAAO;;IAEpB;+GA/DW,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAvB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,uBAAuB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,sBAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECvBpC,owFA4DA,EAAA,MAAA,EAAA,CAAA,mhBAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,ED3CY,mBAAmB,2EAAE,qBAAqB,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,CAAA,cAAA,EAAA,kBAAA,EAAA,iBAAA,EAAA,wBAAA,EAAA,kBAAA,EAAA,gBAAA,EAAA,kBAAA,EAAA,kBAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,cAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,sBAAA,EAAA,0BAAA,EAAA,WAAA,EAAA,aAAA,EAAA,oBAAA,EAAA,mBAAA,EAAA,mBAAA,EAAA,kBAAA,EAAA,kBAAA,EAAA,aAAA,EAAA,0BAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAMzC,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBARnC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,sBAAsB,EAAA,OAAA,EACvB,CAAC,mBAAmB,EAAE,qBAAqB,CAAC,EAAA,eAAA,EAGpC,uBAAuB,CAAC,MAAM,EAAA,OAAA,EACtC,CAAC,sBAAsB,CAAC,EAAA,QAAA,EAAA,owFAAA,EAAA,MAAA,EAAA,CAAA,mhBAAA,CAAA,EAAA;;;AEnBnC;AACO,MAAM,gBAAgB,GAAG;IAC9B,WAAW;IACX,QAAQ;IACR,aAAa;IACb,WAAW;CACH;AAIJ,SAAU,uBAAuB,CAAC,OAAe,EAAA;IACrD,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;AACxC,IAAA,IAAK,gBAAsC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AACzD,QAAA,OAAO,GAAqB;IAC9B;AACA,IAAA,OAAO,QAAQ;AACjB;AAEA;AACM,SAAU,gBAAgB,CAAC,OAAe,EAAA;AAC9C,IAAA,QAAQ,uBAAuB,CAAC,OAAO,CAAC;AACtC,QAAA,KAAK,WAAW;AACd,YAAA,OAAO,SAAS;AAClB,QAAA,KAAK,QAAQ;AACX,YAAA,OAAO,QAAQ;AACjB,QAAA,KAAK,aAAa;AAChB,YAAA,OAAO,QAAQ;AACjB,QAAA,KAAK,WAAW;AACd,YAAA,OAAO,QAAQ;QACjB,SAAS;YACP,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;AACxC,YAAA,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC;AAAE,gBAAA,OAAO,QAAQ;AAC7C,YAAA,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC;AAAE,gBAAA,OAAO,QAAQ;AAC/F,YAAA,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC;AAAE,gBAAA,OAAO,OAAO;AAC7C,YAAA,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;AAAE,gBAAA,OAAO,SAAS;AAC9F,YAAA,OAAO,SAAS;QAClB;;AAEJ;AAEM,SAAU,kBAAkB,CAAC,OAAe,EAAA;AAChD,IAAA,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE;AAC9B,IAAA,IAAI,CAAC,OAAO;AAAE,QAAA,OAAO,SAAS;AAC9B,IAAA,MAAM,KAAK,GAAG,uBAAuB,CAAC,OAAO,CAAC;IAC9C,IAAI,KAAK,KAAK,QAAQ;AAAE,QAAA,OAAO,OAAO;AACtC,IAAA,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AACvD;;MCVa,8BAA8B,CAAA;AAjB3C,IAAA,WAAA,GAAA;AAkBmB,QAAA,IAAA,CAAA,GAAG,GAAG,MAAM,CAAC,wBAAwB,CAAC;AACtC,QAAA,IAAA,CAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;AACzC,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC;AAC5B,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC;AAC9B,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;;AAGrB,QAAA,IAAA,CAAA,eAAe,GAAa,CAAC,SAAS,CAAC;AACvC,QAAA,IAAA,CAAA,qBAAqB,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM;AAEzC,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAuB,IAAI,CAAC;AAC3C,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC;AACtB,QAAA,IAAA,CAAA,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC;AAC7B,QAAA,IAAA,CAAA,kBAAkB,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAU;QAC7C,IAAA,CAAA,gBAAgB,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAU;QAE9C,IAAA,CAAA,aAAa,GAAG,aAAa;QAC7B,IAAA,CAAA,WAAW,GAAG,gBAAgB;QAC9B,IAAA,CAAA,YAAY,GAAG,kBAAkB;QACjC,IAAA,CAAA,cAAc,GAAG,cAAc;AAgE1C,IAAA;AA9DW,IAAA,aAAa,CAAC,IAA+B,EAAA;AACrD,QAAA,OAAO,eAAe,CAAC,IAAI,CAAC;IAC9B;AAEU,IAAA,gBAAgB,CAAC,MAAqB,EAAA;QAC9C,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,QAAQ,KAAK,GAAG,GAAG,MAAM,GAAG,OAAO;IACtF;AAEU,IAAA,mBAAmB,CAAC,MAAqB,EAAA;AACjD,QAAA,OAAO,MAAM,CAAC,SAAS,KAAK,SAAS,GAAG,eAAe,GAAG,WAAW;IACvE;IAEA,QAAQ,GAAA;AACN,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE;AACvD,QAAA,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,KAAI;AAChD,YAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;AACrB,YAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,QAAA,CAAC,CAAC;IACJ;IAEU,YAAY,GAAA;AACpB,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE;AACvB,QAAA,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE;YAAE;AAE5D,QAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5B,QAAA,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM;QACrB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,KACzB,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CACvD;QAED,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;YAC9C,IAAI,EAAE,MAAK;AACT,gBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC;gBAC7B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,yBAAyB,EAAE,SAAS,CAAC;YACvD,CAAC;YACD,KAAK,EAAE,MAAK;AACV,gBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC;gBAC7B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,KACzB,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CACjD;gBACD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,iCAAiC,EAAE,OAAO,CAAC;YAC7D,CAAC;AACF,SAAA,CAAC;IACJ;IAEU,iBAAiB,GAAA;QACzB,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE;AAC5B,QAAA,IAAI,CAAC,EAAE;YAAE;AACT,QAAA,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,KAAI;AAChD,YAAA,IAAI,IAAI;AAAE,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;AACjC,QAAA,CAAC,CAAC;IACJ;IAEU,MAAM,GAAA;AACd,QAAA,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,qBAAqB,EAAE,CAAC;IAC7F;AAEU,IAAA,cAAc,CAAC,GAAW,EAAA;QAClC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC;AAC9B,QAAA,MAAM,CAAC,GAAG,GAAG,GAAG,EAAE;AAClB,QAAA,OAAO,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;IAChD;+GAnFW,8BAA8B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAA9B,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,8BAA8B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,8BAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,sBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECtC3C,o2LAmJA,EAAA,MAAA,EAAA,CAAA,47BAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,ED3HQ,aAAa,sLACb,iBAAiB,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,MAAA,EAAA,UAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,MAAA,EAAA,SAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,MAAA,EAAA,MAAA,EAAA,YAAA,EAAA,KAAA,EAAA,QAAA,EAAA,UAAA,EAAA,WAAA,CAAA,EAAA,OAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACjB,iBAAiB,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACjB,qBAAqB,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,MAAA,EAAA,MAAA,EAAA,SAAA,EAAA,aAAA,EAAA,OAAA,EAAA,SAAA,EAAA,OAAA,EAAA,QAAA,EAAA,OAAA,EAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,SAAA,EAAA,IAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,WAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,OAAA,EAAA,OAAA,EAAA,MAAA,EAAA,QAAA,EAAA,QAAA,EAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACrB,8BAA8B,EAAA,QAAA,EAAA,6BAAA,EAAA,MAAA,EAAA,CAAA,QAAA,EAAA,SAAA,EAAA,YAAA,EAAA,OAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,eAAA,CAAA,EAAA,OAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAC9B,uBAAuB,gGACvB,mBAAmB,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,CAAA,OAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAQd,8BAA8B,EAAA,UAAA,EAAA,CAAA;kBAjB1C,SAAS;AACI,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,8BAA8B,EAAA,OAAA,EAC/B;wBACL,aAAa;wBACb,iBAAiB;wBACjB,iBAAiB;wBACjB,qBAAqB;wBACrB,8BAA8B;wBAC9B,uBAAuB;wBACvB,mBAAmB;AACtB,qBAAA,EAAA,eAAA,EAGgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EAC3C,EAAE,KAAK,EAAE,sBAAsB,EAAE,EAAA,OAAA,EAC5B,CAAC,sBAAsB,CAAC,EAAA,QAAA,EAAA,o2LAAA,EAAA,MAAA,EAAA,CAAA,47BAAA,CAAA,EAAA;;;;;"}
|