@memberjunction/ng-dashboards 5.33.0 → 5.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/AI/components/agents/agent-editor.component.js +2 -2
  2. package/dist/AI/components/agents/agent-editor.component.js.map +1 -1
  3. package/dist/ComponentStudio/components/workspace/component-preview.component.js +1 -1
  4. package/dist/ComponentStudio/components/workspace/component-preview.component.js.map +1 -1
  5. package/dist/ComponentStudio/services/component-studio-state.service.d.ts +28 -8
  6. package/dist/ComponentStudio/services/component-studio-state.service.d.ts.map +1 -1
  7. package/dist/ComponentStudio/services/component-studio-state.service.js +45 -27
  8. package/dist/ComponentStudio/services/component-studio-state.service.js.map +1 -1
  9. package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.d.ts +18 -3
  10. package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.d.ts.map +1 -1
  11. package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js +51 -11
  12. package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js.map +1 -1
  13. package/dist/DataExplorer/data-explorer-dashboard.component.js +2 -2
  14. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  15. package/dist/Integration/components/widgets/integration-card.component.js +2 -2
  16. package/dist/Integration/components/widgets/integration-card.component.js.map +1 -1
  17. package/dist/Integration/components/widgets/run-history-panel.component.js +2 -2
  18. package/dist/Integration/components/widgets/run-history-panel.component.js.map +1 -1
  19. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts +134 -1
  20. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts.map +1 -1
  21. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +1227 -24
  22. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
  23. package/dist/SystemDiagnostics/system-diagnostics.component.js +4 -4
  24. package/dist/SystemDiagnostics/system-diagnostics.component.js.map +1 -1
  25. package/dist/Testing/components/testing-runs.component.js +3 -3
  26. package/dist/Testing/components/testing-runs.component.js.map +1 -1
  27. package/package.json +52 -52
@@ -638,7 +638,7 @@ export class TestingRunsComponent {
638
638
  static ɵfac = function TestingRunsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TestingRunsComponent)(i0.ɵɵdirectiveInject(i1.TestingInstrumentationService), i0.ɵɵdirectiveInject(i2.TestingDialogService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.ViewContainerRef)); };
