@cqa-lib/cqa-ui 1.1.544 → 1.1.546
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2020/lib/templates/modular-table-template/folder-sidebar/folder-sidebar.component.mjs +7 -2
- package/esm2020/lib/templates/modular-table-template/modular-table-template.component.mjs +9 -3
- package/esm2020/lib/test-case-details/test-case-details-edit/test-case-details-edit.component.mjs +159 -7
- package/esm2020/lib/test-case-details/test-case-details.component.mjs +7 -3
- package/esm2020/lib/ui-kit.module.mjs +6 -1
- package/esm2020/lib/viewport-selector/viewport-selector.component.mjs +348 -0
- package/esm2020/public-api.mjs +2 -1
- package/fesm2015/cqa-lib-cqa-ui.mjs +537 -47
- package/fesm2015/cqa-lib-cqa-ui.mjs.map +1 -1
- package/fesm2020/cqa-lib-cqa-ui.mjs +553 -44
- package/fesm2020/cqa-lib-cqa-ui.mjs.map +1 -1
- package/lib/templates/modular-table-template/folder-sidebar/folder-sidebar.component.d.ts +4 -1
- package/lib/templates/modular-table-template/modular-table-template.component.d.ts +5 -1
- package/lib/test-case-details/test-case-details-edit/test-case-details-edit.component.d.ts +30 -1
- package/lib/test-case-details/test-case-details.component.d.ts +8 -1
- package/lib/ui-kit.module.d.ts +189 -188
- package/lib/viewport-selector/viewport-selector.component.d.ts +74 -0
- package/package.json +1 -1
- package/public-api.d.ts +1 -0
- package/styles.css +1 -1
|
@@ -3,7 +3,7 @@ import { EventEmitter, Component, Input, Output, HostListener, HostBinding, View
|
|
|
3
3
|
import * as i2 from '@angular/common';
|
|
4
4
|
import { CommonModule } from '@angular/common';
|
|
5
5
|
import * as i1$1 from '@angular/forms';
|
|
6
|
-
import { NG_VALUE_ACCESSOR, FormControl, FormGroup, Validators, FormBuilder, FormArray, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
6
|
+
import { NG_VALUE_ACCESSOR, FormControl, FormGroup, Validators, FormBuilder, FormArray, NG_VALIDATORS, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
7
7
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
|
8
8
|
import * as i1 from '@angular/material/icon';
|
|
9
9
|
import { MatIconModule } from '@angular/material/icon';
|
|
@@ -9065,6 +9065,9 @@ class FolderSidebarComponent {
|
|
|
9065
9065
|
/** Fires when a folder row is dropped onto another folder (or the Unorganized row). */
|
|
9066
9066
|
this.folderDropped = new EventEmitter();
|
|
9067
9067
|
this.collapsedChange = new EventEmitter();
|
|
9068
|
+
/** Bound to the search input. Exposed as an Input so hosts can seed/restore
|
|
9069
|
+
* the visible search term across destroy/re-create cycles (e.g., when the
|
|
9070
|
+
* sidebar is `*ngIf`'d out by a view-mode toggle and re-mounted later). */
|
|
9068
9071
|
this.searchValue = '';
|
|
9069
9072
|
/** Debounce timer for `searchChange` emissions; cleared on each keystroke so
|
|
9070
9073
|
* the host only re-fetches once the user pauses typing. */
|
|
@@ -9629,7 +9632,7 @@ FolderSidebarComponent.RENAME_LIMIT_FLASH_MS = 600;
|
|
|
9629
9632
|
* position is within this many px of the end. */
|
|
9630
9633
|
FolderSidebarComponent.SCROLL_LOAD_THRESHOLD_PX = 64;
|
|
9631
9634
|
FolderSidebarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: FolderSidebarComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
9632
|
-
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", unorganizedCount: "unorganizedCount", allowCreate: "allowCreate", allowRename: "allowRename", allowDelete: "allowDelete", allowMove: "allowMove", allowDuplicate: "allowDuplicate", allowDrop: "allowDrop", showCounts: "showCounts", collapsed: "collapsed", labels: "labels", serverSideSearch: "serverSideSearch", rootTotal: "rootTotal", folderSearchLoading: "folderSearchLoading", rootFoldersLoading: "rootFoldersLoading" }, outputs: { folderSelected: "folderSelected", folderExpansionToggled: "folderExpansionToggled", folderChildrenRequested: "folderChildrenRequested", folderLoadMoreRequested: "folderLoadMoreRequested", searchChange: "searchChange", rootLoadMoreRequested: "rootLoadMoreRequested", 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 <div class=\"cqa-relative\">\n <cqa-search-bar\n size=\"sm\"\n [fullWidth]=\"true\"\n [value]=\"searchValue\"\n [placeholder]=\"labels.searchFoldersPlaceholder\"\n [showClear]=\"true\"\n (valueChange)=\"onSearchInput($event)\"\n (cleared)=\"onSearchClear()\"\n ></cqa-search-bar>\n <span\n *ngIf=\"folderSearchLoading\"\n class=\"cqa-absolute cqa-right-8 cqa-inset-y-0 cqa-flex cqa-items-center\"\n aria-live=\"polite\"\n aria-label=\"Searching folders\"\n >\n <mat-spinner diameter=\"14\" mode=\"indeterminate\"></mat-spinner>\n </span>\n </div>\n </div>\n\n <!-- Tree (folders only \u2014 Unorganized sits directly below; tree caps at 60vh and scrolls when overflowing).\n Scroll-based lazy-loading at the root level: nearing the bottom emits\n `rootLoadMoreRequested`, which the host responds to by fetching the\n next page of roots. -->\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 (scroll)=\"onTreeScroll($event)\">\n <!-- Initial-load spinner: only renders when we have no folders yet AND\n no search active (search has its own inline spinner). -->\n <div\n *ngIf=\"rootFoldersLoading && folders.length === 0 && !searchValue?.trim()\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-py-6\"\n aria-live=\"polite\"\n >\n <mat-spinner diameter=\"20\" mode=\"indeterminate\"></mat-spinner>\n </div>\n <div\n *ngIf=\"searchValue?.trim() && rows.length === 0 && !folderSearchLoading\"\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 <!-- Synthetic loading row (lazy fetch in flight) -->\n <div\n *ngIf=\"row.kind === 'loading'\"\n [style.paddingLeft.px]=\"8 + row.depth * 16\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-py-1.5 cqa-text-sm cqa-text-neutral-500\"\n aria-live=\"polite\"\n >\n <mat-spinner diameter=\"14\" mode=\"indeterminate\"></mat-spinner>\n <span>Loading\u2026</span>\n </div>\n <!-- Synthetic load-more row (more children available on backend) -->\n <button\n *ngIf=\"row.kind === 'load-more'\"\n type=\"button\"\n [style.paddingLeft.px]=\"8 + row.depth * 16\"\n class=\"cqa-flex cqa-items-center cqa-w-full cqa-py-1.5 cqa-text-sm cqa-text-indigo-600 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onLoadMore(row.node); $event.stopPropagation()\"\n >\n <span>Load more ({{ (row.node.totalChildren ?? 0) - (row.node.children?.length ?? 0) }})</span>\n </button>\n <!-- Real folder row -->\n <div\n *ngIf=\"row.kind === 'folder'\"\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 <!-- Root-level pagination is now driven by scroll (see `(scroll)` on the\n tree container above). Per-folder children retain the explicit\n \"Load more\" button rendered inside the rows loop above, since\n subtrees aren't independently scrollable. -->\n <!-- Pagination spinner \u2014 visible only when fetching an additional page\n of roots (folders.length > 0 distinguishes from initial-load case). -->\n <div\n *ngIf=\"rootFoldersLoading && folders.length > 0 && !searchValue?.trim()\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-py-2\"\n aria-live=\"polite\"\n >\n <mat-spinner diameter=\"14\" mode=\"indeterminate\"></mat-spinner>\n </div>\n </div>\n\n <!-- Divider between folder tree and pinned Unorganized 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 <!-- Unorganized \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)=\"onSelectUnorganized()\"\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.unorganized }}</span>\n <span *ngIf=\"showCounts\" class=\"cqa-text-xs cqa-tabular-nums\" [style.color]=\"isSelected(null) ? '#3F43EE' : '#4C4C51'\">{{ unorganizedCount }}</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"] }, { type: i4.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }], 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 });
|
|
9635
|
+
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", unorganizedCount: "unorganizedCount", allowCreate: "allowCreate", allowRename: "allowRename", allowDelete: "allowDelete", allowMove: "allowMove", allowDuplicate: "allowDuplicate", allowDrop: "allowDrop", showCounts: "showCounts", collapsed: "collapsed", labels: "labels", serverSideSearch: "serverSideSearch", rootTotal: "rootTotal", folderSearchLoading: "folderSearchLoading", rootFoldersLoading: "rootFoldersLoading", searchValue: "searchValue" }, outputs: { folderSelected: "folderSelected", folderExpansionToggled: "folderExpansionToggled", folderChildrenRequested: "folderChildrenRequested", folderLoadMoreRequested: "folderLoadMoreRequested", searchChange: "searchChange", rootLoadMoreRequested: "rootLoadMoreRequested", 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 <div class=\"cqa-relative\">\n <cqa-search-bar\n size=\"sm\"\n [fullWidth]=\"true\"\n [value]=\"searchValue\"\n [placeholder]=\"labels.searchFoldersPlaceholder\"\n [showClear]=\"true\"\n (valueChange)=\"onSearchInput($event)\"\n (cleared)=\"onSearchClear()\"\n ></cqa-search-bar>\n <span\n *ngIf=\"folderSearchLoading\"\n class=\"cqa-absolute cqa-right-8 cqa-inset-y-0 cqa-flex cqa-items-center\"\n aria-live=\"polite\"\n aria-label=\"Searching folders\"\n >\n <mat-spinner diameter=\"14\" mode=\"indeterminate\"></mat-spinner>\n </span>\n </div>\n </div>\n\n <!-- Tree (folders only \u2014 Unorganized sits directly below; tree caps at 60vh and scrolls when overflowing).\n Scroll-based lazy-loading at the root level: nearing the bottom emits\n `rootLoadMoreRequested`, which the host responds to by fetching the\n next page of roots. -->\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 (scroll)=\"onTreeScroll($event)\">\n <!-- Initial-load spinner: only renders when we have no folders yet AND\n no search active (search has its own inline spinner). -->\n <div\n *ngIf=\"rootFoldersLoading && folders.length === 0 && !searchValue?.trim()\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-py-6\"\n aria-live=\"polite\"\n >\n <mat-spinner diameter=\"20\" mode=\"indeterminate\"></mat-spinner>\n </div>\n <div\n *ngIf=\"searchValue?.trim() && rows.length === 0 && !folderSearchLoading\"\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 <!-- Synthetic loading row (lazy fetch in flight) -->\n <div\n *ngIf=\"row.kind === 'loading'\"\n [style.paddingLeft.px]=\"8 + row.depth * 16\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-py-1.5 cqa-text-sm cqa-text-neutral-500\"\n aria-live=\"polite\"\n >\n <mat-spinner diameter=\"14\" mode=\"indeterminate\"></mat-spinner>\n <span>Loading\u2026</span>\n </div>\n <!-- Synthetic load-more row (more children available on backend) -->\n <button\n *ngIf=\"row.kind === 'load-more'\"\n type=\"button\"\n [style.paddingLeft.px]=\"8 + row.depth * 16\"\n class=\"cqa-flex cqa-items-center cqa-w-full cqa-py-1.5 cqa-text-sm cqa-text-indigo-600 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onLoadMore(row.node); $event.stopPropagation()\"\n >\n <span>Load more ({{ (row.node.totalChildren ?? 0) - (row.node.children?.length ?? 0) }})</span>\n </button>\n <!-- Real folder row -->\n <div\n *ngIf=\"row.kind === 'folder'\"\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 <!-- Root-level pagination is now driven by scroll (see `(scroll)` on the\n tree container above). Per-folder children retain the explicit\n \"Load more\" button rendered inside the rows loop above, since\n subtrees aren't independently scrollable. -->\n <!-- Pagination spinner \u2014 visible only when fetching an additional page\n of roots (folders.length > 0 distinguishes from initial-load case). -->\n <div\n *ngIf=\"rootFoldersLoading && folders.length > 0 && !searchValue?.trim()\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-py-2\"\n aria-live=\"polite\"\n >\n <mat-spinner diameter=\"14\" mode=\"indeterminate\"></mat-spinner>\n </div>\n </div>\n\n <!-- Divider between folder tree and pinned Unorganized 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 <!-- Unorganized \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)=\"onSelectUnorganized()\"\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.unorganized }}</span>\n <span *ngIf=\"showCounts\" class=\"cqa-text-xs cqa-tabular-nums\" [style.color]=\"isSelected(null) ? '#3F43EE' : '#4C4C51'\">{{ unorganizedCount }}</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"] }, { type: i4.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }], 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 });
|
|
9633
9636
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: FolderSidebarComponent, decorators: [{
|
|
9634
9637
|
type: Component,
|
|
9635
9638
|
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 <div class=\"cqa-relative\">\n <cqa-search-bar\n size=\"sm\"\n [fullWidth]=\"true\"\n [value]=\"searchValue\"\n [placeholder]=\"labels.searchFoldersPlaceholder\"\n [showClear]=\"true\"\n (valueChange)=\"onSearchInput($event)\"\n (cleared)=\"onSearchClear()\"\n ></cqa-search-bar>\n <span\n *ngIf=\"folderSearchLoading\"\n class=\"cqa-absolute cqa-right-8 cqa-inset-y-0 cqa-flex cqa-items-center\"\n aria-live=\"polite\"\n aria-label=\"Searching folders\"\n >\n <mat-spinner diameter=\"14\" mode=\"indeterminate\"></mat-spinner>\n </span>\n </div>\n </div>\n\n <!-- Tree (folders only \u2014 Unorganized sits directly below; tree caps at 60vh and scrolls when overflowing).\n Scroll-based lazy-loading at the root level: nearing the bottom emits\n `rootLoadMoreRequested`, which the host responds to by fetching the\n next page of roots. -->\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 (scroll)=\"onTreeScroll($event)\">\n <!-- Initial-load spinner: only renders when we have no folders yet AND\n no search active (search has its own inline spinner). -->\n <div\n *ngIf=\"rootFoldersLoading && folders.length === 0 && !searchValue?.trim()\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-py-6\"\n aria-live=\"polite\"\n >\n <mat-spinner diameter=\"20\" mode=\"indeterminate\"></mat-spinner>\n </div>\n <div\n *ngIf=\"searchValue?.trim() && rows.length === 0 && !folderSearchLoading\"\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 <!-- Synthetic loading row (lazy fetch in flight) -->\n <div\n *ngIf=\"row.kind === 'loading'\"\n [style.paddingLeft.px]=\"8 + row.depth * 16\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-py-1.5 cqa-text-sm cqa-text-neutral-500\"\n aria-live=\"polite\"\n >\n <mat-spinner diameter=\"14\" mode=\"indeterminate\"></mat-spinner>\n <span>Loading\u2026</span>\n </div>\n <!-- Synthetic load-more row (more children available on backend) -->\n <button\n *ngIf=\"row.kind === 'load-more'\"\n type=\"button\"\n [style.paddingLeft.px]=\"8 + row.depth * 16\"\n class=\"cqa-flex cqa-items-center cqa-w-full cqa-py-1.5 cqa-text-sm cqa-text-indigo-600 hover:cqa-bg-indigo-50 cqa-text-left\"\n (click)=\"onLoadMore(row.node); $event.stopPropagation()\"\n >\n <span>Load more ({{ (row.node.totalChildren ?? 0) - (row.node.children?.length ?? 0) }})</span>\n </button>\n <!-- Real folder row -->\n <div\n *ngIf=\"row.kind === 'folder'\"\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 <!-- Root-level pagination is now driven by scroll (see `(scroll)` on the\n tree container above). Per-folder children retain the explicit\n \"Load more\" button rendered inside the rows loop above, since\n subtrees aren't independently scrollable. -->\n <!-- Pagination spinner \u2014 visible only when fetching an additional page\n of roots (folders.length > 0 distinguishes from initial-load case). -->\n <div\n *ngIf=\"rootFoldersLoading && folders.length > 0 && !searchValue?.trim()\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-py-2\"\n aria-live=\"polite\"\n >\n <mat-spinner diameter=\"14\" mode=\"indeterminate\"></mat-spinner>\n </div>\n </div>\n\n <!-- Divider between folder tree and pinned Unorganized 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 <!-- Unorganized \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)=\"onSelectUnorganized()\"\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.unorganized }}</span>\n <span *ngIf=\"showCounts\" class=\"cqa-text-xs cqa-tabular-nums\" [style.color]=\"isSelected(null) ? '#3F43EE' : '#4C4C51'\">{{ unorganizedCount }}</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: [] }]
|
|
@@ -9697,6 +9700,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
9697
9700
|
type: Output
|
|
9698
9701
|
}], collapsedChange: [{
|
|
9699
9702
|
type: Output
|
|
9703
|
+
}], searchValue: [{
|
|
9704
|
+
type: Input
|
|
9700
9705
|
}], onDocumentClick: [{
|
|
9701
9706
|
type: HostListener,
|
|
9702
9707
|
args: ['document:click']
|
|
@@ -9870,6 +9875,10 @@ class ModularTableTemplateComponent {
|
|
|
9870
9875
|
/** Lazy-load: true while the host is fetching server-side folder-search
|
|
9871
9876
|
* results. Forwarded to the sidebar so it can render a search spinner. */
|
|
9872
9877
|
this.folderSearchLoading = false;
|
|
9878
|
+
/** Seeded value for the sidebar's search input. Exposed so hosts can restore
|
|
9879
|
+
* an in-flight folder-search across sidebar destroy/re-create cycles (e.g.,
|
|
9880
|
+
* toggling out of and back into modular view). */
|
|
9881
|
+
this.folderSearchValue = '';
|
|
9873
9882
|
/** Lazy-load: true while a root-page fetch is in flight (initial load OR
|
|
9874
9883
|
* the scroll-driven "load more" pagination). Drives the loading indicator
|
|
9875
9884
|
* the modular grid renders at the right edge of the Organized row, and is
|
|
@@ -11206,10 +11215,10 @@ class ModularTableTemplateComponent {
|
|
|
11206
11215
|
}
|
|
11207
11216
|
ModularTableTemplateComponent.GRID_SCROLL_LOAD_THRESHOLD_PX = 96;
|
|
11208
11217
|
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 });
|
|
11209
|
-
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", rootFolders: "rootFolders", selectedFolderId: "selectedFolderId", expandedFolderIds: "expandedFolderIds", unorganizedCount: "unorganizedCount", folderIdAccessor: "folderIdAccessor", modularConfig: "modularConfig", modularLabels: "modularLabels", bulkActions: "bulkActions", sidebarCollapsed: "sidebarCollapsed", serverSideSearch: "serverSideSearch", rootTotal: "rootTotal", folderSearchLoading: "folderSearchLoading", rootFoldersLoading: "rootFoldersLoading", selectedFolderNode: "selectedFolderNode", selectedFolderTrail: "selectedFolderTrail", 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", folderChildrenRequested: "folderChildrenRequested", folderLoadMoreRequested: "folderLoadMoreRequested", rootLoadMoreRequested: "rootLoadMoreRequested", folderSearchChange: "folderSearchChange", 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 [unorganizedCount]=\"unorganizedCount\"\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 [serverSideSearch]=\"serverSideSearch\"\n [rootTotal]=\"rootTotal\"\n [folderSearchLoading]=\"folderSearchLoading\"\n [rootFoldersLoading]=\"rootFoldersLoading\"\n (folderSelected)=\"onFolderSelected($event)\"\n (folderExpansionToggled)=\"onFolderExpansionToggled($event)\"\n (folderChildrenRequested)=\"folderChildrenRequested.emit($event)\"\n (folderLoadMoreRequested)=\"folderLoadMoreRequested.emit($event)\"\n (rootLoadMoreRequested)=\"rootLoadMoreRequested.emit()\"\n (searchChange)=\"folderSearchChange.emit($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.organized }}</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 (scroll)=\"onRootGridScroll($event)\">\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\n <!-- Pagination spinner anchored at the right edge of the Organized\n row. Only renders during an in-flight root fetch (initial OR\n scroll-driven \"load more\"), and is filtered to suppress when\n the section is empty so we don't show a spinner inside an\n otherwise-blank row. -->\n <div\n *ngIf=\"rootFoldersLoading && rootFolderTiles.length > 0\"\n class=\"cqa-shrink-0 cqa-flex cqa-items-center cqa-justify-center cqa-w-[80px]\"\n aria-live=\"polite\"\n [attr.aria-label]=\"'Loading more folders'\"\n >\n <mat-spinner diameter=\"20\" mode=\"indeterminate\"></mat-spinner>\n </div>\n </div>\n </section>\n\n <!-- Subfolder section: modular + folder view. Shown whenever drilled in\n (even if no subfolders, so the \"+ New folder\" tile remains\n reachable, and so we can render a loading state during the\n drill-in fetch before children arrive). -->\n <section\n *ngIf=\"isModularView && !isRootView && modularConfig.showSubfolderSection && (subfolderTiles.length || currentFolderNode?.childrenLoading)\"\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 (scroll)=\"onSubfolderGridScroll($event)\">\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\n <!-- Subfolder fetch indicator. Two cases:\n - Drill-in fetch: no subfolderTiles yet, render a centered\n row spinner so the section isn't empty during the fetch.\n - Pagination fetch: tiles exist, anchor a small spinner at\n the right edge so the user knows the next page is loading. -->\n <div\n *ngIf=\"currentFolderNode?.childrenLoading\"\n class=\"cqa-shrink-0 cqa-flex cqa-items-center cqa-justify-center cqa-w-[80px]\"\n aria-live=\"polite\"\n [attr.aria-label]=\"'Loading subfolders'\"\n >\n <mat-spinner diameter=\"20\" mode=\"indeterminate\"></mat-spinner>\n </div>\n </div>\n </section>\n\n <!-- Folder panel header above the table: \"Hotel Search (3)\" + Clear filter -->\n <div\n *ngIf=\"isModularView && !isRootView && modularConfig.showUnorganizedSection\"\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 <!-- Unorganized section header at root view -->\n <div\n *ngIf=\"isModularView && isRootView && modularConfig.showUnorganizedSection\"\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.unorganized }}</h3>\n <span class=\"cqa-text-xs cqa-text-[#6D6D74]\">\n {{ unorganizedCount === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + unorganizedCount) }}\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", "unorganizedCount", "allowCreate", "allowRename", "allowDelete", "allowMove", "allowDuplicate", "allowDrop", "showCounts", "collapsed", "labels", "serverSideSearch", "rootTotal", "folderSearchLoading", "rootFoldersLoading"], outputs: ["folderSelected", "folderExpansionToggled", "folderChildrenRequested", "folderLoadMoreRequested", "searchChange", "rootLoadMoreRequested", "folderCreated", "folderCreateRequested", "folderRenamed", "folderDeleted", "folderMoveRequested", "folderDuplicateRequested", "testsDropped", "folderDropped", "collapsedChange"] }, { type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i4.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }, { 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 });
|
|
11218
|
+
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", rootFolders: "rootFolders", selectedFolderId: "selectedFolderId", expandedFolderIds: "expandedFolderIds", unorganizedCount: "unorganizedCount", folderIdAccessor: "folderIdAccessor", modularConfig: "modularConfig", modularLabels: "modularLabels", bulkActions: "bulkActions", sidebarCollapsed: "sidebarCollapsed", serverSideSearch: "serverSideSearch", rootTotal: "rootTotal", folderSearchLoading: "folderSearchLoading", folderSearchValue: "folderSearchValue", rootFoldersLoading: "rootFoldersLoading", selectedFolderNode: "selectedFolderNode", selectedFolderTrail: "selectedFolderTrail", 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", folderChildrenRequested: "folderChildrenRequested", folderLoadMoreRequested: "folderLoadMoreRequested", rootLoadMoreRequested: "rootLoadMoreRequested", folderSearchChange: "folderSearchChange", 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 [unorganizedCount]=\"unorganizedCount\"\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 [serverSideSearch]=\"serverSideSearch\"\n [rootTotal]=\"rootTotal\"\n [folderSearchLoading]=\"folderSearchLoading\"\n [rootFoldersLoading]=\"rootFoldersLoading\"\n [searchValue]=\"folderSearchValue\"\n (folderSelected)=\"onFolderSelected($event)\"\n (folderExpansionToggled)=\"onFolderExpansionToggled($event)\"\n (folderChildrenRequested)=\"folderChildrenRequested.emit($event)\"\n (folderLoadMoreRequested)=\"folderLoadMoreRequested.emit($event)\"\n (rootLoadMoreRequested)=\"rootLoadMoreRequested.emit()\"\n (searchChange)=\"folderSearchChange.emit($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.organized }}</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 (scroll)=\"onRootGridScroll($event)\">\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\n <!-- Pagination spinner anchored at the right edge of the Organized\n row. Only renders during an in-flight root fetch (initial OR\n scroll-driven \"load more\"), and is filtered to suppress when\n the section is empty so we don't show a spinner inside an\n otherwise-blank row. -->\n <div\n *ngIf=\"rootFoldersLoading && rootFolderTiles.length > 0\"\n class=\"cqa-shrink-0 cqa-flex cqa-items-center cqa-justify-center cqa-w-[80px]\"\n aria-live=\"polite\"\n [attr.aria-label]=\"'Loading more folders'\"\n >\n <mat-spinner diameter=\"20\" mode=\"indeterminate\"></mat-spinner>\n </div>\n </div>\n </section>\n\n <!-- Subfolder section: modular + folder view. Shown whenever drilled in\n (even if no subfolders, so the \"+ New folder\" tile remains\n reachable, and so we can render a loading state during the\n drill-in fetch before children arrive). -->\n <section\n *ngIf=\"isModularView && !isRootView && modularConfig.showSubfolderSection && (subfolderTiles.length || currentFolderNode?.childrenLoading)\"\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 (scroll)=\"onSubfolderGridScroll($event)\">\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\n <!-- Subfolder fetch indicator. Two cases:\n - Drill-in fetch: no subfolderTiles yet, render a centered\n row spinner so the section isn't empty during the fetch.\n - Pagination fetch: tiles exist, anchor a small spinner at\n the right edge so the user knows the next page is loading. -->\n <div\n *ngIf=\"currentFolderNode?.childrenLoading\"\n class=\"cqa-shrink-0 cqa-flex cqa-items-center cqa-justify-center cqa-w-[80px]\"\n aria-live=\"polite\"\n [attr.aria-label]=\"'Loading subfolders'\"\n >\n <mat-spinner diameter=\"20\" mode=\"indeterminate\"></mat-spinner>\n </div>\n </div>\n </section>\n\n <!-- Folder panel header above the table: \"Hotel Search (3)\" + Clear filter -->\n <div\n *ngIf=\"isModularView && !isRootView && modularConfig.showUnorganizedSection\"\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 <!-- Unorganized section header at root view -->\n <div\n *ngIf=\"isModularView && isRootView && modularConfig.showUnorganizedSection\"\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.unorganized }}</h3>\n <span class=\"cqa-text-xs cqa-text-[#6D6D74]\">\n {{ unorganizedCount === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + unorganizedCount) }}\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", "unorganizedCount", "allowCreate", "allowRename", "allowDelete", "allowMove", "allowDuplicate", "allowDrop", "showCounts", "collapsed", "labels", "serverSideSearch", "rootTotal", "folderSearchLoading", "rootFoldersLoading", "searchValue"], outputs: ["folderSelected", "folderExpansionToggled", "folderChildrenRequested", "folderLoadMoreRequested", "searchChange", "rootLoadMoreRequested", "folderCreated", "folderCreateRequested", "folderRenamed", "folderDeleted", "folderMoveRequested", "folderDuplicateRequested", "testsDropped", "folderDropped", "collapsedChange"] }, { type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i4.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }, { 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 });
|
|
11210
11219
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ModularTableTemplateComponent, decorators: [{
|
|
11211
11220
|
type: Component,
|
|
11212
|
-
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 [unorganizedCount]=\"unorganizedCount\"\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 [serverSideSearch]=\"serverSideSearch\"\n [rootTotal]=\"rootTotal\"\n [folderSearchLoading]=\"folderSearchLoading\"\n [rootFoldersLoading]=\"rootFoldersLoading\"\n (folderSelected)=\"onFolderSelected($event)\"\n (folderExpansionToggled)=\"onFolderExpansionToggled($event)\"\n (folderChildrenRequested)=\"folderChildrenRequested.emit($event)\"\n (folderLoadMoreRequested)=\"folderLoadMoreRequested.emit($event)\"\n (rootLoadMoreRequested)=\"rootLoadMoreRequested.emit()\"\n (searchChange)=\"folderSearchChange.emit($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.organized }}</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 (scroll)=\"onRootGridScroll($event)\">\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\n <!-- Pagination spinner anchored at the right edge of the Organized\n row. Only renders during an in-flight root fetch (initial OR\n scroll-driven \"load more\"), and is filtered to suppress when\n the section is empty so we don't show a spinner inside an\n otherwise-blank row. -->\n <div\n *ngIf=\"rootFoldersLoading && rootFolderTiles.length > 0\"\n class=\"cqa-shrink-0 cqa-flex cqa-items-center cqa-justify-center cqa-w-[80px]\"\n aria-live=\"polite\"\n [attr.aria-label]=\"'Loading more folders'\"\n >\n <mat-spinner diameter=\"20\" mode=\"indeterminate\"></mat-spinner>\n </div>\n </div>\n </section>\n\n <!-- Subfolder section: modular + folder view. Shown whenever drilled in\n (even if no subfolders, so the \"+ New folder\" tile remains\n reachable, and so we can render a loading state during the\n drill-in fetch before children arrive). -->\n <section\n *ngIf=\"isModularView && !isRootView && modularConfig.showSubfolderSection && (subfolderTiles.length || currentFolderNode?.childrenLoading)\"\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 (scroll)=\"onSubfolderGridScroll($event)\">\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\n <!-- Subfolder fetch indicator. Two cases:\n - Drill-in fetch: no subfolderTiles yet, render a centered\n row spinner so the section isn't empty during the fetch.\n - Pagination fetch: tiles exist, anchor a small spinner at\n the right edge so the user knows the next page is loading. -->\n <div\n *ngIf=\"currentFolderNode?.childrenLoading\"\n class=\"cqa-shrink-0 cqa-flex cqa-items-center cqa-justify-center cqa-w-[80px]\"\n aria-live=\"polite\"\n [attr.aria-label]=\"'Loading subfolders'\"\n >\n <mat-spinner diameter=\"20\" mode=\"indeterminate\"></mat-spinner>\n </div>\n </div>\n </section>\n\n <!-- Folder panel header above the table: \"Hotel Search (3)\" + Clear filter -->\n <div\n *ngIf=\"isModularView && !isRootView && modularConfig.showUnorganizedSection\"\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 <!-- Unorganized section header at root view -->\n <div\n *ngIf=\"isModularView && isRootView && modularConfig.showUnorganizedSection\"\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.unorganized }}</h3>\n <span class=\"cqa-text-xs cqa-text-[#6D6D74]\">\n {{ unorganizedCount === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + unorganizedCount) }}\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: [] }]
|
|
11221
|
+
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 [unorganizedCount]=\"unorganizedCount\"\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 [serverSideSearch]=\"serverSideSearch\"\n [rootTotal]=\"rootTotal\"\n [folderSearchLoading]=\"folderSearchLoading\"\n [rootFoldersLoading]=\"rootFoldersLoading\"\n [searchValue]=\"folderSearchValue\"\n (folderSelected)=\"onFolderSelected($event)\"\n (folderExpansionToggled)=\"onFolderExpansionToggled($event)\"\n (folderChildrenRequested)=\"folderChildrenRequested.emit($event)\"\n (folderLoadMoreRequested)=\"folderLoadMoreRequested.emit($event)\"\n (rootLoadMoreRequested)=\"rootLoadMoreRequested.emit()\"\n (searchChange)=\"folderSearchChange.emit($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.organized }}</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 (scroll)=\"onRootGridScroll($event)\">\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\n <!-- Pagination spinner anchored at the right edge of the Organized\n row. Only renders during an in-flight root fetch (initial OR\n scroll-driven \"load more\"), and is filtered to suppress when\n the section is empty so we don't show a spinner inside an\n otherwise-blank row. -->\n <div\n *ngIf=\"rootFoldersLoading && rootFolderTiles.length > 0\"\n class=\"cqa-shrink-0 cqa-flex cqa-items-center cqa-justify-center cqa-w-[80px]\"\n aria-live=\"polite\"\n [attr.aria-label]=\"'Loading more folders'\"\n >\n <mat-spinner diameter=\"20\" mode=\"indeterminate\"></mat-spinner>\n </div>\n </div>\n </section>\n\n <!-- Subfolder section: modular + folder view. Shown whenever drilled in\n (even if no subfolders, so the \"+ New folder\" tile remains\n reachable, and so we can render a loading state during the\n drill-in fetch before children arrive). -->\n <section\n *ngIf=\"isModularView && !isRootView && modularConfig.showSubfolderSection && (subfolderTiles.length || currentFolderNode?.childrenLoading)\"\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 (scroll)=\"onSubfolderGridScroll($event)\">\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\n <!-- Subfolder fetch indicator. Two cases:\n - Drill-in fetch: no subfolderTiles yet, render a centered\n row spinner so the section isn't empty during the fetch.\n - Pagination fetch: tiles exist, anchor a small spinner at\n the right edge so the user knows the next page is loading. -->\n <div\n *ngIf=\"currentFolderNode?.childrenLoading\"\n class=\"cqa-shrink-0 cqa-flex cqa-items-center cqa-justify-center cqa-w-[80px]\"\n aria-live=\"polite\"\n [attr.aria-label]=\"'Loading subfolders'\"\n >\n <mat-spinner diameter=\"20\" mode=\"indeterminate\"></mat-spinner>\n </div>\n </div>\n </section>\n\n <!-- Folder panel header above the table: \"Hotel Search (3)\" + Clear filter -->\n <div\n *ngIf=\"isModularView && !isRootView && modularConfig.showUnorganizedSection\"\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 <!-- Unorganized section header at root view -->\n <div\n *ngIf=\"isModularView && isRootView && modularConfig.showUnorganizedSection\"\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.unorganized }}</h3>\n <span class=\"cqa-text-xs cqa-text-[#6D6D74]\">\n {{ unorganizedCount === 1 ? modularLabels.testsCountSingular : modularLabels.testsCountPlural.replace('{n}', '' + unorganizedCount) }}\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: [] }]
|
|
11213
11222
|
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: DialogService }]; }, propDecorators: { searchPlaceholder: [{
|
|
11214
11223
|
type: Input
|
|
11215
11224
|
}], searchValue: [{
|
|
@@ -11346,6 +11355,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
11346
11355
|
type: Input
|
|
11347
11356
|
}], folderSearchLoading: [{
|
|
11348
11357
|
type: Input
|
|
11358
|
+
}], folderSearchValue: [{
|
|
11359
|
+
type: Input
|
|
11349
11360
|
}], rootFoldersLoading: [{
|
|
11350
11361
|
type: Input
|
|
11351
11362
|
}], selectedFolderNode: [{
|
|
@@ -46453,6 +46464,75 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
46453
46464
|
type: Output
|
|
46454
46465
|
}] } });
|
|
46455
46466
|
|
|
46467
|
+
class RadioCardGroupComponent {
|
|
46468
|
+
constructor() {
|
|
46469
|
+
/** Choices to render (order preserved). */
|
|
46470
|
+
this.options = [];
|
|
46471
|
+
/** When true, cards wrap to the next line (e.g. many platform targets). */
|
|
46472
|
+
this.wrap = false;
|
|
46473
|
+
this.disabled = false;
|
|
46474
|
+
/** Emits the same event as `mat-radio-group` for compatibility with existing handlers. */
|
|
46475
|
+
this.selectionChange = new EventEmitter();
|
|
46476
|
+
this.value = null;
|
|
46477
|
+
this.onChange = () => { };
|
|
46478
|
+
this.onTouched = () => { };
|
|
46479
|
+
}
|
|
46480
|
+
writeValue(obj) {
|
|
46481
|
+
this.value = obj == null ? null : String(obj);
|
|
46482
|
+
}
|
|
46483
|
+
registerOnChange(fn) {
|
|
46484
|
+
this.onChange = fn;
|
|
46485
|
+
}
|
|
46486
|
+
registerOnTouched(fn) {
|
|
46487
|
+
this.onTouched = fn;
|
|
46488
|
+
}
|
|
46489
|
+
setDisabledState(isDisabled) {
|
|
46490
|
+
this.disabled = isDisabled;
|
|
46491
|
+
}
|
|
46492
|
+
trackByValue(_index, opt) {
|
|
46493
|
+
return opt.value;
|
|
46494
|
+
}
|
|
46495
|
+
get hasAnyIcon() {
|
|
46496
|
+
return (this.options || []).some((o) => !!o.icon);
|
|
46497
|
+
}
|
|
46498
|
+
onRadioChange(event) {
|
|
46499
|
+
if (this.disabled) {
|
|
46500
|
+
return;
|
|
46501
|
+
}
|
|
46502
|
+
const next = event.value != null ? String(event.value) : null;
|
|
46503
|
+
this.value = next;
|
|
46504
|
+
this.onChange(next);
|
|
46505
|
+
this.onTouched();
|
|
46506
|
+
this.selectionChange.emit(event);
|
|
46507
|
+
}
|
|
46508
|
+
}
|
|
46509
|
+
RadioCardGroupComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: RadioCardGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
46510
|
+
RadioCardGroupComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: RadioCardGroupComponent, selector: "cqa-radio-card-group", inputs: { options: "options", wrap: "wrap", disabled: "disabled" }, outputs: { selectionChange: "selectionChange" }, host: { classAttribute: "cqa-ui-root cqa-block" }, providers: [
|
|
46511
|
+
{
|
|
46512
|
+
provide: NG_VALUE_ACCESSOR,
|
|
46513
|
+
useExisting: forwardRef(() => RadioCardGroupComponent),
|
|
46514
|
+
multi: true
|
|
46515
|
+
}
|
|
46516
|
+
], ngImport: i0, template: "<mat-radio-group\n class=\"cqa-flex cqa-items-stretch cqa-radio-group\"\n [ngClass]=\"wrap ? 'cqa-flex-wrap cqa-gap-2' : 'cqa-gap-3'\"\n [value]=\"value\"\n (change)=\"onRadioChange($event)\"\n [disabled]=\"disabled\"\n>\n <label\n *ngFor=\"let opt of options; trackBy: trackByValue\"\n class=\"cqa-radio-card-option qqa-m-0 cqa-flex cqa-cursor-pointer cqa-items-center cqa-gap-1.5 cqa-rounded-[8px] cqa-border cqa-border-solid cqa-border-[#e5e7eb] cqa-py-2 cqa-text-[13px] cqa-text-[#374151] hover:cqa-border-[#6366f1]\"\n [ngClass]=\"hasAnyIcon ? 'cqa-px-3' : 'cqa-px-4'\"\n >\n <mat-radio-button [value]=\"opt.value\" class=\"!cqa-pr-0\"></mat-radio-button>\n <mat-icon *ngIf=\"opt.icon\" class=\"cqa-h-[18px] cqa-w-[18px] cqa-text-[18px] cqa-text-[#6366f1]\">{{ opt.icon }}</mat-icon>\n <span class=\"cqa-whitespace-nowrap\">{{ opt.label }}</span>\n </label>\n</mat-radio-group>\n", components: [{ type: i4$1.MatRadioButton, selector: "mat-radio-button", inputs: ["disableRipple", "tabIndex"], exportAs: ["matRadioButton"] }, { type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i4$1.MatRadioGroup, selector: "mat-radio-group", exportAs: ["matRadioGroup"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
46517
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: RadioCardGroupComponent, decorators: [{
|
|
46518
|
+
type: Component,
|
|
46519
|
+
args: [{ selector: 'cqa-radio-card-group', host: { class: 'cqa-ui-root cqa-block' }, providers: [
|
|
46520
|
+
{
|
|
46521
|
+
provide: NG_VALUE_ACCESSOR,
|
|
46522
|
+
useExisting: forwardRef(() => RadioCardGroupComponent),
|
|
46523
|
+
multi: true
|
|
46524
|
+
}
|
|
46525
|
+
], template: "<mat-radio-group\n class=\"cqa-flex cqa-items-stretch cqa-radio-group\"\n [ngClass]=\"wrap ? 'cqa-flex-wrap cqa-gap-2' : 'cqa-gap-3'\"\n [value]=\"value\"\n (change)=\"onRadioChange($event)\"\n [disabled]=\"disabled\"\n>\n <label\n *ngFor=\"let opt of options; trackBy: trackByValue\"\n class=\"cqa-radio-card-option qqa-m-0 cqa-flex cqa-cursor-pointer cqa-items-center cqa-gap-1.5 cqa-rounded-[8px] cqa-border cqa-border-solid cqa-border-[#e5e7eb] cqa-py-2 cqa-text-[13px] cqa-text-[#374151] hover:cqa-border-[#6366f1]\"\n [ngClass]=\"hasAnyIcon ? 'cqa-px-3' : 'cqa-px-4'\"\n >\n <mat-radio-button [value]=\"opt.value\" class=\"!cqa-pr-0\"></mat-radio-button>\n <mat-icon *ngIf=\"opt.icon\" class=\"cqa-h-[18px] cqa-w-[18px] cqa-text-[18px] cqa-text-[#6366f1]\">{{ opt.icon }}</mat-icon>\n <span class=\"cqa-whitespace-nowrap\">{{ opt.label }}</span>\n </label>\n</mat-radio-group>\n", styles: [] }]
|
|
46526
|
+
}], propDecorators: { options: [{
|
|
46527
|
+
type: Input
|
|
46528
|
+
}], wrap: [{
|
|
46529
|
+
type: Input
|
|
46530
|
+
}], disabled: [{
|
|
46531
|
+
type: Input
|
|
46532
|
+
}], selectionChange: [{
|
|
46533
|
+
type: Output
|
|
46534
|
+
}] } });
|
|
46535
|
+
|
|
46456
46536
|
/**
|
|
46457
46537
|
* Dual-mode card summarising the API mocking configuration of a test case.
|
|
46458
46538
|
*
|
|
@@ -46678,6 +46758,8 @@ class TestCaseDetailsEditComponent {
|
|
|
46678
46758
|
/** Forwarded to `cqa-api-mocking-card`. In edit mode the card hides the block anyway, but
|
|
46679
46759
|
* we still pipe the input through for symmetry with the read-only component. */
|
|
46680
46760
|
this.apiMockingShowProgress = false;
|
|
46761
|
+
/** Viewport dropdown options per category from the API. Pass DESKTOP, LAPTOP, TABLET, MOBILE arrays. */
|
|
46762
|
+
this.viewportCategoryOptions = {};
|
|
46681
46763
|
this.save = new EventEmitter();
|
|
46682
46764
|
this.cancel = new EventEmitter();
|
|
46683
46765
|
/** Emitted when user searches in a select (serverSearch mode). Call API and update options via selectConfigOverrides. */
|
|
@@ -46720,6 +46802,48 @@ class TestCaseDetailsEditComponent {
|
|
|
46720
46802
|
this.mobileTestingEnabled = false;
|
|
46721
46803
|
this.extensionUseEnabled = false;
|
|
46722
46804
|
this.dataDrivenEnabled = false;
|
|
46805
|
+
this.viewportMode = 'desktop';
|
|
46806
|
+
this.viewportDesktopDeviceForm = new FormGroup({ viewportDesktopDevice: new FormControl('') });
|
|
46807
|
+
this.viewportLaptopDeviceForm = new FormGroup({ viewportLaptopDevice: new FormControl('') });
|
|
46808
|
+
this.viewportTabletDeviceForm = new FormGroup({ viewportTabletDevice: new FormControl('') });
|
|
46809
|
+
this.viewportMobileDeviceForm = new FormGroup({ viewportMobileDevice: new FormControl('') });
|
|
46810
|
+
this.customViewportWidth = '';
|
|
46811
|
+
this.customViewportHeight = '';
|
|
46812
|
+
this.customViewportTags = [];
|
|
46813
|
+
this.viewportModeOptions = [
|
|
46814
|
+
{ value: 'desktop', label: 'Desktop', icon: 'desktop_windows' },
|
|
46815
|
+
{ value: 'laptop', label: 'Laptop', icon: 'laptop_windows' },
|
|
46816
|
+
{ value: 'tablet', label: 'Tablet', icon: 'tablet_mac' },
|
|
46817
|
+
{ value: 'mobile', label: 'Mobile', icon: 'smartphone' },
|
|
46818
|
+
];
|
|
46819
|
+
this.desktopViewportConfig = {
|
|
46820
|
+
key: 'viewportDesktopDevice',
|
|
46821
|
+
label: '',
|
|
46822
|
+
placeholder: 'Select resolution',
|
|
46823
|
+
searchable: true,
|
|
46824
|
+
options: [],
|
|
46825
|
+
};
|
|
46826
|
+
this.laptopViewportConfig = {
|
|
46827
|
+
key: 'viewportLaptopDevice',
|
|
46828
|
+
label: '',
|
|
46829
|
+
placeholder: 'Select resolution',
|
|
46830
|
+
searchable: true,
|
|
46831
|
+
options: [],
|
|
46832
|
+
};
|
|
46833
|
+
this.tabletViewportConfig = {
|
|
46834
|
+
key: 'viewportTabletDevice',
|
|
46835
|
+
label: '',
|
|
46836
|
+
placeholder: 'Select resolution',
|
|
46837
|
+
searchable: true,
|
|
46838
|
+
options: [],
|
|
46839
|
+
};
|
|
46840
|
+
this.mobileViewportConfig = {
|
|
46841
|
+
key: 'viewportMobileDevice',
|
|
46842
|
+
label: '',
|
|
46843
|
+
placeholder: 'Select device',
|
|
46844
|
+
searchable: true,
|
|
46845
|
+
options: [],
|
|
46846
|
+
};
|
|
46723
46847
|
this.frequentlyUsedLabels = FREQUENTLY_USED_LABELS;
|
|
46724
46848
|
this._initialFormSnapshot = null;
|
|
46725
46849
|
/** FormGroup for cqa-dynamic-select bindings */
|
|
@@ -47142,6 +47266,106 @@ class TestCaseDetailsEditComponent {
|
|
|
47142
47266
|
const section = [...this.configSections, ...this.configSectionsRow2].find((s) => s.title === 'Execution');
|
|
47143
47267
|
return !!((_a = section === null || section === void 0 ? void 0 : section.items) === null || _a === void 0 ? void 0 : _a.some((i) => i.label === 'Prerequisite Case'));
|
|
47144
47268
|
}
|
|
47269
|
+
initViewportFromValue(defaultViewport) {
|
|
47270
|
+
const vp = String(defaultViewport || '');
|
|
47271
|
+
this.customViewportWidth = '';
|
|
47272
|
+
this.customViewportHeight = '';
|
|
47273
|
+
this.customViewportTags = [];
|
|
47274
|
+
this.viewportDesktopDeviceForm.reset({ viewportDesktopDevice: '' });
|
|
47275
|
+
this.viewportLaptopDeviceForm.reset({ viewportLaptopDevice: '' });
|
|
47276
|
+
this.viewportTabletDeviceForm.reset({ viewportTabletDevice: '' });
|
|
47277
|
+
this.viewportMobileDeviceForm.reset({ viewportMobileDevice: '' });
|
|
47278
|
+
if (vp.startsWith('laptop:')) {
|
|
47279
|
+
this.viewportMode = 'laptop';
|
|
47280
|
+
this.viewportLaptopDeviceForm.patchValue({ viewportLaptopDevice: vp.slice(7).trim() });
|
|
47281
|
+
}
|
|
47282
|
+
else if (vp.startsWith('tablet:')) {
|
|
47283
|
+
this.viewportMode = 'tablet';
|
|
47284
|
+
this.viewportTabletDeviceForm.patchValue({ viewportTabletDevice: vp.slice(7).trim() });
|
|
47285
|
+
}
|
|
47286
|
+
else if (vp.startsWith('desktop:')) {
|
|
47287
|
+
this.viewportMode = 'desktop';
|
|
47288
|
+
this.viewportDesktopDeviceForm.patchValue({ viewportDesktopDevice: vp.slice(8).trim() });
|
|
47289
|
+
}
|
|
47290
|
+
else if (vp.startsWith('mobile:')) {
|
|
47291
|
+
this.viewportMode = 'mobile';
|
|
47292
|
+
this.viewportMobileDeviceForm.patchValue({ viewportMobileDevice: vp.slice(7).trim() });
|
|
47293
|
+
}
|
|
47294
|
+
else if (vp && vp.includes('*')) {
|
|
47295
|
+
this.viewportMode = 'custom';
|
|
47296
|
+
this.customViewportTags = vp.split(',').map((v) => v.trim()).filter(Boolean);
|
|
47297
|
+
}
|
|
47298
|
+
else {
|
|
47299
|
+
this.viewportMode = 'desktop';
|
|
47300
|
+
}
|
|
47301
|
+
}
|
|
47302
|
+
buildViewportValue() {
|
|
47303
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
47304
|
+
if (this.viewportMode === 'laptop') {
|
|
47305
|
+
const res = ((_b = (_a = this.viewportLaptopDeviceForm.get('viewportLaptopDevice')) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '').trim();
|
|
47306
|
+
return res ? `laptop:${res}` : 'laptop:';
|
|
47307
|
+
}
|
|
47308
|
+
if (this.viewportMode === 'tablet') {
|
|
47309
|
+
const res = ((_d = (_c = this.viewportTabletDeviceForm.get('viewportTabletDevice')) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '').trim();
|
|
47310
|
+
return res ? `tablet:${res}` : 'tablet:';
|
|
47311
|
+
}
|
|
47312
|
+
if (this.viewportMode === 'mobile') {
|
|
47313
|
+
const device = ((_f = (_e = this.viewportMobileDeviceForm.get('viewportMobileDevice')) === null || _e === void 0 ? void 0 : _e.value) !== null && _f !== void 0 ? _f : '').trim();
|
|
47314
|
+
return device ? `mobile:${device}` : 'mobile:';
|
|
47315
|
+
}
|
|
47316
|
+
if (this.viewportMode === 'custom') {
|
|
47317
|
+
return this.customViewportTags.join(',');
|
|
47318
|
+
}
|
|
47319
|
+
// desktop
|
|
47320
|
+
const res = ((_h = (_g = this.viewportDesktopDeviceForm.get('viewportDesktopDevice')) === null || _g === void 0 ? void 0 : _g.value) !== null && _h !== void 0 ? _h : '').trim();
|
|
47321
|
+
return res ? `desktop:${res}` : '1280x720';
|
|
47322
|
+
}
|
|
47323
|
+
onViewportModeChange(mode) {
|
|
47324
|
+
this.viewportMode = mode;
|
|
47325
|
+
if (mode !== 'desktop')
|
|
47326
|
+
this.viewportDesktopDeviceForm.reset({ viewportDesktopDevice: '' });
|
|
47327
|
+
if (mode !== 'laptop')
|
|
47328
|
+
this.viewportLaptopDeviceForm.reset({ viewportLaptopDevice: '' });
|
|
47329
|
+
if (mode !== 'tablet')
|
|
47330
|
+
this.viewportTabletDeviceForm.reset({ viewportTabletDevice: '' });
|
|
47331
|
+
if (mode !== 'mobile')
|
|
47332
|
+
this.viewportMobileDeviceForm.reset({ viewportMobileDevice: '' });
|
|
47333
|
+
if (mode !== 'custom') {
|
|
47334
|
+
this.customViewportWidth = '';
|
|
47335
|
+
this.customViewportHeight = '';
|
|
47336
|
+
this.customViewportTags = [];
|
|
47337
|
+
}
|
|
47338
|
+
this.cdr.markForCheck();
|
|
47339
|
+
}
|
|
47340
|
+
applyViewportCategoryOptions() {
|
|
47341
|
+
const opts = this.viewportCategoryOptions || {};
|
|
47342
|
+
if (opts.DESKTOP)
|
|
47343
|
+
this.desktopViewportConfig = Object.assign(Object.assign({}, this.desktopViewportConfig), { options: opts.DESKTOP });
|
|
47344
|
+
if (opts.LAPTOP)
|
|
47345
|
+
this.laptopViewportConfig = Object.assign(Object.assign({}, this.laptopViewportConfig), { options: opts.LAPTOP });
|
|
47346
|
+
if (opts.TABLET)
|
|
47347
|
+
this.tabletViewportConfig = Object.assign(Object.assign({}, this.tabletViewportConfig), { options: opts.TABLET });
|
|
47348
|
+
if (opts.MOBILE)
|
|
47349
|
+
this.mobileViewportConfig = Object.assign(Object.assign({}, this.mobileViewportConfig), { options: opts.MOBILE });
|
|
47350
|
+
this.cdr.markForCheck();
|
|
47351
|
+
}
|
|
47352
|
+
addViewportCustomTag() {
|
|
47353
|
+
const w = (this.customViewportWidth || '').trim();
|
|
47354
|
+
const h = (this.customViewportHeight || '').trim();
|
|
47355
|
+
if (!w || !h)
|
|
47356
|
+
return;
|
|
47357
|
+
const tag = `${w}*${h}`;
|
|
47358
|
+
if (!this.customViewportTags.includes(tag)) {
|
|
47359
|
+
this.customViewportTags = [...this.customViewportTags, tag];
|
|
47360
|
+
}
|
|
47361
|
+
this.customViewportWidth = '';
|
|
47362
|
+
this.customViewportHeight = '';
|
|
47363
|
+
this.cdr.markForCheck();
|
|
47364
|
+
}
|
|
47365
|
+
removeViewportCustomTag(index) {
|
|
47366
|
+
this.customViewportTags = this.customViewportTags.filter((_, i) => i !== index);
|
|
47367
|
+
this.cdr.markForCheck();
|
|
47368
|
+
}
|
|
47145
47369
|
ngOnInit() {
|
|
47146
47370
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
|
|
47147
47371
|
this.editDescription = this.descriptionContent;
|
|
@@ -47178,6 +47402,7 @@ class TestCaseDetailsEditComponent {
|
|
|
47178
47402
|
const defaultViewport = this.getDeviceConfigValue('Default Viewport') || this.getDeviceConfigValue('Viewport') || '';
|
|
47179
47403
|
const deviceType = this.getConfigItemValue('Device', 'Type');
|
|
47180
47404
|
const deviceOS = this.getConfigItemValue('Device', 'OS');
|
|
47405
|
+
this.initViewportFromValue(defaultViewport);
|
|
47181
47406
|
this._labelsSelectConfigDirty = true;
|
|
47182
47407
|
this.editApiMockingRestoreMock = !!this.apiMockingRestoreMock;
|
|
47183
47408
|
this.editApiMockingStoreMock = !!this.apiMockingStoreMock;
|
|
@@ -47362,6 +47587,9 @@ class TestCaseDetailsEditComponent {
|
|
|
47362
47587
|
if (changes['prerequisiteCaseOptions'] && this.prerequisiteCaseOptions.length) {
|
|
47363
47588
|
this.prerequisiteCaseSelectConfig = Object.assign(Object.assign({}, this.prerequisiteCaseSelectConfig), { options: this.prerequisiteCaseOptions });
|
|
47364
47589
|
}
|
|
47590
|
+
if (changes['viewportCategoryOptions']) {
|
|
47591
|
+
this.applyViewportCategoryOptions();
|
|
47592
|
+
}
|
|
47365
47593
|
if (changes['configSections'] || changes['configSectionsRow2']) {
|
|
47366
47594
|
const enableAiSmartness = this.getConfigItemValue('AI Configuration', 'Enable AI Smartness');
|
|
47367
47595
|
const defaultAiAction = this.getConfigItemValue('AI Configuration', 'Default AI Action');
|
|
@@ -47382,6 +47610,7 @@ class TestCaseDetailsEditComponent {
|
|
|
47382
47610
|
const defaultViewport = this.getDeviceConfigValue('Default Viewport') || this.getDeviceConfigValue('Viewport') || '';
|
|
47383
47611
|
const deviceType = this.getConfigItemValue('Device', 'Type');
|
|
47384
47612
|
const deviceOS = this.getConfigItemValue('Device', 'OS');
|
|
47613
|
+
this.initViewportFromValue(defaultViewport);
|
|
47385
47614
|
const autoWaitVal = this.getWaitsRetriesValue('Enable Avoid Auto wait for steps') || this.getConfigItemValue('Waits & Retries', 'Auto Wait');
|
|
47386
47615
|
this.autoWaitEnabled = !!(autoWaitVal && autoWaitVal.trim() !== '' && String(autoWaitVal) !== 'false');
|
|
47387
47616
|
this.retryFailedSteps = this.getWaitsRetriesValue('Retry Failed Steps');
|
|
@@ -47512,12 +47741,12 @@ class TestCaseDetailsEditComponent {
|
|
|
47512
47741
|
});
|
|
47513
47742
|
}
|
|
47514
47743
|
mergeConfigSectionsRow2() {
|
|
47515
|
-
var _a, _b, _c, _d, _e, _f
|
|
47744
|
+
var _a, _b, _c, _d, _e, _f;
|
|
47516
47745
|
const platform = this.platform;
|
|
47517
47746
|
const defaultBrowser = (_b = (_a = this.editForm.get('defaultBrowser')) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '';
|
|
47518
|
-
const defaultViewport =
|
|
47519
|
-
const deviceType = (
|
|
47520
|
-
const deviceOS = (
|
|
47747
|
+
const defaultViewport = this.buildViewportValue();
|
|
47748
|
+
const deviceType = (_d = (_c = this.editForm.get('deviceType')) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '';
|
|
47749
|
+
const deviceOS = (_f = (_e = this.editForm.get('deviceOS')) === null || _e === void 0 ? void 0 : _e.value) !== null && _f !== void 0 ? _f : '';
|
|
47521
47750
|
let result = this.configSectionsRow2.map((section) => {
|
|
47522
47751
|
if (section.title === 'Waits & Retries' || section.title === 'Wait and retries') {
|
|
47523
47752
|
const autoWaitValue = this.autoWaitEnabled ? 'Enabled' : '';
|
|
@@ -47617,10 +47846,10 @@ class TestCaseDetailsEditComponent {
|
|
|
47617
47846
|
}
|
|
47618
47847
|
}
|
|
47619
47848
|
TestCaseDetailsEditComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseDetailsEditComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
47620
|
-
TestCaseDetailsEditComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestCaseDetailsEditComponent, selector: "cqa-test-case-details-edit", inputs: { descriptionTitle: "descriptionTitle", descriptionContent: "descriptionContent", enableMarkdown: "enableMarkdown", metadataItems: "metadataItems", labels: "labels", configTitle: "configTitle", configSections: "configSections", configSectionsRow2: "configSectionsRow2", isSaving: "isSaving", prerequisiteCaseOptions: "prerequisiteCaseOptions", platform: "platform", isStepGroup: "isStepGroup", selectConfigOverrides: "selectConfigOverrides", showApiMockingCard: "showApiMockingCard", apiMockingTitle: "apiMockingTitle", apiMockingStatusLabel: "apiMockingStatusLabel", apiMockingCaptureLabel: "apiMockingCaptureLabel", apiMockingCaptureHint: "apiMockingCaptureHint", apiMockingRenewLabel: "apiMockingRenewLabel", apiMockingRenewHint: "apiMockingRenewHint", apiMockingRestoreMock: "apiMockingRestoreMock", apiMockingStoreMock: "apiMockingStoreMock", apiMockingMockedApisCount: "apiMockingMockedApisCount", apiMockingTotalApisCount: "apiMockingTotalApisCount", apiMockingProgressPercent: "apiMockingProgressPercent", apiMockingShowProgress: "apiMockingShowProgress", apiMockingSummaryText: "apiMockingSummaryText", apiMockingPercentText: "apiMockingPercentText", orgLevelTestCaseTimeout: "orgLevelTestCaseTimeout" }, outputs: { save: "save", cancel: "cancel", selectSearch: "selectSearch", selectLoadMore: "selectLoadMore", selectOpened: "selectOpened", selectionChange: "selectionChange", labelAdded: "labelAdded", apiMockingRestoreMockChange: "apiMockingRestoreMockChange", apiMockingStoreMockChange: "apiMockingStoreMockChange", configureApiMocking: "configureApiMocking" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-4 cqa-text-sm cqa-leading-[19.6px] cqa-rounded-lg cqa-border cqa-border-[#E2E8F0] cqa-py-4\">\n <!-- Basic details: Description, Status/Priority/Type, Labels (light background container) -->\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-4 cqa-rounded-lg cqa-border cqa-border-[#E2E8F0] cqa-bg-[#F8F9FE] cqa-p-4\">\n <!-- Description (Figma: document icon, textarea with light purple bg) -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">description</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.6px]\">{{ descriptionTitle }}</span>\n </div>\n <cqa-custom-textarea\n [value]=\"editDescription\"\n (valueChange)=\"editDescription = $event\"\n [fullWidth]=\"true\"\n [rows]=\"4\"\n [enableMarkdown]=\"enableMarkdown\"\n placeholder=\"Enter description...\"\n textareaInlineStyle=\"padding: 12px; font-size: 12px; line-height: 100%\"\n class=\"cqa-w-full\">\n </cqa-custom-textarea>\n </div>\n\n <!-- Status, Priority & Type (Figma: side-by-side dropdowns, cqa-dynamic-select) -->\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <label class=\"cqa-text-[#6B7280] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Status</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('status', statusSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('status')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div *ngIf=\"!isStepGroup\" class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <label class=\"cqa-text-[#6B7280] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Priority</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('priority', prioritySelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('priority')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div *ngIf=\"!isStepGroup\" class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <label class=\"cqa-text-[#6B7280] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Type</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('type', typeSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('type')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n </div>\n\n <!-- Labels (Figma: Current Labels with Clear All, cqa-badge with x, Frequently used, Search) -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5\">\n <div class=\"cqa-flex cqa-items-center cqa-justify-between\">\n <span class=\"cqa-text-[#374151] cqa-text-[15px] cqa-leading-[19.6px] cqa-font-medium\">Current Labels ({{ editLabels.length }})</span>\n <button\n type=\"button\"\n *ngIf=\"editLabels.length > 0\"\n class=\"cqa-text-xs cqa-text-[#DC2626] hover:cqa-underline cqa-font-normal\"\n (click)=\"onClearAllLabels()\">\n Clear All\n </button>\n </div>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2\" *ngIf=\"editLabels.length > 0\">\n <div\n *ngFor=\"let label of editLabels; trackBy: trackByLabel\"\n class=\"cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-px-2.5 cqa-py-1 cqa-text-xs cqa-font-medium cqa-rounded-md cqa-border\"\n [ngStyle]=\"getCurrentLabelChipStyle(label)\">\n <span>{{ label }}</span>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-3.5 cqa-h-3.5 cqa-rounded hover:cqa-opacity-80 cqa-transition-opacity cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n [style.color]=\"getLabelCloseIconColor(label)\"\n (click)=\"onRemoveLabel(label)\"\n [attr.aria-label]=\"'Remove ' + label\">\n <mat-icon class=\"cqa-text-[14px] cqa-w-3.5 cqa-h-3.5\">close</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Frequently used</span>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2\">\n <button\n *ngFor=\"let label of frequentlyUsedLabels; trackBy: trackByLabel\"\n type=\"button\"\n class=\"cqa-cursor-pointer\"\n (click)=\"onAddFrequentLabel(label)\">\n <cqa-badge\n [label]=\"label\"\n variant=\"default\"\n size=\"small\"\n backgroundColor=\"#E8E9FF\"\n textColor=\"#3F43EE\"\n borderColor=\"#E8E9FF\">\n </cqa-badge>\n </button>\n </div>\n </div>\n <label class=\"cqa-text-[#374151] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Add labels</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"labelsSelectConfig\"\n (searchChange)=\"onSelectSearch($event)\"\n (selectClick)=\"onSelectOpened('labels')\"\n (selectionChange)=\"onSelectionChange($event)\"\n (addCustomValue)=\"onLabelsAddCustomValue($event)\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n </div>\n </div>\n\n\n <!-- Configuration (Figma: collapsible, gear icon, light background container) -->\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-[12px] cqa-rounded-lg cqa-border cqa-border-[#E2E8F0] cqa-bg-[#F8F9FE] cqa-p-4\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-text-left cqa-w-full\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">settings</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.5px]\">{{ configTitle }}</span>\n </div>\n\n <div *ngIf=\"configExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-5 cqa-text-xs\">\n <!-- Execution -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"executionExpanded = !executionExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">play_circle</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Execution</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ executionExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"executionExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-min-w-0 cqa-w-full\">\n <!-- <div *ngIf=\"hasPrerequisiteCaseConfig\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\"> \n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('prerequisiteCases', prerequisiteCaseSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('prerequisiteCases')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div> -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-text-[#6B7280] cqa-text-xs cqa-font-medium\">Test Data Profile</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('testDataProfile', testDataProfileSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('testDataProfile')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div *ngIf=\"!isStepGroup\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-text-[#687389] cqa-text-xs cqa-font-medium\">Test Data Set</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('testDataSet', testDataSetSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('testDataSet')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <!-- <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-text-[#6B7280] cqa-text-xs cqa-font-medium\">Video Recording</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('videoRecording', videoRecordingSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('videoRecording')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div> -->\n </div>\n </div>\n <!-- AI Configuration -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"aiConfigExpanded = !aiConfigExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">smart_toy</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">AI Configuration</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ aiConfigExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"aiConfigExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-py-0 cqa-min-w-0 cqa-w-full\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('enableAiSmartness', enableAiSmartnessSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('enableAiSmartness')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('defaultAiAction', defaultAiActionSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('defaultAiAction')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('knowledgeBaseDefaultTestCase', knowledgeBaseDefaultTestCaseSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('knowledgeBaseDefaultTestCase')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('useAiMetadata', aiMetadataCollectionSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('useAiMetadata')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n </div>\n </div>\n <!-- Waits & Retries-->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"waitsRetriesExpanded = !waitsRetriesExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">timer</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Wait and Retries</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ waitsRetriesExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"waitsRetriesExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-min-w-0 cqa-w-full\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"autoWaitEnabled\" (checkedChange)=\"autoWaitEnabled = $event\" ariaLabel=\"Enable Avoid Auto wait for steps\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Enable Avoid Auto wait for steps</span>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-custom-input\n type=\"number\"\n label=\"Retry Failed Steps\"\n [value]=\"retryFailedSteps\"\n (valueChange)=\"retryFailedSteps = onlyDigits($event)\"\n placeholder=\"0\"\n [fullWidth]=\"true\"\n size=\"sm\"\n labelInlineStyle=\"font-size: 14px; line-height: 19.6px\">\n </cqa-custom-input>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-font-medium cqa-text-[#374151] cqa-text-xs cqa-mb-1\" style=\"font-size: 14px; line-height: 19.6px\">\n Test Case Timeout (minutes)\n </label>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-min-w-0 cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-rounded-md cqa-border cqa-border-solid cqa-border-gray-200\">\n <cqa-dropdown-button\n [options]=\"testCaseTimeoutModeOptions\"\n [selectedValue]=\"testCaseTimeoutMode\"\n (selectionChange)=\"onTestCaseTimeoutModeChange($event)\">\n </cqa-dropdown-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-custom-input\n type=\"number\"\n [value]=\"testCaseTimeoutDisplayValue\"\n [disabled]=\"testCaseTimeoutMode === 'org'\"\n (valueChange)=\"testCaseTimeout = onlyDigits($event)\"\n placeholder=\"30\"\n [fullWidth]=\"true\"\n size=\"sm\">\n </cqa-custom-input>\n </div>\n </div>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-custom-input\n type=\"number\"\n label=\"Wait Timeout for Locators (sec)\"\n [value]=\"waitTimeoutLocators\"\n (valueChange)=\"waitTimeoutLocators = onlyDigits($event)\"\n placeholder=\"15\"\n [fullWidth]=\"true\"\n size=\"sm\"\n labelInlineStyle=\"font-size: 14px; line-height: 19.6px\">\n </cqa-custom-input>\n </div>\n </div>\n </div>\n <div *ngIf=\"platform !== 'mobile'\" class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"deviceExpanded = !deviceExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">devices</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Device Settings</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ deviceExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"deviceExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-min-w-0 cqa-w-full\">\n <!-- Web only: mobile Device Settings hidden temporarily -->\n <div class=\"cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('defaultBrowser', defaultBrowserSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('defaultBrowser')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div class=\"cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('defaultViewport', defaultViewportSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('defaultViewport')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n </div>\n </div>\n <!-- Key Flags -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-0 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"keyFlagsExpanded = !keyFlagsExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">flag</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Key Flags</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ keyFlagsExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"keyFlagsExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"mobileTestingEnabled\" (checkedChange)=\"mobileTestingEnabled = $event\" ariaLabel=\"Mobile Testing\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Mobile Testing</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"extensionUseEnabled\" (checkedChange)=\"extensionUseEnabled = $event\" ariaLabel=\"Extension Use\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Extension Use</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"dataDrivenEnabled\" (checkedChange)=\"dataDrivenEnabled = $event\" ariaLabel=\"Data Driven\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Data Driven</span>\n </div>\n </div>\n </div>\n\n \n <!-- API Mocking Card (edit mode: mutually-exclusive toggles driven by one boolean) -->\n <cqa-api-mocking-card\n *ngIf=\"showApiMockingCard\"\n style=\"width: 100%;\"\n [title]=\"apiMockingTitle\"\n [statusLabel]=\"apiMockingStatusLabel\"\n [captureLabel]=\"apiMockingCaptureLabel\"\n [captureHint]=\"apiMockingCaptureHint\"\n [renewLabel]=\"apiMockingRenewLabel\"\n [renewHint]=\"apiMockingRenewHint\"\n [restoreMock]=\"editApiMockingRestoreMock\"\n [storeMock]=\"editApiMockingStoreMock\"\n [mockedApisCount]=\"apiMockingMockedApisCount\"\n [totalApisCount]=\"apiMockingTotalApisCount\"\n [progressPercent]=\"apiMockingProgressPercent\"\n [showProgress]=\"apiMockingShowProgress\"\n [summaryText]=\"apiMockingSummaryText\"\n [percentText]=\"apiMockingPercentText\"\n [editing]=\"true\"\n (restoreMockChange)=\"onApiMockingRestoreMockChange($event)\"\n (storeMockChange)=\"onApiMockingStoreMockChange($event)\"\n (configure)=\"configureApiMocking.emit()\">\n </cqa-api-mocking-card>\n </div>\n </div>\n\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-gap-3 cqa-pt-2 cqa-w-full\">\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button\n variant=\"outlined\"\n [text]=\"'Cancel'\"\n btnSize=\"md\"\n [fullWidth]=\"true\"\n (clicked)=\"onCancel()\">\n </cqa-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button\n *ngIf=\"!isSaving\"\n variant=\"filled\"\n [text]=\"'Save Changes'\"\n btnSize=\"md\"\n [fullWidth]=\"true\"\n [disabled]=\"!hasUnsavedChanges\"\n (clicked)=\"onSave()\">\n </cqa-button>\n <div *ngIf=\"isSaving\" class=\"cqa-w-full\">\n <cqa-badge\n label=\"Saving\u2026\"\n icon=\"autorenew\"\n [isLoading]=\"true\"\n [fullWidth]=\"true\"\n [centerContent]=\"true\"\n variant=\"info\"\n size=\"medium\">\n </cqa-badge>\n </div>\n </div>\n </div>\n</div>\n", components: [{ type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: CustomTextareaComponent, selector: "cqa-custom-textarea", inputs: ["label", "placeholder", "value", "enableMarkdown", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "rows", "cols", "resize", "textareaInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused"] }, { type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore", "addCustomValue"] }, { type: BadgeComponent, selector: "cqa-badge", inputs: ["type", "label", "icon", "iconLibrary", "variant", "size", "backgroundColor", "textColor", "borderColor", "iconBackgroundColor", "iconColor", "iconSize", "inlineStyles", "key", "value", "keyTextColor", "valueTextColor", "isLoading", "fullWidth", "centerContent", "title"] }, { type: CustomToggleComponent, selector: "cqa-custom-toggle", inputs: ["checked", "disabled", "ariaLabel"], outputs: ["checkedChange", "change"] }, { type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["inputId", "label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }, { type: DropdownButtonComponent, selector: "cqa-dropdown-button", inputs: ["label", "options", "selectedValue", "disabled", "placeholder"], outputs: ["selectionChange", "opened", "closed"] }, { type: ApiMockingCardComponent, selector: "cqa-api-mocking-card", inputs: ["title", "statusLabel", "captureLabel", "captureHint", "renewLabel", "renewHint", "restoreMock", "storeMock", "mockedApisCount", "totalApisCount", "progressPercent", "summaryText", "percentText", "configureButtonLabel", "editing", "showProgress", "noDataHint"], outputs: ["configure", "restoreMockChange", "storeMockChange"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "loading", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
47849
|
+
TestCaseDetailsEditComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestCaseDetailsEditComponent, selector: "cqa-test-case-details-edit", inputs: { descriptionTitle: "descriptionTitle", descriptionContent: "descriptionContent", enableMarkdown: "enableMarkdown", metadataItems: "metadataItems", labels: "labels", configTitle: "configTitle", configSections: "configSections", configSectionsRow2: "configSectionsRow2", isSaving: "isSaving", prerequisiteCaseOptions: "prerequisiteCaseOptions", platform: "platform", isStepGroup: "isStepGroup", selectConfigOverrides: "selectConfigOverrides", showApiMockingCard: "showApiMockingCard", apiMockingTitle: "apiMockingTitle", apiMockingStatusLabel: "apiMockingStatusLabel", apiMockingCaptureLabel: "apiMockingCaptureLabel", apiMockingCaptureHint: "apiMockingCaptureHint", apiMockingRenewLabel: "apiMockingRenewLabel", apiMockingRenewHint: "apiMockingRenewHint", apiMockingRestoreMock: "apiMockingRestoreMock", apiMockingStoreMock: "apiMockingStoreMock", apiMockingMockedApisCount: "apiMockingMockedApisCount", apiMockingTotalApisCount: "apiMockingTotalApisCount", apiMockingProgressPercent: "apiMockingProgressPercent", apiMockingShowProgress: "apiMockingShowProgress", apiMockingSummaryText: "apiMockingSummaryText", apiMockingPercentText: "apiMockingPercentText", orgLevelTestCaseTimeout: "orgLevelTestCaseTimeout", viewportCategoryOptions: "viewportCategoryOptions" }, outputs: { save: "save", cancel: "cancel", selectSearch: "selectSearch", selectLoadMore: "selectLoadMore", selectOpened: "selectOpened", selectionChange: "selectionChange", labelAdded: "labelAdded", apiMockingRestoreMockChange: "apiMockingRestoreMockChange", apiMockingStoreMockChange: "apiMockingStoreMockChange", configureApiMocking: "configureApiMocking" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-4 cqa-text-sm cqa-leading-[19.6px] cqa-rounded-lg cqa-border cqa-border-[#E2E8F0] cqa-py-4\">\n <!-- Basic details: Description, Status/Priority/Type, Labels (light background container) -->\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-4 cqa-rounded-lg cqa-border cqa-border-[#E2E8F0] cqa-bg-[#F8F9FE] cqa-p-4\">\n <!-- Description (Figma: document icon, textarea with light purple bg) -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">description</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.6px]\">{{ descriptionTitle }}</span>\n </div>\n <cqa-custom-textarea\n [value]=\"editDescription\"\n (valueChange)=\"editDescription = $event\"\n [fullWidth]=\"true\"\n [rows]=\"4\"\n [enableMarkdown]=\"enableMarkdown\"\n placeholder=\"Enter description...\"\n textareaInlineStyle=\"padding: 12px; font-size: 12px; line-height: 100%\"\n class=\"cqa-w-full\">\n </cqa-custom-textarea>\n </div>\n\n <!-- Status, Priority & Type (Figma: side-by-side dropdowns, cqa-dynamic-select) -->\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <label class=\"cqa-text-[#6B7280] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Status</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('status', statusSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('status')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div *ngIf=\"!isStepGroup\" class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <label class=\"cqa-text-[#6B7280] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Priority</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('priority', prioritySelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('priority')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div *ngIf=\"!isStepGroup\" class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <label class=\"cqa-text-[#6B7280] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Type</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('type', typeSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('type')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n </div>\n\n <!-- Labels (Figma: Current Labels with Clear All, cqa-badge with x, Frequently used, Search) -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5\">\n <div class=\"cqa-flex cqa-items-center cqa-justify-between\">\n <span class=\"cqa-text-[#374151] cqa-text-[15px] cqa-leading-[19.6px] cqa-font-medium\">Current Labels ({{ editLabels.length }})</span>\n <button\n type=\"button\"\n *ngIf=\"editLabels.length > 0\"\n class=\"cqa-text-xs cqa-text-[#DC2626] hover:cqa-underline cqa-font-normal\"\n (click)=\"onClearAllLabels()\">\n Clear All\n </button>\n </div>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2\" *ngIf=\"editLabels.length > 0\">\n <div\n *ngFor=\"let label of editLabels; trackBy: trackByLabel\"\n class=\"cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-px-2.5 cqa-py-1 cqa-text-xs cqa-font-medium cqa-rounded-md cqa-border\"\n [ngStyle]=\"getCurrentLabelChipStyle(label)\">\n <span>{{ label }}</span>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-3.5 cqa-h-3.5 cqa-rounded hover:cqa-opacity-80 cqa-transition-opacity cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n [style.color]=\"getLabelCloseIconColor(label)\"\n (click)=\"onRemoveLabel(label)\"\n [attr.aria-label]=\"'Remove ' + label\">\n <mat-icon class=\"cqa-text-[14px] cqa-w-3.5 cqa-h-3.5\">close</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Frequently used</span>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2\">\n <button\n *ngFor=\"let label of frequentlyUsedLabels; trackBy: trackByLabel\"\n type=\"button\"\n class=\"cqa-cursor-pointer\"\n (click)=\"onAddFrequentLabel(label)\">\n <cqa-badge\n [label]=\"label\"\n variant=\"default\"\n size=\"small\"\n backgroundColor=\"#E8E9FF\"\n textColor=\"#3F43EE\"\n borderColor=\"#E8E9FF\">\n </cqa-badge>\n </button>\n </div>\n </div>\n <label class=\"cqa-text-[#374151] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Add labels</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"labelsSelectConfig\"\n (searchChange)=\"onSelectSearch($event)\"\n (selectClick)=\"onSelectOpened('labels')\"\n (selectionChange)=\"onSelectionChange($event)\"\n (addCustomValue)=\"onLabelsAddCustomValue($event)\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n </div>\n </div>\n\n\n <!-- Configuration (Figma: collapsible, gear icon, light background container) -->\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-[12px] cqa-rounded-lg cqa-border cqa-border-[#E2E8F0] cqa-bg-[#F8F9FE] cqa-p-4\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-text-left cqa-w-full\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">settings</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.5px]\">{{ configTitle }}</span>\n </div>\n\n <div *ngIf=\"configExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-5 cqa-text-xs\">\n <!-- Execution -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"executionExpanded = !executionExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">play_circle</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Execution</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ executionExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"executionExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-min-w-0 cqa-w-full\">\n <!-- <div *ngIf=\"hasPrerequisiteCaseConfig\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\"> \n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('prerequisiteCases', prerequisiteCaseSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('prerequisiteCases')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div> -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-text-[#6B7280] cqa-text-xs cqa-font-medium\">Test Data Profile</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('testDataProfile', testDataProfileSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('testDataProfile')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div *ngIf=\"!isStepGroup\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-text-[#687389] cqa-text-xs cqa-font-medium\">Test Data Set</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('testDataSet', testDataSetSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('testDataSet')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <!-- <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-text-[#6B7280] cqa-text-xs cqa-font-medium\">Video Recording</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('videoRecording', videoRecordingSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('videoRecording')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div> -->\n </div>\n </div>\n <!-- AI Configuration -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"aiConfigExpanded = !aiConfigExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">smart_toy</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">AI Configuration</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ aiConfigExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"aiConfigExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-py-0 cqa-min-w-0 cqa-w-full\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('enableAiSmartness', enableAiSmartnessSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('enableAiSmartness')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('defaultAiAction', defaultAiActionSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('defaultAiAction')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('knowledgeBaseDefaultTestCase', knowledgeBaseDefaultTestCaseSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('knowledgeBaseDefaultTestCase')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('useAiMetadata', aiMetadataCollectionSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('useAiMetadata')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n </div>\n </div>\n <!-- Waits & Retries-->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"waitsRetriesExpanded = !waitsRetriesExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">timer</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Wait and Retries</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ waitsRetriesExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"waitsRetriesExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-min-w-0 cqa-w-full\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"autoWaitEnabled\" (checkedChange)=\"autoWaitEnabled = $event\" ariaLabel=\"Enable Avoid Auto wait for steps\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Enable Avoid Auto wait for steps</span>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-custom-input\n type=\"number\"\n label=\"Retry Failed Steps\"\n [value]=\"retryFailedSteps\"\n (valueChange)=\"retryFailedSteps = onlyDigits($event)\"\n placeholder=\"0\"\n [fullWidth]=\"true\"\n size=\"sm\"\n labelInlineStyle=\"font-size: 14px; line-height: 19.6px\">\n </cqa-custom-input>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-font-medium cqa-text-[#374151] cqa-text-xs cqa-mb-1\" style=\"font-size: 14px; line-height: 19.6px\">\n Test Case Timeout (minutes)\n </label>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-min-w-0 cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-rounded-md cqa-border cqa-border-solid cqa-border-gray-200\">\n <cqa-dropdown-button\n [options]=\"testCaseTimeoutModeOptions\"\n [selectedValue]=\"testCaseTimeoutMode\"\n (selectionChange)=\"onTestCaseTimeoutModeChange($event)\">\n </cqa-dropdown-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-custom-input\n type=\"number\"\n [value]=\"testCaseTimeoutDisplayValue\"\n [disabled]=\"testCaseTimeoutMode === 'org'\"\n (valueChange)=\"testCaseTimeout = onlyDigits($event)\"\n placeholder=\"30\"\n [fullWidth]=\"true\"\n size=\"sm\">\n </cqa-custom-input>\n </div>\n </div>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-custom-input\n type=\"number\"\n label=\"Wait Timeout for Locators (sec)\"\n [value]=\"waitTimeoutLocators\"\n (valueChange)=\"waitTimeoutLocators = onlyDigits($event)\"\n placeholder=\"15\"\n [fullWidth]=\"true\"\n size=\"sm\"\n labelInlineStyle=\"font-size: 14px; line-height: 19.6px\">\n </cqa-custom-input>\n </div>\n </div>\n </div>\n <div *ngIf=\"platform !== 'mobile'\" class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"deviceExpanded = !deviceExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">devices</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Device Settings</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ deviceExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"deviceExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-min-w-0 cqa-w-full\">\n <!-- Web only: mobile Device Settings hidden temporarily -->\n <div class=\"cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('defaultBrowser', defaultBrowserSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('defaultBrowser')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <!-- Viewport selector \u2014 replaces single dropdown -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <span class=\"cqa-text-[13px] cqa-font-medium cqa-text-[#374151] cqa-leading-[18.2px]\">Viewport</span>\n <cqa-radio-card-group\n class=\"viewport-selector\"\n [options]=\"viewportModeOptions\"\n [ngModel]=\"viewportMode\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onViewportModeChange($event)\">\n </cqa-radio-card-group>\n <div *ngIf=\"viewportMode === 'desktop'\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-medium cqa-text-[#6b7280]\">Resolution</span>\n <cqa-dynamic-select\n [form]=\"viewportDesktopDeviceForm\"\n [config]=\"desktopViewportConfig\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n </div>\n <div *ngIf=\"viewportMode === 'laptop'\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-medium cqa-text-[#6b7280]\">Resolution</span>\n <cqa-dynamic-select\n [form]=\"viewportLaptopDeviceForm\"\n [config]=\"laptopViewportConfig\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n </div>\n <div *ngIf=\"viewportMode === 'tablet'\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-medium cqa-text-[#6b7280]\">Resolution</span>\n <cqa-dynamic-select\n [form]=\"viewportTabletDeviceForm\"\n [config]=\"tabletViewportConfig\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n </div>\n <div *ngIf=\"viewportMode === 'mobile'\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-medium cqa-text-[#6b7280]\">Device</span>\n <cqa-dynamic-select\n [form]=\"viewportMobileDeviceForm\"\n [config]=\"mobileViewportConfig\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n </div>\n </div>\n </div>\n </div>\n <!-- Key Flags -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-0 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"keyFlagsExpanded = !keyFlagsExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">flag</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Key Flags</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ keyFlagsExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"keyFlagsExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"mobileTestingEnabled\" (checkedChange)=\"mobileTestingEnabled = $event\" ariaLabel=\"Mobile Testing\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Mobile Testing</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"extensionUseEnabled\" (checkedChange)=\"extensionUseEnabled = $event\" ariaLabel=\"Extension Use\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Extension Use</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"dataDrivenEnabled\" (checkedChange)=\"dataDrivenEnabled = $event\" ariaLabel=\"Data Driven\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Data Driven</span>\n </div>\n </div>\n </div>\n\n \n <!-- API Mocking Card (edit mode: mutually-exclusive toggles driven by one boolean) -->\n <cqa-api-mocking-card\n *ngIf=\"showApiMockingCard\"\n style=\"width: 100%;\"\n [title]=\"apiMockingTitle\"\n [statusLabel]=\"apiMockingStatusLabel\"\n [captureLabel]=\"apiMockingCaptureLabel\"\n [captureHint]=\"apiMockingCaptureHint\"\n [renewLabel]=\"apiMockingRenewLabel\"\n [renewHint]=\"apiMockingRenewHint\"\n [restoreMock]=\"editApiMockingRestoreMock\"\n [storeMock]=\"editApiMockingStoreMock\"\n [mockedApisCount]=\"apiMockingMockedApisCount\"\n [totalApisCount]=\"apiMockingTotalApisCount\"\n [progressPercent]=\"apiMockingProgressPercent\"\n [showProgress]=\"apiMockingShowProgress\"\n [summaryText]=\"apiMockingSummaryText\"\n [percentText]=\"apiMockingPercentText\"\n [editing]=\"true\"\n (restoreMockChange)=\"onApiMockingRestoreMockChange($event)\"\n (storeMockChange)=\"onApiMockingStoreMockChange($event)\"\n (configure)=\"configureApiMocking.emit()\">\n </cqa-api-mocking-card>\n </div>\n </div>\n\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-gap-3 cqa-pt-2 cqa-w-full\">\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button\n variant=\"outlined\"\n [text]=\"'Cancel'\"\n btnSize=\"md\"\n [fullWidth]=\"true\"\n (clicked)=\"onCancel()\">\n </cqa-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button\n *ngIf=\"!isSaving\"\n variant=\"filled\"\n [text]=\"'Save Changes'\"\n btnSize=\"md\"\n [fullWidth]=\"true\"\n [disabled]=\"!hasUnsavedChanges\"\n (clicked)=\"onSave()\">\n </cqa-button>\n <div *ngIf=\"isSaving\" class=\"cqa-w-full\">\n <cqa-badge\n label=\"Saving\u2026\"\n icon=\"autorenew\"\n [isLoading]=\"true\"\n [fullWidth]=\"true\"\n [centerContent]=\"true\"\n variant=\"info\"\n size=\"medium\">\n </cqa-badge>\n </div>\n </div>\n </div>\n</div>\n", components: [{ type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: CustomTextareaComponent, selector: "cqa-custom-textarea", inputs: ["label", "placeholder", "value", "enableMarkdown", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "rows", "cols", "resize", "textareaInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused"] }, { type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore", "addCustomValue"] }, { type: BadgeComponent, selector: "cqa-badge", inputs: ["type", "label", "icon", "iconLibrary", "variant", "size", "backgroundColor", "textColor", "borderColor", "iconBackgroundColor", "iconColor", "iconSize", "inlineStyles", "key", "value", "keyTextColor", "valueTextColor", "isLoading", "fullWidth", "centerContent", "title"] }, { type: CustomToggleComponent, selector: "cqa-custom-toggle", inputs: ["checked", "disabled", "ariaLabel"], outputs: ["checkedChange", "change"] }, { type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["inputId", "label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }, { type: DropdownButtonComponent, selector: "cqa-dropdown-button", inputs: ["label", "options", "selectedValue", "disabled", "placeholder"], outputs: ["selectionChange", "opened", "closed"] }, { type: RadioCardGroupComponent, selector: "cqa-radio-card-group", inputs: ["options", "wrap", "disabled"], outputs: ["selectionChange"] }, { type: ApiMockingCardComponent, selector: "cqa-api-mocking-card", inputs: ["title", "statusLabel", "captureLabel", "captureHint", "renewLabel", "renewHint", "restoreMock", "storeMock", "mockedApisCount", "totalApisCount", "progressPercent", "summaryText", "percentText", "configureButtonLabel", "editing", "showProgress", "noDataHint"], outputs: ["configure", "restoreMockChange", "storeMockChange"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "loading", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
47621
47850
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseDetailsEditComponent, decorators: [{
|
|
47622
47851
|
type: Component,
|
|
47623
|
-
args: [{ selector: 'cqa-test-case-details-edit', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-4 cqa-text-sm cqa-leading-[19.6px] cqa-rounded-lg cqa-border cqa-border-[#E2E8F0] cqa-py-4\">\n <!-- Basic details: Description, Status/Priority/Type, Labels (light background container) -->\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-4 cqa-rounded-lg cqa-border cqa-border-[#E2E8F0] cqa-bg-[#F8F9FE] cqa-p-4\">\n <!-- Description (Figma: document icon, textarea with light purple bg) -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">description</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.6px]\">{{ descriptionTitle }}</span>\n </div>\n <cqa-custom-textarea\n [value]=\"editDescription\"\n (valueChange)=\"editDescription = $event\"\n [fullWidth]=\"true\"\n [rows]=\"4\"\n [enableMarkdown]=\"enableMarkdown\"\n placeholder=\"Enter description...\"\n textareaInlineStyle=\"padding: 12px; font-size: 12px; line-height: 100%\"\n class=\"cqa-w-full\">\n </cqa-custom-textarea>\n </div>\n\n <!-- Status, Priority & Type (Figma: side-by-side dropdowns, cqa-dynamic-select) -->\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <label class=\"cqa-text-[#6B7280] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Status</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('status', statusSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('status')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div *ngIf=\"!isStepGroup\" class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <label class=\"cqa-text-[#6B7280] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Priority</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('priority', prioritySelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('priority')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div *ngIf=\"!isStepGroup\" class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <label class=\"cqa-text-[#6B7280] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Type</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('type', typeSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('type')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n </div>\n\n <!-- Labels (Figma: Current Labels with Clear All, cqa-badge with x, Frequently used, Search) -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5\">\n <div class=\"cqa-flex cqa-items-center cqa-justify-between\">\n <span class=\"cqa-text-[#374151] cqa-text-[15px] cqa-leading-[19.6px] cqa-font-medium\">Current Labels ({{ editLabels.length }})</span>\n <button\n type=\"button\"\n *ngIf=\"editLabels.length > 0\"\n class=\"cqa-text-xs cqa-text-[#DC2626] hover:cqa-underline cqa-font-normal\"\n (click)=\"onClearAllLabels()\">\n Clear All\n </button>\n </div>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2\" *ngIf=\"editLabels.length > 0\">\n <div\n *ngFor=\"let label of editLabels; trackBy: trackByLabel\"\n class=\"cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-px-2.5 cqa-py-1 cqa-text-xs cqa-font-medium cqa-rounded-md cqa-border\"\n [ngStyle]=\"getCurrentLabelChipStyle(label)\">\n <span>{{ label }}</span>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-3.5 cqa-h-3.5 cqa-rounded hover:cqa-opacity-80 cqa-transition-opacity cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n [style.color]=\"getLabelCloseIconColor(label)\"\n (click)=\"onRemoveLabel(label)\"\n [attr.aria-label]=\"'Remove ' + label\">\n <mat-icon class=\"cqa-text-[14px] cqa-w-3.5 cqa-h-3.5\">close</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Frequently used</span>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2\">\n <button\n *ngFor=\"let label of frequentlyUsedLabels; trackBy: trackByLabel\"\n type=\"button\"\n class=\"cqa-cursor-pointer\"\n (click)=\"onAddFrequentLabel(label)\">\n <cqa-badge\n [label]=\"label\"\n variant=\"default\"\n size=\"small\"\n backgroundColor=\"#E8E9FF\"\n textColor=\"#3F43EE\"\n borderColor=\"#E8E9FF\">\n </cqa-badge>\n </button>\n </div>\n </div>\n <label class=\"cqa-text-[#374151] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Add labels</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"labelsSelectConfig\"\n (searchChange)=\"onSelectSearch($event)\"\n (selectClick)=\"onSelectOpened('labels')\"\n (selectionChange)=\"onSelectionChange($event)\"\n (addCustomValue)=\"onLabelsAddCustomValue($event)\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n </div>\n </div>\n\n\n <!-- Configuration (Figma: collapsible, gear icon, light background container) -->\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-[12px] cqa-rounded-lg cqa-border cqa-border-[#E2E8F0] cqa-bg-[#F8F9FE] cqa-p-4\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-text-left cqa-w-full\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">settings</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.5px]\">{{ configTitle }}</span>\n </div>\n\n <div *ngIf=\"configExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-5 cqa-text-xs\">\n <!-- Execution -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"executionExpanded = !executionExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">play_circle</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Execution</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ executionExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"executionExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-min-w-0 cqa-w-full\">\n <!-- <div *ngIf=\"hasPrerequisiteCaseConfig\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\"> \n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('prerequisiteCases', prerequisiteCaseSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('prerequisiteCases')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div> -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-text-[#6B7280] cqa-text-xs cqa-font-medium\">Test Data Profile</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('testDataProfile', testDataProfileSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('testDataProfile')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div *ngIf=\"!isStepGroup\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-text-[#687389] cqa-text-xs cqa-font-medium\">Test Data Set</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('testDataSet', testDataSetSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('testDataSet')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <!-- <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-text-[#6B7280] cqa-text-xs cqa-font-medium\">Video Recording</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('videoRecording', videoRecordingSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('videoRecording')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div> -->\n </div>\n </div>\n <!-- AI Configuration -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"aiConfigExpanded = !aiConfigExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">smart_toy</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">AI Configuration</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ aiConfigExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"aiConfigExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-py-0 cqa-min-w-0 cqa-w-full\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('enableAiSmartness', enableAiSmartnessSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('enableAiSmartness')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('defaultAiAction', defaultAiActionSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('defaultAiAction')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('knowledgeBaseDefaultTestCase', knowledgeBaseDefaultTestCaseSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('knowledgeBaseDefaultTestCase')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('useAiMetadata', aiMetadataCollectionSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('useAiMetadata')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n </div>\n </div>\n <!-- Waits & Retries-->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"waitsRetriesExpanded = !waitsRetriesExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">timer</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Wait and Retries</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ waitsRetriesExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"waitsRetriesExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-min-w-0 cqa-w-full\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"autoWaitEnabled\" (checkedChange)=\"autoWaitEnabled = $event\" ariaLabel=\"Enable Avoid Auto wait for steps\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Enable Avoid Auto wait for steps</span>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-custom-input\n type=\"number\"\n label=\"Retry Failed Steps\"\n [value]=\"retryFailedSteps\"\n (valueChange)=\"retryFailedSteps = onlyDigits($event)\"\n placeholder=\"0\"\n [fullWidth]=\"true\"\n size=\"sm\"\n labelInlineStyle=\"font-size: 14px; line-height: 19.6px\">\n </cqa-custom-input>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-font-medium cqa-text-[#374151] cqa-text-xs cqa-mb-1\" style=\"font-size: 14px; line-height: 19.6px\">\n Test Case Timeout (minutes)\n </label>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-min-w-0 cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-rounded-md cqa-border cqa-border-solid cqa-border-gray-200\">\n <cqa-dropdown-button\n [options]=\"testCaseTimeoutModeOptions\"\n [selectedValue]=\"testCaseTimeoutMode\"\n (selectionChange)=\"onTestCaseTimeoutModeChange($event)\">\n </cqa-dropdown-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-custom-input\n type=\"number\"\n [value]=\"testCaseTimeoutDisplayValue\"\n [disabled]=\"testCaseTimeoutMode === 'org'\"\n (valueChange)=\"testCaseTimeout = onlyDigits($event)\"\n placeholder=\"30\"\n [fullWidth]=\"true\"\n size=\"sm\">\n </cqa-custom-input>\n </div>\n </div>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-custom-input\n type=\"number\"\n label=\"Wait Timeout for Locators (sec)\"\n [value]=\"waitTimeoutLocators\"\n (valueChange)=\"waitTimeoutLocators = onlyDigits($event)\"\n placeholder=\"15\"\n [fullWidth]=\"true\"\n size=\"sm\"\n labelInlineStyle=\"font-size: 14px; line-height: 19.6px\">\n </cqa-custom-input>\n </div>\n </div>\n </div>\n <div *ngIf=\"platform !== 'mobile'\" class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"deviceExpanded = !deviceExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">devices</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Device Settings</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ deviceExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"deviceExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-min-w-0 cqa-w-full\">\n <!-- Web only: mobile Device Settings hidden temporarily -->\n <div class=\"cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('defaultBrowser', defaultBrowserSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('defaultBrowser')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div class=\"cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('defaultViewport', defaultViewportSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('defaultViewport')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n </div>\n </div>\n <!-- Key Flags -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-0 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"keyFlagsExpanded = !keyFlagsExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">flag</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Key Flags</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ keyFlagsExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"keyFlagsExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"mobileTestingEnabled\" (checkedChange)=\"mobileTestingEnabled = $event\" ariaLabel=\"Mobile Testing\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Mobile Testing</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"extensionUseEnabled\" (checkedChange)=\"extensionUseEnabled = $event\" ariaLabel=\"Extension Use\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Extension Use</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"dataDrivenEnabled\" (checkedChange)=\"dataDrivenEnabled = $event\" ariaLabel=\"Data Driven\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Data Driven</span>\n </div>\n </div>\n </div>\n\n \n <!-- API Mocking Card (edit mode: mutually-exclusive toggles driven by one boolean) -->\n <cqa-api-mocking-card\n *ngIf=\"showApiMockingCard\"\n style=\"width: 100%;\"\n [title]=\"apiMockingTitle\"\n [statusLabel]=\"apiMockingStatusLabel\"\n [captureLabel]=\"apiMockingCaptureLabel\"\n [captureHint]=\"apiMockingCaptureHint\"\n [renewLabel]=\"apiMockingRenewLabel\"\n [renewHint]=\"apiMockingRenewHint\"\n [restoreMock]=\"editApiMockingRestoreMock\"\n [storeMock]=\"editApiMockingStoreMock\"\n [mockedApisCount]=\"apiMockingMockedApisCount\"\n [totalApisCount]=\"apiMockingTotalApisCount\"\n [progressPercent]=\"apiMockingProgressPercent\"\n [showProgress]=\"apiMockingShowProgress\"\n [summaryText]=\"apiMockingSummaryText\"\n [percentText]=\"apiMockingPercentText\"\n [editing]=\"true\"\n (restoreMockChange)=\"onApiMockingRestoreMockChange($event)\"\n (storeMockChange)=\"onApiMockingStoreMockChange($event)\"\n (configure)=\"configureApiMocking.emit()\">\n </cqa-api-mocking-card>\n </div>\n </div>\n\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-gap-3 cqa-pt-2 cqa-w-full\">\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button\n variant=\"outlined\"\n [text]=\"'Cancel'\"\n btnSize=\"md\"\n [fullWidth]=\"true\"\n (clicked)=\"onCancel()\">\n </cqa-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button\n *ngIf=\"!isSaving\"\n variant=\"filled\"\n [text]=\"'Save Changes'\"\n btnSize=\"md\"\n [fullWidth]=\"true\"\n [disabled]=\"!hasUnsavedChanges\"\n (clicked)=\"onSave()\">\n </cqa-button>\n <div *ngIf=\"isSaving\" class=\"cqa-w-full\">\n <cqa-badge\n label=\"Saving\u2026\"\n icon=\"autorenew\"\n [isLoading]=\"true\"\n [fullWidth]=\"true\"\n [centerContent]=\"true\"\n variant=\"info\"\n size=\"medium\">\n </cqa-badge>\n </div>\n </div>\n </div>\n</div>\n" }]
|
|
47852
|
+
args: [{ selector: 'cqa-test-case-details-edit', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-4 cqa-text-sm cqa-leading-[19.6px] cqa-rounded-lg cqa-border cqa-border-[#E2E8F0] cqa-py-4\">\n <!-- Basic details: Description, Status/Priority/Type, Labels (light background container) -->\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-4 cqa-rounded-lg cqa-border cqa-border-[#E2E8F0] cqa-bg-[#F8F9FE] cqa-p-4\">\n <!-- Description (Figma: document icon, textarea with light purple bg) -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">description</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.6px]\">{{ descriptionTitle }}</span>\n </div>\n <cqa-custom-textarea\n [value]=\"editDescription\"\n (valueChange)=\"editDescription = $event\"\n [fullWidth]=\"true\"\n [rows]=\"4\"\n [enableMarkdown]=\"enableMarkdown\"\n placeholder=\"Enter description...\"\n textareaInlineStyle=\"padding: 12px; font-size: 12px; line-height: 100%\"\n class=\"cqa-w-full\">\n </cqa-custom-textarea>\n </div>\n\n <!-- Status, Priority & Type (Figma: side-by-side dropdowns, cqa-dynamic-select) -->\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <label class=\"cqa-text-[#6B7280] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Status</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('status', statusSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('status')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div *ngIf=\"!isStepGroup\" class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <label class=\"cqa-text-[#6B7280] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Priority</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('priority', prioritySelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('priority')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div *ngIf=\"!isStepGroup\" class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <label class=\"cqa-text-[#6B7280] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Type</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('type', typeSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('type')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n </div>\n\n <!-- Labels (Figma: Current Labels with Clear All, cqa-badge with x, Frequently used, Search) -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5\">\n <div class=\"cqa-flex cqa-items-center cqa-justify-between\">\n <span class=\"cqa-text-[#374151] cqa-text-[15px] cqa-leading-[19.6px] cqa-font-medium\">Current Labels ({{ editLabels.length }})</span>\n <button\n type=\"button\"\n *ngIf=\"editLabels.length > 0\"\n class=\"cqa-text-xs cqa-text-[#DC2626] hover:cqa-underline cqa-font-normal\"\n (click)=\"onClearAllLabels()\">\n Clear All\n </button>\n </div>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2\" *ngIf=\"editLabels.length > 0\">\n <div\n *ngFor=\"let label of editLabels; trackBy: trackByLabel\"\n class=\"cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-px-2.5 cqa-py-1 cqa-text-xs cqa-font-medium cqa-rounded-md cqa-border\"\n [ngStyle]=\"getCurrentLabelChipStyle(label)\">\n <span>{{ label }}</span>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-3.5 cqa-h-3.5 cqa-rounded hover:cqa-opacity-80 cqa-transition-opacity cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n [style.color]=\"getLabelCloseIconColor(label)\"\n (click)=\"onRemoveLabel(label)\"\n [attr.aria-label]=\"'Remove ' + label\">\n <mat-icon class=\"cqa-text-[14px] cqa-w-3.5 cqa-h-3.5\">close</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Frequently used</span>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2\">\n <button\n *ngFor=\"let label of frequentlyUsedLabels; trackBy: trackByLabel\"\n type=\"button\"\n class=\"cqa-cursor-pointer\"\n (click)=\"onAddFrequentLabel(label)\">\n <cqa-badge\n [label]=\"label\"\n variant=\"default\"\n size=\"small\"\n backgroundColor=\"#E8E9FF\"\n textColor=\"#3F43EE\"\n borderColor=\"#E8E9FF\">\n </cqa-badge>\n </button>\n </div>\n </div>\n <label class=\"cqa-text-[#374151] cqa-text-sm cqa-leading-[19.6px] cqa-font-medium\">Add labels</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"labelsSelectConfig\"\n (searchChange)=\"onSelectSearch($event)\"\n (selectClick)=\"onSelectOpened('labels')\"\n (selectionChange)=\"onSelectionChange($event)\"\n (addCustomValue)=\"onLabelsAddCustomValue($event)\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n </div>\n </div>\n\n\n <!-- Configuration (Figma: collapsible, gear icon, light background container) -->\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-[12px] cqa-rounded-lg cqa-border cqa-border-[#E2E8F0] cqa-bg-[#F8F9FE] cqa-p-4\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-text-left cqa-w-full\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">settings</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.5px]\">{{ configTitle }}</span>\n </div>\n\n <div *ngIf=\"configExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-5 cqa-text-xs\">\n <!-- Execution -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"executionExpanded = !executionExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">play_circle</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Execution</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ executionExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"executionExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-min-w-0 cqa-w-full\">\n <!-- <div *ngIf=\"hasPrerequisiteCaseConfig\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\"> \n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('prerequisiteCases', prerequisiteCaseSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('prerequisiteCases')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div> -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-text-[#6B7280] cqa-text-xs cqa-font-medium\">Test Data Profile</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('testDataProfile', testDataProfileSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('testDataProfile')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div *ngIf=\"!isStepGroup\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-text-[#687389] cqa-text-xs cqa-font-medium\">Test Data Set</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('testDataSet', testDataSetSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('testDataSet')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <!-- <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-text-[#6B7280] cqa-text-xs cqa-font-medium\">Video Recording</label>\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('videoRecording', videoRecordingSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('videoRecording')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div> -->\n </div>\n </div>\n <!-- AI Configuration -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"aiConfigExpanded = !aiConfigExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">smart_toy</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">AI Configuration</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ aiConfigExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"aiConfigExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-py-0 cqa-min-w-0 cqa-w-full\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('enableAiSmartness', enableAiSmartnessSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('enableAiSmartness')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('defaultAiAction', defaultAiActionSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('defaultAiAction')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('knowledgeBaseDefaultTestCase', knowledgeBaseDefaultTestCaseSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('knowledgeBaseDefaultTestCase')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('useAiMetadata', aiMetadataCollectionSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('useAiMetadata')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n </div>\n </div>\n <!-- Waits & Retries-->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"waitsRetriesExpanded = !waitsRetriesExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">timer</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Wait and Retries</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ waitsRetriesExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"waitsRetriesExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-min-w-0 cqa-w-full\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"autoWaitEnabled\" (checkedChange)=\"autoWaitEnabled = $event\" ariaLabel=\"Enable Avoid Auto wait for steps\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Enable Avoid Auto wait for steps</span>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-custom-input\n type=\"number\"\n label=\"Retry Failed Steps\"\n [value]=\"retryFailedSteps\"\n (valueChange)=\"retryFailedSteps = onlyDigits($event)\"\n placeholder=\"0\"\n [fullWidth]=\"true\"\n size=\"sm\"\n labelInlineStyle=\"font-size: 14px; line-height: 19.6px\">\n </cqa-custom-input>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <label class=\"cqa-font-medium cqa-text-[#374151] cqa-text-xs cqa-mb-1\" style=\"font-size: 14px; line-height: 19.6px\">\n Test Case Timeout (minutes)\n </label>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-min-w-0 cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-rounded-md cqa-border cqa-border-solid cqa-border-gray-200\">\n <cqa-dropdown-button\n [options]=\"testCaseTimeoutModeOptions\"\n [selectedValue]=\"testCaseTimeoutMode\"\n (selectionChange)=\"onTestCaseTimeoutModeChange($event)\">\n </cqa-dropdown-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-custom-input\n type=\"number\"\n [value]=\"testCaseTimeoutDisplayValue\"\n [disabled]=\"testCaseTimeoutMode === 'org'\"\n (valueChange)=\"testCaseTimeout = onlyDigits($event)\"\n placeholder=\"30\"\n [fullWidth]=\"true\"\n size=\"sm\">\n </cqa-custom-input>\n </div>\n </div>\n </div>\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-w-0 cqa-w-full\">\n <cqa-custom-input\n type=\"number\"\n label=\"Wait Timeout for Locators (sec)\"\n [value]=\"waitTimeoutLocators\"\n (valueChange)=\"waitTimeoutLocators = onlyDigits($event)\"\n placeholder=\"15\"\n [fullWidth]=\"true\"\n size=\"sm\"\n labelInlineStyle=\"font-size: 14px; line-height: 19.6px\">\n </cqa-custom-input>\n </div>\n </div>\n </div>\n <div *ngIf=\"platform !== 'mobile'\" class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-4 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"deviceExpanded = !deviceExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">devices</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Device Settings</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ deviceExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"deviceExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-min-w-0 cqa-w-full\">\n <!-- Web only: mobile Device Settings hidden temporarily -->\n <div class=\"cqa-min-w-0 cqa-w-full\">\n <cqa-dynamic-select\n [form]=\"editForm\"\n [config]=\"getConfigForSelect('defaultBrowser', defaultBrowserSelectConfig)\"\n (searchChange)=\"onSelectSearch($event)\"\n (loadMore)=\"onSelectLoadMore($event)\"\n (selectClick)=\"onSelectOpened('defaultBrowser')\"\n (selectionChange)=\"onSelectionChange($event)\"\n class=\"cqa-w-full\"></cqa-dynamic-select>\n </div>\n <!-- Viewport selector \u2014 replaces single dropdown -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <span class=\"cqa-text-[13px] cqa-font-medium cqa-text-[#374151] cqa-leading-[18.2px]\">Viewport</span>\n <cqa-radio-card-group\n class=\"viewport-selector\"\n [options]=\"viewportModeOptions\"\n [ngModel]=\"viewportMode\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onViewportModeChange($event)\">\n </cqa-radio-card-group>\n <div *ngIf=\"viewportMode === 'desktop'\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-medium cqa-text-[#6b7280]\">Resolution</span>\n <cqa-dynamic-select\n [form]=\"viewportDesktopDeviceForm\"\n [config]=\"desktopViewportConfig\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n </div>\n <div *ngIf=\"viewportMode === 'laptop'\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-medium cqa-text-[#6b7280]\">Resolution</span>\n <cqa-dynamic-select\n [form]=\"viewportLaptopDeviceForm\"\n [config]=\"laptopViewportConfig\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n </div>\n <div *ngIf=\"viewportMode === 'tablet'\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-medium cqa-text-[#6b7280]\">Resolution</span>\n <cqa-dynamic-select\n [form]=\"viewportTabletDeviceForm\"\n [config]=\"tabletViewportConfig\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n </div>\n <div *ngIf=\"viewportMode === 'mobile'\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5\">\n <span class=\"cqa-text-[12px] cqa-font-medium cqa-text-[#6b7280]\">Device</span>\n <cqa-dynamic-select\n [form]=\"viewportMobileDeviceForm\"\n [config]=\"mobileViewportConfig\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n </div>\n </div>\n </div>\n </div>\n <!-- Key Flags -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2.5 cqa-min-w-0 cqa-rounded-lg cqa-p-4 cqa-mb-0 cqa-border cqa-border-solid cqa-border-[#E2E8F0]\">\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-w-full cqa-bg-transparent cqa-border-none cqa-p-0 cqa-cursor-pointer\"\n (click)=\"keyFlagsExpanded = !keyFlagsExpanded\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">flag</mat-icon>\n </div>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-semibold cqa-text-[#111827]\">Key Flags</span>\n </div>\n <mat-icon class=\"cqa-text-[#64748B] cqa-text-xl cqa-w-5 cqa-h-5\">\n {{ keyFlagsExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div *ngIf=\"keyFlagsExpanded\" class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"mobileTestingEnabled\" (checkedChange)=\"mobileTestingEnabled = $event\" ariaLabel=\"Mobile Testing\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Mobile Testing</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"extensionUseEnabled\" (checkedChange)=\"extensionUseEnabled = $event\" ariaLabel=\"Extension Use\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Extension Use</span>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-px-3 cqa-py-2.5 cqa-rounded-lg\">\n <cqa-custom-toggle [checked]=\"dataDrivenEnabled\" (checkedChange)=\"dataDrivenEnabled = $event\" ariaLabel=\"Data Driven\"></cqa-custom-toggle>\n <span class=\"cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-text-[#111827]\">Data Driven</span>\n </div>\n </div>\n </div>\n\n \n <!-- API Mocking Card (edit mode: mutually-exclusive toggles driven by one boolean) -->\n <cqa-api-mocking-card\n *ngIf=\"showApiMockingCard\"\n style=\"width: 100%;\"\n [title]=\"apiMockingTitle\"\n [statusLabel]=\"apiMockingStatusLabel\"\n [captureLabel]=\"apiMockingCaptureLabel\"\n [captureHint]=\"apiMockingCaptureHint\"\n [renewLabel]=\"apiMockingRenewLabel\"\n [renewHint]=\"apiMockingRenewHint\"\n [restoreMock]=\"editApiMockingRestoreMock\"\n [storeMock]=\"editApiMockingStoreMock\"\n [mockedApisCount]=\"apiMockingMockedApisCount\"\n [totalApisCount]=\"apiMockingTotalApisCount\"\n [progressPercent]=\"apiMockingProgressPercent\"\n [showProgress]=\"apiMockingShowProgress\"\n [summaryText]=\"apiMockingSummaryText\"\n [percentText]=\"apiMockingPercentText\"\n [editing]=\"true\"\n (restoreMockChange)=\"onApiMockingRestoreMockChange($event)\"\n (storeMockChange)=\"onApiMockingStoreMockChange($event)\"\n (configure)=\"configureApiMocking.emit()\">\n </cqa-api-mocking-card>\n </div>\n </div>\n\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-gap-3 cqa-pt-2 cqa-w-full\">\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button\n variant=\"outlined\"\n [text]=\"'Cancel'\"\n btnSize=\"md\"\n [fullWidth]=\"true\"\n (clicked)=\"onCancel()\">\n </cqa-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button\n *ngIf=\"!isSaving\"\n variant=\"filled\"\n [text]=\"'Save Changes'\"\n btnSize=\"md\"\n [fullWidth]=\"true\"\n [disabled]=\"!hasUnsavedChanges\"\n (clicked)=\"onSave()\">\n </cqa-button>\n <div *ngIf=\"isSaving\" class=\"cqa-w-full\">\n <cqa-badge\n label=\"Saving\u2026\"\n icon=\"autorenew\"\n [isLoading]=\"true\"\n [fullWidth]=\"true\"\n [centerContent]=\"true\"\n variant=\"info\"\n size=\"medium\">\n </cqa-badge>\n </div>\n </div>\n </div>\n</div>\n" }]
|
|
47624
47853
|
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { descriptionTitle: [{
|
|
47625
47854
|
type: Input
|
|
47626
47855
|
}], descriptionContent: [{
|
|
@@ -47679,6 +47908,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
47679
47908
|
type: Input
|
|
47680
47909
|
}], orgLevelTestCaseTimeout: [{
|
|
47681
47910
|
type: Input
|
|
47911
|
+
}], viewportCategoryOptions: [{
|
|
47912
|
+
type: Input
|
|
47682
47913
|
}], save: [{
|
|
47683
47914
|
type: Output
|
|
47684
47915
|
}], cancel: [{
|
|
@@ -47758,6 +47989,8 @@ class TestCaseDetailsComponent {
|
|
|
47758
47989
|
/** Forwarded to `cqa-api-mocking-card` — gates the "Mocked / progress / percent" block. */
|
|
47759
47990
|
this.apiMockingShowProgress = false;
|
|
47760
47991
|
this.apiMockingConfigureButtonLabel = 'Configure';
|
|
47992
|
+
/** Viewport dropdown options per category from the API. Forwarded to edit mode. */
|
|
47993
|
+
this.viewportCategoryOptions = {};
|
|
47761
47994
|
/** Labels to filter out from metadata for step groups */
|
|
47762
47995
|
this.stepGroupExcludedMetadataLabels = ['priority', 'type'];
|
|
47763
47996
|
/** When true, description (view mode) is expanded; when false, clamped to 4 lines with Read more */
|
|
@@ -47871,10 +48104,10 @@ class TestCaseDetailsComponent {
|
|
|
47871
48104
|
}
|
|
47872
48105
|
}
|
|
47873
48106
|
TestCaseDetailsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseDetailsComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
47874
|
-
TestCaseDetailsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestCaseDetailsComponent, selector: "cqa-test-case-details", inputs: { editing: "editing", startInEditMode: "startInEditMode", descriptionTitle: "descriptionTitle", descriptionContent: "descriptionContent", enableMarkdown: "enableMarkdown", showEditButton: "showEditButton", metadataItems: "metadataItems", labels: "labels", configTitle: "configTitle", configSections: "configSections", configSectionsRow2: "configSectionsRow2", platform: "platform", isStepGroup: "isStepGroup", selectConfigOverrides: "selectConfigOverrides", isSaving: "isSaving", showApiMockingCard: "showApiMockingCard", apiMockingTitle: "apiMockingTitle", apiMockingStatusLabel: "apiMockingStatusLabel", apiMockingCaptureLabel: "apiMockingCaptureLabel", apiMockingRenewLabel: "apiMockingRenewLabel", apiMockingCaptureHint: "apiMockingCaptureHint", apiMockingRenewHint: "apiMockingRenewHint", apiMockingRestoreMock: "apiMockingRestoreMock", apiMockingStoreMock: "apiMockingStoreMock", apiMockingMockedApisCount: "apiMockingMockedApisCount", apiMockingTotalApisCount: "apiMockingTotalApisCount", apiMockingProgressPercent: "apiMockingProgressPercent", apiMockingShowProgress: "apiMockingShowProgress", apiMockingSummaryText: "apiMockingSummaryText", apiMockingPercentText: "apiMockingPercentText", apiMockingConfigureButtonLabel: "apiMockingConfigureButtonLabel", orgLevelTestCaseTimeout: "orgLevelTestCaseTimeout" }, outputs: { editDescription: "editDescription", cancel: "cancel", saveChanges: "saveChanges", metadataLinkClick: "metadataLinkClick", selectSearch: "selectSearch", selectLoadMore: "selectLoadMore", selectOpened: "selectOpened", selectionChange: "selectionChange", labelAdded: "labelAdded", configureApiMocking: "configureApiMocking", apiMockingRestoreMockChange: "apiMockingRestoreMockChange", apiMockingStoreMockChange: "apiMockingStoreMockChange" }, usesOnChanges: true, ngImport: i0, template: "<!-- Edit mode: show edit form (Figma design) -->\n<cqa-test-case-details-edit\n *ngIf=\"isEditing\"\n [descriptionTitle]=\"descriptionTitle\"\n [descriptionContent]=\"descriptionContent\"\n [enableMarkdown]=\"enableMarkdown\"\n [metadataItems]=\"metadataItems\"\n [labels]=\"labels\"\n [configTitle]=\"configTitle\"\n [configSections]=\"configSections\"\n [configSectionsRow2]=\"configSectionsRow2\"\n [platform]=\"platform\"\n [isStepGroup]=\"isStepGroup\"\n [isSaving]=\"isSaving\"\n [selectConfigOverrides]=\"selectConfigOverrides\"\n [showApiMockingCard]=\"showApiMockingCard\"\n [apiMockingTitle]=\"apiMockingTitle\"\n [apiMockingStatusLabel]=\"apiMockingStatusLabel\"\n [apiMockingCaptureLabel]=\"apiMockingCaptureLabel\"\n [apiMockingCaptureHint]=\"apiMockingCaptureHint\"\n [apiMockingRenewLabel]=\"apiMockingRenewLabel\"\n [apiMockingRenewHint]=\"apiMockingRenewHint\"\n [apiMockingRestoreMock]=\"apiMockingRestoreMock\"\n [apiMockingStoreMock]=\"apiMockingStoreMock\"\n [apiMockingMockedApisCount]=\"apiMockingMockedApisCount\"\n [apiMockingTotalApisCount]=\"apiMockingTotalApisCount\"\n [apiMockingProgressPercent]=\"apiMockingProgressPercent\"\n [apiMockingShowProgress]=\"apiMockingShowProgress\"\n [apiMockingSummaryText]=\"apiMockingSummaryText\"\n [apiMockingPercentText]=\"apiMockingPercentText\"\n [orgLevelTestCaseTimeout]=\"orgLevelTestCaseTimeout\"\n (save)=\"onSaveChanges($event)\"\n (cancel)=\"onCancelEdit()\"\n (selectSearch)=\"selectSearch.emit($event)\"\n (selectLoadMore)=\"selectLoadMore.emit($event)\"\n (selectOpened)=\"selectOpened.emit($event)\"\n (selectionChange)=\"selectionChange.emit($event)\"\n (labelAdded)=\"labelAdded.emit($event)\"\n (apiMockingRestoreMockChange)=\"apiMockingRestoreMockChange.emit($event)\"\n (apiMockingStoreMockChange)=\"apiMockingStoreMockChange.emit($event)\"\n (configureApiMocking)=\"configureApiMocking.emit()\">\n</cqa-test-case-details-edit>\n\n<!-- View mode: read-only details -->\n<div *ngIf=\"!isEditing\" class=\"cqa-self-stretch cqa-py-4 cqa-px-0 cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-4 cqa-text-sm cqa-leading-[19.6px]\">\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-4 cqa-text-sm cqa-leading-[19.6px]\">\n <!-- Description Section -->\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-inline-flex cqa-justify-between cqa-items-center\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">description</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.6px]\">{{ descriptionTitle }}</span>\n </div>\n <button\n *ngIf=\"showEditButton\"\n type=\"button\"\n class=\"cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-px-2.5 cqa-py-1 cqa-rounded !cqa-border !cqa-border-solid !cqa-border-[#D1D5DB] cqa-text-[#6B7280] cqa-text-xs cqa-font-semibold cqa-cursor-pointer cqa-transition-all hover:cqa-text-[#374151] hover:!cqa-border-[#9CA3AF] hover:cqa-bg-[#F9FAFB] focus:cqa-outline-none focus-visible:cqa-ring-2 focus-visible:cqa-ring-[#3F43EE] focus-visible:cqa-ring-offset-2\"\n (click)=\"onEditClick()\">\n <mat-icon class=\"!cqa-w-[14px] !cqa-h-[14px] !cqa-text-[14px]\">edit</mat-icon>\n <span>Edit</span>\n </button>\n </div>\n <div *ngIf=\"descriptionContent\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-1\">\n <div\n *ngIf=\"enableMarkdown\"\n class=\"cqa-self-stretch cqa-text-[#111827] cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-prose cqa-prose-sm cqa-max-w-none\"\n [style]=\"(!descriptionExpanded && showDescriptionReadMore) ? 'display: -webkit-box; -webkit-line-clamp: 4; line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;' : ''\"\n [innerHTML]=\"descriptionContent\"></div>\n <div\n *ngIf=\"!enableMarkdown\"\n class=\"cqa-self-stretch cqa-text-[#111827] cqa-text-sm cqa-leading-[19.6px] cqa-font-normal\"\n [style]=\"(!descriptionExpanded && showDescriptionReadMore) ? 'display: -webkit-box; -webkit-line-clamp: 4; line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;' : ''\">{{ descriptionContent }}</div>\n <button\n *ngIf=\"showDescriptionReadMore\"\n type=\"button\"\n class=\"cqa-text-[#3F43EE] cqa-text-xs cqa-font-medium hover:cqa-underline cqa-cursor-pointer cqa-bg-transparent cqa-border-none cqa-p-0 cqa-self-start focus:cqa-outline-none focus-visible:cqa-ring-2 focus-visible:cqa-ring-[#3F43EE] focus-visible:cqa-ring-offset-2\"\n (click)=\"toggleDescriptionExpand()\">\n {{ descriptionExpanded ? 'Read less' : 'Read more' }}\n </button>\n </div>\n </div>\n\n <!-- Metadata Section -->\n <div *ngIf=\"filteredMetadataItems.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-grid cqa-grid-cols-2 cqa-gap-x-0 cqa-gap-y-4\">\n <ng-container *ngFor=\"let item of filteredMetadataItems; trackBy: trackByMetadataLabel\">\n <div class=\"cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-0.5\">\n <div class=\"cqa-text-[#6B7280] cqa-text-xs cqa-leading-[15px] cqa-font-medium\">{{ item.label }}</div>\n <div\n class=\"cqa-flex cqa-justify-start cqa-items-center cqa-gap-[5px] cqa-min-w-0 cqa-w-full cqa-text-left cqa-text-[#0A0A0A] cqa-border cqa-border-[#F5F5F5]\">\n <mat-icon *ngIf=\"item.icon && (!item.iconLibrary || item.iconLibrary === 'mat')\" class=\"cqa-text-[#6B7280] cqa-text-sm cqa-w-4 cqa-h-4\">\n {{ item.icon }}\n </mat-icon>\n <span *ngIf=\"item.statusColor\" class=\"cqa-w-[10px] cqa-h-[10px] cqa-rounded-full cqa-flex-shrink-0\" [ngClass]=\"getStatusDotClass(item)\"></span>\n <a\n *ngIf=\"item.link\"\n href=\"javascript:void(0)\"\n class=\"cqa-text-[#2563EB] cqa-text-xs cqa-leading-[12px] cqa-font-normal hover:cqa-underline cqa-cursor-pointer cqa-block cqa-truncate cqa-min-w-0\"\n (click)=\"onMetadataLinkClick(item); $event.preventDefault()\">\n {{ item.value }}\n </a>\n <span *ngIf=\"!item.link\" class=\"cqa-text-xs cqa-leading-[12px] cqa-font-normal cqa-align-middle\" [ngClass]=\"getValueTextClass(item)\">\n {{ item.value }}\n </span>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n\n <!-- Labels (Figma: Labels title, cqa-badge chips with tag icon) -->\n <div *ngIf=\"labels.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2 cqa-text-sm cqa-leading-[19.6px]\">\n <span class=\"cqa-text-[#111827] cqa-text-sm cqa-font-medium cqa-leading-5\">Labels</span>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2\">\n <cqa-badge\n *ngFor=\"let label of labels\"\n [label]=\"label\"\n icon=\"label\"\n variant=\"outline\"\n size=\"small\"\n backgroundColor=\"#ffffff\"\n textColor=\"#475569\"\n borderColor=\"#E2E8F0\"\n iconColor=\"#94A3B8\">\n </cqa-badge>\n </div>\n </div>\n\n <!-- Configuration Section -->\n <div *ngIf=\"configSections.length || configSectionsRow2.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-inline-flex cqa-justify-start cqa-items-center\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">settings</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.6px]\">{{ configTitle }}</span>\n </div>\n </div>\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-grid cqa-grid-cols-1 cqa-gap-2.5\">\n <ng-container *ngFor=\"let section of configSections; trackBy: trackByConfigTitle\">\n <cqa-configuration-card\n [icon]=\"section.icon || 'tune'\"\n [title]=\"section.title\"\n [data]=\"section.items\">\n </cqa-configuration-card>\n </ng-container>\n </div>\n <div *ngIf=\"configSectionsRow2.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-4 cqa-text-sm cqa-leading-[19.6px]\">\n <cqa-configuration-card\n *ngFor=\"let section of configSectionsRow2; trackBy: trackByConfigTitle\"\n [icon]=\"section.icon || 'tune'\"\n [title]=\"section.title\"\n [data]=\"section.items\">\n </cqa-configuration-card>\n </div>\n </div>\n <!-- API Mocking Card (read-only) -->\n <cqa-api-mocking-card\n *ngIf=\"showApiMockingCard\"\n style=\"width: 100%;\"\n [title]=\"apiMockingTitle\"\n [statusLabel]=\"apiMockingStatusLabel\"\n [captureLabel]=\"apiMockingCaptureLabel\"\n [renewLabel]=\"apiMockingRenewLabel\"\n [restoreMock]=\"apiMockingRestoreMock\"\n [storeMock]=\"apiMockingStoreMock\"\n [mockedApisCount]=\"apiMockingMockedApisCount\"\n [totalApisCount]=\"apiMockingTotalApisCount\"\n [progressPercent]=\"apiMockingProgressPercent\"\n [showProgress]=\"apiMockingShowProgress\"\n [summaryText]=\"apiMockingSummaryText\"\n [percentText]=\"apiMockingPercentText\"\n [configureButtonLabel]=\"apiMockingConfigureButtonLabel\"\n [editing]=\"false\"\n (configure)=\"configureApiMocking.emit()\">\n </cqa-api-mocking-card>\n </div>\n </div>\n</div>\n", components: [{ type: TestCaseDetailsEditComponent, selector: "cqa-test-case-details-edit", inputs: ["descriptionTitle", "descriptionContent", "enableMarkdown", "metadataItems", "labels", "configTitle", "configSections", "configSectionsRow2", "isSaving", "prerequisiteCaseOptions", "platform", "isStepGroup", "selectConfigOverrides", "showApiMockingCard", "apiMockingTitle", "apiMockingStatusLabel", "apiMockingCaptureLabel", "apiMockingCaptureHint", "apiMockingRenewLabel", "apiMockingRenewHint", "apiMockingRestoreMock", "apiMockingStoreMock", "apiMockingMockedApisCount", "apiMockingTotalApisCount", "apiMockingProgressPercent", "apiMockingShowProgress", "apiMockingSummaryText", "apiMockingPercentText", "orgLevelTestCaseTimeout"], outputs: ["save", "cancel", "selectSearch", "selectLoadMore", "selectOpened", "selectionChange", "labelAdded", "apiMockingRestoreMockChange", "apiMockingStoreMockChange", "configureApiMocking"] }, { type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: BadgeComponent, selector: "cqa-badge", inputs: ["type", "label", "icon", "iconLibrary", "variant", "size", "backgroundColor", "textColor", "borderColor", "iconBackgroundColor", "iconColor", "iconSize", "inlineStyles", "key", "value", "keyTextColor", "valueTextColor", "isLoading", "fullWidth", "centerContent", "title"] }, { type: ConfigurationCardComponent, selector: "cqa-configuration-card", inputs: ["icon", "title", "data"] }, { type: ApiMockingCardComponent, selector: "cqa-api-mocking-card", inputs: ["title", "statusLabel", "captureLabel", "captureHint", "renewLabel", "renewHint", "restoreMock", "storeMock", "mockedApisCount", "totalApisCount", "progressPercent", "summaryText", "percentText", "configureButtonLabel", "editing", "showProgress", "noDataHint"], outputs: ["configure", "restoreMockChange", "storeMockChange"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
48107
|
+
TestCaseDetailsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestCaseDetailsComponent, selector: "cqa-test-case-details", inputs: { editing: "editing", startInEditMode: "startInEditMode", descriptionTitle: "descriptionTitle", descriptionContent: "descriptionContent", enableMarkdown: "enableMarkdown", showEditButton: "showEditButton", metadataItems: "metadataItems", labels: "labels", configTitle: "configTitle", configSections: "configSections", configSectionsRow2: "configSectionsRow2", platform: "platform", isStepGroup: "isStepGroup", selectConfigOverrides: "selectConfigOverrides", isSaving: "isSaving", showApiMockingCard: "showApiMockingCard", apiMockingTitle: "apiMockingTitle", apiMockingStatusLabel: "apiMockingStatusLabel", apiMockingCaptureLabel: "apiMockingCaptureLabel", apiMockingRenewLabel: "apiMockingRenewLabel", apiMockingCaptureHint: "apiMockingCaptureHint", apiMockingRenewHint: "apiMockingRenewHint", apiMockingRestoreMock: "apiMockingRestoreMock", apiMockingStoreMock: "apiMockingStoreMock", apiMockingMockedApisCount: "apiMockingMockedApisCount", apiMockingTotalApisCount: "apiMockingTotalApisCount", apiMockingProgressPercent: "apiMockingProgressPercent", apiMockingShowProgress: "apiMockingShowProgress", apiMockingSummaryText: "apiMockingSummaryText", apiMockingPercentText: "apiMockingPercentText", apiMockingConfigureButtonLabel: "apiMockingConfigureButtonLabel", orgLevelTestCaseTimeout: "orgLevelTestCaseTimeout", viewportCategoryOptions: "viewportCategoryOptions" }, outputs: { editDescription: "editDescription", cancel: "cancel", saveChanges: "saveChanges", metadataLinkClick: "metadataLinkClick", selectSearch: "selectSearch", selectLoadMore: "selectLoadMore", selectOpened: "selectOpened", selectionChange: "selectionChange", labelAdded: "labelAdded", configureApiMocking: "configureApiMocking", apiMockingRestoreMockChange: "apiMockingRestoreMockChange", apiMockingStoreMockChange: "apiMockingStoreMockChange" }, usesOnChanges: true, ngImport: i0, template: "<!-- Edit mode: show edit form (Figma design) -->\n<cqa-test-case-details-edit\n *ngIf=\"isEditing\"\n [descriptionTitle]=\"descriptionTitle\"\n [descriptionContent]=\"descriptionContent\"\n [enableMarkdown]=\"enableMarkdown\"\n [metadataItems]=\"metadataItems\"\n [labels]=\"labels\"\n [configTitle]=\"configTitle\"\n [configSections]=\"configSections\"\n [configSectionsRow2]=\"configSectionsRow2\"\n [platform]=\"platform\"\n [isStepGroup]=\"isStepGroup\"\n [isSaving]=\"isSaving\"\n [selectConfigOverrides]=\"selectConfigOverrides\"\n [showApiMockingCard]=\"showApiMockingCard\"\n [apiMockingTitle]=\"apiMockingTitle\"\n [apiMockingStatusLabel]=\"apiMockingStatusLabel\"\n [apiMockingCaptureLabel]=\"apiMockingCaptureLabel\"\n [apiMockingCaptureHint]=\"apiMockingCaptureHint\"\n [apiMockingRenewLabel]=\"apiMockingRenewLabel\"\n [apiMockingRenewHint]=\"apiMockingRenewHint\"\n [apiMockingRestoreMock]=\"apiMockingRestoreMock\"\n [apiMockingStoreMock]=\"apiMockingStoreMock\"\n [apiMockingMockedApisCount]=\"apiMockingMockedApisCount\"\n [apiMockingTotalApisCount]=\"apiMockingTotalApisCount\"\n [apiMockingProgressPercent]=\"apiMockingProgressPercent\"\n [apiMockingShowProgress]=\"apiMockingShowProgress\"\n [apiMockingSummaryText]=\"apiMockingSummaryText\"\n [apiMockingPercentText]=\"apiMockingPercentText\"\n [orgLevelTestCaseTimeout]=\"orgLevelTestCaseTimeout\"\n [viewportCategoryOptions]=\"viewportCategoryOptions\"\n (save)=\"onSaveChanges($event)\"\n (cancel)=\"onCancelEdit()\"\n (selectSearch)=\"selectSearch.emit($event)\"\n (selectLoadMore)=\"selectLoadMore.emit($event)\"\n (selectOpened)=\"selectOpened.emit($event)\"\n (selectionChange)=\"selectionChange.emit($event)\"\n (labelAdded)=\"labelAdded.emit($event)\"\n (apiMockingRestoreMockChange)=\"apiMockingRestoreMockChange.emit($event)\"\n (apiMockingStoreMockChange)=\"apiMockingStoreMockChange.emit($event)\"\n (configureApiMocking)=\"configureApiMocking.emit()\">\n</cqa-test-case-details-edit>\n\n<!-- View mode: read-only details -->\n<div *ngIf=\"!isEditing\" class=\"cqa-self-stretch cqa-py-4 cqa-px-0 cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-4 cqa-text-sm cqa-leading-[19.6px]\">\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-4 cqa-text-sm cqa-leading-[19.6px]\">\n <!-- Description Section -->\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-inline-flex cqa-justify-between cqa-items-center\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">description</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.6px]\">{{ descriptionTitle }}</span>\n </div>\n <button\n *ngIf=\"showEditButton\"\n type=\"button\"\n class=\"cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-px-2.5 cqa-py-1 cqa-rounded !cqa-border !cqa-border-solid !cqa-border-[#D1D5DB] cqa-text-[#6B7280] cqa-text-xs cqa-font-semibold cqa-cursor-pointer cqa-transition-all hover:cqa-text-[#374151] hover:!cqa-border-[#9CA3AF] hover:cqa-bg-[#F9FAFB] focus:cqa-outline-none focus-visible:cqa-ring-2 focus-visible:cqa-ring-[#3F43EE] focus-visible:cqa-ring-offset-2\"\n (click)=\"onEditClick()\">\n <mat-icon class=\"!cqa-w-[14px] !cqa-h-[14px] !cqa-text-[14px]\">edit</mat-icon>\n <span>Edit</span>\n </button>\n </div>\n <div *ngIf=\"descriptionContent\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-1\">\n <div\n *ngIf=\"enableMarkdown\"\n class=\"cqa-self-stretch cqa-text-[#111827] cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-prose cqa-prose-sm cqa-max-w-none\"\n [style]=\"(!descriptionExpanded && showDescriptionReadMore) ? 'display: -webkit-box; -webkit-line-clamp: 4; line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;' : ''\"\n [innerHTML]=\"descriptionContent\"></div>\n <div\n *ngIf=\"!enableMarkdown\"\n class=\"cqa-self-stretch cqa-text-[#111827] cqa-text-sm cqa-leading-[19.6px] cqa-font-normal\"\n [style]=\"(!descriptionExpanded && showDescriptionReadMore) ? 'display: -webkit-box; -webkit-line-clamp: 4; line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;' : ''\">{{ descriptionContent }}</div>\n <button\n *ngIf=\"showDescriptionReadMore\"\n type=\"button\"\n class=\"cqa-text-[#3F43EE] cqa-text-xs cqa-font-medium hover:cqa-underline cqa-cursor-pointer cqa-bg-transparent cqa-border-none cqa-p-0 cqa-self-start focus:cqa-outline-none focus-visible:cqa-ring-2 focus-visible:cqa-ring-[#3F43EE] focus-visible:cqa-ring-offset-2\"\n (click)=\"toggleDescriptionExpand()\">\n {{ descriptionExpanded ? 'Read less' : 'Read more' }}\n </button>\n </div>\n </div>\n\n <!-- Metadata Section -->\n <div *ngIf=\"filteredMetadataItems.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-grid cqa-grid-cols-2 cqa-gap-x-0 cqa-gap-y-4\">\n <ng-container *ngFor=\"let item of filteredMetadataItems; trackBy: trackByMetadataLabel\">\n <div class=\"cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-0.5\">\n <div class=\"cqa-text-[#6B7280] cqa-text-xs cqa-leading-[15px] cqa-font-medium\">{{ item.label }}</div>\n <div\n class=\"cqa-flex cqa-justify-start cqa-items-center cqa-gap-[5px] cqa-min-w-0 cqa-w-full cqa-text-left cqa-text-[#0A0A0A] cqa-border cqa-border-[#F5F5F5]\">\n <mat-icon *ngIf=\"item.icon && (!item.iconLibrary || item.iconLibrary === 'mat')\" class=\"cqa-text-[#6B7280] cqa-text-sm cqa-w-4 cqa-h-4\">\n {{ item.icon }}\n </mat-icon>\n <span *ngIf=\"item.statusColor\" class=\"cqa-w-[10px] cqa-h-[10px] cqa-rounded-full cqa-flex-shrink-0\" [ngClass]=\"getStatusDotClass(item)\"></span>\n <a\n *ngIf=\"item.link\"\n href=\"javascript:void(0)\"\n class=\"cqa-text-[#2563EB] cqa-text-xs cqa-leading-[12px] cqa-font-normal hover:cqa-underline cqa-cursor-pointer cqa-block cqa-truncate cqa-min-w-0\"\n (click)=\"onMetadataLinkClick(item); $event.preventDefault()\">\n {{ item.value }}\n </a>\n <span *ngIf=\"!item.link\" class=\"cqa-text-xs cqa-leading-[12px] cqa-font-normal cqa-align-middle\" [ngClass]=\"getValueTextClass(item)\">\n {{ item.value }}\n </span>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n\n <!-- Labels (Figma: Labels title, cqa-badge chips with tag icon) -->\n <div *ngIf=\"labels.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2 cqa-text-sm cqa-leading-[19.6px]\">\n <span class=\"cqa-text-[#111827] cqa-text-sm cqa-font-medium cqa-leading-5\">Labels</span>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2\">\n <cqa-badge\n *ngFor=\"let label of labels\"\n [label]=\"label\"\n icon=\"label\"\n variant=\"outline\"\n size=\"small\"\n backgroundColor=\"#ffffff\"\n textColor=\"#475569\"\n borderColor=\"#E2E8F0\"\n iconColor=\"#94A3B8\">\n </cqa-badge>\n </div>\n </div>\n\n <!-- Configuration Section -->\n <div *ngIf=\"configSections.length || configSectionsRow2.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-inline-flex cqa-justify-start cqa-items-center\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">settings</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.6px]\">{{ configTitle }}</span>\n </div>\n </div>\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-grid cqa-grid-cols-1 cqa-gap-2.5\">\n <ng-container *ngFor=\"let section of configSections; trackBy: trackByConfigTitle\">\n <cqa-configuration-card\n [icon]=\"section.icon || 'tune'\"\n [title]=\"section.title\"\n [data]=\"section.items\">\n </cqa-configuration-card>\n </ng-container>\n </div>\n <div *ngIf=\"configSectionsRow2.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-4 cqa-text-sm cqa-leading-[19.6px]\">\n <cqa-configuration-card\n *ngFor=\"let section of configSectionsRow2; trackBy: trackByConfigTitle\"\n [icon]=\"section.icon || 'tune'\"\n [title]=\"section.title\"\n [data]=\"section.items\">\n </cqa-configuration-card>\n </div>\n </div>\n <!-- API Mocking Card (read-only) -->\n <cqa-api-mocking-card\n *ngIf=\"showApiMockingCard\"\n style=\"width: 100%;\"\n [title]=\"apiMockingTitle\"\n [statusLabel]=\"apiMockingStatusLabel\"\n [captureLabel]=\"apiMockingCaptureLabel\"\n [renewLabel]=\"apiMockingRenewLabel\"\n [restoreMock]=\"apiMockingRestoreMock\"\n [storeMock]=\"apiMockingStoreMock\"\n [mockedApisCount]=\"apiMockingMockedApisCount\"\n [totalApisCount]=\"apiMockingTotalApisCount\"\n [progressPercent]=\"apiMockingProgressPercent\"\n [showProgress]=\"apiMockingShowProgress\"\n [summaryText]=\"apiMockingSummaryText\"\n [percentText]=\"apiMockingPercentText\"\n [configureButtonLabel]=\"apiMockingConfigureButtonLabel\"\n [editing]=\"false\"\n (configure)=\"configureApiMocking.emit()\">\n </cqa-api-mocking-card>\n </div>\n </div>\n</div>\n", components: [{ type: TestCaseDetailsEditComponent, selector: "cqa-test-case-details-edit", inputs: ["descriptionTitle", "descriptionContent", "enableMarkdown", "metadataItems", "labels", "configTitle", "configSections", "configSectionsRow2", "isSaving", "prerequisiteCaseOptions", "platform", "isStepGroup", "selectConfigOverrides", "showApiMockingCard", "apiMockingTitle", "apiMockingStatusLabel", "apiMockingCaptureLabel", "apiMockingCaptureHint", "apiMockingRenewLabel", "apiMockingRenewHint", "apiMockingRestoreMock", "apiMockingStoreMock", "apiMockingMockedApisCount", "apiMockingTotalApisCount", "apiMockingProgressPercent", "apiMockingShowProgress", "apiMockingSummaryText", "apiMockingPercentText", "orgLevelTestCaseTimeout", "viewportCategoryOptions"], outputs: ["save", "cancel", "selectSearch", "selectLoadMore", "selectOpened", "selectionChange", "labelAdded", "apiMockingRestoreMockChange", "apiMockingStoreMockChange", "configureApiMocking"] }, { type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: BadgeComponent, selector: "cqa-badge", inputs: ["type", "label", "icon", "iconLibrary", "variant", "size", "backgroundColor", "textColor", "borderColor", "iconBackgroundColor", "iconColor", "iconSize", "inlineStyles", "key", "value", "keyTextColor", "valueTextColor", "isLoading", "fullWidth", "centerContent", "title"] }, { type: ConfigurationCardComponent, selector: "cqa-configuration-card", inputs: ["icon", "title", "data"] }, { type: ApiMockingCardComponent, selector: "cqa-api-mocking-card", inputs: ["title", "statusLabel", "captureLabel", "captureHint", "renewLabel", "renewHint", "restoreMock", "storeMock", "mockedApisCount", "totalApisCount", "progressPercent", "summaryText", "percentText", "configureButtonLabel", "editing", "showProgress", "noDataHint"], outputs: ["configure", "restoreMockChange", "storeMockChange"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
47875
48108
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseDetailsComponent, decorators: [{
|
|
47876
48109
|
type: Component,
|
|
47877
|
-
args: [{ selector: 'cqa-test-case-details', changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Edit mode: show edit form (Figma design) -->\n<cqa-test-case-details-edit\n *ngIf=\"isEditing\"\n [descriptionTitle]=\"descriptionTitle\"\n [descriptionContent]=\"descriptionContent\"\n [enableMarkdown]=\"enableMarkdown\"\n [metadataItems]=\"metadataItems\"\n [labels]=\"labels\"\n [configTitle]=\"configTitle\"\n [configSections]=\"configSections\"\n [configSectionsRow2]=\"configSectionsRow2\"\n [platform]=\"platform\"\n [isStepGroup]=\"isStepGroup\"\n [isSaving]=\"isSaving\"\n [selectConfigOverrides]=\"selectConfigOverrides\"\n [showApiMockingCard]=\"showApiMockingCard\"\n [apiMockingTitle]=\"apiMockingTitle\"\n [apiMockingStatusLabel]=\"apiMockingStatusLabel\"\n [apiMockingCaptureLabel]=\"apiMockingCaptureLabel\"\n [apiMockingCaptureHint]=\"apiMockingCaptureHint\"\n [apiMockingRenewLabel]=\"apiMockingRenewLabel\"\n [apiMockingRenewHint]=\"apiMockingRenewHint\"\n [apiMockingRestoreMock]=\"apiMockingRestoreMock\"\n [apiMockingStoreMock]=\"apiMockingStoreMock\"\n [apiMockingMockedApisCount]=\"apiMockingMockedApisCount\"\n [apiMockingTotalApisCount]=\"apiMockingTotalApisCount\"\n [apiMockingProgressPercent]=\"apiMockingProgressPercent\"\n [apiMockingShowProgress]=\"apiMockingShowProgress\"\n [apiMockingSummaryText]=\"apiMockingSummaryText\"\n [apiMockingPercentText]=\"apiMockingPercentText\"\n [orgLevelTestCaseTimeout]=\"orgLevelTestCaseTimeout\"\n (save)=\"onSaveChanges($event)\"\n (cancel)=\"onCancelEdit()\"\n (selectSearch)=\"selectSearch.emit($event)\"\n (selectLoadMore)=\"selectLoadMore.emit($event)\"\n (selectOpened)=\"selectOpened.emit($event)\"\n (selectionChange)=\"selectionChange.emit($event)\"\n (labelAdded)=\"labelAdded.emit($event)\"\n (apiMockingRestoreMockChange)=\"apiMockingRestoreMockChange.emit($event)\"\n (apiMockingStoreMockChange)=\"apiMockingStoreMockChange.emit($event)\"\n (configureApiMocking)=\"configureApiMocking.emit()\">\n</cqa-test-case-details-edit>\n\n<!-- View mode: read-only details -->\n<div *ngIf=\"!isEditing\" class=\"cqa-self-stretch cqa-py-4 cqa-px-0 cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-4 cqa-text-sm cqa-leading-[19.6px]\">\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-4 cqa-text-sm cqa-leading-[19.6px]\">\n <!-- Description Section -->\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-inline-flex cqa-justify-between cqa-items-center\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">description</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.6px]\">{{ descriptionTitle }}</span>\n </div>\n <button\n *ngIf=\"showEditButton\"\n type=\"button\"\n class=\"cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-px-2.5 cqa-py-1 cqa-rounded !cqa-border !cqa-border-solid !cqa-border-[#D1D5DB] cqa-text-[#6B7280] cqa-text-xs cqa-font-semibold cqa-cursor-pointer cqa-transition-all hover:cqa-text-[#374151] hover:!cqa-border-[#9CA3AF] hover:cqa-bg-[#F9FAFB] focus:cqa-outline-none focus-visible:cqa-ring-2 focus-visible:cqa-ring-[#3F43EE] focus-visible:cqa-ring-offset-2\"\n (click)=\"onEditClick()\">\n <mat-icon class=\"!cqa-w-[14px] !cqa-h-[14px] !cqa-text-[14px]\">edit</mat-icon>\n <span>Edit</span>\n </button>\n </div>\n <div *ngIf=\"descriptionContent\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-1\">\n <div\n *ngIf=\"enableMarkdown\"\n class=\"cqa-self-stretch cqa-text-[#111827] cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-prose cqa-prose-sm cqa-max-w-none\"\n [style]=\"(!descriptionExpanded && showDescriptionReadMore) ? 'display: -webkit-box; -webkit-line-clamp: 4; line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;' : ''\"\n [innerHTML]=\"descriptionContent\"></div>\n <div\n *ngIf=\"!enableMarkdown\"\n class=\"cqa-self-stretch cqa-text-[#111827] cqa-text-sm cqa-leading-[19.6px] cqa-font-normal\"\n [style]=\"(!descriptionExpanded && showDescriptionReadMore) ? 'display: -webkit-box; -webkit-line-clamp: 4; line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;' : ''\">{{ descriptionContent }}</div>\n <button\n *ngIf=\"showDescriptionReadMore\"\n type=\"button\"\n class=\"cqa-text-[#3F43EE] cqa-text-xs cqa-font-medium hover:cqa-underline cqa-cursor-pointer cqa-bg-transparent cqa-border-none cqa-p-0 cqa-self-start focus:cqa-outline-none focus-visible:cqa-ring-2 focus-visible:cqa-ring-[#3F43EE] focus-visible:cqa-ring-offset-2\"\n (click)=\"toggleDescriptionExpand()\">\n {{ descriptionExpanded ? 'Read less' : 'Read more' }}\n </button>\n </div>\n </div>\n\n <!-- Metadata Section -->\n <div *ngIf=\"filteredMetadataItems.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-grid cqa-grid-cols-2 cqa-gap-x-0 cqa-gap-y-4\">\n <ng-container *ngFor=\"let item of filteredMetadataItems; trackBy: trackByMetadataLabel\">\n <div class=\"cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-0.5\">\n <div class=\"cqa-text-[#6B7280] cqa-text-xs cqa-leading-[15px] cqa-font-medium\">{{ item.label }}</div>\n <div\n class=\"cqa-flex cqa-justify-start cqa-items-center cqa-gap-[5px] cqa-min-w-0 cqa-w-full cqa-text-left cqa-text-[#0A0A0A] cqa-border cqa-border-[#F5F5F5]\">\n <mat-icon *ngIf=\"item.icon && (!item.iconLibrary || item.iconLibrary === 'mat')\" class=\"cqa-text-[#6B7280] cqa-text-sm cqa-w-4 cqa-h-4\">\n {{ item.icon }}\n </mat-icon>\n <span *ngIf=\"item.statusColor\" class=\"cqa-w-[10px] cqa-h-[10px] cqa-rounded-full cqa-flex-shrink-0\" [ngClass]=\"getStatusDotClass(item)\"></span>\n <a\n *ngIf=\"item.link\"\n href=\"javascript:void(0)\"\n class=\"cqa-text-[#2563EB] cqa-text-xs cqa-leading-[12px] cqa-font-normal hover:cqa-underline cqa-cursor-pointer cqa-block cqa-truncate cqa-min-w-0\"\n (click)=\"onMetadataLinkClick(item); $event.preventDefault()\">\n {{ item.value }}\n </a>\n <span *ngIf=\"!item.link\" class=\"cqa-text-xs cqa-leading-[12px] cqa-font-normal cqa-align-middle\" [ngClass]=\"getValueTextClass(item)\">\n {{ item.value }}\n </span>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n\n <!-- Labels (Figma: Labels title, cqa-badge chips with tag icon) -->\n <div *ngIf=\"labels.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2 cqa-text-sm cqa-leading-[19.6px]\">\n <span class=\"cqa-text-[#111827] cqa-text-sm cqa-font-medium cqa-leading-5\">Labels</span>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2\">\n <cqa-badge\n *ngFor=\"let label of labels\"\n [label]=\"label\"\n icon=\"label\"\n variant=\"outline\"\n size=\"small\"\n backgroundColor=\"#ffffff\"\n textColor=\"#475569\"\n borderColor=\"#E2E8F0\"\n iconColor=\"#94A3B8\">\n </cqa-badge>\n </div>\n </div>\n\n <!-- Configuration Section -->\n <div *ngIf=\"configSections.length || configSectionsRow2.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-inline-flex cqa-justify-start cqa-items-center\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">settings</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.6px]\">{{ configTitle }}</span>\n </div>\n </div>\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-grid cqa-grid-cols-1 cqa-gap-2.5\">\n <ng-container *ngFor=\"let section of configSections; trackBy: trackByConfigTitle\">\n <cqa-configuration-card\n [icon]=\"section.icon || 'tune'\"\n [title]=\"section.title\"\n [data]=\"section.items\">\n </cqa-configuration-card>\n </ng-container>\n </div>\n <div *ngIf=\"configSectionsRow2.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-4 cqa-text-sm cqa-leading-[19.6px]\">\n <cqa-configuration-card\n *ngFor=\"let section of configSectionsRow2; trackBy: trackByConfigTitle\"\n [icon]=\"section.icon || 'tune'\"\n [title]=\"section.title\"\n [data]=\"section.items\">\n </cqa-configuration-card>\n </div>\n </div>\n <!-- API Mocking Card (read-only) -->\n <cqa-api-mocking-card\n *ngIf=\"showApiMockingCard\"\n style=\"width: 100%;\"\n [title]=\"apiMockingTitle\"\n [statusLabel]=\"apiMockingStatusLabel\"\n [captureLabel]=\"apiMockingCaptureLabel\"\n [renewLabel]=\"apiMockingRenewLabel\"\n [restoreMock]=\"apiMockingRestoreMock\"\n [storeMock]=\"apiMockingStoreMock\"\n [mockedApisCount]=\"apiMockingMockedApisCount\"\n [totalApisCount]=\"apiMockingTotalApisCount\"\n [progressPercent]=\"apiMockingProgressPercent\"\n [showProgress]=\"apiMockingShowProgress\"\n [summaryText]=\"apiMockingSummaryText\"\n [percentText]=\"apiMockingPercentText\"\n [configureButtonLabel]=\"apiMockingConfigureButtonLabel\"\n [editing]=\"false\"\n (configure)=\"configureApiMocking.emit()\">\n </cqa-api-mocking-card>\n </div>\n </div>\n</div>\n", styles: [] }]
|
|
48110
|
+
args: [{ selector: 'cqa-test-case-details', changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Edit mode: show edit form (Figma design) -->\n<cqa-test-case-details-edit\n *ngIf=\"isEditing\"\n [descriptionTitle]=\"descriptionTitle\"\n [descriptionContent]=\"descriptionContent\"\n [enableMarkdown]=\"enableMarkdown\"\n [metadataItems]=\"metadataItems\"\n [labels]=\"labels\"\n [configTitle]=\"configTitle\"\n [configSections]=\"configSections\"\n [configSectionsRow2]=\"configSectionsRow2\"\n [platform]=\"platform\"\n [isStepGroup]=\"isStepGroup\"\n [isSaving]=\"isSaving\"\n [selectConfigOverrides]=\"selectConfigOverrides\"\n [showApiMockingCard]=\"showApiMockingCard\"\n [apiMockingTitle]=\"apiMockingTitle\"\n [apiMockingStatusLabel]=\"apiMockingStatusLabel\"\n [apiMockingCaptureLabel]=\"apiMockingCaptureLabel\"\n [apiMockingCaptureHint]=\"apiMockingCaptureHint\"\n [apiMockingRenewLabel]=\"apiMockingRenewLabel\"\n [apiMockingRenewHint]=\"apiMockingRenewHint\"\n [apiMockingRestoreMock]=\"apiMockingRestoreMock\"\n [apiMockingStoreMock]=\"apiMockingStoreMock\"\n [apiMockingMockedApisCount]=\"apiMockingMockedApisCount\"\n [apiMockingTotalApisCount]=\"apiMockingTotalApisCount\"\n [apiMockingProgressPercent]=\"apiMockingProgressPercent\"\n [apiMockingShowProgress]=\"apiMockingShowProgress\"\n [apiMockingSummaryText]=\"apiMockingSummaryText\"\n [apiMockingPercentText]=\"apiMockingPercentText\"\n [orgLevelTestCaseTimeout]=\"orgLevelTestCaseTimeout\"\n [viewportCategoryOptions]=\"viewportCategoryOptions\"\n (save)=\"onSaveChanges($event)\"\n (cancel)=\"onCancelEdit()\"\n (selectSearch)=\"selectSearch.emit($event)\"\n (selectLoadMore)=\"selectLoadMore.emit($event)\"\n (selectOpened)=\"selectOpened.emit($event)\"\n (selectionChange)=\"selectionChange.emit($event)\"\n (labelAdded)=\"labelAdded.emit($event)\"\n (apiMockingRestoreMockChange)=\"apiMockingRestoreMockChange.emit($event)\"\n (apiMockingStoreMockChange)=\"apiMockingStoreMockChange.emit($event)\"\n (configureApiMocking)=\"configureApiMocking.emit()\">\n</cqa-test-case-details-edit>\n\n<!-- View mode: read-only details -->\n<div *ngIf=\"!isEditing\" class=\"cqa-self-stretch cqa-py-4 cqa-px-0 cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-4 cqa-text-sm cqa-leading-[19.6px]\">\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-4 cqa-text-sm cqa-leading-[19.6px]\">\n <!-- Description Section -->\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-inline-flex cqa-justify-between cqa-items-center\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">description</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.6px]\">{{ descriptionTitle }}</span>\n </div>\n <button\n *ngIf=\"showEditButton\"\n type=\"button\"\n class=\"cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-px-2.5 cqa-py-1 cqa-rounded !cqa-border !cqa-border-solid !cqa-border-[#D1D5DB] cqa-text-[#6B7280] cqa-text-xs cqa-font-semibold cqa-cursor-pointer cqa-transition-all hover:cqa-text-[#374151] hover:!cqa-border-[#9CA3AF] hover:cqa-bg-[#F9FAFB] focus:cqa-outline-none focus-visible:cqa-ring-2 focus-visible:cqa-ring-[#3F43EE] focus-visible:cqa-ring-offset-2\"\n (click)=\"onEditClick()\">\n <mat-icon class=\"!cqa-w-[14px] !cqa-h-[14px] !cqa-text-[14px]\">edit</mat-icon>\n <span>Edit</span>\n </button>\n </div>\n <div *ngIf=\"descriptionContent\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-1\">\n <div\n *ngIf=\"enableMarkdown\"\n class=\"cqa-self-stretch cqa-text-[#111827] cqa-text-sm cqa-leading-[19.6px] cqa-font-normal cqa-prose cqa-prose-sm cqa-max-w-none\"\n [style]=\"(!descriptionExpanded && showDescriptionReadMore) ? 'display: -webkit-box; -webkit-line-clamp: 4; line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;' : ''\"\n [innerHTML]=\"descriptionContent\"></div>\n <div\n *ngIf=\"!enableMarkdown\"\n class=\"cqa-self-stretch cqa-text-[#111827] cqa-text-sm cqa-leading-[19.6px] cqa-font-normal\"\n [style]=\"(!descriptionExpanded && showDescriptionReadMore) ? 'display: -webkit-box; -webkit-line-clamp: 4; line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;' : ''\">{{ descriptionContent }}</div>\n <button\n *ngIf=\"showDescriptionReadMore\"\n type=\"button\"\n class=\"cqa-text-[#3F43EE] cqa-text-xs cqa-font-medium hover:cqa-underline cqa-cursor-pointer cqa-bg-transparent cqa-border-none cqa-p-0 cqa-self-start focus:cqa-outline-none focus-visible:cqa-ring-2 focus-visible:cqa-ring-[#3F43EE] focus-visible:cqa-ring-offset-2\"\n (click)=\"toggleDescriptionExpand()\">\n {{ descriptionExpanded ? 'Read less' : 'Read more' }}\n </button>\n </div>\n </div>\n\n <!-- Metadata Section -->\n <div *ngIf=\"filteredMetadataItems.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-grid cqa-grid-cols-2 cqa-gap-x-0 cqa-gap-y-4\">\n <ng-container *ngFor=\"let item of filteredMetadataItems; trackBy: trackByMetadataLabel\">\n <div class=\"cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-0.5\">\n <div class=\"cqa-text-[#6B7280] cqa-text-xs cqa-leading-[15px] cqa-font-medium\">{{ item.label }}</div>\n <div\n class=\"cqa-flex cqa-justify-start cqa-items-center cqa-gap-[5px] cqa-min-w-0 cqa-w-full cqa-text-left cqa-text-[#0A0A0A] cqa-border cqa-border-[#F5F5F5]\">\n <mat-icon *ngIf=\"item.icon && (!item.iconLibrary || item.iconLibrary === 'mat')\" class=\"cqa-text-[#6B7280] cqa-text-sm cqa-w-4 cqa-h-4\">\n {{ item.icon }}\n </mat-icon>\n <span *ngIf=\"item.statusColor\" class=\"cqa-w-[10px] cqa-h-[10px] cqa-rounded-full cqa-flex-shrink-0\" [ngClass]=\"getStatusDotClass(item)\"></span>\n <a\n *ngIf=\"item.link\"\n href=\"javascript:void(0)\"\n class=\"cqa-text-[#2563EB] cqa-text-xs cqa-leading-[12px] cqa-font-normal hover:cqa-underline cqa-cursor-pointer cqa-block cqa-truncate cqa-min-w-0\"\n (click)=\"onMetadataLinkClick(item); $event.preventDefault()\">\n {{ item.value }}\n </a>\n <span *ngIf=\"!item.link\" class=\"cqa-text-xs cqa-leading-[12px] cqa-font-normal cqa-align-middle\" [ngClass]=\"getValueTextClass(item)\">\n {{ item.value }}\n </span>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n\n <!-- Labels (Figma: Labels title, cqa-badge chips with tag icon) -->\n <div *ngIf=\"labels.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2 cqa-text-sm cqa-leading-[19.6px]\">\n <span class=\"cqa-text-[#111827] cqa-text-sm cqa-font-medium cqa-leading-5\">Labels</span>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2\">\n <cqa-badge\n *ngFor=\"let label of labels\"\n [label]=\"label\"\n icon=\"label\"\n variant=\"outline\"\n size=\"small\"\n backgroundColor=\"#ffffff\"\n textColor=\"#475569\"\n borderColor=\"#E2E8F0\"\n iconColor=\"#94A3B8\">\n </cqa-badge>\n </div>\n </div>\n\n <!-- Configuration Section -->\n <div *ngIf=\"configSections.length || configSectionsRow2.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-inline-flex cqa-justify-start cqa-items-center\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-w-5 cqa-h-5 cqa-p-1 cqa-flex-shrink-0 cqa-bg-[#3F43EE1A] cqa-rounded-md cqa-inline-flex cqa-justify-center cqa-items-center\">\n <mat-icon class=\"cqa-text-[#1B1FEB] cqa-text-[12px] cqa-w-3 cqa-h-3 cqa-leading-none cqa-block\">settings</mat-icon>\n </div>\n <span class=\"cqa-text-[#374151] cqa-text-sm cqa-font-semibold cqa-leading-[19.6px]\">{{ configTitle }}</span>\n </div>\n </div>\n <div class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-justify-start cqa-items-start cqa-gap-2.5\">\n <div class=\"cqa-self-stretch cqa-grid cqa-grid-cols-1 cqa-gap-2.5\">\n <ng-container *ngFor=\"let section of configSections; trackBy: trackByConfigTitle\">\n <cqa-configuration-card\n [icon]=\"section.icon || 'tune'\"\n [title]=\"section.title\"\n [data]=\"section.items\">\n </cqa-configuration-card>\n </ng-container>\n </div>\n <div *ngIf=\"configSectionsRow2.length\" class=\"cqa-self-stretch cqa-flex cqa-flex-col cqa-gap-4 cqa-text-sm cqa-leading-[19.6px]\">\n <cqa-configuration-card\n *ngFor=\"let section of configSectionsRow2; trackBy: trackByConfigTitle\"\n [icon]=\"section.icon || 'tune'\"\n [title]=\"section.title\"\n [data]=\"section.items\">\n </cqa-configuration-card>\n </div>\n </div>\n <!-- API Mocking Card (read-only) -->\n <cqa-api-mocking-card\n *ngIf=\"showApiMockingCard\"\n style=\"width: 100%;\"\n [title]=\"apiMockingTitle\"\n [statusLabel]=\"apiMockingStatusLabel\"\n [captureLabel]=\"apiMockingCaptureLabel\"\n [renewLabel]=\"apiMockingRenewLabel\"\n [restoreMock]=\"apiMockingRestoreMock\"\n [storeMock]=\"apiMockingStoreMock\"\n [mockedApisCount]=\"apiMockingMockedApisCount\"\n [totalApisCount]=\"apiMockingTotalApisCount\"\n [progressPercent]=\"apiMockingProgressPercent\"\n [showProgress]=\"apiMockingShowProgress\"\n [summaryText]=\"apiMockingSummaryText\"\n [percentText]=\"apiMockingPercentText\"\n [configureButtonLabel]=\"apiMockingConfigureButtonLabel\"\n [editing]=\"false\"\n (configure)=\"configureApiMocking.emit()\">\n </cqa-api-mocking-card>\n </div>\n </div>\n</div>\n", styles: [] }]
|
|
47878
48111
|
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { editing: [{
|
|
47879
48112
|
type: Input
|
|
47880
48113
|
}], startInEditMode: [{
|
|
@@ -47939,6 +48172,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
47939
48172
|
type: Input
|
|
47940
48173
|
}], orgLevelTestCaseTimeout: [{
|
|
47941
48174
|
type: Input
|
|
48175
|
+
}], viewportCategoryOptions: [{
|
|
48176
|
+
type: Input
|
|
47942
48177
|
}], editDescription: [{
|
|
47943
48178
|
type: Output
|
|
47944
48179
|
}], cancel: [{
|
|
@@ -50743,21 +50978,122 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
50743
50978
|
type: Output
|
|
50744
50979
|
}] } });
|
|
50745
50980
|
|
|
50746
|
-
|
|
50981
|
+
const DEFAULT_DESKTOP_MODE = 'desktop';
|
|
50982
|
+
class ViewportSelectorComponent {
|
|
50747
50983
|
constructor() {
|
|
50748
|
-
|
|
50749
|
-
this.
|
|
50750
|
-
/** When true, cards wrap to the next line (e.g. many platform targets). */
|
|
50751
|
-
this.wrap = false;
|
|
50984
|
+
this.label = 'Viewport';
|
|
50985
|
+
this.required = false;
|
|
50752
50986
|
this.disabled = false;
|
|
50753
|
-
|
|
50754
|
-
this.
|
|
50755
|
-
this.
|
|
50987
|
+
this.desktopLabel = 'Desktop';
|
|
50988
|
+
this.laptopLabel = 'Laptop';
|
|
50989
|
+
this.mobileLabel = 'Mobile';
|
|
50990
|
+
this.customLabel = 'Custom';
|
|
50991
|
+
this.desktopDeviceLabel = 'Resolution';
|
|
50992
|
+
this.desktopDevicePlaceholder = 'Select resolution';
|
|
50993
|
+
this.desktopDeviceOptions = [];
|
|
50994
|
+
this.laptopDeviceLabel = 'Resolution';
|
|
50995
|
+
this.laptopDevicePlaceholder = 'Select resolution';
|
|
50996
|
+
this.laptopDeviceOptions = [];
|
|
50997
|
+
this.mobileDeviceLabel = 'Device';
|
|
50998
|
+
this.mobileDevicePlaceholder = 'Select device';
|
|
50999
|
+
this.mobileDeviceOptions = [];
|
|
51000
|
+
this.customValueLabel = 'Custom viewport';
|
|
51001
|
+
this.customValuePlaceholder = 'Enter viewport value';
|
|
51002
|
+
this.customValueHint = 'Press Enter to add a viewport value like 1280x720';
|
|
51003
|
+
this.valueChange = new EventEmitter();
|
|
51004
|
+
this.modeOptions = [
|
|
51005
|
+
{ value: 'desktop', label: 'Desktop', icon: 'desktop_windows' },
|
|
51006
|
+
{ value: 'laptop', label: 'Laptop', icon: 'laptop_windows' },
|
|
51007
|
+
{ value: 'mobile', label: 'Mobile', icon: 'smartphone' },
|
|
51008
|
+
{ value: 'custom', label: 'Custom', icon: 'tune' },
|
|
51009
|
+
];
|
|
51010
|
+
this.desktopDeviceForm = new FormGroup({
|
|
51011
|
+
device: new FormControl(null),
|
|
51012
|
+
});
|
|
51013
|
+
this.laptopDeviceForm = new FormGroup({
|
|
51014
|
+
device: new FormControl(null),
|
|
51015
|
+
});
|
|
51016
|
+
this.mobileDeviceForm = new FormGroup({
|
|
51017
|
+
device: new FormControl(null),
|
|
51018
|
+
});
|
|
51019
|
+
this.desktopDeviceConfig = {
|
|
51020
|
+
key: 'device',
|
|
51021
|
+
label: '',
|
|
51022
|
+
placeholder: 'Select resolution',
|
|
51023
|
+
disabled: false,
|
|
51024
|
+
multiple: false,
|
|
51025
|
+
searchable: true,
|
|
51026
|
+
serverSearch: false,
|
|
51027
|
+
options: [],
|
|
51028
|
+
};
|
|
51029
|
+
this.laptopDeviceConfig = {
|
|
51030
|
+
key: 'device',
|
|
51031
|
+
label: '',
|
|
51032
|
+
placeholder: 'Select resolution',
|
|
51033
|
+
disabled: false,
|
|
51034
|
+
multiple: false,
|
|
51035
|
+
searchable: true,
|
|
51036
|
+
serverSearch: false,
|
|
51037
|
+
options: [],
|
|
51038
|
+
};
|
|
51039
|
+
this.mobileDeviceConfig = {
|
|
51040
|
+
key: 'device',
|
|
51041
|
+
label: '',
|
|
51042
|
+
placeholder: 'Select device',
|
|
51043
|
+
disabled: false,
|
|
51044
|
+
multiple: false,
|
|
51045
|
+
searchable: true,
|
|
51046
|
+
serverSearch: false,
|
|
51047
|
+
options: [],
|
|
51048
|
+
};
|
|
51049
|
+
this.customInputValue = '';
|
|
51050
|
+
this.internalValue = {
|
|
51051
|
+
mode: DEFAULT_DESKTOP_MODE,
|
|
51052
|
+
device: null,
|
|
51053
|
+
customValue: null,
|
|
51054
|
+
};
|
|
50756
51055
|
this.onChange = () => { };
|
|
50757
51056
|
this.onTouched = () => { };
|
|
51057
|
+
this.onValidatorChange = () => { };
|
|
50758
51058
|
}
|
|
50759
|
-
|
|
50760
|
-
|
|
51059
|
+
ngOnChanges(changes) {
|
|
51060
|
+
if (changes['desktopDeviceOptions']) {
|
|
51061
|
+
this.desktopDeviceConfig = Object.assign(Object.assign({}, this.desktopDeviceConfig), { options: this.desktopDeviceOptions || [] });
|
|
51062
|
+
}
|
|
51063
|
+
if (changes['laptopDeviceOptions']) {
|
|
51064
|
+
this.laptopDeviceConfig = Object.assign(Object.assign({}, this.laptopDeviceConfig), { options: this.laptopDeviceOptions || [] });
|
|
51065
|
+
}
|
|
51066
|
+
if (changes['mobileDeviceOptions']) {
|
|
51067
|
+
this.mobileDeviceConfig = Object.assign(Object.assign({}, this.mobileDeviceConfig), { options: this.mobileDeviceOptions || [] });
|
|
51068
|
+
}
|
|
51069
|
+
if (changes['desktopLabel'] || changes['laptopLabel'] || changes['mobileLabel'] || changes['customLabel']) {
|
|
51070
|
+
this.modeOptions[0].label = this.desktopLabel;
|
|
51071
|
+
this.modeOptions[1].label = this.laptopLabel;
|
|
51072
|
+
this.modeOptions[2].label = this.mobileLabel;
|
|
51073
|
+
this.modeOptions[3].label = this.customLabel;
|
|
51074
|
+
}
|
|
51075
|
+
if (changes['desktopDevicePlaceholder']) {
|
|
51076
|
+
this.desktopDeviceConfig = Object.assign(Object.assign({}, this.desktopDeviceConfig), { placeholder: this.desktopDevicePlaceholder });
|
|
51077
|
+
}
|
|
51078
|
+
if (changes['laptopDevicePlaceholder']) {
|
|
51079
|
+
this.laptopDeviceConfig = Object.assign(Object.assign({}, this.laptopDeviceConfig), { placeholder: this.laptopDevicePlaceholder });
|
|
51080
|
+
}
|
|
51081
|
+
if (changes['mobileDevicePlaceholder']) {
|
|
51082
|
+
this.mobileDeviceConfig = Object.assign(Object.assign({}, this.mobileDeviceConfig), { placeholder: this.mobileDevicePlaceholder });
|
|
51083
|
+
}
|
|
51084
|
+
if (changes['disabled']) {
|
|
51085
|
+
this.setDisabledState(this.disabled);
|
|
51086
|
+
}
|
|
51087
|
+
}
|
|
51088
|
+
writeValue(value) {
|
|
51089
|
+
var _a, _b, _c, _d;
|
|
51090
|
+
this.internalValue = this.normalizeValue(value);
|
|
51091
|
+
const device = (_a = this.internalValue.device) !== null && _a !== void 0 ? _a : null;
|
|
51092
|
+
const mode = this.internalValue.mode;
|
|
51093
|
+
(_b = this.desktopDeviceForm.get('device')) === null || _b === void 0 ? void 0 : _b.setValue(mode === 'desktop' ? device : null, { emitEvent: false });
|
|
51094
|
+
(_c = this.laptopDeviceForm.get('device')) === null || _c === void 0 ? void 0 : _c.setValue(mode === 'laptop' ? device : null, { emitEvent: false });
|
|
51095
|
+
(_d = this.mobileDeviceForm.get('device')) === null || _d === void 0 ? void 0 : _d.setValue(mode === 'mobile' ? device : null, { emitEvent: false });
|
|
51096
|
+
this.customInputValue = '';
|
|
50761
51097
|
}
|
|
50762
51098
|
registerOnChange(fn) {
|
|
50763
51099
|
this.onChange = fn;
|
|
@@ -50765,50 +51101,200 @@ class RadioCardGroupComponent {
|
|
|
50765
51101
|
registerOnTouched(fn) {
|
|
50766
51102
|
this.onTouched = fn;
|
|
50767
51103
|
}
|
|
51104
|
+
registerOnValidatorChange(fn) {
|
|
51105
|
+
this.onValidatorChange = fn;
|
|
51106
|
+
}
|
|
50768
51107
|
setDisabledState(isDisabled) {
|
|
50769
51108
|
this.disabled = isDisabled;
|
|
51109
|
+
const config = { disabled: isDisabled };
|
|
51110
|
+
this.desktopDeviceConfig = Object.assign(Object.assign({}, this.desktopDeviceConfig), config);
|
|
51111
|
+
this.laptopDeviceConfig = Object.assign(Object.assign({}, this.laptopDeviceConfig), config);
|
|
51112
|
+
this.mobileDeviceConfig = Object.assign(Object.assign({}, this.mobileDeviceConfig), config);
|
|
51113
|
+
if (isDisabled) {
|
|
51114
|
+
this.desktopDeviceForm.disable({ emitEvent: false });
|
|
51115
|
+
this.laptopDeviceForm.disable({ emitEvent: false });
|
|
51116
|
+
this.mobileDeviceForm.disable({ emitEvent: false });
|
|
51117
|
+
}
|
|
51118
|
+
else {
|
|
51119
|
+
this.desktopDeviceForm.enable({ emitEvent: false });
|
|
51120
|
+
this.laptopDeviceForm.enable({ emitEvent: false });
|
|
51121
|
+
this.mobileDeviceForm.enable({ emitEvent: false });
|
|
51122
|
+
}
|
|
50770
51123
|
}
|
|
50771
|
-
|
|
50772
|
-
|
|
51124
|
+
validate(_control) {
|
|
51125
|
+
if (this.internalValue.mode === 'mobile' && !this.internalValue.device) {
|
|
51126
|
+
return { viewportSelection: { requiredDevice: true } };
|
|
51127
|
+
}
|
|
51128
|
+
if (this.internalValue.mode === 'custom' && !this.internalValue.customValue) {
|
|
51129
|
+
return { viewportSelection: { requiredCustomValue: true } };
|
|
51130
|
+
}
|
|
51131
|
+
return null;
|
|
50773
51132
|
}
|
|
50774
|
-
get
|
|
50775
|
-
return
|
|
51133
|
+
get isDesktopMode() {
|
|
51134
|
+
return this.internalValue.mode === 'desktop';
|
|
50776
51135
|
}
|
|
50777
|
-
|
|
51136
|
+
get isLaptopMode() {
|
|
51137
|
+
return this.internalValue.mode === 'laptop';
|
|
51138
|
+
}
|
|
51139
|
+
get isMobileMode() {
|
|
51140
|
+
return this.internalValue.mode === 'mobile';
|
|
51141
|
+
}
|
|
51142
|
+
get isCustomMode() {
|
|
51143
|
+
return this.internalValue.mode === 'custom';
|
|
51144
|
+
}
|
|
51145
|
+
onModeChange(mode) {
|
|
51146
|
+
var _a, _b, _c, _d, _e;
|
|
50778
51147
|
if (this.disabled) {
|
|
50779
51148
|
return;
|
|
50780
51149
|
}
|
|
50781
|
-
const
|
|
50782
|
-
|
|
50783
|
-
this.
|
|
51150
|
+
const nextMode = this.isValidMode(mode) ? mode : DEFAULT_DESKTOP_MODE;
|
|
51151
|
+
const currentDevice = this.internalValue.device;
|
|
51152
|
+
this.internalValue = {
|
|
51153
|
+
mode: nextMode,
|
|
51154
|
+
device: (nextMode === 'desktop' || nextMode === 'laptop' || nextMode === 'mobile') ? (currentDevice !== null && currentDevice !== void 0 ? currentDevice : null) : null,
|
|
51155
|
+
customValue: nextMode === 'custom' ? ((_a = this.internalValue.customValue) !== null && _a !== void 0 ? _a : null) : null,
|
|
51156
|
+
};
|
|
51157
|
+
// Reset device forms; only populate the matching mode's form
|
|
51158
|
+
const deviceValue = (_b = this.internalValue.device) !== null && _b !== void 0 ? _b : null;
|
|
51159
|
+
(_c = this.desktopDeviceForm.get('device')) === null || _c === void 0 ? void 0 : _c.setValue(nextMode === 'desktop' ? deviceValue : null, { emitEvent: false });
|
|
51160
|
+
(_d = this.laptopDeviceForm.get('device')) === null || _d === void 0 ? void 0 : _d.setValue(nextMode === 'laptop' ? deviceValue : null, { emitEvent: false });
|
|
51161
|
+
(_e = this.mobileDeviceForm.get('device')) === null || _e === void 0 ? void 0 : _e.setValue(nextMode === 'mobile' ? deviceValue : null, { emitEvent: false });
|
|
51162
|
+
this.emitValue();
|
|
51163
|
+
}
|
|
51164
|
+
onDesktopSelectionChange(selection) {
|
|
51165
|
+
if (this.disabled)
|
|
51166
|
+
return;
|
|
51167
|
+
this.internalValue = Object.assign(Object.assign({}, this.internalValue), { mode: 'desktop', device: (selection === null || selection === void 0 ? void 0 : selection.value) != null && selection.value !== '' ? String(selection.value) : null, customValue: null });
|
|
51168
|
+
this.emitValue();
|
|
51169
|
+
}
|
|
51170
|
+
onLaptopSelectionChange(selection) {
|
|
51171
|
+
if (this.disabled)
|
|
51172
|
+
return;
|
|
51173
|
+
this.internalValue = Object.assign(Object.assign({}, this.internalValue), { mode: 'laptop', device: (selection === null || selection === void 0 ? void 0 : selection.value) != null && selection.value !== '' ? String(selection.value) : null, customValue: null });
|
|
51174
|
+
this.emitValue();
|
|
51175
|
+
}
|
|
51176
|
+
onMobileSelectionChange(selection) {
|
|
51177
|
+
if (this.disabled) {
|
|
51178
|
+
return;
|
|
51179
|
+
}
|
|
51180
|
+
this.internalValue = Object.assign(Object.assign({}, this.internalValue), { mode: 'mobile', device: (selection === null || selection === void 0 ? void 0 : selection.value) != null && selection.value !== '' ? String(selection.value) : null, customValue: null });
|
|
51181
|
+
this.emitValue();
|
|
51182
|
+
}
|
|
51183
|
+
addCustomValue(rawValue) {
|
|
51184
|
+
if (this.disabled) {
|
|
51185
|
+
return;
|
|
51186
|
+
}
|
|
51187
|
+
const nextValue = this.normalizeCustomValue(rawValue !== null && rawValue !== void 0 ? rawValue : this.customInputValue);
|
|
51188
|
+
if (!nextValue) {
|
|
51189
|
+
return;
|
|
51190
|
+
}
|
|
51191
|
+
this.internalValue = Object.assign(Object.assign({}, this.internalValue), { mode: 'custom', device: null, customValue: nextValue });
|
|
51192
|
+
this.customInputValue = '';
|
|
51193
|
+
this.emitValue();
|
|
51194
|
+
}
|
|
51195
|
+
clearCustomValue() {
|
|
51196
|
+
if (this.disabled) {
|
|
51197
|
+
return;
|
|
51198
|
+
}
|
|
51199
|
+
this.internalValue = Object.assign(Object.assign({}, this.internalValue), { customValue: null });
|
|
51200
|
+
this.emitValue();
|
|
51201
|
+
}
|
|
51202
|
+
emitValue() {
|
|
51203
|
+
const normalized = this.normalizeValue(this.internalValue);
|
|
51204
|
+
this.internalValue = normalized;
|
|
50784
51205
|
this.onTouched();
|
|
50785
|
-
this.
|
|
51206
|
+
this.onChange(normalized);
|
|
51207
|
+
this.onValidatorChange();
|
|
51208
|
+
this.valueChange.emit(normalized);
|
|
51209
|
+
}
|
|
51210
|
+
normalizeValue(value) {
|
|
51211
|
+
var _a;
|
|
51212
|
+
const mode = this.isValidMode(value === null || value === void 0 ? void 0 : value.mode) ? value.mode : DEFAULT_DESKTOP_MODE;
|
|
51213
|
+
const device = (value === null || value === void 0 ? void 0 : value.device) != null && String(value.device).trim() !== '' ? String(value.device).trim() : null;
|
|
51214
|
+
const customValue = this.normalizeCustomValue((_a = value === null || value === void 0 ? void 0 : value.customValue) !== null && _a !== void 0 ? _a : null);
|
|
51215
|
+
return {
|
|
51216
|
+
mode,
|
|
51217
|
+
device: (mode === 'desktop' || mode === 'laptop' || mode === 'mobile') ? device : null,
|
|
51218
|
+
customValue: mode === 'custom' ? customValue : null,
|
|
51219
|
+
};
|
|
51220
|
+
}
|
|
51221
|
+
normalizeCustomValue(value) {
|
|
51222
|
+
if (value == null) {
|
|
51223
|
+
return null;
|
|
51224
|
+
}
|
|
51225
|
+
const normalized = String(value).trim();
|
|
51226
|
+
return normalized ? normalized : null;
|
|
51227
|
+
}
|
|
51228
|
+
isValidMode(mode) {
|
|
51229
|
+
return mode === 'desktop' || mode === 'laptop' || mode === 'mobile' || mode === 'custom';
|
|
50786
51230
|
}
|
|
50787
51231
|
}
|
|
50788
|
-
|
|
50789
|
-
|
|
51232
|
+
ViewportSelectorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ViewportSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
51233
|
+
ViewportSelectorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ViewportSelectorComponent, selector: "cqa-viewport-selector", inputs: { label: "label", required: "required", disabled: "disabled", desktopLabel: "desktopLabel", laptopLabel: "laptopLabel", mobileLabel: "mobileLabel", customLabel: "customLabel", desktopDeviceLabel: "desktopDeviceLabel", desktopDevicePlaceholder: "desktopDevicePlaceholder", desktopDeviceOptions: "desktopDeviceOptions", laptopDeviceLabel: "laptopDeviceLabel", laptopDevicePlaceholder: "laptopDevicePlaceholder", laptopDeviceOptions: "laptopDeviceOptions", mobileDeviceLabel: "mobileDeviceLabel", mobileDevicePlaceholder: "mobileDevicePlaceholder", mobileDeviceOptions: "mobileDeviceOptions", customValueLabel: "customValueLabel", customValuePlaceholder: "customValuePlaceholder", customValueHint: "customValueHint" }, outputs: { valueChange: "valueChange" }, host: { classAttribute: "cqa-ui-root cqa-block" }, providers: [
|
|
50790
51234
|
{
|
|
50791
51235
|
provide: NG_VALUE_ACCESSOR,
|
|
50792
|
-
useExisting: forwardRef(() =>
|
|
50793
|
-
multi: true
|
|
50794
|
-
}
|
|
50795
|
-
|
|
50796
|
-
|
|
51236
|
+
useExisting: forwardRef(() => ViewportSelectorComponent),
|
|
51237
|
+
multi: true,
|
|
51238
|
+
},
|
|
51239
|
+
{
|
|
51240
|
+
provide: NG_VALIDATORS,
|
|
51241
|
+
useExisting: forwardRef(() => ViewportSelectorComponent),
|
|
51242
|
+
multi: true,
|
|
51243
|
+
},
|
|
51244
|
+
], usesOnChanges: true, ngImport: i0, template: "<div id=\"cqa-ui-root\" [style.display]=\"'block'\" [style.width]=\"'100%'\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-w-full\">\n <label\n *ngIf=\"label\"\n class=\"cqa-text-sm cqa-font-medium cqa-text-[#374151]\">\n {{ label }}\n <span *ngIf=\"required\" class=\"cqa-text-[#EF4444]\">*</span>\n </label>\n\n <cqa-radio-card-group\n [options]=\"modeOptions\"\n [disabled]=\"disabled\"\n [ngModel]=\"internalValue.mode\"\n (ngModelChange)=\"onModeChange($event)\">\n </cqa-radio-card-group>\n\n <div *ngIf=\"isDesktopMode\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-w-full\">\n <span class=\"cqa-text-xs cqa-font-medium cqa-text-[#6B7280]\">{{ desktopDeviceLabel }}</span>\n <cqa-dynamic-select\n class=\"cqa-w-full\"\n [form]=\"desktopDeviceForm\"\n [config]=\"desktopDeviceConfig\"\n (selectionChange)=\"onDesktopSelectionChange($event)\">\n </cqa-dynamic-select>\n </div>\n\n <div *ngIf=\"isLaptopMode\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-w-full\">\n <span class=\"cqa-text-xs cqa-font-medium cqa-text-[#6B7280]\">{{ laptopDeviceLabel }}</span>\n <cqa-dynamic-select\n class=\"cqa-w-full\"\n [form]=\"laptopDeviceForm\"\n [config]=\"laptopDeviceConfig\"\n (selectionChange)=\"onLaptopSelectionChange($event)\">\n </cqa-dynamic-select>\n </div>\n\n <div *ngIf=\"isMobileMode\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-w-full\">\n <span class=\"cqa-text-xs cqa-font-medium cqa-text-[#6B7280]\">{{ mobileDeviceLabel }}</span>\n <cqa-dynamic-select\n class=\"cqa-w-full\"\n [form]=\"mobileDeviceForm\"\n [config]=\"mobileDeviceConfig\"\n (selectionChange)=\"onMobileSelectionChange($event)\">\n </cqa-dynamic-select>\n </div>\n\n <div *ngIf=\"isCustomMode\" class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-w-full\">\n <span class=\"cqa-text-xs cqa-font-medium cqa-text-[#6B7280]\">{{ customValueLabel }}</span>\n\n <div class=\"cqa-flex cqa-items-start cqa-gap-2 cqa-w-full\">\n <cqa-custom-input\n class=\"cqa-flex-1\"\n [fullWidth]=\"true\"\n [placeholder]=\"customValuePlaceholder\"\n [value]=\"customInputValue\"\n [disabled]=\"disabled\"\n (valueChange)=\"customInputValue = $event\"\n (enterPressed)=\"addCustomValue($event)\">\n </cqa-custom-input>\n\n <button\n type=\"button\"\n class=\"cqa-h-[42px] cqa-rounded-md cqa-border cqa-border-solid cqa-border-[#D1D5DB] cqa-bg-white cqa-px-3 cqa-text-sm cqa-font-medium cqa-text-[#111827] hover:cqa-bg-[#F9FAFB] disabled:cqa-cursor-not-allowed disabled:cqa-opacity-60\"\n [disabled]=\"disabled || !customInputValue.trim()\"\n (click)=\"addCustomValue()\">\n Add\n </button>\n </div>\n\n <span class=\"cqa-text-xs cqa-text-[#6B7280]\">{{ customValueHint }}</span>\n\n <div *ngIf=\"internalValue.customValue\" class=\"cqa-flex cqa-flex-wrap cqa-gap-2\">\n <span class=\"cqa-inline-flex cqa-items-center cqa-gap-2 cqa-rounded-full cqa-bg-[#EEF2FF] cqa-px-3 cqa-py-1 cqa-text-sm cqa-font-medium cqa-text-[#3730A3]\">\n {{ internalValue.customValue }}\n <button\n type=\"button\"\n class=\"cqa-inline-flex cqa-h-4 cqa-w-4 cqa-items-center cqa-justify-center cqa-rounded-full cqa-text-xs cqa-text-[#3730A3] hover:cqa-bg-[#E0E7FF]\"\n [disabled]=\"disabled\"\n (click)=\"clearCustomValue()\">\n x\n </button>\n </span>\n </div>\n </div>\n </div>\n</div>\n", components: [{ type: RadioCardGroupComponent, selector: "cqa-radio-card-group", inputs: ["options", "wrap", "disabled"], outputs: ["selectionChange"] }, { type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore", "addCustomValue"] }, { type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["inputId", "label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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"] }] });
|
|
51245
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ViewportSelectorComponent, decorators: [{
|
|
50797
51246
|
type: Component,
|
|
50798
|
-
args: [{ selector: 'cqa-
|
|
51247
|
+
args: [{ selector: 'cqa-viewport-selector', host: { class: 'cqa-ui-root cqa-block' }, providers: [
|
|
50799
51248
|
{
|
|
50800
51249
|
provide: NG_VALUE_ACCESSOR,
|
|
50801
|
-
useExisting: forwardRef(() =>
|
|
50802
|
-
multi: true
|
|
50803
|
-
}
|
|
50804
|
-
|
|
50805
|
-
|
|
51250
|
+
useExisting: forwardRef(() => ViewportSelectorComponent),
|
|
51251
|
+
multi: true,
|
|
51252
|
+
},
|
|
51253
|
+
{
|
|
51254
|
+
provide: NG_VALIDATORS,
|
|
51255
|
+
useExisting: forwardRef(() => ViewportSelectorComponent),
|
|
51256
|
+
multi: true,
|
|
51257
|
+
},
|
|
51258
|
+
], template: "<div id=\"cqa-ui-root\" [style.display]=\"'block'\" [style.width]=\"'100%'\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-w-full\">\n <label\n *ngIf=\"label\"\n class=\"cqa-text-sm cqa-font-medium cqa-text-[#374151]\">\n {{ label }}\n <span *ngIf=\"required\" class=\"cqa-text-[#EF4444]\">*</span>\n </label>\n\n <cqa-radio-card-group\n [options]=\"modeOptions\"\n [disabled]=\"disabled\"\n [ngModel]=\"internalValue.mode\"\n (ngModelChange)=\"onModeChange($event)\">\n </cqa-radio-card-group>\n\n <div *ngIf=\"isDesktopMode\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-w-full\">\n <span class=\"cqa-text-xs cqa-font-medium cqa-text-[#6B7280]\">{{ desktopDeviceLabel }}</span>\n <cqa-dynamic-select\n class=\"cqa-w-full\"\n [form]=\"desktopDeviceForm\"\n [config]=\"desktopDeviceConfig\"\n (selectionChange)=\"onDesktopSelectionChange($event)\">\n </cqa-dynamic-select>\n </div>\n\n <div *ngIf=\"isLaptopMode\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-w-full\">\n <span class=\"cqa-text-xs cqa-font-medium cqa-text-[#6B7280]\">{{ laptopDeviceLabel }}</span>\n <cqa-dynamic-select\n class=\"cqa-w-full\"\n [form]=\"laptopDeviceForm\"\n [config]=\"laptopDeviceConfig\"\n (selectionChange)=\"onLaptopSelectionChange($event)\">\n </cqa-dynamic-select>\n </div>\n\n <div *ngIf=\"isMobileMode\" class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-w-full\">\n <span class=\"cqa-text-xs cqa-font-medium cqa-text-[#6B7280]\">{{ mobileDeviceLabel }}</span>\n <cqa-dynamic-select\n class=\"cqa-w-full\"\n [form]=\"mobileDeviceForm\"\n [config]=\"mobileDeviceConfig\"\n (selectionChange)=\"onMobileSelectionChange($event)\">\n </cqa-dynamic-select>\n </div>\n\n <div *ngIf=\"isCustomMode\" class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-w-full\">\n <span class=\"cqa-text-xs cqa-font-medium cqa-text-[#6B7280]\">{{ customValueLabel }}</span>\n\n <div class=\"cqa-flex cqa-items-start cqa-gap-2 cqa-w-full\">\n <cqa-custom-input\n class=\"cqa-flex-1\"\n [fullWidth]=\"true\"\n [placeholder]=\"customValuePlaceholder\"\n [value]=\"customInputValue\"\n [disabled]=\"disabled\"\n (valueChange)=\"customInputValue = $event\"\n (enterPressed)=\"addCustomValue($event)\">\n </cqa-custom-input>\n\n <button\n type=\"button\"\n class=\"cqa-h-[42px] cqa-rounded-md cqa-border cqa-border-solid cqa-border-[#D1D5DB] cqa-bg-white cqa-px-3 cqa-text-sm cqa-font-medium cqa-text-[#111827] hover:cqa-bg-[#F9FAFB] disabled:cqa-cursor-not-allowed disabled:cqa-opacity-60\"\n [disabled]=\"disabled || !customInputValue.trim()\"\n (click)=\"addCustomValue()\">\n Add\n </button>\n </div>\n\n <span class=\"cqa-text-xs cqa-text-[#6B7280]\">{{ customValueHint }}</span>\n\n <div *ngIf=\"internalValue.customValue\" class=\"cqa-flex cqa-flex-wrap cqa-gap-2\">\n <span class=\"cqa-inline-flex cqa-items-center cqa-gap-2 cqa-rounded-full cqa-bg-[#EEF2FF] cqa-px-3 cqa-py-1 cqa-text-sm cqa-font-medium cqa-text-[#3730A3]\">\n {{ internalValue.customValue }}\n <button\n type=\"button\"\n class=\"cqa-inline-flex cqa-h-4 cqa-w-4 cqa-items-center cqa-justify-center cqa-rounded-full cqa-text-xs cqa-text-[#3730A3] hover:cqa-bg-[#E0E7FF]\"\n [disabled]=\"disabled\"\n (click)=\"clearCustomValue()\">\n x\n </button>\n </span>\n </div>\n </div>\n </div>\n</div>\n", styles: [] }]
|
|
51259
|
+
}], propDecorators: { label: [{
|
|
50806
51260
|
type: Input
|
|
50807
|
-
}],
|
|
51261
|
+
}], required: [{
|
|
50808
51262
|
type: Input
|
|
50809
51263
|
}], disabled: [{
|
|
50810
51264
|
type: Input
|
|
50811
|
-
}],
|
|
51265
|
+
}], desktopLabel: [{
|
|
51266
|
+
type: Input
|
|
51267
|
+
}], laptopLabel: [{
|
|
51268
|
+
type: Input
|
|
51269
|
+
}], mobileLabel: [{
|
|
51270
|
+
type: Input
|
|
51271
|
+
}], customLabel: [{
|
|
51272
|
+
type: Input
|
|
51273
|
+
}], desktopDeviceLabel: [{
|
|
51274
|
+
type: Input
|
|
51275
|
+
}], desktopDevicePlaceholder: [{
|
|
51276
|
+
type: Input
|
|
51277
|
+
}], desktopDeviceOptions: [{
|
|
51278
|
+
type: Input
|
|
51279
|
+
}], laptopDeviceLabel: [{
|
|
51280
|
+
type: Input
|
|
51281
|
+
}], laptopDevicePlaceholder: [{
|
|
51282
|
+
type: Input
|
|
51283
|
+
}], laptopDeviceOptions: [{
|
|
51284
|
+
type: Input
|
|
51285
|
+
}], mobileDeviceLabel: [{
|
|
51286
|
+
type: Input
|
|
51287
|
+
}], mobileDevicePlaceholder: [{
|
|
51288
|
+
type: Input
|
|
51289
|
+
}], mobileDeviceOptions: [{
|
|
51290
|
+
type: Input
|
|
51291
|
+
}], customValueLabel: [{
|
|
51292
|
+
type: Input
|
|
51293
|
+
}], customValuePlaceholder: [{
|
|
51294
|
+
type: Input
|
|
51295
|
+
}], customValueHint: [{
|
|
51296
|
+
type: Input
|
|
51297
|
+
}], valueChange: [{
|
|
50812
51298
|
type: Output
|
|
50813
51299
|
}] } });
|
|
50814
51300
|
|
|
@@ -52461,6 +52947,7 @@ UiKitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "1
|
|
|
52461
52947
|
SegmentControlComponent,
|
|
52462
52948
|
StepperComponent,
|
|
52463
52949
|
RadioCardGroupComponent,
|
|
52950
|
+
ViewportSelectorComponent,
|
|
52464
52951
|
DialogComponent,
|
|
52465
52952
|
DynamicTableComponent,
|
|
52466
52953
|
DynamicCellTemplateDirective,
|
|
@@ -52656,6 +53143,7 @@ UiKitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "1
|
|
|
52656
53143
|
SegmentControlComponent,
|
|
52657
53144
|
StepperComponent,
|
|
52658
53145
|
RadioCardGroupComponent,
|
|
53146
|
+
ViewportSelectorComponent,
|
|
52659
53147
|
DialogComponent,
|
|
52660
53148
|
DynamicTableComponent,
|
|
52661
53149
|
DynamicCellTemplateDirective,
|
|
@@ -52896,6 +53384,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
52896
53384
|
SegmentControlComponent,
|
|
52897
53385
|
StepperComponent,
|
|
52898
53386
|
RadioCardGroupComponent,
|
|
53387
|
+
ViewportSelectorComponent,
|
|
52899
53388
|
DialogComponent,
|
|
52900
53389
|
DynamicTableComponent,
|
|
52901
53390
|
DynamicCellTemplateDirective,
|
|
@@ -53097,6 +53586,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
53097
53586
|
SegmentControlComponent,
|
|
53098
53587
|
StepperComponent,
|
|
53099
53588
|
RadioCardGroupComponent,
|
|
53589
|
+
ViewportSelectorComponent,
|
|
53100
53590
|
DialogComponent,
|
|
53101
53591
|
DynamicTableComponent,
|
|
53102
53592
|
DynamicCellTemplateDirective,
|
|
@@ -53979,5 +54469,5 @@ function buildTestCaseDetailsFromApi(data, options) {
|
|
|
53979
54469
|
* Generated bundle index. Do not edit.
|
|
53980
54470
|
*/
|
|
53981
54471
|
|
|
53982
|
-
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, NamePromptModalComponent, 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 };
|
|
54472
|
+
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, NamePromptModalComponent, 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, ViewportSelectorComponent, 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 };
|
|
53983
54473
|
//# sourceMappingURL=cqa-lib-cqa-ui.mjs.map
|