@cqa-lib/cqa-ui 1.1.537 → 1.1.539

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.
@@ -1653,7 +1653,6 @@ class DynamicTableComponent {
1653
1653
  ? `max(${c.minWidth}px, ${dynamicWidth})`
1654
1654
  : dynamicWidth;
1655
1655
  });
1656
- console.log('computedColumnWidths', this.computedColumnWidths);
1657
1656
  if (this.gridTemplateColumns) {
1658
1657
  this.computedGridTemplate = this.gridTemplateColumns;
1659
1658
  }
@@ -7860,7 +7859,13 @@ const DEFAULT_MODULAR_CONFIG = {
7860
7859
  allowNestedFolders: true,
7861
7860
  allowTestDragDrop: true,
7862
7861
  allowBulkSelection: true,
7862
+ showFolderColumn: true,
7863
7863
  };
7864
+ /**
7865
+ * Reserved fieldId for the auto-injected folder column. Hosts should avoid
7866
+ * defining a column with this id of their own.
7867
+ */
7868
+ const FOLDER_COLUMN_FIELD_ID = 'folder';
7864
7869
  const DEFAULT_MODULAR_LABELS = {
7865
7870
  folders: 'Folders',
7866
7871
  organised: 'Organised',
@@ -7915,6 +7920,9 @@ const DEFAULT_MODULAR_LABELS = {
7915
7920
  deleteFolderDialogConfirm: 'Delete folder',
7916
7921
  emptyNoTestsInFolderTitle: 'No Test Case Found',
7917
7922
  emptyNoTestsInFolderDescription: 'This folder does not contain any test cases yet.',
7923
+ folderColumnLabel: 'Folder',
7924
+ unorganisedRowLabel: 'Unorganised',
7925
+ noFoldersFound: 'No Folders Found',
7918
7926
  };
7919
7927
  const DEFAULT_REORDER_LABELS = {
7920
7928
  reorderButton: 'Reorder',
@@ -9502,10 +9510,10 @@ class FolderSidebarComponent {
9502
9510
  }
9503
9511
  FolderSidebarComponent.RENAME_LIMIT_FLASH_MS = 600;
9504
9512
  FolderSidebarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: FolderSidebarComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
9505
- FolderSidebarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: FolderSidebarComponent, selector: "cqa-folder-sidebar", inputs: { folders: "folders", selectedFolderId: "selectedFolderId", expandedFolderIds: "expandedFolderIds", unorganisedCount: "unorganisedCount", allowCreate: "allowCreate", allowRename: "allowRename", allowDelete: "allowDelete", allowMove: "allowMove", allowDuplicate: "allowDuplicate", allowDrop: "allowDrop", showCounts: "showCounts", collapsed: "collapsed", labels: "labels" }, outputs: { folderSelected: "folderSelected", folderExpansionToggled: "folderExpansionToggled", folderCreated: "folderCreated", folderCreateRequested: "folderCreateRequested", folderRenamed: "folderRenamed", folderDeleted: "folderDeleted", folderMoveRequested: "folderMoveRequested", folderDuplicateRequested: "folderDuplicateRequested", testsDropped: "testsDropped", folderDropped: "folderDropped", collapsedChange: "collapsedChange" }, host: { listeners: { "document:click": "onDocumentClick()", "document:keydown.escape": "onEscape()", "document:dragend": "onDocumentDragEnd()" }, classAttribute: "cqa-ui-root" }, ngImport: i0, template: "<!-- Reusable folder icon. Render via <ng-container *ngTemplateOutlet=\"folderIcon; context: { color: node.color }\"></ng-container>. -->\n<ng-template #folderIcon let-color=\"color\">\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-4 cqa-h-4 cqa-shrink-0\">\n <svg width=\"13\" height=\"12\" viewBox=\"0 0 13 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.1916 9.85824C12.1916 10.1677 12.0687 10.4644 11.8499 10.6832C11.6311 10.902 11.3343 11.0249 11.0249 11.0249H1.69157C1.38215 11.0249 1.0854 10.902 0.866611 10.6832C0.647819 10.4644 0.524902 10.1677 0.524902 9.85824V1.69157C0.524902 1.38215 0.647819 1.0854 0.866611 0.866611C1.0854 0.647819 1.38215 0.524902 1.69157 0.524902H4.60824L5.7749 2.2749H11.0249C11.3343 2.2749 11.6311 2.39782 11.8499 2.61661C12.0687 2.8354 12.1916 3.13215 12.1916 3.44157V9.85824Z\" [attr.stroke]=\"color || '#99999E'\" stroke-width=\"1.05\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n</ng-template>\n\n<aside\n class=\"cqa-flex cqa-flex-col cqa-bg-white cqa-border cqa-border-neutral-200 cqa-rounded-lg cqa-h-full cqa-min-h-0\"\n [class.cqa-w-[240px]]=\"!collapsed\"\n [class.cqa-w-[48px]]=\"collapsed\"\n style=\"transition: width 150ms ease;\"\n>\n <!-- Header -->\n <div\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-px-3 cqa-py-1\"\n [style.border-bottom]=\"collapsed ? null : '1px solid #E2E2E3'\"\n [style.margin-bottom.px]=\"collapsed ? 0 : 8\"\n >\n <span *ngIf=\"!collapsed\" class=\"cqa-text-sm cqa-font-semibold cqa-text-neutral-900\">\n {{ labels.folders }}\n </span>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\" [class.cqa-w-full]=\"collapsed\" [class.cqa-justify-center]=\"collapsed\">\n <button\n type=\"button\"\n class=\"cqa-p-1 cqa-rounded hover:cqa-bg-neutral-100 cqa-text-neutral-500\"\n (click)=\"togglePanel()\"\n [attr.aria-label]=\"collapsed ? 'Expand folders panel' : 'Collapse folders panel'\"\n >\n <mat-icon style=\"font-size:18px;width:18px;height:18px\">\n {{ collapsed ? 'chevron_right' : 'keyboard_double_arrow_left' }}\n </mat-icon>\n </button>\n <button\n *ngIf=\"!collapsed && allowCreate\"\n type=\"button\"\n class=\"cqa-p-1 cqa-rounded hover:cqa-bg-neutral-100 cqa-text-neutral-500\"\n (click)=\"requestCreate(null)\"\n [attr.aria-label]=\"labels.newFolder\"\n [title]=\"labels.newFolder\"\n >\n <mat-icon style=\"font-size:18px;width:18px;height:18px\">add</mat-icon>\n </button>\n </div>\n </div>\n\n <ng-container *ngIf=\"!collapsed\">\n <!-- Search -->\n <div class=\"cqa-px-3 cqa-pb-2\">\n <cqa-search-bar\n size=\"sm\"\n [fullWidth]=\"true\"\n [value]=\"searchValue\"\n [placeholder]=\"labels.searchFoldersPlaceholder\"\n [showClear]=\"true\"\n (valueChange)=\"searchValue = $event\"\n (cleared)=\"searchValue = ''\"\n ></cqa-search-bar>\n </div>\n\n <!-- Tree (folders only \u2014 Unorganised sits directly below; tree caps at 60vh and scrolls when overflowing) -->\n <div role=\"tree\" class=\"cqa-min-h-0 cqa-max-h-[60vh] cqa-overflow-y-auto cqa-py-1 cqa-scrollbar-thin cqa-scrollbar-track-transparent cqa-scrollbar-thumb-[#E5E7EB] cqa-scrollbar-thumb-rounded-full cqa-scrollbar-thumb-hover:cqa-bg-[#D1D5DB]\">\n <ng-container *ngFor=\"let row of rows; let i = index; trackBy: trackByRow\">\n <div\n role=\"treeitem\"\n tabindex=\"0\"\n [attr.aria-expanded]=\"row.hasChildren ? isExpanded(row.node.id) : null\"\n [attr.aria-selected]=\"isSelected(row.node.id)\"\n [attr.data-folder-row-id]=\"row.node.id\"\n [cqaFolderDrop]=\"row.node.id\"\n [dropEnabled]=\"allowDrop\"\n (testsDropped)=\"rowDropped(row.node.id, $event)\"\n (folderDropped)=\"onFolderRowDropped(row.node.id, $event)\"\n [cqaFolderDrag]=\"row.node.id\"\n [dragEnabled]=\"allowDrop\"\n (dragstart)=\"onFolderDragStart(row.node)\"\n (dragend)=\"onFolderDragEnd()\"\n (dragover)=\"onFolderRowDragOver(row)\"\n (dragleave)=\"onFolderRowDragLeave(row)\"\n (click)=\"onSelect(row.node)\"\n (contextmenu)=\"openContextMenu(row.node, $event)\"\n (keydown)=\"onRowKeydown($event, row, i)\"\n class=\"cqa-group cqa-flex cqa-items-center cqa-gap-1 cqa-pr-3 cqa-py-1.5 cqa-cursor-pointer hover:cqa-bg-indigo-50 focus:cqa-outline-none focus:cqa-bg-indigo-50 cqa-relative\"\n [class.cqa-bg-indigo-50]=\"isSelected(row.node.id) || contextMenuFolderId === row.node.id\"\n [style.paddingLeft.px]=\"8 + row.depth * 16\"\n [attr.title]=\"row.node.totalCount != null ? (row.node.totalCount + ' total including subfolders') : null\"\n >\n <span\n *ngIf=\"isSelected(row.node.id)\"\n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-bottom-0 cqa-w-[3px] cqa-bg-indigo-600\"\n ></span>\n <button\n type=\"button\"\n class=\"cqa-p-0\"\n [style.color]=\"isSelected(row.node.id) ? '#3F43EE' : '#4C4C51'\"\n [style.visibility]=\"row.hasChildren ? 'visible' : 'hidden'\"\n (click)=\"onToggle(row.node, $event)\"\n [attr.aria-label]=\"isExpanded(row.node.id) ? 'Collapse' : 'Expand'\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">\n {{ isExpanded(row.node.id) ? 'expand_more' : 'chevron_right' }}\n </mat-icon>\n </button>\n <ng-container *ngTemplateOutlet=\"folderIcon; context: { color: row.node.color }\"></ng-container>\n\n <ng-container *ngIf=\"renamingId === row.node.id; else nameTpl\">\n <input\n type=\"text\"\n size=\"1\"\n [attr.data-folder-rename-input]=\"row.node.id\"\n [attr.maxlength]=\"renameMaxLength\"\n class=\"cqa-flex-1 cqa-min-w-0 cqa-w-full cqa-px-2 cqa-py-0.5 cqa-rounded cqa-border cqa-bg-white cqa-text-sm cqa-shadow-sm focus:cqa-outline-none focus:cqa-ring-1\"\n [ngClass]=\"(isRenameDraftValid && !renameLimitFlash)\n ? 'cqa-border-neutral-300 focus:cqa-border-indigo-400 focus:cqa-ring-indigo-200'\n : 'cqa-border-[#EF4444] focus:cqa-border-[#EF4444] focus:cqa-ring-[#FCA5A5]'\"\n [attr.aria-invalid]=\"!isRenameDraftValid || renameLimitFlash\"\n [(ngModel)]=\"renameDraft\"\n (keydown)=\"onRenameKey($event, row.node)\"\n (keypress)=\"$event.stopPropagation()\"\n (keyup)=\"$event.stopPropagation()\"\n (blur)=\"commitRename(row.node)\"\n (click)=\"$event.stopPropagation()\"\n />\n </ng-container>\n <ng-template #nameTpl>\n <span\n class=\"cqa-flex-1 cqa-text-sm cqa-truncate\"\n [style.color]=\"isSelected(row.node.id) ? '#3F43EE' : '#4C4C51'\"\n (dblclick)=\"beginRename(row.node, $event)\"\n >{{ row.node.name }}</span>\n </ng-template>\n\n <!-- Count shown at rest; hidden on row hover when delete is allowed -->\n <span\n *ngIf=\"showCounts && row.node.count != null\"\n class=\"cqa-text-xs cqa-tabular-nums cqa-ml-1\"\n [style.color]=\"isSelected(row.node.id) ? '#3F43EE' : '#4C4C51'\"\n [class.group-hover:cqa-hidden]=\"allowDelete\"\n >{{ row.node.count }}</span>\n\n <button\n *ngIf=\"hasAnyContextAction\"\n type=\"button\"\n class=\"cqa-p-0.5 cqa-rounded hover:cqa-bg-neutral-200\"\n [style.color]=\"isSelected(row.node.id) || contextMenuFolderId === row.node.id ? '#3F43EE' : '#4C4C51'\"\n [class.cqa-hidden]=\"contextMenuFolderId !== row.node.id\"\n [class.group-hover:cqa-inline-flex]=\"true\"\n [class.cqa-inline-flex]=\"contextMenuFolderId === row.node.id\"\n (click)=\"openContextMenu(row.node, $event)\"\n [attr.aria-label]=\"'Open actions for ' + row.node.name\"\n [attr.aria-haspopup]=\"'menu'\"\n [attr.aria-expanded]=\"contextMenuFolderId === row.node.id\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">more_horiz</mat-icon>\n </button>\n </div>\n </ng-container>\n </div>\n\n <!-- Divider between folder tree and pinned Unorganised tab -->\n <div\n aria-hidden=\"true\"\n class=\"cqa-mx-3 cqa-shrink-0\"\n style=\"height: 1px; background-color: #E5E7EB; margin-top: 6px; margin-bottom: 6px;\"\n ></div>\n\n <!-- Unorganised \u2014 pinned below the scrollable folder tree so it stays visible regardless of folder count -->\n <div\n role=\"treeitem\"\n tabindex=\"0\"\n [attr.aria-selected]=\"isSelected(null)\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-1.5 cqa-cursor-pointer hover:cqa-bg-indigo-50 focus:cqa-outline-none focus:cqa-bg-indigo-50 cqa-relative cqa-shrink-0\"\n [class.cqa-bg-indigo-50]=\"isSelected(null)\"\n [cqaFolderDrop]=\"null\"\n [dropEnabled]=\"allowDrop\"\n (testsDropped)=\"rowDropped(null, $event)\"\n (folderDropped)=\"onFolderRowDropped(null, $event)\"\n (click)=\"onSelectUnorganised()\"\n >\n <span\n *ngIf=\"isSelected(null)\"\n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-bottom-0 cqa-w-[3px] cqa-bg-indigo-600\"\n ></span>\n <mat-icon [style.color]=\"isSelected(null) ? '#3F43EE' : '#4C4C51'\" style=\"font-size:16px;width:16px;height:16px\">inbox</mat-icon>\n <span class=\"cqa-flex-1 cqa-text-sm\" [style.color]=\"isSelected(null) ? '#3F43EE' : '#4C4C51'\">{{ labels.unorganised }}</span>\n <span *ngIf=\"showCounts\" class=\"cqa-text-xs cqa-tabular-nums\" [style.color]=\"isSelected(null) ? '#3F43EE' : '#4C4C51'\">{{ unorganisedCount }}</span>\n </div>\n\n <!-- Folder context menu (right-click / ellipsis). A 0\u00D70 fixed-position\n anchor at the click coords drives a cdkConnectedOverlay; CDK's\n flexible-connected positioning auto-flips up/left when the menu\n would overflow the viewport (last-folder-near-bottom case). -->\n <div #ctxAnchor cdkOverlayOrigin\n class=\"cqa-fixed cqa-w-0 cqa-h-0 cqa-pointer-events-none\"\n [style.left.px]=\"contextMenuPosition.x\"\n [style.top.px]=\"contextMenuPosition.y\"></div>\n\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"ctxAnchor\"\n [cdkConnectedOverlayOpen]=\"contextMenuFolderId !== null\"\n [cdkConnectedOverlayPositions]=\"contextMenuPositions\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\n [cdkConnectedOverlayPush]=\"true\"\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\n (detach)=\"closeContextMenu()\"\n >\n <!-- The lib's tailwind config sets important: '.cqa-ui-root', which\n emits descendant selectors like `.cqa-ui-root .cqa-bg-white`.\n CDK Overlay teleports this template into the global overlay\n container (outside the host's cqa-ui-root), so we wrap the menu in\n an ancestor cqa-ui-root div to re-establish the utility scope. -->\n <div class=\"cqa-ui-root\">\n <div\n role=\"menu\"\n class=\"cqa-min-w-[180px] cqa-bg-white cqa-border cqa-border-neutral-200 cqa-rounded-md cqa-shadow-lg cqa-py-1\"\n (click)=\"$event.stopPropagation()\"\n (contextmenu)=\"$event.preventDefault(); $event.stopPropagation()\"\n >\n <ng-container *ngIf=\"folderById(contextMenuFolderId) as menuNode\">\n <button\n *ngIf=\"allowCreate\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextCreateSubfolder(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">create_new_folder</mat-icon>\n <span>{{ labels.folderMenuCreateSubfolder }}</span>\n </button>\n <button\n *ngIf=\"allowRename\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextRename(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">edit</mat-icon>\n <span>{{ labels.folderMenuRename }}</span>\n </button>\n <button\n *ngIf=\"allowMove\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextMove(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">drive_file_move</mat-icon>\n <span>{{ labels.folderMenuMove }}</span>\n </button>\n <button\n *ngIf=\"allowDuplicate\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextDuplicate(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">content_copy</mat-icon>\n <span>{{ labels.folderMenuDuplicate }}</span>\n </button>\n <div *ngIf=\"allowDelete && (allowCreate || allowRename || allowMove || allowDuplicate)\" class=\"cqa-h-px cqa-bg-neutral-200 cqa-my-1\"></div>\n <button\n *ngIf=\"allowDelete\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-red-600 hover:cqa-bg-red-50 cqa-text-left\"\n (click)=\"onContextDelete(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">delete_outline</mat-icon>\n <span>{{ labels.folderMenuDelete }}</span>\n </button>\n </ng-container>\n </div>\n </div>\n </ng-template>\n\n </ng-container>\n</aside>\n", components: [{ type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: SearchBarComponent, selector: "cqa-search-bar", inputs: ["placeholder", "value", "disabled", "showClear", "ariaLabel", "autoFocus", "size", "fullWidth"], outputs: ["valueChange", "search", "cleared"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: FolderDropDirective, selector: "[cqaFolderDrop]", inputs: ["cqaFolderDrop", "dropEnabled"], outputs: ["testsDropped", "folderDropped"] }, { type: FolderDragDirective, selector: "[cqaFolderDrag]", inputs: ["cqaFolderDrag", "dragEnabled"] }, { type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i1$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i1$6.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { type: i1$6.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
9513
+ FolderSidebarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: FolderSidebarComponent, selector: "cqa-folder-sidebar", inputs: { folders: "folders", selectedFolderId: "selectedFolderId", expandedFolderIds: "expandedFolderIds", unorganisedCount: "unorganisedCount", allowCreate: "allowCreate", allowRename: "allowRename", allowDelete: "allowDelete", allowMove: "allowMove", allowDuplicate: "allowDuplicate", allowDrop: "allowDrop", showCounts: "showCounts", collapsed: "collapsed", labels: "labels" }, outputs: { folderSelected: "folderSelected", folderExpansionToggled: "folderExpansionToggled", folderCreated: "folderCreated", folderCreateRequested: "folderCreateRequested", folderRenamed: "folderRenamed", folderDeleted: "folderDeleted", folderMoveRequested: "folderMoveRequested", folderDuplicateRequested: "folderDuplicateRequested", testsDropped: "testsDropped", folderDropped: "folderDropped", collapsedChange: "collapsedChange" }, host: { listeners: { "document:click": "onDocumentClick()", "document:keydown.escape": "onEscape()", "document:dragend": "onDocumentDragEnd()" }, classAttribute: "cqa-ui-root" }, ngImport: i0, template: "<!-- Reusable folder icon. Render via <ng-container *ngTemplateOutlet=\"folderIcon; context: { color: node.color }\"></ng-container>. -->\n<ng-template #folderIcon let-color=\"color\">\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-4 cqa-h-4 cqa-shrink-0\">\n <svg width=\"13\" height=\"12\" viewBox=\"0 0 13 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.1916 9.85824C12.1916 10.1677 12.0687 10.4644 11.8499 10.6832C11.6311 10.902 11.3343 11.0249 11.0249 11.0249H1.69157C1.38215 11.0249 1.0854 10.902 0.866611 10.6832C0.647819 10.4644 0.524902 10.1677 0.524902 9.85824V1.69157C0.524902 1.38215 0.647819 1.0854 0.866611 0.866611C1.0854 0.647819 1.38215 0.524902 1.69157 0.524902H4.60824L5.7749 2.2749H11.0249C11.3343 2.2749 11.6311 2.39782 11.8499 2.61661C12.0687 2.8354 12.1916 3.13215 12.1916 3.44157V9.85824Z\" [attr.stroke]=\"color || '#99999E'\" stroke-width=\"1.05\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n</ng-template>\n\n<aside\n class=\"cqa-flex cqa-flex-col cqa-bg-white cqa-border cqa-border-neutral-200 cqa-rounded-lg cqa-h-full cqa-min-h-0\"\n [class.cqa-w-[240px]]=\"!collapsed\"\n [class.cqa-w-[48px]]=\"collapsed\"\n style=\"transition: width 150ms ease;\"\n>\n <!-- Header -->\n <div\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-px-3 cqa-py-1\"\n [style.border-bottom]=\"collapsed ? null : '1px solid #E2E2E3'\"\n [style.margin-bottom.px]=\"collapsed ? 0 : 8\"\n >\n <span *ngIf=\"!collapsed\" class=\"cqa-text-sm cqa-font-semibold cqa-text-neutral-900\">\n {{ labels.folders }}\n </span>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\" [class.cqa-w-full]=\"collapsed\" [class.cqa-justify-center]=\"collapsed\">\n <button\n type=\"button\"\n class=\"cqa-p-1 cqa-rounded hover:cqa-bg-neutral-100 cqa-text-neutral-500\"\n (click)=\"togglePanel()\"\n [attr.aria-label]=\"collapsed ? 'Expand folders panel' : 'Collapse folders panel'\"\n >\n <mat-icon style=\"font-size:18px;width:18px;height:18px\">\n {{ collapsed ? 'chevron_right' : 'keyboard_double_arrow_left' }}\n </mat-icon>\n </button>\n <button\n *ngIf=\"!collapsed && allowCreate\"\n type=\"button\"\n class=\"cqa-p-1 cqa-rounded hover:cqa-bg-neutral-100 cqa-text-neutral-500\"\n (click)=\"requestCreate(null)\"\n [attr.aria-label]=\"labels.newFolder\"\n [title]=\"labels.newFolder\"\n >\n <mat-icon style=\"font-size:18px;width:18px;height:18px\">add</mat-icon>\n </button>\n </div>\n </div>\n\n <ng-container *ngIf=\"!collapsed\">\n <!-- Search -->\n <div class=\"cqa-px-3 cqa-pb-2\">\n <cqa-search-bar\n size=\"sm\"\n [fullWidth]=\"true\"\n [value]=\"searchValue\"\n [placeholder]=\"labels.searchFoldersPlaceholder\"\n [showClear]=\"true\"\n (valueChange)=\"searchValue = $event\"\n (cleared)=\"searchValue = ''\"\n ></cqa-search-bar>\n </div>\n\n <!-- Tree (folders only \u2014 Unorganised sits directly below; tree caps at 60vh and scrolls when overflowing) -->\n <div role=\"tree\" class=\"cqa-min-h-0 cqa-max-h-[60vh] cqa-overflow-y-auto cqa-py-1 cqa-scrollbar-thin cqa-scrollbar-track-transparent cqa-scrollbar-thumb-[#E5E7EB] cqa-scrollbar-thumb-rounded-full cqa-scrollbar-thumb-hover:cqa-bg-[#D1D5DB]\">\n <div\n *ngIf=\"searchValue?.trim() && rows.length === 0\"\n class=\"cqa-px-3 cqa-py-2 cqa-text-sm cqa-text-neutral-500 cqa-text-center\"\n >\n {{ labels.noFoldersFound }}\n </div>\n <ng-container *ngFor=\"let row of rows; let i = index; trackBy: trackByRow\">\n <div\n role=\"treeitem\"\n tabindex=\"0\"\n [attr.aria-expanded]=\"row.hasChildren ? isExpanded(row.node.id) : null\"\n [attr.aria-selected]=\"isSelected(row.node.id)\"\n [attr.data-folder-row-id]=\"row.node.id\"\n [cqaFolderDrop]=\"row.node.id\"\n [dropEnabled]=\"allowDrop\"\n (testsDropped)=\"rowDropped(row.node.id, $event)\"\n (folderDropped)=\"onFolderRowDropped(row.node.id, $event)\"\n [cqaFolderDrag]=\"row.node.id\"\n [dragEnabled]=\"allowDrop\"\n (dragstart)=\"onFolderDragStart(row.node)\"\n (dragend)=\"onFolderDragEnd()\"\n (dragover)=\"onFolderRowDragOver(row)\"\n (dragleave)=\"onFolderRowDragLeave(row)\"\n (click)=\"onSelect(row.node)\"\n (contextmenu)=\"openContextMenu(row.node, $event)\"\n (keydown)=\"onRowKeydown($event, row, i)\"\n class=\"cqa-group cqa-flex cqa-items-center cqa-gap-1 cqa-pr-3 cqa-py-1.5 cqa-cursor-pointer hover:cqa-bg-indigo-50 focus:cqa-outline-none focus:cqa-bg-indigo-50 cqa-relative\"\n [class.cqa-bg-indigo-50]=\"isSelected(row.node.id) || contextMenuFolderId === row.node.id\"\n [style.paddingLeft.px]=\"8 + row.depth * 16\"\n [attr.title]=\"row.node.totalCount != null ? (row.node.totalCount + ' total including subfolders') : null\"\n >\n <span\n *ngIf=\"isSelected(row.node.id)\"\n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-bottom-0 cqa-w-[3px] cqa-bg-indigo-600\"\n ></span>\n <button\n type=\"button\"\n class=\"cqa-p-0\"\n [style.color]=\"isSelected(row.node.id) ? '#3F43EE' : '#4C4C51'\"\n [style.visibility]=\"row.hasChildren ? 'visible' : 'hidden'\"\n (click)=\"onToggle(row.node, $event)\"\n [attr.aria-label]=\"isExpanded(row.node.id) ? 'Collapse' : 'Expand'\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">\n {{ isExpanded(row.node.id) ? 'expand_more' : 'chevron_right' }}\n </mat-icon>\n </button>\n <ng-container *ngTemplateOutlet=\"folderIcon; context: { color: row.node.color }\"></ng-container>\n\n <ng-container *ngIf=\"renamingId === row.node.id; else nameTpl\">\n <input\n type=\"text\"\n size=\"1\"\n [attr.data-folder-rename-input]=\"row.node.id\"\n [attr.maxlength]=\"renameMaxLength\"\n class=\"cqa-flex-1 cqa-min-w-0 cqa-w-full cqa-px-2 cqa-py-0.5 cqa-rounded cqa-border cqa-bg-white cqa-text-sm cqa-shadow-sm focus:cqa-outline-none focus:cqa-ring-1\"\n [ngClass]=\"(isRenameDraftValid && !renameLimitFlash)\n ? 'cqa-border-neutral-300 focus:cqa-border-indigo-400 focus:cqa-ring-indigo-200'\n : 'cqa-border-[#EF4444] focus:cqa-border-[#EF4444] focus:cqa-ring-[#FCA5A5]'\"\n [attr.aria-invalid]=\"!isRenameDraftValid || renameLimitFlash\"\n [(ngModel)]=\"renameDraft\"\n (keydown)=\"onRenameKey($event, row.node)\"\n (keypress)=\"$event.stopPropagation()\"\n (keyup)=\"$event.stopPropagation()\"\n (blur)=\"commitRename(row.node)\"\n (click)=\"$event.stopPropagation()\"\n />\n </ng-container>\n <ng-template #nameTpl>\n <span\n class=\"cqa-flex-1 cqa-text-sm cqa-truncate\"\n [style.color]=\"isSelected(row.node.id) ? '#3F43EE' : '#4C4C51'\"\n (dblclick)=\"beginRename(row.node, $event)\"\n >{{ row.node.name }}</span>\n </ng-template>\n\n <!-- Count shown at rest; hidden on row hover when delete is allowed -->\n <span\n *ngIf=\"showCounts && row.node.count != null\"\n class=\"cqa-text-xs cqa-tabular-nums cqa-ml-1\"\n [style.color]=\"isSelected(row.node.id) ? '#3F43EE' : '#4C4C51'\"\n [class.group-hover:cqa-hidden]=\"allowDelete\"\n >{{ row.node.count }}</span>\n\n <button\n *ngIf=\"hasAnyContextAction\"\n type=\"button\"\n class=\"cqa-p-0.5 cqa-rounded hover:cqa-bg-neutral-200\"\n [style.color]=\"isSelected(row.node.id) || contextMenuFolderId === row.node.id ? '#3F43EE' : '#4C4C51'\"\n [class.cqa-hidden]=\"contextMenuFolderId !== row.node.id\"\n [class.group-hover:cqa-inline-flex]=\"true\"\n [class.cqa-inline-flex]=\"contextMenuFolderId === row.node.id\"\n (click)=\"openContextMenu(row.node, $event)\"\n [attr.aria-label]=\"'Open actions for ' + row.node.name\"\n [attr.aria-haspopup]=\"'menu'\"\n [attr.aria-expanded]=\"contextMenuFolderId === row.node.id\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">more_horiz</mat-icon>\n </button>\n </div>\n </ng-container>\n </div>\n\n <!-- Divider between folder tree and pinned Unorganised tab -->\n <div\n aria-hidden=\"true\"\n class=\"cqa-mx-3 cqa-shrink-0\"\n style=\"height: 1px; background-color: #E5E7EB; margin-top: 6px; margin-bottom: 6px;\"\n ></div>\n\n <!-- Unorganised \u2014 pinned below the scrollable folder tree so it stays visible regardless of folder count -->\n <div\n role=\"treeitem\"\n tabindex=\"0\"\n [attr.aria-selected]=\"isSelected(null)\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-1.5 cqa-cursor-pointer hover:cqa-bg-indigo-50 focus:cqa-outline-none focus:cqa-bg-indigo-50 cqa-relative cqa-shrink-0\"\n [class.cqa-bg-indigo-50]=\"isSelected(null)\"\n [cqaFolderDrop]=\"null\"\n [dropEnabled]=\"allowDrop\"\n (testsDropped)=\"rowDropped(null, $event)\"\n (folderDropped)=\"onFolderRowDropped(null, $event)\"\n (click)=\"onSelectUnorganised()\"\n >\n <span\n *ngIf=\"isSelected(null)\"\n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-bottom-0 cqa-w-[3px] cqa-bg-indigo-600\"\n ></span>\n <mat-icon [style.color]=\"isSelected(null) ? '#3F43EE' : '#4C4C51'\" style=\"font-size:16px;width:16px;height:16px\">inbox</mat-icon>\n <span class=\"cqa-flex-1 cqa-text-sm\" [style.color]=\"isSelected(null) ? '#3F43EE' : '#4C4C51'\">{{ labels.unorganised }}</span>\n <span *ngIf=\"showCounts\" class=\"cqa-text-xs cqa-tabular-nums\" [style.color]=\"isSelected(null) ? '#3F43EE' : '#4C4C51'\">{{ unorganisedCount }}</span>\n </div>\n\n <!-- Folder context menu (right-click / ellipsis). A 0\u00D70 fixed-position\n anchor at the click coords drives a cdkConnectedOverlay; CDK's\n flexible-connected positioning auto-flips up/left when the menu\n would overflow the viewport (last-folder-near-bottom case). -->\n <div #ctxAnchor cdkOverlayOrigin\n class=\"cqa-fixed cqa-w-0 cqa-h-0 cqa-pointer-events-none\"\n [style.left.px]=\"contextMenuPosition.x\"\n [style.top.px]=\"contextMenuPosition.y\"></div>\n\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"ctxAnchor\"\n [cdkConnectedOverlayOpen]=\"contextMenuFolderId !== null\"\n [cdkConnectedOverlayPositions]=\"contextMenuPositions\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\n [cdkConnectedOverlayPush]=\"true\"\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\n (detach)=\"closeContextMenu()\"\n >\n <!-- The lib's tailwind config sets important: '.cqa-ui-root', which\n emits descendant selectors like `.cqa-ui-root .cqa-bg-white`.\n CDK Overlay teleports this template into the global overlay\n container (outside the host's cqa-ui-root), so we wrap the menu in\n an ancestor cqa-ui-root div to re-establish the utility scope. -->\n <div class=\"cqa-ui-root\">\n <div\n role=\"menu\"\n class=\"cqa-min-w-[180px] cqa-bg-white cqa-border cqa-border-neutral-200 cqa-rounded-md cqa-shadow-lg cqa-py-1\"\n (click)=\"$event.stopPropagation()\"\n (contextmenu)=\"$event.preventDefault(); $event.stopPropagation()\"\n >\n <ng-container *ngIf=\"folderById(contextMenuFolderId) as menuNode\">\n <button\n *ngIf=\"allowCreate\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextCreateSubfolder(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">create_new_folder</mat-icon>\n <span>{{ labels.folderMenuCreateSubfolder }}</span>\n </button>\n <button\n *ngIf=\"allowRename\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextRename(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">edit</mat-icon>\n <span>{{ labels.folderMenuRename }}</span>\n </button>\n <button\n *ngIf=\"allowMove\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextMove(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">drive_file_move</mat-icon>\n <span>{{ labels.folderMenuMove }}</span>\n </button>\n <button\n *ngIf=\"allowDuplicate\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextDuplicate(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">content_copy</mat-icon>\n <span>{{ labels.folderMenuDuplicate }}</span>\n </button>\n <div *ngIf=\"allowDelete && (allowCreate || allowRename || allowMove || allowDuplicate)\" class=\"cqa-h-px cqa-bg-neutral-200 cqa-my-1\"></div>\n <button\n *ngIf=\"allowDelete\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-red-600 hover:cqa-bg-red-50 cqa-text-left\"\n (click)=\"onContextDelete(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">delete_outline</mat-icon>\n <span>{{ labels.folderMenuDelete }}</span>\n </button>\n </ng-container>\n </div>\n </div>\n </ng-template>\n\n </ng-container>\n</aside>\n", components: [{ type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: SearchBarComponent, selector: "cqa-search-bar", inputs: ["placeholder", "value", "disabled", "showClear", "ariaLabel", "autoFocus", "size", "fullWidth"], outputs: ["valueChange", "search", "cleared"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: FolderDropDirective, selector: "[cqaFolderDrop]", inputs: ["cqaFolderDrop", "dropEnabled"], outputs: ["testsDropped", "folderDropped"] }, { type: FolderDragDirective, selector: "[cqaFolderDrag]", inputs: ["cqaFolderDrag", "dragEnabled"] }, { type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i1$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i1$6.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { type: i1$6.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
9506
9514
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: FolderSidebarComponent, decorators: [{
9507
9515
  type: Component,
9508
- args: [{ selector: 'cqa-folder-sidebar', host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Reusable folder icon. Render via <ng-container *ngTemplateOutlet=\"folderIcon; context: { color: node.color }\"></ng-container>. -->\n<ng-template #folderIcon let-color=\"color\">\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-4 cqa-h-4 cqa-shrink-0\">\n <svg width=\"13\" height=\"12\" viewBox=\"0 0 13 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.1916 9.85824C12.1916 10.1677 12.0687 10.4644 11.8499 10.6832C11.6311 10.902 11.3343 11.0249 11.0249 11.0249H1.69157C1.38215 11.0249 1.0854 10.902 0.866611 10.6832C0.647819 10.4644 0.524902 10.1677 0.524902 9.85824V1.69157C0.524902 1.38215 0.647819 1.0854 0.866611 0.866611C1.0854 0.647819 1.38215 0.524902 1.69157 0.524902H4.60824L5.7749 2.2749H11.0249C11.3343 2.2749 11.6311 2.39782 11.8499 2.61661C12.0687 2.8354 12.1916 3.13215 12.1916 3.44157V9.85824Z\" [attr.stroke]=\"color || '#99999E'\" stroke-width=\"1.05\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n</ng-template>\n\n<aside\n class=\"cqa-flex cqa-flex-col cqa-bg-white cqa-border cqa-border-neutral-200 cqa-rounded-lg cqa-h-full cqa-min-h-0\"\n [class.cqa-w-[240px]]=\"!collapsed\"\n [class.cqa-w-[48px]]=\"collapsed\"\n style=\"transition: width 150ms ease;\"\n>\n <!-- Header -->\n <div\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-px-3 cqa-py-1\"\n [style.border-bottom]=\"collapsed ? null : '1px solid #E2E2E3'\"\n [style.margin-bottom.px]=\"collapsed ? 0 : 8\"\n >\n <span *ngIf=\"!collapsed\" class=\"cqa-text-sm cqa-font-semibold cqa-text-neutral-900\">\n {{ labels.folders }}\n </span>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\" [class.cqa-w-full]=\"collapsed\" [class.cqa-justify-center]=\"collapsed\">\n <button\n type=\"button\"\n class=\"cqa-p-1 cqa-rounded hover:cqa-bg-neutral-100 cqa-text-neutral-500\"\n (click)=\"togglePanel()\"\n [attr.aria-label]=\"collapsed ? 'Expand folders panel' : 'Collapse folders panel'\"\n >\n <mat-icon style=\"font-size:18px;width:18px;height:18px\">\n {{ collapsed ? 'chevron_right' : 'keyboard_double_arrow_left' }}\n </mat-icon>\n </button>\n <button\n *ngIf=\"!collapsed && allowCreate\"\n type=\"button\"\n class=\"cqa-p-1 cqa-rounded hover:cqa-bg-neutral-100 cqa-text-neutral-500\"\n (click)=\"requestCreate(null)\"\n [attr.aria-label]=\"labels.newFolder\"\n [title]=\"labels.newFolder\"\n >\n <mat-icon style=\"font-size:18px;width:18px;height:18px\">add</mat-icon>\n </button>\n </div>\n </div>\n\n <ng-container *ngIf=\"!collapsed\">\n <!-- Search -->\n <div class=\"cqa-px-3 cqa-pb-2\">\n <cqa-search-bar\n size=\"sm\"\n [fullWidth]=\"true\"\n [value]=\"searchValue\"\n [placeholder]=\"labels.searchFoldersPlaceholder\"\n [showClear]=\"true\"\n (valueChange)=\"searchValue = $event\"\n (cleared)=\"searchValue = ''\"\n ></cqa-search-bar>\n </div>\n\n <!-- Tree (folders only \u2014 Unorganised sits directly below; tree caps at 60vh and scrolls when overflowing) -->\n <div role=\"tree\" class=\"cqa-min-h-0 cqa-max-h-[60vh] cqa-overflow-y-auto cqa-py-1 cqa-scrollbar-thin cqa-scrollbar-track-transparent cqa-scrollbar-thumb-[#E5E7EB] cqa-scrollbar-thumb-rounded-full cqa-scrollbar-thumb-hover:cqa-bg-[#D1D5DB]\">\n <ng-container *ngFor=\"let row of rows; let i = index; trackBy: trackByRow\">\n <div\n role=\"treeitem\"\n tabindex=\"0\"\n [attr.aria-expanded]=\"row.hasChildren ? isExpanded(row.node.id) : null\"\n [attr.aria-selected]=\"isSelected(row.node.id)\"\n [attr.data-folder-row-id]=\"row.node.id\"\n [cqaFolderDrop]=\"row.node.id\"\n [dropEnabled]=\"allowDrop\"\n (testsDropped)=\"rowDropped(row.node.id, $event)\"\n (folderDropped)=\"onFolderRowDropped(row.node.id, $event)\"\n [cqaFolderDrag]=\"row.node.id\"\n [dragEnabled]=\"allowDrop\"\n (dragstart)=\"onFolderDragStart(row.node)\"\n (dragend)=\"onFolderDragEnd()\"\n (dragover)=\"onFolderRowDragOver(row)\"\n (dragleave)=\"onFolderRowDragLeave(row)\"\n (click)=\"onSelect(row.node)\"\n (contextmenu)=\"openContextMenu(row.node, $event)\"\n (keydown)=\"onRowKeydown($event, row, i)\"\n class=\"cqa-group cqa-flex cqa-items-center cqa-gap-1 cqa-pr-3 cqa-py-1.5 cqa-cursor-pointer hover:cqa-bg-indigo-50 focus:cqa-outline-none focus:cqa-bg-indigo-50 cqa-relative\"\n [class.cqa-bg-indigo-50]=\"isSelected(row.node.id) || contextMenuFolderId === row.node.id\"\n [style.paddingLeft.px]=\"8 + row.depth * 16\"\n [attr.title]=\"row.node.totalCount != null ? (row.node.totalCount + ' total including subfolders') : null\"\n >\n <span\n *ngIf=\"isSelected(row.node.id)\"\n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-bottom-0 cqa-w-[3px] cqa-bg-indigo-600\"\n ></span>\n <button\n type=\"button\"\n class=\"cqa-p-0\"\n [style.color]=\"isSelected(row.node.id) ? '#3F43EE' : '#4C4C51'\"\n [style.visibility]=\"row.hasChildren ? 'visible' : 'hidden'\"\n (click)=\"onToggle(row.node, $event)\"\n [attr.aria-label]=\"isExpanded(row.node.id) ? 'Collapse' : 'Expand'\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">\n {{ isExpanded(row.node.id) ? 'expand_more' : 'chevron_right' }}\n </mat-icon>\n </button>\n <ng-container *ngTemplateOutlet=\"folderIcon; context: { color: row.node.color }\"></ng-container>\n\n <ng-container *ngIf=\"renamingId === row.node.id; else nameTpl\">\n <input\n type=\"text\"\n size=\"1\"\n [attr.data-folder-rename-input]=\"row.node.id\"\n [attr.maxlength]=\"renameMaxLength\"\n class=\"cqa-flex-1 cqa-min-w-0 cqa-w-full cqa-px-2 cqa-py-0.5 cqa-rounded cqa-border cqa-bg-white cqa-text-sm cqa-shadow-sm focus:cqa-outline-none focus:cqa-ring-1\"\n [ngClass]=\"(isRenameDraftValid && !renameLimitFlash)\n ? 'cqa-border-neutral-300 focus:cqa-border-indigo-400 focus:cqa-ring-indigo-200'\n : 'cqa-border-[#EF4444] focus:cqa-border-[#EF4444] focus:cqa-ring-[#FCA5A5]'\"\n [attr.aria-invalid]=\"!isRenameDraftValid || renameLimitFlash\"\n [(ngModel)]=\"renameDraft\"\n (keydown)=\"onRenameKey($event, row.node)\"\n (keypress)=\"$event.stopPropagation()\"\n (keyup)=\"$event.stopPropagation()\"\n (blur)=\"commitRename(row.node)\"\n (click)=\"$event.stopPropagation()\"\n />\n </ng-container>\n <ng-template #nameTpl>\n <span\n class=\"cqa-flex-1 cqa-text-sm cqa-truncate\"\n [style.color]=\"isSelected(row.node.id) ? '#3F43EE' : '#4C4C51'\"\n (dblclick)=\"beginRename(row.node, $event)\"\n >{{ row.node.name }}</span>\n </ng-template>\n\n <!-- Count shown at rest; hidden on row hover when delete is allowed -->\n <span\n *ngIf=\"showCounts && row.node.count != null\"\n class=\"cqa-text-xs cqa-tabular-nums cqa-ml-1\"\n [style.color]=\"isSelected(row.node.id) ? '#3F43EE' : '#4C4C51'\"\n [class.group-hover:cqa-hidden]=\"allowDelete\"\n >{{ row.node.count }}</span>\n\n <button\n *ngIf=\"hasAnyContextAction\"\n type=\"button\"\n class=\"cqa-p-0.5 cqa-rounded hover:cqa-bg-neutral-200\"\n [style.color]=\"isSelected(row.node.id) || contextMenuFolderId === row.node.id ? '#3F43EE' : '#4C4C51'\"\n [class.cqa-hidden]=\"contextMenuFolderId !== row.node.id\"\n [class.group-hover:cqa-inline-flex]=\"true\"\n [class.cqa-inline-flex]=\"contextMenuFolderId === row.node.id\"\n (click)=\"openContextMenu(row.node, $event)\"\n [attr.aria-label]=\"'Open actions for ' + row.node.name\"\n [attr.aria-haspopup]=\"'menu'\"\n [attr.aria-expanded]=\"contextMenuFolderId === row.node.id\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">more_horiz</mat-icon>\n </button>\n </div>\n </ng-container>\n </div>\n\n <!-- Divider between folder tree and pinned Unorganised tab -->\n <div\n aria-hidden=\"true\"\n class=\"cqa-mx-3 cqa-shrink-0\"\n style=\"height: 1px; background-color: #E5E7EB; margin-top: 6px; margin-bottom: 6px;\"\n ></div>\n\n <!-- Unorganised \u2014 pinned below the scrollable folder tree so it stays visible regardless of folder count -->\n <div\n role=\"treeitem\"\n tabindex=\"0\"\n [attr.aria-selected]=\"isSelected(null)\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-1.5 cqa-cursor-pointer hover:cqa-bg-indigo-50 focus:cqa-outline-none focus:cqa-bg-indigo-50 cqa-relative cqa-shrink-0\"\n [class.cqa-bg-indigo-50]=\"isSelected(null)\"\n [cqaFolderDrop]=\"null\"\n [dropEnabled]=\"allowDrop\"\n (testsDropped)=\"rowDropped(null, $event)\"\n (folderDropped)=\"onFolderRowDropped(null, $event)\"\n (click)=\"onSelectUnorganised()\"\n >\n <span\n *ngIf=\"isSelected(null)\"\n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-bottom-0 cqa-w-[3px] cqa-bg-indigo-600\"\n ></span>\n <mat-icon [style.color]=\"isSelected(null) ? '#3F43EE' : '#4C4C51'\" style=\"font-size:16px;width:16px;height:16px\">inbox</mat-icon>\n <span class=\"cqa-flex-1 cqa-text-sm\" [style.color]=\"isSelected(null) ? '#3F43EE' : '#4C4C51'\">{{ labels.unorganised }}</span>\n <span *ngIf=\"showCounts\" class=\"cqa-text-xs cqa-tabular-nums\" [style.color]=\"isSelected(null) ? '#3F43EE' : '#4C4C51'\">{{ unorganisedCount }}</span>\n </div>\n\n <!-- Folder context menu (right-click / ellipsis). A 0\u00D70 fixed-position\n anchor at the click coords drives a cdkConnectedOverlay; CDK's\n flexible-connected positioning auto-flips up/left when the menu\n would overflow the viewport (last-folder-near-bottom case). -->\n <div #ctxAnchor cdkOverlayOrigin\n class=\"cqa-fixed cqa-w-0 cqa-h-0 cqa-pointer-events-none\"\n [style.left.px]=\"contextMenuPosition.x\"\n [style.top.px]=\"contextMenuPosition.y\"></div>\n\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"ctxAnchor\"\n [cdkConnectedOverlayOpen]=\"contextMenuFolderId !== null\"\n [cdkConnectedOverlayPositions]=\"contextMenuPositions\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\n [cdkConnectedOverlayPush]=\"true\"\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\n (detach)=\"closeContextMenu()\"\n >\n <!-- The lib's tailwind config sets important: '.cqa-ui-root', which\n emits descendant selectors like `.cqa-ui-root .cqa-bg-white`.\n CDK Overlay teleports this template into the global overlay\n container (outside the host's cqa-ui-root), so we wrap the menu in\n an ancestor cqa-ui-root div to re-establish the utility scope. -->\n <div class=\"cqa-ui-root\">\n <div\n role=\"menu\"\n class=\"cqa-min-w-[180px] cqa-bg-white cqa-border cqa-border-neutral-200 cqa-rounded-md cqa-shadow-lg cqa-py-1\"\n (click)=\"$event.stopPropagation()\"\n (contextmenu)=\"$event.preventDefault(); $event.stopPropagation()\"\n >\n <ng-container *ngIf=\"folderById(contextMenuFolderId) as menuNode\">\n <button\n *ngIf=\"allowCreate\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextCreateSubfolder(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">create_new_folder</mat-icon>\n <span>{{ labels.folderMenuCreateSubfolder }}</span>\n </button>\n <button\n *ngIf=\"allowRename\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextRename(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">edit</mat-icon>\n <span>{{ labels.folderMenuRename }}</span>\n </button>\n <button\n *ngIf=\"allowMove\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextMove(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">drive_file_move</mat-icon>\n <span>{{ labels.folderMenuMove }}</span>\n </button>\n <button\n *ngIf=\"allowDuplicate\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextDuplicate(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">content_copy</mat-icon>\n <span>{{ labels.folderMenuDuplicate }}</span>\n </button>\n <div *ngIf=\"allowDelete && (allowCreate || allowRename || allowMove || allowDuplicate)\" class=\"cqa-h-px cqa-bg-neutral-200 cqa-my-1\"></div>\n <button\n *ngIf=\"allowDelete\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-red-600 hover:cqa-bg-red-50 cqa-text-left\"\n (click)=\"onContextDelete(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">delete_outline</mat-icon>\n <span>{{ labels.folderMenuDelete }}</span>\n </button>\n </ng-container>\n </div>\n </div>\n </ng-template>\n\n </ng-container>\n</aside>\n", styles: [] }]
9516
+ args: [{ selector: 'cqa-folder-sidebar', host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Reusable folder icon. Render via <ng-container *ngTemplateOutlet=\"folderIcon; context: { color: node.color }\"></ng-container>. -->\n<ng-template #folderIcon let-color=\"color\">\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-4 cqa-h-4 cqa-shrink-0\">\n <svg width=\"13\" height=\"12\" viewBox=\"0 0 13 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.1916 9.85824C12.1916 10.1677 12.0687 10.4644 11.8499 10.6832C11.6311 10.902 11.3343 11.0249 11.0249 11.0249H1.69157C1.38215 11.0249 1.0854 10.902 0.866611 10.6832C0.647819 10.4644 0.524902 10.1677 0.524902 9.85824V1.69157C0.524902 1.38215 0.647819 1.0854 0.866611 0.866611C1.0854 0.647819 1.38215 0.524902 1.69157 0.524902H4.60824L5.7749 2.2749H11.0249C11.3343 2.2749 11.6311 2.39782 11.8499 2.61661C12.0687 2.8354 12.1916 3.13215 12.1916 3.44157V9.85824Z\" [attr.stroke]=\"color || '#99999E'\" stroke-width=\"1.05\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n</ng-template>\n\n<aside\n class=\"cqa-flex cqa-flex-col cqa-bg-white cqa-border cqa-border-neutral-200 cqa-rounded-lg cqa-h-full cqa-min-h-0\"\n [class.cqa-w-[240px]]=\"!collapsed\"\n [class.cqa-w-[48px]]=\"collapsed\"\n style=\"transition: width 150ms ease;\"\n>\n <!-- Header -->\n <div\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-px-3 cqa-py-1\"\n [style.border-bottom]=\"collapsed ? null : '1px solid #E2E2E3'\"\n [style.margin-bottom.px]=\"collapsed ? 0 : 8\"\n >\n <span *ngIf=\"!collapsed\" class=\"cqa-text-sm cqa-font-semibold cqa-text-neutral-900\">\n {{ labels.folders }}\n </span>\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\" [class.cqa-w-full]=\"collapsed\" [class.cqa-justify-center]=\"collapsed\">\n <button\n type=\"button\"\n class=\"cqa-p-1 cqa-rounded hover:cqa-bg-neutral-100 cqa-text-neutral-500\"\n (click)=\"togglePanel()\"\n [attr.aria-label]=\"collapsed ? 'Expand folders panel' : 'Collapse folders panel'\"\n >\n <mat-icon style=\"font-size:18px;width:18px;height:18px\">\n {{ collapsed ? 'chevron_right' : 'keyboard_double_arrow_left' }}\n </mat-icon>\n </button>\n <button\n *ngIf=\"!collapsed && allowCreate\"\n type=\"button\"\n class=\"cqa-p-1 cqa-rounded hover:cqa-bg-neutral-100 cqa-text-neutral-500\"\n (click)=\"requestCreate(null)\"\n [attr.aria-label]=\"labels.newFolder\"\n [title]=\"labels.newFolder\"\n >\n <mat-icon style=\"font-size:18px;width:18px;height:18px\">add</mat-icon>\n </button>\n </div>\n </div>\n\n <ng-container *ngIf=\"!collapsed\">\n <!-- Search -->\n <div class=\"cqa-px-3 cqa-pb-2\">\n <cqa-search-bar\n size=\"sm\"\n [fullWidth]=\"true\"\n [value]=\"searchValue\"\n [placeholder]=\"labels.searchFoldersPlaceholder\"\n [showClear]=\"true\"\n (valueChange)=\"searchValue = $event\"\n (cleared)=\"searchValue = ''\"\n ></cqa-search-bar>\n </div>\n\n <!-- Tree (folders only \u2014 Unorganised sits directly below; tree caps at 60vh and scrolls when overflowing) -->\n <div role=\"tree\" class=\"cqa-min-h-0 cqa-max-h-[60vh] cqa-overflow-y-auto cqa-py-1 cqa-scrollbar-thin cqa-scrollbar-track-transparent cqa-scrollbar-thumb-[#E5E7EB] cqa-scrollbar-thumb-rounded-full cqa-scrollbar-thumb-hover:cqa-bg-[#D1D5DB]\">\n <div\n *ngIf=\"searchValue?.trim() && rows.length === 0\"\n class=\"cqa-px-3 cqa-py-2 cqa-text-sm cqa-text-neutral-500 cqa-text-center\"\n >\n {{ labels.noFoldersFound }}\n </div>\n <ng-container *ngFor=\"let row of rows; let i = index; trackBy: trackByRow\">\n <div\n role=\"treeitem\"\n tabindex=\"0\"\n [attr.aria-expanded]=\"row.hasChildren ? isExpanded(row.node.id) : null\"\n [attr.aria-selected]=\"isSelected(row.node.id)\"\n [attr.data-folder-row-id]=\"row.node.id\"\n [cqaFolderDrop]=\"row.node.id\"\n [dropEnabled]=\"allowDrop\"\n (testsDropped)=\"rowDropped(row.node.id, $event)\"\n (folderDropped)=\"onFolderRowDropped(row.node.id, $event)\"\n [cqaFolderDrag]=\"row.node.id\"\n [dragEnabled]=\"allowDrop\"\n (dragstart)=\"onFolderDragStart(row.node)\"\n (dragend)=\"onFolderDragEnd()\"\n (dragover)=\"onFolderRowDragOver(row)\"\n (dragleave)=\"onFolderRowDragLeave(row)\"\n (click)=\"onSelect(row.node)\"\n (contextmenu)=\"openContextMenu(row.node, $event)\"\n (keydown)=\"onRowKeydown($event, row, i)\"\n class=\"cqa-group cqa-flex cqa-items-center cqa-gap-1 cqa-pr-3 cqa-py-1.5 cqa-cursor-pointer hover:cqa-bg-indigo-50 focus:cqa-outline-none focus:cqa-bg-indigo-50 cqa-relative\"\n [class.cqa-bg-indigo-50]=\"isSelected(row.node.id) || contextMenuFolderId === row.node.id\"\n [style.paddingLeft.px]=\"8 + row.depth * 16\"\n [attr.title]=\"row.node.totalCount != null ? (row.node.totalCount + ' total including subfolders') : null\"\n >\n <span\n *ngIf=\"isSelected(row.node.id)\"\n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-bottom-0 cqa-w-[3px] cqa-bg-indigo-600\"\n ></span>\n <button\n type=\"button\"\n class=\"cqa-p-0\"\n [style.color]=\"isSelected(row.node.id) ? '#3F43EE' : '#4C4C51'\"\n [style.visibility]=\"row.hasChildren ? 'visible' : 'hidden'\"\n (click)=\"onToggle(row.node, $event)\"\n [attr.aria-label]=\"isExpanded(row.node.id) ? 'Collapse' : 'Expand'\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">\n {{ isExpanded(row.node.id) ? 'expand_more' : 'chevron_right' }}\n </mat-icon>\n </button>\n <ng-container *ngTemplateOutlet=\"folderIcon; context: { color: row.node.color }\"></ng-container>\n\n <ng-container *ngIf=\"renamingId === row.node.id; else nameTpl\">\n <input\n type=\"text\"\n size=\"1\"\n [attr.data-folder-rename-input]=\"row.node.id\"\n [attr.maxlength]=\"renameMaxLength\"\n class=\"cqa-flex-1 cqa-min-w-0 cqa-w-full cqa-px-2 cqa-py-0.5 cqa-rounded cqa-border cqa-bg-white cqa-text-sm cqa-shadow-sm focus:cqa-outline-none focus:cqa-ring-1\"\n [ngClass]=\"(isRenameDraftValid && !renameLimitFlash)\n ? 'cqa-border-neutral-300 focus:cqa-border-indigo-400 focus:cqa-ring-indigo-200'\n : 'cqa-border-[#EF4444] focus:cqa-border-[#EF4444] focus:cqa-ring-[#FCA5A5]'\"\n [attr.aria-invalid]=\"!isRenameDraftValid || renameLimitFlash\"\n [(ngModel)]=\"renameDraft\"\n (keydown)=\"onRenameKey($event, row.node)\"\n (keypress)=\"$event.stopPropagation()\"\n (keyup)=\"$event.stopPropagation()\"\n (blur)=\"commitRename(row.node)\"\n (click)=\"$event.stopPropagation()\"\n />\n </ng-container>\n <ng-template #nameTpl>\n <span\n class=\"cqa-flex-1 cqa-text-sm cqa-truncate\"\n [style.color]=\"isSelected(row.node.id) ? '#3F43EE' : '#4C4C51'\"\n (dblclick)=\"beginRename(row.node, $event)\"\n >{{ row.node.name }}</span>\n </ng-template>\n\n <!-- Count shown at rest; hidden on row hover when delete is allowed -->\n <span\n *ngIf=\"showCounts && row.node.count != null\"\n class=\"cqa-text-xs cqa-tabular-nums cqa-ml-1\"\n [style.color]=\"isSelected(row.node.id) ? '#3F43EE' : '#4C4C51'\"\n [class.group-hover:cqa-hidden]=\"allowDelete\"\n >{{ row.node.count }}</span>\n\n <button\n *ngIf=\"hasAnyContextAction\"\n type=\"button\"\n class=\"cqa-p-0.5 cqa-rounded hover:cqa-bg-neutral-200\"\n [style.color]=\"isSelected(row.node.id) || contextMenuFolderId === row.node.id ? '#3F43EE' : '#4C4C51'\"\n [class.cqa-hidden]=\"contextMenuFolderId !== row.node.id\"\n [class.group-hover:cqa-inline-flex]=\"true\"\n [class.cqa-inline-flex]=\"contextMenuFolderId === row.node.id\"\n (click)=\"openContextMenu(row.node, $event)\"\n [attr.aria-label]=\"'Open actions for ' + row.node.name\"\n [attr.aria-haspopup]=\"'menu'\"\n [attr.aria-expanded]=\"contextMenuFolderId === row.node.id\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">more_horiz</mat-icon>\n </button>\n </div>\n </ng-container>\n </div>\n\n <!-- Divider between folder tree and pinned Unorganised tab -->\n <div\n aria-hidden=\"true\"\n class=\"cqa-mx-3 cqa-shrink-0\"\n style=\"height: 1px; background-color: #E5E7EB; margin-top: 6px; margin-bottom: 6px;\"\n ></div>\n\n <!-- Unorganised \u2014 pinned below the scrollable folder tree so it stays visible regardless of folder count -->\n <div\n role=\"treeitem\"\n tabindex=\"0\"\n [attr.aria-selected]=\"isSelected(null)\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-1.5 cqa-cursor-pointer hover:cqa-bg-indigo-50 focus:cqa-outline-none focus:cqa-bg-indigo-50 cqa-relative cqa-shrink-0\"\n [class.cqa-bg-indigo-50]=\"isSelected(null)\"\n [cqaFolderDrop]=\"null\"\n [dropEnabled]=\"allowDrop\"\n (testsDropped)=\"rowDropped(null, $event)\"\n (folderDropped)=\"onFolderRowDropped(null, $event)\"\n (click)=\"onSelectUnorganised()\"\n >\n <span\n *ngIf=\"isSelected(null)\"\n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-bottom-0 cqa-w-[3px] cqa-bg-indigo-600\"\n ></span>\n <mat-icon [style.color]=\"isSelected(null) ? '#3F43EE' : '#4C4C51'\" style=\"font-size:16px;width:16px;height:16px\">inbox</mat-icon>\n <span class=\"cqa-flex-1 cqa-text-sm\" [style.color]=\"isSelected(null) ? '#3F43EE' : '#4C4C51'\">{{ labels.unorganised }}</span>\n <span *ngIf=\"showCounts\" class=\"cqa-text-xs cqa-tabular-nums\" [style.color]=\"isSelected(null) ? '#3F43EE' : '#4C4C51'\">{{ unorganisedCount }}</span>\n </div>\n\n <!-- Folder context menu (right-click / ellipsis). A 0\u00D70 fixed-position\n anchor at the click coords drives a cdkConnectedOverlay; CDK's\n flexible-connected positioning auto-flips up/left when the menu\n would overflow the viewport (last-folder-near-bottom case). -->\n <div #ctxAnchor cdkOverlayOrigin\n class=\"cqa-fixed cqa-w-0 cqa-h-0 cqa-pointer-events-none\"\n [style.left.px]=\"contextMenuPosition.x\"\n [style.top.px]=\"contextMenuPosition.y\"></div>\n\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"ctxAnchor\"\n [cdkConnectedOverlayOpen]=\"contextMenuFolderId !== null\"\n [cdkConnectedOverlayPositions]=\"contextMenuPositions\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n [cdkConnectedOverlayFlexibleDimensions]=\"false\"\n [cdkConnectedOverlayPush]=\"true\"\n (overlayOutsideClick)=\"onOverlayOutsideClick()\"\n (detach)=\"closeContextMenu()\"\n >\n <!-- The lib's tailwind config sets important: '.cqa-ui-root', which\n emits descendant selectors like `.cqa-ui-root .cqa-bg-white`.\n CDK Overlay teleports this template into the global overlay\n container (outside the host's cqa-ui-root), so we wrap the menu in\n an ancestor cqa-ui-root div to re-establish the utility scope. -->\n <div class=\"cqa-ui-root\">\n <div\n role=\"menu\"\n class=\"cqa-min-w-[180px] cqa-bg-white cqa-border cqa-border-neutral-200 cqa-rounded-md cqa-shadow-lg cqa-py-1\"\n (click)=\"$event.stopPropagation()\"\n (contextmenu)=\"$event.preventDefault(); $event.stopPropagation()\"\n >\n <ng-container *ngIf=\"folderById(contextMenuFolderId) as menuNode\">\n <button\n *ngIf=\"allowCreate\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextCreateSubfolder(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">create_new_folder</mat-icon>\n <span>{{ labels.folderMenuCreateSubfolder }}</span>\n </button>\n <button\n *ngIf=\"allowRename\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextRename(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">edit</mat-icon>\n <span>{{ labels.folderMenuRename }}</span>\n </button>\n <button\n *ngIf=\"allowMove\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextMove(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">drive_file_move</mat-icon>\n <span>{{ labels.folderMenuMove }}</span>\n </button>\n <button\n *ngIf=\"allowDuplicate\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-neutral-800 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onContextDuplicate(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">content_copy</mat-icon>\n <span>{{ labels.folderMenuDuplicate }}</span>\n </button>\n <div *ngIf=\"allowDelete && (allowCreate || allowRename || allowMove || allowDuplicate)\" class=\"cqa-h-px cqa-bg-neutral-200 cqa-my-1\"></div>\n <button\n *ngIf=\"allowDelete\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-w-full cqa-px-3 cqa-py-1.5 cqa-text-sm cqa-text-red-600 hover:cqa-bg-red-50 cqa-text-left\"\n (click)=\"onContextDelete(menuNode)\"\n >\n <mat-icon style=\"font-size:16px;width:16px;height:16px\">delete_outline</mat-icon>\n <span>{{ labels.folderMenuDelete }}</span>\n </button>\n </ng-container>\n </div>\n </div>\n </ng-template>\n\n </ng-container>\n</aside>\n", styles: [] }]
9509
9517
  }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { folders: [{
9510
9518
  type: Input
9511
9519
  }], selectedFolderId: [{
@@ -9863,17 +9871,85 @@ class ModularTableTemplateComponent {
9863
9871
  return this._reorderLabels;
9864
9872
  }
9865
9873
  updateComputedColumns() {
9874
+ var _a;
9866
9875
  const visibility = this._columnVisibility || {};
9867
9876
  const source = this.columns || [];
9868
- this.computedColumns = source.map(col => {
9877
+ const mapped = source.map(col => {
9869
9878
  if (['checkbox', 'actions'].includes(col.fieldId)) {
9870
9879
  return col;
9871
9880
  }
9872
9881
  const show = visibility[col.fieldId];
9873
9882
  return Object.assign(Object.assign({}, col), { isShow: show !== false });
9874
9883
  });
9884
+ if (((_a = this.modularConfig) === null || _a === void 0 ? void 0 : _a.showFolderColumn) && !mapped.some(c => c.fieldId === FOLDER_COLUMN_FIELD_ID)) {
9885
+ const folderShow = visibility[FOLDER_COLUMN_FIELD_ID];
9886
+ const folderCol = Object.assign(Object.assign({}, this.buildFolderColumn()), { isShow: folderShow !== false });
9887
+ // Insert before the trailing 'actions' column when present so the folder
9888
+ // column reads as the last data column rather than after the action menu.
9889
+ const actionsIdx = mapped.findIndex(c => c.fieldId === 'actions');
9890
+ if (actionsIdx >= 0) {
9891
+ mapped.splice(actionsIdx, 0, folderCol);
9892
+ }
9893
+ else {
9894
+ mapped.push(folderCol);
9895
+ }
9896
+ }
9897
+ this.computedColumns = mapped;
9875
9898
  this.cdr.markForCheck();
9876
9899
  }
9900
+ buildFolderColumn() {
9901
+ var _a;
9902
+ return {
9903
+ fieldId: FOLDER_COLUMN_FIELD_ID,
9904
+ fieldName: ((_a = this.modularLabels) === null || _a === void 0 ? void 0 : _a.folderColumnLabel) || 'Folder',
9905
+ // Lets the dynamic table sort/filter on the resolved name without going
9906
+ // through render() — also makes `row.folderName` a first-class field
9907
+ // alongside row.priority etc. for downstream code.
9908
+ fieldValue: 'folderName',
9909
+ sortable: true,
9910
+ // isDefault === false marks the column as "user-toggleable" — it shows up
9911
+ // in mapVisibilityColumns and therefore in the settings dropdown.
9912
+ isDefault: false,
9913
+ render: (row) => this.renderFolderCell(row),
9914
+ };
9915
+ }
9916
+ resolveFolderName(row) {
9917
+ var _a;
9918
+ if (row && typeof row.folderName === 'string' && row.folderName) {
9919
+ return row.folderName;
9920
+ }
9921
+ const folderId = this.folderIdAccessor ? this.folderIdAccessor(row) : row === null || row === void 0 ? void 0 : row.folderId;
9922
+ const node = folderId != null ? this.findFolder(this.folders, folderId) : null;
9923
+ return (node === null || node === void 0 ? void 0 : node.name) || ((_a = this.modularLabels) === null || _a === void 0 ? void 0 : _a.unorganisedRowLabel) || 'Unorganised';
9924
+ }
9925
+ /**
9926
+ * Attach a derived `folderName` to each row when the host hasn't supplied
9927
+ * one. Mutates in place so the value is available everywhere the row flows
9928
+ * — sort, filter, column renders, exports — alongside fields like priority.
9929
+ */
9930
+ enrichRowsWithFolderName(rows) {
9931
+ if (!rows || rows.length === 0)
9932
+ return;
9933
+ for (const row of rows) {
9934
+ if (!row || typeof row !== 'object')
9935
+ continue;
9936
+ if (typeof row.folderName === 'string' && row.folderName)
9937
+ continue;
9938
+ row.folderName = this.resolveFolderName(row);
9939
+ }
9940
+ }
9941
+ renderFolderCell(row) {
9942
+ const name = this.resolveFolderName(row);
9943
+ const escaped = name.replace(/[&<>"']/g, ch => ({
9944
+ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;',
9945
+ }[ch]));
9946
+ return (`<span class="cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-text-[#6D6D74]">` +
9947
+ `<svg width="14" height="13" viewBox="0 0 14 13" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">` +
9948
+ `<path d="M12.9583 10.4585C12.9583 10.79 12.8266 11.108 12.5921 11.3424C12.3577 11.5768 12.0398 11.7085 11.7083 11.7085H1.70825C1.37673 11.7085 1.05879 11.5768 0.824368 11.3424C0.589948 11.108 0.458252 10.79 0.458252 10.4585V1.7085C0.458252 1.37698 0.589948 1.05903 0.824368 0.824613C1.05879 0.590192 1.37673 0.458496 1.70825 0.458496H4.83325L6.08325 2.3335H11.7083C12.0398 2.3335 12.3577 2.46519 12.5921 2.69961C12.8266 2.93403 12.9583 3.25198 12.9583 3.5835V10.4585Z" stroke="currentColor" stroke-width="0.916667"/>` +
9949
+ `</svg>` +
9950
+ `<span>${escaped}</span>` +
9951
+ `</span>`);
9952
+ }
9877
9953
  updateVisibilityColumns() {
9878
9954
  this._cachedVisibilityColumns = this.mapVisibilityColumns();
9879
9955
  this.visibilityColumns = this._cachedVisibilityColumns;
@@ -9899,11 +9975,20 @@ class ModularTableTemplateComponent {
9899
9975
  if (changes['data'] || changes['isEmptyState']) {
9900
9976
  this.initializeComponent();
9901
9977
  }
9902
- if (changes['columns']) {
9978
+ if (changes['columns'] || changes['modularConfig'] || changes['modularLabels']) {
9903
9979
  this.initializeColumnVisibility();
9904
9980
  this.updateComputedColumns();
9905
9981
  this.updateVisibilityColumns();
9906
9982
  }
9983
+ if (changes['folders'] && !changes['folders'].firstChange) {
9984
+ // Folder name lookup lives inside the column's render(); rebuild the
9985
+ // columns array so the dynamic table's OnPush CD picks up the new ref
9986
+ // and re-invokes render() with the latest folders. Also refresh any
9987
+ // rows we've previously enriched so sort/filter on row.folderName
9988
+ // reflects the new folder list.
9989
+ this.enrichRowsWithFolderName(this.data);
9990
+ this.updateComputedColumns();
9991
+ }
9907
9992
  if (changes['selectedFolderId'] && !changes['selectedFolderId'].firstChange) {
9908
9993
  // Per the approved plan: clear selection and reset pagination on folder change.
9909
9994
  this.selectedItems = [];
@@ -9934,6 +10019,7 @@ class ModularTableTemplateComponent {
9934
10019
  this.pagedRows = [];
9935
10020
  return;
9936
10021
  }
10022
+ this.enrichRowsWithFolderName(this.data);
9937
10023
  // In server-side mode, assume incoming data is already a page slice
9938
10024
  if (this.serverSidePagination) {
9939
10025
  this.filteredRows = [...this.data];
@@ -10020,10 +10106,24 @@ class ModularTableTemplateComponent {
10020
10106
  // can pre-apply persisted preferences via columns[i].isShow.
10021
10107
  const source = this.columns || [];
10022
10108
  for (const col of this._cachedVisibilityColumns) {
10023
- if (this._columnVisibility[col.id] === undefined) {
10024
- const srcCol = source.find(c => c.fieldId === col.id);
10025
- this._columnVisibility[col.id] = srcCol && srcCol.isShow === false ? false : true;
10109
+ if (this._columnVisibility[col.id] !== undefined)
10110
+ continue;
10111
+ const srcCol = source.find(c => c.fieldId === col.id);
10112
+ if (srcCol) {
10113
+ // Host-supplied column — honour its isShow exactly, including for the
10114
+ // folder column. Hosts wanting view-mode-aware defaults should set
10115
+ // isShow themselves.
10116
+ this._columnVisibility[col.id] = srcCol.isShow !== false;
10117
+ continue;
10118
+ }
10119
+ if (col.id === FOLDER_COLUMN_FIELD_ID) {
10120
+ // Auto-injected folder column (host did not supply one): default to
10121
+ // visible in list view, hidden in modular view. The user's toggle
10122
+ // persists across viewMode flips once seeded.
10123
+ this._columnVisibility[col.id] = this.viewMode === 'list';
10124
+ continue;
10026
10125
  }
10126
+ this._columnVisibility[col.id] = true;
10027
10127
  }
10028
10128
  }
10029
10129
  get anyRowSelected() {
@@ -10246,9 +10346,17 @@ class ModularTableTemplateComponent {
10246
10346
  this.pagedRows = this.filteredRows.slice(start, end);
10247
10347
  }
10248
10348
  mapVisibilityColumns() {
10249
- return (this.columns || [])
10349
+ var _a, _b;
10350
+ const items = (this.columns || [])
10250
10351
  .filter(c => c.isDefault === false)
10251
10352
  .map(c => ({ id: c.fieldId, label: c.fieldName || c.fieldId }));
10353
+ if (((_a = this.modularConfig) === null || _a === void 0 ? void 0 : _a.showFolderColumn) && !items.some(i => i.id === FOLDER_COLUMN_FIELD_ID)) {
10354
+ items.push({
10355
+ id: FOLDER_COLUMN_FIELD_ID,
10356
+ label: ((_b = this.modularLabels) === null || _b === void 0 ? void 0 : _b.folderColumnLabel) || 'Folder',
10357
+ });
10358
+ }
10359
+ return items;
10252
10360
  }
10253
10361
  normalizeDate(d) {
10254
10362
  if (!d)
@@ -10834,10 +10942,10 @@ class ModularTableTemplateComponent {
10834
10942
  }
10835
10943
  }
10836
10944
  ModularTableTemplateComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ModularTableTemplateComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: DialogService }], target: i0.ɵɵFactoryTarget.Component });
10837
- ModularTableTemplateComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ModularTableTemplateComponent, selector: "cqa-modular-table-template", inputs: { searchPlaceholder: "searchPlaceholder", searchValue: "searchValue", showClear: "showClear", showSearchBar: "showSearchBar", showExportButton: "showExportButton", isExporting: "isExporting", filterConfig: "filterConfig", filterModel: "filterModel", showFilterPanel: "showFilterPanel", showFilterButton: "showFilterButton", otherButtons: "otherButtons", otherDropDownButtons: "otherDropDownButtons", otherSelectDropDownButtons: "otherSelectDropDownButtons", otherButtonLabel: "otherButtonLabel", otherButtonVariant: "otherButtonVariant", showOtherButton: "showOtherButton", showActionButton: "showActionButton", showSettingsButton: "showSettingsButton", showAutoRefreshButton: "showAutoRefreshButton", showViewModeToggle: "showViewModeToggle", viewMode: "viewMode", viewModeLabels: "viewModeLabels", data: "data", isEmptyState: "isEmptyState", emptyStateConfig: "emptyStateConfig", actions: "actions", chips: "chips", filterApplied: "filterApplied", columns: "columns", rowSelectable: "rowSelectable", selectedAutoRefreshInterval: "selectedAutoRefreshInterval", pageIndex: "pageIndex", pageSize: "pageSize", pageSizeOptions: "pageSizeOptions", pageSizeMenuDirection: "pageSizeMenuDirection", serverSidePagination: "serverSidePagination", totalElements: "totalElements", enableLocalSort: "enableLocalSort", isTableLoading: "isTableLoading", isTableDataLoading: "isTableDataLoading", cellJsonPathGetter: "cellJsonPathGetter", onJsonPathCopiedHandler: "onJsonPathCopiedHandler", selectedItems: "selectedItems", showSelectAllInToolbar: "showSelectAllInToolbar", showDismissInToolbar: "showDismissInToolbar", allSelectedInToolbar: "allSelectedInToolbar", folders: "folders", selectedFolderId: "selectedFolderId", expandedFolderIds: "expandedFolderIds", unorganisedCount: "unorganisedCount", folderIdAccessor: "folderIdAccessor", modularConfig: "modularConfig", modularLabels: "modularLabels", bulkActions: "bulkActions", sidebarCollapsed: "sidebarCollapsed", useInternalDialogs: "useInternalDialogs", showReorderButton: "showReorderButton", reorderSaving: "reorderSaving", reorderLabels: "reorderLabels", columnVisibility: "columnVisibility" }, outputs: { onSearchChange: "onSearchChange", onExportClick: "onExportClick", onApplyFilterClick: "onApplyFilterClick", onResetFilterClick: "onResetFilterClick", onClearAll: "onClearAll", removeChip: "removeChip", viewModeChange: "viewModeChange", pageChange: "pageChange", sortChange: "sortChange", folderSelected: "folderSelected", folderExpansionToggled: "folderExpansionToggled", folderCreated: "folderCreated", folderCreateRequested: "folderCreateRequested", folderRenamed: "folderRenamed", folderDeleted: "folderDeleted", testsMoved: "testsMoved", bulkActionClick: "bulkActionClick", bulkSelectAllChange: "bulkSelectAllChange", bulkDismiss: "bulkDismiss", bulkActionInvoked: "bulkActionInvoked", sidebarCollapsedChange: "sidebarCollapsedChange", reorderStart: "reorderStart", reorderCancel: "reorderCancel", reorderSave: "reorderSave", moveRequested: "moveRequested", selectedItemsChange: "selectedItemsChange", folderDeleteRequested: "folderDeleteRequested", folderMoveRequested: "folderMoveRequested", folderMoved: "folderMoved", folderDuplicateRequested: "folderDuplicateRequested", onReload: "onReload", onAutoRefreshClick: "onAutoRefreshClick", columnVisibilityChange: "columnVisibilityChange", autoRefreshIntervalChange: "autoRefreshIntervalChange" }, host: { classAttribute: "cqa-ui-root" }, viewQueries: [{ propertyName: "dynamicFilterComponent", first: true, predicate: DynamicFilterComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!-- Reusable folder-icon chip. Render via <ng-container *ngTemplateOutlet=\"folderIconChip\"></ng-container>. -->\n<ng-template #folderIconChip>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-10 cqa-h-10 cqa-rounded-lg cqa-bg-[#F0F0F1] cqa-text-[#6D6D74] cqa-shrink-0 group-hover:cqa-bg-indigo-50 group-hover:cqa-text-[#3F43EE]\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9583 10.4585C12.9583 10.79 12.8266 11.108 12.5921 11.3424C12.3577 11.5768 12.0398 11.7085 11.7083 11.7085H1.70825C1.37673 11.7085 1.05879 11.5768 0.824368 11.3424C0.589948 11.108 0.458252 10.79 0.458252 10.4585V1.7085C0.458252 1.37698 0.589948 1.05903 0.824368 0.824613C1.05879 0.590192 1.37673 0.458496 1.70825 0.458496H4.83325L6.08325 2.3335H11.7083C12.0398 2.3335 12.3577 2.46519 12.5921 2.69961C12.8266 2.93403 12.9583 3.25198 12.9583 3.5835V10.4585Z\" stroke=\"currentColor\" stroke-width=\"0.916667\"/>\n </svg>\n </span>\n</ng-template>\n\n<!-- Reusable \"+\" chip used by the \"New folder\" tile. -->\n<ng-template #addIconChip>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-10 cqa-h-10 cqa-rounded-lg cqa-bg-[#F0F0F1] cqa-text-[#6D6D74] cqa-shrink-0 group-hover:cqa-bg-indigo-50 group-hover:cqa-text-[#3F43EE]\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M8 3V13M3 8H13\" stroke=\"currentColor\" stroke-width=\"1.275\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n</ng-template>\n\n<div class=\"cqa-ui-root\">\n <div class=\"cqa-w-full cqa-flex cqa-flex-col cqa-relative\">\n <div [class]=\"!showSearchBar ? 'cqa-justify-end' : 'cqa-justify-between'\" class=\"cqa-w-full cqa-flex cqa-items-center cqa-gap-3 cqa-flex-wrap cqa-mb-3\">\n <cqa-search-bar\n *ngIf=\"showSearchBar\"\n [placeholder]=\"searchPlaceholder\"\n [value]=\"searchValue\"\n [showClear]=\"showClear\"\n (valueChange)=\"valueChange($event)\"\n (search)=\"search($event)\"\n (cleared)=\"cleared()\"\n ></cqa-search-bar>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-flex-wrap\">\n <cqa-button\n *ngIf=\"showExportButton\"\n variant=\"grey-solid\"\n icon=\"open_in_new\"\n [text]=\"isExporting ? 'Exporting...' : 'Export'\"\n [disabled]=\"isExporting\"\n (clicked)=\"exportCodeClick()\"\n >\n <span>{{ isExporting ? 'Exporting...' : 'Export' }}</span>\n </cqa-button>\n \n <!-- Export Code Modal -->\n <cqa-export-code-modal\n *ngIf=\"showExportButton\"\n [isOpen]=\"isExportModalOpen\"\n [cases]=\"selectedCasesForExport\"\n [disabled]=\"false\"\n (closeModal)=\"closeExportModal()\"\n (export)=\"onExportModalExport($event)\">\n </cqa-export-code-modal>\n <ng-container *ngFor=\"let dropdownTemplate of otherDropDownButtons; trackBy: trackByDropdownTemplateRef\">\n <ng-container *ngTemplateOutlet=\"dropdownTemplate\"></ng-container>\n </ng-container>\n\n <ng-container *ngFor=\"let selectDropdownTemplate of otherSelectDropDownButtons; trackBy: trackBySelectDropdownTemplateRef\">\n <ng-container *ngTemplateOutlet=\"selectDropdownTemplate\"></ng-container>\n </ng-container>\n \n <cqa-button\n *ngIf=\"showFilterButton\"\n variant=\"grey-solid\"\n icon=\"add\"\n [disabled]=\"isReordering\"\n (clicked)=\"toggleFilter()\"\n >\n <span class=\"cqa-flex cqa-items-center cqa-gap-1\">\n Filter \n <div [class]=\"arrowClasses\">\n <svg\n class=\"cqa-w-2 cqa-h-1 cqa-absolute cqa-left-[4px] cqa-top-[6px]\"\n viewBox=\"0 0 8 4\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0 0L4 4L8 0\"\n stroke=\"#0B0B0C\"\n stroke-width=\"1.33\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n </span>\n </cqa-button>\n <cqa-column-visibility\n *ngIf=\"showSettingsButton\"\n [columns]=\"visibilityColumns\"\n [columnVisibility]=\"columnVisibility\"\n [selectedAutoRefreshInterval]=\"selectedAutoRefreshInterval\"\n (columnVisibilityChange)=\"onColumnVisibilityChange($event)\"\n (autoRefreshChange)=\"onAutoRefreshChange($event)\"\n ></cqa-column-visibility>\n <cqa-button\n *ngIf=\"showAutoRefreshButton\"\n variant=\"grey-solid\"\n icon=\"refresh\"\n (clicked)=\"handleRefreshClick()\"\n [tooltip]=\"'Refresh'\"\n tooltipPosition=\"below\"\n [disabled]=\"isReordering\"\n ></cqa-button>\n <ng-container *ngFor=\"let buttonTemplate of otherButtons; trackBy: trackByTemplateRef\">\n <ng-container *ngTemplateOutlet=\"buttonTemplate\"></ng-container>\n </ng-container>\n <cqa-segment-control\n *ngIf=\"showViewModeToggle\"\n size=\"lg\"\n [segments]=\"viewModeSegments\"\n [value]=\"viewMode\"\n (valueChange)=\"onViewModeChange($event)\"\n ></cqa-segment-control>\n <cqa-button\n *ngIf=\"showReorderButton && !isReordering\"\n variant=\"outlined\"\n icon=\"drag_indicator\"\n [text]=\"reorderLabels.reorderButton\"\n [disabled]=\"!pagedRows || pagedRows.length === 0 || isTableLoading || isTableDataLoading\"\n (clicked)=\"startReorder()\"\n ></cqa-button>\n <ng-container *ngIf=\"showReorderButton && isReordering\">\n <cqa-button\n variant=\"outlined\"\n [text]=\"reorderLabels.cancelButton\"\n [disabled]=\"reorderSaving\"\n (clicked)=\"cancelReorder()\"\n ></cqa-button>\n <cqa-button\n variant=\"filled\"\n [icon]=\"reorderSaving ? 'hourglass_empty' : ''\"\n [text]=\"reorderSaving ? reorderLabels.savingButton : reorderLabels.doneButton\"\n [disabled]=\"reorderSaving\"\n (clicked)=\"saveReorder()\"\n ></cqa-button>\n </ng-container>\n </div>\n </div>\n\n <!-- Reorder mode banner -->\n <div *ngIf=\"isReordering\" class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-3 cqa-px-3 cqa-py-2 cqa-rounded-md cqa-bg-[#FFFBEB] cqa-border cqa-border-[#FDE68A]\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <circle cx=\"3\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"3\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"3\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n </svg>\n <span class=\"cqa-text-sm cqa-font-semibold cqa-text-[#92400E]\">{{ reorderLabels.bannerTitle }}</span>\n <span class=\"cqa-text-sm cqa-text-[#92400E]\">{{ reorderLabels.bannerDescription }}</span>\n </div>\n\n <cqa-selected-filters\n [filterApplied]=\"filterApplied\"\n [chips]=\"chips\"\n (removeChip)=\"onRemoveChip($event)\"\n (clearAll)=\"onClearAllChips()\"\n (onClearAll)=\"onClearAll.emit()\"\n >\n </cqa-selected-filters>\n\n <cqa-dynamic-filter\n *ngIf=\"showFilterPanel\"\n [config]=\"filterConfig\"\n [model]=\"filterModel\"\n [showFilterPanel]=\"showFilterPanel\"\n (filtersChanged)=\"onFiltersChanged($event)\"\n (filtersApplied)=\"onFiltersApplied($event)\"\n (onApplyFilterClick)=\"onApplyFilterClick.emit($event)\"\n (onResetFilterClick)=\"handleResetFilterClick()\"\n >\n </cqa-dynamic-filter>\n\n <div class=\"cqa-flex cqa-items-stretch cqa-gap-3 cqa-min-h-0\">\n <!-- Sidebar (only shown in modular view) -->\n <cqa-folder-sidebar\n *ngIf=\"isModularView && modularConfig.showSidebar\"\n [folders]=\"folders\"\n [selectedFolderId]=\"selectedFolderId\"\n [expandedFolderIds]=\"expandedFolderIds\"\n [unorganisedCount]=\"unorganisedCount\"\n [allowCreate]=\"modularConfig.allowCreateFolder\"\n [allowRename]=\"modularConfig.allowRenameFolder\"\n [allowDelete]=\"modularConfig.allowDeleteFolder\"\n [allowDrop]=\"modularConfig.allowTestDragDrop\"\n [showCounts]=\"modularConfig.showCounts\"\n [collapsed]=\"sidebarCollapsed\"\n [labels]=\"modularLabels\"\n (folderSelected)=\"onFolderSelected($event)\"\n (folderExpansionToggled)=\"onFolderExpansionToggled($event)\"\n (folderCreated)=\"onFolderCreated($event)\"\n (folderCreateRequested)=\"onFolderCreateRequested($event)\"\n (folderRenamed)=\"onFolderRenamed($event)\"\n (folderDeleted)=\"onFolderDeleted($event)\"\n (folderMoveRequested)=\"onFolderMoveRequested($event)\"\n (folderDuplicateRequested)=\"onFolderDuplicateRequested($event)\"\n (testsDropped)=\"onTestsDropped($event)\"\n (folderDropped)=\"onFolderDropped($event)\"\n (collapsedChange)=\"onSidebarCollapsedChange($event)\"\n ></cqa-folder-sidebar>\n\n <!-- Right pane -->\n <div\n class=\"cqa-flex-1 cqa-flex cqa-flex-col cqa-min-w-0\"\n [style.border-top]=\"isModularView ? '1px solid #E2E2E3' : null\"\n [style.border-left]=\"isModularView ? '1px solid #E2E2E3' : null\"\n [style.border-right]=\"isModularView ? '1px solid #E2E2E3' : null\"\n >\n <!-- Breadcrumb (modular view, folder drilled-in) -->\n <nav\n *ngIf=\"isModularView && modularConfig.showBreadcrumb && !isRootView\"\n aria-label=\"Folder path\"\n class=\"cqa-flex cqa-items-center cqa-gap-1 cqa-text-sm cqa-px-3 cqa-py-1 cqa-mb-3 cqa-rounded-none\"\n style=\"color: #6D6D74; border-bottom: 1px solid #E2E2E3;\"\n >\n <button type=\"button\" class=\"hover:cqa-text-[#3F43EE] cqa-inline-flex cqa-items-center cqa-gap-1\" (click)=\"onFolderSelected(null)\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9583 10.4585C12.9583 10.79 12.8266 11.108 12.5921 11.3424C12.3577 11.5768 12.0398 11.7085 11.7083 11.7085H1.70825C1.37673 11.7085 1.05879 11.5768 0.824368 11.3424C0.589948 11.108 0.458252 10.79 0.458252 10.4585V1.7085C0.458252 1.37698 0.589948 1.05903 0.824368 0.824613C1.05879 0.590192 1.37673 0.458496 1.70825 0.458496H4.83325L6.08325 2.3335H11.7083C12.0398 2.3335 12.3577 2.46519 12.5921 2.69961C12.8266 2.93403 12.9583 3.25198 12.9583 3.5835V10.4585Z\" stroke=\"currentColor\" stroke-width=\"0.916667\"/>\n </svg>\n <span>{{ modularLabels.allFolders }}</span>\n </button>\n <ng-container *ngFor=\"let crumb of breadcrumbTrail; let last = last\">\n <mat-icon class=\"cqa-align-middle\" style=\"font-size:16px;width:16px;height:16px;color:#6D6D74;\">chevron_right</mat-icon>\n <button\n type=\"button\"\n [ngClass]=\"last\n ? 'cqa-text-[#161617] cqa-font-semibold'\n : 'cqa-text-[#6D6D74] hover:cqa-text-[#3F43EE]'\"\n [disabled]=\"last\"\n (click)=\"!last && onFolderSelected(crumb.id)\"\n >{{ crumb.name }}</button>\n </ng-container>\n </nav>\n\n <!-- Folder grid: modular + root view -->\n <section\n *ngIf=\"isModularView && isRootView && modularConfig.showFolderGrid && rootFolderTiles.length\"\n class=\"cqa-mb-4 cqa-px-5 cqa-pt-4 cqa-pb-[14px]\"\n style=\"border-bottom: 1px solid #F0F0F1;\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9583 10.4585C12.9583 10.79 12.8266 11.108 12.5921 11.3424C12.3577 11.5768 12.0398 11.7085 11.7083 11.7085H1.70825C1.37673 11.7085 1.05879 11.5768 0.824368 11.3424C0.589948 11.108 0.458252 10.79 0.458252 10.4585V1.7085C0.458252 1.37698 0.589948 1.05903 0.824368 0.824613C1.05879 0.590192 1.37673 0.458496 1.70825 0.458496H4.83325L6.08325 2.3335H11.7083C12.0398 2.3335 12.3577 2.46519 12.5921 2.69961C12.8266 2.93403 12.9583 3.25198 12.9583 3.5835V10.4585Z\" stroke=\"#6D6D74\" stroke-width=\"0.916667\"/>\n </svg>\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-[#6D6D74]\">{{ modularLabels.organised }}</h3>\n <span class=\"cqa-text-xs cqa-text-[#6D6D74]\">\n {{ rootFolderTiles.length === 1 ? modularLabels.foldersCountSingular : modularLabels.foldersCountPlural.replace('{n}', '' + rootFolderTiles.length) }}\n </span>\n </div>\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-2\">\n <button\n *ngFor=\"let f of rootFolderTiles\"\n type=\"button\"\n [cqaFolderDrop]=\"f.id\"\n [dropEnabled]=\"modularConfig.allowTestDragDrop\"\n (testsDropped)=\"onTestsDropped($event)\"\n (click)=\"onFolderSelected(f.id)\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-justify-between cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-white hover:cqa-border-[#3F43EE] hover:cqa-shadow-sm cqa-transition-colors\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-min-w-0\">\n <ng-container *ngTemplateOutlet=\"folderIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ f.name }}</span>\n <span *ngIf=\"modularConfig.showCounts\" class=\"cqa-text-sm cqa-text-neutral-500 cqa-truncate\">\n {{ (f.count ?? 0) === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + (f.count ?? 0)) }}<ng-container *ngIf=\"f.children?.length\"> \u00B7 {{ f.children!.length === 1 ? modularLabels.oneSubfolder : modularLabels.subfoldersCount.replace('{n}', '' + f.children!.length) }}</ng-container>\n </span>\n </div>\n </div>\n <mat-icon class=\"cqa-text-neutral-400 cqa-shrink-0\" style=\"font-size:20px;width:20px;height:20px\">chevron_right</mat-icon>\n </button>\n\n <!-- \"+ New folder\" tile -->\n <button\n *ngIf=\"modularConfig.allowCreateFolder\"\n type=\"button\"\n (click)=\"onFolderCreateRequested({ parentId: null })\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-dashed cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-[#FAFAFA] hover:cqa-border-[#3F43EE] hover:cqa-bg-white cqa-transition-colors\"\n >\n <ng-container *ngTemplateOutlet=\"addIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ modularLabels.newFolder }}</span>\n <span class=\"cqa-text-sm cqa-text-neutral-400\">{{ modularLabels.testsCountPlural.replace('{n}', '0') }}</span>\n </div>\n </button>\n </div>\n </section>\n\n <!-- Subfolder section: modular + folder view. Shown whenever drilled in (even if no subfolders, so the \"+ New folder\" tile remains reachable). -->\n <section\n *ngIf=\"isModularView && !isRootView && modularConfig.showSubfolderSection && subfolderTiles.length\"\n class=\"cqa-mb-4 cqa-px-3 cqa-py-1\"\n >\n <div *ngIf=\"subfolderTiles.length || modularConfig.allowCreateFolder\" class=\"cqa-text-sm cqa-text-neutral-600 cqa-mb-2\">\n {{ modularLabels.subfoldersIn }} {{ breadcrumbTrail.length ? breadcrumbTrail[breadcrumbTrail.length - 1].name : '' }}\n </div>\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-2\">\n <button\n *ngFor=\"let f of subfolderTiles\"\n type=\"button\"\n [cqaFolderDrop]=\"f.id\"\n [dropEnabled]=\"modularConfig.allowTestDragDrop\"\n (testsDropped)=\"onTestsDropped($event)\"\n (click)=\"onFolderSelected(f.id)\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-justify-between cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-white hover:cqa-border-[#3F43EE] hover:cqa-shadow-sm cqa-transition-colors\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-min-w-0\">\n <ng-container *ngTemplateOutlet=\"folderIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ f.name }}</span>\n <span *ngIf=\"modularConfig.showCounts\" class=\"cqa-text-sm cqa-text-neutral-500 cqa-truncate\">\n {{ (f.count ?? 0) === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + (f.count ?? 0)) }}\n </span>\n </div>\n </div>\n <mat-icon class=\"cqa-text-neutral-400 cqa-shrink-0\" style=\"font-size:20px;width:20px;height:20px\">chevron_right</mat-icon>\n </button>\n\n <!-- \"+ New folder\" tile -->\n <button\n *ngIf=\"modularConfig.allowCreateFolder\"\n type=\"button\"\n (click)=\"onFolderCreateRequested({ parentId: selectedFolderId })\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-dashed cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-[#FAFAFA] hover:cqa-border-[#3F43EE] hover:cqa-bg-white cqa-transition-colors\"\n >\n <ng-container *ngTemplateOutlet=\"addIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ modularLabels.newFolder }}</span>\n <span class=\"cqa-text-sm cqa-text-neutral-400\">{{ modularLabels.testsCountPlural.replace('{n}', '0') }}</span>\n </div>\n </button>\n </div>\n </section>\n\n <!-- Folder panel header above the table: \"Hotel Search (3)\" + Clear filter -->\n <div\n *ngIf=\"isModularView && !isRootView && modularConfig.showUnorganisedSection\"\n class=\"cqa-flex cqa-mb-1 cqa-items-center cqa-justify-between cqa-px-4 cqa-py-3 cqa-rounded-t-lg cqa-bg-indigo-50 cqa-border cqa-border-indigo-100\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9585 10.4585C12.9585 10.79 12.8268 11.108 12.5924 11.3424C12.358 11.5768 12.04 11.7085 11.7085 11.7085H1.7085C1.37698 11.7085 1.05903 11.5768 0.824613 11.3424C0.590192 11.108 0.458496 10.79 0.458496 10.4585V1.7085C0.458496 1.37698 0.590192 1.05903 0.824613 0.824613C1.05903 0.590192 1.37698 0.458496 1.7085 0.458496H4.8335L6.0835 2.3335H11.7085C12.04 2.3335 12.358 2.46519 12.5924 2.69961C12.8268 2.93403 12.9585 3.25198 12.9585 3.5835V10.4585Z\" stroke=\"#3F43EE\" stroke-width=\"0.916667\"/>\n </svg>\n <span class=\"cqa-text-sm cqa-font-semibold cqa-text-indigo-700\">\n {{ currentFolderNode?.name }} ({{ currentFolderDirectCount }})\n </span>\n </div>\n <button\n type=\"button\"\n class=\"cqa-px-3 cqa-py-1 cqa-text-xs cqa-font-medium cqa-text-indigo-700 cqa-bg-white cqa-border cqa-border-indigo-200 cqa-rounded hover:cqa-bg-indigo-50\"\n (click)=\"onFolderSelected(null)\"\n >{{ modularLabels.clearFilter }}</button>\n </div>\n\n <!-- Unorganised section header at root view -->\n <div\n *ngIf=\"isModularView && isRootView && modularConfig.showUnorganisedSection\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2 cqa-mt-2\" style=\"margin-left: 20px;\"\n >\n <mat-icon class=\"cqa-text-[#6D6D74]\" style=\"font-size:16px;width:16px;height:16px\">inbox</mat-icon>\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-[#6D6D74]\">{{ modularLabels.unorganised }}</h3>\n <span class=\"cqa-text-xs cqa-text-[#6D6D74]\">\n {{ unorganisedCount === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + unorganisedCount) }}\n </span>\n </div>\n\n <!-- Table -->\n <div class=\"cqa-rounded-[7px] cqa-overflow-hidden cqa-border-t cqa-border-l cqa-border-r cqa-border-grey-200 cqa-relative cqa-overflow-x-auto\">\n <ng-container *ngIf=\"(isTableLoading || isTableDataLoading) || (!effectiveIsEmptyState && pagedRows && pagedRows.length > 0); else storyEmptyTpl\">\n <app-dynamic-table\n [columns]=\"computedColumns\"\n [data]=\"pagedRows\"\n [rowSelectable]=\"rowSelectable\"\n [enableLocalSort]=\"enableLocalSort && !isReordering\"\n [isTableLoading]=\"isTableLoading\"\n [isTableDataLoading]=\"isTableDataLoading\"\n [cellJsonPathGetter]=\"cellJsonPathGetter\"\n [onJsonPathCopiedHandler]=\"onJsonPathCopiedHandler\"\n [enableRowReorder]=\"isReordering\"\n (rowReorder)=\"onRowReorder($event)\"\n (sortChange)=\"sortChange.emit($event)\">\n <ng-template #emptyTableTpl>\n <div class=\"cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-py-8\">\n <img src=\"/assets/illustrations/empty-state.svg\" alt=\"No data\" class=\"cqa-w-32 cqa-h-32 cqa-mb-4\" />\n <h3 class=\"cqa-text-lg cqa-font-semibold cqa-mb-2\">No test cases</h3>\n <p class=\"cqa-text-sm cqa-text-neutral-500 cqa-mb-4\">Try adjusting filters or create a new test case.</p>\n <cqa-button variant=\"filled\" (clicked)=\"toggleFilter()\">Show Filters</cqa-button>\n </div>\n </ng-template>\n </app-dynamic-table>\n </ng-container>\n\n <ng-template #storyEmptyTpl>\n <div class=\"cqa-p-6 cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <cqa-empty-state\n *ngIf=\"effectiveIsEmptyState\"\n [title]=\"effectiveEmptyStateConfig.title\"\n [description]=\"effectiveEmptyStateConfig.description\"\n [imageUrl]=\"effectiveEmptyStateConfig.imageUrl\"\n [actions]=\"effectiveEmptyStateConfig.actions\"\n (actionClick)=\"onEmptyAction($event)\"\n >\n </cqa-empty-state>\n </div>\n </ng-template>\n </div>\n\n <cqa-pagination\n [totalElements]=\"serverSidePagination ? totalElements : filteredRows.length\"\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\"\n [pageSizeMenuDirection]=\"pageSizeMenuDirection\"\n [pageItemCount]=\"pagedRows.length\"\n (paginate)=\"onPaginate($event)\"\n (pageSizeChange)=\"onPageSizeChange($event)\"\n >\n </cqa-pagination>\n </div>\n </div>\n\n <!-- Reused bulk action toolbar -->\n <div *ngIf=\"anyRowSelected && modularConfig.allowBulkSelection && !isReordering\" class=\"cqa-absolute cqa-bottom-[18.75px] cqa-left-[50%] cqa-translate-x-[-50%] cqa-w-full lg:cqa-max-w-[68%] cqa-sm:max-w-[75%] cqa-max-w-[90%] cqa-z-[1]\">\n <cqa-table-action-toolbar\n [selectedItems]=\"selectedItems && selectedItems.length > 0 ? selectedItems : currentSelectedItems\"\n [actions]=\"effectiveBulkActions\"\n [showSelectAll]=\"showSelectAllInToolbar\"\n [allSelected]=\"allSelectedInToolbar\"\n [showDismiss]=\"showDismissInToolbar\"\n (actionClick)=\"onBulkAction($event)\"\n (selectAllChange)=\"onBulkSelectAll($event)\"\n (dismiss)=\"onBulkDismiss()\"\n ></cqa-table-action-toolbar>\n </div>\n\n </div>\n</div>\n\n", components: [{ type: SearchBarComponent, selector: "cqa-search-bar", inputs: ["placeholder", "value", "disabled", "showClear", "ariaLabel", "autoFocus", "size", "fullWidth"], outputs: ["valueChange", "search", "cleared"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "loading", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: ExportCodeModalComponent, selector: "cqa-export-code-modal", inputs: ["isOpen", "cases", "disabled"], outputs: ["closeModal", "export"] }, { type: ColumnVisibilityComponent, selector: "cqa-column-visibility", inputs: ["isStepGroup", "columns", "columnVisibility", "selectedAutoRefreshInterval"], outputs: ["columnVisibilityChange", "autoRefreshChange"] }, { type: SegmentControlComponent, selector: "cqa-segment-control", inputs: ["segments", "value", "disabled", "containerBgColor", "fullWidth", "size"], outputs: ["valueChange"] }, { type: SelectedFiltersComponent, selector: "cqa-selected-filters", inputs: ["filterApplied", "chips", "defaultChips", "defaultChipClass"], outputs: ["removeChip", "clearAll", "onClearAll"] }, { type: DynamicFilterComponent, selector: "cqa-dynamic-filter", inputs: ["config", "model", "showFilterPanel", "buttonLayout"], outputs: ["filtersApplied", "filtersChanged", "resetAction", "onApplyFilterClick", "onResetFilterClick"] }, { type: FolderSidebarComponent, selector: "cqa-folder-sidebar", inputs: ["folders", "selectedFolderId", "expandedFolderIds", "unorganisedCount", "allowCreate", "allowRename", "allowDelete", "allowMove", "allowDuplicate", "allowDrop", "showCounts", "collapsed", "labels"], outputs: ["folderSelected", "folderExpansionToggled", "folderCreated", "folderCreateRequested", "folderRenamed", "folderDeleted", "folderMoveRequested", "folderDuplicateRequested", "testsDropped", "folderDropped", "collapsedChange"] }, { type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: DynamicTableComponent, selector: "app-dynamic-table", inputs: ["data", "columns", "emptyState", "gridTemplateColumns", "screenWidth", "enableSelectAll", "rowSelectable", "enableLocalSort", "isTableLoading", "isTableDataLoading", "cellJsonPathGetter", "onJsonPathCopiedHandler", "enableRowReorder", "reorderHandleTooltip"], outputs: ["sortChange", "rowReorder"] }, { type: EmptyStateComponent, selector: "cqa-empty-state", inputs: ["preset", "imageUrl", "title", "description", "actions"], outputs: ["actionClick"] }, { type: PaginationComponent, selector: "cqa-pagination", inputs: ["totalElements", "totalPages", "pageIndex", "pageSize", "pageItemCount", "pageSizeOptions", "pageSizeMenuDirection"], outputs: ["pageIndexChange", "pageSizeChange", "paginate"] }, { type: TableActionToolbarComponent, selector: "cqa-table-action-toolbar", inputs: ["selectedItems", "actions", "showSelectAll", "allSelected", "showDismiss"], outputs: ["actionClick", "selectAllChange", "dismiss"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: FolderDropDirective, selector: "[cqaFolderDrop]", inputs: ["cqaFolderDrop", "dropEnabled"], outputs: ["testsDropped", "folderDropped"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
10945
+ ModularTableTemplateComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ModularTableTemplateComponent, selector: "cqa-modular-table-template", inputs: { searchPlaceholder: "searchPlaceholder", searchValue: "searchValue", showClear: "showClear", showSearchBar: "showSearchBar", showExportButton: "showExportButton", isExporting: "isExporting", filterConfig: "filterConfig", filterModel: "filterModel", showFilterPanel: "showFilterPanel", showFilterButton: "showFilterButton", otherButtons: "otherButtons", otherDropDownButtons: "otherDropDownButtons", otherSelectDropDownButtons: "otherSelectDropDownButtons", otherButtonLabel: "otherButtonLabel", otherButtonVariant: "otherButtonVariant", showOtherButton: "showOtherButton", showActionButton: "showActionButton", showSettingsButton: "showSettingsButton", showAutoRefreshButton: "showAutoRefreshButton", showViewModeToggle: "showViewModeToggle", viewMode: "viewMode", viewModeLabels: "viewModeLabels", data: "data", isEmptyState: "isEmptyState", emptyStateConfig: "emptyStateConfig", actions: "actions", chips: "chips", filterApplied: "filterApplied", columns: "columns", rowSelectable: "rowSelectable", selectedAutoRefreshInterval: "selectedAutoRefreshInterval", pageIndex: "pageIndex", pageSize: "pageSize", pageSizeOptions: "pageSizeOptions", pageSizeMenuDirection: "pageSizeMenuDirection", serverSidePagination: "serverSidePagination", totalElements: "totalElements", enableLocalSort: "enableLocalSort", isTableLoading: "isTableLoading", isTableDataLoading: "isTableDataLoading", cellJsonPathGetter: "cellJsonPathGetter", onJsonPathCopiedHandler: "onJsonPathCopiedHandler", selectedItems: "selectedItems", showSelectAllInToolbar: "showSelectAllInToolbar", showDismissInToolbar: "showDismissInToolbar", allSelectedInToolbar: "allSelectedInToolbar", folders: "folders", selectedFolderId: "selectedFolderId", expandedFolderIds: "expandedFolderIds", unorganisedCount: "unorganisedCount", folderIdAccessor: "folderIdAccessor", modularConfig: "modularConfig", modularLabels: "modularLabels", bulkActions: "bulkActions", sidebarCollapsed: "sidebarCollapsed", useInternalDialogs: "useInternalDialogs", showReorderButton: "showReorderButton", reorderSaving: "reorderSaving", reorderLabels: "reorderLabels", columnVisibility: "columnVisibility" }, outputs: { onSearchChange: "onSearchChange", onExportClick: "onExportClick", onApplyFilterClick: "onApplyFilterClick", onResetFilterClick: "onResetFilterClick", onClearAll: "onClearAll", removeChip: "removeChip", viewModeChange: "viewModeChange", pageChange: "pageChange", sortChange: "sortChange", folderSelected: "folderSelected", folderExpansionToggled: "folderExpansionToggled", folderCreated: "folderCreated", folderCreateRequested: "folderCreateRequested", folderRenamed: "folderRenamed", folderDeleted: "folderDeleted", testsMoved: "testsMoved", bulkActionClick: "bulkActionClick", bulkSelectAllChange: "bulkSelectAllChange", bulkDismiss: "bulkDismiss", bulkActionInvoked: "bulkActionInvoked", sidebarCollapsedChange: "sidebarCollapsedChange", reorderStart: "reorderStart", reorderCancel: "reorderCancel", reorderSave: "reorderSave", moveRequested: "moveRequested", selectedItemsChange: "selectedItemsChange", folderDeleteRequested: "folderDeleteRequested", folderMoveRequested: "folderMoveRequested", folderMoved: "folderMoved", folderDuplicateRequested: "folderDuplicateRequested", onReload: "onReload", onAutoRefreshClick: "onAutoRefreshClick", columnVisibilityChange: "columnVisibilityChange", autoRefreshIntervalChange: "autoRefreshIntervalChange" }, host: { classAttribute: "cqa-ui-root" }, viewQueries: [{ propertyName: "dynamicFilterComponent", first: true, predicate: DynamicFilterComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!-- Reusable folder-icon chip. Render via <ng-container *ngTemplateOutlet=\"folderIconChip; context: { color: f.color }\"></ng-container>. -->\n<ng-template #folderIconChip let-color=\"color\">\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-10 cqa-h-10 cqa-rounded-lg cqa-bg-[#F0F0F1] cqa-text-[#6D6D74] cqa-shrink-0 group-hover:cqa-bg-indigo-50 group-hover:cqa-text-[#3F43EE]\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9583 10.4585C12.9583 10.79 12.8266 11.108 12.5921 11.3424C12.3577 11.5768 12.0398 11.7085 11.7083 11.7085H1.70825C1.37673 11.7085 1.05879 11.5768 0.824368 11.3424C0.589948 11.108 0.458252 10.79 0.458252 10.4585V1.7085C0.458252 1.37698 0.589948 1.05903 0.824368 0.824613C1.05879 0.590192 1.37673 0.458496 1.70825 0.458496H4.83325L6.08325 2.3335H11.7083C12.0398 2.3335 12.3577 2.46519 12.5921 2.69961C12.8266 2.93403 12.9583 3.25198 12.9583 3.5835V10.4585Z\" [attr.stroke]=\"color || 'currentColor'\" stroke-width=\"0.916667\"/>\n </svg>\n </span>\n</ng-template>\n\n<!-- Reusable \"+\" chip used by the \"New folder\" tile. -->\n<ng-template #addIconChip>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-10 cqa-h-10 cqa-rounded-lg cqa-bg-[#F0F0F1] cqa-text-[#6D6D74] cqa-shrink-0 group-hover:cqa-bg-indigo-50 group-hover:cqa-text-[#3F43EE]\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M8 3V13M3 8H13\" stroke=\"currentColor\" stroke-width=\"1.275\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n</ng-template>\n\n<div class=\"cqa-ui-root\">\n <div class=\"cqa-w-full cqa-flex cqa-flex-col cqa-relative\">\n <div [class]=\"!showSearchBar ? 'cqa-justify-end' : 'cqa-justify-between'\" class=\"cqa-w-full cqa-flex cqa-items-center cqa-gap-3 cqa-flex-wrap cqa-mb-3\">\n <cqa-search-bar\n *ngIf=\"showSearchBar\"\n [placeholder]=\"searchPlaceholder\"\n [value]=\"searchValue\"\n [showClear]=\"showClear\"\n (valueChange)=\"valueChange($event)\"\n (search)=\"search($event)\"\n (cleared)=\"cleared()\"\n ></cqa-search-bar>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-flex-wrap\">\n <cqa-button\n *ngIf=\"showExportButton\"\n variant=\"grey-solid\"\n icon=\"open_in_new\"\n [text]=\"isExporting ? 'Exporting...' : 'Export'\"\n [disabled]=\"isExporting\"\n (clicked)=\"exportCodeClick()\"\n >\n <span>{{ isExporting ? 'Exporting...' : 'Export' }}</span>\n </cqa-button>\n \n <!-- Export Code Modal -->\n <cqa-export-code-modal\n *ngIf=\"showExportButton\"\n [isOpen]=\"isExportModalOpen\"\n [cases]=\"selectedCasesForExport\"\n [disabled]=\"false\"\n (closeModal)=\"closeExportModal()\"\n (export)=\"onExportModalExport($event)\">\n </cqa-export-code-modal>\n <ng-container *ngFor=\"let dropdownTemplate of otherDropDownButtons; trackBy: trackByDropdownTemplateRef\">\n <ng-container *ngTemplateOutlet=\"dropdownTemplate\"></ng-container>\n </ng-container>\n\n <ng-container *ngFor=\"let selectDropdownTemplate of otherSelectDropDownButtons; trackBy: trackBySelectDropdownTemplateRef\">\n <ng-container *ngTemplateOutlet=\"selectDropdownTemplate\"></ng-container>\n </ng-container>\n \n <cqa-button\n *ngIf=\"showFilterButton\"\n variant=\"grey-solid\"\n icon=\"add\"\n [disabled]=\"isReordering\"\n (clicked)=\"toggleFilter()\"\n >\n <span class=\"cqa-flex cqa-items-center cqa-gap-1\">\n Filter \n <div [class]=\"arrowClasses\">\n <svg\n class=\"cqa-w-2 cqa-h-1 cqa-absolute cqa-left-[4px] cqa-top-[6px]\"\n viewBox=\"0 0 8 4\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0 0L4 4L8 0\"\n stroke=\"#0B0B0C\"\n stroke-width=\"1.33\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n </span>\n </cqa-button>\n <cqa-column-visibility\n *ngIf=\"showSettingsButton\"\n [columns]=\"visibilityColumns\"\n [columnVisibility]=\"columnVisibility\"\n [selectedAutoRefreshInterval]=\"selectedAutoRefreshInterval\"\n (columnVisibilityChange)=\"onColumnVisibilityChange($event)\"\n (autoRefreshChange)=\"onAutoRefreshChange($event)\"\n ></cqa-column-visibility>\n <cqa-button\n *ngIf=\"showAutoRefreshButton\"\n variant=\"grey-solid\"\n icon=\"refresh\"\n (clicked)=\"handleRefreshClick()\"\n [tooltip]=\"'Refresh'\"\n tooltipPosition=\"below\"\n [disabled]=\"isReordering\"\n ></cqa-button>\n <ng-container *ngFor=\"let buttonTemplate of otherButtons; trackBy: trackByTemplateRef\">\n <ng-container *ngTemplateOutlet=\"buttonTemplate\"></ng-container>\n </ng-container>\n <cqa-segment-control\n *ngIf=\"showViewModeToggle\"\n size=\"lg\"\n [segments]=\"viewModeSegments\"\n [value]=\"viewMode\"\n (valueChange)=\"onViewModeChange($event)\"\n ></cqa-segment-control>\n <cqa-button\n *ngIf=\"showReorderButton && !isReordering\"\n variant=\"outlined\"\n icon=\"drag_indicator\"\n [text]=\"reorderLabels.reorderButton\"\n [disabled]=\"!pagedRows || pagedRows.length === 0 || isTableLoading || isTableDataLoading\"\n (clicked)=\"startReorder()\"\n ></cqa-button>\n <ng-container *ngIf=\"showReorderButton && isReordering\">\n <cqa-button\n variant=\"outlined\"\n [text]=\"reorderLabels.cancelButton\"\n [disabled]=\"reorderSaving\"\n (clicked)=\"cancelReorder()\"\n ></cqa-button>\n <cqa-button\n variant=\"filled\"\n [icon]=\"reorderSaving ? 'hourglass_empty' : ''\"\n [text]=\"reorderSaving ? reorderLabels.savingButton : reorderLabels.doneButton\"\n [disabled]=\"reorderSaving\"\n (clicked)=\"saveReorder()\"\n ></cqa-button>\n </ng-container>\n </div>\n </div>\n\n <!-- Reorder mode banner -->\n <div *ngIf=\"isReordering\" class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-3 cqa-px-3 cqa-py-2 cqa-rounded-md cqa-bg-[#FFFBEB] cqa-border cqa-border-[#FDE68A]\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <circle cx=\"3\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"3\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"3\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n </svg>\n <span class=\"cqa-text-sm cqa-font-semibold cqa-text-[#92400E]\">{{ reorderLabels.bannerTitle }}</span>\n <span class=\"cqa-text-sm cqa-text-[#92400E]\">{{ reorderLabels.bannerDescription }}</span>\n </div>\n\n <cqa-selected-filters\n [filterApplied]=\"filterApplied\"\n [chips]=\"chips\"\n (removeChip)=\"onRemoveChip($event)\"\n (clearAll)=\"onClearAllChips()\"\n (onClearAll)=\"onClearAll.emit()\"\n >\n </cqa-selected-filters>\n\n <cqa-dynamic-filter\n *ngIf=\"showFilterPanel\"\n [config]=\"filterConfig\"\n [model]=\"filterModel\"\n [showFilterPanel]=\"showFilterPanel\"\n (filtersChanged)=\"onFiltersChanged($event)\"\n (filtersApplied)=\"onFiltersApplied($event)\"\n (onApplyFilterClick)=\"onApplyFilterClick.emit($event)\"\n (onResetFilterClick)=\"handleResetFilterClick()\"\n >\n </cqa-dynamic-filter>\n\n <div class=\"cqa-flex cqa-items-stretch cqa-gap-3 cqa-min-h-0 \" style=\"border-bottom: 1px solid rgb(226, 226, 227);\">\n <!-- Sidebar (only shown in modular view) -->\n <cqa-folder-sidebar\n *ngIf=\"isModularView && modularConfig.showSidebar\"\n [folders]=\"folders\"\n [selectedFolderId]=\"selectedFolderId\"\n [expandedFolderIds]=\"expandedFolderIds\"\n [unorganisedCount]=\"unorganisedCount\"\n [allowCreate]=\"modularConfig.allowCreateFolder\"\n [allowRename]=\"modularConfig.allowRenameFolder\"\n [allowDelete]=\"modularConfig.allowDeleteFolder\"\n [allowDrop]=\"modularConfig.allowTestDragDrop\"\n [showCounts]=\"modularConfig.showCounts\"\n [collapsed]=\"sidebarCollapsed\"\n [labels]=\"modularLabels\"\n (folderSelected)=\"onFolderSelected($event)\"\n (folderExpansionToggled)=\"onFolderExpansionToggled($event)\"\n (folderCreated)=\"onFolderCreated($event)\"\n (folderCreateRequested)=\"onFolderCreateRequested($event)\"\n (folderRenamed)=\"onFolderRenamed($event)\"\n (folderDeleted)=\"onFolderDeleted($event)\"\n (folderMoveRequested)=\"onFolderMoveRequested($event)\"\n (folderDuplicateRequested)=\"onFolderDuplicateRequested($event)\"\n (testsDropped)=\"onTestsDropped($event)\"\n (folderDropped)=\"onFolderDropped($event)\"\n (collapsedChange)=\"onSidebarCollapsedChange($event)\"\n ></cqa-folder-sidebar>\n\n <!-- Right pane -->\n <div\n class=\"cqa-flex-1 cqa-flex cqa-flex-col cqa-min-w-0\"\n [style.border-top]=\"isModularView ? '1px solid #E2E2E3' : null\"\n [style.border-left]=\"isModularView ? '1px solid #E2E2E3' : null\"\n [style.border-right]=\"isModularView ? '1px solid #E2E2E3' : null\"\n >\n <!-- Breadcrumb (modular view, folder drilled-in) -->\n <nav\n *ngIf=\"isModularView && modularConfig.showBreadcrumb && !isRootView\"\n aria-label=\"Folder path\"\n class=\"cqa-flex cqa-items-center cqa-gap-1 cqa-text-sm cqa-px-3 cqa-py-1 cqa-mb-3 cqa-rounded-none\"\n style=\"color: #6D6D74; border-bottom: 1px solid #E2E2E3;\"\n >\n <button type=\"button\" class=\"hover:cqa-text-[#3F43EE] cqa-inline-flex cqa-items-center cqa-gap-1\" (click)=\"onFolderSelected(null)\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9583 10.4585C12.9583 10.79 12.8266 11.108 12.5921 11.3424C12.3577 11.5768 12.0398 11.7085 11.7083 11.7085H1.70825C1.37673 11.7085 1.05879 11.5768 0.824368 11.3424C0.589948 11.108 0.458252 10.79 0.458252 10.4585V1.7085C0.458252 1.37698 0.589948 1.05903 0.824368 0.824613C1.05879 0.590192 1.37673 0.458496 1.70825 0.458496H4.83325L6.08325 2.3335H11.7083C12.0398 2.3335 12.3577 2.46519 12.5921 2.69961C12.8266 2.93403 12.9583 3.25198 12.9583 3.5835V10.4585Z\" stroke=\"currentColor\" stroke-width=\"0.916667\"/>\n </svg>\n <span>{{ modularLabels.allFolders }}</span>\n </button>\n <ng-container *ngFor=\"let crumb of breadcrumbTrail; let last = last\">\n <mat-icon class=\"cqa-align-middle\" style=\"font-size:16px;width:16px;height:16px;color:#6D6D74;\">chevron_right</mat-icon>\n <button\n type=\"button\"\n [ngClass]=\"last\n ? 'cqa-text-[#161617] cqa-font-semibold'\n : 'cqa-text-[#6D6D74] hover:cqa-text-[#3F43EE]'\"\n [disabled]=\"last\"\n (click)=\"!last && onFolderSelected(crumb.id)\"\n >{{ crumb.name }}</button>\n </ng-container>\n </nav>\n\n <!-- Folder grid: modular + root view -->\n <section\n *ngIf=\"isModularView && isRootView && modularConfig.showFolderGrid && rootFolderTiles.length\"\n class=\"cqa-mb-4 cqa-px-5 cqa-pt-4 cqa-pb-[14px]\"\n style=\"border-bottom: 1px solid #F0F0F1;\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9583 10.4585C12.9583 10.79 12.8266 11.108 12.5921 11.3424C12.3577 11.5768 12.0398 11.7085 11.7083 11.7085H1.70825C1.37673 11.7085 1.05879 11.5768 0.824368 11.3424C0.589948 11.108 0.458252 10.79 0.458252 10.4585V1.7085C0.458252 1.37698 0.589948 1.05903 0.824368 0.824613C1.05879 0.590192 1.37673 0.458496 1.70825 0.458496H4.83325L6.08325 2.3335H11.7083C12.0398 2.3335 12.3577 2.46519 12.5921 2.69961C12.8266 2.93403 12.9583 3.25198 12.9583 3.5835V10.4585Z\" stroke=\"#6D6D74\" stroke-width=\"0.916667\"/>\n </svg>\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-[#6D6D74]\">{{ modularLabels.organised }}</h3>\n <span class=\"cqa-text-xs cqa-text-[#6D6D74]\">\n {{ rootFolderTiles.length === 1 ? modularLabels.foldersCountSingular : modularLabels.foldersCountPlural.replace('{n}', '' + rootFolderTiles.length) }}\n </span>\n </div>\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-2\">\n <button\n *ngFor=\"let f of rootFolderTiles\"\n type=\"button\"\n [cqaFolderDrop]=\"f.id\"\n [dropEnabled]=\"modularConfig.allowTestDragDrop\"\n (testsDropped)=\"onTestsDropped($event)\"\n (click)=\"onFolderSelected(f.id)\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-justify-between cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-white hover:cqa-border-[#3F43EE] hover:cqa-shadow-sm cqa-transition-colors\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-min-w-0\">\n <ng-container *ngTemplateOutlet=\"folderIconChip; context: { color: f.color }\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ f.name }}</span>\n <span *ngIf=\"modularConfig.showCounts\" class=\"cqa-text-sm cqa-text-neutral-500 cqa-truncate\">\n {{ (f.count ?? 0) === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + (f.count ?? 0)) }}<ng-container *ngIf=\"f.children?.length\"> \u00B7 {{ f.children!.length === 1 ? modularLabels.oneSubfolder : modularLabels.subfoldersCount.replace('{n}', '' + f.children!.length) }}</ng-container>\n </span>\n </div>\n </div>\n <mat-icon class=\"cqa-text-neutral-400 cqa-shrink-0\" style=\"font-size:20px;width:20px;height:20px\">chevron_right</mat-icon>\n </button>\n\n <!-- \"+ New folder\" tile -->\n <button\n *ngIf=\"modularConfig.allowCreateFolder\"\n type=\"button\"\n (click)=\"onFolderCreateRequested({ parentId: null })\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-dashed cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-[#FAFAFA] hover:cqa-border-[#3F43EE] hover:cqa-bg-white cqa-transition-colors\"\n >\n <ng-container *ngTemplateOutlet=\"addIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ modularLabels.newFolder }}</span>\n <span class=\"cqa-text-sm cqa-text-neutral-400\">{{ modularLabels.testsCountPlural.replace('{n}', '0') }}</span>\n </div>\n </button>\n </div>\n </section>\n\n <!-- Subfolder section: modular + folder view. Shown whenever drilled in (even if no subfolders, so the \"+ New folder\" tile remains reachable). -->\n <section\n *ngIf=\"isModularView && !isRootView && modularConfig.showSubfolderSection && subfolderTiles.length\"\n class=\"cqa-mb-4 cqa-px-3 cqa-py-1\"\n >\n <div *ngIf=\"subfolderTiles.length || modularConfig.allowCreateFolder\" class=\"cqa-text-sm cqa-text-neutral-600 cqa-mb-2\">\n {{ modularLabels.subfoldersIn }} {{ breadcrumbTrail.length ? breadcrumbTrail[breadcrumbTrail.length - 1].name : '' }}\n </div>\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-2\">\n <button\n *ngFor=\"let f of subfolderTiles\"\n type=\"button\"\n [cqaFolderDrop]=\"f.id\"\n [dropEnabled]=\"modularConfig.allowTestDragDrop\"\n (testsDropped)=\"onTestsDropped($event)\"\n (click)=\"onFolderSelected(f.id)\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-justify-between cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-white hover:cqa-border-[#3F43EE] hover:cqa-shadow-sm cqa-transition-colors\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-min-w-0\">\n <ng-container *ngTemplateOutlet=\"folderIconChip; context: { color: f.color }\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ f.name }}</span>\n <span *ngIf=\"modularConfig.showCounts\" class=\"cqa-text-sm cqa-text-neutral-500 cqa-truncate\">\n {{ (f.count ?? 0) === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + (f.count ?? 0)) }}\n </span>\n </div>\n </div>\n <mat-icon class=\"cqa-text-neutral-400 cqa-shrink-0\" style=\"font-size:20px;width:20px;height:20px\">chevron_right</mat-icon>\n </button>\n\n <!-- \"+ New folder\" tile -->\n <button\n *ngIf=\"modularConfig.allowCreateFolder\"\n type=\"button\"\n (click)=\"onFolderCreateRequested({ parentId: selectedFolderId })\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-dashed cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-[#FAFAFA] hover:cqa-border-[#3F43EE] hover:cqa-bg-white cqa-transition-colors\"\n >\n <ng-container *ngTemplateOutlet=\"addIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ modularLabels.newFolder }}</span>\n <span class=\"cqa-text-sm cqa-text-neutral-400\">{{ modularLabels.testsCountPlural.replace('{n}', '0') }}</span>\n </div>\n </button>\n </div>\n </section>\n\n <!-- Folder panel header above the table: \"Hotel Search (3)\" + Clear filter -->\n <div\n *ngIf=\"isModularView && !isRootView && modularConfig.showUnorganisedSection\"\n class=\"cqa-flex cqa-mb-1 cqa-items-center cqa-justify-between cqa-px-4 cqa-py-3 cqa-rounded-t-lg cqa-bg-indigo-50 cqa-border cqa-border-indigo-100\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9585 10.4585C12.9585 10.79 12.8268 11.108 12.5924 11.3424C12.358 11.5768 12.04 11.7085 11.7085 11.7085H1.7085C1.37698 11.7085 1.05903 11.5768 0.824613 11.3424C0.590192 11.108 0.458496 10.79 0.458496 10.4585V1.7085C0.458496 1.37698 0.590192 1.05903 0.824613 0.824613C1.05903 0.590192 1.37698 0.458496 1.7085 0.458496H4.8335L6.0835 2.3335H11.7085C12.04 2.3335 12.358 2.46519 12.5924 2.69961C12.8268 2.93403 12.9585 3.25198 12.9585 3.5835V10.4585Z\" [attr.stroke]=\"currentFolderNode?.color || '#3F43EE'\" stroke-width=\"0.916667\"/>\n </svg>\n <span class=\"cqa-text-sm cqa-font-semibold cqa-text-indigo-700\">\n {{ currentFolderNode?.name }} ({{ currentFolderDirectCount }})\n </span>\n </div>\n <button\n type=\"button\"\n class=\"cqa-px-3 cqa-py-1 cqa-text-xs cqa-font-medium cqa-text-indigo-700 cqa-bg-white cqa-border cqa-border-indigo-200 cqa-rounded hover:cqa-bg-indigo-50\"\n (click)=\"onFolderSelected(null)\"\n >{{ modularLabels.clearFilter }}</button>\n </div>\n\n <!-- Unorganised section header at root view -->\n <div\n *ngIf=\"isModularView && isRootView && modularConfig.showUnorganisedSection\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2 cqa-mt-2\" style=\"margin-left: 20px;\"\n >\n <mat-icon class=\"cqa-text-[#6D6D74]\" style=\"font-size:16px;width:16px;height:16px\">inbox</mat-icon>\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-[#6D6D74]\">{{ modularLabels.unorganised }}</h3>\n <span class=\"cqa-text-xs cqa-text-[#6D6D74]\">\n {{ unorganisedCount === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + unorganisedCount) }}\n </span>\n </div>\n\n <!-- Table -->\n <div class=\"cqa-rounded-[7px] cqa-overflow-hidden cqa-border-t cqa-border-l cqa-border-r cqa-border-grey-200 cqa-relative cqa-overflow-x-auto\"\n [attr.style]=\"pagedRows && pagedRows.length > 0 ? null : 'border-bottom: none !important'\">\n <ng-container *ngIf=\"(isTableLoading || isTableDataLoading) || (!effectiveIsEmptyState && pagedRows && pagedRows.length > 0); else storyEmptyTpl\">\n <app-dynamic-table\n [style.border-bottom]=\"pagedRows && pagedRows.length > 0 ? '1px solid rgb(226, 226, 227)' : null\"\n [columns]=\"computedColumns\"\n [data]=\"pagedRows\"\n [rowSelectable]=\"rowSelectable\"\n [enableLocalSort]=\"enableLocalSort && !isReordering\"\n [isTableLoading]=\"isTableLoading\"\n [isTableDataLoading]=\"isTableDataLoading\"\n [cellJsonPathGetter]=\"cellJsonPathGetter\"\n [onJsonPathCopiedHandler]=\"onJsonPathCopiedHandler\"\n [enableRowReorder]=\"isReordering\"\n (rowReorder)=\"onRowReorder($event)\"\n (sortChange)=\"sortChange.emit($event)\">\n <ng-template #emptyTableTpl>\n <div class=\"cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-py-8\">\n <img src=\"/assets/illustrations/empty-state.svg\" alt=\"No data\" class=\"cqa-w-32 cqa-h-32 cqa-mb-4\" />\n <h3 class=\"cqa-text-lg cqa-font-semibold cqa-mb-2\">No test cases</h3>\n <p class=\"cqa-text-sm cqa-text-neutral-500 cqa-mb-4\">Try adjusting filters or create a new test case.</p>\n <cqa-button variant=\"filled\" (clicked)=\"toggleFilter()\">Show Filters</cqa-button>\n </div>\n </ng-template>\n </app-dynamic-table>\n </ng-container>\n\n <ng-template #storyEmptyTpl>\n <div class=\"cqa-p-6 cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <cqa-empty-state\n *ngIf=\"effectiveIsEmptyState\"\n [title]=\"effectiveEmptyStateConfig.title\"\n [description]=\"effectiveEmptyStateConfig.description\"\n [imageUrl]=\"effectiveEmptyStateConfig.imageUrl\"\n [actions]=\"effectiveEmptyStateConfig.actions\"\n (actionClick)=\"onEmptyAction($event)\"\n >\n </cqa-empty-state>\n </div>\n </ng-template>\n </div>\n\n <cqa-pagination\n [totalElements]=\"serverSidePagination ? totalElements : filteredRows.length\"\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\"\n [pageSizeMenuDirection]=\"pageSizeMenuDirection\"\n [pageItemCount]=\"pagedRows.length\"\n (paginate)=\"onPaginate($event)\"\n (pageSizeChange)=\"onPageSizeChange($event)\"\n >\n </cqa-pagination>\n </div>\n </div>\n\n <!-- Reused bulk action toolbar -->\n <div *ngIf=\"anyRowSelected && modularConfig.allowBulkSelection && !isReordering\" class=\"cqa-absolute cqa-bottom-[18.75px] cqa-left-[50%] cqa-translate-x-[-50%] cqa-w-full lg:cqa-max-w-[68%] cqa-sm:max-w-[75%] cqa-max-w-[90%] cqa-z-[1]\">\n <cqa-table-action-toolbar\n [selectedItems]=\"selectedItems && selectedItems.length > 0 ? selectedItems : currentSelectedItems\"\n [actions]=\"effectiveBulkActions\"\n [showSelectAll]=\"showSelectAllInToolbar\"\n [allSelected]=\"allSelectedInToolbar\"\n [showDismiss]=\"showDismissInToolbar\"\n (actionClick)=\"onBulkAction($event)\"\n (selectAllChange)=\"onBulkSelectAll($event)\"\n (dismiss)=\"onBulkDismiss()\"\n ></cqa-table-action-toolbar>\n </div>\n\n </div>\n</div>\n\n", components: [{ type: SearchBarComponent, selector: "cqa-search-bar", inputs: ["placeholder", "value", "disabled", "showClear", "ariaLabel", "autoFocus", "size", "fullWidth"], outputs: ["valueChange", "search", "cleared"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "loading", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: ExportCodeModalComponent, selector: "cqa-export-code-modal", inputs: ["isOpen", "cases", "disabled"], outputs: ["closeModal", "export"] }, { type: ColumnVisibilityComponent, selector: "cqa-column-visibility", inputs: ["isStepGroup", "columns", "columnVisibility", "selectedAutoRefreshInterval"], outputs: ["columnVisibilityChange", "autoRefreshChange"] }, { type: SegmentControlComponent, selector: "cqa-segment-control", inputs: ["segments", "value", "disabled", "containerBgColor", "fullWidth", "size"], outputs: ["valueChange"] }, { type: SelectedFiltersComponent, selector: "cqa-selected-filters", inputs: ["filterApplied", "chips", "defaultChips", "defaultChipClass"], outputs: ["removeChip", "clearAll", "onClearAll"] }, { type: DynamicFilterComponent, selector: "cqa-dynamic-filter", inputs: ["config", "model", "showFilterPanel", "buttonLayout"], outputs: ["filtersApplied", "filtersChanged", "resetAction", "onApplyFilterClick", "onResetFilterClick"] }, { type: FolderSidebarComponent, selector: "cqa-folder-sidebar", inputs: ["folders", "selectedFolderId", "expandedFolderIds", "unorganisedCount", "allowCreate", "allowRename", "allowDelete", "allowMove", "allowDuplicate", "allowDrop", "showCounts", "collapsed", "labels"], outputs: ["folderSelected", "folderExpansionToggled", "folderCreated", "folderCreateRequested", "folderRenamed", "folderDeleted", "folderMoveRequested", "folderDuplicateRequested", "testsDropped", "folderDropped", "collapsedChange"] }, { type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: DynamicTableComponent, selector: "app-dynamic-table", inputs: ["data", "columns", "emptyState", "gridTemplateColumns", "screenWidth", "enableSelectAll", "rowSelectable", "enableLocalSort", "isTableLoading", "isTableDataLoading", "cellJsonPathGetter", "onJsonPathCopiedHandler", "enableRowReorder", "reorderHandleTooltip"], outputs: ["sortChange", "rowReorder"] }, { type: EmptyStateComponent, selector: "cqa-empty-state", inputs: ["preset", "imageUrl", "title", "description", "actions"], outputs: ["actionClick"] }, { type: PaginationComponent, selector: "cqa-pagination", inputs: ["totalElements", "totalPages", "pageIndex", "pageSize", "pageItemCount", "pageSizeOptions", "pageSizeMenuDirection"], outputs: ["pageIndexChange", "pageSizeChange", "paginate"] }, { type: TableActionToolbarComponent, selector: "cqa-table-action-toolbar", inputs: ["selectedItems", "actions", "showSelectAll", "allSelected", "showDismiss"], outputs: ["actionClick", "selectAllChange", "dismiss"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: FolderDropDirective, selector: "[cqaFolderDrop]", inputs: ["cqaFolderDrop", "dropEnabled"], outputs: ["testsDropped", "folderDropped"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
10838
10946
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ModularTableTemplateComponent, decorators: [{
10839
10947
  type: Component,
10840
- args: [{ selector: 'cqa-modular-table-template', host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Reusable folder-icon chip. Render via <ng-container *ngTemplateOutlet=\"folderIconChip\"></ng-container>. -->\n<ng-template #folderIconChip>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-10 cqa-h-10 cqa-rounded-lg cqa-bg-[#F0F0F1] cqa-text-[#6D6D74] cqa-shrink-0 group-hover:cqa-bg-indigo-50 group-hover:cqa-text-[#3F43EE]\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9583 10.4585C12.9583 10.79 12.8266 11.108 12.5921 11.3424C12.3577 11.5768 12.0398 11.7085 11.7083 11.7085H1.70825C1.37673 11.7085 1.05879 11.5768 0.824368 11.3424C0.589948 11.108 0.458252 10.79 0.458252 10.4585V1.7085C0.458252 1.37698 0.589948 1.05903 0.824368 0.824613C1.05879 0.590192 1.37673 0.458496 1.70825 0.458496H4.83325L6.08325 2.3335H11.7083C12.0398 2.3335 12.3577 2.46519 12.5921 2.69961C12.8266 2.93403 12.9583 3.25198 12.9583 3.5835V10.4585Z\" stroke=\"currentColor\" stroke-width=\"0.916667\"/>\n </svg>\n </span>\n</ng-template>\n\n<!-- Reusable \"+\" chip used by the \"New folder\" tile. -->\n<ng-template #addIconChip>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-10 cqa-h-10 cqa-rounded-lg cqa-bg-[#F0F0F1] cqa-text-[#6D6D74] cqa-shrink-0 group-hover:cqa-bg-indigo-50 group-hover:cqa-text-[#3F43EE]\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M8 3V13M3 8H13\" stroke=\"currentColor\" stroke-width=\"1.275\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n</ng-template>\n\n<div class=\"cqa-ui-root\">\n <div class=\"cqa-w-full cqa-flex cqa-flex-col cqa-relative\">\n <div [class]=\"!showSearchBar ? 'cqa-justify-end' : 'cqa-justify-between'\" class=\"cqa-w-full cqa-flex cqa-items-center cqa-gap-3 cqa-flex-wrap cqa-mb-3\">\n <cqa-search-bar\n *ngIf=\"showSearchBar\"\n [placeholder]=\"searchPlaceholder\"\n [value]=\"searchValue\"\n [showClear]=\"showClear\"\n (valueChange)=\"valueChange($event)\"\n (search)=\"search($event)\"\n (cleared)=\"cleared()\"\n ></cqa-search-bar>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-flex-wrap\">\n <cqa-button\n *ngIf=\"showExportButton\"\n variant=\"grey-solid\"\n icon=\"open_in_new\"\n [text]=\"isExporting ? 'Exporting...' : 'Export'\"\n [disabled]=\"isExporting\"\n (clicked)=\"exportCodeClick()\"\n >\n <span>{{ isExporting ? 'Exporting...' : 'Export' }}</span>\n </cqa-button>\n \n <!-- Export Code Modal -->\n <cqa-export-code-modal\n *ngIf=\"showExportButton\"\n [isOpen]=\"isExportModalOpen\"\n [cases]=\"selectedCasesForExport\"\n [disabled]=\"false\"\n (closeModal)=\"closeExportModal()\"\n (export)=\"onExportModalExport($event)\">\n </cqa-export-code-modal>\n <ng-container *ngFor=\"let dropdownTemplate of otherDropDownButtons; trackBy: trackByDropdownTemplateRef\">\n <ng-container *ngTemplateOutlet=\"dropdownTemplate\"></ng-container>\n </ng-container>\n\n <ng-container *ngFor=\"let selectDropdownTemplate of otherSelectDropDownButtons; trackBy: trackBySelectDropdownTemplateRef\">\n <ng-container *ngTemplateOutlet=\"selectDropdownTemplate\"></ng-container>\n </ng-container>\n \n <cqa-button\n *ngIf=\"showFilterButton\"\n variant=\"grey-solid\"\n icon=\"add\"\n [disabled]=\"isReordering\"\n (clicked)=\"toggleFilter()\"\n >\n <span class=\"cqa-flex cqa-items-center cqa-gap-1\">\n Filter \n <div [class]=\"arrowClasses\">\n <svg\n class=\"cqa-w-2 cqa-h-1 cqa-absolute cqa-left-[4px] cqa-top-[6px]\"\n viewBox=\"0 0 8 4\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0 0L4 4L8 0\"\n stroke=\"#0B0B0C\"\n stroke-width=\"1.33\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n </span>\n </cqa-button>\n <cqa-column-visibility\n *ngIf=\"showSettingsButton\"\n [columns]=\"visibilityColumns\"\n [columnVisibility]=\"columnVisibility\"\n [selectedAutoRefreshInterval]=\"selectedAutoRefreshInterval\"\n (columnVisibilityChange)=\"onColumnVisibilityChange($event)\"\n (autoRefreshChange)=\"onAutoRefreshChange($event)\"\n ></cqa-column-visibility>\n <cqa-button\n *ngIf=\"showAutoRefreshButton\"\n variant=\"grey-solid\"\n icon=\"refresh\"\n (clicked)=\"handleRefreshClick()\"\n [tooltip]=\"'Refresh'\"\n tooltipPosition=\"below\"\n [disabled]=\"isReordering\"\n ></cqa-button>\n <ng-container *ngFor=\"let buttonTemplate of otherButtons; trackBy: trackByTemplateRef\">\n <ng-container *ngTemplateOutlet=\"buttonTemplate\"></ng-container>\n </ng-container>\n <cqa-segment-control\n *ngIf=\"showViewModeToggle\"\n size=\"lg\"\n [segments]=\"viewModeSegments\"\n [value]=\"viewMode\"\n (valueChange)=\"onViewModeChange($event)\"\n ></cqa-segment-control>\n <cqa-button\n *ngIf=\"showReorderButton && !isReordering\"\n variant=\"outlined\"\n icon=\"drag_indicator\"\n [text]=\"reorderLabels.reorderButton\"\n [disabled]=\"!pagedRows || pagedRows.length === 0 || isTableLoading || isTableDataLoading\"\n (clicked)=\"startReorder()\"\n ></cqa-button>\n <ng-container *ngIf=\"showReorderButton && isReordering\">\n <cqa-button\n variant=\"outlined\"\n [text]=\"reorderLabels.cancelButton\"\n [disabled]=\"reorderSaving\"\n (clicked)=\"cancelReorder()\"\n ></cqa-button>\n <cqa-button\n variant=\"filled\"\n [icon]=\"reorderSaving ? 'hourglass_empty' : ''\"\n [text]=\"reorderSaving ? reorderLabels.savingButton : reorderLabels.doneButton\"\n [disabled]=\"reorderSaving\"\n (clicked)=\"saveReorder()\"\n ></cqa-button>\n </ng-container>\n </div>\n </div>\n\n <!-- Reorder mode banner -->\n <div *ngIf=\"isReordering\" class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-3 cqa-px-3 cqa-py-2 cqa-rounded-md cqa-bg-[#FFFBEB] cqa-border cqa-border-[#FDE68A]\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <circle cx=\"3\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"3\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"3\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n </svg>\n <span class=\"cqa-text-sm cqa-font-semibold cqa-text-[#92400E]\">{{ reorderLabels.bannerTitle }}</span>\n <span class=\"cqa-text-sm cqa-text-[#92400E]\">{{ reorderLabels.bannerDescription }}</span>\n </div>\n\n <cqa-selected-filters\n [filterApplied]=\"filterApplied\"\n [chips]=\"chips\"\n (removeChip)=\"onRemoveChip($event)\"\n (clearAll)=\"onClearAllChips()\"\n (onClearAll)=\"onClearAll.emit()\"\n >\n </cqa-selected-filters>\n\n <cqa-dynamic-filter\n *ngIf=\"showFilterPanel\"\n [config]=\"filterConfig\"\n [model]=\"filterModel\"\n [showFilterPanel]=\"showFilterPanel\"\n (filtersChanged)=\"onFiltersChanged($event)\"\n (filtersApplied)=\"onFiltersApplied($event)\"\n (onApplyFilterClick)=\"onApplyFilterClick.emit($event)\"\n (onResetFilterClick)=\"handleResetFilterClick()\"\n >\n </cqa-dynamic-filter>\n\n <div class=\"cqa-flex cqa-items-stretch cqa-gap-3 cqa-min-h-0\">\n <!-- Sidebar (only shown in modular view) -->\n <cqa-folder-sidebar\n *ngIf=\"isModularView && modularConfig.showSidebar\"\n [folders]=\"folders\"\n [selectedFolderId]=\"selectedFolderId\"\n [expandedFolderIds]=\"expandedFolderIds\"\n [unorganisedCount]=\"unorganisedCount\"\n [allowCreate]=\"modularConfig.allowCreateFolder\"\n [allowRename]=\"modularConfig.allowRenameFolder\"\n [allowDelete]=\"modularConfig.allowDeleteFolder\"\n [allowDrop]=\"modularConfig.allowTestDragDrop\"\n [showCounts]=\"modularConfig.showCounts\"\n [collapsed]=\"sidebarCollapsed\"\n [labels]=\"modularLabels\"\n (folderSelected)=\"onFolderSelected($event)\"\n (folderExpansionToggled)=\"onFolderExpansionToggled($event)\"\n (folderCreated)=\"onFolderCreated($event)\"\n (folderCreateRequested)=\"onFolderCreateRequested($event)\"\n (folderRenamed)=\"onFolderRenamed($event)\"\n (folderDeleted)=\"onFolderDeleted($event)\"\n (folderMoveRequested)=\"onFolderMoveRequested($event)\"\n (folderDuplicateRequested)=\"onFolderDuplicateRequested($event)\"\n (testsDropped)=\"onTestsDropped($event)\"\n (folderDropped)=\"onFolderDropped($event)\"\n (collapsedChange)=\"onSidebarCollapsedChange($event)\"\n ></cqa-folder-sidebar>\n\n <!-- Right pane -->\n <div\n class=\"cqa-flex-1 cqa-flex cqa-flex-col cqa-min-w-0\"\n [style.border-top]=\"isModularView ? '1px solid #E2E2E3' : null\"\n [style.border-left]=\"isModularView ? '1px solid #E2E2E3' : null\"\n [style.border-right]=\"isModularView ? '1px solid #E2E2E3' : null\"\n >\n <!-- Breadcrumb (modular view, folder drilled-in) -->\n <nav\n *ngIf=\"isModularView && modularConfig.showBreadcrumb && !isRootView\"\n aria-label=\"Folder path\"\n class=\"cqa-flex cqa-items-center cqa-gap-1 cqa-text-sm cqa-px-3 cqa-py-1 cqa-mb-3 cqa-rounded-none\"\n style=\"color: #6D6D74; border-bottom: 1px solid #E2E2E3;\"\n >\n <button type=\"button\" class=\"hover:cqa-text-[#3F43EE] cqa-inline-flex cqa-items-center cqa-gap-1\" (click)=\"onFolderSelected(null)\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9583 10.4585C12.9583 10.79 12.8266 11.108 12.5921 11.3424C12.3577 11.5768 12.0398 11.7085 11.7083 11.7085H1.70825C1.37673 11.7085 1.05879 11.5768 0.824368 11.3424C0.589948 11.108 0.458252 10.79 0.458252 10.4585V1.7085C0.458252 1.37698 0.589948 1.05903 0.824368 0.824613C1.05879 0.590192 1.37673 0.458496 1.70825 0.458496H4.83325L6.08325 2.3335H11.7083C12.0398 2.3335 12.3577 2.46519 12.5921 2.69961C12.8266 2.93403 12.9583 3.25198 12.9583 3.5835V10.4585Z\" stroke=\"currentColor\" stroke-width=\"0.916667\"/>\n </svg>\n <span>{{ modularLabels.allFolders }}</span>\n </button>\n <ng-container *ngFor=\"let crumb of breadcrumbTrail; let last = last\">\n <mat-icon class=\"cqa-align-middle\" style=\"font-size:16px;width:16px;height:16px;color:#6D6D74;\">chevron_right</mat-icon>\n <button\n type=\"button\"\n [ngClass]=\"last\n ? 'cqa-text-[#161617] cqa-font-semibold'\n : 'cqa-text-[#6D6D74] hover:cqa-text-[#3F43EE]'\"\n [disabled]=\"last\"\n (click)=\"!last && onFolderSelected(crumb.id)\"\n >{{ crumb.name }}</button>\n </ng-container>\n </nav>\n\n <!-- Folder grid: modular + root view -->\n <section\n *ngIf=\"isModularView && isRootView && modularConfig.showFolderGrid && rootFolderTiles.length\"\n class=\"cqa-mb-4 cqa-px-5 cqa-pt-4 cqa-pb-[14px]\"\n style=\"border-bottom: 1px solid #F0F0F1;\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9583 10.4585C12.9583 10.79 12.8266 11.108 12.5921 11.3424C12.3577 11.5768 12.0398 11.7085 11.7083 11.7085H1.70825C1.37673 11.7085 1.05879 11.5768 0.824368 11.3424C0.589948 11.108 0.458252 10.79 0.458252 10.4585V1.7085C0.458252 1.37698 0.589948 1.05903 0.824368 0.824613C1.05879 0.590192 1.37673 0.458496 1.70825 0.458496H4.83325L6.08325 2.3335H11.7083C12.0398 2.3335 12.3577 2.46519 12.5921 2.69961C12.8266 2.93403 12.9583 3.25198 12.9583 3.5835V10.4585Z\" stroke=\"#6D6D74\" stroke-width=\"0.916667\"/>\n </svg>\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-[#6D6D74]\">{{ modularLabels.organised }}</h3>\n <span class=\"cqa-text-xs cqa-text-[#6D6D74]\">\n {{ rootFolderTiles.length === 1 ? modularLabels.foldersCountSingular : modularLabels.foldersCountPlural.replace('{n}', '' + rootFolderTiles.length) }}\n </span>\n </div>\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-2\">\n <button\n *ngFor=\"let f of rootFolderTiles\"\n type=\"button\"\n [cqaFolderDrop]=\"f.id\"\n [dropEnabled]=\"modularConfig.allowTestDragDrop\"\n (testsDropped)=\"onTestsDropped($event)\"\n (click)=\"onFolderSelected(f.id)\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-justify-between cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-white hover:cqa-border-[#3F43EE] hover:cqa-shadow-sm cqa-transition-colors\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-min-w-0\">\n <ng-container *ngTemplateOutlet=\"folderIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ f.name }}</span>\n <span *ngIf=\"modularConfig.showCounts\" class=\"cqa-text-sm cqa-text-neutral-500 cqa-truncate\">\n {{ (f.count ?? 0) === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + (f.count ?? 0)) }}<ng-container *ngIf=\"f.children?.length\"> \u00B7 {{ f.children!.length === 1 ? modularLabels.oneSubfolder : modularLabels.subfoldersCount.replace('{n}', '' + f.children!.length) }}</ng-container>\n </span>\n </div>\n </div>\n <mat-icon class=\"cqa-text-neutral-400 cqa-shrink-0\" style=\"font-size:20px;width:20px;height:20px\">chevron_right</mat-icon>\n </button>\n\n <!-- \"+ New folder\" tile -->\n <button\n *ngIf=\"modularConfig.allowCreateFolder\"\n type=\"button\"\n (click)=\"onFolderCreateRequested({ parentId: null })\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-dashed cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-[#FAFAFA] hover:cqa-border-[#3F43EE] hover:cqa-bg-white cqa-transition-colors\"\n >\n <ng-container *ngTemplateOutlet=\"addIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ modularLabels.newFolder }}</span>\n <span class=\"cqa-text-sm cqa-text-neutral-400\">{{ modularLabels.testsCountPlural.replace('{n}', '0') }}</span>\n </div>\n </button>\n </div>\n </section>\n\n <!-- Subfolder section: modular + folder view. Shown whenever drilled in (even if no subfolders, so the \"+ New folder\" tile remains reachable). -->\n <section\n *ngIf=\"isModularView && !isRootView && modularConfig.showSubfolderSection && subfolderTiles.length\"\n class=\"cqa-mb-4 cqa-px-3 cqa-py-1\"\n >\n <div *ngIf=\"subfolderTiles.length || modularConfig.allowCreateFolder\" class=\"cqa-text-sm cqa-text-neutral-600 cqa-mb-2\">\n {{ modularLabels.subfoldersIn }} {{ breadcrumbTrail.length ? breadcrumbTrail[breadcrumbTrail.length - 1].name : '' }}\n </div>\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-2\">\n <button\n *ngFor=\"let f of subfolderTiles\"\n type=\"button\"\n [cqaFolderDrop]=\"f.id\"\n [dropEnabled]=\"modularConfig.allowTestDragDrop\"\n (testsDropped)=\"onTestsDropped($event)\"\n (click)=\"onFolderSelected(f.id)\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-justify-between cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-white hover:cqa-border-[#3F43EE] hover:cqa-shadow-sm cqa-transition-colors\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-min-w-0\">\n <ng-container *ngTemplateOutlet=\"folderIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ f.name }}</span>\n <span *ngIf=\"modularConfig.showCounts\" class=\"cqa-text-sm cqa-text-neutral-500 cqa-truncate\">\n {{ (f.count ?? 0) === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + (f.count ?? 0)) }}\n </span>\n </div>\n </div>\n <mat-icon class=\"cqa-text-neutral-400 cqa-shrink-0\" style=\"font-size:20px;width:20px;height:20px\">chevron_right</mat-icon>\n </button>\n\n <!-- \"+ New folder\" tile -->\n <button\n *ngIf=\"modularConfig.allowCreateFolder\"\n type=\"button\"\n (click)=\"onFolderCreateRequested({ parentId: selectedFolderId })\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-dashed cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-[#FAFAFA] hover:cqa-border-[#3F43EE] hover:cqa-bg-white cqa-transition-colors\"\n >\n <ng-container *ngTemplateOutlet=\"addIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ modularLabels.newFolder }}</span>\n <span class=\"cqa-text-sm cqa-text-neutral-400\">{{ modularLabels.testsCountPlural.replace('{n}', '0') }}</span>\n </div>\n </button>\n </div>\n </section>\n\n <!-- Folder panel header above the table: \"Hotel Search (3)\" + Clear filter -->\n <div\n *ngIf=\"isModularView && !isRootView && modularConfig.showUnorganisedSection\"\n class=\"cqa-flex cqa-mb-1 cqa-items-center cqa-justify-between cqa-px-4 cqa-py-3 cqa-rounded-t-lg cqa-bg-indigo-50 cqa-border cqa-border-indigo-100\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9585 10.4585C12.9585 10.79 12.8268 11.108 12.5924 11.3424C12.358 11.5768 12.04 11.7085 11.7085 11.7085H1.7085C1.37698 11.7085 1.05903 11.5768 0.824613 11.3424C0.590192 11.108 0.458496 10.79 0.458496 10.4585V1.7085C0.458496 1.37698 0.590192 1.05903 0.824613 0.824613C1.05903 0.590192 1.37698 0.458496 1.7085 0.458496H4.8335L6.0835 2.3335H11.7085C12.04 2.3335 12.358 2.46519 12.5924 2.69961C12.8268 2.93403 12.9585 3.25198 12.9585 3.5835V10.4585Z\" stroke=\"#3F43EE\" stroke-width=\"0.916667\"/>\n </svg>\n <span class=\"cqa-text-sm cqa-font-semibold cqa-text-indigo-700\">\n {{ currentFolderNode?.name }} ({{ currentFolderDirectCount }})\n </span>\n </div>\n <button\n type=\"button\"\n class=\"cqa-px-3 cqa-py-1 cqa-text-xs cqa-font-medium cqa-text-indigo-700 cqa-bg-white cqa-border cqa-border-indigo-200 cqa-rounded hover:cqa-bg-indigo-50\"\n (click)=\"onFolderSelected(null)\"\n >{{ modularLabels.clearFilter }}</button>\n </div>\n\n <!-- Unorganised section header at root view -->\n <div\n *ngIf=\"isModularView && isRootView && modularConfig.showUnorganisedSection\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2 cqa-mt-2\" style=\"margin-left: 20px;\"\n >\n <mat-icon class=\"cqa-text-[#6D6D74]\" style=\"font-size:16px;width:16px;height:16px\">inbox</mat-icon>\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-[#6D6D74]\">{{ modularLabels.unorganised }}</h3>\n <span class=\"cqa-text-xs cqa-text-[#6D6D74]\">\n {{ unorganisedCount === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + unorganisedCount) }}\n </span>\n </div>\n\n <!-- Table -->\n <div class=\"cqa-rounded-[7px] cqa-overflow-hidden cqa-border-t cqa-border-l cqa-border-r cqa-border-grey-200 cqa-relative cqa-overflow-x-auto\">\n <ng-container *ngIf=\"(isTableLoading || isTableDataLoading) || (!effectiveIsEmptyState && pagedRows && pagedRows.length > 0); else storyEmptyTpl\">\n <app-dynamic-table\n [columns]=\"computedColumns\"\n [data]=\"pagedRows\"\n [rowSelectable]=\"rowSelectable\"\n [enableLocalSort]=\"enableLocalSort && !isReordering\"\n [isTableLoading]=\"isTableLoading\"\n [isTableDataLoading]=\"isTableDataLoading\"\n [cellJsonPathGetter]=\"cellJsonPathGetter\"\n [onJsonPathCopiedHandler]=\"onJsonPathCopiedHandler\"\n [enableRowReorder]=\"isReordering\"\n (rowReorder)=\"onRowReorder($event)\"\n (sortChange)=\"sortChange.emit($event)\">\n <ng-template #emptyTableTpl>\n <div class=\"cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-py-8\">\n <img src=\"/assets/illustrations/empty-state.svg\" alt=\"No data\" class=\"cqa-w-32 cqa-h-32 cqa-mb-4\" />\n <h3 class=\"cqa-text-lg cqa-font-semibold cqa-mb-2\">No test cases</h3>\n <p class=\"cqa-text-sm cqa-text-neutral-500 cqa-mb-4\">Try adjusting filters or create a new test case.</p>\n <cqa-button variant=\"filled\" (clicked)=\"toggleFilter()\">Show Filters</cqa-button>\n </div>\n </ng-template>\n </app-dynamic-table>\n </ng-container>\n\n <ng-template #storyEmptyTpl>\n <div class=\"cqa-p-6 cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <cqa-empty-state\n *ngIf=\"effectiveIsEmptyState\"\n [title]=\"effectiveEmptyStateConfig.title\"\n [description]=\"effectiveEmptyStateConfig.description\"\n [imageUrl]=\"effectiveEmptyStateConfig.imageUrl\"\n [actions]=\"effectiveEmptyStateConfig.actions\"\n (actionClick)=\"onEmptyAction($event)\"\n >\n </cqa-empty-state>\n </div>\n </ng-template>\n </div>\n\n <cqa-pagination\n [totalElements]=\"serverSidePagination ? totalElements : filteredRows.length\"\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\"\n [pageSizeMenuDirection]=\"pageSizeMenuDirection\"\n [pageItemCount]=\"pagedRows.length\"\n (paginate)=\"onPaginate($event)\"\n (pageSizeChange)=\"onPageSizeChange($event)\"\n >\n </cqa-pagination>\n </div>\n </div>\n\n <!-- Reused bulk action toolbar -->\n <div *ngIf=\"anyRowSelected && modularConfig.allowBulkSelection && !isReordering\" class=\"cqa-absolute cqa-bottom-[18.75px] cqa-left-[50%] cqa-translate-x-[-50%] cqa-w-full lg:cqa-max-w-[68%] cqa-sm:max-w-[75%] cqa-max-w-[90%] cqa-z-[1]\">\n <cqa-table-action-toolbar\n [selectedItems]=\"selectedItems && selectedItems.length > 0 ? selectedItems : currentSelectedItems\"\n [actions]=\"effectiveBulkActions\"\n [showSelectAll]=\"showSelectAllInToolbar\"\n [allSelected]=\"allSelectedInToolbar\"\n [showDismiss]=\"showDismissInToolbar\"\n (actionClick)=\"onBulkAction($event)\"\n (selectAllChange)=\"onBulkSelectAll($event)\"\n (dismiss)=\"onBulkDismiss()\"\n ></cqa-table-action-toolbar>\n </div>\n\n </div>\n</div>\n\n", styles: [] }]
10948
+ args: [{ selector: 'cqa-modular-table-template', host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Reusable folder-icon chip. Render via <ng-container *ngTemplateOutlet=\"folderIconChip; context: { color: f.color }\"></ng-container>. -->\n<ng-template #folderIconChip let-color=\"color\">\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-10 cqa-h-10 cqa-rounded-lg cqa-bg-[#F0F0F1] cqa-text-[#6D6D74] cqa-shrink-0 group-hover:cqa-bg-indigo-50 group-hover:cqa-text-[#3F43EE]\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9583 10.4585C12.9583 10.79 12.8266 11.108 12.5921 11.3424C12.3577 11.5768 12.0398 11.7085 11.7083 11.7085H1.70825C1.37673 11.7085 1.05879 11.5768 0.824368 11.3424C0.589948 11.108 0.458252 10.79 0.458252 10.4585V1.7085C0.458252 1.37698 0.589948 1.05903 0.824368 0.824613C1.05879 0.590192 1.37673 0.458496 1.70825 0.458496H4.83325L6.08325 2.3335H11.7083C12.0398 2.3335 12.3577 2.46519 12.5921 2.69961C12.8266 2.93403 12.9583 3.25198 12.9583 3.5835V10.4585Z\" [attr.stroke]=\"color || 'currentColor'\" stroke-width=\"0.916667\"/>\n </svg>\n </span>\n</ng-template>\n\n<!-- Reusable \"+\" chip used by the \"New folder\" tile. -->\n<ng-template #addIconChip>\n <span class=\"cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-10 cqa-h-10 cqa-rounded-lg cqa-bg-[#F0F0F1] cqa-text-[#6D6D74] cqa-shrink-0 group-hover:cqa-bg-indigo-50 group-hover:cqa-text-[#3F43EE]\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M8 3V13M3 8H13\" stroke=\"currentColor\" stroke-width=\"1.275\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n</ng-template>\n\n<div class=\"cqa-ui-root\">\n <div class=\"cqa-w-full cqa-flex cqa-flex-col cqa-relative\">\n <div [class]=\"!showSearchBar ? 'cqa-justify-end' : 'cqa-justify-between'\" class=\"cqa-w-full cqa-flex cqa-items-center cqa-gap-3 cqa-flex-wrap cqa-mb-3\">\n <cqa-search-bar\n *ngIf=\"showSearchBar\"\n [placeholder]=\"searchPlaceholder\"\n [value]=\"searchValue\"\n [showClear]=\"showClear\"\n (valueChange)=\"valueChange($event)\"\n (search)=\"search($event)\"\n (cleared)=\"cleared()\"\n ></cqa-search-bar>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-flex-wrap\">\n <cqa-button\n *ngIf=\"showExportButton\"\n variant=\"grey-solid\"\n icon=\"open_in_new\"\n [text]=\"isExporting ? 'Exporting...' : 'Export'\"\n [disabled]=\"isExporting\"\n (clicked)=\"exportCodeClick()\"\n >\n <span>{{ isExporting ? 'Exporting...' : 'Export' }}</span>\n </cqa-button>\n \n <!-- Export Code Modal -->\n <cqa-export-code-modal\n *ngIf=\"showExportButton\"\n [isOpen]=\"isExportModalOpen\"\n [cases]=\"selectedCasesForExport\"\n [disabled]=\"false\"\n (closeModal)=\"closeExportModal()\"\n (export)=\"onExportModalExport($event)\">\n </cqa-export-code-modal>\n <ng-container *ngFor=\"let dropdownTemplate of otherDropDownButtons; trackBy: trackByDropdownTemplateRef\">\n <ng-container *ngTemplateOutlet=\"dropdownTemplate\"></ng-container>\n </ng-container>\n\n <ng-container *ngFor=\"let selectDropdownTemplate of otherSelectDropDownButtons; trackBy: trackBySelectDropdownTemplateRef\">\n <ng-container *ngTemplateOutlet=\"selectDropdownTemplate\"></ng-container>\n </ng-container>\n \n <cqa-button\n *ngIf=\"showFilterButton\"\n variant=\"grey-solid\"\n icon=\"add\"\n [disabled]=\"isReordering\"\n (clicked)=\"toggleFilter()\"\n >\n <span class=\"cqa-flex cqa-items-center cqa-gap-1\">\n Filter \n <div [class]=\"arrowClasses\">\n <svg\n class=\"cqa-w-2 cqa-h-1 cqa-absolute cqa-left-[4px] cqa-top-[6px]\"\n viewBox=\"0 0 8 4\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M0 0L4 4L8 0\"\n stroke=\"#0B0B0C\"\n stroke-width=\"1.33\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n </span>\n </cqa-button>\n <cqa-column-visibility\n *ngIf=\"showSettingsButton\"\n [columns]=\"visibilityColumns\"\n [columnVisibility]=\"columnVisibility\"\n [selectedAutoRefreshInterval]=\"selectedAutoRefreshInterval\"\n (columnVisibilityChange)=\"onColumnVisibilityChange($event)\"\n (autoRefreshChange)=\"onAutoRefreshChange($event)\"\n ></cqa-column-visibility>\n <cqa-button\n *ngIf=\"showAutoRefreshButton\"\n variant=\"grey-solid\"\n icon=\"refresh\"\n (clicked)=\"handleRefreshClick()\"\n [tooltip]=\"'Refresh'\"\n tooltipPosition=\"below\"\n [disabled]=\"isReordering\"\n ></cqa-button>\n <ng-container *ngFor=\"let buttonTemplate of otherButtons; trackBy: trackByTemplateRef\">\n <ng-container *ngTemplateOutlet=\"buttonTemplate\"></ng-container>\n </ng-container>\n <cqa-segment-control\n *ngIf=\"showViewModeToggle\"\n size=\"lg\"\n [segments]=\"viewModeSegments\"\n [value]=\"viewMode\"\n (valueChange)=\"onViewModeChange($event)\"\n ></cqa-segment-control>\n <cqa-button\n *ngIf=\"showReorderButton && !isReordering\"\n variant=\"outlined\"\n icon=\"drag_indicator\"\n [text]=\"reorderLabels.reorderButton\"\n [disabled]=\"!pagedRows || pagedRows.length === 0 || isTableLoading || isTableDataLoading\"\n (clicked)=\"startReorder()\"\n ></cqa-button>\n <ng-container *ngIf=\"showReorderButton && isReordering\">\n <cqa-button\n variant=\"outlined\"\n [text]=\"reorderLabels.cancelButton\"\n [disabled]=\"reorderSaving\"\n (clicked)=\"cancelReorder()\"\n ></cqa-button>\n <cqa-button\n variant=\"filled\"\n [icon]=\"reorderSaving ? 'hourglass_empty' : ''\"\n [text]=\"reorderSaving ? reorderLabels.savingButton : reorderLabels.doneButton\"\n [disabled]=\"reorderSaving\"\n (clicked)=\"saveReorder()\"\n ></cqa-button>\n </ng-container>\n </div>\n </div>\n\n <!-- Reorder mode banner -->\n <div *ngIf=\"isReordering\" class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-3 cqa-px-3 cqa-py-2 cqa-rounded-md cqa-bg-[#FFFBEB] cqa-border cqa-border-[#FDE68A]\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <circle cx=\"3\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"3\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"3\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"8\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"3\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"8\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n <circle cx=\"13\" cy=\"13\" r=\"1.5\" fill=\"#92400E\"></circle>\n </svg>\n <span class=\"cqa-text-sm cqa-font-semibold cqa-text-[#92400E]\">{{ reorderLabels.bannerTitle }}</span>\n <span class=\"cqa-text-sm cqa-text-[#92400E]\">{{ reorderLabels.bannerDescription }}</span>\n </div>\n\n <cqa-selected-filters\n [filterApplied]=\"filterApplied\"\n [chips]=\"chips\"\n (removeChip)=\"onRemoveChip($event)\"\n (clearAll)=\"onClearAllChips()\"\n (onClearAll)=\"onClearAll.emit()\"\n >\n </cqa-selected-filters>\n\n <cqa-dynamic-filter\n *ngIf=\"showFilterPanel\"\n [config]=\"filterConfig\"\n [model]=\"filterModel\"\n [showFilterPanel]=\"showFilterPanel\"\n (filtersChanged)=\"onFiltersChanged($event)\"\n (filtersApplied)=\"onFiltersApplied($event)\"\n (onApplyFilterClick)=\"onApplyFilterClick.emit($event)\"\n (onResetFilterClick)=\"handleResetFilterClick()\"\n >\n </cqa-dynamic-filter>\n\n <div class=\"cqa-flex cqa-items-stretch cqa-gap-3 cqa-min-h-0 \" style=\"border-bottom: 1px solid rgb(226, 226, 227);\">\n <!-- Sidebar (only shown in modular view) -->\n <cqa-folder-sidebar\n *ngIf=\"isModularView && modularConfig.showSidebar\"\n [folders]=\"folders\"\n [selectedFolderId]=\"selectedFolderId\"\n [expandedFolderIds]=\"expandedFolderIds\"\n [unorganisedCount]=\"unorganisedCount\"\n [allowCreate]=\"modularConfig.allowCreateFolder\"\n [allowRename]=\"modularConfig.allowRenameFolder\"\n [allowDelete]=\"modularConfig.allowDeleteFolder\"\n [allowDrop]=\"modularConfig.allowTestDragDrop\"\n [showCounts]=\"modularConfig.showCounts\"\n [collapsed]=\"sidebarCollapsed\"\n [labels]=\"modularLabels\"\n (folderSelected)=\"onFolderSelected($event)\"\n (folderExpansionToggled)=\"onFolderExpansionToggled($event)\"\n (folderCreated)=\"onFolderCreated($event)\"\n (folderCreateRequested)=\"onFolderCreateRequested($event)\"\n (folderRenamed)=\"onFolderRenamed($event)\"\n (folderDeleted)=\"onFolderDeleted($event)\"\n (folderMoveRequested)=\"onFolderMoveRequested($event)\"\n (folderDuplicateRequested)=\"onFolderDuplicateRequested($event)\"\n (testsDropped)=\"onTestsDropped($event)\"\n (folderDropped)=\"onFolderDropped($event)\"\n (collapsedChange)=\"onSidebarCollapsedChange($event)\"\n ></cqa-folder-sidebar>\n\n <!-- Right pane -->\n <div\n class=\"cqa-flex-1 cqa-flex cqa-flex-col cqa-min-w-0\"\n [style.border-top]=\"isModularView ? '1px solid #E2E2E3' : null\"\n [style.border-left]=\"isModularView ? '1px solid #E2E2E3' : null\"\n [style.border-right]=\"isModularView ? '1px solid #E2E2E3' : null\"\n >\n <!-- Breadcrumb (modular view, folder drilled-in) -->\n <nav\n *ngIf=\"isModularView && modularConfig.showBreadcrumb && !isRootView\"\n aria-label=\"Folder path\"\n class=\"cqa-flex cqa-items-center cqa-gap-1 cqa-text-sm cqa-px-3 cqa-py-1 cqa-mb-3 cqa-rounded-none\"\n style=\"color: #6D6D74; border-bottom: 1px solid #E2E2E3;\"\n >\n <button type=\"button\" class=\"hover:cqa-text-[#3F43EE] cqa-inline-flex cqa-items-center cqa-gap-1\" (click)=\"onFolderSelected(null)\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9583 10.4585C12.9583 10.79 12.8266 11.108 12.5921 11.3424C12.3577 11.5768 12.0398 11.7085 11.7083 11.7085H1.70825C1.37673 11.7085 1.05879 11.5768 0.824368 11.3424C0.589948 11.108 0.458252 10.79 0.458252 10.4585V1.7085C0.458252 1.37698 0.589948 1.05903 0.824368 0.824613C1.05879 0.590192 1.37673 0.458496 1.70825 0.458496H4.83325L6.08325 2.3335H11.7083C12.0398 2.3335 12.3577 2.46519 12.5921 2.69961C12.8266 2.93403 12.9583 3.25198 12.9583 3.5835V10.4585Z\" stroke=\"currentColor\" stroke-width=\"0.916667\"/>\n </svg>\n <span>{{ modularLabels.allFolders }}</span>\n </button>\n <ng-container *ngFor=\"let crumb of breadcrumbTrail; let last = last\">\n <mat-icon class=\"cqa-align-middle\" style=\"font-size:16px;width:16px;height:16px;color:#6D6D74;\">chevron_right</mat-icon>\n <button\n type=\"button\"\n [ngClass]=\"last\n ? 'cqa-text-[#161617] cqa-font-semibold'\n : 'cqa-text-[#6D6D74] hover:cqa-text-[#3F43EE]'\"\n [disabled]=\"last\"\n (click)=\"!last && onFolderSelected(crumb.id)\"\n >{{ crumb.name }}</button>\n </ng-container>\n </nav>\n\n <!-- Folder grid: modular + root view -->\n <section\n *ngIf=\"isModularView && isRootView && modularConfig.showFolderGrid && rootFolderTiles.length\"\n class=\"cqa-mb-4 cqa-px-5 cqa-pt-4 cqa-pb-[14px]\"\n style=\"border-bottom: 1px solid #F0F0F1;\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9583 10.4585C12.9583 10.79 12.8266 11.108 12.5921 11.3424C12.3577 11.5768 12.0398 11.7085 11.7083 11.7085H1.70825C1.37673 11.7085 1.05879 11.5768 0.824368 11.3424C0.589948 11.108 0.458252 10.79 0.458252 10.4585V1.7085C0.458252 1.37698 0.589948 1.05903 0.824368 0.824613C1.05879 0.590192 1.37673 0.458496 1.70825 0.458496H4.83325L6.08325 2.3335H11.7083C12.0398 2.3335 12.3577 2.46519 12.5921 2.69961C12.8266 2.93403 12.9583 3.25198 12.9583 3.5835V10.4585Z\" stroke=\"#6D6D74\" stroke-width=\"0.916667\"/>\n </svg>\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-[#6D6D74]\">{{ modularLabels.organised }}</h3>\n <span class=\"cqa-text-xs cqa-text-[#6D6D74]\">\n {{ rootFolderTiles.length === 1 ? modularLabels.foldersCountSingular : modularLabels.foldersCountPlural.replace('{n}', '' + rootFolderTiles.length) }}\n </span>\n </div>\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-2\">\n <button\n *ngFor=\"let f of rootFolderTiles\"\n type=\"button\"\n [cqaFolderDrop]=\"f.id\"\n [dropEnabled]=\"modularConfig.allowTestDragDrop\"\n (testsDropped)=\"onTestsDropped($event)\"\n (click)=\"onFolderSelected(f.id)\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-justify-between cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-white hover:cqa-border-[#3F43EE] hover:cqa-shadow-sm cqa-transition-colors\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-min-w-0\">\n <ng-container *ngTemplateOutlet=\"folderIconChip; context: { color: f.color }\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ f.name }}</span>\n <span *ngIf=\"modularConfig.showCounts\" class=\"cqa-text-sm cqa-text-neutral-500 cqa-truncate\">\n {{ (f.count ?? 0) === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + (f.count ?? 0)) }}<ng-container *ngIf=\"f.children?.length\"> \u00B7 {{ f.children!.length === 1 ? modularLabels.oneSubfolder : modularLabels.subfoldersCount.replace('{n}', '' + f.children!.length) }}</ng-container>\n </span>\n </div>\n </div>\n <mat-icon class=\"cqa-text-neutral-400 cqa-shrink-0\" style=\"font-size:20px;width:20px;height:20px\">chevron_right</mat-icon>\n </button>\n\n <!-- \"+ New folder\" tile -->\n <button\n *ngIf=\"modularConfig.allowCreateFolder\"\n type=\"button\"\n (click)=\"onFolderCreateRequested({ parentId: null })\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-dashed cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-[#FAFAFA] hover:cqa-border-[#3F43EE] hover:cqa-bg-white cqa-transition-colors\"\n >\n <ng-container *ngTemplateOutlet=\"addIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ modularLabels.newFolder }}</span>\n <span class=\"cqa-text-sm cqa-text-neutral-400\">{{ modularLabels.testsCountPlural.replace('{n}', '0') }}</span>\n </div>\n </button>\n </div>\n </section>\n\n <!-- Subfolder section: modular + folder view. Shown whenever drilled in (even if no subfolders, so the \"+ New folder\" tile remains reachable). -->\n <section\n *ngIf=\"isModularView && !isRootView && modularConfig.showSubfolderSection && subfolderTiles.length\"\n class=\"cqa-mb-4 cqa-px-3 cqa-py-1\"\n >\n <div *ngIf=\"subfolderTiles.length || modularConfig.allowCreateFolder\" class=\"cqa-text-sm cqa-text-neutral-600 cqa-mb-2\">\n {{ modularLabels.subfoldersIn }} {{ breadcrumbTrail.length ? breadcrumbTrail[breadcrumbTrail.length - 1].name : '' }}\n </div>\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-2\">\n <button\n *ngFor=\"let f of subfolderTiles\"\n type=\"button\"\n [cqaFolderDrop]=\"f.id\"\n [dropEnabled]=\"modularConfig.allowTestDragDrop\"\n (testsDropped)=\"onTestsDropped($event)\"\n (click)=\"onFolderSelected(f.id)\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-justify-between cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-solid cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-white hover:cqa-border-[#3F43EE] hover:cqa-shadow-sm cqa-transition-colors\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-min-w-0\">\n <ng-container *ngTemplateOutlet=\"folderIconChip; context: { color: f.color }\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ f.name }}</span>\n <span *ngIf=\"modularConfig.showCounts\" class=\"cqa-text-sm cqa-text-neutral-500 cqa-truncate\">\n {{ (f.count ?? 0) === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + (f.count ?? 0)) }}\n </span>\n </div>\n </div>\n <mat-icon class=\"cqa-text-neutral-400 cqa-shrink-0\" style=\"font-size:20px;width:20px;height:20px\">chevron_right</mat-icon>\n </button>\n\n <!-- \"+ New folder\" tile -->\n <button\n *ngIf=\"modularConfig.allowCreateFolder\"\n type=\"button\"\n (click)=\"onFolderCreateRequested({ parentId: selectedFolderId })\"\n class=\"cqa-group cqa-shrink-0 cqa-w-[240px] cqa-flex cqa-items-center cqa-gap-3 cqa-text-left cqa-p-3 cqa-rounded-[10px] cqa-border-dashed cqa-border-[0.5px] cqa-border-[#E2E2E3] cqa-bg-[#FAFAFA] hover:cqa-border-[#3F43EE] hover:cqa-bg-white cqa-transition-colors\"\n >\n <ng-container *ngTemplateOutlet=\"addIconChip\"></ng-container>\n <div class=\"cqa-flex cqa-flex-col cqa-min-w-0\">\n <span class=\"cqa-text-[15px] cqa-text-[#161617] cqa-truncate cqa-leading-tight group-hover:cqa-text-[#3F43EE]\">{{ modularLabels.newFolder }}</span>\n <span class=\"cqa-text-sm cqa-text-neutral-400\">{{ modularLabels.testsCountPlural.replace('{n}', '0') }}</span>\n </div>\n </button>\n </div>\n </section>\n\n <!-- Folder panel header above the table: \"Hotel Search (3)\" + Clear filter -->\n <div\n *ngIf=\"isModularView && !isRootView && modularConfig.showUnorganisedSection\"\n class=\"cqa-flex cqa-mb-1 cqa-items-center cqa-justify-between cqa-px-4 cqa-py-3 cqa-rounded-t-lg cqa-bg-indigo-50 cqa-border cqa-border-indigo-100\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9585 10.4585C12.9585 10.79 12.8268 11.108 12.5924 11.3424C12.358 11.5768 12.04 11.7085 11.7085 11.7085H1.7085C1.37698 11.7085 1.05903 11.5768 0.824613 11.3424C0.590192 11.108 0.458496 10.79 0.458496 10.4585V1.7085C0.458496 1.37698 0.590192 1.05903 0.824613 0.824613C1.05903 0.590192 1.37698 0.458496 1.7085 0.458496H4.8335L6.0835 2.3335H11.7085C12.04 2.3335 12.358 2.46519 12.5924 2.69961C12.8268 2.93403 12.9585 3.25198 12.9585 3.5835V10.4585Z\" [attr.stroke]=\"currentFolderNode?.color || '#3F43EE'\" stroke-width=\"0.916667\"/>\n </svg>\n <span class=\"cqa-text-sm cqa-font-semibold cqa-text-indigo-700\">\n {{ currentFolderNode?.name }} ({{ currentFolderDirectCount }})\n </span>\n </div>\n <button\n type=\"button\"\n class=\"cqa-px-3 cqa-py-1 cqa-text-xs cqa-font-medium cqa-text-indigo-700 cqa-bg-white cqa-border cqa-border-indigo-200 cqa-rounded hover:cqa-bg-indigo-50\"\n (click)=\"onFolderSelected(null)\"\n >{{ modularLabels.clearFilter }}</button>\n </div>\n\n <!-- Unorganised section header at root view -->\n <div\n *ngIf=\"isModularView && isRootView && modularConfig.showUnorganisedSection\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2 cqa-mt-2\" style=\"margin-left: 20px;\"\n >\n <mat-icon class=\"cqa-text-[#6D6D74]\" style=\"font-size:16px;width:16px;height:16px\">inbox</mat-icon>\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-[#6D6D74]\">{{ modularLabels.unorganised }}</h3>\n <span class=\"cqa-text-xs cqa-text-[#6D6D74]\">\n {{ unorganisedCount === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + unorganisedCount) }}\n </span>\n </div>\n\n <!-- Table -->\n <div class=\"cqa-rounded-[7px] cqa-overflow-hidden cqa-border-t cqa-border-l cqa-border-r cqa-border-grey-200 cqa-relative cqa-overflow-x-auto\"\n [attr.style]=\"pagedRows && pagedRows.length > 0 ? null : 'border-bottom: none !important'\">\n <ng-container *ngIf=\"(isTableLoading || isTableDataLoading) || (!effectiveIsEmptyState && pagedRows && pagedRows.length > 0); else storyEmptyTpl\">\n <app-dynamic-table\n [style.border-bottom]=\"pagedRows && pagedRows.length > 0 ? '1px solid rgb(226, 226, 227)' : null\"\n [columns]=\"computedColumns\"\n [data]=\"pagedRows\"\n [rowSelectable]=\"rowSelectable\"\n [enableLocalSort]=\"enableLocalSort && !isReordering\"\n [isTableLoading]=\"isTableLoading\"\n [isTableDataLoading]=\"isTableDataLoading\"\n [cellJsonPathGetter]=\"cellJsonPathGetter\"\n [onJsonPathCopiedHandler]=\"onJsonPathCopiedHandler\"\n [enableRowReorder]=\"isReordering\"\n (rowReorder)=\"onRowReorder($event)\"\n (sortChange)=\"sortChange.emit($event)\">\n <ng-template #emptyTableTpl>\n <div class=\"cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-py-8\">\n <img src=\"/assets/illustrations/empty-state.svg\" alt=\"No data\" class=\"cqa-w-32 cqa-h-32 cqa-mb-4\" />\n <h3 class=\"cqa-text-lg cqa-font-semibold cqa-mb-2\">No test cases</h3>\n <p class=\"cqa-text-sm cqa-text-neutral-500 cqa-mb-4\">Try adjusting filters or create a new test case.</p>\n <cqa-button variant=\"filled\" (clicked)=\"toggleFilter()\">Show Filters</cqa-button>\n </div>\n </ng-template>\n </app-dynamic-table>\n </ng-container>\n\n <ng-template #storyEmptyTpl>\n <div class=\"cqa-p-6 cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <cqa-empty-state\n *ngIf=\"effectiveIsEmptyState\"\n [title]=\"effectiveEmptyStateConfig.title\"\n [description]=\"effectiveEmptyStateConfig.description\"\n [imageUrl]=\"effectiveEmptyStateConfig.imageUrl\"\n [actions]=\"effectiveEmptyStateConfig.actions\"\n (actionClick)=\"onEmptyAction($event)\"\n >\n </cqa-empty-state>\n </div>\n </ng-template>\n </div>\n\n <cqa-pagination\n [totalElements]=\"serverSidePagination ? totalElements : filteredRows.length\"\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\"\n [pageSizeMenuDirection]=\"pageSizeMenuDirection\"\n [pageItemCount]=\"pagedRows.length\"\n (paginate)=\"onPaginate($event)\"\n (pageSizeChange)=\"onPageSizeChange($event)\"\n >\n </cqa-pagination>\n </div>\n </div>\n\n <!-- Reused bulk action toolbar -->\n <div *ngIf=\"anyRowSelected && modularConfig.allowBulkSelection && !isReordering\" class=\"cqa-absolute cqa-bottom-[18.75px] cqa-left-[50%] cqa-translate-x-[-50%] cqa-w-full lg:cqa-max-w-[68%] cqa-sm:max-w-[75%] cqa-max-w-[90%] cqa-z-[1]\">\n <cqa-table-action-toolbar\n [selectedItems]=\"selectedItems && selectedItems.length > 0 ? selectedItems : currentSelectedItems\"\n [actions]=\"effectiveBulkActions\"\n [showSelectAll]=\"showSelectAllInToolbar\"\n [allSelected]=\"allSelectedInToolbar\"\n [showDismiss]=\"showDismissInToolbar\"\n (actionClick)=\"onBulkAction($event)\"\n (selectAllChange)=\"onBulkSelectAll($event)\"\n (dismiss)=\"onBulkDismiss()\"\n ></cqa-table-action-toolbar>\n </div>\n\n </div>\n</div>\n\n", styles: [] }]
10841
10949
  }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: DialogService }]; }, propDecorators: { searchPlaceholder: [{
10842
10950
  type: Input
10843
10951
  }], searchValue: [{
@@ -53323,5 +53431,5 @@ function buildTestCaseDetailsFromApi(data, options) {
53323
53431
  * Generated bundle index. Do not edit.
53324
53432
  */
53325
53433
 
53326
- export { ADVANCED_SUBFIELDS_BY_TYPE, ADVANCED_TOGGLE_KEYS, AIActionStepComponent, AIAgentStepComponent, ALL_FILTER_VALUE, API_EDIT_STEP_LABELS, ActionMenuButtonComponent, AddPrerequisiteCasesSectionComponent, AdvancedVariablesFormComponent, AiDebugAlertComponent, AiLogsWithReasoningComponent, AiPromptCardComponent, AiReasoningComponent, ApiEditStepComponent, ApiMockingCardComponent, ApiStepComponent, AssignEnvironmentsDialogComponent, AuditLogDrawerComponent, AuditLogDrawerService, AuditLogEntryCardComponent, AutocompleteComponent, BadgeComponent, BasicStepComponent, BreakpointsModalComponent, ButtonComponent, CUSTOM_EDIT_STEP_DATA, CUSTOM_EDIT_STEP_EDIT_IN_DEPTH, CUSTOM_EDIT_STEP_REF, CUSTOM_ELEMENT_POPUP_REF, CaptureVideoDialogComponent, ChangeHistoryComponent, ChartCardComponent, CodeEditorComponent, ColumnVisibilityComponent, CompareRunsComponent, ConditionBranchEditorComponent, ConditionDebugStepComponent, ConditionStepComponent, ConfigurationCardComponent, ConsoleAlertComponent, CoverageModuleCardComponent, CreateStepGroupComponent, CustomEditStepComponent, CustomEditStepRef, CustomEditStepService, CustomInputComponent, CustomTextareaComponent, CustomToggleComponent, DEFAULT_FOLDER_COLOR, DEFAULT_METADATA_COLOR, DEFAULT_MODULAR_CONFIG, DEFAULT_MODULAR_LABELS, DEFAULT_PRIORITY_COLOR_CONFIG, DEFAULT_REORDER_LABELS, DEFAULT_STATUS_COLOR_CONFIG, DIALOG_DATA, DIALOG_REF, DashboardHeaderComponent, DaterangepickerComponent, DaterangepickerDirective, DbQueryExecutionItemComponent, DbVerificationStepComponent, DeleteFolderDialogComponent, DeleteStepsComponent, DetailDrawerComponent, DetailDrawerTabComponent, DetailDrawerTabContentDirective, DetailSidePanelComponent, DialogComponent, DialogRef, DialogService, DocumentVerificationStepComponent, DropdownButtonComponent, DynamicCellContainerDirective, DynamicCellTemplateDirective, DynamicFilterComponent, DynamicHeaderTemplateDirective, DynamicSelectFieldComponent, DynamicTableComponent, ELEMENT_POPUP_DATA, ELEMENT_POPUP_EDIT_IN_DEPTH, EMPTY_STATE_IMAGES, EMPTY_STATE_PRESETS, ENVIRONMENT_ACCENT_COLORS, ElementFormComponent, ElementListComponent, ElementPopupComponent, ElementPopupRef, ElementPopupService, EmptyStateComponent, ErrorModalComponent, ExecutionResultModalComponent, ExportCodeModalComponent, FOLDER_DRAG_MIME, FOLDER_NAME_MAX_LENGTH, FailedStepCardComponent, FailedStepComponent, FailedTestCasesCardComponent, FileDownloadStepComponent, FileUploadComponent, FolderDragDirective, FolderDropDirective, FolderSidebarComponent, FullTableLoaderComponent, HeatErrorMapCellComponent, InsightCardComponent, ItemListComponent, IterationsLoopComponent, JumpToStepModalComponent, LiveConversationComponent, LiveExecutionStepComponent, LoopStepComponent, MONACO_LANGUAGE_MAP, MainStepCollapseComponent, ManageColumnsDialogComponent, MetricsCardComponent, MixedVariableInputComponent, ModularTableTemplateComponent, MoveToFolderDialogComponent, NetworkRequestComponent, NewDbConfigDialogComponent, NewEnvironmentDialogComponent, NewEnvironmentVariableDialogComponent, NewFolderDialogComponent, NewGlobalVariableDialogComponent, NewTestDataProfileDialogComponent, NewVersionHistoryDetailComponent, OtherButtonComponent, PRIORITY_COLORS, PaginationComponent, PermissionToggleComponent, ProgressIndicatorComponent, ProgressTextCardComponent, QuestionnaireListComponent, RESULT_COLORS, ROW_DRAG_MIME, RadioCardGroupComponent, RecordingBannerComponent, ReviewRecordedStepsModalComponent, RowDragDirective, RunExecutionAlertComponent, RunHistoryCardComponent, STATUS_COLORS, STEP_DETAILS_DRAWER_DATA, STEP_DETAILS_DRAWER_REF, STEP_DETAILS_FIELDS_BY_TYPE, STEP_DETAILS_FIELD_META, STEP_DETAILS_MODAL_DATA, STEP_DETAILS_MODAL_REF, SearchBarComponent, SegmentControlComponent, SelectedFiltersComponent, SelfHealAnalysisComponent, SessionChangesModalComponent, SessionRestorationDialogComponent, SimulatorComponent, StepBuilderActionComponent, StepBuilderAiAgentComponent, StepBuilderConditionComponent, StepBuilderCustomCodeComponent, StepBuilderDatabaseComponent, StepBuilderDocumentComponent, StepBuilderDocumentGenerationTemplateStepComponent, StepBuilderGroupComponent, StepBuilderLoopComponent, StepBuilderRecordStepComponent, StepDetailsDrawerComponent, StepDetailsDrawerRef, StepDetailsDrawerService, StepDetailsModalComponent, StepDetailsModalRef, StepDetailsModalService, StepGroupComponent, StepProgressCardComponent, StepRendererComponent, StepStatusCardComponent, StepTypes, StepperComponent, SubStepsConfirmationDialogComponent, TEST_CASE_DETAILS_FIELD_MAP, TEST_CASE_DETAILS_SELECT_KEYS, TEST_DATA_MODAL_DATA, TEST_DATA_MODAL_EDIT_IN_DEPTH, TEST_DATA_MODAL_REF, TableActionToolbarComponent, TableDataLoaderComponent, TableTemplateComponent, TailwindOverlayContainer, TemplateVariablesFormComponent, TestCaseAiAgentStepComponent, TestCaseAiVerifyStepComponent, TestCaseApiStepComponent, TestCaseConditionStepComponent, TestCaseCustomCodeStepComponent, TestCaseDatabaseStepComponent, TestCaseDetailsComponent, TestCaseDetailsEditComponent, TestCaseDetailsRendererComponent, TestCaseLinkCellComponent, TestCaseLoopStepComponent, TestCaseNormalStepComponent, TestCaseRestoreSessionStepComponent, TestCaseScreenshotStepComponent, TestCaseScrollStepComponent, TestCaseStepGroupComponent, TestCaseUploadStepComponent, TestCaseVerifyUrlStepComponent, TestDataModalComponent, TestDataModalRef, TestDataModalService, TestDistributionCardComponent, UiKitModule, UpdatedFailedStepComponent, VersionHistoryCompareComponent, VersionHistoryDetailComponent, VersionHistoryListComponent, VersionHistoryRestoreConfirmComponent, ViewCompareButtonComponent, ViewMoreFailedStepButtonComponent, VisualComparisonComponent, VisualDifferenceModalComponent, WorkspaceSelectorComponent, buildTestCaseDetailsFromApi, getDynamicFieldsFromLegacyConfig, getEmptyStatePreset, getMetadataColor, getMetadataValueStyle, getStepDetailsStepType, humanizeVariableKey, isAiAgentStepConfig, isAiVerifyStepConfig, isApiStepConfig, isConditionStepConfig, isCustomCodeStepConfig, isDatabaseStepConfig, isLoopStepConfig, isNormalStepConfig, isRestoreSessionStepConfig, isScreenshotStepConfig, isScrollStepConfig, isStepGroupConfig, isUploadStepConfig, isVerifyUrlStepConfig, mapApiVariablesToDynamicFields };
53434
+ export { ADVANCED_SUBFIELDS_BY_TYPE, ADVANCED_TOGGLE_KEYS, AIActionStepComponent, AIAgentStepComponent, ALL_FILTER_VALUE, API_EDIT_STEP_LABELS, ActionMenuButtonComponent, AddPrerequisiteCasesSectionComponent, AdvancedVariablesFormComponent, AiDebugAlertComponent, AiLogsWithReasoningComponent, AiPromptCardComponent, AiReasoningComponent, ApiEditStepComponent, ApiMockingCardComponent, ApiStepComponent, AssignEnvironmentsDialogComponent, AuditLogDrawerComponent, AuditLogDrawerService, AuditLogEntryCardComponent, AutocompleteComponent, BadgeComponent, BasicStepComponent, BreakpointsModalComponent, ButtonComponent, CUSTOM_EDIT_STEP_DATA, CUSTOM_EDIT_STEP_EDIT_IN_DEPTH, CUSTOM_EDIT_STEP_REF, CUSTOM_ELEMENT_POPUP_REF, CaptureVideoDialogComponent, ChangeHistoryComponent, ChartCardComponent, CodeEditorComponent, ColumnVisibilityComponent, CompareRunsComponent, ConditionBranchEditorComponent, ConditionDebugStepComponent, ConditionStepComponent, ConfigurationCardComponent, ConsoleAlertComponent, CoverageModuleCardComponent, CreateStepGroupComponent, CustomEditStepComponent, CustomEditStepRef, CustomEditStepService, CustomInputComponent, CustomTextareaComponent, CustomToggleComponent, DEFAULT_FOLDER_COLOR, DEFAULT_METADATA_COLOR, DEFAULT_MODULAR_CONFIG, DEFAULT_MODULAR_LABELS, DEFAULT_PRIORITY_COLOR_CONFIG, DEFAULT_REORDER_LABELS, DEFAULT_STATUS_COLOR_CONFIG, DIALOG_DATA, DIALOG_REF, DashboardHeaderComponent, DaterangepickerComponent, DaterangepickerDirective, DbQueryExecutionItemComponent, DbVerificationStepComponent, DeleteFolderDialogComponent, DeleteStepsComponent, DetailDrawerComponent, DetailDrawerTabComponent, DetailDrawerTabContentDirective, DetailSidePanelComponent, DialogComponent, DialogRef, DialogService, DocumentVerificationStepComponent, DropdownButtonComponent, DynamicCellContainerDirective, DynamicCellTemplateDirective, DynamicFilterComponent, DynamicHeaderTemplateDirective, DynamicSelectFieldComponent, DynamicTableComponent, ELEMENT_POPUP_DATA, ELEMENT_POPUP_EDIT_IN_DEPTH, EMPTY_STATE_IMAGES, EMPTY_STATE_PRESETS, ENVIRONMENT_ACCENT_COLORS, ElementFormComponent, ElementListComponent, ElementPopupComponent, ElementPopupRef, ElementPopupService, EmptyStateComponent, ErrorModalComponent, ExecutionResultModalComponent, ExportCodeModalComponent, FOLDER_COLUMN_FIELD_ID, FOLDER_DRAG_MIME, FOLDER_NAME_MAX_LENGTH, FailedStepCardComponent, FailedStepComponent, FailedTestCasesCardComponent, FileDownloadStepComponent, FileUploadComponent, FolderDragDirective, FolderDropDirective, FolderSidebarComponent, FullTableLoaderComponent, HeatErrorMapCellComponent, InsightCardComponent, ItemListComponent, IterationsLoopComponent, JumpToStepModalComponent, LiveConversationComponent, LiveExecutionStepComponent, LoopStepComponent, MONACO_LANGUAGE_MAP, MainStepCollapseComponent, ManageColumnsDialogComponent, MetricsCardComponent, MixedVariableInputComponent, ModularTableTemplateComponent, MoveToFolderDialogComponent, NetworkRequestComponent, NewDbConfigDialogComponent, NewEnvironmentDialogComponent, NewEnvironmentVariableDialogComponent, NewFolderDialogComponent, NewGlobalVariableDialogComponent, NewTestDataProfileDialogComponent, NewVersionHistoryDetailComponent, OtherButtonComponent, PRIORITY_COLORS, PaginationComponent, PermissionToggleComponent, ProgressIndicatorComponent, ProgressTextCardComponent, QuestionnaireListComponent, RESULT_COLORS, ROW_DRAG_MIME, RadioCardGroupComponent, RecordingBannerComponent, ReviewRecordedStepsModalComponent, RowDragDirective, RunExecutionAlertComponent, RunHistoryCardComponent, STATUS_COLORS, STEP_DETAILS_DRAWER_DATA, STEP_DETAILS_DRAWER_REF, STEP_DETAILS_FIELDS_BY_TYPE, STEP_DETAILS_FIELD_META, STEP_DETAILS_MODAL_DATA, STEP_DETAILS_MODAL_REF, SearchBarComponent, SegmentControlComponent, SelectedFiltersComponent, SelfHealAnalysisComponent, SessionChangesModalComponent, SessionRestorationDialogComponent, SimulatorComponent, StepBuilderActionComponent, StepBuilderAiAgentComponent, StepBuilderConditionComponent, StepBuilderCustomCodeComponent, StepBuilderDatabaseComponent, StepBuilderDocumentComponent, StepBuilderDocumentGenerationTemplateStepComponent, StepBuilderGroupComponent, StepBuilderLoopComponent, StepBuilderRecordStepComponent, StepDetailsDrawerComponent, StepDetailsDrawerRef, StepDetailsDrawerService, StepDetailsModalComponent, StepDetailsModalRef, StepDetailsModalService, StepGroupComponent, StepProgressCardComponent, StepRendererComponent, StepStatusCardComponent, StepTypes, StepperComponent, SubStepsConfirmationDialogComponent, TEST_CASE_DETAILS_FIELD_MAP, TEST_CASE_DETAILS_SELECT_KEYS, TEST_DATA_MODAL_DATA, TEST_DATA_MODAL_EDIT_IN_DEPTH, TEST_DATA_MODAL_REF, TableActionToolbarComponent, TableDataLoaderComponent, TableTemplateComponent, TailwindOverlayContainer, TemplateVariablesFormComponent, TestCaseAiAgentStepComponent, TestCaseAiVerifyStepComponent, TestCaseApiStepComponent, TestCaseConditionStepComponent, TestCaseCustomCodeStepComponent, TestCaseDatabaseStepComponent, TestCaseDetailsComponent, TestCaseDetailsEditComponent, TestCaseDetailsRendererComponent, TestCaseLinkCellComponent, TestCaseLoopStepComponent, TestCaseNormalStepComponent, TestCaseRestoreSessionStepComponent, TestCaseScreenshotStepComponent, TestCaseScrollStepComponent, TestCaseStepGroupComponent, TestCaseUploadStepComponent, TestCaseVerifyUrlStepComponent, TestDataModalComponent, TestDataModalRef, TestDataModalService, TestDistributionCardComponent, UiKitModule, UpdatedFailedStepComponent, VersionHistoryCompareComponent, VersionHistoryDetailComponent, VersionHistoryListComponent, VersionHistoryRestoreConfirmComponent, ViewCompareButtonComponent, ViewMoreFailedStepButtonComponent, VisualComparisonComponent, VisualDifferenceModalComponent, WorkspaceSelectorComponent, buildTestCaseDetailsFromApi, getDynamicFieldsFromLegacyConfig, getEmptyStatePreset, getMetadataColor, getMetadataValueStyle, getStepDetailsStepType, humanizeVariableKey, isAiAgentStepConfig, isAiVerifyStepConfig, isApiStepConfig, isConditionStepConfig, isCustomCodeStepConfig, isDatabaseStepConfig, isLoopStepConfig, isNormalStepConfig, isRestoreSessionStepConfig, isScreenshotStepConfig, isScrollStepConfig, isStepGroupConfig, isUploadStepConfig, isVerifyUrlStepConfig, mapApiVariablesToDynamicFields };
53327
53435
  //# sourceMappingURL=cqa-lib-cqa-ui.mjs.map