639
639
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TestingRunsComponent, selectors: [["app-testing-runs"]], hostBindings: function TestingRunsComponent_HostBindings(rf, ctx) { if (rf & 1) {
640
640
  i0.ɵɵlistener("keydown.escape", function TestingRunsComponent_keydown_escape_HostBindingHandler() { return ctx.OnEscapeKey(); }, i0.ɵɵresolveDocument);
641
- } }, inputs: { initialState: "initialState" }, outputs: { stateChange: "stateChange" }, standalone: false, decls: 59, vars: 18, consts: [[1, "runs-container", 3, "keydown.escape"], [1, "page-header"], [1, "header-title"], [1, "fa-solid", "fa-list-check"], [1, "header-actions"], [1, "btn", "btn-secondary", 3, "click", "disabled"], [1, "fa-solid", "fa-sync-alt"], [1, "btn", "btn-primary", 3, "click"], [1, "fa-solid", "fa-play"], [1, "filter-bar"], [1, "filter-left"], [1, "filter-chips"], [1, "chip", 3, "active"], [1, "result-count"], [1, "filter-right"], [1, "time-select", 3, "change", "value"], ["value", "today"], ["value", "week"], ["value", "month"], ["value", "90days"], [1, "search-box"], [1, "fa-solid", "fa-search"], ["type", "text", "placeholder", "Search by test name...", 3, "input", "value"], [1, "clear-search"], [1, "stats-row"], [1, "runs-table-wrapper"], [1, "table-header"], [1, "col", "col-name"], [1, "col", "col-eval"], [1, "col", "col-score"], [1, "col", "col-duration"], [1, "col", "col-cost"], [1, "col", "col-time"], [1, "col", "col-actions"], [1, "table-loading"], [1, "table-empty"], [1, "chip", 3, "click"], [3, "class"], [1, "clear-search", 3, "click"], [1, "fa-solid", "fa-times"], [1, "stat-card"], [1, "stat-icon", "total"], [1, "fa-solid", "fa-hashtag"], [1, "stat-body"], [1, "stat-value"], [1, "stat-label"], [1, "stat-icon", "pass"], [1, "fa-solid", "fa-check-circle"], [1, "stat-icon", "duration"], [1, "fa-solid", "fa-clock"], [1, "stat-icon", "cost"], [1, "fa-solid", "fa-dollar-sign"], ["text", "Loading test runs..."], [1, "fa-solid", "fa-inbox"], [1, "empty-hint"], [1, "table-row", 3, "is-running", "is-selected"], [1, "table-row", 3, "click"], [1, "test-name-link", 3, "click"], ["mode", "compact", 3, "executionStatus", "originalStatus", "autoScore", "passedChecks", "failedChecks", "totalChecks", "humanRating", "humanIsCorrect", "hasHumanFeedback", "preferences"], [3, "score", "showBar"], [3, "cost"], ["title", "View details", 1, "icon-btn", 3, "click"], [1, "fa-solid", "fa-eye"], ["title", "Re-run test", 1, "icon-btn", 3, "click"], [1, "fa-solid", "fa-rotate-right"], [1, "detail-overlay", 3, "click"], [1, "detail-panel"], [1, "detail-panel-header"], [1, "detail-title-section"], [3, "status"], [1, "close-btn", 3, "click"], [1, "detail-panel-body"], [1, "detail-metrics"], [1, "detail-metric"], [1, "dm-label"], [1, "dm-value"], [1, "detail-section"], [1, "fa-solid", "fa-clipboard-check"], ["mode", "expanded", 3, "executionStatus", "originalStatus", "autoScore", "passedChecks", "failedChecks", "totalChecks", "humanRating", "humanIsCorrect", "hasHumanFeedback", "preferences"], [1, "detail-section", "feedback-section"], [1, "fa-solid", "fa-comment-dots"], [1, "existing-feedback"], [1, "feedback-form"], [1, "fa-solid", "fa-server"], [1, "feedback-label"], [1, "feedback-value"], [1, "feedback-comments"], [1, "fa-solid", "fa-check", 2, "color", "#22c55e"], [1, "fa-solid", "fa-times", 2, "color", "#ef4444"], [1, "rating-row"], [1, "rating-buttons"], [1, "rating-btn", 3, "selected"], [1, "correctness-row"], [1, "toggle-group"], [1, "toggle-btn", 3, "click"], [1, "fa-solid", "fa-check"], [1, "comments-row"], ["rows", "3", "placeholder", "Optional feedback comments...", 3, "input", "value"], [1, "btn", "btn-primary", "submit-feedback-btn", 3, "click", "disabled"], [1, "fa-solid", "fa-paper-plane"], [1, "rating-btn", 3, "click"]], template: function TestingRunsComponent_Template(rf, ctx) { if (rf & 1) {
641
+ } }, inputs: { initialState: "initialState" }, outputs: { stateChange: "stateChange" }, standalone: false, decls: 59, vars: 18, consts: [[1, "runs-container", 3, "keydown.escape"], [1, "page-header"], [1, "header-title"], [1, "fa-solid", "fa-list-check"], [1, "header-actions"], [1, "btn", "btn-secondary", 3, "click", "disabled"], [1, "fa-solid", "fa-sync-alt"], [1, "btn", "btn-primary", 3, "click"], [1, "fa-solid", "fa-play"], [1, "filter-bar"], [1, "filter-left"], [1, "filter-chips"], [1, "chip", 3, "active"], [1, "result-count"], [1, "filter-right"], [1, "time-select", 3, "change", "value"], ["value", "today"], ["value", "week"], ["value", "month"], ["value", "90days"], [1, "search-box"], [1, "fa-solid", "fa-search"], ["type", "text", "placeholder", "Search by test name...", 3, "input", "value"], [1, "clear-search"], [1, "stats-row"], [1, "runs-table-wrapper"], [1, "table-header"], [1, "col", "col-name"], [1, "col", "col-eval"], [1, "col", "col-score"], [1, "col", "col-duration"], [1, "col", "col-cost"], [1, "col", "col-time"], [1, "col", "col-actions"], [1, "table-loading"], [1, "table-empty"], [1, "chip", 3, "click"], [3, "class"], [1, "clear-search", 3, "click"], [1, "fa-solid", "fa-times"], [1, "stat-card"], [1, "stat-icon", "total"], [1, "fa-solid", "fa-hashtag"], [1, "stat-body"], [1, "stat-value"], [1, "stat-label"], [1, "stat-icon", "pass"], [1, "fa-solid", "fa-check-circle"], [1, "stat-icon", "duration"], [1, "fa-solid", "fa-clock"], [1, "stat-icon", "cost"], [1, "fa-solid", "fa-dollar-sign"], ["text", "Loading test runs..."], [1, "fa-solid", "fa-inbox"], [1, "empty-hint"], [1, "table-row", 3, "is-running", "is-selected"], [1, "table-row", 3, "click"], [1, "test-name-link", 3, "click"], ["mode", "compact", 3, "executionStatus", "originalStatus", "autoScore", "passedChecks", "failedChecks", "totalChecks", "humanRating", "humanIsCorrect", "hasHumanFeedback", "preferences"], [3, "score", "showBar"], [3, "cost"], ["title", "View details", 1, "icon-btn", 3, "click"], [1, "fa-solid", "fa-eye"], ["title", "Re-run test", 1, "icon-btn", 3, "click"], [1, "fa-solid", "fa-rotate-right"], [1, "detail-overlay", 3, "click"], [1, "detail-panel"], [1, "detail-panel-header"], [1, "detail-title-section"], [3, "status"], [1, "close-btn", 3, "click"], [1, "detail-panel-body"], [1, "detail-metrics"], [1, "detail-metric"], [1, "dm-label"], [1, "dm-value"], [1, "detail-section"], [1, "fa-solid", "fa-clipboard-check"], ["mode", "expanded", 3, "executionStatus", "originalStatus", "autoScore", "passedChecks", "failedChecks", "totalChecks", "humanRating", "humanIsCorrect", "hasHumanFeedback", "preferences"], [1, "detail-section", "feedback-section"], [1, "fa-solid", "fa-comment-dots"], [1, "existing-feedback"], [1, "feedback-form"], [1, "fa-solid", "fa-server"], [1, "feedback-label"], [1, "feedback-value"], [1, "feedback-comments"], [1, "fa-solid", "fa-check", 2, "color", "var(--mj-status-success)"], [1, "fa-solid", "fa-times", 2, "color", "var(--mj-status-error)"], [1, "rating-row"], [1, "rating-buttons"], [1, "rating-btn", 3, "selected"], [1, "correctness-row"], [1, "toggle-group"], [1, "toggle-btn", 3, "click"], [1, "fa-solid", "fa-check"], [1, "comments-row"], ["rows", "3", "placeholder", "Optional feedback comments...", 3, "input", "value"], [1, "btn", "btn-primary", "submit-feedback-btn", 3, "click", "disabled"], [1, "fa-solid", "fa-paper-plane"], [1, "rating-btn", 3, "click"]], template: function TestingRunsComponent_Template(rf, ctx) { if (rf & 1) {
642
642
  i0.ɵɵelementStart(0, "div", 0);
643
643
  i0.ɵɵlistener("keydown.escape", function TestingRunsComponent_Template_div_keydown_escape_0_listener() { return ctx.CloseDetailPanel(); });
644
644
  i0.ɵɵelementStart(1, "div", 1)(2, "div", 2);
@@ -986,9 +986,9 @@ export class TestingRunsComponent {
986
986
  <span class="feedback-label">Correct:</span>
987
987
  <span class="feedback-value">
988
988
  @if (SelectedRun.humanIsCorrect === true) {
989
- <i class="fa-solid fa-check" style="color: #22c55e"></i> Yes
989
+ <i class="fa-solid fa-check" style="color: var(--mj-status-success)"></i> Yes
990
990
  } @else if (SelectedRun.humanIsCorrect === false) {
991
- <i class="fa-solid fa-times" style="color: #ef4444"></i> No
991
+ <i class="fa-solid fa-times" style="color: var(--mj-status-error)"></i> No
992
992
  } @else {
993
993
  --
994
994
  }
@@ -1 +1 @@
1
- {"version":3,"file":"testing-runs.component.js","sourceRoot":"","sources":["../../../src/Testing/components/testing-runs.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 ViewContainerRef,\n HostListener\n} from '@angular/core';\nimport { Observable, Subject, BehaviorSubject, combineLatest } from 'rxjs';\nimport { takeUntil, map } from 'rxjs/operators';\nimport { CompositeKey } from '@memberjunction/core';\nimport { SharedService } from '@memberjunction/ng-shared';\nimport { TestingDialogService } from '@memberjunction/ng-testing';\nimport { EvaluationPreferences, DEFAULT_EVALUATION_PREFERENCES } from '@memberjunction/ng-testing';\nimport {\n TestingInstrumentationService,\n TestRunWithFeedbackSummary,\n EvaluationSummaryMetrics\n} from '../services/testing-instrumentation.service';\n\ntype StatusFilter = 'all' | 'running' | 'passed' | 'failed' | 'error';\ntype TimeRange = 'today' | 'week' | 'month' | '90days';\n\ninterface RunsFilterState {\n status: StatusFilter;\n timeRange: TimeRange;\n searchText: string;\n}\n\ninterface FilteredStats {\n totalRuns: number;\n passRate: number;\n avgDuration: number;\n totalCost: number;\n}\n\n@Component({\n standalone: false,\n selector: 'app-testing-runs',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <!-- Page Header -->\n <div class=\"runs-container\" (keydown.escape)=\"CloseDetailPanel()\">\n <div class=\"page-header\">\n <div class=\"header-title\">\n <i class=\"fa-solid fa-list-check\"></i>\n <h2>Test Runs</h2>\n </div>\n <div class=\"header-actions\">\n <button class=\"btn btn-secondary\" (click)=\"Refresh()\" [disabled]=\"IsRefreshing\">\n <i class=\"fa-solid fa-sync-alt\" [class.spinning]=\"IsRefreshing\"></i>\n Refresh\n </button>\n <button class=\"btn btn-primary\" (click)=\"StartNewTest()\">\n <i class=\"fa-solid fa-play\"></i>\n Run Test\n </button>\n </div>\n </div>\n\n <!-- Filter Bar -->\n <div class=\"filter-bar\">\n <div class=\"filter-left\">\n <div class=\"filter-chips\">\n @for (chip of StatusChips; track chip.value) {\n <button\n class=\"chip\"\n [class.active]=\"filterState.status === chip.value\"\n [attr.data-status]=\"chip.value\"\n (click)=\"SetStatusFilter(chip.value)\"\n >\n @if (chip.icon) {\n <i [class]=\"chip.icon\"></i>\n }\n {{ chip.label }}\n </button>\n }\n </div>\n <span class=\"result-count\">{{ (FilteredRuns$ | async)?.length ?? 0 }} results</span>\n </div>\n <div class=\"filter-right\">\n <select\n class=\"time-select\"\n [value]=\"filterState.timeRange\"\n (change)=\"OnTimeRangeChange($event)\"\n >\n <option value=\"today\">Today</option>\n <option value=\"week\">This Week</option>\n <option value=\"month\">This Month</option>\n <option value=\"90days\">Last 90 Days</option>\n </select>\n <div class=\"search-box\">\n <i class=\"fa-solid fa-search\"></i>\n <input\n type=\"text\"\n placeholder=\"Search by test name...\"\n [value]=\"filterState.searchText\"\n (input)=\"OnSearchInput($event)\"\n />\n @if (filterState.searchText) {\n <button class=\"clear-search\" (click)=\"ClearSearch()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n </div>\n </div>\n\n <!-- Summary Stats Row -->\n @if (FilteredStats$ | async; as stats) {\n <div class=\"stats-row\">\n <div class=\"stat-card\">\n <div class=\"stat-icon total\"><i class=\"fa-solid fa-hashtag\"></i></div>\n <div class=\"stat-body\">\n <div class=\"stat-value\">{{ stats.totalRuns }}</div>\n <div class=\"stat-label\">Total Runs</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon pass\"><i class=\"fa-solid fa-check-circle\"></i></div>\n <div class=\"stat-body\">\n <div class=\"stat-value\">{{ FormatPercent(stats.passRate) }}</div>\n <div class=\"stat-label\">Pass Rate</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon duration\"><i class=\"fa-solid fa-clock\"></i></div>\n <div class=\"stat-body\">\n <div class=\"stat-value\">{{ FormatDuration(stats.avgDuration) }}</div>\n <div class=\"stat-label\">Avg Duration</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon cost\"><i class=\"fa-solid fa-dollar-sign\"></i></div>\n <div class=\"stat-body\">\n <div class=\"stat-value\">{{ FormatCostTotal(stats.totalCost) }}</div>\n <div class=\"stat-label\">Total Cost</div>\n </div>\n </div>\n </div>\n }\n\n <!-- Runs Table -->\n <div class=\"runs-table-wrapper\">\n <div class=\"table-header\">\n <div class=\"col col-name\">Test Name</div>\n <div class=\"col col-eval\">Evaluation</div>\n <div class=\"col col-score\">Score</div>\n <div class=\"col col-duration\">Duration</div>\n <div class=\"col col-cost\">Cost</div>\n <div class=\"col col-time\">Started</div>\n <div class=\"col col-actions\">Actions</div>\n </div>\n\n @if (instrumentationService.isLoading$ | async) {\n <div class=\"table-loading\">\n <mj-loading text=\"Loading test runs...\"></mj-loading>\n </div>\n } @else if ((FilteredRuns$ | async)?.length === 0) {\n <div class=\"table-empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n <p>No test runs found</p>\n <span class=\"empty-hint\">Try adjusting your filters or run a new test.</span>\n </div>\n } @else {\n @for (run of FilteredRuns$ | async; track TrackByRunId($index, run)) {\n <div\n class=\"table-row\"\n [class.is-running]=\"run.status === 'Running'\"\n [class.is-selected]=\"SelectedRun?.id === run.id\"\n (click)=\"SelectRun(run)\"\n >\n <div class=\"col col-name\">\n <span class=\"test-name-link\" (click)=\"NavigateToTest(run, $event)\">\n {{ run.testName }}\n </span>\n </div>\n <div class=\"col col-eval\">\n <app-evaluation-badge\n [executionStatus]=\"run.status\"\n [originalStatus]=\"run.status\"\n [autoScore]=\"run.score\"\n [passedChecks]=\"run.passedChecks\"\n [failedChecks]=\"run.failedChecks\"\n [totalChecks]=\"run.totalChecks\"\n [humanRating]=\"run.humanRating\"\n [humanIsCorrect]=\"run.humanIsCorrect\"\n [hasHumanFeedback]=\"run.hasHumanFeedback\"\n [preferences]=\"EvalPreferences\"\n mode=\"compact\"\n ></app-evaluation-badge>\n </div>\n <div class=\"col col-score\">\n <app-score-indicator [score]=\"run.score\" [showBar]=\"true\"></app-score-indicator>\n </div>\n <div class=\"col col-duration\">{{ FormatDuration(run.duration) }}</div>\n <div class=\"col col-cost\">\n <app-cost-display [cost]=\"run.cost\"></app-cost-display>\n </div>\n <div class=\"col col-time\">{{ FormatRelativeTime(run.runDateTime) }}</div>\n <div class=\"col col-actions\">\n <button class=\"icon-btn\" title=\"View details\" (click)=\"SelectRun(run); $event.stopPropagation()\">\n <i class=\"fa-solid fa-eye\"></i>\n </button>\n <button class=\"icon-btn\" title=\"Re-run test\" (click)=\"RerunTest(run); $event.stopPropagation()\">\n <i class=\"fa-solid fa-rotate-right\"></i>\n </button>\n </div>\n </div>\n }\n }\n </div>\n\n <!-- Detail Panel (slide-in) -->\n @if (SelectedRun) {\n <div class=\"detail-overlay\" (click)=\"CloseDetailPanel()\"></div>\n <div class=\"detail-panel\">\n <div class=\"detail-panel-header\">\n <div class=\"detail-title-section\">\n <h3>{{ SelectedRun.testName }}</h3>\n <app-test-status-badge [status]=\"SelectedRun.status\"></app-test-status-badge>\n </div>\n <button class=\"close-btn\" (click)=\"CloseDetailPanel()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"detail-panel-body\">\n <!-- Metrics row -->\n <div class=\"detail-metrics\">\n <div class=\"detail-metric\">\n <span class=\"dm-label\">Score</span>\n <app-score-indicator [score]=\"SelectedRun.score\" [showBar]=\"true\"></app-score-indicator>\n </div>\n <div class=\"detail-metric\">\n <span class=\"dm-label\">Duration</span>\n <span class=\"dm-value\">{{ FormatDuration(SelectedRun.duration) }}</span>\n </div>\n <div class=\"detail-metric\">\n <span class=\"dm-label\">Cost</span>\n <app-cost-display [cost]=\"SelectedRun.cost\"></app-cost-display>\n </div>\n <div class=\"detail-metric\">\n <span class=\"dm-label\">Started</span>\n <span class=\"dm-value\">{{ FormatDateTime(SelectedRun.runDateTime) }}</span>\n </div>\n </div>\n\n <!-- Evaluation Badge (expanded) -->\n <div class=\"detail-section\">\n <h4><i class=\"fa-solid fa-clipboard-check\"></i> Evaluation</h4>\n <app-evaluation-badge\n [executionStatus]=\"SelectedRun.status\"\n [originalStatus]=\"SelectedRun.status\"\n [autoScore]=\"SelectedRun.score\"\n [passedChecks]=\"SelectedRun.passedChecks\"\n [failedChecks]=\"SelectedRun.failedChecks\"\n [totalChecks]=\"SelectedRun.totalChecks\"\n [humanRating]=\"SelectedRun.humanRating\"\n [humanIsCorrect]=\"SelectedRun.humanIsCorrect\"\n [hasHumanFeedback]=\"SelectedRun.hasHumanFeedback\"\n [preferences]=\"EvalPreferences\"\n mode=\"expanded\"\n ></app-evaluation-badge>\n </div>\n\n <!-- Execution Context -->\n @if (SelectedRun.targetType) {\n <div class=\"detail-section\">\n <h4><i class=\"fa-solid fa-server\"></i> Execution Context</h4>\n <mj-execution-context></mj-execution-context>\n </div>\n }\n\n <!-- Inline Feedback Form -->\n <div class=\"detail-section feedback-section\">\n <h4><i class=\"fa-solid fa-comment-dots\"></i> Human Feedback</h4>\n @if (SelectedRun.hasHumanFeedback) {\n <div class=\"existing-feedback\">\n <span class=\"feedback-label\">Rating:</span>\n <span class=\"feedback-value\">{{ SelectedRun.humanRating }}/10</span>\n <span class=\"feedback-label\">Correct:</span>\n <span class=\"feedback-value\">\n @if (SelectedRun.humanIsCorrect === true) {\n <i class=\"fa-solid fa-check\" style=\"color: #22c55e\"></i> Yes\n } @else if (SelectedRun.humanIsCorrect === false) {\n <i class=\"fa-solid fa-times\" style=\"color: #ef4444\"></i> No\n } @else {\n --\n }\n </span>\n @if (SelectedRun.humanComments) {\n <div class=\"feedback-comments\">{{ SelectedRun.humanComments }}</div>\n }\n </div>\n } @else {\n <div class=\"feedback-form\">\n <div class=\"rating-row\">\n <label>Rating</label>\n <div class=\"rating-buttons\">\n @for (n of RatingValues; track n) {\n <button\n class=\"rating-btn\"\n [class.selected]=\"feedbackRating === n\"\n (click)=\"feedbackRating = n\"\n >\n {{ n }}\n </button>\n }\n </div>\n </div>\n <div class=\"correctness-row\">\n <label>Is the result correct?</label>\n <div class=\"toggle-group\">\n <button\n class=\"toggle-btn\"\n [class.active]=\"feedbackIsCorrect === true\"\n (click)=\"feedbackIsCorrect = true\"\n >\n <i class=\"fa-solid fa-check\"></i> Yes\n </button>\n <button\n class=\"toggle-btn\"\n [class.active]=\"feedbackIsCorrect === false\"\n (click)=\"feedbackIsCorrect = false\"\n >\n <i class=\"fa-solid fa-times\"></i> No\n </button>\n </div>\n </div>\n <div class=\"comments-row\">\n <label>Comments</label>\n <textarea\n rows=\"3\"\n placeholder=\"Optional feedback comments...\"\n [value]=\"feedbackComments\"\n (input)=\"OnFeedbackCommentInput($event)\"\n ></textarea>\n </div>\n <button\n class=\"btn btn-primary submit-feedback-btn\"\n (click)=\"SubmitFeedback()\"\n [disabled]=\"IsSubmittingFeedback\"\n >\n <i class=\"fa-solid fa-paper-plane\"></i>\n {{ IsSubmittingFeedback ? 'Submitting...' : 'Submit Feedback' }}\n </button>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n `,\n styles: [`\n /* ==========================================\n Testing Runs Component\n ========================================== */\n\n .runs-container {\n padding: 24px;\n height: 100%;\n overflow-y: auto;\n background: var(--mj-bg-surface-card);\n position: relative;\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 }\n\n .header-title {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .header-title i {\n font-size: 22px;\n color: var(--mj-brand-primary);\n }\n\n .header-title h2 {\n margin: 0;\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n }\n\n .header-actions {\n display: flex;\n gap: 10px;\n }\n\n /* Buttons */\n .btn {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 10px 18px;\n border: none;\n border-radius: 10px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n }\n\n .btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-md);\n }\n\n .btn-secondary {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n }\n\n .btn-secondary:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n }\n\n .spinning {\n animation: spin 1s linear infinite;\n }\n\n @keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n\n /* Filter Bar */\n .filter-bar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 16px;\n margin-bottom: 20px;\n padding: 14px 20px;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n }\n\n .filter-left {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .filter-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n }\n\n .chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 7px 14px;\n background: var(--mj-bg-surface-sunken);\n border: 2px solid transparent;\n border-radius: 20px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .chip:hover {\n background: var(--mj-border-default);\n }\n\n .chip.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n }\n\n .chip.active[data-status=\"running\"] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n }\n\n .chip.active[data-status=\"passed\"] {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n }\n\n .chip.active[data-status=\"failed\"] {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n }\n\n .chip.active[data-status=\"error\"] {\n background: var(--mj-status-warning);\n border-color: var(--mj-status-warning);\n }\n\n .result-count {\n font-size: 12px;\n color: var(--mj-text-disabled);\n font-weight: 500;\n white-space: nowrap;\n }\n\n .filter-right {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .time-select {\n padding: 8px 12px;\n border: 2px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface);\n cursor: pointer;\n }\n\n .time-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n }\n\n .search-box {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 14px;\n background: var(--mj-bg-surface-card);\n border: 2px solid var(--mj-border-default);\n border-radius: 8px;\n min-width: 220px;\n transition: border-color 0.2s ease;\n }\n\n .search-box:focus-within {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n }\n\n .search-box i {\n color: var(--mj-text-disabled);\n font-size: 13px;\n }\n\n .search-box input {\n flex: 1;\n border: none;\n background: transparent;\n outline: none;\n font-size: 13px;\n color: var(--mj-text-secondary);\n }\n\n .search-box input::placeholder {\n color: var(--mj-text-disabled);\n }\n\n .clear-search {\n border: none;\n background: transparent;\n color: var(--mj-text-disabled);\n cursor: pointer;\n padding: 2px 4px;\n border-radius: 4px;\n }\n\n .clear-search:hover {\n color: var(--mj-text-muted);\n background: var(--mj-border-default);\n }\n\n /* Stats Row */\n .stats-row {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 14px;\n margin-bottom: 20px;\n }\n\n .stat-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 16px 20px;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n }\n\n .stat-icon {\n width: 42px;\n height: 42px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n }\n\n .stat-icon.total { background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface)); color: var(--mj-brand-primary); }\n .stat-icon.pass { background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface)); color: var(--mj-status-success); }\n .stat-icon.duration { background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface)); color: var(--mj-brand-primary); }\n .stat-icon.cost { background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface)); color: var(--mj-status-warning); }\n\n .stat-body {\n flex: 1;\n }\n\n .stat-value {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.1;\n }\n\n .stat-label {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 2px;\n }\n\n /* Runs Table */\n .runs-table-wrapper {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n }\n\n .table-header {\n display: grid;\n grid-template-columns: 2fr 140px 120px 100px 100px 120px 90px;\n gap: 12px;\n padding: 14px 24px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .table-row {\n display: grid;\n grid-template-columns: 2fr 140px 120px 100px 100px 120px 90px;\n gap: 12px;\n padding: 14px 24px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n cursor: pointer;\n transition: background 0.15s ease;\n align-items: center;\n }\n\n .table-row:last-child {\n border-bottom: none;\n }\n\n .table-row:hover {\n background: var(--mj-bg-surface-card);\n }\n\n .table-row.is-selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-brand-primary);\n }\n\n .table-row.is-running {\n background: color-mix(in srgb, var(--mj-brand-primary) 4%, var(--mj-bg-surface));\n }\n\n .table-row.is-running .test-name-link::after {\n content: '';\n display: inline-block;\n width: 8px;\n height: 8px;\n background: var(--mj-brand-primary);\n border-radius: 50%;\n margin-left: 8px;\n animation: pulse-dot 1.5s infinite;\n }\n\n @keyframes pulse-dot {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.3; }\n }\n\n .col {\n display: flex;\n align-items: center;\n font-size: 13px;\n color: var(--mj-text-secondary);\n overflow: hidden;\n }\n\n .test-name-link {\n font-weight: 600;\n color: var(--mj-text-primary);\n cursor: pointer;\n text-decoration: none;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .test-name-link:hover {\n color: var(--mj-brand-primary);\n text-decoration: underline;\n }\n\n .col-actions {\n gap: 6px;\n justify-content: flex-end;\n }\n\n .icon-btn {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n color: var(--mj-text-muted);\n cursor: pointer;\n border-radius: 8px;\n font-size: 13px;\n transition: all 0.2s ease;\n }\n\n .icon-btn:hover {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-md);\n }\n\n /* Table states */\n .table-loading {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 80px 40px;\n }\n\n .table-empty {\n padding: 80px 40px;\n text-align: center;\n }\n\n .table-empty i {\n font-size: 48px;\n color: var(--mj-border-strong);\n margin-bottom: 16px;\n }\n\n .table-empty p {\n font-size: 16px;\n color: var(--mj-text-muted);\n margin: 0 0 8px 0;\n }\n\n .empty-hint {\n font-size: 13px;\n color: var(--mj-text-disabled);\n }\n\n /* Detail Panel Overlay */\n .detail-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 999;\n }\n\n /* Detail Panel */\n .detail-panel {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 520px;\n max-width: 90vw;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-lg);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n animation: slideIn 0.25s ease-out;\n }\n\n @keyframes slideIn {\n from { transform: translateX(100%); }\n to { transform: translateX(0); }\n }\n\n .detail-panel-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n padding: 20px 24px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n }\n\n .detail-title-section {\n display: flex;\n flex-direction: column;\n gap: 8px;\n flex: 1;\n min-width: 0;\n }\n\n .detail-title-section h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .close-btn {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n flex-shrink: 0;\n margin-left: 12px;\n transition: all 0.15s ease;\n }\n\n .close-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n }\n\n .detail-panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 20px 24px;\n }\n\n .detail-metrics {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px;\n margin-bottom: 24px;\n }\n\n .detail-metric {\n padding: 12px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n border-left: 3px solid var(--mj-brand-primary);\n }\n\n .dm-label {\n display: block;\n font-size: 10px;\n font-weight: 700;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 6px;\n }\n\n .dm-value {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .detail-section {\n margin-bottom: 24px;\n }\n\n .detail-section h4 {\n font-size: 13px;\n font-weight: 700;\n color: var(--mj-text-secondary);\n margin: 0 0 12px 0;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .detail-section h4 i {\n color: var(--mj-brand-primary);\n font-size: 14px;\n }\n\n /* Feedback Section */\n .existing-feedback {\n display: flex;\n flex-wrap: wrap;\n gap: 8px 16px;\n align-items: center;\n padding: 14px;\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n border-radius: 8px;\n font-size: 13px;\n }\n\n .feedback-label {\n font-weight: 600;\n color: var(--mj-text-muted);\n }\n\n .feedback-value {\n color: var(--mj-text-primary);\n font-weight: 500;\n }\n\n .feedback-comments {\n width: 100%;\n margin-top: 8px;\n padding-top: 8px;\n border-top: 1px solid color-mix(in srgb, var(--mj-status-success) 25%, var(--mj-bg-surface));\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-style: italic;\n }\n\n .feedback-form {\n display: flex;\n flex-direction: column;\n gap: 16px;\n }\n\n .feedback-form label {\n display: block;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-muted);\n margin-bottom: 6px;\n }\n\n .rating-buttons {\n display: flex;\n gap: 4px;\n }\n\n .rating-btn {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.15s ease;\n }\n\n .rating-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n }\n\n .rating-btn.selected {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n }\n\n .toggle-group {\n display: flex;\n gap: 8px;\n }\n\n .toggle-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.15s ease;\n }\n\n .toggle-btn.active {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n .comments-row textarea {\n width: 100%;\n padding: 10px 12px;\n border: 2px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 13px;\n font-family: inherit;\n color: var(--mj-text-secondary);\n resize: vertical;\n box-sizing: border-box;\n }\n\n .comments-row textarea:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n }\n\n .comments-row textarea::placeholder {\n color: var(--mj-text-disabled);\n }\n\n .submit-feedback-btn {\n align-self: flex-start;\n }\n\n /* Responsive */\n @media (max-width: 1400px) {\n .stats-row {\n grid-template-columns: repeat(2, 1fr);\n }\n }\n\n @media (max-width: 1200px) {\n .filter-bar {\n flex-direction: column;\n align-items: stretch;\n }\n\n .filter-left, .filter-right {\n justify-content: center;\n }\n\n .table-header, .table-row {\n grid-template-columns: 2fr 120px 100px 100px 80px;\n }\n\n .col-eval, .col-time {\n display: none;\n }\n }\n\n @media (max-width: 768px) {\n .stats-row {\n grid-template-columns: 1fr;\n }\n\n .detail-panel {\n width: 100vw;\n max-width: 100vw;\n }\n }\n\n @media (max-width: 480px) {\n .table-header, .table-row {\n grid-template-columns: 1fr 80px 60px;\n }\n\n .col-score, .col-duration {\n display: none;\n }\n\n .chip {\n min-height: 44px;\n padding: 8px 14px;\n }\n\n .table-row {\n min-height: 44px;\n }\n }\n `]\n})\nexport class TestingRunsComponent implements OnInit, OnDestroy {\n @Input() initialState: Record<string, unknown> | null = null;\n @Output() stateChange = new EventEmitter<Record<string, unknown>>();\n\n private destroy$ = new Subject<void>();\n private filterTrigger$ = new BehaviorSubject<void>(undefined);\n\n // Filter state\n filterState: RunsFilterState = {\n status: 'all',\n timeRange: 'month',\n searchText: ''\n };\n\n // Feedback form state\n feedbackRating = 5;\n feedbackIsCorrect: boolean | null = null;\n feedbackComments = '';\n IsSubmittingFeedback = false;\n IsRefreshing = false;\n\n SelectedRun: TestRunWithFeedbackSummary | null = null;\n\n EvalPreferences: EvaluationPreferences = { ...DEFAULT_EVALUATION_PREFERENCES, showAuto: true };\n\n // Observables\n FilteredRuns$!: Observable<TestRunWithFeedbackSummary[]>;\n FilteredStats$!: Observable<FilteredStats>;\n\n // Constants\n readonly StatusChips: Array<{ value: StatusFilter; label: string; icon: string }> = [\n { value: 'all', label: 'All', icon: '' },\n { value: 'running', label: 'Running', icon: 'fa-solid fa-spinner fa-spin' },\n { value: 'passed', label: 'Passed', icon: 'fa-solid fa-check' },\n { value: 'failed', label: 'Failed', icon: 'fa-solid fa-times' },\n { value: 'error', label: 'Error', icon: 'fa-solid fa-exclamation-triangle' }\n ];\n\n readonly RatingValues: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n\n constructor(\n public instrumentationService: TestingInstrumentationService,\n private testingDialogService: TestingDialogService,\n private cdr: ChangeDetectorRef,\n private viewContainerRef: ViewContainerRef\n ) {}\n\n ngOnInit(): void {\n this.applyInitialState();\n this.updateServiceDateRange();\n this.setupObservables();\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n @HostListener('document:keydown.escape')\n OnEscapeKey(): void {\n if (this.SelectedRun) {\n this.CloseDetailPanel();\n }\n }\n\n // ------- Public Methods -------\n\n SetStatusFilter(status: StatusFilter): void {\n this.filterState.status = status;\n this.filterTrigger$.next();\n this.emitStateChange();\n this.cdr.markForCheck();\n }\n\n OnTimeRangeChange(event: Event): void {\n const select = event.target as HTMLSelectElement;\n this.filterState.timeRange = select.value as TimeRange;\n this.updateServiceDateRange();\n this.emitStateChange();\n this.cdr.markForCheck();\n }\n\n OnSearchInput(event: Event): void {\n const input = event.target as HTMLInputElement;\n this.filterState.searchText = input.value;\n this.filterTrigger$.next();\n this.emitStateChange();\n this.cdr.markForCheck();\n }\n\n ClearSearch(): void {\n this.filterState.searchText = '';\n this.filterTrigger$.next();\n this.emitStateChange();\n this.cdr.markForCheck();\n }\n\n Refresh(): void {\n this.IsRefreshing = true;\n this.instrumentationService.refresh();\n setTimeout(() => {\n this.IsRefreshing = false;\n this.cdr.markForCheck();\n }, 1000);\n }\n\n StartNewTest(): void {\n console.log('[TestingRuns] StartNewTest called, service IsPanelOpen before:', this.testingDialogService.IsPanelOpen);\n this.testingDialogService.OpenAsPanel();\n console.log('[TestingRuns] After OpenAsPanel, IsPanelOpen:', this.testingDialogService.IsPanelOpen);\n }\n\n SelectRun(run: TestRunWithFeedbackSummary): void {\n this.SelectedRun = run;\n this.resetFeedbackForm();\n this.cdr.markForCheck();\n }\n\n CloseDetailPanel(): void {\n this.SelectedRun = null;\n this.cdr.markForCheck();\n }\n\n NavigateToTest(run: TestRunWithFeedbackSummary, event: MouseEvent): void {\n event.stopPropagation();\n SharedService.Instance.OpenEntityRecord('MJ: Test Runs', CompositeKey.FromID(run.id));\n }\n\n RerunTest(run: TestRunWithFeedbackSummary): void {\n if (!run.testId) return;\n this.testingDialogService.OpenTestPanel(run.testId);\n }\n\n async SubmitFeedback(): Promise<void> {\n if (!this.SelectedRun) return;\n\n this.IsSubmittingFeedback = true;\n this.cdr.markForCheck();\n\n const success = await this.instrumentationService.submitFeedback(\n this.SelectedRun.id,\n this.feedbackRating,\n this.feedbackIsCorrect === true,\n this.feedbackComments\n );\n\n this.IsSubmittingFeedback = false;\n\n if (success) {\n // Update the selected run to reflect feedback was submitted\n this.SelectedRun = {\n ...this.SelectedRun,\n hasHumanFeedback: true,\n humanRating: this.feedbackRating,\n humanIsCorrect: this.feedbackIsCorrect,\n humanComments: this.feedbackComments\n };\n }\n\n this.cdr.markForCheck();\n }\n\n OnFeedbackCommentInput(event: Event): void {\n const textarea = event.target as HTMLTextAreaElement;\n this.feedbackComments = textarea.value;\n }\n\n TrackByRunId(_index: number, run: TestRunWithFeedbackSummary): string {\n return run.id;\n }\n\n // ------- Formatting Helpers -------\n\n FormatDuration(milliseconds: number): string {\n if (milliseconds < 1000) return `${Math.round(milliseconds)}ms`;\n const seconds = Math.floor(milliseconds / 1000);\n const minutes = Math.floor(seconds / 60);\n if (minutes > 0) return `${minutes}m ${seconds % 60}s`;\n return `${seconds}s`;\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 diffMinutes = Math.floor(diffMs / 60000);\n const diffHours = Math.floor(diffMs / 3600000);\n\n if (diffMinutes < 1) return 'Just now';\n if (diffMinutes < 60) return `${diffMinutes}m ago`;\n if (diffHours < 24) return `${diffHours}h ago`;\n\n return this.formatShortDate(date);\n }\n\n FormatDateTime(date: Date): string {\n const d = date instanceof Date ? date : new Date(date);\n return d.toLocaleString(undefined, {\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit'\n });\n }\n\n FormatPercent(value: number): string {\n return `${Math.round(value)}%`;\n }\n\n FormatCostTotal(cost: number): string {\n if (cost < 0.01) return '$0.00';\n if (cost < 1) return `$${cost.toFixed(2)}`;\n return `$${cost.toFixed(2)}`;\n }\n\n // ------- Private Methods -------\n\n private setupObservables(): void {\n const data$ = this.instrumentationService.testRunsWithFeedback$.pipe(\n takeUntil(this.destroy$)\n );\n\n this.FilteredRuns$ = combineLatest([data$, this.filterTrigger$]).pipe(\n map(([runs]) => this.applyClientFilters(runs)),\n takeUntil(this.destroy$)\n );\n\n this.FilteredStats$ = this.FilteredRuns$.pipe(\n map(runs => this.computeStats(runs)),\n takeUntil(this.destroy$)\n );\n }\n\n private applyClientFilters(runs: TestRunWithFeedbackSummary[]): TestRunWithFeedbackSummary[] {\n let filtered = runs;\n\n filtered = this.filterByStatus(filtered);\n filtered = this.filterBySearch(filtered);\n filtered = this.sortRunsWithRunningFirst(filtered);\n\n return filtered;\n }\n\n private filterByStatus(runs: TestRunWithFeedbackSummary[]): TestRunWithFeedbackSummary[] {\n const status = this.filterState.status;\n if (status === 'all') return runs;\n\n const statusMap: Record<string, string[]> = {\n running: ['Running'],\n passed: ['Passed'],\n failed: ['Failed'],\n error: ['Error', 'Timeout']\n };\n\n const validStatuses = statusMap[status] ?? [];\n return runs.filter(r => validStatuses.includes(r.status));\n }\n\n private filterBySearch(runs: TestRunWithFeedbackSummary[]): TestRunWithFeedbackSummary[] {\n const text = this.filterState.searchText.toLowerCase().trim();\n if (!text) return runs;\n return runs.filter(r => r.testName.toLowerCase().includes(text));\n }\n\n private sortRunsWithRunningFirst(runs: TestRunWithFeedbackSummary[]): TestRunWithFeedbackSummary[] {\n return [...runs].sort((a, b) => {\n // Running tests at the top\n if (a.status === 'Running' && b.status !== 'Running') return -1;\n if (a.status !== 'Running' && b.status === 'Running') return 1;\n // Then by StartedAt DESC\n return b.runDateTime.getTime() - a.runDateTime.getTime();\n });\n }\n\n private computeStats(runs: TestRunWithFeedbackSummary[]): FilteredStats {\n const total = runs.length;\n if (total === 0) {\n return { totalRuns: 0, passRate: 0, avgDuration: 0, totalCost: 0 };\n }\n\n const passed = runs.filter(r => r.status === 'Passed').length;\n const passRate = (passed / total) * 100;\n\n const completedRuns = runs.filter(r => r.duration > 0 && r.status !== 'Running');\n const avgDuration = completedRuns.length > 0\n ? completedRuns.reduce((sum, r) => sum + r.duration, 0) / completedRuns.length\n : 0;\n\n const totalCost = runs.reduce((sum, r) => sum + r.cost, 0);\n\n return { totalRuns: total, passRate, avgDuration, totalCost };\n }\n\n private updateServiceDateRange(): void {\n const now = new Date();\n let startDate: Date;\n\n switch (this.filterState.timeRange) {\n case 'today':\n startDate = new Date(now);\n startDate.setHours(0, 0, 0, 0);\n break;\n case 'week':\n startDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);\n break;\n case 'month':\n startDate = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);\n break;\n case '90days':\n startDate = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000);\n break;\n default:\n startDate = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);\n break;\n }\n\n this.instrumentationService.setDateRange(startDate, now);\n }\n\n private applyInitialState(): void {\n if (!this.initialState) return;\n\n const state = this.initialState;\n if (state['status'] && typeof state['status'] === 'string') {\n this.filterState.status = state['status'] as StatusFilter;\n }\n if (state['timeRange'] && typeof state['timeRange'] === 'string') {\n this.filterState.timeRange = state['timeRange'] as TimeRange;\n }\n if (state['searchText'] && typeof state['searchText'] === 'string') {\n this.filterState.searchText = state['searchText'] as string;\n }\n }\n\n private emitStateChange(): void {\n this.stateChange.emit({\n status: this.filterState.status,\n timeRange: this.filterState.timeRange,\n searchText: this.filterState.searchText\n });\n }\n\n private resetFeedbackForm(): void {\n this.feedbackRating = 5;\n this.feedbackIsCorrect = null;\n this.feedbackComments = '';\n this.IsSubmittingFeedback = false;\n }\n\n private formatShortDate(date: Date): string {\n const d = date instanceof Date ? date : new Date(date);\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n}\n"]}
1
+ {"version":3,"file":"testing-runs.component.js","sourceRoot":"","sources":["../../../src/Testing/components/testing-runs.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 ViewContainerRef,\n HostListener\n} from '@angular/core';\nimport { Observable, Subject, BehaviorSubject, combineLatest } from 'rxjs';\nimport { takeUntil, map } from 'rxjs/operators';\nimport { CompositeKey } from '@memberjunction/core';\nimport { SharedService } from '@memberjunction/ng-shared';\nimport { TestingDialogService } from '@memberjunction/ng-testing';\nimport { EvaluationPreferences, DEFAULT_EVALUATION_PREFERENCES } from '@memberjunction/ng-testing';\nimport {\n TestingInstrumentationService,\n TestRunWithFeedbackSummary,\n EvaluationSummaryMetrics\n} from '../services/testing-instrumentation.service';\n\ntype StatusFilter = 'all' | 'running' | 'passed' | 'failed' | 'error';\ntype TimeRange = 'today' | 'week' | 'month' | '90days';\n\ninterface RunsFilterState {\n status: StatusFilter;\n timeRange: TimeRange;\n searchText: string;\n}\n\ninterface FilteredStats {\n totalRuns: number;\n passRate: number;\n avgDuration: number;\n totalCost: number;\n}\n\n@Component({\n standalone: false,\n selector: 'app-testing-runs',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <!-- Page Header -->\n <div class=\"runs-container\" (keydown.escape)=\"CloseDetailPanel()\">\n <div class=\"page-header\">\n <div class=\"header-title\">\n <i class=\"fa-solid fa-list-check\"></i>\n <h2>Test Runs</h2>\n </div>\n <div class=\"header-actions\">\n <button class=\"btn btn-secondary\" (click)=\"Refresh()\" [disabled]=\"IsRefreshing\">\n <i class=\"fa-solid fa-sync-alt\" [class.spinning]=\"IsRefreshing\"></i>\n Refresh\n </button>\n <button class=\"btn btn-primary\" (click)=\"StartNewTest()\">\n <i class=\"fa-solid fa-play\"></i>\n Run Test\n </button>\n </div>\n </div>\n\n <!-- Filter Bar -->\n <div class=\"filter-bar\">\n <div class=\"filter-left\">\n <div class=\"filter-chips\">\n @for (chip of StatusChips; track chip.value) {\n <button\n class=\"chip\"\n [class.active]=\"filterState.status === chip.value\"\n [attr.data-status]=\"chip.value\"\n (click)=\"SetStatusFilter(chip.value)\"\n >\n @if (chip.icon) {\n <i [class]=\"chip.icon\"></i>\n }\n {{ chip.label }}\n </button>\n }\n </div>\n <span class=\"result-count\">{{ (FilteredRuns$ | async)?.length ?? 0 }} results</span>\n </div>\n <div class=\"filter-right\">\n <select\n class=\"time-select\"\n [value]=\"filterState.timeRange\"\n (change)=\"OnTimeRangeChange($event)\"\n >\n <option value=\"today\">Today</option>\n <option value=\"week\">This Week</option>\n <option value=\"month\">This Month</option>\n <option value=\"90days\">Last 90 Days</option>\n </select>\n <div class=\"search-box\">\n <i class=\"fa-solid fa-search\"></i>\n <input\n type=\"text\"\n placeholder=\"Search by test name...\"\n [value]=\"filterState.searchText\"\n (input)=\"OnSearchInput($event)\"\n />\n @if (filterState.searchText) {\n <button class=\"clear-search\" (click)=\"ClearSearch()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n </div>\n </div>\n\n <!-- Summary Stats Row -->\n @if (FilteredStats$ | async; as stats) {\n <div class=\"stats-row\">\n <div class=\"stat-card\">\n <div class=\"stat-icon total\"><i class=\"fa-solid fa-hashtag\"></i></div>\n <div class=\"stat-body\">\n <div class=\"stat-value\">{{ stats.totalRuns }}</div>\n <div class=\"stat-label\">Total Runs</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon pass\"><i class=\"fa-solid fa-check-circle\"></i></div>\n <div class=\"stat-body\">\n <div class=\"stat-value\">{{ FormatPercent(stats.passRate) }}</div>\n <div class=\"stat-label\">Pass Rate</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon duration\"><i class=\"fa-solid fa-clock\"></i></div>\n <div class=\"stat-body\">\n <div class=\"stat-value\">{{ FormatDuration(stats.avgDuration) }}</div>\n <div class=\"stat-label\">Avg Duration</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon cost\"><i class=\"fa-solid fa-dollar-sign\"></i></div>\n <div class=\"stat-body\">\n <div class=\"stat-value\">{{ FormatCostTotal(stats.totalCost) }}</div>\n <div class=\"stat-label\">Total Cost</div>\n </div>\n </div>\n </div>\n }\n\n <!-- Runs Table -->\n <div class=\"runs-table-wrapper\">\n <div class=\"table-header\">\n <div class=\"col col-name\">Test Name</div>\n <div class=\"col col-eval\">Evaluation</div>\n <div class=\"col col-score\">Score</div>\n <div class=\"col col-duration\">Duration</div>\n <div class=\"col col-cost\">Cost</div>\n <div class=\"col col-time\">Started</div>\n <div class=\"col col-actions\">Actions</div>\n </div>\n\n @if (instrumentationService.isLoading$ | async) {\n <div class=\"table-loading\">\n <mj-loading text=\"Loading test runs...\"></mj-loading>\n </div>\n } @else if ((FilteredRuns$ | async)?.length === 0) {\n <div class=\"table-empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n <p>No test runs found</p>\n <span class=\"empty-hint\">Try adjusting your filters or run a new test.</span>\n </div>\n } @else {\n @for (run of FilteredRuns$ | async; track TrackByRunId($index, run)) {\n <div\n class=\"table-row\"\n [class.is-running]=\"run.status === 'Running'\"\n [class.is-selected]=\"SelectedRun?.id === run.id\"\n (click)=\"SelectRun(run)\"\n >\n <div class=\"col col-name\">\n <span class=\"test-name-link\" (click)=\"NavigateToTest(run, $event)\">\n {{ run.testName }}\n </span>\n </div>\n <div class=\"col col-eval\">\n <app-evaluation-badge\n [executionStatus]=\"run.status\"\n [originalStatus]=\"run.status\"\n [autoScore]=\"run.score\"\n [passedChecks]=\"run.passedChecks\"\n [failedChecks]=\"run.failedChecks\"\n [totalChecks]=\"run.totalChecks\"\n [humanRating]=\"run.humanRating\"\n [humanIsCorrect]=\"run.humanIsCorrect\"\n [hasHumanFeedback]=\"run.hasHumanFeedback\"\n [preferences]=\"EvalPreferences\"\n mode=\"compact\"\n ></app-evaluation-badge>\n </div>\n <div class=\"col col-score\">\n <app-score-indicator [score]=\"run.score\" [showBar]=\"true\"></app-score-indicator>\n </div>\n <div class=\"col col-duration\">{{ FormatDuration(run.duration) }}</div>\n <div class=\"col col-cost\">\n <app-cost-display [cost]=\"run.cost\"></app-cost-display>\n </div>\n <div class=\"col col-time\">{{ FormatRelativeTime(run.runDateTime) }}</div>\n <div class=\"col col-actions\">\n <button class=\"icon-btn\" title=\"View details\" (click)=\"SelectRun(run); $event.stopPropagation()\">\n <i class=\"fa-solid fa-eye\"></i>\n </button>\n <button class=\"icon-btn\" title=\"Re-run test\" (click)=\"RerunTest(run); $event.stopPropagation()\">\n <i class=\"fa-solid fa-rotate-right\"></i>\n </button>\n </div>\n </div>\n }\n }\n </div>\n\n <!-- Detail Panel (slide-in) -->\n @if (SelectedRun) {\n <div class=\"detail-overlay\" (click)=\"CloseDetailPanel()\"></div>\n <div class=\"detail-panel\">\n <div class=\"detail-panel-header\">\n <div class=\"detail-title-section\">\n <h3>{{ SelectedRun.testName }}</h3>\n <app-test-status-badge [status]=\"SelectedRun.status\"></app-test-status-badge>\n </div>\n <button class=\"close-btn\" (click)=\"CloseDetailPanel()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <div class=\"detail-panel-body\">\n <!-- Metrics row -->\n <div class=\"detail-metrics\">\n <div class=\"detail-metric\">\n <span class=\"dm-label\">Score</span>\n <app-score-indicator [score]=\"SelectedRun.score\" [showBar]=\"true\"></app-score-indicator>\n </div>\n <div class=\"detail-metric\">\n <span class=\"dm-label\">Duration</span>\n <span class=\"dm-value\">{{ FormatDuration(SelectedRun.duration) }}</span>\n </div>\n <div class=\"detail-metric\">\n <span class=\"dm-label\">Cost</span>\n <app-cost-display [cost]=\"SelectedRun.cost\"></app-cost-display>\n </div>\n <div class=\"detail-metric\">\n <span class=\"dm-label\">Started</span>\n <span class=\"dm-value\">{{ FormatDateTime(SelectedRun.runDateTime) }}</span>\n </div>\n </div>\n\n <!-- Evaluation Badge (expanded) -->\n <div class=\"detail-section\">\n <h4><i class=\"fa-solid fa-clipboard-check\"></i> Evaluation</h4>\n <app-evaluation-badge\n [executionStatus]=\"SelectedRun.status\"\n [originalStatus]=\"SelectedRun.status\"\n [autoScore]=\"SelectedRun.score\"\n [passedChecks]=\"SelectedRun.passedChecks\"\n [failedChecks]=\"SelectedRun.failedChecks\"\n [totalChecks]=\"SelectedRun.totalChecks\"\n [humanRating]=\"SelectedRun.humanRating\"\n [humanIsCorrect]=\"SelectedRun.humanIsCorrect\"\n [hasHumanFeedback]=\"SelectedRun.hasHumanFeedback\"\n [preferences]=\"EvalPreferences\"\n mode=\"expanded\"\n ></app-evaluation-badge>\n </div>\n\n <!-- Execution Context -->\n @if (SelectedRun.targetType) {\n <div class=\"detail-section\">\n <h4><i class=\"fa-solid fa-server\"></i> Execution Context</h4>\n <mj-execution-context></mj-execution-context>\n </div>\n }\n\n <!-- Inline Feedback Form -->\n <div class=\"detail-section feedback-section\">\n <h4><i class=\"fa-solid fa-comment-dots\"></i> Human Feedback</h4>\n @if (SelectedRun.hasHumanFeedback) {\n <div class=\"existing-feedback\">\n <span class=\"feedback-label\">Rating:</span>\n <span class=\"feedback-value\">{{ SelectedRun.humanRating }}/10</span>\n <span class=\"feedback-label\">Correct:</span>\n <span class=\"feedback-value\">\n @if (SelectedRun.humanIsCorrect === true) {\n <i class=\"fa-solid fa-check\" style=\"color: var(--mj-status-success)\"></i> Yes\n } @else if (SelectedRun.humanIsCorrect === false) {\n <i class=\"fa-solid fa-times\" style=\"color: var(--mj-status-error)\"></i> No\n } @else {\n --\n }\n </span>\n @if (SelectedRun.humanComments) {\n <div class=\"feedback-comments\">{{ SelectedRun.humanComments }}</div>\n }\n </div>\n } @else {\n <div class=\"feedback-form\">\n <div class=\"rating-row\">\n <label>Rating</label>\n <div class=\"rating-buttons\">\n @for (n of RatingValues; track n) {\n <button\n class=\"rating-btn\"\n [class.selected]=\"feedbackRating === n\"\n (click)=\"feedbackRating = n\"\n >\n {{ n }}\n </button>\n }\n </div>\n </div>\n <div class=\"correctness-row\">\n <label>Is the result correct?</label>\n <div class=\"toggle-group\">\n <button\n class=\"toggle-btn\"\n [class.active]=\"feedbackIsCorrect === true\"\n (click)=\"feedbackIsCorrect = true\"\n >\n <i class=\"fa-solid fa-check\"></i> Yes\n </button>\n <button\n class=\"toggle-btn\"\n [class.active]=\"feedbackIsCorrect === false\"\n (click)=\"feedbackIsCorrect = false\"\n >\n <i class=\"fa-solid fa-times\"></i> No\n </button>\n </div>\n </div>\n <div class=\"comments-row\">\n <label>Comments</label>\n <textarea\n rows=\"3\"\n placeholder=\"Optional feedback comments...\"\n [value]=\"feedbackComments\"\n (input)=\"OnFeedbackCommentInput($event)\"\n ></textarea>\n </div>\n <button\n class=\"btn btn-primary submit-feedback-btn\"\n (click)=\"SubmitFeedback()\"\n [disabled]=\"IsSubmittingFeedback\"\n >\n <i class=\"fa-solid fa-paper-plane\"></i>\n {{ IsSubmittingFeedback ? 'Submitting...' : 'Submit Feedback' }}\n </button>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n `,\n styles: [`\n /* ==========================================\n Testing Runs Component\n ========================================== */\n\n .runs-container {\n padding: 24px;\n height: 100%;\n overflow-y: auto;\n background: var(--mj-bg-surface-card);\n position: relative;\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 }\n\n .header-title {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .header-title i {\n font-size: 22px;\n color: var(--mj-brand-primary);\n }\n\n .header-title h2 {\n margin: 0;\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n }\n\n .header-actions {\n display: flex;\n gap: 10px;\n }\n\n /* Buttons */\n .btn {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 10px 18px;\n border: none;\n border-radius: 10px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n }\n\n .btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-md);\n }\n\n .btn-secondary {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n }\n\n .btn-secondary:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n }\n\n .spinning {\n animation: spin 1s linear infinite;\n }\n\n @keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n\n /* Filter Bar */\n .filter-bar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 16px;\n margin-bottom: 20px;\n padding: 14px 20px;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n }\n\n .filter-left {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .filter-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n }\n\n .chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 7px 14px;\n background: var(--mj-bg-surface-sunken);\n border: 2px solid transparent;\n border-radius: 20px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .chip:hover {\n background: var(--mj-border-default);\n }\n\n .chip.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n }\n\n .chip.active[data-status=\"running\"] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n }\n\n .chip.active[data-status=\"passed\"] {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n }\n\n .chip.active[data-status=\"failed\"] {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n }\n\n .chip.active[data-status=\"error\"] {\n background: var(--mj-status-warning);\n border-color: var(--mj-status-warning);\n }\n\n .result-count {\n font-size: 12px;\n color: var(--mj-text-disabled);\n font-weight: 500;\n white-space: nowrap;\n }\n\n .filter-right {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .time-select {\n padding: 8px 12px;\n border: 2px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface);\n cursor: pointer;\n }\n\n .time-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n }\n\n .search-box {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 14px;\n background: var(--mj-bg-surface-card);\n border: 2px solid var(--mj-border-default);\n border-radius: 8px;\n min-width: 220px;\n transition: border-color 0.2s ease;\n }\n\n .search-box:focus-within {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n }\n\n .search-box i {\n color: var(--mj-text-disabled);\n font-size: 13px;\n }\n\n .search-box input {\n flex: 1;\n border: none;\n background: transparent;\n outline: none;\n font-size: 13px;\n color: var(--mj-text-secondary);\n }\n\n .search-box input::placeholder {\n color: var(--mj-text-disabled);\n }\n\n .clear-search {\n border: none;\n background: transparent;\n color: var(--mj-text-disabled);\n cursor: pointer;\n padding: 2px 4px;\n border-radius: 4px;\n }\n\n .clear-search:hover {\n color: var(--mj-text-muted);\n background: var(--mj-border-default);\n }\n\n /* Stats Row */\n .stats-row {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 14px;\n margin-bottom: 20px;\n }\n\n .stat-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 16px 20px;\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n }\n\n .stat-icon {\n width: 42px;\n height: 42px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n }\n\n .stat-icon.total { background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface)); color: var(--mj-brand-primary); }\n .stat-icon.pass { background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface)); color: var(--mj-status-success); }\n .stat-icon.duration { background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface)); color: var(--mj-brand-primary); }\n .stat-icon.cost { background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface)); color: var(--mj-status-warning); }\n\n .stat-body {\n flex: 1;\n }\n\n .stat-value {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.1;\n }\n\n .stat-label {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 2px;\n }\n\n /* Runs Table */\n .runs-table-wrapper {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n }\n\n .table-header {\n display: grid;\n grid-template-columns: 2fr 140px 120px 100px 100px 120px 90px;\n gap: 12px;\n padding: 14px 24px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .table-row {\n display: grid;\n grid-template-columns: 2fr 140px 120px 100px 100px 120px 90px;\n gap: 12px;\n padding: 14px 24px;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n cursor: pointer;\n transition: background 0.15s ease;\n align-items: center;\n }\n\n .table-row:last-child {\n border-bottom: none;\n }\n\n .table-row:hover {\n background: var(--mj-bg-surface-card);\n }\n\n .table-row.is-selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-brand-primary);\n }\n\n .table-row.is-running {\n background: color-mix(in srgb, var(--mj-brand-primary) 4%, var(--mj-bg-surface));\n }\n\n .table-row.is-running .test-name-link::after {\n content: '';\n display: inline-block;\n width: 8px;\n height: 8px;\n background: var(--mj-brand-primary);\n border-radius: 50%;\n margin-left: 8px;\n animation: pulse-dot 1.5s infinite;\n }\n\n @keyframes pulse-dot {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.3; }\n }\n\n .col {\n display: flex;\n align-items: center;\n font-size: 13px;\n color: var(--mj-text-secondary);\n overflow: hidden;\n }\n\n .test-name-link {\n font-weight: 600;\n color: var(--mj-text-primary);\n cursor: pointer;\n text-decoration: none;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .test-name-link:hover {\n color: var(--mj-brand-primary);\n text-decoration: underline;\n }\n\n .col-actions {\n gap: 6px;\n justify-content: flex-end;\n }\n\n .icon-btn {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n color: var(--mj-text-muted);\n cursor: pointer;\n border-radius: 8px;\n font-size: 13px;\n transition: all 0.2s ease;\n }\n\n .icon-btn:hover {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transform: translateY(-1px);\n box-shadow: var(--mj-shadow-md);\n }\n\n /* Table states */\n .table-loading {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 80px 40px;\n }\n\n .table-empty {\n padding: 80px 40px;\n text-align: center;\n }\n\n .table-empty i {\n font-size: 48px;\n color: var(--mj-border-strong);\n margin-bottom: 16px;\n }\n\n .table-empty p {\n font-size: 16px;\n color: var(--mj-text-muted);\n margin: 0 0 8px 0;\n }\n\n .empty-hint {\n font-size: 13px;\n color: var(--mj-text-disabled);\n }\n\n /* Detail Panel Overlay */\n .detail-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 999;\n }\n\n /* Detail Panel */\n .detail-panel {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 520px;\n max-width: 90vw;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-lg);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n animation: slideIn 0.25s ease-out;\n }\n\n @keyframes slideIn {\n from { transform: translateX(100%); }\n to { transform: translateX(0); }\n }\n\n .detail-panel-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n padding: 20px 24px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n }\n\n .detail-title-section {\n display: flex;\n flex-direction: column;\n gap: 8px;\n flex: 1;\n min-width: 0;\n }\n\n .detail-title-section h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .close-btn {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n flex-shrink: 0;\n margin-left: 12px;\n transition: all 0.15s ease;\n }\n\n .close-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n }\n\n .detail-panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 20px 24px;\n }\n\n .detail-metrics {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px;\n margin-bottom: 24px;\n }\n\n .detail-metric {\n padding: 12px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n border-left: 3px solid var(--mj-brand-primary);\n }\n\n .dm-label {\n display: block;\n font-size: 10px;\n font-weight: 700;\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 6px;\n }\n\n .dm-value {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .detail-section {\n margin-bottom: 24px;\n }\n\n .detail-section h4 {\n font-size: 13px;\n font-weight: 700;\n color: var(--mj-text-secondary);\n margin: 0 0 12px 0;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .detail-section h4 i {\n color: var(--mj-brand-primary);\n font-size: 14px;\n }\n\n /* Feedback Section */\n .existing-feedback {\n display: flex;\n flex-wrap: wrap;\n gap: 8px 16px;\n align-items: center;\n padding: 14px;\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n border-radius: 8px;\n font-size: 13px;\n }\n\n .feedback-label {\n font-weight: 600;\n color: var(--mj-text-muted);\n }\n\n .feedback-value {\n color: var(--mj-text-primary);\n font-weight: 500;\n }\n\n .feedback-comments {\n width: 100%;\n margin-top: 8px;\n padding-top: 8px;\n border-top: 1px solid color-mix(in srgb, var(--mj-status-success) 25%, var(--mj-bg-surface));\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-style: italic;\n }\n\n .feedback-form {\n display: flex;\n flex-direction: column;\n gap: 16px;\n }\n\n .feedback-form label {\n display: block;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-muted);\n margin-bottom: 6px;\n }\n\n .rating-buttons {\n display: flex;\n gap: 4px;\n }\n\n .rating-btn {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.15s ease;\n }\n\n .rating-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n }\n\n .rating-btn.selected {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n }\n\n .toggle-group {\n display: flex;\n gap: 8px;\n }\n\n .toggle-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.15s ease;\n }\n\n .toggle-btn.active {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n .comments-row textarea {\n width: 100%;\n padding: 10px 12px;\n border: 2px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 13px;\n font-family: inherit;\n color: var(--mj-text-secondary);\n resize: vertical;\n box-sizing: border-box;\n }\n\n .comments-row textarea:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n }\n\n .comments-row textarea::placeholder {\n color: var(--mj-text-disabled);\n }\n\n .submit-feedback-btn {\n align-self: flex-start;\n }\n\n /* Responsive */\n @media (max-width: 1400px) {\n .stats-row {\n grid-template-columns: repeat(2, 1fr);\n }\n }\n\n @media (max-width: 1200px) {\n .filter-bar {\n flex-direction: column;\n align-items: stretch;\n }\n\n .filter-left, .filter-right {\n justify-content: center;\n }\n\n .table-header, .table-row {\n grid-template-columns: 2fr 120px 100px 100px 80px;\n }\n\n .col-eval, .col-time {\n display: none;\n }\n }\n\n @media (max-width: 768px) {\n .stats-row {\n grid-template-columns: 1fr;\n }\n\n .detail-panel {\n width: 100vw;\n max-width: 100vw;\n }\n }\n\n @media (max-width: 480px) {\n .table-header, .table-row {\n grid-template-columns: 1fr 80px 60px;\n }\n\n .col-score, .col-duration {\n display: none;\n }\n\n .chip {\n min-height: 44px;\n padding: 8px 14px;\n }\n\n .table-row {\n min-height: 44px;\n }\n }\n `]\n})\nexport class TestingRunsComponent implements OnInit, OnDestroy {\n @Input() initialState: Record<string, unknown> | null = null;\n @Output() stateChange = new EventEmitter<Record<string, unknown>>();\n\n private destroy$ = new Subject<void>();\n private filterTrigger$ = new BehaviorSubject<void>(undefined);\n\n // Filter state\n filterState: RunsFilterState = {\n status: 'all',\n timeRange: 'month',\n searchText: ''\n };\n\n // Feedback form state\n feedbackRating = 5;\n feedbackIsCorrect: boolean | null = null;\n feedbackComments = '';\n IsSubmittingFeedback = false;\n IsRefreshing = false;\n\n SelectedRun: TestRunWithFeedbackSummary | null = null;\n\n EvalPreferences: EvaluationPreferences = { ...DEFAULT_EVALUATION_PREFERENCES, showAuto: true };\n\n // Observables\n FilteredRuns$!: Observable<TestRunWithFeedbackSummary[]>;\n FilteredStats$!: Observable<FilteredStats>;\n\n // Constants\n readonly StatusChips: Array<{ value: StatusFilter; label: string; icon: string }> = [\n { value: 'all', label: 'All', icon: '' },\n { value: 'running', label: 'Running', icon: 'fa-solid fa-spinner fa-spin' },\n { value: 'passed', label: 'Passed', icon: 'fa-solid fa-check' },\n { value: 'failed', label: 'Failed', icon: 'fa-solid fa-times' },\n { value: 'error', label: 'Error', icon: 'fa-solid fa-exclamation-triangle' }\n ];\n\n readonly RatingValues: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n\n constructor(\n public instrumentationService: TestingInstrumentationService,\n private testingDialogService: TestingDialogService,\n private cdr: ChangeDetectorRef,\n private viewContainerRef: ViewContainerRef\n ) {}\n\n ngOnInit(): void {\n this.applyInitialState();\n this.updateServiceDateRange();\n this.setupObservables();\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n @HostListener('document:keydown.escape')\n OnEscapeKey(): void {\n if (this.SelectedRun) {\n this.CloseDetailPanel();\n }\n }\n\n // ------- Public Methods -------\n\n SetStatusFilter(status: StatusFilter): void {\n this.filterState.status = status;\n this.filterTrigger$.next();\n this.emitStateChange();\n this.cdr.markForCheck();\n }\n\n OnTimeRangeChange(event: Event): void {\n const select = event.target as HTMLSelectElement;\n this.filterState.timeRange = select.value as TimeRange;\n this.updateServiceDateRange();\n this.emitStateChange();\n this.cdr.markForCheck();\n }\n\n OnSearchInput(event: Event): void {\n const input = event.target as HTMLInputElement;\n this.filterState.searchText = input.value;\n this.filterTrigger$.next();\n this.emitStateChange();\n this.cdr.markForCheck();\n }\n\n ClearSearch(): void {\n this.filterState.searchText = '';\n this.filterTrigger$.next();\n this.emitStateChange();\n this.cdr.markForCheck();\n }\n\n Refresh(): void {\n this.IsRefreshing = true;\n this.instrumentationService.refresh();\n setTimeout(() => {\n this.IsRefreshing = false;\n this.cdr.markForCheck();\n }, 1000);\n }\n\n StartNewTest(): void {\n console.log('[TestingRuns] StartNewTest called, service IsPanelOpen before:', this.testingDialogService.IsPanelOpen);\n this.testingDialogService.OpenAsPanel();\n console.log('[TestingRuns] After OpenAsPanel, IsPanelOpen:', this.testingDialogService.IsPanelOpen);\n }\n\n SelectRun(run: TestRunWithFeedbackSummary): void {\n this.SelectedRun = run;\n this.resetFeedbackForm();\n this.cdr.markForCheck();\n }\n\n CloseDetailPanel(): void {\n this.SelectedRun = null;\n this.cdr.markForCheck();\n }\n\n NavigateToTest(run: TestRunWithFeedbackSummary, event: MouseEvent): void {\n event.stopPropagation();\n SharedService.Instance.OpenEntityRecord('MJ: Test Runs', CompositeKey.FromID(run.id));\n }\n\n RerunTest(run: TestRunWithFeedbackSummary): void {\n if (!run.testId) return;\n this.testingDialogService.OpenTestPanel(run.testId);\n }\n\n async SubmitFeedback(): Promise<void> {\n if (!this.SelectedRun) return;\n\n this.IsSubmittingFeedback = true;\n this.cdr.markForCheck();\n\n const success = await this.instrumentationService.submitFeedback(\n this.SelectedRun.id,\n this.feedbackRating,\n this.feedbackIsCorrect === true,\n this.feedbackComments\n );\n\n this.IsSubmittingFeedback = false;\n\n if (success) {\n // Update the selected run to reflect feedback was submitted\n this.SelectedRun = {\n ...this.SelectedRun,\n hasHumanFeedback: true,\n humanRating: this.feedbackRating,\n humanIsCorrect: this.feedbackIsCorrect,\n humanComments: this.feedbackComments\n };\n }\n\n this.cdr.markForCheck();\n }\n\n OnFeedbackCommentInput(event: Event): void {\n const textarea = event.target as HTMLTextAreaElement;\n this.feedbackComments = textarea.value;\n }\n\n TrackByRunId(_index: number, run: TestRunWithFeedbackSummary): string {\n return run.id;\n }\n\n // ------- Formatting Helpers -------\n\n FormatDuration(milliseconds: number): string {\n if (milliseconds < 1000) return `${Math.round(milliseconds)}ms`;\n const seconds = Math.floor(milliseconds / 1000);\n const minutes = Math.floor(seconds / 60);\n if (minutes > 0) return `${minutes}m ${seconds % 60}s`;\n return `${seconds}s`;\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 diffMinutes = Math.floor(diffMs / 60000);\n const diffHours = Math.floor(diffMs / 3600000);\n\n if (diffMinutes < 1) return 'Just now';\n if (diffMinutes < 60) return `${diffMinutes}m ago`;\n if (diffHours < 24) return `${diffHours}h ago`;\n\n return this.formatShortDate(date);\n }\n\n FormatDateTime(date: Date): string {\n const d = date instanceof Date ? date : new Date(date);\n return d.toLocaleString(undefined, {\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit'\n });\n }\n\n FormatPercent(value: number): string {\n return `${Math.round(value)}%`;\n }\n\n FormatCostTotal(cost: number): string {\n if (cost < 0.01) return '$0.00';\n if (cost < 1) return `$${cost.toFixed(2)}`;\n return `$${cost.toFixed(2)}`;\n }\n\n // ------- Private Methods -------\n\n private setupObservables(): void {\n const data$ = this.instrumentationService.testRunsWithFeedback$.pipe(\n takeUntil(this.destroy$)\n );\n\n this.FilteredRuns$ = combineLatest([data$, this.filterTrigger$]).pipe(\n map(([runs]) => this.applyClientFilters(runs)),\n takeUntil(this.destroy$)\n );\n\n this.FilteredStats$ = this.FilteredRuns$.pipe(\n map(runs => this.computeStats(runs)),\n takeUntil(this.destroy$)\n );\n }\n\n private applyClientFilters(runs: TestRunWithFeedbackSummary[]): TestRunWithFeedbackSummary[] {\n let filtered = runs;\n\n filtered = this.filterByStatus(filtered);\n filtered = this.filterBySearch(filtered);\n filtered = this.sortRunsWithRunningFirst(filtered);\n\n return filtered;\n }\n\n private filterByStatus(runs: TestRunWithFeedbackSummary[]): TestRunWithFeedbackSummary[] {\n const status = this.filterState.status;\n if (status === 'all') return runs;\n\n const statusMap: Record<string, string[]> = {\n running: ['Running'],\n passed: ['Passed'],\n failed: ['Failed'],\n error: ['Error', 'Timeout']\n };\n\n const validStatuses = statusMap[status] ?? [];\n return runs.filter(r => validStatuses.includes(r.status));\n }\n\n private filterBySearch(runs: TestRunWithFeedbackSummary[]): TestRunWithFeedbackSummary[] {\n const text = this.filterState.searchText.toLowerCase().trim();\n if (!text) return runs;\n return runs.filter(r => r.testName.toLowerCase().includes(text));\n }\n\n private sortRunsWithRunningFirst(runs: TestRunWithFeedbackSummary[]): TestRunWithFeedbackSummary[] {\n return [...runs].sort((a, b) => {\n // Running tests at the top\n if (a.status === 'Running' && b.status !== 'Running') return -1;\n if (a.status !== 'Running' && b.status === 'Running') return 1;\n // Then by StartedAt DESC\n return b.runDateTime.getTime() - a.runDateTime.getTime();\n });\n }\n\n private computeStats(runs: TestRunWithFeedbackSummary[]): FilteredStats {\n const total = runs.length;\n if (total === 0) {\n return { totalRuns: 0, passRate: 0, avgDuration: 0, totalCost: 0 };\n }\n\n const passed = runs.filter(r => r.status === 'Passed').length;\n const passRate = (passed / total) * 100;\n\n const completedRuns = runs.filter(r => r.duration > 0 && r.status !== 'Running');\n const avgDuration = completedRuns.length > 0\n ? completedRuns.reduce((sum, r) => sum + r.duration, 0) / completedRuns.length\n : 0;\n\n const totalCost = runs.reduce((sum, r) => sum + r.cost, 0);\n\n return { totalRuns: total, passRate, avgDuration, totalCost };\n }\n\n private updateServiceDateRange(): void {\n const now = new Date();\n let startDate: Date;\n\n switch (this.filterState.timeRange) {\n case 'today':\n startDate = new Date(now);\n startDate.setHours(0, 0, 0, 0);\n break;\n case 'week':\n startDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);\n break;\n case 'month':\n startDate = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);\n break;\n case '90days':\n startDate = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000);\n break;\n default:\n startDate = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);\n break;\n }\n\n this.instrumentationService.setDateRange(startDate, now);\n }\n\n private applyInitialState(): void {\n if (!this.initialState) return;\n\n const state = this.initialState;\n if (state['status'] && typeof state['status'] === 'string') {\n this.filterState.status = state['status'] as StatusFilter;\n }\n if (state['timeRange'] && typeof state['timeRange'] === 'string') {\n this.filterState.timeRange = state['timeRange'] as TimeRange;\n }\n if (state['searchText'] && typeof state['searchText'] === 'string') {\n this.filterState.searchText = state['searchText'] as string;\n }\n }\n\n private emitStateChange(): void {\n this.stateChange.emit({\n status: this.filterState.status,\n timeRange: this.filterState.timeRange,\n searchText: this.filterState.searchText\n });\n }\n\n private resetFeedbackForm(): void {\n this.feedbackRating = 5;\n this.feedbackIsCorrect = null;\n this.feedbackComments = '';\n this.IsSubmittingFeedback = false;\n }\n\n private formatShortDate(date: Date): string {\n const d = date instanceof Date ? date : new Date(date);\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-dashboards",
3
- "version": "5.33.0",
3
+ "version": "5.34.0",
4
4
  "description": "MemberJunction Dashboards",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -93,57 +93,57 @@
93
93
  "@codemirror/merge": "^6.11.2",
94
94
  "@codemirror/state": "^6.5.4",
95
95
  "@codemirror/view": "^6.39.12",
96
- "@memberjunction/actions-base": "5.33.0",
97
- "@memberjunction/ai-core-plus": "5.33.0",
98
- "@memberjunction/ai-engine-base": "5.33.0",
99
- "@memberjunction/api-keys-base": "5.33.0",
100
- "@memberjunction/core": "5.33.0",
101
- "@memberjunction/core-entities": "5.33.0",
102
- "@memberjunction/credentials": "5.33.0",
103
- "@memberjunction/export-engine": "5.33.0",
104
- "@memberjunction/global": "5.33.0",
105
- "@memberjunction/graphql-dataprovider": "5.33.0",
106
- "@memberjunction/integration-engine-base": "5.33.0",
107
- "@memberjunction/interactive-component-types": "5.33.0",
108
- "@memberjunction/ng-action-gallery": "5.33.0",
109
- "@memberjunction/ng-actions": "5.33.0",
110
- "@memberjunction/ng-agent-requests": "5.33.0",
111
- "@memberjunction/ng-agents": "5.33.0",
112
- "@memberjunction/ng-ai-test-harness": "5.33.0",
113
- "@memberjunction/ng-archive-manager": "5.33.0",
114
- "@memberjunction/ng-base-application": "5.33.0",
115
- "@memberjunction/ng-base-types": "5.33.0",
116
- "@memberjunction/ng-clustering": "5.33.0",
117
- "@memberjunction/ng-code-editor": "5.33.0",
118
- "@memberjunction/ng-container-directives": "5.33.0",
119
- "@memberjunction/ng-conversations": "5.33.0",
120
- "@memberjunction/ng-core-entity-forms": "5.33.0",
121
- "@memberjunction/ng-credentials": "5.33.0",
122
- "@memberjunction/ng-dashboard-viewer": "5.33.0",
123
- "@memberjunction/ng-entity-relationship-diagram": "5.33.0",
124
- "@memberjunction/ng-entity-viewer": "5.33.0",
125
- "@memberjunction/ng-explorer-settings": "5.33.0",
126
- "@memberjunction/ng-export-service": "5.33.0",
127
- "@memberjunction/ng-filter-builder": "5.33.0",
128
- "@memberjunction/ng-list-management": "5.33.0",
129
- "@memberjunction/ng-map-view": "5.33.0",
130
- "@memberjunction/ng-markdown": "5.33.0",
131
- "@memberjunction/ng-notifications": "5.33.0",
132
- "@memberjunction/ng-query-viewer": "5.33.0",
133
- "@memberjunction/ng-react": "5.33.0",
134
- "@memberjunction/ng-resource-permissions": "5.33.0",
135
- "@memberjunction/ng-scheduling": "5.33.0",
136
- "@memberjunction/ng-search": "5.33.0",
137
- "@memberjunction/ng-shared": "5.33.0",
138
- "@memberjunction/ng-shared-generic": "5.33.0",
139
- "@memberjunction/ng-testing": "5.33.0",
140
- "@memberjunction/ng-trees": "5.33.0",
141
- "@memberjunction/ng-ui-components": "5.33.0",
142
- "@memberjunction/ng-versions": "5.33.0",
143
- "@memberjunction/ng-word-cloud": "5.33.0",
144
- "@memberjunction/skip-types": "5.33.0",
145
- "@memberjunction/templates-base-types": "5.33.0",
146
- "@memberjunction/testing-engine-base": "5.33.0",
96
+ "@memberjunction/actions-base": "5.34.0",
97
+ "@memberjunction/ai-core-plus": "5.34.0",
98
+ "@memberjunction/ai-engine-base": "5.34.0",
99
+ "@memberjunction/api-keys-base": "5.34.0",
100
+ "@memberjunction/core": "5.34.0",
101
+ "@memberjunction/core-entities": "5.34.0",
102
+ "@memberjunction/credentials": "5.34.0",
103
+ "@memberjunction/export-engine": "5.34.0",
104
+ "@memberjunction/global": "5.34.0",
105
+ "@memberjunction/graphql-dataprovider": "5.34.0",
106
+ "@memberjunction/integration-engine-base": "5.34.0",
107
+ "@memberjunction/interactive-component-types": "5.34.0",
108
+ "@memberjunction/ng-action-gallery": "5.34.0",
109
+ "@memberjunction/ng-actions": "5.34.0",
110
+ "@memberjunction/ng-agent-requests": "5.34.0",
111
+ "@memberjunction/ng-agents": "5.34.0",
112
+ "@memberjunction/ng-ai-test-harness": "5.34.0",
113
+ "@memberjunction/ng-archive-manager": "5.34.0",
114
+ "@memberjunction/ng-base-application": "5.34.0",
115
+ "@memberjunction/ng-base-types": "5.34.0",
116
+ "@memberjunction/ng-clustering": "5.34.0",
117
+ "@memberjunction/ng-code-editor": "5.34.0",
118
+ "@memberjunction/ng-container-directives": "5.34.0",
119
+ "@memberjunction/ng-conversations": "5.34.0",
120
+ "@memberjunction/ng-core-entity-forms": "5.34.0",
121
+ "@memberjunction/ng-credentials": "5.34.0",
122
+ "@memberjunction/ng-dashboard-viewer": "5.34.0",
123
+ "@memberjunction/ng-entity-relationship-diagram": "5.34.0",
124
+ "@memberjunction/ng-entity-viewer": "5.34.0",
125
+ "@memberjunction/ng-explorer-settings": "5.34.0",
126
+ "@memberjunction/ng-export-service": "5.34.0",
127
+ "@memberjunction/ng-filter-builder": "5.34.0",
128
+ "@memberjunction/ng-list-management": "5.34.0",
129
+ "@memberjunction/ng-map-view": "5.34.0",
130
+ "@memberjunction/ng-markdown": "5.34.0",
131
+ "@memberjunction/ng-notifications": "5.34.0",
132
+ "@memberjunction/ng-query-viewer": "5.34.0",
133
+ "@memberjunction/ng-react": "5.34.0",
134
+ "@memberjunction/ng-resource-permissions": "5.34.0",
135
+ "@memberjunction/ng-scheduling": "5.34.0",
136
+ "@memberjunction/ng-search": "5.34.0",
137
+ "@memberjunction/ng-shared": "5.34.0",
138
+ "@memberjunction/ng-shared-generic": "5.34.0",
139
+ "@memberjunction/ng-testing": "5.34.0",
140
+ "@memberjunction/ng-trees": "5.34.0",
141
+ "@memberjunction/ng-ui-components": "5.34.0",
142
+ "@memberjunction/ng-versions": "5.34.0",
143
+ "@memberjunction/ng-word-cloud": "5.34.0",
144
+ "@memberjunction/skip-types": "5.34.0",
145
+ "@memberjunction/templates-base-types": "5.34.0",
146
+ "@memberjunction/testing-engine-base": "5.34.0",
147
147
  "angular-split": "^20.0.0",
148
148
  "codemirror": "^6.0.2",
149
149
  "d3": "^7.8.5",