@memberjunction/ng-dashboards 6.2.0-edge.1 → 6.2.0-edge.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts.map +1 -1
  2. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js +3 -1
  3. package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js.map +1 -1
  4. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -1
  5. package/dist/AI/components/autotagging/tabs/sources-tab.component.js +1 -2
  6. package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -1
  7. package/dist/AI/components/rubric-drift-series.d.ts +32 -0
  8. package/dist/AI/components/rubric-drift-series.d.ts.map +1 -0
  9. package/dist/AI/components/rubric-drift-series.js +49 -0
  10. package/dist/AI/components/rubric-drift-series.js.map +1 -0
  11. package/dist/AI/components/rubric-drift.component.d.ts +42 -0
  12. package/dist/AI/components/rubric-drift.component.d.ts.map +1 -0
  13. package/dist/AI/components/rubric-drift.component.js +197 -0
  14. package/dist/AI/components/rubric-drift.component.js.map +1 -0
  15. package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
  16. package/dist/AI/components/tags/tags-resource.component.js +4 -3
  17. package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
  18. package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
  19. package/dist/AI/components/vectors/vector-management-resource.component.js +5 -2
  20. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  21. package/dist/Integration/components/connections/connections.component.d.ts +5 -0
  22. package/dist/Integration/components/connections/connections.component.d.ts.map +1 -1
  23. package/dist/Integration/components/connections/connections.component.js +151 -136
  24. package/dist/Integration/components/connections/connections.component.js.map +1 -1
  25. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts.map +1 -1
  26. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +3 -2
  27. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
  28. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.d.ts +11 -0
  29. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.d.ts.map +1 -1
  30. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.js +17 -1
  31. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.js.map +1 -1
  32. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js +52 -45
  33. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js.map +1 -1
  34. package/dist/QueryBrowser/query-browser-resource.component.d.ts +11 -0
  35. package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
  36. package/dist/QueryBrowser/query-browser-resource.component.js +47 -10
  37. package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
  38. package/dist/Rubrics/catalog-grid.d.ts +4 -0
  39. package/dist/Rubrics/catalog-grid.d.ts.map +1 -0
  40. package/dist/Rubrics/catalog-grid.js +22 -0
  41. package/dist/Rubrics/catalog-grid.js.map +1 -0
  42. package/dist/Rubrics/rubrics-dashboard.component.d.ts +31 -0
  43. package/dist/Rubrics/rubrics-dashboard.component.d.ts.map +1 -0
  44. package/dist/Rubrics/rubrics-dashboard.component.js +285 -0
  45. package/dist/Rubrics/rubrics-dashboard.component.js.map +1 -0
  46. package/dist/Rubrics/rubrics-resource.component.d.ts +13 -0
  47. package/dist/Rubrics/rubrics-resource.component.d.ts.map +1 -0
  48. package/dist/Rubrics/rubrics-resource.component.js +42 -0
  49. package/dist/Rubrics/rubrics-resource.component.js.map +1 -0
  50. package/dist/Rubrics/scales-dashboard.component.d.ts +34 -0
  51. package/dist/Rubrics/scales-dashboard.component.d.ts.map +1 -0
  52. package/dist/Rubrics/scales-dashboard.component.js +204 -0
  53. package/dist/Rubrics/scales-dashboard.component.js.map +1 -0
  54. package/dist/Rubrics/scales-resource.component.d.ts +13 -0
  55. package/dist/Rubrics/scales-resource.component.d.ts.map +1 -0
  56. package/dist/Rubrics/scales-resource.component.js +42 -0
  57. package/dist/Rubrics/scales-resource.component.js.map +1 -0
  58. package/dist/Testing/components/testing-analytics.component.d.ts +15 -0
  59. package/dist/Testing/components/testing-analytics.component.d.ts.map +1 -1
  60. package/dist/Testing/components/testing-analytics.component.js +465 -296
  61. package/dist/Testing/components/testing-analytics.component.js.map +1 -1
  62. package/dist/Testing/components/testing-review.component.d.ts +6 -0
  63. package/dist/Testing/components/testing-review.component.d.ts.map +1 -1
  64. package/dist/Testing/components/testing-review.component.js +289 -173
  65. package/dist/Testing/components/testing-review.component.js.map +1 -1
  66. package/dist/Testing/components/widgets/test-run-detail-panel.component.d.ts +8 -1
  67. package/dist/Testing/components/widgets/test-run-detail-panel.component.d.ts.map +1 -1
  68. package/dist/Testing/components/widgets/test-run-detail-panel.component.js +68 -43
  69. package/dist/Testing/components/widgets/test-run-detail-panel.component.js.map +1 -1
  70. package/dist/module.d.ts +23 -22
  71. package/dist/module.d.ts.map +1 -1
  72. package/dist/module.js +7 -0
  73. package/dist/module.js.map +1 -1
  74. package/dist/public-api.d.ts +1 -0
  75. package/dist/public-api.d.ts.map +1 -1
  76. package/dist/public-api.js +1 -0
  77. package/dist/public-api.js.map +1 -1
  78. package/dist/rubrics-dashboards.module.d.ts +17 -0
  79. package/dist/rubrics-dashboards.module.d.ts.map +1 -0
  80. package/dist/rubrics-dashboards.module.js +76 -0
  81. package/dist/rubrics-dashboards.module.js.map +1 -0
  82. package/package.json +70 -64
