@cqa-lib/cqa-ui 1.1.512 → 1.1.514

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.
@@ -1192,6 +1192,15 @@ class DynamicTableComponent {
1192
1192
  this.computedData = [];
1193
1193
  this.computedGridTemplate = '';
1194
1194
  this.computedColumnWidths = [];
1195
+ /**
1196
+ * Hard floor on the `<table>` width = sum of every visible column's minimum (fixed
1197
+ * widths + dynamic columns' `minWidth`). With `table-layout: fixed; width: 100%;` set
1198
+ * by consumers, `<col>` widths become advisory once the container is narrower than
1199
+ * the column-width sum — the browser silently shrinks them. Pinning `min-width` on
1200
+ * the table itself prevents that compaction; the consumer's `overflow-x: auto`
1201
+ * wrapper then scrolls horizontally instead of squishing columns to zero width.
1202
+ */
1203
+ this.computedTableMinWidth = 0;
1195
1204
  // Cache for sanitized HTML to avoid redundant innerHTML renders
1196
1205
  this.htmlCache = new Map();
1197
1206
  this._sortDirection = null;
@@ -1444,13 +1453,32 @@ class DynamicTableComponent {
1444
1453
  const fixedPx = cols.reduce((sum, c) => sum + (c.fixedPx || 0), 0);
1445
1454
  const dynamicCols = cols.filter(c => !c.fixedPx);
1446
1455
  const totalWeight = dynamicCols.reduce((sum, c) => sum + (c.weight || 1), 0) || 1;
1456
+ // Floor on the table itself = every column's minimum width contribution. Fixed
1457
+ // columns contribute `fixedPx`; dynamic columns contribute `minWidth` (or 0 when
1458
+ // unset). The template binds this via `[style.min-width.px]` on the <table> so
1459
+ // narrow containers force horizontal scroll instead of squishing columns to 0.
1460
+ this.computedTableMinWidth = cols.reduce((sum, c) => sum + (c.fixedPx && c.fixedPx > 0 ? c.fixedPx : (c.minWidth || 0)), 0);
1447
1461
  this.computedColumnWidths = cols.map(c => {
1448
1462
  if (c.fixedPx && c.fixedPx > 0) {
1449
- return `${c.fixedPx}px`;
1463
+ // Fixed-width columns still respect minWidth in the (rare) case the consumer
1464
+ // configured both — `max(fixed, min)` picks whichever is larger.
1465
+ return c.minWidth && c.minWidth > c.fixedPx
1466
+ ? `max(${c.fixedPx}px, ${c.minWidth}px)`
1467
+ : `${c.fixedPx}px`;
1450
1468
  }
1451
1469
  const share = (c.weight || 1) / totalWeight;
1452
- return `calc((100% - ${fixedPx}px) * ${share.toFixed(4)})`;
1470
+ const dynamicWidth = `calc((100% - ${fixedPx}px) * ${share.toFixed(4)})`;
1471
+ // Dynamic-share columns can collapse to ~0 when the table is narrower than
1472
+ // (sum of fixed widths) + the share they'd compute to. Using CSS `max()` floors
1473
+ // the column at `minWidth` so it grows naturally as the table widens but never
1474
+ // shrinks below the configured pixel minimum. With `table-layout: fixed`, the
1475
+ // <col> width is authoritative — without max() here the cell-level `min-width`
1476
+ // we set on <th>/<td> is ignored and columns visually disappear at narrow widths.
1477
+ return c.minWidth && c.minWidth > 0
1478
+ ? `max(${c.minWidth}px, ${dynamicWidth})`
1479
+ : dynamicWidth;
1453
1480
  });
1481
+ console.log('computedColumnWidths', this.computedColumnWidths);
1454
1482
  if (this.gridTemplateColumns) {
1455
1483
  this.computedGridTemplate = this.gridTemplateColumns;
1456
1484
  }
@@ -1598,10 +1626,10 @@ class DynamicTableComponent {
1598
1626
  }
1599
1627
  }
1600
1628
  DynamicTableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: DynamicTableComponent, deps: [{ token: i1$2.DomSanitizer }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1601
- DynamicTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: DynamicTableComponent, selector: "app-dynamic-table", inputs: { data: "data", columns: "columns", emptyState: "emptyState", gridTemplateColumns: "gridTemplateColumns", screenWidth: "screenWidth", enableSelectAll: "enableSelectAll", rowSelectable: "rowSelectable", enableLocalSort: "enableLocalSort", isTableLoading: "isTableLoading", isTableDataLoading: "isTableDataLoading", cellJsonPathGetter: "cellJsonPathGetter", onJsonPathCopiedHandler: "onJsonPathCopiedHandler" }, outputs: { sortChange: "sortChange" }, host: { classAttribute: "cqa-ui-root" }, queries: [{ propertyName: "emptyTableTpl", first: true, predicate: ["emptyTableTpl"], descendants: true, read: TemplateRef }, { propertyName: "cellTemplates", predicate: DynamicCellTemplateDirective }, { propertyName: "headerTemplates", predicate: DynamicHeaderTemplateDirective }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-ui-root\">\n <div class=\"cqa-relative\" [class.cqa-max-h-[100px]]=\"showTableLoading\">\n <cqa-full-table-loader *ngIf=\"showTableLoading\"></cqa-full-table-loader>\n <cqa-table-data-loader *ngIf=\"showTableDataLoading\"></cqa-table-data-loader>\n <table class=\"table-inner cqa-w-full cqa-border cqa-border-solid cqa-border-gray-200\" [class.is-loading]=\"true\" *ngIf=\"!showTableLoading\">\n <colgroup>\n <ng-container *ngFor=\"let width of computedColumnWidths; trackBy: trackByIndex\">\n <col [style.width]=\"width\" />\n </ng-container>\n </colgroup>\n\n <thead *ngIf=\"data?.length\">\n <tr class=\"table-header cqa-items-center\">\n <ng-container *ngFor=\"let col of visibleColumns; trackBy: trackByIndex\">\n <th\n class=\"header-cell cqa-py-[13.25px] cqa-px-[10.5px] cqa-text-xs cqa-font-semibold cqa-text-[#374151] cqa-bg-[#eff0f7]\"\n [ngClass]=\"[\n col.fieldId + '-cell',\n col.align === 'center' ? 'cqa-text-center' : col.align === 'right' ? 'cqa-text-right' : 'cqa-text-left'\n ]\">\n <!-- Built-in select-all for checkbox column when enabled and no custom header template -->\n <ng-container\n *ngIf=\"col.fieldId === 'checkbox' && enableSelectAll && !getHeaderTemplate(col.fieldId); else headerTplOrDefault\">\n <div class=\"custom-checkbox\">\n <input type=\"checkbox\" id=\"checkbox\" aria-label=\"Select all rows\" [checked]=\"allSelected\"\n [indeterminate]=\"someSelected\" (change)=\"onSelectAllChange($event)\" class=\"hidden-checkbox\" />\n <label for=\"checkbox\" class=\"custom-checkbox-label\"></label>\n </div>\n </ng-container>\n <ng-template #headerTplOrDefault>\n <ng-container *ngIf=\"getHeaderTemplate(col.fieldId) as headerTpl; else defaultHeader\">\n <ng-container *ngTemplateOutlet=\"headerTpl\"></ng-container>\n </ng-container>\n <ng-template #defaultHeader>\n <ng-container *ngIf=\"col.sortable; else plainHeader\">\n <button type=\"button\" class=\"header-text cqa-inline-flex cqa-items-center cqa-gap-1 cqa-px-0\"\n (click)=\"toggleSort(col)\" [attr.aria-label]=\"'Sort by ' + (col.fieldName || col.fieldId)\">\n <span class=\"cqa-text-[12.3px] cqa-leading-[17.5px] cqa-text-[#0A0A0A] cqa-font-medium\">{{\n col.fieldName }}</span>\n <span *ngIf=\"isSortedAsc(col.fieldId)\">\u25B2</span>\n <span *ngIf=\"isSortedDesc(col.fieldId)\">\u25BC</span>\n </button>\n </ng-container>\n <ng-template #plainHeader>\n <span class=\"header-text\">{{ col.fieldName }}</span>\n </ng-template>\n </ng-template>\n </ng-template>\n </th>\n </ng-container>\n </tr>\n </thead>\n\n <tbody class=\"table-body cqa-w-full\">\n <tr class=\"table-row cqa-bg-surface-default hover:cqa-bg-surface-hover\" *ngFor=\"let row of computedData; let rowIndex = index; trackBy: trackByIndex\"\n [class.selected]=\"row?.isSelected\">\n <ng-container *ngFor=\"let col of visibleColumns; trackBy: trackByIndex\">\n <td class=\"cell cqa-px-[10.5px] cqa-py-[11px]\" \n [ngClass]=\"[\n col.fieldId + '-cell',\n col.align === 'center' ? 'cqa-text-center' : col.align === 'right' ? 'cqa-text-right' : 'cqa-text-left',\n cellJsonPathGetter && col.fieldId !== 'checkbox' && col.fieldId !== 'actions' ? 'cqa-cursor-pointer' : ''\n ]\"\n (dblclick)=\"cellJsonPathGetter && col?.fieldId !== 'checkbox' && col?.fieldId !== 'actions' && copyCellJsonPath(cellJsonPathGetter(rowIndex, col?.fieldId, row), $event, 'dbQueryResponse')\">\n <!-- Built-in checkbox cell when no custom template is provided -->\n <ng-container *ngIf=\"col.fieldId === 'checkbox' && !getCellTemplate(col.fieldId); else regularCell\">\n <div class=\"custom-checkbox\" [ngClass]=\"[\n col.align === 'center' ? 'cqa-flex cqa-justify-center' : col.align === 'right' ? 'cqa-flex cqa-justify-end' : ''\n ]\">\n <input\n type=\"checkbox\"\n class=\"hidden-checkbox\"\n [attr.id]=\"'row-checkbox-' + rowIndex\"\n aria-label=\"Select row\"\n [checked]=\"row?.isSelected\"\n [disabled]=\"!isRowSelectable(row)\"\n (change)=\"onRowSelectChange($event, row)\" />\n <label\n class=\"custom-checkbox-label\"\n [style.opacity]=\"!isRowSelectable(row) ? '0.45' : null\"\n [style.cursor]=\"!isRowSelectable(row) ? 'not-allowed' : null\"\n [style.pointer-events]=\"!isRowSelectable(row) ? 'none' : null\"\n [attr.for]=\"'row-checkbox-' + rowIndex\">\n </label>\n </div>\n </ng-container>\n <ng-template #regularCell>\n <ng-container *ngIf=\"getCellTemplate(col.fieldId) as cellTpl; else defaultCell\">\n <ng-container\n *ngTemplateOutlet=\"cellTpl; context: {$implicit: row, row: row, value: getCellValue(row, col.fieldValue)}\"></ng-container>\n </ng-container>\n <ng-template #defaultCell>\n <ng-container *ngIf=\"getRenderedValue(row, col) as renderedValue\">\n <ng-container *ngIf=\"isComponent(renderedValue); else nonComponentCell\">\n <ng-container \n cqaCellContainer \n #cellContainer=\"cqaCellContainer\"\n [componentConfig]=\"renderedValue\"\n [row]=\"row\"\n [column]=\"col\"\n [rowIndex]=\"rowIndex\"\n [colId]=\"col.fieldId\">\n </ng-container>\n </ng-container>\n <ng-template #nonComponentCell>\n <ng-container *ngIf=\"isHtmlString(renderedValue); else textCell\">\n <div class=\"cqa-text-xs cqa-leading-[17px]\" [innerHTML]=\"getSanitizedHtml(renderedValue)\" [ngClass]=\"[\n col.align === 'center' ? 'cqa-flex cqa-justify-center' : col.align === 'right' ? 'cqa-flex cqa-justify-end' : ''\n ]\"></div>\n </ng-container>\n <ng-template #textCell>\n <span class=\"cqa-text-xs cqa-text-[#374151]\" [ngClass]=\"[\n col.align === 'center' ? 'cqa-flex cqa-justify-center' : col.align === 'right' ? 'cqa-flex cqa-justify-end' : ''\n ]\">{{ renderedValue }}</span>\n </ng-template>\n </ng-template>\n </ng-container>\n </ng-template>\n </ng-template>\n </td>\n </ng-container>\n </tr>\n </tbody>\n </table>\n </div>\n</div>", components: [{ type: FullTableLoaderComponent, selector: "cqa-full-table-loader", inputs: ["label"] }, { type: TableDataLoaderComponent, selector: "cqa-table-data-loader", inputs: ["label", "size"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: DynamicCellContainerDirective, selector: "[cqaCellContainer]", inputs: ["componentConfig", "row", "column", "rowIndex", "colId"], exportAs: ["cqaCellContainer"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1629
+ DynamicTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: DynamicTableComponent, selector: "app-dynamic-table", inputs: { data: "data", columns: "columns", emptyState: "emptyState", gridTemplateColumns: "gridTemplateColumns", screenWidth: "screenWidth", enableSelectAll: "enableSelectAll", rowSelectable: "rowSelectable", enableLocalSort: "enableLocalSort", isTableLoading: "isTableLoading", isTableDataLoading: "isTableDataLoading", cellJsonPathGetter: "cellJsonPathGetter", onJsonPathCopiedHandler: "onJsonPathCopiedHandler" }, outputs: { sortChange: "sortChange" }, host: { classAttribute: "cqa-ui-root" }, queries: [{ propertyName: "emptyTableTpl", first: true, predicate: ["emptyTableTpl"], descendants: true, read: TemplateRef }, { propertyName: "cellTemplates", predicate: DynamicCellTemplateDirective }, { propertyName: "headerTemplates", predicate: DynamicHeaderTemplateDirective }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-ui-root\">\n <div class=\"cqa-relative\" [class.cqa-max-h-[100px]]=\"showTableLoading\">\n <cqa-full-table-loader *ngIf=\"showTableLoading\"></cqa-full-table-loader>\n <cqa-table-data-loader *ngIf=\"showTableDataLoading\"></cqa-table-data-loader>\n <table class=\"table-inner cqa-w-full cqa-border cqa-border-solid cqa-border-gray-200\"\n [class.is-loading]=\"true\"\n [style.min-width.px]=\"computedTableMinWidth || null\"\n *ngIf=\"!showTableLoading\">\n <colgroup>\n <ng-container *ngFor=\"let width of computedColumnWidths; trackBy: trackByIndex\">\n <col [style.width]=\"width\" />\n </ng-container>\n </colgroup>\n\n <thead *ngIf=\"data?.length\">\n <tr class=\"table-header cqa-items-center\">\n <ng-container *ngFor=\"let col of visibleColumns; trackBy: trackByIndex\">\n <th\n class=\"header-cell cqa-py-[13.25px] cqa-px-[10.5px] cqa-text-xs cqa-font-semibold cqa-text-[#374151] cqa-bg-[#eff0f7]\"\n [style.min-width.px]=\"col.minWidth\"\n [ngClass]=\"[\n col.fieldId + '-cell',\n col.align === 'center' ? 'cqa-text-center' : col.align === 'right' ? 'cqa-text-right' : 'cqa-text-left'\n ]\">\n <!-- Built-in select-all for checkbox column when enabled and no custom header template -->\n <ng-container\n *ngIf=\"col.fieldId === 'checkbox' && enableSelectAll && !getHeaderTemplate(col.fieldId); else headerTplOrDefault\">\n <div class=\"custom-checkbox\">\n <input type=\"checkbox\" id=\"checkbox\" aria-label=\"Select all rows\" [checked]=\"allSelected\"\n [indeterminate]=\"someSelected\" (change)=\"onSelectAllChange($event)\" class=\"hidden-checkbox\" />\n <label for=\"checkbox\" class=\"custom-checkbox-label\"></label>\n </div>\n </ng-container>\n <ng-template #headerTplOrDefault>\n <ng-container *ngIf=\"getHeaderTemplate(col.fieldId) as headerTpl; else defaultHeader\">\n <ng-container *ngTemplateOutlet=\"headerTpl\"></ng-container>\n </ng-container>\n <ng-template #defaultHeader>\n <ng-container *ngIf=\"col.sortable; else plainHeader\">\n <button type=\"button\" class=\"header-text cqa-inline-flex cqa-items-center cqa-gap-1 cqa-px-0\"\n (click)=\"toggleSort(col)\" [attr.aria-label]=\"'Sort by ' + (col.fieldName || col.fieldId)\">\n <span class=\"cqa-text-[12.3px] cqa-leading-[17.5px] cqa-text-[#0A0A0A] cqa-font-medium\">{{\n col.fieldName }}</span>\n <span *ngIf=\"isSortedAsc(col.fieldId)\">\u25B2</span>\n <span *ngIf=\"isSortedDesc(col.fieldId)\">\u25BC</span>\n </button>\n </ng-container>\n <ng-template #plainHeader>\n <span class=\"header-text\">{{ col.fieldName }}</span>\n </ng-template>\n </ng-template>\n </ng-template>\n </th>\n </ng-container>\n </tr>\n </thead>\n\n <tbody class=\"table-body cqa-w-full\">\n <tr class=\"table-row cqa-bg-surface-default hover:cqa-bg-surface-hover\" *ngFor=\"let row of computedData; let rowIndex = index; trackBy: trackByIndex\"\n [class.selected]=\"row?.isSelected\">\n <ng-container *ngFor=\"let col of visibleColumns; trackBy: trackByIndex\">\n <td class=\"cell cqa-px-[10.5px] cqa-py-[11px]\"\n [style.min-width.px]=\"col.minWidth\"\n [ngClass]=\"[\n col.fieldId + '-cell',\n col.align === 'center' ? 'cqa-text-center' : col.align === 'right' ? 'cqa-text-right' : 'cqa-text-left',\n cellJsonPathGetter && col.fieldId !== 'checkbox' && col.fieldId !== 'actions' ? 'cqa-cursor-pointer' : ''\n ]\"\n (dblclick)=\"cellJsonPathGetter && col?.fieldId !== 'checkbox' && col?.fieldId !== 'actions' && copyCellJsonPath(cellJsonPathGetter(rowIndex, col?.fieldId, row), $event, 'dbQueryResponse')\">\n <!-- Built-in checkbox cell when no custom template is provided -->\n <ng-container *ngIf=\"col.fieldId === 'checkbox' && !getCellTemplate(col.fieldId); else regularCell\">\n <div class=\"custom-checkbox\" [ngClass]=\"[\n col.align === 'center' ? 'cqa-flex cqa-justify-center' : col.align === 'right' ? 'cqa-flex cqa-justify-end' : ''\n ]\">\n <input\n type=\"checkbox\"\n class=\"hidden-checkbox\"\n [attr.id]=\"'row-checkbox-' + rowIndex\"\n aria-label=\"Select row\"\n [checked]=\"row?.isSelected\"\n [disabled]=\"!isRowSelectable(row)\"\n (change)=\"onRowSelectChange($event, row)\" />\n <label\n class=\"custom-checkbox-label\"\n [style.opacity]=\"!isRowSelectable(row) ? '0.45' : null\"\n [style.cursor]=\"!isRowSelectable(row) ? 'not-allowed' : null\"\n [style.pointer-events]=\"!isRowSelectable(row) ? 'none' : null\"\n [attr.for]=\"'row-checkbox-' + rowIndex\">\n </label>\n </div>\n </ng-container>\n <ng-template #regularCell>\n <ng-container *ngIf=\"getCellTemplate(col.fieldId) as cellTpl; else defaultCell\">\n <ng-container\n *ngTemplateOutlet=\"cellTpl; context: {$implicit: row, row: row, value: getCellValue(row, col.fieldValue)}\"></ng-container>\n </ng-container>\n <ng-template #defaultCell>\n <ng-container *ngIf=\"getRenderedValue(row, col) as renderedValue\">\n <ng-container *ngIf=\"isComponent(renderedValue); else nonComponentCell\">\n <ng-container \n cqaCellContainer \n #cellContainer=\"cqaCellContainer\"\n [componentConfig]=\"renderedValue\"\n [row]=\"row\"\n [column]=\"col\"\n [rowIndex]=\"rowIndex\"\n [colId]=\"col.fieldId\">\n </ng-container>\n </ng-container>\n <ng-template #nonComponentCell>\n <ng-container *ngIf=\"isHtmlString(renderedValue); else textCell\">\n <div class=\"cqa-text-xs cqa-leading-[17px]\" [innerHTML]=\"getSanitizedHtml(renderedValue)\" [ngClass]=\"[\n col.align === 'center' ? 'cqa-flex cqa-justify-center' : col.align === 'right' ? 'cqa-flex cqa-justify-end' : ''\n ]\"></div>\n </ng-container>\n <ng-template #textCell>\n <span class=\"cqa-text-xs cqa-text-[#374151]\" [ngClass]=\"[\n col.align === 'center' ? 'cqa-flex cqa-justify-center' : col.align === 'right' ? 'cqa-flex cqa-justify-end' : ''\n ]\">{{ renderedValue }}</span>\n </ng-template>\n </ng-template>\n </ng-container>\n </ng-template>\n </ng-template>\n </td>\n </ng-container>\n </tr>\n </tbody>\n </table>\n </div>\n</div>", components: [{ type: FullTableLoaderComponent, selector: "cqa-full-table-loader", inputs: ["label"] }, { type: TableDataLoaderComponent, selector: "cqa-table-data-loader", inputs: ["label", "size"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: DynamicCellContainerDirective, selector: "[cqaCellContainer]", inputs: ["componentConfig", "row", "column", "rowIndex", "colId"], exportAs: ["cqaCellContainer"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1602
1630
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: DynamicTableComponent, decorators: [{
1603
1631
  type: Component,
1604
- args: [{ selector: "app-dynamic-table", host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"cqa-ui-root\">\n <div class=\"cqa-relative\" [class.cqa-max-h-[100px]]=\"showTableLoading\">\n <cqa-full-table-loader *ngIf=\"showTableLoading\"></cqa-full-table-loader>\n <cqa-table-data-loader *ngIf=\"showTableDataLoading\"></cqa-table-data-loader>\n <table class=\"table-inner cqa-w-full cqa-border cqa-border-solid cqa-border-gray-200\" [class.is-loading]=\"true\" *ngIf=\"!showTableLoading\">\n <colgroup>\n <ng-container *ngFor=\"let width of computedColumnWidths; trackBy: trackByIndex\">\n <col [style.width]=\"width\" />\n </ng-container>\n </colgroup>\n\n <thead *ngIf=\"data?.length\">\n <tr class=\"table-header cqa-items-center\">\n <ng-container *ngFor=\"let col of visibleColumns; trackBy: trackByIndex\">\n <th\n class=\"header-cell cqa-py-[13.25px] cqa-px-[10.5px] cqa-text-xs cqa-font-semibold cqa-text-[#374151] cqa-bg-[#eff0f7]\"\n [ngClass]=\"[\n col.fieldId + '-cell',\n col.align === 'center' ? 'cqa-text-center' : col.align === 'right' ? 'cqa-text-right' : 'cqa-text-left'\n ]\">\n <!-- Built-in select-all for checkbox column when enabled and no custom header template -->\n <ng-container\n *ngIf=\"col.fieldId === 'checkbox' && enableSelectAll && !getHeaderTemplate(col.fieldId); else headerTplOrDefault\">\n <div class=\"custom-checkbox\">\n <input type=\"checkbox\" id=\"checkbox\" aria-label=\"Select all rows\" [checked]=\"allSelected\"\n [indeterminate]=\"someSelected\" (change)=\"onSelectAllChange($event)\" class=\"hidden-checkbox\" />\n <label for=\"checkbox\" class=\"custom-checkbox-label\"></label>\n </div>\n </ng-container>\n <ng-template #headerTplOrDefault>\n <ng-container *ngIf=\"getHeaderTemplate(col.fieldId) as headerTpl; else defaultHeader\">\n <ng-container *ngTemplateOutlet=\"headerTpl\"></ng-container>\n </ng-container>\n <ng-template #defaultHeader>\n <ng-container *ngIf=\"col.sortable; else plainHeader\">\n <button type=\"button\" class=\"header-text cqa-inline-flex cqa-items-center cqa-gap-1 cqa-px-0\"\n (click)=\"toggleSort(col)\" [attr.aria-label]=\"'Sort by ' + (col.fieldName || col.fieldId)\">\n <span class=\"cqa-text-[12.3px] cqa-leading-[17.5px] cqa-text-[#0A0A0A] cqa-font-medium\">{{\n col.fieldName }}</span>\n <span *ngIf=\"isSortedAsc(col.fieldId)\">\u25B2</span>\n <span *ngIf=\"isSortedDesc(col.fieldId)\">\u25BC</span>\n </button>\n </ng-container>\n <ng-template #plainHeader>\n <span class=\"header-text\">{{ col.fieldName }}</span>\n </ng-template>\n </ng-template>\n </ng-template>\n </th>\n </ng-container>\n </tr>\n </thead>\n\n <tbody class=\"table-body cqa-w-full\">\n <tr class=\"table-row cqa-bg-surface-default hover:cqa-bg-surface-hover\" *ngFor=\"let row of computedData; let rowIndex = index; trackBy: trackByIndex\"\n [class.selected]=\"row?.isSelected\">\n <ng-container *ngFor=\"let col of visibleColumns; trackBy: trackByIndex\">\n <td class=\"cell cqa-px-[10.5px] cqa-py-[11px]\" \n [ngClass]=\"[\n col.fieldId + '-cell',\n col.align === 'center' ? 'cqa-text-center' : col.align === 'right' ? 'cqa-text-right' : 'cqa-text-left',\n cellJsonPathGetter && col.fieldId !== 'checkbox' && col.fieldId !== 'actions' ? 'cqa-cursor-pointer' : ''\n ]\"\n (dblclick)=\"cellJsonPathGetter && col?.fieldId !== 'checkbox' && col?.fieldId !== 'actions' && copyCellJsonPath(cellJsonPathGetter(rowIndex, col?.fieldId, row), $event, 'dbQueryResponse')\">\n <!-- Built-in checkbox cell when no custom template is provided -->\n <ng-container *ngIf=\"col.fieldId === 'checkbox' && !getCellTemplate(col.fieldId); else regularCell\">\n <div class=\"custom-checkbox\" [ngClass]=\"[\n col.align === 'center' ? 'cqa-flex cqa-justify-center' : col.align === 'right' ? 'cqa-flex cqa-justify-end' : ''\n ]\">\n <input\n type=\"checkbox\"\n class=\"hidden-checkbox\"\n [attr.id]=\"'row-checkbox-' + rowIndex\"\n aria-label=\"Select row\"\n [checked]=\"row?.isSelected\"\n [disabled]=\"!isRowSelectable(row)\"\n (change)=\"onRowSelectChange($event, row)\" />\n <label\n class=\"custom-checkbox-label\"\n [style.opacity]=\"!isRowSelectable(row) ? '0.45' : null\"\n [style.cursor]=\"!isRowSelectable(row) ? 'not-allowed' : null\"\n [style.pointer-events]=\"!isRowSelectable(row) ? 'none' : null\"\n [attr.for]=\"'row-checkbox-' + rowIndex\">\n </label>\n </div>\n </ng-container>\n <ng-template #regularCell>\n <ng-container *ngIf=\"getCellTemplate(col.fieldId) as cellTpl; else defaultCell\">\n <ng-container\n *ngTemplateOutlet=\"cellTpl; context: {$implicit: row, row: row, value: getCellValue(row, col.fieldValue)}\"></ng-container>\n </ng-container>\n <ng-template #defaultCell>\n <ng-container *ngIf=\"getRenderedValue(row, col) as renderedValue\">\n <ng-container *ngIf=\"isComponent(renderedValue); else nonComponentCell\">\n <ng-container \n cqaCellContainer \n #cellContainer=\"cqaCellContainer\"\n [componentConfig]=\"renderedValue\"\n [row]=\"row\"\n [column]=\"col\"\n [rowIndex]=\"rowIndex\"\n [colId]=\"col.fieldId\">\n </ng-container>\n </ng-container>\n <ng-template #nonComponentCell>\n <ng-container *ngIf=\"isHtmlString(renderedValue); else textCell\">\n <div class=\"cqa-text-xs cqa-leading-[17px]\" [innerHTML]=\"getSanitizedHtml(renderedValue)\" [ngClass]=\"[\n col.align === 'center' ? 'cqa-flex cqa-justify-center' : col.align === 'right' ? 'cqa-flex cqa-justify-end' : ''\n ]\"></div>\n </ng-container>\n <ng-template #textCell>\n <span class=\"cqa-text-xs cqa-text-[#374151]\" [ngClass]=\"[\n col.align === 'center' ? 'cqa-flex cqa-justify-center' : col.align === 'right' ? 'cqa-flex cqa-justify-end' : ''\n ]\">{{ renderedValue }}</span>\n </ng-template>\n </ng-template>\n </ng-container>\n </ng-template>\n </ng-template>\n </td>\n </ng-container>\n </tr>\n </tbody>\n </table>\n </div>\n</div>", styles: [] }]
1632
+ args: [{ selector: "app-dynamic-table", host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"cqa-ui-root\">\n <div class=\"cqa-relative\" [class.cqa-max-h-[100px]]=\"showTableLoading\">\n <cqa-full-table-loader *ngIf=\"showTableLoading\"></cqa-full-table-loader>\n <cqa-table-data-loader *ngIf=\"showTableDataLoading\"></cqa-table-data-loader>\n <table class=\"table-inner cqa-w-full cqa-border cqa-border-solid cqa-border-gray-200\"\n [class.is-loading]=\"true\"\n [style.min-width.px]=\"computedTableMinWidth || null\"\n *ngIf=\"!showTableLoading\">\n <colgroup>\n <ng-container *ngFor=\"let width of computedColumnWidths; trackBy: trackByIndex\">\n <col [style.width]=\"width\" />\n </ng-container>\n </colgroup>\n\n <thead *ngIf=\"data?.length\">\n <tr class=\"table-header cqa-items-center\">\n <ng-container *ngFor=\"let col of visibleColumns; trackBy: trackByIndex\">\n <th\n class=\"header-cell cqa-py-[13.25px] cqa-px-[10.5px] cqa-text-xs cqa-font-semibold cqa-text-[#374151] cqa-bg-[#eff0f7]\"\n [style.min-width.px]=\"col.minWidth\"\n [ngClass]=\"[\n col.fieldId + '-cell',\n col.align === 'center' ? 'cqa-text-center' : col.align === 'right' ? 'cqa-text-right' : 'cqa-text-left'\n ]\">\n <!-- Built-in select-all for checkbox column when enabled and no custom header template -->\n <ng-container\n *ngIf=\"col.fieldId === 'checkbox' && enableSelectAll && !getHeaderTemplate(col.fieldId); else headerTplOrDefault\">\n <div class=\"custom-checkbox\">\n <input type=\"checkbox\" id=\"checkbox\" aria-label=\"Select all rows\" [checked]=\"allSelected\"\n [indeterminate]=\"someSelected\" (change)=\"onSelectAllChange($event)\" class=\"hidden-checkbox\" />\n <label for=\"checkbox\" class=\"custom-checkbox-label\"></label>\n </div>\n </ng-container>\n <ng-template #headerTplOrDefault>\n <ng-container *ngIf=\"getHeaderTemplate(col.fieldId) as headerTpl; else defaultHeader\">\n <ng-container *ngTemplateOutlet=\"headerTpl\"></ng-container>\n </ng-container>\n <ng-template #defaultHeader>\n <ng-container *ngIf=\"col.sortable; else plainHeader\">\n <button type=\"button\" class=\"header-text cqa-inline-flex cqa-items-center cqa-gap-1 cqa-px-0\"\n (click)=\"toggleSort(col)\" [attr.aria-label]=\"'Sort by ' + (col.fieldName || col.fieldId)\">\n <span class=\"cqa-text-[12.3px] cqa-leading-[17.5px] cqa-text-[#0A0A0A] cqa-font-medium\">{{\n col.fieldName }}</span>\n <span *ngIf=\"isSortedAsc(col.fieldId)\">\u25B2</span>\n <span *ngIf=\"isSortedDesc(col.fieldId)\">\u25BC</span>\n </button>\n </ng-container>\n <ng-template #plainHeader>\n <span class=\"header-text\">{{ col.fieldName }}</span>\n </ng-template>\n </ng-template>\n </ng-template>\n </th>\n </ng-container>\n </tr>\n </thead>\n\n <tbody class=\"table-body cqa-w-full\">\n <tr class=\"table-row cqa-bg-surface-default hover:cqa-bg-surface-hover\" *ngFor=\"let row of computedData; let rowIndex = index; trackBy: trackByIndex\"\n [class.selected]=\"row?.isSelected\">\n <ng-container *ngFor=\"let col of visibleColumns; trackBy: trackByIndex\">\n <td class=\"cell cqa-px-[10.5px] cqa-py-[11px]\"\n [style.min-width.px]=\"col.minWidth\"\n [ngClass]=\"[\n col.fieldId + '-cell',\n col.align === 'center' ? 'cqa-text-center' : col.align === 'right' ? 'cqa-text-right' : 'cqa-text-left',\n cellJsonPathGetter && col.fieldId !== 'checkbox' && col.fieldId !== 'actions' ? 'cqa-cursor-pointer' : ''\n ]\"\n (dblclick)=\"cellJsonPathGetter && col?.fieldId !== 'checkbox' && col?.fieldId !== 'actions' && copyCellJsonPath(cellJsonPathGetter(rowIndex, col?.fieldId, row), $event, 'dbQueryResponse')\">\n <!-- Built-in checkbox cell when no custom template is provided -->\n <ng-container *ngIf=\"col.fieldId === 'checkbox' && !getCellTemplate(col.fieldId); else regularCell\">\n <div class=\"custom-checkbox\" [ngClass]=\"[\n col.align === 'center' ? 'cqa-flex cqa-justify-center' : col.align === 'right' ? 'cqa-flex cqa-justify-end' : ''\n ]\">\n <input\n type=\"checkbox\"\n class=\"hidden-checkbox\"\n [attr.id]=\"'row-checkbox-' + rowIndex\"\n aria-label=\"Select row\"\n [checked]=\"row?.isSelected\"\n [disabled]=\"!isRowSelectable(row)\"\n (change)=\"onRowSelectChange($event, row)\" />\n <label\n class=\"custom-checkbox-label\"\n [style.opacity]=\"!isRowSelectable(row) ? '0.45' : null\"\n [style.cursor]=\"!isRowSelectable(row) ? 'not-allowed' : null\"\n [style.pointer-events]=\"!isRowSelectable(row) ? 'none' : null\"\n [attr.for]=\"'row-checkbox-' + rowIndex\">\n </label>\n </div>\n </ng-container>\n <ng-template #regularCell>\n <ng-container *ngIf=\"getCellTemplate(col.fieldId) as cellTpl; else defaultCell\">\n <ng-container\n *ngTemplateOutlet=\"cellTpl; context: {$implicit: row, row: row, value: getCellValue(row, col.fieldValue)}\"></ng-container>\n </ng-container>\n <ng-template #defaultCell>\n <ng-container *ngIf=\"getRenderedValue(row, col) as renderedValue\">\n <ng-container *ngIf=\"isComponent(renderedValue); else nonComponentCell\">\n <ng-container \n cqaCellContainer \n #cellContainer=\"cqaCellContainer\"\n [componentConfig]=\"renderedValue\"\n [row]=\"row\"\n [column]=\"col\"\n [rowIndex]=\"rowIndex\"\n [colId]=\"col.fieldId\">\n </ng-container>\n </ng-container>\n <ng-template #nonComponentCell>\n <ng-container *ngIf=\"isHtmlString(renderedValue); else textCell\">\n <div class=\"cqa-text-xs cqa-leading-[17px]\" [innerHTML]=\"getSanitizedHtml(renderedValue)\" [ngClass]=\"[\n col.align === 'center' ? 'cqa-flex cqa-justify-center' : col.align === 'right' ? 'cqa-flex cqa-justify-end' : ''\n ]\"></div>\n </ng-container>\n <ng-template #textCell>\n <span class=\"cqa-text-xs cqa-text-[#374151]\" [ngClass]=\"[\n col.align === 'center' ? 'cqa-flex cqa-justify-center' : col.align === 'right' ? 'cqa-flex cqa-justify-end' : ''\n ]\">{{ renderedValue }}</span>\n </ng-template>\n </ng-template>\n </ng-container>\n </ng-template>\n </ng-template>\n </td>\n </ng-container>\n </tr>\n </tbody>\n </table>\n </div>\n</div>", styles: [] }]
1605
1633
  }], ctorParameters: function () { return [{ type: i1$2.DomSanitizer }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { data: [{
1606
1634
  type: Input
1607
1635
  }], columns: [{
@@ -19286,19 +19314,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
19286
19314
 
19287
19315
  class ViewCompareButtonComponent {
19288
19316
  constructor() {
19317
+ this.label = 'View Compare';
19318
+ this.isFailureAction = false;
19289
19319
  this.clicked = new EventEmitter();
19290
19320
  }
19291
19321
  }
19292
19322
  ViewCompareButtonComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ViewCompareButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
19293
- ViewCompareButtonComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ViewCompareButtonComponent, selector: "cqa-view-compare-button", outputs: { clicked: "clicked" }, ngImport: i0, template: `
19323
+ ViewCompareButtonComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ViewCompareButtonComponent, selector: "cqa-view-compare-button", inputs: { label: "label", isFailureAction: "isFailureAction" }, outputs: { clicked: "clicked" }, ngImport: i0, template: `
19294
19324
  <button
19295
19325
  type="button"
19296
- class="cqa-inline-flex cqa-items-center cqa-justify-center cqa-px-3 cqa-py-1.5 cqa-text-xs cqa-font-medium cqa-rounded-[6px] cqa-border cqa-border-[#155DFC] cqa-text-[#155DFC] cqa-bg-white"
19326
+ class="cqa-inline-flex cqa-items-center cqa-justify-center cqa-min-w-[92px] cqa-px-3 cqa-py-1.5 cqa-text-xs cqa-font-medium cqa-rounded-[6px] cqa-border"
19327
+ [ngClass]="isFailureAction ? 'cqa-border-[#F7C9CD] cqa-text-[#FB2C36] cqa-bg-[#FDE8EA]' : 'cqa-border-[#D1D5DB] cqa-text-[#636363] cqa-bg-[#F9FAFB]'"
19297
19328
  (click)="clicked.emit()"
19298
19329
  >
19299
- View Compare
19330
+ {{ label }}
19300
19331
  </button>
19301
- `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
19332
+ `, isInline: true, directives: [{ type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
19302
19333
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ViewCompareButtonComponent, decorators: [{
19303
19334
  type: Component,
19304
19335
  args: [{
@@ -19306,15 +19337,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
19306
19337
  template: `
19307
19338
  <button
19308
19339
  type="button"
19309
- class="cqa-inline-flex cqa-items-center cqa-justify-center cqa-px-3 cqa-py-1.5 cqa-text-xs cqa-font-medium cqa-rounded-[6px] cqa-border cqa-border-[#155DFC] cqa-text-[#155DFC] cqa-bg-white"
19340
+ class="cqa-inline-flex cqa-items-center cqa-justify-center cqa-min-w-[92px] cqa-px-3 cqa-py-1.5 cqa-text-xs cqa-font-medium cqa-rounded-[6px] cqa-border"
19341
+ [ngClass]="isFailureAction ? 'cqa-border-[#F7C9CD] cqa-text-[#FB2C36] cqa-bg-[#FDE8EA]' : 'cqa-border-[#D1D5DB] cqa-text-[#636363] cqa-bg-[#F9FAFB]'"
19310
19342
  (click)="clicked.emit()"
19311
19343
  >
19312
- View Compare
19344
+ {{ label }}
19313
19345
  </button>
19314
19346
  `,
19315
19347
  changeDetection: ChangeDetectionStrategy.OnPush
19316
19348
  }]
19317
- }], propDecorators: { clicked: [{
19349
+ }], propDecorators: { label: [{
19350
+ type: Input
19351
+ }], isFailureAction: [{
19352
+ type: Input
19353
+ }], clicked: [{
19318
19354
  type: Output
19319
19355
  }] } });
19320
19356
 
@@ -19589,6 +19625,14 @@ class CompareRunsComponent {
19589
19625
  setupTableColumns() {
19590
19626
  if (this.compareMode === 'testPlan') {
19591
19627
  this.tableColumns = [
19628
+ {
19629
+ fieldId: 'rowIndex',
19630
+ fieldName: '',
19631
+ fieldValue: '_compareRowOrdinal',
19632
+ isShow: true,
19633
+ fixedPx: 44,
19634
+ align: 'center'
19635
+ },
19592
19636
  {
19593
19637
  fieldId: 'testCase',
19594
19638
  fieldName: 'Test Cases',
@@ -19636,9 +19680,7 @@ class CompareRunsComponent {
19636
19680
  isShow: true,
19637
19681
  weight: 1.1,
19638
19682
  align: 'center',
19639
- render: (row) => `
19640
- <span class="cqa-text-xs cqa-text-[#636363]">${row.priorityName || 'Unassigned'}</span>
19641
- `
19683
+ render: (row) => this.renderPriorityChip(row.priorityName)
19642
19684
  },
19643
19685
  {
19644
19686
  fieldId: 'actions',
@@ -19648,6 +19690,10 @@ class CompareRunsComponent {
19648
19690
  align: 'center',
19649
19691
  render: (row) => ({
19650
19692
  component: ViewCompareButtonComponent,
19693
+ inputs: {
19694
+ label: this.getActionLabel(row),
19695
+ isFailureAction: this.isFailureAction(row)
19696
+ },
19651
19697
  outputs: {
19652
19698
  clicked: () => this.onViewCompare(row)
19653
19699
  }
@@ -19657,6 +19703,14 @@ class CompareRunsComponent {
19657
19703
  return;
19658
19704
  }
19659
19705
  this.tableColumns = [
19706
+ {
19707
+ fieldId: 'rowIndex',
19708
+ fieldName: '',
19709
+ fieldValue: '_compareRowOrdinal',
19710
+ isShow: true,
19711
+ fixedPx: 44,
19712
+ align: 'center'
19713
+ },
19660
19714
  {
19661
19715
  fieldId: 'step',
19662
19716
  fieldName: 'Step',
@@ -19664,9 +19718,12 @@ class CompareRunsComponent {
19664
19718
  isShow: true,
19665
19719
  weight: 3,
19666
19720
  render: (row) => {
19721
+ const inner = row.stepTitle != null && String(row.stepTitle).trim() !== ''
19722
+ ? row.stepTitle
19723
+ : '<span class="cqa-text-xs cqa-text-[#9CA3AF]">—</span>';
19667
19724
  return `
19668
- <div class="cqa-flex cqa-items-center cqa-gap-2">
19669
- <span class="cqa-text-xs cqa-text-[#0B0B0B]">${row.stepTitle}</span>
19725
+ <div class="cqa-flex cqa-items-center cqa-gap-2" style="min-width:0;">
19726
+ <span class="cqa-text-xs cqa-text-[#0B0B0B]">${inner}</span>
19670
19727
  </div>
19671
19728
  `;
19672
19729
  }
@@ -19807,45 +19864,67 @@ class CompareRunsComponent {
19807
19864
  'TIMING_CHANGED': 'Timing Changed',
19808
19865
  'FIXED': 'Fixed',
19809
19866
  'REGRESSION': 'Regression',
19810
- 'ADDED': 'Added',
19811
- 'NEW STEP': 'New Step',
19867
+ 'ADDED': 'New',
19868
+ 'NEW STEP': 'New',
19812
19869
  'REMOVED': 'Removed',
19813
19870
  'DELETED STEP': 'Deleted Step'
19814
19871
  };
19815
19872
  const changeColors = {
19816
- 'UNCHANGED': '#6B7280',
19817
- 'NO CHANGE': '#6B7280',
19818
- 'STATUS_CHANGED': '#3B82F6',
19819
- 'TIMING_CHANGED': '#3B82F6',
19820
- 'FIXED': '#3B82F6',
19821
- 'REGRESSION': '#3B82F6',
19822
- 'ADDED': '#10B981',
19823
- 'NEW STEP': '#10B981',
19824
- 'REMOVED': '#EF4444',
19825
- 'DELETED STEP': '#EF4444'
19826
- };
19827
- const changeBgColors = {
19828
- 'UNCHANGED': '#F3F4F6',
19829
- 'NO CHANGE': '#F3F4F6',
19830
- 'STATUS_CHANGED': '#DBEAFE',
19831
- 'TIMING_CHANGED': '#DBEAFE',
19832
- 'FIXED': '#DBEAFE',
19833
- 'REGRESSION': '#DBEAFE',
19834
- 'ADDED': '#D1FAE5',
19835
- 'NEW STEP': '#D1FAE5',
19836
- 'REMOVED': '#FEE2E2',
19837
- 'DELETED STEP': '#FEE2E2'
19873
+ 'UNCHANGED': { text: '#6B7280', bg: '#F3F4F6', dot: '#9CA3AF' },
19874
+ 'NO CHANGE': { text: '#6B7280', bg: '#F3F4F6', dot: '#9CA3AF' },
19875
+ 'TIMING_CHANGED': { text: '#6B7280', bg: '#F3F4F6', dot: '#9CA3AF' },
19876
+ 'FIXED': { text: '#00A63E', bg: '#DDF5E8', dot: '#00C950' },
19877
+ 'REGRESSION': { text: '#FB2C36', bg: '#FDE8EA', dot: '#FB2C36' },
19878
+ 'STATUS_CHANGED': { text: '#FB2C36', bg: '#FDE8EA', dot: '#FB2C36' },
19879
+ 'ADDED': { text: '#155DFC', bg: '#DBEAFE', dot: '#0A84FF' },
19880
+ 'NEW STEP': { text: '#155DFC', bg: '#DBEAFE', dot: '#0A84FF' },
19881
+ 'REMOVED': { text: '#6B7280', bg: '#F3F4F6', dot: '#9CA3AF' },
19882
+ 'DELETED STEP': { text: '#6B7280', bg: '#F3F4F6', dot: '#9CA3AF' }
19838
19883
  };
19839
19884
  const label = changeLabels[normalizedChange] || change;
19840
- const color = changeColors[normalizedChange] || '#6B7280';
19841
- const bgColor = changeBgColors[normalizedChange] || '#F3F4F6';
19885
+ const token = changeColors[normalizedChange] || { text: '#6B7280', bg: '#F3F4F6', dot: '#9CA3AF' };
19842
19886
  return `
19843
- <span class="cqa-inline-flex cqa-items-center cqa-justify-center cqa-px-2 cqa-py-0.5 cqa-rounded-full cqa-text-[10px] cqa-font-semibold cqa-w-max"
19844
- style="background-color: ${bgColor}; color: ${color};">
19887
+ <span class="cqa-inline-flex cqa-items-center cqa-gap-1 cqa-px-3 cqa-py-1 cqa-rounded-full cqa-text-xs cqa-font-medium cqa-leading-none cqa-w-max"
19888
+ style="background-color: ${token.bg}; color: ${token.text};">
19889
+ <span style="width: 10px; height: 10px; border-radius: 50%; background-color: ${token.dot}; display: inline-block;"></span>
19845
19890
  ${label}
19846
19891
  </span>
19847
19892
  `;
19848
19893
  }
19894
+ renderPriorityChip(priority) {
19895
+ const raw = (priority || '').toString().trim();
19896
+ const normalized = raw.toUpperCase();
19897
+ const priorityTokens = {
19898
+ CRITICAL: { label: 'Critical', text: '#FB2C36', bg: '#FDE8EA' },
19899
+ HIGH: { label: 'High', text: '#FB2C36', bg: '#FDE8EA' },
19900
+ MEDIUM: { label: 'Medium', text: '#D97706', bg: '#FEF3C7' },
19901
+ NORMAL: { label: 'Normal', text: '#EA580C', bg: '#FDEFE3' },
19902
+ LOW: { label: 'Low', text: '#A16207', bg: '#F5EEDC' }
19903
+ };
19904
+ const token = priorityTokens[normalized];
19905
+ if (!token) {
19906
+ const fallback = raw || 'Unassigned';
19907
+ return `
19908
+ <span class="cqa-inline-flex cqa-items-center cqa-justify-center cqa-px-3 cqa-py-1 cqa-rounded-full cqa-text-xs cqa-font-medium cqa-leading-none cqa-w-max"
19909
+ style="background-color: #F3F4F6; color: #6B7280;">
19910
+ ${fallback}
19911
+ </span>
19912
+ `;
19913
+ }
19914
+ return `
19915
+ <span class="cqa-inline-flex cqa-items-center cqa-justify-center cqa-px-3 cqa-py-1 cqa-rounded-full cqa-text-xs cqa-font-medium cqa-leading-none cqa-w-max"
19916
+ style="background-color: ${token.bg}; color: ${token.text};">
19917
+ ${token.label}
19918
+ </span>
19919
+ `;
19920
+ }
19921
+ isFailureAction(row) {
19922
+ const runBStatus = (row?.runBStatus || '').toString().toUpperCase().trim();
19923
+ return runBStatus === 'FAILURE';
19924
+ }
19925
+ getActionLabel(row) {
19926
+ return this.isFailureAction(row) ? 'View Failure' : 'View Compare';
19927
+ }
19849
19928
  getRunColumnHeader(run) {
19850
19929
  const selectedRun = run === 'A' ? this.selectedRunA : this.selectedRunB;
19851
19930
  if (selectedRun && selectedRun.id != null) {
@@ -19946,10 +20025,77 @@ class CompareRunsComponent {
19946
20025
  if (!this.comparisonData)
19947
20026
  return;
19948
20027
  this.comparisonSummary = this.comparisonData.summary;
19949
- this.stepComparisons = this.comparisonData.stepsComparison;
20028
+ const steps = this.comparisonData.stepsComparison || [];
20029
+ this.stepComparisons = steps.map((row, i) => ({ ...row, _compareRowOrdinal: i + 1 }));
20030
+ this.testPlanCardSummary = this.computeTestPlanCardSummary(this.stepComparisons);
19950
20031
  this.pageIndex = 0;
19951
20032
  this.cdr.markForCheck();
19952
20033
  }
20034
+ /**
20035
+ * Builds summary card counts for test-plan compare: pass/fail from Run B vs total;
20036
+ * change buckets from `change` (REGRESSION, FIXED, NEW STEP, etc.).
20037
+ */
20038
+ computeTestPlanCardSummary(steps) {
20039
+ const totalCases = steps.length;
20040
+ let passed = 0;
20041
+ let regressions = 0;
20042
+ let fixed = 0;
20043
+ let newSteps = 0;
20044
+ let removed = 0;
20045
+ let noChange = 0;
20046
+ for (const row of steps) {
20047
+ const b = (row.runBStatus || '').toUpperCase().trim();
20048
+ if (b === 'SUCCESS') {
20049
+ passed++;
20050
+ }
20051
+ const changeUpper = (row.change || '').toString().toUpperCase().trim();
20052
+ if (changeUpper === 'REGRESSION') {
20053
+ regressions++;
20054
+ }
20055
+ else if (changeUpper === 'FIXED') {
20056
+ fixed++;
20057
+ }
20058
+ else if (changeUpper === 'NEW STEP' || changeUpper === 'ADDED') {
20059
+ newSteps++;
20060
+ }
20061
+ else if (changeUpper === 'DELETED STEP' || changeUpper === 'REMOVED') {
20062
+ removed++;
20063
+ }
20064
+ else if (changeUpper === 'NO CHANGE' ||
20065
+ changeUpper === 'UNCHANGED' ||
20066
+ changeUpper === 'TIMING_CHANGED' ||
20067
+ changeUpper === 'TIMING CHANGED') {
20068
+ noChange++;
20069
+ }
20070
+ else if (changeUpper === 'STATUS_CHANGED') {
20071
+ const ra = (row.runAStatus || '').toUpperCase().trim();
20072
+ const rb = (row.runBStatus || '').toUpperCase().trim();
20073
+ if (ra === 'SUCCESS' && rb === 'FAILURE') {
20074
+ regressions++;
20075
+ }
20076
+ else if (ra === 'FAILURE' && rb === 'SUCCESS') {
20077
+ fixed++;
20078
+ }
20079
+ else {
20080
+ regressions++;
20081
+ }
20082
+ }
20083
+ else {
20084
+ noChange++;
20085
+ }
20086
+ }
20087
+ const failed = Math.max(0, totalCases - passed);
20088
+ return {
20089
+ totalCases,
20090
+ passed,
20091
+ failed,
20092
+ regressions,
20093
+ fixed,
20094
+ newSteps,
20095
+ removed,
20096
+ noChange
20097
+ };
20098
+ }
19953
20099
  onPageChange(event) {
19954
20100
  this.pageIndex = event.pageIndex;
19955
20101
  this.pageSize = event.pageSize;
@@ -20094,10 +20240,10 @@ class CompareRunsComponent {
20094
20240
  }
20095
20241
  }
20096
20242
  CompareRunsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: CompareRunsComponent, deps: [{ token: i1$1.FormBuilder }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
20097
- CompareRunsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: CompareRunsComponent, selector: "cqa-compare-runs", inputs: { runs: "runs", comparisonData: "comparisonData", compareMode: "compareMode", initialRunAId: "initialRunAId", initialRunBId: "initialRunBId", autoCompareOnInit: "autoCompareOnInit", isLoadingRuns: "isLoadingRuns", hasMoreRuns: "hasMoreRuns", isComparingRuns: "isComparingRuns", hasComparedRuns: "hasComparedRuns", pageSizeMenuDirection: "pageSizeMenuDirection", hideRunSelectorsAndCompareButton: "hideRunSelectorsAndCompareButton", isExportingTestPlanCompare: "isExportingTestPlanCompare" }, outputs: { searchRuns: "searchRuns", loadMoreRuns: "loadMoreRuns", compareRuns: "compareRuns", viewCompare: "viewCompare", testCaseClick: "testCaseClick", exportTestPlanCompare: "exportTestPlanCompare" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-ui-root\" style=\"display: flex; flex-direction: column; width: 100%; height: 100%;\">\n <div class=\"cqa-flex cqa-flex-col\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3 sm:cqa-gap-4 cqa-py-3 sm:cqa-py-4 cqa-px-4 sm:cqa-px-6\" style=\"border-bottom: 1px solid #E4E4E4\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-mb-1\">\n <span class=\"cqa-text-[11px] cqa-text-[#6B7280]\">Status legend:</span>\n <div class=\"cqa-flex cqa-items-center cqa-gap-3\">\n <!-- Passed -->\n <span class=\"cqa-inline-flex cqa-items-center cqa-gap-1\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M7.99998 14.6663C11.6819 14.6663 14.6666 11.6816 14.6666 7.99967C14.6666 4.31778 11.6819 1.33301 7.99998 1.33301C4.31808 1.33301 1.33331 4.31778 1.33331 7.99967C1.33331 11.6816 4.31808 14.6663 7.99998 14.6663Z\" stroke=\"#0B9D68\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6 8.00033L7.33333 9.33366L10 6.66699\" stroke=\"#0B9D68\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"cqa-text-[11px] cqa-text-[#0B9D68] cqa-font-medium\">Passed</span>\n </span>\n <!-- Failed -->\n <span class=\"cqa-inline-flex cqa-items-center cqa-gap-1\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M8.00004 14.6673C11.6819 14.6673 14.6667 11.6825 14.6667 8.00065C14.6667 4.31875 11.6819 1.33398 8.00004 1.33398C4.31814 1.33398 1.33337 4.31875 1.33337 8.00065C1.33337 11.6825 4.31814 14.6673 8.00004 14.6673Z\" stroke=\"#FB2C36\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M10 6L6 10\" stroke=\"#FB2C36\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6 6L10 10\" stroke=\"#FB2C36\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"cqa-text-[11px] cqa-text-[#FB2C36] cqa-font-medium\">Failed</span>\n </span>\n <!-- Aborted -->\n <span class=\"cqa-inline-flex cqa-items-center cqa-gap-1\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M8.00004 14.6673C11.6819 14.6673 14.6667 11.6825 14.6667 8.00065C14.6667 4.31875 11.6819 1.33398 8.00004 1.33398C4.31814 1.33398 1.33337 4.31875 1.33337 8.00065C1.33337 11.6825 4.31814 14.6673 8.00004 14.6673Z\" stroke=\"#F59E0B\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6 8H10\" stroke=\"#F59E0B\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"cqa-text-[11px] cqa-text-[#F59E0B] cqa-font-medium\">Aborted</span>\n </span>\n </div>\n </div>\n\n <div *ngIf=\"!hideRunSelectorsAndCompareButton\" class=\"cqa-grid cqa-grid-cols-1 md:cqa-grid-cols-2 cqa-gap-4 md:cqa-gap-16 cqa-relative\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#636363]\">Run A (Base)</span>\n <cqa-dynamic-select \n [form]=\"form\" \n [config]=\"runASelectConfig\"\n (searchChange)=\"onSearchChange($event)\"\n (loadMore)=\"onLoadMore($event)\">\n </cqa-dynamic-select>\n </div>\n \n <div class=\"cqa-hidden md:cqa-flex cqa-items-center cqa-justify-center\" style=\"position: absolute; left: 50%; transform: translateX(-50%); top: 30px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M4.16669 10H15.8334\" stroke=\"#636363\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M10 4.16699L15.8333 10.0003L10 15.8337\" stroke=\"#636363\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n \n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#636363]\">Run B (Compare)</span>\n <cqa-dynamic-select \n [form]=\"form\" \n [config]=\"runBSelectConfig\"\n (searchChange)=\"onSearchChange($event)\"\n (loadMore)=\"onLoadMore($event)\">\n </cqa-dynamic-select>\n </div>\n </div>\n \n <ng-container *ngIf=\"selectedRunA || selectedRunB\">\n <div class=\"cqa-grid cqa-grid-cols-1 md:cqa-grid-cols-2 cqa-gap-4\">\n <div class=\"cqa-bg-white cqa-rounded-lg cqa-p-3\"\n [style.background-color]=\"selectedRunA ? runAStatusBgColor : null\"\n [style.border-color]=\"selectedRunA ? runAStatusBorderColor : null\"\n [ngClass]=\"{'cqa-border cqa-border-solid': selectedRunA}\">\n <ng-container *ngIf=\"selectedRunA\">\n <div class=\"cqa-flex cqa-items-start cqa-justify-between cqa-mb-2\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#0B0B0B]\">Run #{{ selectedRunA.id }}</span>\n </div>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-px-2 cqa-py-0.5 cqa-rounded-full cqa-text-[10px] cqa-font-medium\"\n [style.background-color]=\"runAStatusColor\"\n [style.color]=\"'#FFFFFF'\">\n {{ runAStatusLabel }}\n </span>\n </div>\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-3\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Time: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatTime(selectedRunA.startTime) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Duration: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatDurationString(selectedRunA.duration) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Env: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunA.environment || 'NA' }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\" *ngIf=\"selectedRunA.device\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">{{ selectedRunA?.platform === 'desktop' ? 'Browser' : 'Device' }}: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunA.device }}</span>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-bg-white cqa-rounded-lg cqa-p-3\"\n [style.background-color]=\"selectedRunB ? runBStatusBgColor : null\"\n [style.border-color]=\"selectedRunB ? runBStatusBorderColor : null\"\n [ngClass]=\"{'cqa-border cqa-border-solid': selectedRunB}\">\n <ng-container *ngIf=\"selectedRunB\">\n <div class=\"cqa-flex cqa-items-start cqa-justify-between cqa-mb-2\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#0B0B0B]\">Run #{{ selectedRunB.id }}</span>\n </div>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-px-2 cqa-py-0.5 cqa-rounded-full cqa-text-[10px] cqa-font-medium\"\n [style.background-color]=\"runBStatusColor\"\n [style.color]=\"'#FFFFFF'\">\n {{ runBStatusLabel }}\n </span>\n </div>\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-3\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Time: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatTime(selectedRunB.startTime) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Duration: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatDurationString(selectedRunB.duration) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Env: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunB.environment || 'NA' }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\" *ngIf=\"selectedRunB.device\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">{{ selectedRunB?.platform === 'desktop' ? 'Browser' : 'Device' }}: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunB.device }}</span>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n </ng-container>\n\n <div *ngIf=\"!hideRunSelectorsAndCompareButton\" class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-center cqa-gap-3\">\n <cqa-button \n variant=\"filled\" \n [disabled]=\"!canCompare\"\n (click)=\"onCompareClick()\">\n {{ isComparingRuns ? 'Comparing...' : 'Compare Runs' }}\n </cqa-button>\n <cqa-button\n *ngIf=\"compareMode === 'testPlan'\"\n variant=\"outlined\"\n [text]=\"isExportingTestPlanCompare ? 'Exporting\u2026' : 'Export'\"\n [loading]=\"isExportingTestPlanCompare\"\n [disabled]=\"!canCompare\"\n (clicked)=\"onExportTestPlanCompare()\"\n ></cqa-button>\n </div>\n </div>\n\n <div *ngIf=\"showComparison && comparisonSummary && stepComparisons && stepComparisons.length > 0\" \n class=\"cqa-bg-white cqa-py-3 sm:cqa-py-4 cqa-px-3 sm:cqa-px-6 cqa-flex cqa-items-center cqa-gap-3 sm:cqa-gap-4\"\n style=\"flex-shrink: 0;\">\n <p class=\"cqa-text-[12px] cqa-text-[#636363]\">Summary:</p>\n <div class=\"cqa-flex cqa-flex-wrap cqa-items-center cqa-gap-3\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\n <path d=\"M2.91669 5.25H11.0834\" stroke=\"#636363\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2.91669 8.75H11.0834\" stroke=\"#636363\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#0B0B0B]\">{{ comparisonSummary.unchanged }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Unchanged</span>\n </div>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-flex-shrink-0 cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg fill=\"#000000\" viewBox=\"0 0 24 24\" id=\"update-alt-2\" data-name=\"Flat Color\" xmlns=\"http://www.w3.org/2000/svg\" class=\"icon flat-color\">\n <g id=\"SVGRepo_bgCarrier\" stroke-width=\"0\"></g>\n <g id=\"SVGRepo_tracerCarrier\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></g>\n <g id=\"SVGRepo_iconCarrier\">\n <path id=\"primary\" d=\"M21.71,10.29a1,1,0,0,0-1.42,0L19,11.59V7a3,3,0,0,0-3-3H6A1,1,0,0,0,6,6H16a1,1,0,0,1,1,1v4.59l-1.29-1.3a1,1,0,0,0-1.42,1.42l3,3a1,1,0,0,0,1.42,0l3-3A1,1,0,0,0,21.71,10.29Z\" fill=\"#155DFC\"></path>\n <path id=\"secondary\" d=\"M18,18H8a1,1,0,0,1-1-1V12.41l1.29,1.3a1,1,0,0,0,1.42,0,1,1,0,0,0,0-1.42l-3-3a1,1,0,0,0-1.42,0l-3,3a1,1,0,0,0,1.42,1.42L5,12.41V17a3,3,0,0,0,3,3H18a1,1,0,0,0,0-2Z\" fill=\"#155DFC\"></path>\n </g>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#155DFC]\">{{ comparisonSummary.statusChanged }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Status Changed</span>\n </div>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-flex-shrink-0 cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\n <path d=\"M2.91669 7H11.0834\" stroke=\"#00C950\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M7 2.91699V11.0837\" stroke=\"#00C950\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#00A63E]\">{{ comparisonSummary.added }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Added</span>\n </div>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-flex-shrink-0 cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\n <path d=\"M2.91669 7H11.0834\" stroke=\"#FB2C36\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#FB2C36]\">{{ comparisonSummary.removed }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Removed</span>\n </div>\n\n <!-- Timing Changed summary removed -->\n </div>\n </div>\n\n <div class=\"cqa-bg-white cqa-rounded-lg\" style=\"overflow-y: auto; max-height: calc(90dvh - 468px); scrollbar-width: thin;\">\n <cqa-table-template style=\"height: 100%; display: block;\"\n [columns]=\"tableColumns\"\n [data]=\"stepComparisons\"\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [pageSizeMenuDirection]=\"pageSizeMenuDirection\"\n [isEmptyState]=\"isEmptyState\"\n [emptyStateConfig]=\"emptyStateConfig\"\n [isTableDataLoading]=\"isComparingRuns\"\n [showSearchBar]=\"false\"\n [showFilterButton]=\"false\"\n [showSettingsButton]=\"false\"\n [showAutoRefreshButton]=\"false\"\n [showOtherButton]=\"false\"\n [showFilterPanel]=\"false\"\n [serverSidePagination]=\"false\"\n (pageChange)=\"onPageChange($event)\">\n </cqa-table-template>\n </div>\n\n </div>\n</div>\n\n", components: [{ type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore", "addCustomValue"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "loading", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: TableTemplateComponent, selector: "cqa-table-template", inputs: ["searchPlaceholder", "searchValue", "showClear", "showSearchBar", "showExportButton", "isExporting", "filterConfig", "filterModel", "showFilterPanel", "showFilterButton", "otherButtons", "otherDropDownButtons", "otherSelectDropDownButtons", "otherButtonLabel", "otherButtonVariant", "showOtherButton", "showActionButton", "showSettingsButton", "showAutoRefreshButton", "data", "isEmptyState", "emptyStateConfig", "actions", "chips", "filterApplied", "columns", "rowSelectable", "selectedAutoRefreshInterval", "pageIndex", "pageSize", "pageSizeOptions", "pageSizeMenuDirection", "serverSidePagination", "totalElements", "enableLocalSort", "isTableLoading", "isTableDataLoading", "cellJsonPathGetter", "onJsonPathCopiedHandler", "selectedItems"], outputs: ["onSearchChange", "onExportClick", "onApplyFilterClick", "onResetFilterClick", "onClearAll", "removeChip", "pageChange", "sortChange", "onReload", "onAutoRefreshClick"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
20243
+ CompareRunsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: CompareRunsComponent, selector: "cqa-compare-runs", inputs: { runs: "runs", comparisonData: "comparisonData", compareMode: "compareMode", initialRunAId: "initialRunAId", initialRunBId: "initialRunBId", autoCompareOnInit: "autoCompareOnInit", isLoadingRuns: "isLoadingRuns", hasMoreRuns: "hasMoreRuns", isComparingRuns: "isComparingRuns", hasComparedRuns: "hasComparedRuns", pageSizeMenuDirection: "pageSizeMenuDirection", hideRunSelectorsAndCompareButton: "hideRunSelectorsAndCompareButton", isExportingTestPlanCompare: "isExportingTestPlanCompare" }, outputs: { searchRuns: "searchRuns", loadMoreRuns: "loadMoreRuns", compareRuns: "compareRuns", viewCompare: "viewCompare", testCaseClick: "testCaseClick", exportTestPlanCompare: "exportTestPlanCompare" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-ui-root\" style=\"display: flex; flex-direction: column; width: 100%; height: 100%;\">\n <div class=\"cqa-flex cqa-flex-col\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3 sm:cqa-gap-4 cqa-py-3 sm:cqa-py-4 cqa-px-4 sm:cqa-px-6\" style=\"border-bottom: 1px solid #E4E4E4\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-mb-1\">\n <span class=\"cqa-text-[11px] cqa-text-[#6B7280]\">Status legend:</span>\n <div class=\"cqa-flex cqa-items-center cqa-gap-3\">\n <!-- Passed -->\n <span class=\"cqa-inline-flex cqa-items-center cqa-gap-1\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M7.99998 14.6663C11.6819 14.6663 14.6666 11.6816 14.6666 7.99967C14.6666 4.31778 11.6819 1.33301 7.99998 1.33301C4.31808 1.33301 1.33331 4.31778 1.33331 7.99967C1.33331 11.6816 4.31808 14.6663 7.99998 14.6663Z\" stroke=\"#0B9D68\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6 8.00033L7.33333 9.33366L10 6.66699\" stroke=\"#0B9D68\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"cqa-text-[11px] cqa-text-[#0B9D68] cqa-font-medium\">Passed</span>\n </span>\n <!-- Failed -->\n <span class=\"cqa-inline-flex cqa-items-center cqa-gap-1\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M8.00004 14.6673C11.6819 14.6673 14.6667 11.6825 14.6667 8.00065C14.6667 4.31875 11.6819 1.33398 8.00004 1.33398C4.31814 1.33398 1.33337 4.31875 1.33337 8.00065C1.33337 11.6825 4.31814 14.6673 8.00004 14.6673Z\" stroke=\"#FB2C36\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M10 6L6 10\" stroke=\"#FB2C36\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6 6L10 10\" stroke=\"#FB2C36\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"cqa-text-[11px] cqa-text-[#FB2C36] cqa-font-medium\">Failed</span>\n </span>\n <!-- Aborted -->\n <span class=\"cqa-inline-flex cqa-items-center cqa-gap-1\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M8.00004 14.6673C11.6819 14.6673 14.6667 11.6825 14.6667 8.00065C14.6667 4.31875 11.6819 1.33398 8.00004 1.33398C4.31814 1.33398 1.33337 4.31875 1.33337 8.00065C1.33337 11.6825 4.31814 14.6673 8.00004 14.6673Z\" stroke=\"#F59E0B\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6 8H10\" stroke=\"#F59E0B\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"cqa-text-[11px] cqa-text-[#F59E0B] cqa-font-medium\">Aborted</span>\n </span>\n </div>\n </div>\n\n <div *ngIf=\"!hideRunSelectorsAndCompareButton\" class=\"cqa-grid cqa-grid-cols-1 md:cqa-grid-cols-2 cqa-gap-4 md:cqa-gap-16 cqa-relative\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#636363]\">Run A (Base)</span>\n <cqa-dynamic-select \n [form]=\"form\" \n [config]=\"runASelectConfig\"\n (searchChange)=\"onSearchChange($event)\"\n (loadMore)=\"onLoadMore($event)\">\n </cqa-dynamic-select>\n </div>\n \n <div class=\"cqa-hidden md:cqa-flex cqa-items-center cqa-justify-center\" style=\"position: absolute; left: 50%; transform: translateX(-50%); top: 30px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M4.16669 10H15.8334\" stroke=\"#636363\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M10 4.16699L15.8333 10.0003L10 15.8337\" stroke=\"#636363\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n \n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#636363]\">Run B (Compare)</span>\n <cqa-dynamic-select \n [form]=\"form\" \n [config]=\"runBSelectConfig\"\n (searchChange)=\"onSearchChange($event)\"\n (loadMore)=\"onLoadMore($event)\">\n </cqa-dynamic-select>\n </div>\n </div>\n \n <ng-container *ngIf=\"selectedRunA || selectedRunB\">\n <div class=\"cqa-grid cqa-grid-cols-1 md:cqa-grid-cols-2 cqa-gap-4\">\n <div class=\"cqa-bg-white cqa-rounded-lg cqa-p-3\"\n [style.background-color]=\"selectedRunA ? runAStatusBgColor : null\"\n [style.border-color]=\"selectedRunA ? runAStatusBorderColor : null\"\n [ngClass]=\"{'cqa-border cqa-border-solid': selectedRunA}\">\n <ng-container *ngIf=\"selectedRunA\">\n <div class=\"cqa-flex cqa-items-start cqa-justify-between cqa-mb-2\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#0B0B0B]\">Run #{{ selectedRunA.id }}</span>\n </div>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-px-2 cqa-py-0.5 cqa-rounded-full cqa-text-[10px] cqa-font-medium\"\n [style.background-color]=\"runAStatusColor\"\n [style.color]=\"'#FFFFFF'\">\n {{ runAStatusLabel }}\n </span>\n </div>\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-3\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Time: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatTime(selectedRunA.startTime) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Duration: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatDurationString(selectedRunA.duration) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Env: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunA.environment || 'NA' }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\" *ngIf=\"selectedRunA.device\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">{{ selectedRunA?.platform === 'desktop' ? 'Browser' : 'Device' }}: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunA.device }}</span>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-bg-white cqa-rounded-lg cqa-p-3\"\n [style.background-color]=\"selectedRunB ? runBStatusBgColor : null\"\n [style.border-color]=\"selectedRunB ? runBStatusBorderColor : null\"\n [ngClass]=\"{'cqa-border cqa-border-solid': selectedRunB}\">\n <ng-container *ngIf=\"selectedRunB\">\n <div class=\"cqa-flex cqa-items-start cqa-justify-between cqa-mb-2\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#0B0B0B]\">Run #{{ selectedRunB.id }}</span>\n </div>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-px-2 cqa-py-0.5 cqa-rounded-full cqa-text-[10px] cqa-font-medium\"\n [style.background-color]=\"runBStatusColor\"\n [style.color]=\"'#FFFFFF'\">\n {{ runBStatusLabel }}\n </span>\n </div>\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-3\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Time: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatTime(selectedRunB.startTime) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Duration: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatDurationString(selectedRunB.duration) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Env: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunB.environment || 'NA' }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\" *ngIf=\"selectedRunB.device\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">{{ selectedRunB?.platform === 'desktop' ? 'Browser' : 'Device' }}: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunB.device }}</span>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n </ng-container>\n\n <div *ngIf=\"!hideRunSelectorsAndCompareButton\" class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-center cqa-gap-3\">\n <cqa-button \n variant=\"filled\" \n [disabled]=\"!canCompare\"\n (click)=\"onCompareClick()\">\n {{ isComparingRuns ? 'Comparing...' : 'Compare Runs' }}\n </cqa-button>\n <cqa-button\n *ngIf=\"compareMode === 'testPlan'\"\n variant=\"outlined\"\n [text]=\"isExportingTestPlanCompare ? 'Exporting\u2026' : 'Export'\"\n [loading]=\"isExportingTestPlanCompare\"\n [disabled]=\"!canCompare\"\n (clicked)=\"onExportTestPlanCompare()\"\n ></cqa-button>\n </div>\n </div>\n\n <div\n *ngIf=\"showComparison && compareMode === 'testPlan' && testPlanCardSummary && stepComparisons && stepComparisons.length > 0\"\n class=\"cqa-bg-white cqa-py-3 sm:cqa-py-4 cqa-px-3 sm:cqa-px-6\"\n style=\"flex-shrink: 0;\"\n >\n <div\n class=\"cqa-flex cqa-flex-row cqa-flex-wrap cqa-items-stretch cqa-justify-between sm:cqa-justify-start cqa-gap-2 sm:cqa-gap-3\"\n >\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[92px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#A5B4FC] cqa-bg-[#EEF2FF] cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#1E293B]\">{{ testPlanCardSummary.totalCases }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#64748B]\">Total Cases</span>\n </div>\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[88px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-bg-white cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#00A63E]\">{{ testPlanCardSummary.passed }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#6B7280]\">Passed</span>\n </div>\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[88px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-bg-white cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#FB2C36]\">{{ testPlanCardSummary.failed }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#6B7280]\">Failed</span>\n </div>\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[88px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-bg-white cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#FB2C36]\">{{ testPlanCardSummary.regressions }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#6B7280]\">Regressions</span>\n </div>\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[88px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-bg-white cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#00A63E]\">{{ testPlanCardSummary.fixed }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#6B7280]\">Fixed</span>\n </div>\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[88px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-bg-white cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#155DFC]\">{{ testPlanCardSummary.newSteps }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#6B7280]\">New</span>\n </div>\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[88px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-bg-white cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#6B7280]\">{{ testPlanCardSummary.removed }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#6B7280]\">Removed</span>\n </div>\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[88px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-bg-white cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#6B7280]\">{{ testPlanCardSummary.noChange }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#6B7280]\">No Change</span>\n </div>\n </div>\n </div>\n\n <div\n *ngIf=\"showComparison && compareMode !== 'testPlan' && comparisonSummary && stepComparisons && stepComparisons.length > 0\"\n class=\"cqa-bg-white cqa-py-3 sm:cqa-py-4 cqa-px-3 sm:cqa-px-6 cqa-flex cqa-items-center cqa-gap-3 sm:cqa-gap-4\"\n style=\"flex-shrink: 0;\"\n >\n <p class=\"cqa-text-[12px] cqa-text-[#636363]\">Summary:</p>\n <div class=\"cqa-flex cqa-flex-wrap cqa-items-center cqa-gap-3\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\n <path d=\"M2.91669 5.25H11.0834\" stroke=\"#636363\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2.91669 8.75H11.0834\" stroke=\"#636363\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#0B0B0B]\">{{ comparisonSummary.unchanged }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Unchanged</span>\n </div>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-flex-shrink-0 cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg fill=\"#000000\" viewBox=\"0 0 24 24\" id=\"update-alt-2\" data-name=\"Flat Color\" xmlns=\"http://www.w3.org/2000/svg\" class=\"icon flat-color\">\n <g id=\"SVGRepo_bgCarrier\" stroke-width=\"0\"></g>\n <g id=\"SVGRepo_tracerCarrier\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></g>\n <g id=\"SVGRepo_iconCarrier\">\n <path id=\"primary\" d=\"M21.71,10.29a1,1,0,0,0-1.42,0L19,11.59V7a3,3,0,0,0-3-3H6A1,1,0,0,0,6,6H16a1,1,0,0,1,1,1v4.59l-1.29-1.3a1,1,0,0,0-1.42,1.42l3,3a1,1,0,0,0,1.42,0l3-3A1,1,0,0,0,21.71,10.29Z\" fill=\"#155DFC\"></path>\n <path id=\"secondary\" d=\"M18,18H8a1,1,0,0,1-1-1V12.41l1.29,1.3a1,1,0,0,0,1.42,0,1,1,0,0,0,0-1.42l-3-3a1,1,0,0,0-1.42,0l-3,3a1,1,0,0,0,1.42,1.42L5,12.41V17a3,3,0,0,0,3,3H18a1,1,0,0,0,0-2Z\" fill=\"#155DFC\"></path>\n </g>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#155DFC]\">{{ comparisonSummary.statusChanged }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Status Changed</span>\n </div>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-flex-shrink-0 cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\n <path d=\"M2.91669 7H11.0834\" stroke=\"#00C950\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M7 2.91699V11.0837\" stroke=\"#00C950\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#00A63E]\">{{ comparisonSummary.added }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Added</span>\n </div>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-flex-shrink-0 cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\n <path d=\"M2.91669 7H11.0834\" stroke=\"#FB2C36\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#FB2C36]\">{{ comparisonSummary.removed }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Removed</span>\n </div>\n </div>\n </div>\n\n <div class=\"cqa-bg-white cqa-rounded-lg\" style=\"overflow-y: auto; max-height: calc(90dvh - 468px); scrollbar-width: thin;\">\n <cqa-table-template style=\"height: 100%; display: block;\"\n [columns]=\"tableColumns\"\n [data]=\"stepComparisons\"\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [pageSizeMenuDirection]=\"pageSizeMenuDirection\"\n [isEmptyState]=\"isEmptyState\"\n [emptyStateConfig]=\"emptyStateConfig\"\n [isTableDataLoading]=\"isComparingRuns\"\n [showSearchBar]=\"false\"\n [showFilterButton]=\"false\"\n [showSettingsButton]=\"false\"\n [showAutoRefreshButton]=\"false\"\n [showOtherButton]=\"false\"\n [showFilterPanel]=\"false\"\n [serverSidePagination]=\"false\"\n (pageChange)=\"onPageChange($event)\">\n </cqa-table-template>\n </div>\n\n </div>\n</div>\n\n", components: [{ type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore", "addCustomValue"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "loading", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: TableTemplateComponent, selector: "cqa-table-template", inputs: ["searchPlaceholder", "searchValue", "showClear", "showSearchBar", "showExportButton", "isExporting", "filterConfig", "filterModel", "showFilterPanel", "showFilterButton", "otherButtons", "otherDropDownButtons", "otherSelectDropDownButtons", "otherButtonLabel", "otherButtonVariant", "showOtherButton", "showActionButton", "showSettingsButton", "showAutoRefreshButton", "data", "isEmptyState", "emptyStateConfig", "actions", "chips", "filterApplied", "columns", "rowSelectable", "selectedAutoRefreshInterval", "pageIndex", "pageSize", "pageSizeOptions", "pageSizeMenuDirection", "serverSidePagination", "totalElements", "enableLocalSort", "isTableLoading", "isTableDataLoading", "cellJsonPathGetter", "onJsonPathCopiedHandler", "selectedItems"], outputs: ["onSearchChange", "onExportClick", "onApplyFilterClick", "onResetFilterClick", "onClearAll", "removeChip", "pageChange", "sortChange", "onReload", "onAutoRefreshClick"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
20098
20244
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: CompareRunsComponent, decorators: [{
20099
20245
  type: Component,
20100
- args: [{ selector: 'cqa-compare-runs', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"cqa-ui-root\" style=\"display: flex; flex-direction: column; width: 100%; height: 100%;\">\n <div class=\"cqa-flex cqa-flex-col\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3 sm:cqa-gap-4 cqa-py-3 sm:cqa-py-4 cqa-px-4 sm:cqa-px-6\" style=\"border-bottom: 1px solid #E4E4E4\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-mb-1\">\n <span class=\"cqa-text-[11px] cqa-text-[#6B7280]\">Status legend:</span>\n <div class=\"cqa-flex cqa-items-center cqa-gap-3\">\n <!-- Passed -->\n <span class=\"cqa-inline-flex cqa-items-center cqa-gap-1\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M7.99998 14.6663C11.6819 14.6663 14.6666 11.6816 14.6666 7.99967C14.6666 4.31778 11.6819 1.33301 7.99998 1.33301C4.31808 1.33301 1.33331 4.31778 1.33331 7.99967C1.33331 11.6816 4.31808 14.6663 7.99998 14.6663Z\" stroke=\"#0B9D68\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6 8.00033L7.33333 9.33366L10 6.66699\" stroke=\"#0B9D68\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"cqa-text-[11px] cqa-text-[#0B9D68] cqa-font-medium\">Passed</span>\n </span>\n <!-- Failed -->\n <span class=\"cqa-inline-flex cqa-items-center cqa-gap-1\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M8.00004 14.6673C11.6819 14.6673 14.6667 11.6825 14.6667 8.00065C14.6667 4.31875 11.6819 1.33398 8.00004 1.33398C4.31814 1.33398 1.33337 4.31875 1.33337 8.00065C1.33337 11.6825 4.31814 14.6673 8.00004 14.6673Z\" stroke=\"#FB2C36\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M10 6L6 10\" stroke=\"#FB2C36\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6 6L10 10\" stroke=\"#FB2C36\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"cqa-text-[11px] cqa-text-[#FB2C36] cqa-font-medium\">Failed</span>\n </span>\n <!-- Aborted -->\n <span class=\"cqa-inline-flex cqa-items-center cqa-gap-1\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M8.00004 14.6673C11.6819 14.6673 14.6667 11.6825 14.6667 8.00065C14.6667 4.31875 11.6819 1.33398 8.00004 1.33398C4.31814 1.33398 1.33337 4.31875 1.33337 8.00065C1.33337 11.6825 4.31814 14.6673 8.00004 14.6673Z\" stroke=\"#F59E0B\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6 8H10\" stroke=\"#F59E0B\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"cqa-text-[11px] cqa-text-[#F59E0B] cqa-font-medium\">Aborted</span>\n </span>\n </div>\n </div>\n\n <div *ngIf=\"!hideRunSelectorsAndCompareButton\" class=\"cqa-grid cqa-grid-cols-1 md:cqa-grid-cols-2 cqa-gap-4 md:cqa-gap-16 cqa-relative\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#636363]\">Run A (Base)</span>\n <cqa-dynamic-select \n [form]=\"form\" \n [config]=\"runASelectConfig\"\n (searchChange)=\"onSearchChange($event)\"\n (loadMore)=\"onLoadMore($event)\">\n </cqa-dynamic-select>\n </div>\n \n <div class=\"cqa-hidden md:cqa-flex cqa-items-center cqa-justify-center\" style=\"position: absolute; left: 50%; transform: translateX(-50%); top: 30px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M4.16669 10H15.8334\" stroke=\"#636363\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M10 4.16699L15.8333 10.0003L10 15.8337\" stroke=\"#636363\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n \n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#636363]\">Run B (Compare)</span>\n <cqa-dynamic-select \n [form]=\"form\" \n [config]=\"runBSelectConfig\"\n (searchChange)=\"onSearchChange($event)\"\n (loadMore)=\"onLoadMore($event)\">\n </cqa-dynamic-select>\n </div>\n </div>\n \n <ng-container *ngIf=\"selectedRunA || selectedRunB\">\n <div class=\"cqa-grid cqa-grid-cols-1 md:cqa-grid-cols-2 cqa-gap-4\">\n <div class=\"cqa-bg-white cqa-rounded-lg cqa-p-3\"\n [style.background-color]=\"selectedRunA ? runAStatusBgColor : null\"\n [style.border-color]=\"selectedRunA ? runAStatusBorderColor : null\"\n [ngClass]=\"{'cqa-border cqa-border-solid': selectedRunA}\">\n <ng-container *ngIf=\"selectedRunA\">\n <div class=\"cqa-flex cqa-items-start cqa-justify-between cqa-mb-2\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#0B0B0B]\">Run #{{ selectedRunA.id }}</span>\n </div>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-px-2 cqa-py-0.5 cqa-rounded-full cqa-text-[10px] cqa-font-medium\"\n [style.background-color]=\"runAStatusColor\"\n [style.color]=\"'#FFFFFF'\">\n {{ runAStatusLabel }}\n </span>\n </div>\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-3\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Time: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatTime(selectedRunA.startTime) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Duration: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatDurationString(selectedRunA.duration) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Env: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunA.environment || 'NA' }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\" *ngIf=\"selectedRunA.device\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">{{ selectedRunA?.platform === 'desktop' ? 'Browser' : 'Device' }}: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunA.device }}</span>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-bg-white cqa-rounded-lg cqa-p-3\"\n [style.background-color]=\"selectedRunB ? runBStatusBgColor : null\"\n [style.border-color]=\"selectedRunB ? runBStatusBorderColor : null\"\n [ngClass]=\"{'cqa-border cqa-border-solid': selectedRunB}\">\n <ng-container *ngIf=\"selectedRunB\">\n <div class=\"cqa-flex cqa-items-start cqa-justify-between cqa-mb-2\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#0B0B0B]\">Run #{{ selectedRunB.id }}</span>\n </div>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-px-2 cqa-py-0.5 cqa-rounded-full cqa-text-[10px] cqa-font-medium\"\n [style.background-color]=\"runBStatusColor\"\n [style.color]=\"'#FFFFFF'\">\n {{ runBStatusLabel }}\n </span>\n </div>\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-3\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Time: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatTime(selectedRunB.startTime) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Duration: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatDurationString(selectedRunB.duration) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Env: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunB.environment || 'NA' }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\" *ngIf=\"selectedRunB.device\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">{{ selectedRunB?.platform === 'desktop' ? 'Browser' : 'Device' }}: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunB.device }}</span>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n </ng-container>\n\n <div *ngIf=\"!hideRunSelectorsAndCompareButton\" class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-center cqa-gap-3\">\n <cqa-button \n variant=\"filled\" \n [disabled]=\"!canCompare\"\n (click)=\"onCompareClick()\">\n {{ isComparingRuns ? 'Comparing...' : 'Compare Runs' }}\n </cqa-button>\n <cqa-button\n *ngIf=\"compareMode === 'testPlan'\"\n variant=\"outlined\"\n [text]=\"isExportingTestPlanCompare ? 'Exporting\u2026' : 'Export'\"\n [loading]=\"isExportingTestPlanCompare\"\n [disabled]=\"!canCompare\"\n (clicked)=\"onExportTestPlanCompare()\"\n ></cqa-button>\n </div>\n </div>\n\n <div *ngIf=\"showComparison && comparisonSummary && stepComparisons && stepComparisons.length > 0\" \n class=\"cqa-bg-white cqa-py-3 sm:cqa-py-4 cqa-px-3 sm:cqa-px-6 cqa-flex cqa-items-center cqa-gap-3 sm:cqa-gap-4\"\n style=\"flex-shrink: 0;\">\n <p class=\"cqa-text-[12px] cqa-text-[#636363]\">Summary:</p>\n <div class=\"cqa-flex cqa-flex-wrap cqa-items-center cqa-gap-3\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\n <path d=\"M2.91669 5.25H11.0834\" stroke=\"#636363\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2.91669 8.75H11.0834\" stroke=\"#636363\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#0B0B0B]\">{{ comparisonSummary.unchanged }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Unchanged</span>\n </div>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-flex-shrink-0 cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg fill=\"#000000\" viewBox=\"0 0 24 24\" id=\"update-alt-2\" data-name=\"Flat Color\" xmlns=\"http://www.w3.org/2000/svg\" class=\"icon flat-color\">\n <g id=\"SVGRepo_bgCarrier\" stroke-width=\"0\"></g>\n <g id=\"SVGRepo_tracerCarrier\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></g>\n <g id=\"SVGRepo_iconCarrier\">\n <path id=\"primary\" d=\"M21.71,10.29a1,1,0,0,0-1.42,0L19,11.59V7a3,3,0,0,0-3-3H6A1,1,0,0,0,6,6H16a1,1,0,0,1,1,1v4.59l-1.29-1.3a1,1,0,0,0-1.42,1.42l3,3a1,1,0,0,0,1.42,0l3-3A1,1,0,0,0,21.71,10.29Z\" fill=\"#155DFC\"></path>\n <path id=\"secondary\" d=\"M18,18H8a1,1,0,0,1-1-1V12.41l1.29,1.3a1,1,0,0,0,1.42,0,1,1,0,0,0,0-1.42l-3-3a1,1,0,0,0-1.42,0l-3,3a1,1,0,0,0,1.42,1.42L5,12.41V17a3,3,0,0,0,3,3H18a1,1,0,0,0,0-2Z\" fill=\"#155DFC\"></path>\n </g>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#155DFC]\">{{ comparisonSummary.statusChanged }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Status Changed</span>\n </div>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-flex-shrink-0 cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\n <path d=\"M2.91669 7H11.0834\" stroke=\"#00C950\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M7 2.91699V11.0837\" stroke=\"#00C950\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#00A63E]\">{{ comparisonSummary.added }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Added</span>\n </div>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-flex-shrink-0 cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\n <path d=\"M2.91669 7H11.0834\" stroke=\"#FB2C36\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#FB2C36]\">{{ comparisonSummary.removed }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Removed</span>\n </div>\n\n <!-- Timing Changed summary removed -->\n </div>\n </div>\n\n <div class=\"cqa-bg-white cqa-rounded-lg\" style=\"overflow-y: auto; max-height: calc(90dvh - 468px); scrollbar-width: thin;\">\n <cqa-table-template style=\"height: 100%; display: block;\"\n [columns]=\"tableColumns\"\n [data]=\"stepComparisons\"\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [pageSizeMenuDirection]=\"pageSizeMenuDirection\"\n [isEmptyState]=\"isEmptyState\"\n [emptyStateConfig]=\"emptyStateConfig\"\n [isTableDataLoading]=\"isComparingRuns\"\n [showSearchBar]=\"false\"\n [showFilterButton]=\"false\"\n [showSettingsButton]=\"false\"\n [showAutoRefreshButton]=\"false\"\n [showOtherButton]=\"false\"\n [showFilterPanel]=\"false\"\n [serverSidePagination]=\"false\"\n (pageChange)=\"onPageChange($event)\">\n </cqa-table-template>\n </div>\n\n </div>\n</div>\n\n", styles: [] }]
20246
+ args: [{ selector: 'cqa-compare-runs', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"cqa-ui-root\" style=\"display: flex; flex-direction: column; width: 100%; height: 100%;\">\n <div class=\"cqa-flex cqa-flex-col\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3 sm:cqa-gap-4 cqa-py-3 sm:cqa-py-4 cqa-px-4 sm:cqa-px-6\" style=\"border-bottom: 1px solid #E4E4E4\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-mb-1\">\n <span class=\"cqa-text-[11px] cqa-text-[#6B7280]\">Status legend:</span>\n <div class=\"cqa-flex cqa-items-center cqa-gap-3\">\n <!-- Passed -->\n <span class=\"cqa-inline-flex cqa-items-center cqa-gap-1\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M7.99998 14.6663C11.6819 14.6663 14.6666 11.6816 14.6666 7.99967C14.6666 4.31778 11.6819 1.33301 7.99998 1.33301C4.31808 1.33301 1.33331 4.31778 1.33331 7.99967C1.33331 11.6816 4.31808 14.6663 7.99998 14.6663Z\" stroke=\"#0B9D68\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6 8.00033L7.33333 9.33366L10 6.66699\" stroke=\"#0B9D68\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"cqa-text-[11px] cqa-text-[#0B9D68] cqa-font-medium\">Passed</span>\n </span>\n <!-- Failed -->\n <span class=\"cqa-inline-flex cqa-items-center cqa-gap-1\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M8.00004 14.6673C11.6819 14.6673 14.6667 11.6825 14.6667 8.00065C14.6667 4.31875 11.6819 1.33398 8.00004 1.33398C4.31814 1.33398 1.33337 4.31875 1.33337 8.00065C1.33337 11.6825 4.31814 14.6673 8.00004 14.6673Z\" stroke=\"#FB2C36\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M10 6L6 10\" stroke=\"#FB2C36\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6 6L10 10\" stroke=\"#FB2C36\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"cqa-text-[11px] cqa-text-[#FB2C36] cqa-font-medium\">Failed</span>\n </span>\n <!-- Aborted -->\n <span class=\"cqa-inline-flex cqa-items-center cqa-gap-1\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M8.00004 14.6673C11.6819 14.6673 14.6667 11.6825 14.6667 8.00065C14.6667 4.31875 11.6819 1.33398 8.00004 1.33398C4.31814 1.33398 1.33337 4.31875 1.33337 8.00065C1.33337 11.6825 4.31814 14.6673 8.00004 14.6673Z\" stroke=\"#F59E0B\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6 8H10\" stroke=\"#F59E0B\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"cqa-text-[11px] cqa-text-[#F59E0B] cqa-font-medium\">Aborted</span>\n </span>\n </div>\n </div>\n\n <div *ngIf=\"!hideRunSelectorsAndCompareButton\" class=\"cqa-grid cqa-grid-cols-1 md:cqa-grid-cols-2 cqa-gap-4 md:cqa-gap-16 cqa-relative\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#636363]\">Run A (Base)</span>\n <cqa-dynamic-select \n [form]=\"form\" \n [config]=\"runASelectConfig\"\n (searchChange)=\"onSearchChange($event)\"\n (loadMore)=\"onLoadMore($event)\">\n </cqa-dynamic-select>\n </div>\n \n <div class=\"cqa-hidden md:cqa-flex cqa-items-center cqa-justify-center\" style=\"position: absolute; left: 50%; transform: translateX(-50%); top: 30px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M4.16669 10H15.8334\" stroke=\"#636363\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M10 4.16699L15.8333 10.0003L10 15.8337\" stroke=\"#636363\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n \n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#636363]\">Run B (Compare)</span>\n <cqa-dynamic-select \n [form]=\"form\" \n [config]=\"runBSelectConfig\"\n (searchChange)=\"onSearchChange($event)\"\n (loadMore)=\"onLoadMore($event)\">\n </cqa-dynamic-select>\n </div>\n </div>\n \n <ng-container *ngIf=\"selectedRunA || selectedRunB\">\n <div class=\"cqa-grid cqa-grid-cols-1 md:cqa-grid-cols-2 cqa-gap-4\">\n <div class=\"cqa-bg-white cqa-rounded-lg cqa-p-3\"\n [style.background-color]=\"selectedRunA ? runAStatusBgColor : null\"\n [style.border-color]=\"selectedRunA ? runAStatusBorderColor : null\"\n [ngClass]=\"{'cqa-border cqa-border-solid': selectedRunA}\">\n <ng-container *ngIf=\"selectedRunA\">\n <div class=\"cqa-flex cqa-items-start cqa-justify-between cqa-mb-2\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#0B0B0B]\">Run #{{ selectedRunA.id }}</span>\n </div>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-px-2 cqa-py-0.5 cqa-rounded-full cqa-text-[10px] cqa-font-medium\"\n [style.background-color]=\"runAStatusColor\"\n [style.color]=\"'#FFFFFF'\">\n {{ runAStatusLabel }}\n </span>\n </div>\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-3\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Time: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatTime(selectedRunA.startTime) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Duration: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatDurationString(selectedRunA.duration) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Env: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunA.environment || 'NA' }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\" *ngIf=\"selectedRunA.device\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">{{ selectedRunA?.platform === 'desktop' ? 'Browser' : 'Device' }}: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunA.device }}</span>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-bg-white cqa-rounded-lg cqa-p-3\"\n [style.background-color]=\"selectedRunB ? runBStatusBgColor : null\"\n [style.border-color]=\"selectedRunB ? runBStatusBorderColor : null\"\n [ngClass]=\"{'cqa-border cqa-border-solid': selectedRunB}\">\n <ng-container *ngIf=\"selectedRunB\">\n <div class=\"cqa-flex cqa-items-start cqa-justify-between cqa-mb-2\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1\">\n <span class=\"cqa-text-[12px] cqa-font-semibold cqa-text-[#0B0B0B]\">Run #{{ selectedRunB.id }}</span>\n </div>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-px-2 cqa-py-0.5 cqa-rounded-full cqa-text-[10px] cqa-font-medium\"\n [style.background-color]=\"runBStatusColor\"\n [style.color]=\"'#FFFFFF'\">\n {{ runBStatusLabel }}\n </span>\n </div>\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-3\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Time: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatTime(selectedRunB.startTime) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Duration: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ formatDurationString(selectedRunB.duration) }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">Env: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunB.environment || 'NA' }}</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\" *ngIf=\"selectedRunB.device\">\n <span class=\"cqa-text-xs cqa-text-[#636363]\">{{ selectedRunB?.platform === 'desktop' ? 'Browser' : 'Device' }}: </span>\n <span class=\"cqa-text-xs cqa-text-[#0B0B0B] cqa-font-medium\">{{ selectedRunB.device }}</span>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n </ng-container>\n\n <div *ngIf=\"!hideRunSelectorsAndCompareButton\" class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-center cqa-gap-3\">\n <cqa-button \n variant=\"filled\" \n [disabled]=\"!canCompare\"\n (click)=\"onCompareClick()\">\n {{ isComparingRuns ? 'Comparing...' : 'Compare Runs' }}\n </cqa-button>\n <cqa-button\n *ngIf=\"compareMode === 'testPlan'\"\n variant=\"outlined\"\n [text]=\"isExportingTestPlanCompare ? 'Exporting\u2026' : 'Export'\"\n [loading]=\"isExportingTestPlanCompare\"\n [disabled]=\"!canCompare\"\n (clicked)=\"onExportTestPlanCompare()\"\n ></cqa-button>\n </div>\n </div>\n\n <div\n *ngIf=\"showComparison && compareMode === 'testPlan' && testPlanCardSummary && stepComparisons && stepComparisons.length > 0\"\n class=\"cqa-bg-white cqa-py-3 sm:cqa-py-4 cqa-px-3 sm:cqa-px-6\"\n style=\"flex-shrink: 0;\"\n >\n <div\n class=\"cqa-flex cqa-flex-row cqa-flex-wrap cqa-items-stretch cqa-justify-between sm:cqa-justify-start cqa-gap-2 sm:cqa-gap-3\"\n >\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[92px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#A5B4FC] cqa-bg-[#EEF2FF] cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#1E293B]\">{{ testPlanCardSummary.totalCases }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#64748B]\">Total Cases</span>\n </div>\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[88px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-bg-white cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#00A63E]\">{{ testPlanCardSummary.passed }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#6B7280]\">Passed</span>\n </div>\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[88px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-bg-white cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#FB2C36]\">{{ testPlanCardSummary.failed }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#6B7280]\">Failed</span>\n </div>\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[88px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-bg-white cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#FB2C36]\">{{ testPlanCardSummary.regressions }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#6B7280]\">Regressions</span>\n </div>\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[88px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-bg-white cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#00A63E]\">{{ testPlanCardSummary.fixed }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#6B7280]\">Fixed</span>\n </div>\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[88px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-bg-white cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#155DFC]\">{{ testPlanCardSummary.newSteps }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#6B7280]\">New</span>\n </div>\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[88px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-bg-white cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#6B7280]\">{{ testPlanCardSummary.removed }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#6B7280]\">Removed</span>\n </div>\n <div\n class=\"cqa-flex cqa-min-w-0 cqa-flex-[1_1_72px] sm:cqa-flex-none sm:cqa-w-[88px] cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-1 cqa-rounded-xl cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-bg-white cqa-py-3 cqa-px-2\"\n >\n <span class=\"cqa-text-xl cqa-font-bold cqa-leading-none cqa-text-[#6B7280]\">{{ testPlanCardSummary.noChange }}</span>\n <span class=\"cqa-text-center cqa-text-[10px] cqa-font-semibold cqa-leading-tight cqa-text-[#6B7280]\">No Change</span>\n </div>\n </div>\n </div>\n\n <div\n *ngIf=\"showComparison && compareMode !== 'testPlan' && comparisonSummary && stepComparisons && stepComparisons.length > 0\"\n class=\"cqa-bg-white cqa-py-3 sm:cqa-py-4 cqa-px-3 sm:cqa-px-6 cqa-flex cqa-items-center cqa-gap-3 sm:cqa-gap-4\"\n style=\"flex-shrink: 0;\"\n >\n <p class=\"cqa-text-[12px] cqa-text-[#636363]\">Summary:</p>\n <div class=\"cqa-flex cqa-flex-wrap cqa-items-center cqa-gap-3\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\n <path d=\"M2.91669 5.25H11.0834\" stroke=\"#636363\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2.91669 8.75H11.0834\" stroke=\"#636363\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#0B0B0B]\">{{ comparisonSummary.unchanged }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Unchanged</span>\n </div>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-flex-shrink-0 cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg fill=\"#000000\" viewBox=\"0 0 24 24\" id=\"update-alt-2\" data-name=\"Flat Color\" xmlns=\"http://www.w3.org/2000/svg\" class=\"icon flat-color\">\n <g id=\"SVGRepo_bgCarrier\" stroke-width=\"0\"></g>\n <g id=\"SVGRepo_tracerCarrier\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></g>\n <g id=\"SVGRepo_iconCarrier\">\n <path id=\"primary\" d=\"M21.71,10.29a1,1,0,0,0-1.42,0L19,11.59V7a3,3,0,0,0-3-3H6A1,1,0,0,0,6,6H16a1,1,0,0,1,1,1v4.59l-1.29-1.3a1,1,0,0,0-1.42,1.42l3,3a1,1,0,0,0,1.42,0l3-3A1,1,0,0,0,21.71,10.29Z\" fill=\"#155DFC\"></path>\n <path id=\"secondary\" d=\"M18,18H8a1,1,0,0,1-1-1V12.41l1.29,1.3a1,1,0,0,0,1.42,0,1,1,0,0,0,0-1.42l-3-3a1,1,0,0,0-1.42,0l-3,3a1,1,0,0,0,1.42,1.42L5,12.41V17a3,3,0,0,0,3,3H18a1,1,0,0,0,0-2Z\" fill=\"#155DFC\"></path>\n </g>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#155DFC]\">{{ comparisonSummary.statusChanged }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Status Changed</span>\n </div>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-flex-shrink-0 cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\n <path d=\"M2.91669 7H11.0834\" stroke=\"#00C950\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M7 2.91699V11.0837\" stroke=\"#00C950\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#00A63E]\">{{ comparisonSummary.added }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Added</span>\n </div>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"cqa-flex-shrink-0 cqa-w-[14px] cqa-h-[14px] cqa-text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\n <path d=\"M2.91669 7H11.0834\" stroke=\"#FB2C36\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <span class=\"cqa-text-sm cqa-font-semibold leading-normal cqa-text-[#FB2C36]\">{{ comparisonSummary.removed }}</span>\n <span class=\"cqa-text-[10px] cqa-font-semibold cqa-text-[#6B7280]\">Removed</span>\n </div>\n </div>\n </div>\n\n <div class=\"cqa-bg-white cqa-rounded-lg\" style=\"overflow-y: auto; max-height: calc(90dvh - 468px); scrollbar-width: thin;\">\n <cqa-table-template style=\"height: 100%; display: block;\"\n [columns]=\"tableColumns\"\n [data]=\"stepComparisons\"\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [pageSizeMenuDirection]=\"pageSizeMenuDirection\"\n [isEmptyState]=\"isEmptyState\"\n [emptyStateConfig]=\"emptyStateConfig\"\n [isTableDataLoading]=\"isComparingRuns\"\n [showSearchBar]=\"false\"\n [showFilterButton]=\"false\"\n [showSettingsButton]=\"false\"\n [showAutoRefreshButton]=\"false\"\n [showOtherButton]=\"false\"\n [showFilterPanel]=\"false\"\n [serverSidePagination]=\"false\"\n (pageChange)=\"onPageChange($event)\">\n </cqa-table-template>\n </div>\n\n </div>\n</div>\n\n", styles: [] }]
20101
20247
  }], ctorParameters: function () { return [{ type: i1$1.FormBuilder }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { runs: [{
20102
20248
  type: Input
20103
20249
  }], comparisonData: [{