@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';
|
|
@@ -8953,6 +8953,9 @@ class FolderSidebarComponent {
|
|
|
8953
8953
|
/** Fires when a folder row is dropped onto another folder (or the Unorganized row). */
|
|
8954
8954
|
this.folderDropped = new EventEmitter();
|
|
8955
8955
|
this.collapsedChange = new EventEmitter();
|
|
8956
|
+
/** Bound to the search input. Exposed as an Input so hosts can seed/restore
|
|
8957
|
+
* the visible search term across destroy/re-create cycles (e.g., when the
|
|
8958
|
+
* sidebar is `*ngIf`'d out by a view-mode toggle and re-mounted later). */
|
|
8956
8959
|
this.searchValue = '';
|
|
8957
8960
|
/** Debounce timer for `searchChange` emissions; cleared on each keystroke so
|
|
8958
8961
|
* the host only re-fetches once the user pauses typing. */
|
|
@@ -9510,7 +9513,7 @@ FolderSidebarComponent.RENAME_LIMIT_FLASH_MS = 600;
|
|
|
9510
9513
|
* position is within this many px of the end. */
|
|
9511
9514
|
FolderSidebarComponent.SCROLL_LOAD_THRESHOLD_PX = 64;
|
|
9512
9515
|
FolderSidebarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: FolderSidebarComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
9513
|
-
FolderSidebarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: FolderSidebarComponent, selector: "cqa-folder-sidebar", inputs: { folders: "folders", selectedFolderId: "selectedFolderId", expandedFolderIds: "expandedFolderIds", 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 });
|
|
9516
|
+
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 });
|
|
9514
9517
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: FolderSidebarComponent, decorators: [{
|
|
9515
9518
|
type: Component,
|
|
9516
9519
|
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: [] }]
|
|
@@ -9578,6 +9581,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
9578
9581
|
type: Output
|
|
9579
9582
|
}], collapsedChange: [{
|
|
9580
9583
|
type: Output
|
|
9584
|
+
}], searchValue: [{
|
|
9585
|
+
type: Input
|
|
9581
9586
|
}], onDocumentClick: [{
|
|
9582
9587
|
type: HostListener,
|
|
9583
9588
|
args: ['document:click']
|
|
@@ -9751,6 +9756,10 @@ class ModularTableTemplateComponent {
|
|
|
9751
9756
|
/** Lazy-load: true while the host is fetching server-side folder-search
|
|
9752
9757
|
* results. Forwarded to the sidebar so it can render a search spinner. */
|
|
9753
9758
|
this.folderSearchLoading = false;
|
|
9759
|
+
/** Seeded value for the sidebar's search input. Exposed so hosts can restore
|
|
9760
|
+
* an in-flight folder-search across sidebar destroy/re-create cycles (e.g.,
|
|
9761
|
+
* toggling out of and back into modular view). */
|
|
9762
|
+
this.folderSearchValue = '';
|
|
9754
9763
|
/** Lazy-load: true while a root-page fetch is in flight (initial load OR
|
|
9755
9764
|
* the scroll-driven "load more" pagination). Drives the loading indicator
|
|
9756
9765
|
* the modular grid renders at the right edge of the Organized row, and is
|
|
@@ -11074,10 +11083,10 @@ class ModularTableTemplateComponent {
|
|
|
11074
11083
|
}
|
|
11075
11084
|
ModularTableTemplateComponent.GRID_SCROLL_LOAD_THRESHOLD_PX = 96;
|
|
11076
11085
|
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 });
|
|
11077
|
-
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 });
|
|
11086
|
+
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 });
|
|
11078
11087
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ModularTableTemplateComponent, decorators: [{
|
|
11079
11088
|
type: Component,
|
|
11080
|
-
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: [] }]
|
|
11089
|
+
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: [] }]
|
|
11081
11090
|
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: DialogService }]; }, propDecorators: { searchPlaceholder: [{
|
|
11082
11091
|
type: Input
|
|
11083
11092
|
}], searchValue: [{
|
|
@@ -11214,6 +11223,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
11214
11223
|
type: Input
|
|
11215
11224
|
}], folderSearchLoading: [{
|
|
11216
11225
|
type: Input
|
|
11226
|
+
}], folderSearchValue: [{
|
|
11227
|
+
type: Input
|
|
11217
11228
|
}], rootFoldersLoading: [{
|
|
11218
11229
|
type: Input
|
|
11219
11230
|
}], selectedFolderNode: [{
|
|
@@ -46291,6 +46302,75 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
46291
46302
|
type: Output
|
|
46292
46303
|
}] } });
|
|
46293
46304
|
|
|
46305
|
+
class RadioCardGroupComponent {
|
|
46306
|
+
constructor() {
|
|
46307
|
+
/** Choices to render (order preserved). */
|
|
46308
|
+
this.options = [];
|
|
46309
|
+
/** When true, cards wrap to the next line (e.g. many platform targets). */
|
|
46310
|
+
this.wrap = false;
|
|
46311
|
+
this.disabled = false;
|
|
46312
|
+
/** Emits the same event as `mat-radio-group` for compatibility with existing handlers. */
|
|
46313
|
+
this.selectionChange = new EventEmitter();
|
|
46314
|
+
this.value = null;
|
|
46315
|
+
this.onChange = () => { };
|
|
46316
|
+
this.onTouched = () => { };
|
|
46317
|
+
}
|
|
46318
|
+
writeValue(obj) {
|
|
46319
|
+
this.value = obj == null ? null : String(obj);
|
|
46320
|
+
}
|
|
46321
|
+
registerOnChange(fn) {
|
|
46322
|
+
this.onChange = fn;
|
|
46323
|
+
}
|
|
46324
|
+
registerOnTouched(fn) {
|
|
46325
|
+
this.onTouched = fn;
|
|
46326
|
+
}
|
|
46327
|
+
setDisabledState(isDisabled) {
|
|
46328
|
+
this.disabled = isDisabled;
|
|
46329
|
+
}
|
|
46330
|
+
trackByValue(_index, opt) {
|
|
46331
|
+
return opt.value;
|
|
46332
|
+
}
|
|
46333
|
+
get hasAnyIcon() {
|
|
46334
|
+
return (this.options || []).some((o) => !!o.icon);
|
|
46335
|
+
}
|
|
46336
|
+
onRadioChange(event) {
|
|
46337
|
+
if (this.disabled) {
|
|
46338
|
+
return;
|
|
46339
|
+
}
|
|
46340
|
+
const next = event.value != null ? String(event.value) : null;
|
|
46341
|
+
this.value = next;
|
|
46342
|
+
this.onChange(next);
|
|
46343
|
+
this.onTouched();
|
|
46344
|
+
this.selectionChange.emit(event);
|
|
46345
|
+
}
|
|
46346
|
+
}
|
|
46347
|
+
RadioCardGroupComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: RadioCardGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
46348
|
+
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: [
|
|
46349
|
+
{
|
|
46350
|
+
provide: NG_VALUE_ACCESSOR,
|
|
46351
|
+
useExisting: forwardRef(() => RadioCardGroupComponent),
|
|
46352
|
+
multi: true
|
|
46353
|
+
}
|
|
46354
|
+
], 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"] }] });
|
|
46355
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: RadioCardGroupComponent, decorators: [{
|
|
46356
|
+
type: Component,
|
|
46357
|
+
args: [{ selector: 'cqa-radio-card-group', host: { class: 'cqa-ui-root cqa-block' }, providers: [
|
|
46358
|
+
{
|
|
46359
|
+
provide: NG_VALUE_ACCESSOR,
|
|
46360
|
+
useExisting: forwardRef(() => RadioCardGroupComponent),
|
|
46361
|
+
multi: true
|
|
46362
|
+
}
|
|
46363
|
+
], 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: [] }]
|
|
46364
|
+
}], propDecorators: { options: [{
|
|
46365
|
+
type: Input
|
|
46366
|
+
}], wrap: [{
|
|
46367
|
+
type: Input
|
|
46368
|
+
}], disabled: [{
|
|
46369
|
+
type: Input
|
|
46370
|
+
}], selectionChange: [{
|
|
46371
|
+
type: Output
|
|
46372
|
+
}] } });
|
|
46373
|
+
|
|
46294
46374
|
/**
|
|
46295
46375
|
* Dual-mode card summarising the API mocking configuration of a test case.
|
|
46296
46376
|
*
|
|
@@ -46516,6 +46596,8 @@ class TestCaseDetailsEditComponent {
|
|
|
46516
46596
|
/** Forwarded to `cqa-api-mocking-card`. In edit mode the card hides the block anyway, but
|
|
46517
46597
|
* we still pipe the input through for symmetry with the read-only component. */
|
|
46518
46598
|
this.apiMockingShowProgress = false;
|
|
46599
|
+
/** Viewport dropdown options per category from the API. Pass DESKTOP, LAPTOP, TABLET, MOBILE arrays. */
|
|
46600
|
+
this.viewportCategoryOptions = {};
|
|
46519
46601
|
this.save = new EventEmitter();
|
|
46520
46602
|
this.cancel = new EventEmitter();
|
|
46521
46603
|
/** Emitted when user searches in a select (serverSearch mode). Call API and update options via selectConfigOverrides. */
|
|
@@ -46558,6 +46640,48 @@ class TestCaseDetailsEditComponent {
|
|
|
46558
46640
|
this.mobileTestingEnabled = false;
|
|
46559
46641
|
this.extensionUseEnabled = false;
|
|
46560
46642
|
this.dataDrivenEnabled = false;
|
|
46643
|
+
this.viewportMode = 'desktop';
|
|
46644
|
+
this.viewportDesktopDeviceForm = new FormGroup({ viewportDesktopDevice: new FormControl('') });
|
|
46645
|
+
this.viewportLaptopDeviceForm = new FormGroup({ viewportLaptopDevice: new FormControl('') });
|
|
46646
|
+
this.viewportTabletDeviceForm = new FormGroup({ viewportTabletDevice: new FormControl('') });
|
|
46647
|
+
this.viewportMobileDeviceForm = new FormGroup({ viewportMobileDevice: new FormControl('') });
|
|
46648
|
+
this.customViewportWidth = '';
|
|
46649
|
+
this.customViewportHeight = '';
|
|
46650
|
+
this.customViewportTags = [];
|
|
46651
|
+
this.viewportModeOptions = [
|
|
46652
|
+
{ value: 'desktop', label: 'Desktop', icon: 'desktop_windows' },
|
|
46653
|
+
{ value: 'laptop', label: 'Laptop', icon: 'laptop_windows' },
|
|
46654
|
+
{ value: 'tablet', label: 'Tablet', icon: 'tablet_mac' },
|
|
46655
|
+
{ value: 'mobile', label: 'Mobile', icon: 'smartphone' },
|
|
46656
|
+
];
|
|
46657
|
+
this.desktopViewportConfig = {
|
|
46658
|
+
key: 'viewportDesktopDevice',
|
|
46659
|
+
label: '',
|
|
46660
|
+
placeholder: 'Select resolution',
|
|
46661
|
+
searchable: true,
|
|
46662
|
+
options: [],
|
|
46663
|
+
};
|
|
46664
|
+
this.laptopViewportConfig = {
|
|
46665
|
+
key: 'viewportLaptopDevice',
|
|
46666
|
+
label: '',
|
|
46667
|
+
placeholder: 'Select resolution',
|
|
46668
|
+
searchable: true,
|
|
46669
|
+
options: [],
|
|
46670
|
+
};
|
|
46671
|
+
this.tabletViewportConfig = {
|
|
46672
|
+
key: 'viewportTabletDevice',
|
|
46673
|
+
label: '',
|
|
46674
|
+
placeholder: 'Select resolution',
|
|
46675
|
+
searchable: true,
|
|
46676
|
+
options: [],
|
|
46677
|
+
};
|
|
46678
|
+
this.mobileViewportConfig = {
|
|
46679
|
+
key: 'viewportMobileDevice',
|
|
46680
|
+
label: '',
|
|
46681
|
+
placeholder: 'Select device',
|
|
46682
|
+
searchable: true,
|
|
46683
|
+
options: [],
|
|
46684
|
+
};
|
|
46561
46685
|
this.frequentlyUsedLabels = FREQUENTLY_USED_LABELS;
|
|
46562
46686
|
this._initialFormSnapshot = null;
|
|
46563
46687
|
/** FormGroup for cqa-dynamic-select bindings */
|
|
@@ -46970,6 +47094,105 @@ class TestCaseDetailsEditComponent {
|
|
|
46970
47094
|
const section = [...this.configSections, ...this.configSectionsRow2].find((s) => s.title === 'Execution');
|
|
46971
47095
|
return !!section?.items?.some((i) => i.label === 'Prerequisite Case');
|
|
46972
47096
|
}
|
|
47097
|
+
initViewportFromValue(defaultViewport) {
|
|
47098
|
+
const vp = String(defaultViewport || '');
|
|
47099
|
+
this.customViewportWidth = '';
|
|
47100
|
+
this.customViewportHeight = '';
|
|
47101
|
+
this.customViewportTags = [];
|
|
47102
|
+
this.viewportDesktopDeviceForm.reset({ viewportDesktopDevice: '' });
|
|
47103
|
+
this.viewportLaptopDeviceForm.reset({ viewportLaptopDevice: '' });
|
|
47104
|
+
this.viewportTabletDeviceForm.reset({ viewportTabletDevice: '' });
|
|
47105
|
+
this.viewportMobileDeviceForm.reset({ viewportMobileDevice: '' });
|
|
47106
|
+
if (vp.startsWith('laptop:')) {
|
|
47107
|
+
this.viewportMode = 'laptop';
|
|
47108
|
+
this.viewportLaptopDeviceForm.patchValue({ viewportLaptopDevice: vp.slice(7).trim() });
|
|
47109
|
+
}
|
|
47110
|
+
else if (vp.startsWith('tablet:')) {
|
|
47111
|
+
this.viewportMode = 'tablet';
|
|
47112
|
+
this.viewportTabletDeviceForm.patchValue({ viewportTabletDevice: vp.slice(7).trim() });
|
|
47113
|
+
}
|
|
47114
|
+
else if (vp.startsWith('desktop:')) {
|
|
47115
|
+
this.viewportMode = 'desktop';
|
|
47116
|
+
this.viewportDesktopDeviceForm.patchValue({ viewportDesktopDevice: vp.slice(8).trim() });
|
|
47117
|
+
}
|
|
47118
|
+
else if (vp.startsWith('mobile:')) {
|
|
47119
|
+
this.viewportMode = 'mobile';
|
|
47120
|
+
this.viewportMobileDeviceForm.patchValue({ viewportMobileDevice: vp.slice(7).trim() });
|
|
47121
|
+
}
|
|
47122
|
+
else if (vp && vp.includes('*')) {
|
|
47123
|
+
this.viewportMode = 'custom';
|
|
47124
|
+
this.customViewportTags = vp.split(',').map((v) => v.trim()).filter(Boolean);
|
|
47125
|
+
}
|
|
47126
|
+
else {
|
|
47127
|
+
this.viewportMode = 'desktop';
|
|
47128
|
+
}
|
|
47129
|
+
}
|
|
47130
|
+
buildViewportValue() {
|
|
47131
|
+
if (this.viewportMode === 'laptop') {
|
|
47132
|
+
const res = (this.viewportLaptopDeviceForm.get('viewportLaptopDevice')?.value ?? '').trim();
|
|
47133
|
+
return res ? `laptop:${res}` : 'laptop:';
|
|
47134
|
+
}
|
|
47135
|
+
if (this.viewportMode === 'tablet') {
|
|
47136
|
+
const res = (this.viewportTabletDeviceForm.get('viewportTabletDevice')?.value ?? '').trim();
|
|
47137
|
+
return res ? `tablet:${res}` : 'tablet:';
|
|
47138
|
+
}
|
|
47139
|
+
if (this.viewportMode === 'mobile') {
|
|
47140
|
+
const device = (this.viewportMobileDeviceForm.get('viewportMobileDevice')?.value ?? '').trim();
|
|
47141
|
+
return device ? `mobile:${device}` : 'mobile:';
|
|
47142
|
+
}
|
|
47143
|
+
if (this.viewportMode === 'custom') {
|
|
47144
|
+
return this.customViewportTags.join(',');
|
|
47145
|
+
}
|
|
47146
|
+
// desktop
|
|
47147
|
+
const res = (this.viewportDesktopDeviceForm.get('viewportDesktopDevice')?.value ?? '').trim();
|
|
47148
|
+
return res ? `desktop:${res}` : '1280x720';
|
|
47149
|
+
}
|
|
47150
|
+
onViewportModeChange(mode) {
|
|
47151
|
+
this.viewportMode = mode;
|
|
47152
|
+
if (mode !== 'desktop')
|
|
47153
|
+
this.viewportDesktopDeviceForm.reset({ viewportDesktopDevice: '' });
|
|
47154
|
+
if (mode !== 'laptop')
|
|
47155
|
+
this.viewportLaptopDeviceForm.reset({ viewportLaptopDevice: '' });
|
|
47156
|
+
if (mode !== 'tablet')
|
|
47157
|
+
this.viewportTabletDeviceForm.reset({ viewportTabletDevice: '' });
|
|
47158
|
+
if (mode !== 'mobile')
|
|
47159
|
+
this.viewportMobileDeviceForm.reset({ viewportMobileDevice: '' });
|
|
47160
|
+
if (mode !== 'custom') {
|
|
47161
|
+
this.customViewportWidth = '';
|
|
47162
|
+
this.customViewportHeight = '';
|
|
47163
|
+
this.customViewportTags = [];
|
|
47164
|
+
}
|
|
47165
|
+
this.cdr.markForCheck();
|
|
47166
|
+
}
|
|
47167
|
+
applyViewportCategoryOptions() {
|
|
47168
|
+
const opts = this.viewportCategoryOptions || {};
|
|
47169
|
+
if (opts.DESKTOP)
|
|
47170
|
+
this.desktopViewportConfig = { ...this.desktopViewportConfig, options: opts.DESKTOP };
|
|
47171
|
+
if (opts.LAPTOP)
|
|
47172
|
+
this.laptopViewportConfig = { ...this.laptopViewportConfig, options: opts.LAPTOP };
|
|
47173
|
+
if (opts.TABLET)
|
|
47174
|
+
this.tabletViewportConfig = { ...this.tabletViewportConfig, options: opts.TABLET };
|
|
47175
|
+
if (opts.MOBILE)
|
|
47176
|
+
this.mobileViewportConfig = { ...this.mobileViewportConfig, options: opts.MOBILE };
|
|
47177
|
+
this.cdr.markForCheck();
|
|
47178
|
+
}
|
|
47179
|
+
addViewportCustomTag() {
|
|
47180
|
+
const w = (this.customViewportWidth || '').trim();
|
|
47181
|
+
const h = (this.customViewportHeight || '').trim();
|
|
47182
|
+
if (!w || !h)
|
|
47183
|
+
return;
|
|
47184
|
+
const tag = `${w}*${h}`;
|
|
47185
|
+
if (!this.customViewportTags.includes(tag)) {
|
|
47186
|
+
this.customViewportTags = [...this.customViewportTags, tag];
|
|
47187
|
+
}
|
|
47188
|
+
this.customViewportWidth = '';
|
|
47189
|
+
this.customViewportHeight = '';
|
|
47190
|
+
this.cdr.markForCheck();
|
|
47191
|
+
}
|
|
47192
|
+
removeViewportCustomTag(index) {
|
|
47193
|
+
this.customViewportTags = this.customViewportTags.filter((_, i) => i !== index);
|
|
47194
|
+
this.cdr.markForCheck();
|
|
47195
|
+
}
|
|
46973
47196
|
ngOnInit() {
|
|
46974
47197
|
this.editDescription = this.descriptionContent;
|
|
46975
47198
|
this.editStatus = this.statusItem?.value ?? '';
|
|
@@ -47005,6 +47228,7 @@ class TestCaseDetailsEditComponent {
|
|
|
47005
47228
|
const defaultViewport = this.getDeviceConfigValue('Default Viewport') || this.getDeviceConfigValue('Viewport') || '';
|
|
47006
47229
|
const deviceType = this.getConfigItemValue('Device', 'Type');
|
|
47007
47230
|
const deviceOS = this.getConfigItemValue('Device', 'OS');
|
|
47231
|
+
this.initViewportFromValue(defaultViewport);
|
|
47008
47232
|
this._labelsSelectConfigDirty = true;
|
|
47009
47233
|
this.editApiMockingRestoreMock = !!this.apiMockingRestoreMock;
|
|
47010
47234
|
this.editApiMockingStoreMock = !!this.apiMockingStoreMock;
|
|
@@ -47195,6 +47419,9 @@ class TestCaseDetailsEditComponent {
|
|
|
47195
47419
|
options: this.prerequisiteCaseOptions,
|
|
47196
47420
|
};
|
|
47197
47421
|
}
|
|
47422
|
+
if (changes['viewportCategoryOptions']) {
|
|
47423
|
+
this.applyViewportCategoryOptions();
|
|
47424
|
+
}
|
|
47198
47425
|
if (changes['configSections'] || changes['configSectionsRow2']) {
|
|
47199
47426
|
const enableAiSmartness = this.getConfigItemValue('AI Configuration', 'Enable AI Smartness');
|
|
47200
47427
|
const defaultAiAction = this.getConfigItemValue('AI Configuration', 'Default AI Action');
|
|
@@ -47215,6 +47442,7 @@ class TestCaseDetailsEditComponent {
|
|
|
47215
47442
|
const defaultViewport = this.getDeviceConfigValue('Default Viewport') || this.getDeviceConfigValue('Viewport') || '';
|
|
47216
47443
|
const deviceType = this.getConfigItemValue('Device', 'Type');
|
|
47217
47444
|
const deviceOS = this.getConfigItemValue('Device', 'OS');
|
|
47445
|
+
this.initViewportFromValue(defaultViewport);
|
|
47218
47446
|
const autoWaitVal = this.getWaitsRetriesValue('Enable Avoid Auto wait for steps') || this.getConfigItemValue('Waits & Retries', 'Auto Wait');
|
|
47219
47447
|
this.autoWaitEnabled = !!(autoWaitVal && autoWaitVal.trim() !== '' && String(autoWaitVal) !== 'false');
|
|
47220
47448
|
this.retryFailedSteps = this.getWaitsRetriesValue('Retry Failed Steps');
|
|
@@ -47342,7 +47570,7 @@ class TestCaseDetailsEditComponent {
|
|
|
47342
47570
|
mergeConfigSectionsRow2() {
|
|
47343
47571
|
const platform = this.platform;
|
|
47344
47572
|
const defaultBrowser = this.editForm.get('defaultBrowser')?.value ?? '';
|
|
47345
|
-
const defaultViewport = this.
|
|
47573
|
+
const defaultViewport = this.buildViewportValue();
|
|
47346
47574
|
const deviceType = this.editForm.get('deviceType')?.value ?? '';
|
|
47347
47575
|
const deviceOS = this.editForm.get('deviceOS')?.value ?? '';
|
|
47348
47576
|
let result = this.configSectionsRow2.map((section) => {
|
|
@@ -47443,10 +47671,10 @@ class TestCaseDetailsEditComponent {
|
|
|
47443
47671
|
}
|
|
47444
47672
|
}
|
|
47445
47673
|
TestCaseDetailsEditComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseDetailsEditComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
47446
|
-
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 });
|
|
47674
|
+
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 });
|
|
47447
47675
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseDetailsEditComponent, decorators: [{
|
|
47448
47676
|
type: Component,
|
|
47449
|
-
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" }]
|
|
47677
|
+
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" }]
|
|
47450
47678
|
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { descriptionTitle: [{
|
|
47451
47679
|
type: Input
|
|
47452
47680
|
}], descriptionContent: [{
|
|
@@ -47505,6 +47733,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
47505
47733
|
type: Input
|
|
47506
47734
|
}], orgLevelTestCaseTimeout: [{
|
|
47507
47735
|
type: Input
|
|
47736
|
+
}], viewportCategoryOptions: [{
|
|
47737
|
+
type: Input
|
|
47508
47738
|
}], save: [{
|
|
47509
47739
|
type: Output
|
|
47510
47740
|
}], cancel: [{
|
|
@@ -47584,6 +47814,8 @@ class TestCaseDetailsComponent {
|
|
|
47584
47814
|
/** Forwarded to `cqa-api-mocking-card` — gates the "Mocked / progress / percent" block. */
|
|
47585
47815
|
this.apiMockingShowProgress = false;
|
|
47586
47816
|
this.apiMockingConfigureButtonLabel = 'Configure';
|
|
47817
|
+
/** Viewport dropdown options per category from the API. Forwarded to edit mode. */
|
|
47818
|
+
this.viewportCategoryOptions = {};
|
|
47587
47819
|
/** Labels to filter out from metadata for step groups */
|
|
47588
47820
|
this.stepGroupExcludedMetadataLabels = ['priority', 'type'];
|
|
47589
47821
|
/** When true, description (view mode) is expanded; when false, clamped to 4 lines with Read more */
|
|
@@ -47696,10 +47928,10 @@ class TestCaseDetailsComponent {
|
|
|
47696
47928
|
}
|
|
47697
47929
|
}
|
|
47698
47930
|
TestCaseDetailsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseDetailsComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
47699
|
-
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 });
|
|
47931
|
+
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 });
|
|
47700
47932
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseDetailsComponent, decorators: [{
|
|
47701
47933
|
type: Component,
|
|
47702
|
-
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: [] }]
|
|
47934
|
+
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: [] }]
|
|
47703
47935
|
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { editing: [{
|
|
47704
47936
|
type: Input
|
|
47705
47937
|
}], startInEditMode: [{
|
|
@@ -47764,6 +47996,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
47764
47996
|
type: Input
|
|
47765
47997
|
}], orgLevelTestCaseTimeout: [{
|
|
47766
47998
|
type: Input
|
|
47999
|
+
}], viewportCategoryOptions: [{
|
|
48000
|
+
type: Input
|
|
47767
48001
|
}], editDescription: [{
|
|
47768
48002
|
type: Output
|
|
47769
48003
|
}], cancel: [{
|
|
@@ -50555,21 +50789,121 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
50555
50789
|
type: Output
|
|
50556
50790
|
}] } });
|
|
50557
50791
|
|
|
50558
|
-
|
|
50792
|
+
const DEFAULT_DESKTOP_MODE = 'desktop';
|
|
50793
|
+
class ViewportSelectorComponent {
|
|
50559
50794
|
constructor() {
|
|
50560
|
-
|
|
50561
|
-
this.
|
|
50562
|
-
/** When true, cards wrap to the next line (e.g. many platform targets). */
|
|
50563
|
-
this.wrap = false;
|
|
50795
|
+
this.label = 'Viewport';
|
|
50796
|
+
this.required = false;
|
|
50564
50797
|
this.disabled = false;
|
|
50565
|
-
|
|
50566
|
-
this.
|
|
50567
|
-
this.
|
|
50798
|
+
this.desktopLabel = 'Desktop';
|
|
50799
|
+
this.laptopLabel = 'Laptop';
|
|
50800
|
+
this.mobileLabel = 'Mobile';
|
|
50801
|
+
this.customLabel = 'Custom';
|
|
50802
|
+
this.desktopDeviceLabel = 'Resolution';
|
|
50803
|
+
this.desktopDevicePlaceholder = 'Select resolution';
|
|
50804
|
+
this.desktopDeviceOptions = [];
|
|
50805
|
+
this.laptopDeviceLabel = 'Resolution';
|
|
50806
|
+
this.laptopDevicePlaceholder = 'Select resolution';
|
|
50807
|
+
this.laptopDeviceOptions = [];
|
|
50808
|
+
this.mobileDeviceLabel = 'Device';
|
|
50809
|
+
this.mobileDevicePlaceholder = 'Select device';
|
|
50810
|
+
this.mobileDeviceOptions = [];
|
|
50811
|
+
this.customValueLabel = 'Custom viewport';
|
|
50812
|
+
this.customValuePlaceholder = 'Enter viewport value';
|
|
50813
|
+
this.customValueHint = 'Press Enter to add a viewport value like 1280x720';
|
|
50814
|
+
this.valueChange = new EventEmitter();
|
|
50815
|
+
this.modeOptions = [
|
|
50816
|
+
{ value: 'desktop', label: 'Desktop', icon: 'desktop_windows' },
|
|
50817
|
+
{ value: 'laptop', label: 'Laptop', icon: 'laptop_windows' },
|
|
50818
|
+
{ value: 'mobile', label: 'Mobile', icon: 'smartphone' },
|
|
50819
|
+
{ value: 'custom', label: 'Custom', icon: 'tune' },
|
|
50820
|
+
];
|
|
50821
|
+
this.desktopDeviceForm = new FormGroup({
|
|
50822
|
+
device: new FormControl(null),
|
|
50823
|
+
});
|
|
50824
|
+
this.laptopDeviceForm = new FormGroup({
|
|
50825
|
+
device: new FormControl(null),
|
|
50826
|
+
});
|
|
50827
|
+
this.mobileDeviceForm = new FormGroup({
|
|
50828
|
+
device: new FormControl(null),
|
|
50829
|
+
});
|
|
50830
|
+
this.desktopDeviceConfig = {
|
|
50831
|
+
key: 'device',
|
|
50832
|
+
label: '',
|
|
50833
|
+
placeholder: 'Select resolution',
|
|
50834
|
+
disabled: false,
|
|
50835
|
+
multiple: false,
|
|
50836
|
+
searchable: true,
|
|
50837
|
+
serverSearch: false,
|
|
50838
|
+
options: [],
|
|
50839
|
+
};
|
|
50840
|
+
this.laptopDeviceConfig = {
|
|
50841
|
+
key: 'device',
|
|
50842
|
+
label: '',
|
|
50843
|
+
placeholder: 'Select resolution',
|
|
50844
|
+
disabled: false,
|
|
50845
|
+
multiple: false,
|
|
50846
|
+
searchable: true,
|
|
50847
|
+
serverSearch: false,
|
|
50848
|
+
options: [],
|
|
50849
|
+
};
|
|
50850
|
+
this.mobileDeviceConfig = {
|
|
50851
|
+
key: 'device',
|
|
50852
|
+
label: '',
|
|
50853
|
+
placeholder: 'Select device',
|
|
50854
|
+
disabled: false,
|
|
50855
|
+
multiple: false,
|
|
50856
|
+
searchable: true,
|
|
50857
|
+
serverSearch: false,
|
|
50858
|
+
options: [],
|
|
50859
|
+
};
|
|
50860
|
+
this.customInputValue = '';
|
|
50861
|
+
this.internalValue = {
|
|
50862
|
+
mode: DEFAULT_DESKTOP_MODE,
|
|
50863
|
+
device: null,
|
|
50864
|
+
customValue: null,
|
|
50865
|
+
};
|
|
50568
50866
|
this.onChange = () => { };
|
|
50569
50867
|
this.onTouched = () => { };
|
|
50868
|
+
this.onValidatorChange = () => { };
|
|
50570
50869
|
}
|
|
50571
|
-
|
|
50572
|
-
|
|
50870
|
+
ngOnChanges(changes) {
|
|
50871
|
+
if (changes['desktopDeviceOptions']) {
|
|
50872
|
+
this.desktopDeviceConfig = { ...this.desktopDeviceConfig, options: this.desktopDeviceOptions || [] };
|
|
50873
|
+
}
|
|
50874
|
+
if (changes['laptopDeviceOptions']) {
|
|
50875
|
+
this.laptopDeviceConfig = { ...this.laptopDeviceConfig, options: this.laptopDeviceOptions || [] };
|
|
50876
|
+
}
|
|
50877
|
+
if (changes['mobileDeviceOptions']) {
|
|
50878
|
+
this.mobileDeviceConfig = { ...this.mobileDeviceConfig, options: this.mobileDeviceOptions || [] };
|
|
50879
|
+
}
|
|
50880
|
+
if (changes['desktopLabel'] || changes['laptopLabel'] || changes['mobileLabel'] || changes['customLabel']) {
|
|
50881
|
+
this.modeOptions[0].label = this.desktopLabel;
|
|
50882
|
+
this.modeOptions[1].label = this.laptopLabel;
|
|
50883
|
+
this.modeOptions[2].label = this.mobileLabel;
|
|
50884
|
+
this.modeOptions[3].label = this.customLabel;
|
|
50885
|
+
}
|
|
50886
|
+
if (changes['desktopDevicePlaceholder']) {
|
|
50887
|
+
this.desktopDeviceConfig = { ...this.desktopDeviceConfig, placeholder: this.desktopDevicePlaceholder };
|
|
50888
|
+
}
|
|
50889
|
+
if (changes['laptopDevicePlaceholder']) {
|
|
50890
|
+
this.laptopDeviceConfig = { ...this.laptopDeviceConfig, placeholder: this.laptopDevicePlaceholder };
|
|
50891
|
+
}
|
|
50892
|
+
if (changes['mobileDevicePlaceholder']) {
|
|
50893
|
+
this.mobileDeviceConfig = { ...this.mobileDeviceConfig, placeholder: this.mobileDevicePlaceholder };
|
|
50894
|
+
}
|
|
50895
|
+
if (changes['disabled']) {
|
|
50896
|
+
this.setDisabledState(this.disabled);
|
|
50897
|
+
}
|
|
50898
|
+
}
|
|
50899
|
+
writeValue(value) {
|
|
50900
|
+
this.internalValue = this.normalizeValue(value);
|
|
50901
|
+
const device = this.internalValue.device ?? null;
|
|
50902
|
+
const mode = this.internalValue.mode;
|
|
50903
|
+
this.desktopDeviceForm.get('device')?.setValue(mode === 'desktop' ? device : null, { emitEvent: false });
|
|
50904
|
+
this.laptopDeviceForm.get('device')?.setValue(mode === 'laptop' ? device : null, { emitEvent: false });
|
|
50905
|
+
this.mobileDeviceForm.get('device')?.setValue(mode === 'mobile' ? device : null, { emitEvent: false });
|
|
50906
|
+
this.customInputValue = '';
|
|
50573
50907
|
}
|
|
50574
50908
|
registerOnChange(fn) {
|
|
50575
50909
|
this.onChange = fn;
|
|
@@ -50577,50 +50911,221 @@ class RadioCardGroupComponent {
|
|
|
50577
50911
|
registerOnTouched(fn) {
|
|
50578
50912
|
this.onTouched = fn;
|
|
50579
50913
|
}
|
|
50914
|
+
registerOnValidatorChange(fn) {
|
|
50915
|
+
this.onValidatorChange = fn;
|
|
50916
|
+
}
|
|
50580
50917
|
setDisabledState(isDisabled) {
|
|
50581
50918
|
this.disabled = isDisabled;
|
|
50919
|
+
const config = { disabled: isDisabled };
|
|
50920
|
+
this.desktopDeviceConfig = { ...this.desktopDeviceConfig, ...config };
|
|
50921
|
+
this.laptopDeviceConfig = { ...this.laptopDeviceConfig, ...config };
|
|
50922
|
+
this.mobileDeviceConfig = { ...this.mobileDeviceConfig, ...config };
|
|
50923
|
+
if (isDisabled) {
|
|
50924
|
+
this.desktopDeviceForm.disable({ emitEvent: false });
|
|
50925
|
+
this.laptopDeviceForm.disable({ emitEvent: false });
|
|
50926
|
+
this.mobileDeviceForm.disable({ emitEvent: false });
|
|
50927
|
+
}
|
|
50928
|
+
else {
|
|
50929
|
+
this.desktopDeviceForm.enable({ emitEvent: false });
|
|
50930
|
+
this.laptopDeviceForm.enable({ emitEvent: false });
|
|
50931
|
+
this.mobileDeviceForm.enable({ emitEvent: false });
|
|
50932
|
+
}
|
|
50582
50933
|
}
|
|
50583
|
-
|
|
50584
|
-
|
|
50934
|
+
validate(_control) {
|
|
50935
|
+
if (this.internalValue.mode === 'mobile' && !this.internalValue.device) {
|
|
50936
|
+
return { viewportSelection: { requiredDevice: true } };
|
|
50937
|
+
}
|
|
50938
|
+
if (this.internalValue.mode === 'custom' && !this.internalValue.customValue) {
|
|
50939
|
+
return { viewportSelection: { requiredCustomValue: true } };
|
|
50940
|
+
}
|
|
50941
|
+
return null;
|
|
50585
50942
|
}
|
|
50586
|
-
get
|
|
50587
|
-
return
|
|
50943
|
+
get isDesktopMode() {
|
|
50944
|
+
return this.internalValue.mode === 'desktop';
|
|
50588
50945
|
}
|
|
50589
|
-
|
|
50946
|
+
get isLaptopMode() {
|
|
50947
|
+
return this.internalValue.mode === 'laptop';
|
|
50948
|
+
}
|
|
50949
|
+
get isMobileMode() {
|
|
50950
|
+
return this.internalValue.mode === 'mobile';
|
|
50951
|
+
}
|
|
50952
|
+
get isCustomMode() {
|
|
50953
|
+
return this.internalValue.mode === 'custom';
|
|
50954
|
+
}
|
|
50955
|
+
onModeChange(mode) {
|
|
50590
50956
|
if (this.disabled) {
|
|
50591
50957
|
return;
|
|
50592
50958
|
}
|
|
50593
|
-
const
|
|
50594
|
-
|
|
50595
|
-
this.
|
|
50959
|
+
const nextMode = this.isValidMode(mode) ? mode : DEFAULT_DESKTOP_MODE;
|
|
50960
|
+
const currentDevice = this.internalValue.device;
|
|
50961
|
+
this.internalValue = {
|
|
50962
|
+
mode: nextMode,
|
|
50963
|
+
device: (nextMode === 'desktop' || nextMode === 'laptop' || nextMode === 'mobile') ? (currentDevice ?? null) : null,
|
|
50964
|
+
customValue: nextMode === 'custom' ? (this.internalValue.customValue ?? null) : null,
|
|
50965
|
+
};
|
|
50966
|
+
// Reset device forms; only populate the matching mode's form
|
|
50967
|
+
const deviceValue = this.internalValue.device ?? null;
|
|
50968
|
+
this.desktopDeviceForm.get('device')?.setValue(nextMode === 'desktop' ? deviceValue : null, { emitEvent: false });
|
|
50969
|
+
this.laptopDeviceForm.get('device')?.setValue(nextMode === 'laptop' ? deviceValue : null, { emitEvent: false });
|
|
50970
|
+
this.mobileDeviceForm.get('device')?.setValue(nextMode === 'mobile' ? deviceValue : null, { emitEvent: false });
|
|
50971
|
+
this.emitValue();
|
|
50972
|
+
}
|
|
50973
|
+
onDesktopSelectionChange(selection) {
|
|
50974
|
+
if (this.disabled)
|
|
50975
|
+
return;
|
|
50976
|
+
this.internalValue = {
|
|
50977
|
+
...this.internalValue,
|
|
50978
|
+
mode: 'desktop',
|
|
50979
|
+
device: selection?.value != null && selection.value !== '' ? String(selection.value) : null,
|
|
50980
|
+
customValue: null,
|
|
50981
|
+
};
|
|
50982
|
+
this.emitValue();
|
|
50983
|
+
}
|
|
50984
|
+
onLaptopSelectionChange(selection) {
|
|
50985
|
+
if (this.disabled)
|
|
50986
|
+
return;
|
|
50987
|
+
this.internalValue = {
|
|
50988
|
+
...this.internalValue,
|
|
50989
|
+
mode: 'laptop',
|
|
50990
|
+
device: selection?.value != null && selection.value !== '' ? String(selection.value) : null,
|
|
50991
|
+
customValue: null,
|
|
50992
|
+
};
|
|
50993
|
+
this.emitValue();
|
|
50994
|
+
}
|
|
50995
|
+
onMobileSelectionChange(selection) {
|
|
50996
|
+
if (this.disabled) {
|
|
50997
|
+
return;
|
|
50998
|
+
}
|
|
50999
|
+
this.internalValue = {
|
|
51000
|
+
...this.internalValue,
|
|
51001
|
+
mode: 'mobile',
|
|
51002
|
+
device: selection?.value != null && selection.value !== '' ? String(selection.value) : null,
|
|
51003
|
+
customValue: null,
|
|
51004
|
+
};
|
|
51005
|
+
this.emitValue();
|
|
51006
|
+
}
|
|
51007
|
+
addCustomValue(rawValue) {
|
|
51008
|
+
if (this.disabled) {
|
|
51009
|
+
return;
|
|
51010
|
+
}
|
|
51011
|
+
const nextValue = this.normalizeCustomValue(rawValue ?? this.customInputValue);
|
|
51012
|
+
if (!nextValue) {
|
|
51013
|
+
return;
|
|
51014
|
+
}
|
|
51015
|
+
this.internalValue = {
|
|
51016
|
+
...this.internalValue,
|
|
51017
|
+
mode: 'custom',
|
|
51018
|
+
device: null,
|
|
51019
|
+
customValue: nextValue,
|
|
51020
|
+
};
|
|
51021
|
+
this.customInputValue = '';
|
|
51022
|
+
this.emitValue();
|
|
51023
|
+
}
|
|
51024
|
+
clearCustomValue() {
|
|
51025
|
+
if (this.disabled) {
|
|
51026
|
+
return;
|
|
51027
|
+
}
|
|
51028
|
+
this.internalValue = {
|
|
51029
|
+
...this.internalValue,
|
|
51030
|
+
customValue: null,
|
|
51031
|
+
};
|
|
51032
|
+
this.emitValue();
|
|
51033
|
+
}
|
|
51034
|
+
emitValue() {
|
|
51035
|
+
const normalized = this.normalizeValue(this.internalValue);
|
|
51036
|
+
this.internalValue = normalized;
|
|
50596
51037
|
this.onTouched();
|
|
50597
|
-
this.
|
|
51038
|
+
this.onChange(normalized);
|
|
51039
|
+
this.onValidatorChange();
|
|
51040
|
+
this.valueChange.emit(normalized);
|
|
51041
|
+
}
|
|
51042
|
+
normalizeValue(value) {
|
|
51043
|
+
const mode = this.isValidMode(value?.mode) ? value.mode : DEFAULT_DESKTOP_MODE;
|
|
51044
|
+
const device = value?.device != null && String(value.device).trim() !== '' ? String(value.device).trim() : null;
|
|
51045
|
+
const customValue = this.normalizeCustomValue(value?.customValue ?? null);
|
|
51046
|
+
return {
|
|
51047
|
+
mode,
|
|
51048
|
+
device: (mode === 'desktop' || mode === 'laptop' || mode === 'mobile') ? device : null,
|
|
51049
|
+
customValue: mode === 'custom' ? customValue : null,
|
|
51050
|
+
};
|
|
51051
|
+
}
|
|
51052
|
+
normalizeCustomValue(value) {
|
|
51053
|
+
if (value == null) {
|
|
51054
|
+
return null;
|
|
51055
|
+
}
|
|
51056
|
+
const normalized = String(value).trim();
|
|
51057
|
+
return normalized ? normalized : null;
|
|
51058
|
+
}
|
|
51059
|
+
isValidMode(mode) {
|
|
51060
|
+
return mode === 'desktop' || mode === 'laptop' || mode === 'mobile' || mode === 'custom';
|
|
50598
51061
|
}
|
|
50599
51062
|
}
|
|
50600
|
-
|
|
50601
|
-
|
|
51063
|
+
ViewportSelectorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ViewportSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
51064
|
+
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: [
|
|
50602
51065
|
{
|
|
50603
51066
|
provide: NG_VALUE_ACCESSOR,
|
|
50604
|
-
useExisting: forwardRef(() =>
|
|
50605
|
-
multi: true
|
|
50606
|
-
}
|
|
50607
|
-
|
|
50608
|
-
|
|
51067
|
+
useExisting: forwardRef(() => ViewportSelectorComponent),
|
|
51068
|
+
multi: true,
|
|
51069
|
+
},
|
|
51070
|
+
{
|
|
51071
|
+
provide: NG_VALIDATORS,
|
|
51072
|
+
useExisting: forwardRef(() => ViewportSelectorComponent),
|
|
51073
|
+
multi: true,
|
|
51074
|
+
},
|
|
51075
|
+
], 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"] }] });
|
|
51076
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ViewportSelectorComponent, decorators: [{
|
|
50609
51077
|
type: Component,
|
|
50610
|
-
args: [{ selector: 'cqa-
|
|
51078
|
+
args: [{ selector: 'cqa-viewport-selector', host: { class: 'cqa-ui-root cqa-block' }, providers: [
|
|
50611
51079
|
{
|
|
50612
51080
|
provide: NG_VALUE_ACCESSOR,
|
|
50613
|
-
useExisting: forwardRef(() =>
|
|
50614
|
-
multi: true
|
|
50615
|
-
}
|
|
50616
|
-
|
|
50617
|
-
|
|
51081
|
+
useExisting: forwardRef(() => ViewportSelectorComponent),
|
|
51082
|
+
multi: true,
|
|
51083
|
+
},
|
|
51084
|
+
{
|
|
51085
|
+
provide: NG_VALIDATORS,
|
|
51086
|
+
useExisting: forwardRef(() => ViewportSelectorComponent),
|
|
51087
|
+
multi: true,
|
|
51088
|
+
},
|
|
51089
|
+
], 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: [] }]
|
|
51090
|
+
}], propDecorators: { label: [{
|
|
50618
51091
|
type: Input
|
|
50619
|
-
}],
|
|
51092
|
+
}], required: [{
|
|
50620
51093
|
type: Input
|
|
50621
51094
|
}], disabled: [{
|
|
50622
51095
|
type: Input
|
|
50623
|
-
}],
|
|
51096
|
+
}], desktopLabel: [{
|
|
51097
|
+
type: Input
|
|
51098
|
+
}], laptopLabel: [{
|
|
51099
|
+
type: Input
|
|
51100
|
+
}], mobileLabel: [{
|
|
51101
|
+
type: Input
|
|
51102
|
+
}], customLabel: [{
|
|
51103
|
+
type: Input
|
|
51104
|
+
}], desktopDeviceLabel: [{
|
|
51105
|
+
type: Input
|
|
51106
|
+
}], desktopDevicePlaceholder: [{
|
|
51107
|
+
type: Input
|
|
51108
|
+
}], desktopDeviceOptions: [{
|
|
51109
|
+
type: Input
|
|
51110
|
+
}], laptopDeviceLabel: [{
|
|
51111
|
+
type: Input
|
|
51112
|
+
}], laptopDevicePlaceholder: [{
|
|
51113
|
+
type: Input
|
|
51114
|
+
}], laptopDeviceOptions: [{
|
|
51115
|
+
type: Input
|
|
51116
|
+
}], mobileDeviceLabel: [{
|
|
51117
|
+
type: Input
|
|
51118
|
+
}], mobileDevicePlaceholder: [{
|
|
51119
|
+
type: Input
|
|
51120
|
+
}], mobileDeviceOptions: [{
|
|
51121
|
+
type: Input
|
|
51122
|
+
}], customValueLabel: [{
|
|
51123
|
+
type: Input
|
|
51124
|
+
}], customValuePlaceholder: [{
|
|
51125
|
+
type: Input
|
|
51126
|
+
}], customValueHint: [{
|
|
51127
|
+
type: Input
|
|
51128
|
+
}], valueChange: [{
|
|
50624
51129
|
type: Output
|
|
50625
51130
|
}] } });
|
|
50626
51131
|
|
|
@@ -52249,6 +52754,7 @@ UiKitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "1
|
|
|
52249
52754
|
SegmentControlComponent,
|
|
52250
52755
|
StepperComponent,
|
|
52251
52756
|
RadioCardGroupComponent,
|
|
52757
|
+
ViewportSelectorComponent,
|
|
52252
52758
|
DialogComponent,
|
|
52253
52759
|
DynamicTableComponent,
|
|
52254
52760
|
DynamicCellTemplateDirective,
|
|
@@ -52444,6 +52950,7 @@ UiKitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "1
|
|
|
52444
52950
|
SegmentControlComponent,
|
|
52445
52951
|
StepperComponent,
|
|
52446
52952
|
RadioCardGroupComponent,
|
|
52953
|
+
ViewportSelectorComponent,
|
|
52447
52954
|
DialogComponent,
|
|
52448
52955
|
DynamicTableComponent,
|
|
52449
52956
|
DynamicCellTemplateDirective,
|
|
@@ -52684,6 +53191,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
52684
53191
|
SegmentControlComponent,
|
|
52685
53192
|
StepperComponent,
|
|
52686
53193
|
RadioCardGroupComponent,
|
|
53194
|
+
ViewportSelectorComponent,
|
|
52687
53195
|
DialogComponent,
|
|
52688
53196
|
DynamicTableComponent,
|
|
52689
53197
|
DynamicCellTemplateDirective,
|
|
@@ -52885,6 +53393,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
52885
53393
|
SegmentControlComponent,
|
|
52886
53394
|
StepperComponent,
|
|
52887
53395
|
RadioCardGroupComponent,
|
|
53396
|
+
ViewportSelectorComponent,
|
|
52888
53397
|
DialogComponent,
|
|
52889
53398
|
DynamicTableComponent,
|
|
52890
53399
|
DynamicCellTemplateDirective,
|
|
@@ -53763,5 +54272,5 @@ function buildTestCaseDetailsFromApi(data, options) {
|
|
|
53763
54272
|
* Generated bundle index. Do not edit.
|
|
53764
54273
|
*/
|
|
53765
54274
|
|
|
53766
|
-
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 };
|
|
54275
|
+
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 };
|
|
53767
54276
|
//# sourceMappingURL=cqa-lib-cqa-ui.mjs.map
|