@@ -1 +1 @@
1
- {"version":3,"file":"testing-review.component.js","sourceRoot":"","sources":["../../../src/Testing/components/testing-review.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n OnInit,\n OnDestroy,\n Input,\n Output,\n EventEmitter,\n ChangeDetectorRef,\n ChangeDetectionStrategy\n} from '@angular/core';\nimport { Subject, Observable, combineLatest, BehaviorSubject } from 'rxjs';\nimport { takeUntil, map, shareReplay } from 'rxjs/operators';\nimport {\n TestingInstrumentationService,\n FeedbackPending,\n FeedbackStats,\n TestRunWithFeedbackSummary,\n EvaluationSummaryMetrics\n} from '../services/testing-instrumentation.service';\nimport { UUIDsEqual } from '@memberjunction/global';\n\ntype ViewMode = 'queue' | 'history';\ntype HistorySort = 'date' | 'rating' | 'test-name';\n\ninterface ReviewFormState {\n rating: number | null;\n isCorrect: boolean | null;\n comments: string;\n}\n\n@Component({\n standalone: false,\n selector: 'app-testing-review',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n @if (HideToolbar) {\n <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n } @else {\n <mj-page-layout>\n <mj-page-header\n Title=\"Human Review\"\n Icon=\"fa-solid fa-clipboard-check\"\n Subtitle=\"Human-in-the-loop review for test outcomes\">\n <div meta>\n @if (PendingCount > 0) {\n <mj-stat-badge\n Icon=\"fa-solid fa-hourglass-half\"\n [Count]=\"PendingCount\"\n Label=\"pending\"\n Variant=\"warning\">\n </mj-stat-badge>\n }\n </div>\n <div actions>\n <mj-refresh-button [Loading]=\"IsRefreshing\" (Clicked)=\"Refresh()\"></mj-refresh-button>\n </div>\n </mj-page-header>\n <mj-page-body>\n <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n </mj-page-body>\n </mj-page-layout>\n }\n\n <ng-template #content>\n <!-- Inner page content -->\n <div class=\"review-page\">\n\n <!-- KPI Summary Row -->\n @if (Metrics) {\n <div class=\"kpi-row\">\n <div class=\"kpi-card\">\n <div class=\"kpi-icon orange\">\n <i class=\"fa-solid fa-hourglass-half\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ Metrics.humanPendingCount }}</div>\n <div class=\"kpi-label\">Pending Review</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon green\">\n <i class=\"fa-solid fa-check-circle\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ Metrics.humanReviewedCount }}</div>\n <div class=\"kpi-label\">Reviewed</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon gold\">\n <i class=\"fa-solid fa-star\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ FormatDecimal(Metrics.humanAvgRating, 1) }}<span class=\"kpi-unit\">/10</span></div>\n <div class=\"kpi-label\">Avg Rating</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon blue\">\n <i class=\"fa-solid fa-handshake\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ FormatDecimal(Metrics.agreementRate, 0) }}<span class=\"kpi-unit\">%</span></div>\n <div class=\"kpi-label\">Agreement Rate</div>\n </div>\n </div>\n </div>\n }\n\n <!-- View Mode Toggle -->\n <div class=\"view-toggle-bar\">\n <div class=\"toggle-group\">\n <button class=\"toggle-btn\" [class.active]=\"CurrentView === 'queue'\" (click)=\"SetView('queue')\">\n <i class=\"fa-solid fa-list-check\"></i>\n Review Queue\n </button>\n <button class=\"toggle-btn\" [class.active]=\"CurrentView === 'history'\" (click)=\"SetView('history')\">\n <i class=\"fa-solid fa-clock-rotate-left\"></i>\n History\n </button>\n </div>\n </div>\n\n <!-- Review Queue View -->\n @if (CurrentView === 'queue') {\n <div class=\"content-card\">\n @if (PendingItems.length === 0) {\n <mj-empty-state Variant=\"success\"\n Title=\"All caught up!\"\n Message=\"No tests currently require human review.\" />\n } @else {\n <div class=\"queue-list\">\n @for (item of PendingItems; track item.testRunID) {\n <mj-accordion-panel\n Size=\"sm\"\n [FlushBody]=\"true\"\n [Expanded]=\"IsItemExpanded(item.testRunID)\"\n (ExpandedChange)=\"OnItemExpandedChange(item.testRunID, $event)\">\n <ng-template mjAccordionTitle>\n <div class=\"item-info\">\n <div class=\"item-name\">{{ item.testName }}</div>\n <div class=\"item-meta\">\n <span class=\"meta-time\">\n <i class=\"fa-solid fa-clock\"></i>\n {{ FormatRelativeTime(item.runDateTime) }}\n </span>\n <app-score-indicator [score]=\"item.automatedScore\" [showBar]=\"true\"></app-score-indicator>\n <app-test-status-badge [status]=\"$any(item.automatedStatus)\"></app-test-status-badge>\n </div>\n </div>\n </ng-template>\n <ng-template mjAccordionActions>\n <span class=\"reason-badge\" [class]=\"'reason-' + item.reason\">\n @if (item.reason === 'no-feedback') {\n <i class=\"fa-solid fa-comment-slash\"></i> No Feedback\n } @else if (item.reason === 'high-score-failed') {\n <i class=\"fa-solid fa-triangle-exclamation\"></i> Score Mismatch\n } @else {\n <i class=\"fa-solid fa-circle-question\"></i> Needs Verification\n }\n </span>\n </ng-template>\n <ng-template mjAccordionBody>\n <div class=\"review-form-panel\">\n <!-- Rating -->\n <div class=\"form-section\">\n <label class=\"form-label\">Rating</label>\n <div class=\"rating-row\">\n @for (n of RatingNumbers; track n) {\n <button class=\"rating-circle\"\n [class.selected]=\"FormState.rating != null && n <= FormState.rating\"\n [class.current]=\"FormState.rating === n\"\n (click)=\"SelectRating(n)\">\n {{ n }}\n </button>\n }\n @if (FormState.rating != null) {\n <span class=\"rating-display\">{{ FormState.rating }}/10</span>\n }\n </div>\n </div>\n\n <!-- Correctness -->\n <div class=\"form-section\">\n <label class=\"form-label\">Is the automated result correct?</label>\n <div class=\"correctness-row\">\n <button class=\"correctness-btn correct\"\n [class.active]=\"FormState.isCorrect === true\"\n (click)=\"SelectCorrectness(true)\">\n <i class=\"fa-solid fa-check\"></i> Correct\n </button>\n <button class=\"correctness-btn incorrect\"\n [class.active]=\"FormState.isCorrect === false\"\n (click)=\"SelectCorrectness(false)\">\n <i class=\"fa-solid fa-xmark\"></i> Incorrect\n </button>\n </div>\n </div>\n\n <!-- Notes -->\n <div class=\"form-section\">\n <label class=\"form-label\">Notes (optional)</label>\n <textarea class=\"notes-textarea\"\n rows=\"3\"\n placeholder=\"Add any comments about this evaluation...\"\n [value]=\"FormState.comments\"\n (input)=\"OnCommentsChange($event)\"></textarea>\n </div>\n\n <!-- Actions -->\n <div class=\"form-actions\">\n <button class=\"submit-btn\"\n [disabled]=\"!IsFormValid || IsSubmitting\"\n (click)=\"SubmitReview(item)\">\n <i class=\"fa-solid fa-paper-plane\"></i>\n {{ IsSubmitting ? 'Submitting...' : 'Submit' }}\n </button>\n <button class=\"skip-btn\" (click)=\"SkipItem()\">\n <i class=\"fa-solid fa-forward\"></i> Skip\n </button>\n </div>\n </div>\n </ng-template>\n </mj-accordion-panel>\n }\n </div>\n }\n </div>\n }\n\n <!-- History View -->\n @if (CurrentView === 'history') {\n <div class=\"content-card\">\n <!-- Filter Bar -->\n <div class=\"history-filters\">\n <div class=\"search-wrapper\">\n <i class=\"fa-solid fa-search\"></i>\n <input type=\"text\"\n placeholder=\"Search by test name...\"\n [value]=\"HistorySearchText\"\n (input)=\"OnHistorySearch($event)\" />\n </div>\n <div class=\"sort-control\">\n <label>Sort by:</label>\n <select [value]=\"HistorySortField\" (change)=\"OnHistorySortChange($event)\">\n <option value=\"date\">Date</option>\n <option value=\"rating\">Rating</option>\n <option value=\"test-name\">Test Name</option>\n </select>\n </div>\n </div>\n\n @if (FilteredHistoryItems.length === 0) {\n <mj-empty-state Icon=\"fa-solid fa-folder-open\"\n Title=\"No reviewed items\"\n Message=\"Reviewed tests will appear here once feedback is submitted.\" />\n } @else {\n <div class=\"history-list\">\n @for (item of FilteredHistoryItems; track item.id) {\n <div class=\"history-item\">\n <div class=\"history-item-main\">\n <div class=\"history-name\">{{ item.testName }}</div>\n <div class=\"history-date\">\n <i class=\"fa-solid fa-calendar\"></i>\n {{ FormatRelativeTime(item.runDateTime) }}\n </div>\n </div>\n <div class=\"history-rating\">\n <div class=\"rating-dots\">\n @for (n of RatingNumbers; track n) {\n <span class=\"rating-dot\" [class.filled]=\"item.humanRating != null && n <= item.humanRating\"></span>\n }\n </div>\n <span class=\"rating-label\">{{ item.humanRating ?? 0 }}/10</span>\n </div>\n <div class=\"history-verdict\">\n @if (item.humanIsCorrect === true) {\n <span class=\"verdict correct\">\n <i class=\"fa-solid fa-check\"></i> Correct\n </span>\n } @else if (item.humanIsCorrect === false) {\n <span class=\"verdict incorrect\">\n <i class=\"fa-solid fa-xmark\"></i> Incorrect\n </span>\n }\n </div>\n <div class=\"history-auto-score\">\n <app-score-indicator [score]=\"item.score\" [showBar]=\"true\"></app-score-indicator>\n </div>\n @if (item.humanComments) {\n <div class=\"history-comments\"\n [class.expanded]=\"ExpandedHistoryId === item.id\"\n (click)=\"ToggleHistoryComment(item.id)\">\n <p>{{ item.humanComments }}</p>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Calibration Insights -->\n <div class=\"calibration-section\">\n <h3>\n <i class=\"fa-solid fa-scale-balanced\"></i>\n Human vs Auto Agreement\n </h3>\n <div class=\"calibration-body\">\n <div class=\"gauge-display\">\n <div class=\"gauge-ring\">\n <svg viewBox=\"0 0 120 120\" class=\"gauge-svg\">\n <circle cx=\"60\" cy=\"60\" r=\"52\" fill=\"none\" class=\"gauge-track\" stroke-width=\"10\" />\n <circle cx=\"60\" cy=\"60\" r=\"52\" fill=\"none\"\n [attr.stroke]=\"AgreementColor\"\n stroke-width=\"10\"\n stroke-linecap=\"round\"\n [attr.stroke-dasharray]=\"AgreementDash\"\n stroke-dashoffset=\"0\"\n transform=\"rotate(-90 60 60)\" />\n </svg>\n <div class=\"gauge-value\">{{ FormatDecimal(AgreementRate, 0) }}%</div>\n </div>\n </div>\n <div class=\"calibration-text\">\n <p class=\"calibration-description\">\n Measures how often human reviewers agree with automated evaluation scores.\n </p>\n @if (AgreementRate < 70) {\n <mj-alert Variant=\"warning\">\n Low agreement may indicate evaluation criteria need refinement.\n </mj-alert>\n }\n </div>\n </div>\n </div>\n </div>\n </ng-template>\n `,\n styles: [`\n :host {\n display: block;\n height: 100%;\n }\n\n .review-page {\n padding: 20px;\n height: 100%;\n overflow-y: auto;\n background: var(--mj-bg-surface-card);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n /* Page Header */\n .page-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n background: var(--mj-bg-surface);\n padding: 20px;\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n }\n\n .header-left {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .header-left h2 {\n margin: 0;\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .header-left h2 i {\n color: var(--mj-brand-primary);\n }\n\n .pending-badge {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 14px;\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-warning);\n border-radius: 20px;\n }\n\n .badge-count {\n background: var(--mj-status-warning);\n color: var(--mj-text-inverse);\n min-width: 24px;\n height: 24px;\n padding: 0 6px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 700;\n }\n\n .badge-text {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-status-warning);\n }\n\n .refresh-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 18px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-muted);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .refresh-btn:hover:not(:disabled) {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n }\n\n .refresh-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n /* KPI Row */\n .kpi-row {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 16px;\n margin-bottom: 20px;\n }\n\n .kpi-card {\n background: var(--mj-bg-surface);\n padding: 20px;\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .kpi-icon {\n width: 48px;\n height: 48px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 20px;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n }\n\n .kpi-icon.orange { background: var(--mj-status-warning); }\n .kpi-icon.green { background: var(--mj-status-success); }\n .kpi-icon.gold { background: var(--mj-status-warning); }\n .kpi-icon.blue { background: var(--mj-brand-primary); }\n\n .kpi-content {\n flex: 1;\n min-width: 0;\n }\n\n .kpi-value {\n font-size: 26px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1;\n margin-bottom: 4px;\n }\n\n .kpi-unit {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-muted);\n }\n\n .kpi-label {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n /* View Toggle */\n .view-toggle-bar {\n margin-bottom: 20px;\n }\n\n .toggle-group {\n display: inline-flex;\n background: var(--mj-bg-surface);\n border-radius: 10px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n }\n\n .toggle-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 24px;\n border: none;\n background: var(--mj-bg-surface);\n color: var(--mj-text-muted);\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .toggle-btn:hover:not(.active) {\n background: var(--mj-bg-surface-card);\n }\n\n .toggle-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n }\n\n /* Content Card */\n .content-card {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n margin-bottom: 20px;\n }\n\n /* Queue List */\n .queue-list {\n max-height: 600px;\n overflow-y: auto;\n }\n\n /* Queue items migrated to <mj-accordion-panel> — the panel owns the row\n chrome (border, hover, expanded state) and the chevron toggle, so the\n bespoke .queue-item / .queue-item-header / .expand-toggle styles were\n removed. */\n\n .item-info {\n flex: 1;\n min-width: 0;\n }\n\n .item-name {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 6px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .item-meta {\n display: flex;\n gap: 14px;\n font-size: 12px;\n color: var(--mj-text-muted);\n align-items: center;\n flex-wrap: wrap;\n }\n\n .meta-time {\n display: flex;\n align-items: center;\n gap: 5px;\n }\n\n /* .item-actions-area removed — the reason badge now lives in the accordion's\n [mjAccordionActions] slot, which provides its own flex container. */\n\n .reason-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n }\n\n .reason-no-feedback {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n .reason-high-score-failed {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n }\n\n .reason-low-score-passed {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n }\n\n /* .expand-toggle removed — the bespoke chevron was replaced by\n <mj-accordion-panel>'s built-in chevron. */\n\n /* Review Form — rendered in the accordion body ([FlushBody]=\"true\"), so it\n supplies its own padding; the header/body separator is owned by the\n accordion (border-top removed to avoid a doubled line). */\n .review-form-panel {\n padding: 20px 20px 20px 36px;\n background: var(--mj-bg-surface);\n }\n\n .form-section {\n margin-bottom: 20px;\n }\n\n .form-section:last-of-type {\n margin-bottom: 16px;\n }\n\n .form-label {\n display: block;\n font-size: 12px;\n font-weight: 700;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 10px;\n }\n\n /* Rating Circles */\n .rating-row {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .rating-circle {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: 2px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-disabled);\n font-size: 13px;\n font-weight: 700;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.15s ease;\n }\n\n .rating-circle:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n transform: scale(1.1);\n }\n\n .rating-circle.selected {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n }\n\n .rating-circle.current {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n color: var(--mj-text-inverse);\n box-shadow: var(--mj-shadow-sm);\n }\n\n .rating-display {\n margin-left: 12px;\n font-size: 16px;\n font-weight: 700;\n color: var(--mj-text-primary);\n }\n\n /* Correctness Buttons */\n .correctness-row {\n display: flex;\n gap: 12px;\n }\n\n .correctness-btn {\n flex: 1;\n max-width: 200px;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 12px 20px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 10px;\n background: var(--mj-bg-surface-card);\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .correctness-btn.correct:hover,\n .correctness-btn.correct.active {\n border-color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n\n .correctness-btn.incorrect:hover,\n .correctness-btn.incorrect.active {\n border-color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n\n /* Notes */\n .notes-textarea {\n width: 100%;\n max-width: 500px;\n padding: 12px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n font-family: inherit;\n resize: vertical;\n min-height: 72px;\n box-sizing: border-box;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n }\n\n .notes-textarea:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n\n /* Form Actions */\n .form-actions {\n display: flex;\n gap: 12px;\n }\n\n .submit-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 11px 22px;\n border: none;\n border-radius: 8px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .submit-btn:hover:not(:disabled) {\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-md);\n }\n\n .submit-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .skip-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 11px 20px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-muted);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .skip-btn:hover {\n border-color: var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n }\n\n /* History Filters */\n .history-filters {\n display: flex;\n gap: 16px;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n align-items: center;\n }\n\n .search-wrapper {\n flex: 1;\n position: relative;\n display: flex;\n align-items: center;\n }\n\n .search-wrapper > i {\n position: absolute;\n left: 12px;\n color: var(--mj-text-disabled);\n font-size: 13px;\n }\n\n .search-wrapper input {\n width: 100%;\n padding: 10px 12px 10px 36px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 13px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n }\n\n .search-wrapper input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n\n .sort-control {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: var(--mj-text-muted);\n flex-shrink: 0;\n }\n\n .sort-control select {\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 12px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n }\n\n /* History List */\n .history-list {\n max-height: 600px;\n overflow-y: auto;\n }\n\n .history-item {\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n display: flex;\n align-items: center;\n gap: 16px;\n flex-wrap: wrap;\n }\n\n .history-item:last-child {\n border-bottom: none;\n }\n\n .history-item-main {\n flex: 1;\n min-width: 160px;\n }\n\n .history-name {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n }\n\n .history-date {\n font-size: 12px;\n color: var(--mj-text-disabled);\n display: flex;\n align-items: center;\n gap: 5px;\n }\n\n .history-rating {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .rating-dots {\n display: flex;\n gap: 3px;\n }\n\n .rating-dot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: var(--mj-border-default);\n }\n\n .rating-dot.filled {\n background: var(--mj-status-warning);\n }\n\n .rating-label {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-muted);\n }\n\n .history-verdict {\n flex-shrink: 0;\n }\n\n .verdict {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 5px 12px;\n border-radius: 14px;\n font-size: 11px;\n font-weight: 600;\n }\n\n .verdict.correct {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n\n .verdict.incorrect {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n\n .history-auto-score {\n flex-shrink: 0;\n }\n\n .history-comments {\n width: 100%;\n margin-top: 8px;\n padding: 10px 14px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n border-left: 3px solid var(--mj-brand-primary);\n cursor: pointer;\n }\n\n .history-comments p {\n margin: 0;\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .history-comments.expanded p {\n white-space: normal;\n }\n\n /* Calibration Section */\n .calibration-section {\n background: var(--mj-bg-surface);\n padding: 24px;\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n }\n\n .calibration-section h3 {\n margin: 0 0 20px 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 10px;\n }\n\n .calibration-section h3 i {\n color: var(--mj-brand-primary);\n }\n\n .calibration-body {\n display: flex;\n align-items: center;\n gap: 32px;\n }\n\n .gauge-display {\n flex-shrink: 0;\n }\n\n .gauge-ring {\n position: relative;\n width: 120px;\n height: 120px;\n }\n\n .gauge-svg {\n width: 100%;\n height: 100%;\n }\n\n .gauge-track {\n stroke: var(--mj-border-default);\n }\n\n .gauge-value {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 24px;\n font-weight: 800;\n color: var(--mj-text-primary);\n }\n\n .calibration-text {\n flex: 1;\n }\n\n .calibration-description {\n margin: 0 0 12px 0;\n font-size: 14px;\n color: var(--mj-text-muted);\n line-height: 1.6;\n }\n\n\n /* (Removed .queue-item fadeIn animation — the queue-item wrapper no longer\n exists; the accordion panel owns its own reveal.) */\n\n /* Responsive */\n @media (max-width: 1024px) {\n .kpi-row {\n grid-template-columns: repeat(2, 1fr);\n }\n }\n\n @media (max-width: 768px) {\n .review-page {\n padding: 16px;\n }\n\n .page-header {\n flex-direction: column;\n gap: 16px;\n align-items: flex-start;\n }\n\n .kpi-row {\n grid-template-columns: 1fr 1fr;\n }\n\n .kpi-card {\n padding: 16px;\n }\n\n .kpi-value {\n font-size: 22px;\n }\n\n .correctness-row {\n flex-direction: column;\n }\n\n .correctness-btn {\n max-width: 100%;\n }\n\n .history-item {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .calibration-body {\n flex-direction: column;\n align-items: center;\n text-align: center;\n }\n }\n `]\n})\nexport class TestingReviewComponent implements OnInit, OnDestroy {\n @Input() InitialState: Record<string, unknown> | null = null;\n\n /** @deprecated Use {@link InitialState}. */\n @Input() set initialState(value: Record<string, unknown> | null) {\n this.InitialState = value;\n }\n /** @deprecated Use {@link InitialState}. */\n get initialState(): Record<string, unknown> | null {\n return this.InitialState;\n }\n /** When true, the inner bespoke .page-header is hidden — the parent shell owns the chrome. */\n @Input() HideToolbar = false;\n @Output() StateChange = new EventEmitter<Record<string, unknown>>();\n\n /**\n * @deprecated Use {@link StateChange}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (stateChange) keeps working. Must stay AFTER StateChange: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() stateChange = this.StateChange;\n\n private destroy$ = new Subject<void>();\n\n // View state\n CurrentView: ViewMode = 'queue';\n ExpandedItemId: string | null = null;\n ExpandedHistoryId: string | null = null;\n IsRefreshing = false;\n IsSubmitting = false;\n HistorySearchText = '';\n HistorySortField: HistorySort = 'date';\n\n // Form state for active review\n FormState: ReviewFormState = { rating: null, isCorrect: null, comments: '' };\n\n // Data\n PendingItems: FeedbackPending[] = [];\n HistoryItems: TestRunWithFeedbackSummary[] = [];\n FilteredHistoryItems: TestRunWithFeedbackSummary[] = [];\n Metrics: EvaluationSummaryMetrics | null = null;\n PendingCount = 0;\n\n // Constants\n readonly RatingNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n\n constructor(\n private instrumentationService: TestingInstrumentationService,\n private cdr: ChangeDetectorRef\n ) {}\n\n ngOnInit(): void {\n this.restoreState();\n this.setupSubscriptions();\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n // ------------------------------------------------------------------\n // Computed properties\n // ------------------------------------------------------------------\n\n get IsFormValid(): boolean {\n return this.FormState.rating != null && this.FormState.isCorrect != null;\n }\n\n get AgreementRate(): number {\n return this.Metrics?.agreementRate ?? 0;\n }\n\n get AgreementColor(): string {\n const rate = this.AgreementRate;\n if (rate >= 80) return '#22c55e';\n if (rate >= 60) return '#eab308';\n return '#ef4444';\n }\n\n get AgreementDash(): string {\n const circumference = 2 * Math.PI * 52; // r=52\n const filled = (this.AgreementRate / 100) * circumference;\n return `${filled} ${circumference}`;\n }\n\n // ------------------------------------------------------------------\n // Setup\n // ------------------------------------------------------------------\n\n private restoreState(): void {\n if (!this.InitialState) return;\n const view = this.InitialState['viewMode'] as string | undefined;\n if (view === 'queue' || view === 'history') {\n this.CurrentView = view;\n }\n }\n\n private setupSubscriptions(): void {\n this.instrumentationService.pendingFeedback$\n .pipe(takeUntil(this.destroy$))\n .subscribe(items => {\n this.PendingItems = items;\n this.PendingCount = items.length;\n this.emitState();\n this.cdr.markForCheck();\n });\n\n this.instrumentationService.evaluationMetrics$\n .pipe(takeUntil(this.destroy$))\n .subscribe(metrics => {\n this.Metrics = metrics;\n this.emitState();\n this.cdr.markForCheck();\n });\n\n this.instrumentationService.testRunsWithFeedback$\n .pipe(takeUntil(this.destroy$))\n .subscribe(runs => {\n this.HistoryItems = runs.filter(r => r.hasHumanFeedback);\n this.applyHistoryFilters();\n this.cdr.markForCheck();\n });\n }\n\n // ------------------------------------------------------------------\n // View toggling\n // ------------------------------------------------------------------\n\n SetView(mode: ViewMode): void {\n this.CurrentView = mode;\n this.ExpandedItemId = null;\n this.emitState();\n this.cdr.markForCheck();\n }\n\n // ------------------------------------------------------------------\n // Queue interactions\n // ------------------------------------------------------------------\n\n IsItemExpanded(testRunID: string): boolean {\n return UUIDsEqual(this.ExpandedItemId, testRunID);\n }\n\n /**\n * Accordion ExpandedChange handler for a review queue item. Single-expand\n * (radio-like) model: expanding an item makes it the sole open one (the\n * template's `IsItemExpanded` binding collapses the prior one) and resets the\n * review form for the newly-opened item; collapsing the open item clears it.\n * OnPush — drives change detection. Preserves the original ToggleExpand side\n * effect (resetForm on open).\n */\n OnItemExpandedChange(testRunID: string, expanded: boolean): void {\n if (expanded) {\n this.ExpandedItemId = testRunID;\n this.resetForm();\n } else if (UUIDsEqual(this.ExpandedItemId, testRunID)) {\n this.ExpandedItemId = null;\n }\n this.cdr.markForCheck();\n }\n\n SelectRating(n: number): void {\n this.FormState = { ...this.FormState, rating: n };\n this.cdr.markForCheck();\n }\n\n SelectCorrectness(value: boolean): void {\n this.FormState = { ...this.FormState, isCorrect: value };\n this.cdr.markForCheck();\n }\n\n OnCommentsChange(event: Event): void {\n const target = event.target as HTMLTextAreaElement;\n this.FormState = { ...this.FormState, comments: target.value };\n }\n\n async SubmitReview(item: FeedbackPending): Promise<void> {\n if (!this.IsFormValid || this.IsSubmitting) return;\n\n this.IsSubmitting = true;\n this.cdr.markForCheck();\n\n try {\n const success = await this.instrumentationService.submitFeedback(\n item.testRunID,\n this.FormState.rating!,\n this.FormState.isCorrect!,\n this.FormState.comments\n );\n\n if (success) {\n this.ExpandedItemId = null;\n this.resetForm();\n }\n } finally {\n this.IsSubmitting = false;\n this.cdr.markForCheck();\n }\n }\n\n SkipItem(): void {\n const currentIndex = this.PendingItems.findIndex(\n i => UUIDsEqual(i.testRunID, this.ExpandedItemId)\n );\n this.ExpandedItemId = null;\n this.resetForm();\n\n // Expand the next item if available\n if (currentIndex >= 0 && currentIndex + 1 < this.PendingItems.length) {\n this.ExpandedItemId = this.PendingItems[currentIndex + 1].testRunID;\n }\n this.cdr.markForCheck();\n }\n\n // ------------------------------------------------------------------\n // History interactions\n // ------------------------------------------------------------------\n\n OnHistorySearch(event: Event): void {\n const target = event.target as HTMLInputElement;\n this.HistorySearchText = target.value;\n this.applyHistoryFilters();\n this.emitState();\n this.cdr.markForCheck();\n }\n\n OnHistorySortChange(event: Event): void {\n const target = event.target as HTMLSelectElement;\n this.HistorySortField = target.value as HistorySort;\n this.applyHistoryFilters();\n this.cdr.markForCheck();\n }\n\n ToggleHistoryComment(id: string): void {\n this.ExpandedHistoryId = this.ExpandedHistoryId === id ? null : id;\n this.cdr.markForCheck();\n }\n\n // ------------------------------------------------------------------\n // Refresh\n // ------------------------------------------------------------------\n\n Refresh(): void {\n this.IsRefreshing = true;\n this.cdr.markForCheck();\n this.instrumentationService.refresh();\n\n setTimeout(() => {\n this.IsRefreshing = false;\n this.cdr.markForCheck();\n }, 1500);\n }\n\n // ------------------------------------------------------------------\n // Formatting helpers\n // ------------------------------------------------------------------\n\n FormatDecimal(value: number | undefined | null, decimals: number): string {\n if (value == null) return '0';\n return value.toFixed(decimals);\n }\n\n FormatRelativeTime(date: Date): string {\n const now = Date.now();\n const then = date instanceof Date ? date.getTime() : new Date(date).getTime();\n const diffMs = now - then;\n const diffMin = Math.floor(diffMs / 60000);\n\n if (diffMin < 1) return 'just now';\n if (diffMin < 60) return `${diffMin}m ago`;\n\n const diffHours = Math.floor(diffMin / 60);\n if (diffHours < 24) return `${diffHours}h ago`;\n\n const diffDays = Math.floor(diffHours / 24);\n if (diffDays < 7) return `${diffDays}d ago`;\n\n const diffWeeks = Math.floor(diffDays / 7);\n if (diffWeeks < 4) return `${diffWeeks}w ago`;\n\n const diffMonths = Math.floor(diffDays / 30);\n return `${diffMonths}mo ago`;\n }\n\n // ------------------------------------------------------------------\n // Private helpers\n // ------------------------------------------------------------------\n\n private resetForm(): void {\n this.FormState = { rating: null, isCorrect: null, comments: '' };\n }\n\n private applyHistoryFilters(): void {\n let items = [...this.HistoryItems];\n\n // Search filter\n if (this.HistorySearchText) {\n const term = this.HistorySearchText.toLowerCase();\n items = items.filter(i => i.testName.toLowerCase().includes(term));\n }\n\n // Sort\n items.sort((a, b) => {\n switch (this.HistorySortField) {\n case 'date':\n return b.runDateTime.getTime() - a.runDateTime.getTime();\n case 'rating':\n return (b.humanRating ?? 0) - (a.humanRating ?? 0);\n case 'test-name':\n return a.testName.localeCompare(b.testName);\n default:\n return 0;\n }\n });\n\n this.FilteredHistoryItems = items;\n }\n\n private emitState(): void {\n this.StateChange.emit({\n viewMode: this.CurrentView,\n // Richer state for the dashboard's agent context (queue depth, reviewed\n // count, avg human rating, agreement rate, history search).\n pendingCount: this.PendingCount,\n reviewedCount: this.Metrics?.humanReviewedCount ?? 0,\n averageHumanRating: this.Metrics?.humanAvgRating ?? 0,\n agreementRate: this.Metrics?.agreementRate ?? 0,\n historySearchText: this.HistorySearchText\n });\n }\n}\n"]}
1
+ {"version":3,"file":"testing-review.component.js","sourceRoot":"","sources":["../../../src/Testing/components/testing-review.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n OnInit,\n OnDestroy,\n Input,\n Output,\n EventEmitter,\n ChangeDetectorRef,\n ChangeDetectionStrategy\n} from '@angular/core';\nimport { Subject, Observable, combineLatest, BehaviorSubject } from 'rxjs';\nimport { takeUntil, map, shareReplay } from 'rxjs/operators';\nimport {\n TestingInstrumentationService,\n FeedbackPending,\n FeedbackStats,\n TestRunWithFeedbackSummary,\n EvaluationSummaryMetrics\n} from '../services/testing-instrumentation.service';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { CompositeKey, RunView } from '@memberjunction/core';\nimport { SharedService } from '@memberjunction/ng-shared';\nimport { CohortDisagreement, type DisagreementItem } from '@memberjunction/ng-testing';\n\ntype ViewMode = 'queue' | 'history';\ntype HistorySort = 'date' | 'rating' | 'test-name';\n\ninterface ReviewFormState {\n rating: number | null;\n isCorrect: boolean | null;\n comments: string;\n}\n\n@Component({\n standalone: false,\n selector: 'app-testing-review',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n @if (HideToolbar) {\n <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n } @else {\n <mj-page-layout>\n <mj-page-header\n Title=\"Human Review\"\n Icon=\"fa-solid fa-clipboard-check\"\n Subtitle=\"Human-in-the-loop review for test outcomes\">\n <div meta>\n @if (PendingCount > 0) {\n <mj-stat-badge\n Icon=\"fa-solid fa-hourglass-half\"\n [Count]=\"PendingCount\"\n Label=\"pending\"\n Variant=\"warning\">\n </mj-stat-badge>\n }\n </div>\n <div actions>\n <mj-refresh-button [Loading]=\"IsRefreshing\" (Clicked)=\"Refresh()\"></mj-refresh-button>\n </div>\n </mj-page-header>\n <mj-page-body>\n <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n </mj-page-body>\n </mj-page-layout>\n }\n\n <ng-template #content>\n <!-- Inner page content -->\n <div class=\"review-page\">\n @if (DisagreementError) {\n <p role=\"alert\">{{ DisagreementError }}</p>\n }\n @if (Disagreement.length) {\n <section class=\"rubric-disagreement\" aria-label=\"Rubric disagreement\">\n <h3>Rubric disagreement</h3>\n @for (row of Disagreement; track $index) {\n <p>\n {{ row.name }}\n CriterionKey <code>{{ row.key }}</code>\n — human {{ row.humanMean }} / AI {{ row.aiMean }}\n @if (row.runId) {\n <button type=\"button\" mjButton variant=\"secondary\" size=\"sm\" (click)=\"OpenRun(row.runId)\">Open run</button>\n }\n </p>\n }\n </section>\n }\n\n <!-- KPI Summary Row -->\n @if (Metrics) {\n <div class=\"kpi-row\">\n <div class=\"kpi-card\">\n <div class=\"kpi-icon orange\">\n <i class=\"fa-solid fa-hourglass-half\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ Metrics.humanPendingCount }}</div>\n <div class=\"kpi-label\">Pending Review</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon green\">\n <i class=\"fa-solid fa-check-circle\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ Metrics.humanReviewedCount }}</div>\n <div class=\"kpi-label\">Reviewed</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon gold\">\n <i class=\"fa-solid fa-star\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ FormatDecimal(Metrics.humanAvgRating, 1) }}<span class=\"kpi-unit\">/10</span></div>\n <div class=\"kpi-label\">Avg Rating</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon blue\">\n <i class=\"fa-solid fa-handshake\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ FormatDecimal(Metrics.agreementRate, 0) }}<span class=\"kpi-unit\">%</span></div>\n <div class=\"kpi-label\">Agreement Rate</div>\n </div>\n </div>\n </div>\n }\n\n <!-- View Mode Toggle -->\n <div class=\"view-toggle-bar\">\n <div class=\"toggle-group\">\n <button class=\"toggle-btn\" [class.active]=\"CurrentView === 'queue'\" (click)=\"SetView('queue')\">\n <i class=\"fa-solid fa-list-check\"></i>\n Review Queue\n </button>\n <button class=\"toggle-btn\" [class.active]=\"CurrentView === 'history'\" (click)=\"SetView('history')\">\n <i class=\"fa-solid fa-clock-rotate-left\"></i>\n History\n </button>\n </div>\n </div>\n\n <!-- Review Queue View -->\n @if (CurrentView === 'queue') {\n <div class=\"content-card\">\n @if (PendingItems.length === 0) {\n <mj-empty-state Variant=\"success\"\n Title=\"All caught up!\"\n Message=\"No tests currently require human review.\" />\n } @else {\n <div class=\"queue-list\">\n @for (item of PendingItems; track item.testRunID) {\n <mj-accordion-panel\n Size=\"sm\"\n [FlushBody]=\"true\"\n [Expanded]=\"IsItemExpanded(item.testRunID)\"\n (ExpandedChange)=\"OnItemExpandedChange(item.testRunID, $event)\">\n <ng-template mjAccordionTitle>\n <div class=\"item-info\">\n <div class=\"item-name\">{{ item.testName }}</div>\n <div class=\"item-meta\">\n <span class=\"meta-time\">\n <i class=\"fa-solid fa-clock\"></i>\n {{ FormatRelativeTime(item.runDateTime) }}\n </span>\n <app-score-indicator [score]=\"item.automatedScore\" [showBar]=\"true\"></app-score-indicator>\n <app-test-status-badge [status]=\"$any(item.automatedStatus)\"></app-test-status-badge>\n </div>\n </div>\n </ng-template>\n <ng-template mjAccordionActions>\n <span class=\"reason-badge\" [class]=\"'reason-' + item.reason\">\n @if (item.reason === 'no-feedback') {\n <i class=\"fa-solid fa-comment-slash\"></i> No Feedback\n } @else if (item.reason === 'high-score-failed') {\n <i class=\"fa-solid fa-triangle-exclamation\"></i> Score Mismatch\n } @else {\n <i class=\"fa-solid fa-circle-question\"></i> Needs Verification\n }\n </span>\n </ng-template>\n <ng-template mjAccordionBody>\n <div class=\"review-form-panel\">\n <!-- Rating -->\n <div class=\"form-section\">\n <label class=\"form-label\">Rating</label>\n <div class=\"rating-row\">\n @for (n of RatingNumbers; track n) {\n <button class=\"rating-circle\"\n [class.selected]=\"FormState.rating != null && n <= FormState.rating\"\n [class.current]=\"FormState.rating === n\"\n (click)=\"SelectRating(n)\">\n {{ n }}\n </button>\n }\n @if (FormState.rating != null) {\n <span class=\"rating-display\">{{ FormState.rating }}/10</span>\n }\n </div>\n </div>\n\n <!-- Correctness -->\n <div class=\"form-section\">\n <label class=\"form-label\">Is the automated result correct?</label>\n <div class=\"correctness-row\">\n <button class=\"correctness-btn correct\"\n [class.active]=\"FormState.isCorrect === true\"\n (click)=\"SelectCorrectness(true)\">\n <i class=\"fa-solid fa-check\"></i> Correct\n </button>\n <button class=\"correctness-btn incorrect\"\n [class.active]=\"FormState.isCorrect === false\"\n (click)=\"SelectCorrectness(false)\">\n <i class=\"fa-solid fa-xmark\"></i> Incorrect\n </button>\n </div>\n </div>\n\n <!-- Notes -->\n <div class=\"form-section\">\n <label class=\"form-label\">Notes (optional)</label>\n <textarea class=\"notes-textarea\"\n rows=\"3\"\n placeholder=\"Add any comments about this evaluation...\"\n [value]=\"FormState.comments\"\n (input)=\"OnCommentsChange($event)\"></textarea>\n </div>\n\n <!-- Actions -->\n <div class=\"form-actions\">\n <button class=\"submit-btn\"\n [disabled]=\"!IsFormValid || IsSubmitting\"\n (click)=\"SubmitReview(item)\">\n <i class=\"fa-solid fa-paper-plane\"></i>\n {{ IsSubmitting ? 'Submitting...' : 'Submit' }}\n </button>\n <button class=\"skip-btn\" (click)=\"SkipItem()\">\n <i class=\"fa-solid fa-forward\"></i> Skip\n </button>\n </div>\n </div>\n </ng-template>\n </mj-accordion-panel>\n }\n </div>\n }\n </div>\n }\n\n <!-- History View -->\n @if (CurrentView === 'history') {\n <div class=\"content-card\">\n <!-- Filter Bar -->\n <div class=\"history-filters\">\n <div class=\"search-wrapper\">\n <i class=\"fa-solid fa-search\"></i>\n <input type=\"text\"\n placeholder=\"Search by test name...\"\n [value]=\"HistorySearchText\"\n (input)=\"OnHistorySearch($event)\" />\n </div>\n <div class=\"sort-control\">\n <label>Sort by:</label>\n <select [value]=\"HistorySortField\" (change)=\"OnHistorySortChange($event)\">\n <option value=\"date\">Date</option>\n <option value=\"rating\">Rating</option>\n <option value=\"test-name\">Test Name</option>\n </select>\n </div>\n </div>\n\n @if (FilteredHistoryItems.length === 0) {\n <mj-empty-state Icon=\"fa-solid fa-folder-open\"\n Title=\"No reviewed items\"\n Message=\"Reviewed tests will appear here once feedback is submitted.\" />\n } @else {\n <div class=\"history-list\">\n @for (item of FilteredHistoryItems; track item.id) {\n <div class=\"history-item\">\n <div class=\"history-item-main\">\n <div class=\"history-name\">{{ item.testName }}</div>\n <div class=\"history-date\">\n <i class=\"fa-solid fa-calendar\"></i>\n {{ FormatRelativeTime(item.runDateTime) }}\n </div>\n </div>\n <div class=\"history-rating\">\n <div class=\"rating-dots\">\n @for (n of RatingNumbers; track n) {\n <span class=\"rating-dot\" [class.filled]=\"item.humanRating != null && n <= item.humanRating\"></span>\n }\n </div>\n <span class=\"rating-label\">{{ item.humanRating ?? 0 }}/10</span>\n </div>\n <div class=\"history-verdict\">\n @if (item.humanIsCorrect === true) {\n <span class=\"verdict correct\">\n <i class=\"fa-solid fa-check\"></i> Correct\n </span>\n } @else if (item.humanIsCorrect === false) {\n <span class=\"verdict incorrect\">\n <i class=\"fa-solid fa-xmark\"></i> Incorrect\n </span>\n }\n </div>\n <div class=\"history-auto-score\">\n <app-score-indicator [score]=\"item.score\" [showBar]=\"true\"></app-score-indicator>\n </div>\n @if (item.humanComments) {\n <div class=\"history-comments\"\n [class.expanded]=\"ExpandedHistoryId === item.id\"\n (click)=\"ToggleHistoryComment(item.id)\">\n <p>{{ item.humanComments }}</p>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Calibration Insights -->\n <div class=\"calibration-section\">\n <h3>\n <i class=\"fa-solid fa-scale-balanced\"></i>\n Human vs Auto Agreement\n </h3>\n <div class=\"calibration-body\">\n <div class=\"gauge-display\">\n <div class=\"gauge-ring\">\n <svg viewBox=\"0 0 120 120\" class=\"gauge-svg\">\n <circle cx=\"60\" cy=\"60\" r=\"52\" fill=\"none\" class=\"gauge-track\" stroke-width=\"10\" />\n <circle cx=\"60\" cy=\"60\" r=\"52\" fill=\"none\"\n [attr.stroke]=\"AgreementColor\"\n stroke-width=\"10\"\n stroke-linecap=\"round\"\n [attr.stroke-dasharray]=\"AgreementDash\"\n stroke-dashoffset=\"0\"\n transform=\"rotate(-90 60 60)\" />\n </svg>\n <div class=\"gauge-value\">{{ FormatDecimal(AgreementRate, 0) }}%</div>\n </div>\n </div>\n <div class=\"calibration-text\">\n <p class=\"calibration-description\">\n Measures how often human reviewers agree with automated evaluation scores.\n </p>\n @if (AgreementRate < 70) {\n <mj-alert Variant=\"warning\">\n Low agreement may indicate evaluation criteria need refinement.\n </mj-alert>\n }\n </div>\n </div>\n </div>\n </div>\n </ng-template>\n `,\n styles: [`\n :host {\n display: block;\n height: 100%;\n }\n\n .review-page {\n padding: 20px;\n height: 100%;\n overflow-y: auto;\n background: var(--mj-bg-surface-card);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n /* Page Header */\n .page-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n background: var(--mj-bg-surface);\n padding: 20px;\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n }\n\n .header-left {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .header-left h2 {\n margin: 0;\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .header-left h2 i {\n color: var(--mj-brand-primary);\n }\n\n .pending-badge {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 14px;\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-warning);\n border-radius: 20px;\n }\n\n .badge-count {\n background: var(--mj-status-warning);\n color: var(--mj-text-inverse);\n min-width: 24px;\n height: 24px;\n padding: 0 6px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 700;\n }\n\n .badge-text {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-status-warning);\n }\n\n .refresh-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 18px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-muted);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .refresh-btn:hover:not(:disabled) {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n }\n\n .refresh-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n /* KPI Row */\n .kpi-row {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 16px;\n margin-bottom: 20px;\n }\n\n .kpi-card {\n background: var(--mj-bg-surface);\n padding: 20px;\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .kpi-icon {\n width: 48px;\n height: 48px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 20px;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n }\n\n .kpi-icon.orange { background: var(--mj-status-warning); }\n .kpi-icon.green { background: var(--mj-status-success); }\n .kpi-icon.gold { background: var(--mj-status-warning); }\n .kpi-icon.blue { background: var(--mj-brand-primary); }\n\n .kpi-content {\n flex: 1;\n min-width: 0;\n }\n\n .kpi-value {\n font-size: 26px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1;\n margin-bottom: 4px;\n }\n\n .kpi-unit {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-muted);\n }\n\n .kpi-label {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n /* View Toggle */\n .view-toggle-bar {\n margin-bottom: 20px;\n }\n\n .toggle-group {\n display: inline-flex;\n background: var(--mj-bg-surface);\n border-radius: 10px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n }\n\n .toggle-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 24px;\n border: none;\n background: var(--mj-bg-surface);\n color: var(--mj-text-muted);\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .toggle-btn:hover:not(.active) {\n background: var(--mj-bg-surface-card);\n }\n\n .toggle-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n }\n\n /* Content Card */\n .content-card {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n margin-bottom: 20px;\n }\n\n /* Queue List */\n .queue-list {\n max-height: 600px;\n overflow-y: auto;\n }\n\n /* Queue items migrated to <mj-accordion-panel> — the panel owns the row\n chrome (border, hover, expanded state) and the chevron toggle, so the\n bespoke .queue-item / .queue-item-header / .expand-toggle styles were\n removed. */\n\n .item-info {\n flex: 1;\n min-width: 0;\n }\n\n .item-name {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 6px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .item-meta {\n display: flex;\n gap: 14px;\n font-size: 12px;\n color: var(--mj-text-muted);\n align-items: center;\n flex-wrap: wrap;\n }\n\n .meta-time {\n display: flex;\n align-items: center;\n gap: 5px;\n }\n\n /* .item-actions-area removed — the reason badge now lives in the accordion's\n [mjAccordionActions] slot, which provides its own flex container. */\n\n .reason-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n }\n\n .reason-no-feedback {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n .reason-high-score-failed {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n }\n\n .reason-low-score-passed {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n }\n\n /* .expand-toggle removed — the bespoke chevron was replaced by\n <mj-accordion-panel>'s built-in chevron. */\n\n /* Review Form — rendered in the accordion body ([FlushBody]=\"true\"), so it\n supplies its own padding; the header/body separator is owned by the\n accordion (border-top removed to avoid a doubled line). */\n .review-form-panel {\n padding: 20px 20px 20px 36px;\n background: var(--mj-bg-surface);\n }\n\n .form-section {\n margin-bottom: 20px;\n }\n\n .form-section:last-of-type {\n margin-bottom: 16px;\n }\n\n .form-label {\n display: block;\n font-size: 12px;\n font-weight: 700;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 10px;\n }\n\n /* Rating Circles */\n .rating-row {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .rating-circle {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: 2px solid var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-disabled);\n font-size: 13px;\n font-weight: 700;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.15s ease;\n }\n\n .rating-circle:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n transform: scale(1.1);\n }\n\n .rating-circle.selected {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n }\n\n .rating-circle.current {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n color: var(--mj-text-inverse);\n box-shadow: var(--mj-shadow-sm);\n }\n\n .rating-display {\n margin-left: 12px;\n font-size: 16px;\n font-weight: 700;\n color: var(--mj-text-primary);\n }\n\n /* Correctness Buttons */\n .correctness-row {\n display: flex;\n gap: 12px;\n }\n\n .correctness-btn {\n flex: 1;\n max-width: 200px;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 12px 20px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 10px;\n background: var(--mj-bg-surface-card);\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .correctness-btn.correct:hover,\n .correctness-btn.correct.active {\n border-color: var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n\n .correctness-btn.incorrect:hover,\n .correctness-btn.incorrect.active {\n border-color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n\n /* Notes */\n .notes-textarea {\n width: 100%;\n max-width: 500px;\n padding: 12px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n font-family: inherit;\n resize: vertical;\n min-height: 72px;\n box-sizing: border-box;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n }\n\n .notes-textarea:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n\n /* Form Actions */\n .form-actions {\n display: flex;\n gap: 12px;\n }\n\n .submit-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 11px 22px;\n border: none;\n border-radius: 8px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .submit-btn:hover:not(:disabled) {\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-md);\n }\n\n .submit-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .skip-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 11px 20px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-muted);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .skip-btn:hover {\n border-color: var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n }\n\n /* History Filters */\n .history-filters {\n display: flex;\n gap: 16px;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n align-items: center;\n }\n\n .search-wrapper {\n flex: 1;\n position: relative;\n display: flex;\n align-items: center;\n }\n\n .search-wrapper > i {\n position: absolute;\n left: 12px;\n color: var(--mj-text-disabled);\n font-size: 13px;\n }\n\n .search-wrapper input {\n width: 100%;\n padding: 10px 12px 10px 36px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 13px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n }\n\n .search-wrapper input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n\n .sort-control {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: var(--mj-text-muted);\n flex-shrink: 0;\n }\n\n .sort-control select {\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 12px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n }\n\n /* History List */\n .history-list {\n max-height: 600px;\n overflow-y: auto;\n }\n\n .history-item {\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n display: flex;\n align-items: center;\n gap: 16px;\n flex-wrap: wrap;\n }\n\n .history-item:last-child {\n border-bottom: none;\n }\n\n .history-item-main {\n flex: 1;\n min-width: 160px;\n }\n\n .history-name {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n }\n\n .history-date {\n font-size: 12px;\n color: var(--mj-text-disabled);\n display: flex;\n align-items: center;\n gap: 5px;\n }\n\n .history-rating {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .rating-dots {\n display: flex;\n gap: 3px;\n }\n\n .rating-dot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: var(--mj-border-default);\n }\n\n .rating-dot.filled {\n background: var(--mj-status-warning);\n }\n\n .rating-label {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-muted);\n }\n\n .history-verdict {\n flex-shrink: 0;\n }\n\n .verdict {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 5px 12px;\n border-radius: 14px;\n font-size: 11px;\n font-weight: 600;\n }\n\n .verdict.correct {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n }\n\n .verdict.incorrect {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n }\n\n .history-auto-score {\n flex-shrink: 0;\n }\n\n .history-comments {\n width: 100%;\n margin-top: 8px;\n padding: 10px 14px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n border-left: 3px solid var(--mj-brand-primary);\n cursor: pointer;\n }\n\n .history-comments p {\n margin: 0;\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .history-comments.expanded p {\n white-space: normal;\n }\n\n /* Calibration Section */\n .calibration-section {\n background: var(--mj-bg-surface);\n padding: 24px;\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n }\n\n .calibration-section h3 {\n margin: 0 0 20px 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 10px;\n }\n\n .calibration-section h3 i {\n color: var(--mj-brand-primary);\n }\n\n .calibration-body {\n display: flex;\n align-items: center;\n gap: 32px;\n }\n\n .gauge-display {\n flex-shrink: 0;\n }\n\n .gauge-ring {\n position: relative;\n width: 120px;\n height: 120px;\n }\n\n .gauge-svg {\n width: 100%;\n height: 100%;\n }\n\n .gauge-track {\n stroke: var(--mj-border-default);\n }\n\n .gauge-value {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 24px;\n font-weight: 800;\n color: var(--mj-text-primary);\n }\n\n .calibration-text {\n flex: 1;\n }\n\n .calibration-description {\n margin: 0 0 12px 0;\n font-size: 14px;\n color: var(--mj-text-muted);\n line-height: 1.6;\n }\n\n\n /* (Removed .queue-item fadeIn animation — the queue-item wrapper no longer\n exists; the accordion panel owns its own reveal.) */\n\n /* Responsive */\n @media (max-width: 1024px) {\n .kpi-row {\n grid-template-columns: repeat(2, 1fr);\n }\n }\n\n @media (max-width: 768px) {\n .review-page {\n padding: 16px;\n }\n\n .page-header {\n flex-direction: column;\n gap: 16px;\n align-items: flex-start;\n }\n\n .kpi-row {\n grid-template-columns: 1fr 1fr;\n }\n\n .kpi-card {\n padding: 16px;\n }\n\n .kpi-value {\n font-size: 22px;\n }\n\n .correctness-row {\n flex-direction: column;\n }\n\n .correctness-btn {\n max-width: 100%;\n }\n\n .history-item {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .calibration-body {\n flex-direction: column;\n align-items: center;\n text-align: center;\n }\n }\n `]\n})\nexport class TestingReviewComponent implements OnInit, OnDestroy {\n @Input() InitialState: Record<string, unknown> | null = null;\n\n /** @deprecated Use {@link InitialState}. */\n @Input() set initialState(value: Record<string, unknown> | null) {\n this.InitialState = value;\n }\n /** @deprecated Use {@link InitialState}. */\n get initialState(): Record<string, unknown> | null {\n return this.InitialState;\n }\n /** When true, the inner bespoke .page-header is hidden — the parent shell owns the chrome. */\n @Input() HideToolbar = false;\n @Output() StateChange = new EventEmitter<Record<string, unknown>>();\n\n /**\n * @deprecated Use {@link StateChange}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (stateChange) keeps working. Must stay AFTER StateChange: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() stateChange = this.StateChange;\n\n private destroy$ = new Subject<void>();\n\n // View state\n CurrentView: ViewMode = 'queue';\n ExpandedItemId: string | null = null;\n ExpandedHistoryId: string | null = null;\n IsRefreshing = false;\n IsSubmitting = false;\n HistorySearchText = '';\n HistorySortField: HistorySort = 'date';\n\n // Form state for active review\n FormState: ReviewFormState = { rating: null, isCorrect: null, comments: '' };\n\n // Data\n PendingItems: FeedbackPending[] = [];\n HistoryItems: TestRunWithFeedbackSummary[] = [];\n FilteredHistoryItems: TestRunWithFeedbackSummary[] = [];\n Metrics: EvaluationSummaryMetrics | null = null;\n PendingCount = 0;\n Disagreement: DisagreementItem[] = [];\n DisagreementError = '';\n\n // Constants\n readonly RatingNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n\n constructor(\n private instrumentationService: TestingInstrumentationService,\n private cdr: ChangeDetectorRef\n ) {}\n\n ngOnInit(): void {\n this.restoreState();\n this.setupSubscriptions();\n void this.LoadDisagreement();\n }\n\n /** Stored cohort means, largest gap first. The view computes the means; this screen does not average a sample. */\n async LoadDisagreement(): Promise<void> {\n try {\n const provider = this.instrumentationService.Provider;\n if (!provider) return;\n const view = RunView.FromMetadataProvider(provider);\n const scores = await view.RunView({\n EntityName: 'MJ: Rubric Evaluation Scores',\n ExtraFilter: `EvaluationStatus = 'Submitted' AND CriterionCohortHumanMeanScore IS NOT NULL AND CriterionCohortAIMeanScore IS NOT NULL`,\n ResultType: 'simple',\n MaxRows: 1000,\n });\n if (!scores.Success) throw new Error(scores.ErrorMessage || 'Could not load scores.');\n this.Disagreement = CohortDisagreement(((scores.Results ?? []) as Record<string, unknown>[]).map(row => ({\n CriterionKey: row.CriterionKey,\n Criterion: row.Criterion,\n CriterionCohortHumanMeanScore: row.CriterionCohortHumanMeanScore,\n CriterionCohortAIMeanScore: row.CriterionCohortAIMeanScore,\n SubjectRecordID: row.SubjectRecordID,\n ContextRecordID: row.ContextRecordID,\n RubricID: row.RubricID,\n RubricMajorVersion: row.RubricMajorVersion,\n })));\n this.DisagreementError = '';\n this.cdr.markForCheck();\n } catch (error) {\n this.Disagreement = [];\n this.DisagreementError = error instanceof Error ? error.message : 'Could not load disagreement.';\n this.cdr.markForCheck();\n }\n }\n\n OpenRun(runId: string): void {\n if (!runId) return;\n SharedService.Instance.OpenEntityRecord('MJ: Test Runs', CompositeKey.FromID(runId));\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n // ------------------------------------------------------------------\n // Computed properties\n // ------------------------------------------------------------------\n\n get IsFormValid(): boolean {\n return this.FormState.rating != null && this.FormState.isCorrect != null;\n }\n\n get AgreementRate(): number {\n return this.Metrics?.agreementRate ?? 0;\n }\n\n get AgreementColor(): string {\n const rate = this.AgreementRate;\n if (rate >= 80) return '#22c55e';\n if (rate >= 60) return '#eab308';\n return '#ef4444';\n }\n\n get AgreementDash(): string {\n const circumference = 2 * Math.PI * 52; // r=52\n const filled = (this.AgreementRate / 100) * circumference;\n return `${filled} ${circumference}`;\n }\n\n // ------------------------------------------------------------------\n // Setup\n // ------------------------------------------------------------------\n\n private restoreState(): void {\n if (!this.InitialState) return;\n const view = this.InitialState['viewMode'] as string | undefined;\n if (view === 'queue' || view === 'history') {\n this.CurrentView = view;\n }\n }\n\n private setupSubscriptions(): void {\n this.instrumentationService.pendingFeedback$\n .pipe(takeUntil(this.destroy$))\n .subscribe(items => {\n this.PendingItems = items;\n this.PendingCount = items.length;\n this.emitState();\n this.cdr.markForCheck();\n });\n\n this.instrumentationService.evaluationMetrics$\n .pipe(takeUntil(this.destroy$))\n .subscribe(metrics => {\n this.Metrics = metrics;\n this.emitState();\n this.cdr.markForCheck();\n });\n\n this.instrumentationService.testRunsWithFeedback$\n .pipe(takeUntil(this.destroy$))\n .subscribe(runs => {\n this.HistoryItems = runs.filter(r => r.hasHumanFeedback);\n this.applyHistoryFilters();\n this.cdr.markForCheck();\n });\n }\n\n // ------------------------------------------------------------------\n // View toggling\n // ------------------------------------------------------------------\n\n SetView(mode: ViewMode): void {\n this.CurrentView = mode;\n this.ExpandedItemId = null;\n this.emitState();\n this.cdr.markForCheck();\n }\n\n // ------------------------------------------------------------------\n // Queue interactions\n // ------------------------------------------------------------------\n\n IsItemExpanded(testRunID: string): boolean {\n return UUIDsEqual(this.ExpandedItemId, testRunID);\n }\n\n /**\n * Accordion ExpandedChange handler for a review queue item. Single-expand\n * (radio-like) model: expanding an item makes it the sole open one (the\n * template's `IsItemExpanded` binding collapses the prior one) and resets the\n * review form for the newly-opened item; collapsing the open item clears it.\n * OnPush — drives change detection. Preserves the original ToggleExpand side\n * effect (resetForm on open).\n */\n OnItemExpandedChange(testRunID: string, expanded: boolean): void {\n if (expanded) {\n this.ExpandedItemId = testRunID;\n this.resetForm();\n } else if (UUIDsEqual(this.ExpandedItemId, testRunID)) {\n this.ExpandedItemId = null;\n }\n this.cdr.markForCheck();\n }\n\n SelectRating(n: number): void {\n this.FormState = { ...this.FormState, rating: n };\n this.cdr.markForCheck();\n }\n\n SelectCorrectness(value: boolean): void {\n this.FormState = { ...this.FormState, isCorrect: value };\n this.cdr.markForCheck();\n }\n\n OnCommentsChange(event: Event): void {\n const target = event.target as HTMLTextAreaElement;\n this.FormState = { ...this.FormState, comments: target.value };\n }\n\n async SubmitReview(item: FeedbackPending): Promise<void> {\n if (!this.IsFormValid || this.IsSubmitting) return;\n\n this.IsSubmitting = true;\n this.cdr.markForCheck();\n\n try {\n const success = await this.instrumentationService.submitFeedback(\n item.testRunID,\n this.FormState.rating!,\n this.FormState.isCorrect!,\n this.FormState.comments\n );\n\n if (success) {\n this.ExpandedItemId = null;\n this.resetForm();\n }\n } finally {\n this.IsSubmitting = false;\n this.cdr.markForCheck();\n }\n }\n\n SkipItem(): void {\n const currentIndex = this.PendingItems.findIndex(\n i => UUIDsEqual(i.testRunID, this.ExpandedItemId)\n );\n this.ExpandedItemId = null;\n this.resetForm();\n\n // Expand the next item if available\n if (currentIndex >= 0 && currentIndex + 1 < this.PendingItems.length) {\n this.ExpandedItemId = this.PendingItems[currentIndex + 1].testRunID;\n }\n this.cdr.markForCheck();\n }\n\n // ------------------------------------------------------------------\n // History interactions\n // ------------------------------------------------------------------\n\n OnHistorySearch(event: Event): void {\n const target = event.target as HTMLInputElement;\n this.HistorySearchText = target.value;\n this.applyHistoryFilters();\n this.emitState();\n this.cdr.markForCheck();\n }\n\n OnHistorySortChange(event: Event): void {\n const target = event.target as HTMLSelectElement;\n this.HistorySortField = target.value as HistorySort;\n this.applyHistoryFilters();\n this.cdr.markForCheck();\n }\n\n ToggleHistoryComment(id: string): void {\n this.ExpandedHistoryId = this.ExpandedHistoryId === id ? null : id;\n this.cdr.markForCheck();\n }\n\n // ------------------------------------------------------------------\n // Refresh\n // ------------------------------------------------------------------\n\n Refresh(): void {\n this.IsRefreshing = true;\n this.cdr.markForCheck();\n this.instrumentationService.refresh();\n\n setTimeout(() => {\n this.IsRefreshing = false;\n this.cdr.markForCheck();\n }, 1500);\n }\n\n // ------------------------------------------------------------------\n // Formatting helpers\n // ------------------------------------------------------------------\n\n FormatDecimal(value: number | undefined | null, decimals: number): string {\n if (value == null) return '0';\n return value.toFixed(decimals);\n }\n\n FormatRelativeTime(date: Date): string {\n const now = Date.now();\n const then = date instanceof Date ? date.getTime() : new Date(date).getTime();\n const diffMs = now - then;\n const diffMin = Math.floor(diffMs / 60000);\n\n if (diffMin < 1) return 'just now';\n if (diffMin < 60) return `${diffMin}m ago`;\n\n const diffHours = Math.floor(diffMin / 60);\n if (diffHours < 24) return `${diffHours}h ago`;\n\n const diffDays = Math.floor(diffHours / 24);\n if (diffDays < 7) return `${diffDays}d ago`;\n\n const diffWeeks = Math.floor(diffDays / 7);\n if (diffWeeks < 4) return `${diffWeeks}w ago`;\n\n const diffMonths = Math.floor(diffDays / 30);\n return `${diffMonths}mo ago`;\n }\n\n // ------------------------------------------------------------------\n // Private helpers\n // ------------------------------------------------------------------\n\n private resetForm(): void {\n this.FormState = { rating: null, isCorrect: null, comments: '' };\n }\n\n private applyHistoryFilters(): void {\n let items = [...this.HistoryItems];\n\n // Search filter\n if (this.HistorySearchText) {\n const term = this.HistorySearchText.toLowerCase();\n items = items.filter(i => i.testName.toLowerCase().includes(term));\n }\n\n // Sort\n items.sort((a, b) => {\n switch (this.HistorySortField) {\n case 'date':\n return b.runDateTime.getTime() - a.runDateTime.getTime();\n case 'rating':\n return (b.humanRating ?? 0) - (a.humanRating ?? 0);\n case 'test-name':\n return a.testName.localeCompare(b.testName);\n default:\n return 0;\n }\n });\n\n this.FilteredHistoryItems = items;\n }\n\n private emitState(): void {\n this.StateChange.emit({\n viewMode: this.CurrentView,\n // Richer state for the dashboard's agent context (queue depth, reviewed\n // count, avg human rating, agreement rate, history search).\n pendingCount: this.PendingCount,\n reviewedCount: this.Metrics?.humanReviewedCount ?? 0,\n averageHumanRating: this.Metrics?.humanAvgRating ?? 0,\n agreementRate: this.Metrics?.agreementRate ?? 0,\n historySearchText: this.HistorySearchText\n });\n }\n}\n"]}
@@ -1,8 +1,14 @@
1
1
  import { EventEmitter } from '@angular/core';
2
+ import type { IMetadataProvider } from '@memberjunction/core';
2
3
  import { TestRunSummary } from '../../services/testing-instrumentation.service';
3
4
  import { OracleResult } from './oracle-breakdown-table.component';
5
+ import { RubricRunView } from '@memberjunction/ng-testing';
4
6
  import * as i0 from "@angular/core";
5
7
  export declare class TestRunDetailPanelComponent {
8
+ private readonly session;
9
+ /** The signed-in session provider. An input wins; otherwise the testing service's provider is used. */
10
+ Provider: IMetadataProvider | null;
11
+ get SessionProvider(): IMetadataProvider | null;
6
12
  TestRun: TestRunSummary;
7
13
  /** @deprecated Use {@link TestRun}. */
8
14
  set testRun(value: TestRunSummary);
@@ -11,6 +17,7 @@ export declare class TestRunDetailPanelComponent {
11
17
  OracleResults: OracleResult[];
12
18
  /** @deprecated Use {@link OracleResults}. */
13
19
  set oracleResults(value: OracleResult[]);
20
+ get RubricView(): RubricRunView | null;
14
21
  /** @deprecated Use {@link OracleResults}. */
15
22
  get oracleResults(): OracleResult[];
16
23
  ResultDetails: any;
@@ -105,6 +112,6 @@ export declare class TestRunDetailPanelComponent {
105
112
  /** @deprecated Use {@link OnSubmitFeedback}. */
106
113
  onSubmitFeedback(): Promise<void>;
107
114
  static ɵfac: i0.ɵɵFactoryDeclaration<TestRunDetailPanelComponent, never>;
108
- static ɵcmp: i0.ɵɵComponentDeclaration<TestRunDetailPanelComponent, "app-test-run-detail-panel", never, { "TestRun": { "alias": "TestRun"; "required": false; }; "testRun": { "alias": "testRun"; "required": false; }; "OracleResults": { "alias": "OracleResults"; "required": false; }; "oracleResults": { "alias": "oracleResults"; "required": false; }; "ResultDetails": { "alias": "ResultDetails"; "required": false; }; "resultDetails": { "alias": "resultDetails"; "required": false; }; "Closeable": { "alias": "Closeable"; "required": false; }; "closeable": { "alias": "closeable"; "required": false; }; }, { "Close": "Close"; "close": "close"; "ViewTarget": "ViewTarget"; "viewTarget": "viewTarget"; "SubmitFeedback": "SubmitFeedback"; "submitFeedback": "submitFeedback"; }, never, never, false, never>;
115
+ static ɵcmp: i0.ɵɵComponentDeclaration<TestRunDetailPanelComponent, "app-test-run-detail-panel", never, { "Provider": { "alias": "Provider"; "required": false; }; "TestRun": { "alias": "TestRun"; "required": false; }; "testRun": { "alias": "testRun"; "required": false; }; "OracleResults": { "alias": "OracleResults"; "required": false; }; "oracleResults": { "alias": "oracleResults"; "required": false; }; "ResultDetails": { "alias": "ResultDetails"; "required": false; }; "resultDetails": { "alias": "resultDetails"; "required": false; }; "Closeable": { "alias": "Closeable"; "required": false; }; "closeable": { "alias": "closeable"; "required": false; }; }, { "Close": "Close"; "close": "close"; "ViewTarget": "ViewTarget"; "viewTarget": "viewTarget"; "SubmitFeedback": "SubmitFeedback"; "submitFeedback": "submitFeedback"; }, never, never, false, never>;
109
116
  }
110
117
  //# sourceMappingURL=test-run-detail-panel.component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"test-run-detail-panel.component.d.ts","sourceRoot":"","sources":["../../../../src/Testing/components/widgets/test-run-detail-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,gDAAgD,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;;AAElE,qBAqXa,2BAA2B;IAC7B,OAAO,EAAG,cAAc,CAAC;IAElC,uCAAuC;IACvC,IAAa,OAAO,CAAC,KAAK,EAAE,cAAc,EAEzC;IACD,uCAAuC;IACvC,IAAI,OAAO,IAAI,cAAc,CAE5B;IACQ,aAAa,EAAE,YAAY,EAAE,CAAM;IAE5C,6CAA6C;IAC7C,IAAa,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,EAE/C;IACD,6CAA6C;IAC7C,IAAI,aAAa,IAAI,YAAY,EAAE,CAElC;IACQ,aAAa,EAAE,GAAG,CAAQ;IAEnC,6CAA6C;IAC7C,IAAa,aAAa,CAAC,KAAK,EAAE,GAAG,EAEpC;IACD,6CAA6C;IAC7C,IAAI,aAAa,IAAI,GAAG,CAEvB;IACQ,SAAS,UAAQ;IAE1B,yCAAyC;IACzC,IAAa,SAAS,CAAC,KAAK,EAAE,2BAA2B,CAAC,WAAW,CAAC,EAErE;IACD,yCAAyC;IACzC,IAAI,SAAS,IAAI,2BAA2B,CAAC,WAAW,CAAC,CAExD;IAES,KAAK,qBAA4B;IAE3C;;;;;;OAMG;IACO,KAAK,qBAAc;IACnB,UAAU;cAA4B,MAAM;YAAM,MAAM;OAAM;IAExE;;;;;;OAMG;IACO,UAAU;cAT4B,MAAM;YAAM,MAAM;OAS3B;IAC7B,cAAc;gBACd,MAAM;mBACH,OAAO;kBACR,MAAM;OACb;IAEL;;;;;;OAMG;IACO,cAAc;gBAZd,MAAM;mBACH,OAAO;kBACR,MAAM;OAU6B;IAE/C,iBAAiB,UAAS;IAE1B,iDAAiD;IACjD,IAAI,iBAAiB,YAEpB;IACD,iDAAiD;IACjD,IAAI,iBAAiB,CAAC,KAAK,SAAA,EAE1B;IACD,cAAc,SAAK;IAEnB,8CAA8C;IAC9C,IAAI,cAAc,WAEjB;IACD,8CAA8C;IAC9C,IAAI,cAAc,CAAC,KAAK,QAAA,EAEvB;IACD,iBAAiB,UAAQ;IAEzB,iDAAiD;IACjD,IAAI,iBAAiB,YAEpB;IACD,iDAAiD;IACjD,IAAI,iBAAiB,CAAC,KAAK,SAAA,EAE1B;IACD,gBAAgB,SAAM;IAEtB,gDAAgD;IAChD,IAAI,gBAAgB,WAEnB;IACD,gDAAgD;IAChD,IAAI,gBAAgB,CAAC,KAAK,QAAA,EAEzB;IACD,kBAAkB,UAAS;IAE3B,kDAAkD;IAClD,IAAI,kBAAkB,YAErB;IACD,kDAAkD;IAClD,IAAI,kBAAkB,CAAC,KAAK,SAAA,EAE3B;IAED,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAc5C,8CAA8C;IAC9C,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAI5C,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM;IAQ5B,0CAA0C;IAC1C,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM;IAQ5B,OAAO,IAAI,IAAI;IAIf,uCAAuC;IACvC,OAAO,IAAI,IAAI;IAIf,YAAY,IAAI,IAAI;IASpB,4CAA4C;IAC5C,YAAY,IAAI,IAAI;IAId,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBvC,gDAAgD;IAC1C,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;yCA7M5B,2BAA2B;2CAA3B,2BAA2B;CAgNvC"}
1
+ {"version":3,"file":"test-run-detail-panel.component.d.ts","sourceRoot":"","sources":["../../../../src/Testing/components/widgets/test-run-detail-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAU,MAAM,eAAe,CAAC;AAC/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAiC,MAAM,gDAAgD,CAAC;AAC/G,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;;AAE3D,qBAwXa,2BAA2B;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6D;IAErF,uGAAuG;IAC9F,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAQ;IAEnD,IAAW,eAAe,IAAI,iBAAiB,GAAG,IAAI,CAErD;IAEQ,OAAO,EAAG,cAAc,CAAC;IAElC,uCAAuC;IACvC,IAAa,OAAO,CAAC,KAAK,EAAE,cAAc,EAEzC;IACD,uCAAuC;IACvC,IAAI,OAAO,IAAI,cAAc,CAE5B;IACQ,aAAa,EAAE,YAAY,EAAE,CAAM;IAE5C,6CAA6C;IAC7C,IAAa,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,EAE/C;IACD,IAAI,UAAU,yBAEb;IAED,6CAA6C;IAC7C,IAAI,aAAa,IAAI,YAAY,EAAE,CAElC;IACQ,aAAa,EAAE,GAAG,CAAQ;IAEnC,6CAA6C;IAC7C,IAAa,aAAa,CAAC,KAAK,EAAE,GAAG,EAEpC;IACD,6CAA6C;IAC7C,IAAI,aAAa,IAAI,GAAG,CAEvB;IACQ,SAAS,UAAQ;IAE1B,yCAAyC;IACzC,IAAa,SAAS,CAAC,KAAK,EAAE,2BAA2B,CAAC,WAAW,CAAC,EAErE;IACD,yCAAyC;IACzC,IAAI,SAAS,IAAI,2BAA2B,CAAC,WAAW,CAAC,CAExD;IAES,KAAK,qBAA4B;IAE3C;;;;;;OAMG;IACO,KAAK,qBAAc;IACnB,UAAU;cAA4B,MAAM;YAAM,MAAM;OAAM;IAExE;;;;;;OAMG;IACO,UAAU;cAT4B,MAAM;YAAM,MAAM;OAS3B;IAC7B,cAAc;gBACd,MAAM;mBACH,OAAO;kBACR,MAAM;OACb;IAEL;;;;;;OAMG;IACO,cAAc;gBAZd,MAAM;mBACH,OAAO;kBACR,MAAM;OAU6B;IAE/C,iBAAiB,UAAS;IAE1B,iDAAiD;IACjD,IAAI,iBAAiB,YAEpB;IACD,iDAAiD;IACjD,IAAI,iBAAiB,CAAC,KAAK,SAAA,EAE1B;IACD,cAAc,SAAK;IAEnB,8CAA8C;IAC9C,IAAI,cAAc,WAEjB;IACD,8CAA8C;IAC9C,IAAI,cAAc,CAAC,KAAK,QAAA,EAEvB;IACD,iBAAiB,UAAQ;IAEzB,iDAAiD;IACjD,IAAI,iBAAiB,YAEpB;IACD,iDAAiD;IACjD,IAAI,iBAAiB,CAAC,KAAK,SAAA,EAE1B;IACD,gBAAgB,SAAM;IAEtB,gDAAgD;IAChD,IAAI,gBAAgB,WAEnB;IACD,gDAAgD;IAChD,IAAI,gBAAgB,CAAC,KAAK,QAAA,EAEzB;IACD,kBAAkB,UAAS;IAE3B,kDAAkD;IAClD,IAAI,kBAAkB,YAErB;IACD,kDAAkD;IAClD,IAAI,kBAAkB,CAAC,KAAK,SAAA,EAE3B;IAED,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAc5C,8CAA8C;IAC9C,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAI5C,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM;IAQ5B,0CAA0C;IAC1C,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM;IAQ5B,OAAO,IAAI,IAAI;IAIf,uCAAuC;IACvC,OAAO,IAAI,IAAI;IAIf,YAAY,IAAI,IAAI;IASpB,4CAA4C;IAC5C,YAAY,IAAI,IAAI;IAId,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBvC,gDAAgD;IAC1C,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;yCA1N5B,2BAA2B;2CAA3B,2BAA2B;CA6NvC"}