@cqa-lib/cqa-ui 1.1.557 → 1.1.558

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/esm2020/lib/sidebar/nav-item.component.mjs +171 -0
  2. package/esm2020/lib/sidebar/nav-menu.component.mjs +56 -0
  3. package/esm2020/lib/sidebar/nav-sub-item.component.mjs +27 -0
  4. package/esm2020/lib/sidebar/profile-menu/profile-menu.component.mjs +122 -0
  5. package/esm2020/lib/sidebar/profile-menu/profile-menu.models.mjs +4 -0
  6. package/esm2020/lib/sidebar/sidebar.component.mjs +286 -0
  7. package/esm2020/lib/sidebar/sidebar.models.mjs +5 -0
  8. package/esm2020/lib/sidebar/workspace-menu/workspace-menu.component.mjs +120 -0
  9. package/esm2020/lib/sidebar/workspace-menu/workspace-menu.models.mjs +2 -0
  10. package/esm2020/lib/templates/modular-table-template/modular-table-template.component.mjs +3 -3
  11. package/esm2020/lib/ui-kit.module.mjs +31 -1
  12. package/esm2020/lib/utils/tw-overlay-container.mjs +3 -1
  13. package/esm2020/public-api.mjs +10 -1
  14. package/fesm2015/cqa-lib-cqa-ui.mjs +818 -20
  15. package/fesm2015/cqa-lib-cqa-ui.mjs.map +1 -1
  16. package/fesm2020/cqa-lib-cqa-ui.mjs +801 -20
  17. package/fesm2020/cqa-lib-cqa-ui.mjs.map +1 -1
  18. package/lib/sidebar/nav-item.component.d.ts +48 -0
  19. package/lib/sidebar/nav-menu.component.d.ts +19 -0
  20. package/lib/sidebar/nav-sub-item.component.d.ts +11 -0
  21. package/lib/sidebar/profile-menu/profile-menu.component.d.ts +35 -0
  22. package/lib/sidebar/profile-menu/profile-menu.models.d.ts +35 -0
  23. package/lib/sidebar/sidebar.component.d.ts +97 -0
  24. package/lib/sidebar/sidebar.models.d.ts +63 -0
  25. package/lib/sidebar/workspace-menu/workspace-menu.component.d.ts +34 -0
  26. package/lib/sidebar/workspace-menu/workspace-menu.models.d.ts +12 -0
  27. package/lib/ui-kit.module.d.ts +164 -158
  28. package/package.json +1 -1
  29. package/public-api.d.ts +9 -0
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, Component, Input, Output, HostListener, HostBinding, ViewChildren, ViewChild, ChangeDetectionStrategy, Directive, TemplateRef, ContentChildren, ContentChild, ElementRef, forwardRef, Optional, Inject, InjectionToken, Injector, Injectable, ChangeDetectorRef, SimpleChange, ViewContainerRef, Pipe, NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
2
+ import { EventEmitter, Component, Input, Output, HostListener, HostBinding, ViewChildren, ViewChild, ChangeDetectionStrategy, Directive, TemplateRef, ContentChildren, ContentChild, ElementRef, forwardRef, Optional, Inject, InjectionToken, Injector, Injectable, Pipe, ChangeDetectorRef, SimpleChange, ViewContainerRef, NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
3
3
  import * as i2 from '@angular/common';
4
4
  import { CommonModule } from '@angular/common';
5
5
  import * as i1$1 from '@angular/forms';
@@ -11222,10 +11222,10 @@ class ModularTableTemplateComponent {
11222
11222
  }
11223
11223
  ModularTableTemplateComponent.GRID_SCROLL_LOAD_THRESHOLD_PX = 96;
11224
11224
  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 });
11225
- 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", subfolderSectionExpanded: "subfolderSectionExpanded", organizedSectionExpanded: "organizedSectionExpanded", serverSideSearch: "serverSideSearch", rootTotal: "rootTotal", folderSearchLoading: "folderSearchLoading", folderSearchValue: "folderSearchValue", rootFoldersLoading: "rootFoldersLoading", savingFolderIds: "savingFolderIds", 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", subfolderSectionExpandedChange: "subfolderSectionExpandedChange", organizedSectionExpandedChange: "organizedSectionExpandedChange", 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-flex-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 indeterminate loading spinner. Render via\n <ng-container *ngTemplateOutlet=\"loadingSpinner; context: { size: 20 }\"></ng-container>. -->\n<ng-template #loadingSpinner let-size=\"size\">\n <svg [attr.width]=\"size || 20\" [attr.height]=\"size || 20\" viewBox=\"0 0 50 50\" aria-label=\"loading\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"25\" cy=\"25\" r=\"20\" stroke=\"#E5E7EB\" stroke-width=\"6\" fill=\"none\"></circle>\n <path d=\"M45 25a20 20 0 0 0-20-20\" stroke=\"#4F46E5\" stroke-width=\"6\" fill=\"none\" stroke-linecap=\"round\">\n <animateTransform attributeName=\"transform\" type=\"rotate\" from=\"0 25 25\" to=\"360 25 25\" dur=\"0.8s\" repeatCount=\"indefinite\"></animateTransform>\n </path>\n </svg>\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-flex-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-2 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 [allowDuplicate]=\"modularConfig.allowDuplicateFolder\"\n [showCounts]=\"modularConfig.showCounts\"\n [collapsed]=\"sidebarCollapsed\"\n [labels]=\"modularLabels\"\n [serverSideSearch]=\"serverSideSearch\"\n [rootTotal]=\"rootTotal\"\n [folderSearchLoading]=\"folderSearchLoading\"\n [rootFoldersLoading]=\"rootFoldersLoading\"\n [savingFolderIds]=\"savingFolderIds\"\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-2 cqa-text-sm cqa-px-3 cqa-py-2 cqa-rounded-none cqa-min-w-0\"\n style=\"color: #6D6D74; border-bottom: 1px solid #E2E2E3;\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-1 cqa-flex-1 cqa-min-w-0 cqa-overflow-x-auto cqa-scrollbar-thin cqa-whitespace-nowrap\">\n <button type=\"button\" class=\"hover:cqa-text-[#3F43EE] cqa-inline-flex cqa-items-center cqa-gap-1 cqa-flex-shrink-0\" (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 cqa-flex-shrink-0\" style=\"font-size:16px;width:16px;height:16px;color:#6D6D74;\">chevron_right</mat-icon>\n <button\n type=\"button\"\n class=\"cqa-flex-shrink-0\"\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 </div>\n <cqa-button\n *ngIf=\"modularConfig.showSubfolderSection && subfolderTiles.length\"\n class=\"cqa-flex-shrink-0\"\n variant=\"text\"\n btnSize=\"sm\"\n customClass=\"!cqa-text-[13px] !cqa-leading-[18px]\"\n [icon]=\"subfolderSectionExpanded ? 'expand_less' : 'expand_more'\"\n [text]=\"(subfolderSectionExpanded ? 'Hide' : 'Show') + ' subfolders'\"\n [attr.aria-expanded]=\"subfolderSectionExpanded\"\n (clicked)=\"toggleSubfolderSection()\"\n ></cqa-button>\n <cqa-button\n *ngIf=\"modularConfig.allowCreateFolder\"\n class=\"cqa-flex-shrink-0\"\n variant=\"text\"\n btnSize=\"sm\"\n customClass=\"!cqa-text-[13px] !cqa-leading-[18px]\"\n icon=\"add\"\n [text]=\"modularLabels.newFolder\"\n (clicked)=\"onFolderCreateRequested({ parentId: selectedFolderId })\"\n ></cqa-button>\n </nav>\n\n <!-- Folder grid: modular + root view -->\n <section\n *ngIf=\"isModularView && isRootView && modularConfig.showFolderGrid && rootFolderTiles.length\"\n class=\"cqa-px-5 cqa-pt-2\"\n style=\"border-bottom: 1px solid #F0F0F1;\"\n >\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2 cqa-w-full cqa-text-left\"\n [attr.aria-expanded]=\"organizedSectionExpanded\"\n (click)=\"toggleOrganizedSection()\"\n >\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 <mat-icon class=\"cqa-text-[#6D6D74] cqa-ml-auto\" style=\"font-size:18px;width:18px;height:18px\">\n {{ organizedSectionExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div\n class=\"cqa-grid\"\n style=\"transition: grid-template-rows 300ms cubic-bezier(0.4, 0, 0.2, 1);\"\n [style.grid-template-rows]=\"organizedSectionExpanded ? '1fr' : '0fr'\"\n >\n <div class=\"cqa-min-h-0\" style=\"overflow: hidden;\">\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-1\"\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-flex-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-flex-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-flex-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-flex-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 <ng-container *ngTemplateOutlet=\"loadingSpinner; context: { size: 20 }\"></ng-container>\n </div>\n </div>\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-grid\"\n style=\"transition: grid-template-rows 300ms cubic-bezier(0.4, 0, 0.2, 1);\"\n [style.grid-template-rows]=\"subfolderSectionExpanded ? '1fr' : '0fr'\"\n >\n <div class=\"cqa-min-h-0\" style=\"overflow: hidden;\">\n <div class=\"cqa-px-3 cqa-py-2 cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin\"\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-flex-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-flex-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-flex-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-flex-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 <ng-container *ngTemplateOutlet=\"loadingSpinner; context: { size: 20 }\"></ng-container>\n </div>\n </div>\n </div>\n </section>\n\n <div\n *ngIf=\"isModularView && !isRootView && modularConfig.showUnorganizedSection\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-px-4 cqa-py-3 cqa-border cqa-border-indigo-100\"\n style=\"background-color: #D8D9FC;\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9585 10.4585C12.9585 10.79 12.8268 11.108 12.5924 11.3424C12.358 11.5768 12.04 11.7085 11.7085 11.7085H1.7085C1.37698 11.7085 1.05903 11.5768 0.824613 11.3424C0.590192 11.108 0.458496 10.79 0.458496 10.4585V1.7085C0.458496 1.37698 0.590192 1.05903 0.824613 0.824613C1.05903 0.590192 1.37698 0.458496 1.7085 0.458496H4.8335L6.0835 2.3335H11.7085C12.04 2.3335 12.358 2.46519 12.5924 2.69961C12.8268 2.93403 12.9585 3.25198 12.9585 3.5835V10.4585Z\" stroke=\"#3F43EE\" stroke-width=\"0.916667\"/>\n </svg>\n <span class=\"cqa-text-sm cqa-font-semibold\" style=\"color: #3F43EE;\">\n {{ currentFolderNode?.name }} ({{ currentFolderDirectCount }})\n </span>\n </div>\n <cqa-button\n variant=\"outlined\"\n btnSize=\"sm\"\n customClass=\"!cqa-text-[13px]\"\n inlineStyles=\"border-color: #3F43EE; color: #3F43EE;\"\n [text]=\"modularLabels.clearFilter\"\n (clicked)=\"onFolderSelected(null)\"\n ></cqa-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 <div class=\"cqa-overflow-hidden cqa-border-t cqa-border-l cqa-border-r cqa-border-grey-200 cqa-relative cqa-overflow-x-auto\"\n [class.cqa-modular-table-flush]=\"isModularView\"\n [attr.style]=\"(!isModularView ? 'border-radius: 7px;' : '') + ((pagedRows && pagedRows.length > 0) ? '' : ' 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", "foldersAccordionExpanded", "labels", "serverSideSearch", "rootTotal", "folderSearchLoading", "rootFoldersLoading", "savingFolderIds", "searchValue"], outputs: ["folderSelected", "folderExpansionToggled", "folderChildrenRequested", "folderLoadMoreRequested", "searchChange", "rootLoadMoreRequested", "folderCreated", "folderCreateRequested", "folderRenamed", "folderDeleted", "folderMoveRequested", "folderDuplicateRequested", "testsDropped", "folderDropped", "collapsedChange", "foldersAccordionExpandedChange"] }, { type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: DynamicTableComponent, selector: "app-dynamic-table", inputs: ["data", "columns", "emptyState", "gridTemplateColumns", "screenWidth", "enableSelectAll", "rowSelectable", "enableLocalSort", "isTableLoading", "isTableDataLoading", "cellJsonPathGetter", "onJsonPathCopiedHandler", "enableRowReorder", "reorderHandleTooltip"], outputs: ["sortChange", "rowReorder"] }, { type: EmptyStateComponent, selector: "cqa-empty-state", inputs: ["preset", "imageUrl", "title", "description", "actions"], outputs: ["actionClick"] }, { type: PaginationComponent, selector: "cqa-pagination", inputs: ["totalElements", "totalPages", "pageIndex", "pageSize", "pageItemCount", "pageSizeOptions", "pageSizeMenuDirection"], outputs: ["pageIndexChange", "pageSizeChange", "paginate"] }, { type: TableActionToolbarComponent, selector: "cqa-table-action-toolbar", inputs: ["selectedItems", "actions", "showSelectAll", "allSelected", "showDismiss"], outputs: ["actionClick", "selectAllChange", "dismiss"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: FolderDropDirective, selector: "[cqaFolderDrop]", inputs: ["cqaFolderDrop", "dropEnabled"], outputs: ["testsDropped", "folderDropped"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
11225
+ 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", subfolderSectionExpanded: "subfolderSectionExpanded", organizedSectionExpanded: "organizedSectionExpanded", serverSideSearch: "serverSideSearch", rootTotal: "rootTotal", folderSearchLoading: "folderSearchLoading", folderSearchValue: "folderSearchValue", rootFoldersLoading: "rootFoldersLoading", savingFolderIds: "savingFolderIds", 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", subfolderSectionExpandedChange: "subfolderSectionExpandedChange", organizedSectionExpandedChange: "organizedSectionExpandedChange", 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-flex-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 indeterminate loading spinner. Render via\n <ng-container *ngTemplateOutlet=\"loadingSpinner; context: { size: 20 }\"></ng-container>. -->\n<ng-template #loadingSpinner let-size=\"size\">\n <svg [attr.width]=\"size || 20\" [attr.height]=\"size || 20\" viewBox=\"0 0 50 50\" aria-label=\"loading\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"25\" cy=\"25\" r=\"20\" stroke=\"#E5E7EB\" stroke-width=\"6\" fill=\"none\"></circle>\n <path d=\"M45 25a20 20 0 0 0-20-20\" stroke=\"#4F46E5\" stroke-width=\"6\" fill=\"none\" stroke-linecap=\"round\">\n <animateTransform attributeName=\"transform\" type=\"rotate\" from=\"0 25 25\" to=\"360 25 25\" dur=\"0.8s\" repeatCount=\"indefinite\"></animateTransform>\n </path>\n </svg>\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-flex-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-max-w-full cqa-flex cqa-flex-col cqa-relative cqa-min-w-0\">\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-2 cqa-min-h-0 cqa-min-w-0 cqa-w-full cqa-max-w-full cqa-overflow-hidden\" 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 [allowDuplicate]=\"modularConfig.allowDuplicateFolder\"\n [showCounts]=\"modularConfig.showCounts\"\n [collapsed]=\"sidebarCollapsed\"\n [labels]=\"modularLabels\"\n [serverSideSearch]=\"serverSideSearch\"\n [rootTotal]=\"rootTotal\"\n [folderSearchLoading]=\"folderSearchLoading\"\n [rootFoldersLoading]=\"rootFoldersLoading\"\n [savingFolderIds]=\"savingFolderIds\"\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-2 cqa-text-sm cqa-px-3 cqa-py-2 cqa-rounded-none cqa-min-w-0\"\n style=\"color: #6D6D74; border-bottom: 1px solid #E2E2E3;\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-1 cqa-flex-1 cqa-min-w-0 cqa-overflow-x-auto cqa-scrollbar-thin cqa-whitespace-nowrap\">\n <button type=\"button\" class=\"hover:cqa-text-[#3F43EE] cqa-inline-flex cqa-items-center cqa-gap-1 cqa-flex-shrink-0\" (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 cqa-flex-shrink-0\" style=\"font-size:16px;width:16px;height:16px;color:#6D6D74;\">chevron_right</mat-icon>\n <button\n type=\"button\"\n class=\"cqa-flex-shrink-0\"\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 </div>\n <cqa-button\n *ngIf=\"modularConfig.showSubfolderSection && subfolderTiles.length\"\n class=\"cqa-flex-shrink-0\"\n variant=\"text\"\n btnSize=\"sm\"\n customClass=\"!cqa-text-[13px] !cqa-leading-[18px]\"\n [icon]=\"subfolderSectionExpanded ? 'expand_less' : 'expand_more'\"\n [text]=\"(subfolderSectionExpanded ? 'Hide' : 'Show') + ' subfolders'\"\n [attr.aria-expanded]=\"subfolderSectionExpanded\"\n (clicked)=\"toggleSubfolderSection()\"\n ></cqa-button>\n <cqa-button\n *ngIf=\"modularConfig.allowCreateFolder\"\n class=\"cqa-flex-shrink-0\"\n variant=\"text\"\n btnSize=\"sm\"\n customClass=\"!cqa-text-[13px] !cqa-leading-[18px]\"\n icon=\"add\"\n [text]=\"modularLabels.newFolder\"\n (clicked)=\"onFolderCreateRequested({ parentId: selectedFolderId })\"\n ></cqa-button>\n </nav>\n\n <!-- Folder grid: modular + root view -->\n <section\n *ngIf=\"isModularView && isRootView && modularConfig.showFolderGrid && rootFolderTiles.length\"\n class=\"cqa-px-5 cqa-pt-2\"\n style=\"border-bottom: 1px solid #F0F0F1;\"\n >\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2 cqa-w-full cqa-text-left\"\n [attr.aria-expanded]=\"organizedSectionExpanded\"\n (click)=\"toggleOrganizedSection()\"\n >\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 <mat-icon class=\"cqa-text-[#6D6D74] cqa-ml-auto\" style=\"font-size:18px;width:18px;height:18px\">\n {{ organizedSectionExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div\n class=\"cqa-grid\"\n style=\"transition: grid-template-rows 300ms cubic-bezier(0.4, 0, 0.2, 1);\"\n [style.grid-template-rows]=\"organizedSectionExpanded ? '1fr' : '0fr'\"\n >\n <div class=\"cqa-min-h-0\" style=\"overflow: hidden;\">\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-1\"\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-flex-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-flex-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-flex-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-flex-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 <ng-container *ngTemplateOutlet=\"loadingSpinner; context: { size: 20 }\"></ng-container>\n </div>\n </div>\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-grid\"\n style=\"transition: grid-template-rows 300ms cubic-bezier(0.4, 0, 0.2, 1);\"\n [style.grid-template-rows]=\"subfolderSectionExpanded ? '1fr' : '0fr'\"\n >\n <div class=\"cqa-min-h-0\" style=\"overflow: hidden;\">\n <div class=\"cqa-px-3 cqa-py-2 cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin\"\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-flex-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-flex-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-flex-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-flex-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 <ng-container *ngTemplateOutlet=\"loadingSpinner; context: { size: 20 }\"></ng-container>\n </div>\n </div>\n </div>\n </section>\n\n <div\n *ngIf=\"isModularView && !isRootView && modularConfig.showUnorganizedSection\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-px-4 cqa-py-3 cqa-border cqa-border-indigo-100\"\n style=\"background-color: #D8D9FC;\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9585 10.4585C12.9585 10.79 12.8268 11.108 12.5924 11.3424C12.358 11.5768 12.04 11.7085 11.7085 11.7085H1.7085C1.37698 11.7085 1.05903 11.5768 0.824613 11.3424C0.590192 11.108 0.458496 10.79 0.458496 10.4585V1.7085C0.458496 1.37698 0.590192 1.05903 0.824613 0.824613C1.05903 0.590192 1.37698 0.458496 1.7085 0.458496H4.8335L6.0835 2.3335H11.7085C12.04 2.3335 12.358 2.46519 12.5924 2.69961C12.8268 2.93403 12.9585 3.25198 12.9585 3.5835V10.4585Z\" stroke=\"#3F43EE\" stroke-width=\"0.916667\"/>\n </svg>\n <span class=\"cqa-text-sm cqa-font-semibold\" style=\"color: #3F43EE;\">\n {{ currentFolderNode?.name }} ({{ currentFolderDirectCount }})\n </span>\n </div>\n <cqa-button\n variant=\"outlined\"\n btnSize=\"sm\"\n customClass=\"!cqa-text-[13px]\"\n inlineStyles=\"border-color: #3F43EE; color: #3F43EE;\"\n [text]=\"modularLabels.clearFilter\"\n (clicked)=\"onFolderSelected(null)\"\n ></cqa-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 <div class=\"cqa-overflow-hidden cqa-border-t cqa-border-l cqa-border-r cqa-border-grey-200 cqa-relative cqa-overflow-x-auto\"\n [class.cqa-modular-table-flush]=\"isModularView\"\n [attr.style]=\"(!isModularView ? 'border-radius: 7px;' : '') + ((pagedRows && pagedRows.length > 0) ? '' : ' 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", "foldersAccordionExpanded", "labels", "serverSideSearch", "rootTotal", "folderSearchLoading", "rootFoldersLoading", "savingFolderIds", "searchValue"], outputs: ["folderSelected", "folderExpansionToggled", "folderChildrenRequested", "folderLoadMoreRequested", "searchChange", "rootLoadMoreRequested", "folderCreated", "folderCreateRequested", "folderRenamed", "folderDeleted", "folderMoveRequested", "folderDuplicateRequested", "testsDropped", "folderDropped", "collapsedChange", "foldersAccordionExpandedChange"] }, { type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: DynamicTableComponent, selector: "app-dynamic-table", inputs: ["data", "columns", "emptyState", "gridTemplateColumns", "screenWidth", "enableSelectAll", "rowSelectable", "enableLocalSort", "isTableLoading", "isTableDataLoading", "cellJsonPathGetter", "onJsonPathCopiedHandler", "enableRowReorder", "reorderHandleTooltip"], outputs: ["sortChange", "rowReorder"] }, { type: EmptyStateComponent, selector: "cqa-empty-state", inputs: ["preset", "imageUrl", "title", "description", "actions"], outputs: ["actionClick"] }, { type: PaginationComponent, selector: "cqa-pagination", inputs: ["totalElements", "totalPages", "pageIndex", "pageSize", "pageItemCount", "pageSizeOptions", "pageSizeMenuDirection"], outputs: ["pageIndexChange", "pageSizeChange", "paginate"] }, { type: TableActionToolbarComponent, selector: "cqa-table-action-toolbar", inputs: ["selectedItems", "actions", "showSelectAll", "allSelected", "showDismiss"], outputs: ["actionClick", "selectAllChange", "dismiss"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: FolderDropDirective, selector: "[cqaFolderDrop]", inputs: ["cqaFolderDrop", "dropEnabled"], outputs: ["testsDropped", "folderDropped"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
11226
11226
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ModularTableTemplateComponent, decorators: [{
11227
11227
  type: Component,
11228
- 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-flex-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 indeterminate loading spinner. Render via\n <ng-container *ngTemplateOutlet=\"loadingSpinner; context: { size: 20 }\"></ng-container>. -->\n<ng-template #loadingSpinner let-size=\"size\">\n <svg [attr.width]=\"size || 20\" [attr.height]=\"size || 20\" viewBox=\"0 0 50 50\" aria-label=\"loading\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"25\" cy=\"25\" r=\"20\" stroke=\"#E5E7EB\" stroke-width=\"6\" fill=\"none\"></circle>\n <path d=\"M45 25a20 20 0 0 0-20-20\" stroke=\"#4F46E5\" stroke-width=\"6\" fill=\"none\" stroke-linecap=\"round\">\n <animateTransform attributeName=\"transform\" type=\"rotate\" from=\"0 25 25\" to=\"360 25 25\" dur=\"0.8s\" repeatCount=\"indefinite\"></animateTransform>\n </path>\n </svg>\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-flex-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-2 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 [allowDuplicate]=\"modularConfig.allowDuplicateFolder\"\n [showCounts]=\"modularConfig.showCounts\"\n [collapsed]=\"sidebarCollapsed\"\n [labels]=\"modularLabels\"\n [serverSideSearch]=\"serverSideSearch\"\n [rootTotal]=\"rootTotal\"\n [folderSearchLoading]=\"folderSearchLoading\"\n [rootFoldersLoading]=\"rootFoldersLoading\"\n [savingFolderIds]=\"savingFolderIds\"\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-2 cqa-text-sm cqa-px-3 cqa-py-2 cqa-rounded-none cqa-min-w-0\"\n style=\"color: #6D6D74; border-bottom: 1px solid #E2E2E3;\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-1 cqa-flex-1 cqa-min-w-0 cqa-overflow-x-auto cqa-scrollbar-thin cqa-whitespace-nowrap\">\n <button type=\"button\" class=\"hover:cqa-text-[#3F43EE] cqa-inline-flex cqa-items-center cqa-gap-1 cqa-flex-shrink-0\" (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 cqa-flex-shrink-0\" style=\"font-size:16px;width:16px;height:16px;color:#6D6D74;\">chevron_right</mat-icon>\n <button\n type=\"button\"\n class=\"cqa-flex-shrink-0\"\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 </div>\n <cqa-button\n *ngIf=\"modularConfig.showSubfolderSection && subfolderTiles.length\"\n class=\"cqa-flex-shrink-0\"\n variant=\"text\"\n btnSize=\"sm\"\n customClass=\"!cqa-text-[13px] !cqa-leading-[18px]\"\n [icon]=\"subfolderSectionExpanded ? 'expand_less' : 'expand_more'\"\n [text]=\"(subfolderSectionExpanded ? 'Hide' : 'Show') + ' subfolders'\"\n [attr.aria-expanded]=\"subfolderSectionExpanded\"\n (clicked)=\"toggleSubfolderSection()\"\n ></cqa-button>\n <cqa-button\n *ngIf=\"modularConfig.allowCreateFolder\"\n class=\"cqa-flex-shrink-0\"\n variant=\"text\"\n btnSize=\"sm\"\n customClass=\"!cqa-text-[13px] !cqa-leading-[18px]\"\n icon=\"add\"\n [text]=\"modularLabels.newFolder\"\n (clicked)=\"onFolderCreateRequested({ parentId: selectedFolderId })\"\n ></cqa-button>\n </nav>\n\n <!-- Folder grid: modular + root view -->\n <section\n *ngIf=\"isModularView && isRootView && modularConfig.showFolderGrid && rootFolderTiles.length\"\n class=\"cqa-px-5 cqa-pt-2\"\n style=\"border-bottom: 1px solid #F0F0F1;\"\n >\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2 cqa-w-full cqa-text-left\"\n [attr.aria-expanded]=\"organizedSectionExpanded\"\n (click)=\"toggleOrganizedSection()\"\n >\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 <mat-icon class=\"cqa-text-[#6D6D74] cqa-ml-auto\" style=\"font-size:18px;width:18px;height:18px\">\n {{ organizedSectionExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div\n class=\"cqa-grid\"\n style=\"transition: grid-template-rows 300ms cubic-bezier(0.4, 0, 0.2, 1);\"\n [style.grid-template-rows]=\"organizedSectionExpanded ? '1fr' : '0fr'\"\n >\n <div class=\"cqa-min-h-0\" style=\"overflow: hidden;\">\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-1\"\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-flex-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-flex-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-flex-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-flex-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 <ng-container *ngTemplateOutlet=\"loadingSpinner; context: { size: 20 }\"></ng-container>\n </div>\n </div>\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-grid\"\n style=\"transition: grid-template-rows 300ms cubic-bezier(0.4, 0, 0.2, 1);\"\n [style.grid-template-rows]=\"subfolderSectionExpanded ? '1fr' : '0fr'\"\n >\n <div class=\"cqa-min-h-0\" style=\"overflow: hidden;\">\n <div class=\"cqa-px-3 cqa-py-2 cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin\"\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-flex-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-flex-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-flex-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-flex-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 <ng-container *ngTemplateOutlet=\"loadingSpinner; context: { size: 20 }\"></ng-container>\n </div>\n </div>\n </div>\n </section>\n\n <div\n *ngIf=\"isModularView && !isRootView && modularConfig.showUnorganizedSection\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-px-4 cqa-py-3 cqa-border cqa-border-indigo-100\"\n style=\"background-color: #D8D9FC;\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9585 10.4585C12.9585 10.79 12.8268 11.108 12.5924 11.3424C12.358 11.5768 12.04 11.7085 11.7085 11.7085H1.7085C1.37698 11.7085 1.05903 11.5768 0.824613 11.3424C0.590192 11.108 0.458496 10.79 0.458496 10.4585V1.7085C0.458496 1.37698 0.590192 1.05903 0.824613 0.824613C1.05903 0.590192 1.37698 0.458496 1.7085 0.458496H4.8335L6.0835 2.3335H11.7085C12.04 2.3335 12.358 2.46519 12.5924 2.69961C12.8268 2.93403 12.9585 3.25198 12.9585 3.5835V10.4585Z\" stroke=\"#3F43EE\" stroke-width=\"0.916667\"/>\n </svg>\n <span class=\"cqa-text-sm cqa-font-semibold\" style=\"color: #3F43EE;\">\n {{ currentFolderNode?.name }} ({{ currentFolderDirectCount }})\n </span>\n </div>\n <cqa-button\n variant=\"outlined\"\n btnSize=\"sm\"\n customClass=\"!cqa-text-[13px]\"\n inlineStyles=\"border-color: #3F43EE; color: #3F43EE;\"\n [text]=\"modularLabels.clearFilter\"\n (clicked)=\"onFolderSelected(null)\"\n ></cqa-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 <div class=\"cqa-overflow-hidden cqa-border-t cqa-border-l cqa-border-r cqa-border-grey-200 cqa-relative cqa-overflow-x-auto\"\n [class.cqa-modular-table-flush]=\"isModularView\"\n [attr.style]=\"(!isModularView ? 'border-radius: 7px;' : '') + ((pagedRows && pagedRows.length > 0) ? '' : ' 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: [] }]
11228
+ 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-flex-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 indeterminate loading spinner. Render via\n <ng-container *ngTemplateOutlet=\"loadingSpinner; context: { size: 20 }\"></ng-container>. -->\n<ng-template #loadingSpinner let-size=\"size\">\n <svg [attr.width]=\"size || 20\" [attr.height]=\"size || 20\" viewBox=\"0 0 50 50\" aria-label=\"loading\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"25\" cy=\"25\" r=\"20\" stroke=\"#E5E7EB\" stroke-width=\"6\" fill=\"none\"></circle>\n <path d=\"M45 25a20 20 0 0 0-20-20\" stroke=\"#4F46E5\" stroke-width=\"6\" fill=\"none\" stroke-linecap=\"round\">\n <animateTransform attributeName=\"transform\" type=\"rotate\" from=\"0 25 25\" to=\"360 25 25\" dur=\"0.8s\" repeatCount=\"indefinite\"></animateTransform>\n </path>\n </svg>\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-flex-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-max-w-full cqa-flex cqa-flex-col cqa-relative cqa-min-w-0\">\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-2 cqa-min-h-0 cqa-min-w-0 cqa-w-full cqa-max-w-full cqa-overflow-hidden\" 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 [allowDuplicate]=\"modularConfig.allowDuplicateFolder\"\n [showCounts]=\"modularConfig.showCounts\"\n [collapsed]=\"sidebarCollapsed\"\n [labels]=\"modularLabels\"\n [serverSideSearch]=\"serverSideSearch\"\n [rootTotal]=\"rootTotal\"\n [folderSearchLoading]=\"folderSearchLoading\"\n [rootFoldersLoading]=\"rootFoldersLoading\"\n [savingFolderIds]=\"savingFolderIds\"\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-2 cqa-text-sm cqa-px-3 cqa-py-2 cqa-rounded-none cqa-min-w-0\"\n style=\"color: #6D6D74; border-bottom: 1px solid #E2E2E3;\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-1 cqa-flex-1 cqa-min-w-0 cqa-overflow-x-auto cqa-scrollbar-thin cqa-whitespace-nowrap\">\n <button type=\"button\" class=\"hover:cqa-text-[#3F43EE] cqa-inline-flex cqa-items-center cqa-gap-1 cqa-flex-shrink-0\" (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 cqa-flex-shrink-0\" style=\"font-size:16px;width:16px;height:16px;color:#6D6D74;\">chevron_right</mat-icon>\n <button\n type=\"button\"\n class=\"cqa-flex-shrink-0\"\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 </div>\n <cqa-button\n *ngIf=\"modularConfig.showSubfolderSection && subfolderTiles.length\"\n class=\"cqa-flex-shrink-0\"\n variant=\"text\"\n btnSize=\"sm\"\n customClass=\"!cqa-text-[13px] !cqa-leading-[18px]\"\n [icon]=\"subfolderSectionExpanded ? 'expand_less' : 'expand_more'\"\n [text]=\"(subfolderSectionExpanded ? 'Hide' : 'Show') + ' subfolders'\"\n [attr.aria-expanded]=\"subfolderSectionExpanded\"\n (clicked)=\"toggleSubfolderSection()\"\n ></cqa-button>\n <cqa-button\n *ngIf=\"modularConfig.allowCreateFolder\"\n class=\"cqa-flex-shrink-0\"\n variant=\"text\"\n btnSize=\"sm\"\n customClass=\"!cqa-text-[13px] !cqa-leading-[18px]\"\n icon=\"add\"\n [text]=\"modularLabels.newFolder\"\n (clicked)=\"onFolderCreateRequested({ parentId: selectedFolderId })\"\n ></cqa-button>\n </nav>\n\n <!-- Folder grid: modular + root view -->\n <section\n *ngIf=\"isModularView && isRootView && modularConfig.showFolderGrid && rootFolderTiles.length\"\n class=\"cqa-px-5 cqa-pt-2\"\n style=\"border-bottom: 1px solid #F0F0F1;\"\n >\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-2 cqa-w-full cqa-text-left\"\n [attr.aria-expanded]=\"organizedSectionExpanded\"\n (click)=\"toggleOrganizedSection()\"\n >\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 <mat-icon class=\"cqa-text-[#6D6D74] cqa-ml-auto\" style=\"font-size:18px;width:18px;height:18px\">\n {{ organizedSectionExpanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </button>\n <div\n class=\"cqa-grid\"\n style=\"transition: grid-template-rows 300ms cubic-bezier(0.4, 0, 0.2, 1);\"\n [style.grid-template-rows]=\"organizedSectionExpanded ? '1fr' : '0fr'\"\n >\n <div class=\"cqa-min-h-0\" style=\"overflow: hidden;\">\n <div class=\"cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin cqa-pb-1\"\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-flex-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-flex-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-flex-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-flex-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 <ng-container *ngTemplateOutlet=\"loadingSpinner; context: { size: 20 }\"></ng-container>\n </div>\n </div>\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-grid\"\n style=\"transition: grid-template-rows 300ms cubic-bezier(0.4, 0, 0.2, 1);\"\n [style.grid-template-rows]=\"subfolderSectionExpanded ? '1fr' : '0fr'\"\n >\n <div class=\"cqa-min-h-0\" style=\"overflow: hidden;\">\n <div class=\"cqa-px-3 cqa-py-2 cqa-flex cqa-flex-nowrap cqa-gap-3 cqa-overflow-x-auto cqa-scrollbar-thin\"\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-flex-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-flex-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-flex-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-flex-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 <ng-container *ngTemplateOutlet=\"loadingSpinner; context: { size: 20 }\"></ng-container>\n </div>\n </div>\n </div>\n </section>\n\n <div\n *ngIf=\"isModularView && !isRootView && modularConfig.showUnorganizedSection\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-px-4 cqa-py-3 cqa-border cqa-border-indigo-100\"\n style=\"background-color: #D8D9FC;\"\n >\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <svg width=\"14\" height=\"13\" viewBox=\"0 0 14 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path d=\"M12.9585 10.4585C12.9585 10.79 12.8268 11.108 12.5924 11.3424C12.358 11.5768 12.04 11.7085 11.7085 11.7085H1.7085C1.37698 11.7085 1.05903 11.5768 0.824613 11.3424C0.590192 11.108 0.458496 10.79 0.458496 10.4585V1.7085C0.458496 1.37698 0.590192 1.05903 0.824613 0.824613C1.05903 0.590192 1.37698 0.458496 1.7085 0.458496H4.8335L6.0835 2.3335H11.7085C12.04 2.3335 12.358 2.46519 12.5924 2.69961C12.8268 2.93403 12.9585 3.25198 12.9585 3.5835V10.4585Z\" stroke=\"#3F43EE\" stroke-width=\"0.916667\"/>\n </svg>\n <span class=\"cqa-text-sm cqa-font-semibold\" style=\"color: #3F43EE;\">\n {{ currentFolderNode?.name }} ({{ currentFolderDirectCount }})\n </span>\n </div>\n <cqa-button\n variant=\"outlined\"\n btnSize=\"sm\"\n customClass=\"!cqa-text-[13px]\"\n inlineStyles=\"border-color: #3F43EE; color: #3F43EE;\"\n [text]=\"modularLabels.clearFilter\"\n (clicked)=\"onFolderSelected(null)\"\n ></cqa-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 <div class=\"cqa-overflow-hidden cqa-border-t cqa-border-l cqa-border-r cqa-border-grey-200 cqa-relative cqa-overflow-x-auto\"\n [class.cqa-modular-table-flush]=\"isModularView\"\n [attr.style]=\"(!isModularView ? 'border-radius: 7px;' : '') + ((pagedRows && pagedRows.length > 0) ? '' : ' 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: [] }]
11229
11229
  }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: DialogService }]; }, propDecorators: { searchPlaceholder: [{
11230
11230
  type: Input
11231
11231
  }], searchValue: [{
@@ -12222,6 +12222,8 @@ class TailwindOverlayContainer extends OverlayContainer {
12222
12222
  // Check if this pane itself has library component classes (e.g., backdrop)
12223
12223
  const paneHasLibraryClass = pane.classList.contains('cqa-dialog-panel') ||
12224
12224
  pane.classList.contains('cqa-dialog-backdrop') ||
12225
+ pane.classList.contains('cqa-profile-menu-panel') ||
12226
+ pane.classList.contains('cqa-workspace-menu-panel') ||
12225
12227
  pane.classList.contains('ctc-select-panel') ||
12226
12228
  pane.classList.contains('ctc-date-range-panel') ||
12227
12229
  pane.classList.contains('visual-difference-dialog') ||
@@ -12263,6 +12265,777 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
12263
12265
  type: Injectable
12264
12266
  }] });
12265
12267
 
12268
+ function isProfileMenuDivider(entry) {
12269
+ return entry.type === 'divider';
12270
+ }
12271
+
12272
+ function isNavSection(item) {
12273
+ return item.type === 'section';
12274
+ }
12275
+
12276
+ class NavItemComponent {
12277
+ constructor(overlay) {
12278
+ this.overlay = overlay;
12279
+ this.isActive = false;
12280
+ /** Whether the sidebar is in expanded (wide) mode */
12281
+ this.isExpanded = false;
12282
+ /** Whether this item's sub-menu is open */
12283
+ this.isOpen = false;
12284
+ /** Current route / selection id — used to highlight child in collapsed flyout */
12285
+ this.activeNavId = '';
12286
+ this.itemClick = new EventEmitter();
12287
+ /** Collapsed parent: drives CDK connected overlay for submenu */
12288
+ this.showCollapsedFlyout = false;
12289
+ this.closeFlyoutTimer = null;
12290
+ this.collapsedFlyoutPositions = [
12291
+ {
12292
+ originX: 'end',
12293
+ originY: 'center',
12294
+ overlayX: 'start',
12295
+ overlayY: 'center',
12296
+ offsetX: 8
12297
+ },
12298
+ {
12299
+ originX: 'end',
12300
+ originY: 'top',
12301
+ overlayX: 'start',
12302
+ overlayY: 'top',
12303
+ offsetX: 8
12304
+ },
12305
+ {
12306
+ originX: 'end',
12307
+ originY: 'bottom',
12308
+ overlayX: 'start',
12309
+ overlayY: 'bottom',
12310
+ offsetX: 8
12311
+ }
12312
+ ];
12313
+ this.flyoutScrollStrategy = this.overlay.scrollStrategies.reposition();
12314
+ }
12315
+ ngOnDestroy() {
12316
+ this.clearFlyoutCloseTimer();
12317
+ }
12318
+ get hasChildren() {
12319
+ return !!(this.item?.children?.length);
12320
+ }
12321
+ get collapsedFlyoutOpen() {
12322
+ return (!this.isExpanded &&
12323
+ this.showCollapsedFlyout &&
12324
+ this.hasChildren &&
12325
+ !!(this.item?.children?.length));
12326
+ }
12327
+ /**
12328
+ * Collapsed rail: show label (leaf) or disabled copy in MatTooltip so it renders in CDK overlay,
12329
+ * not as an absolute child inside the scrolling nav.
12330
+ */
12331
+ get collapsedRailTooltip() {
12332
+ if (this.item?.disabled && this.item?.disabledTooltip) {
12333
+ return this.item.disabledTooltip;
12334
+ }
12335
+ if (!this.isExpanded && !this.hasChildren && this.item?.label) {
12336
+ return this.item.label;
12337
+ }
12338
+ return '';
12339
+ }
12340
+ get collapsedRailTooltipClass() {
12341
+ return !this.isExpanded && this.collapsedRailTooltip ? 'cqa-nav-rail-tooltip' : '';
12342
+ }
12343
+ isChildRowActive(childId) {
12344
+ return this.activeNavId === childId;
12345
+ }
12346
+ onHostMouseEnter() {
12347
+ this.clearFlyoutCloseTimer();
12348
+ if (!this.isExpanded && !this.item?.disabled && this.hasChildren) {
12349
+ this.showCollapsedFlyout = true;
12350
+ }
12351
+ }
12352
+ onHostMouseLeave() {
12353
+ this.scheduleCloseCollapsedFlyout();
12354
+ }
12355
+ onHostFocusIn(_e) {
12356
+ this.clearFlyoutCloseTimer();
12357
+ if (!this.isExpanded && !this.item?.disabled && this.hasChildren) {
12358
+ this.showCollapsedFlyout = true;
12359
+ }
12360
+ }
12361
+ onHostFocusOut(e) {
12362
+ if (this.isExpanded)
12363
+ return;
12364
+ const related = e.relatedTarget;
12365
+ if (related?.closest('.cqa-nav-flyout-overlay')) {
12366
+ return;
12367
+ }
12368
+ const host = e.currentTarget;
12369
+ if (related && host.contains(related))
12370
+ return;
12371
+ this.closeCollapsedFlyout();
12372
+ }
12373
+ onFlyoutOverlayPointerEnter() {
12374
+ this.clearFlyoutCloseTimer();
12375
+ }
12376
+ onFlyoutOverlayPointerLeave() {
12377
+ this.scheduleCloseCollapsedFlyout();
12378
+ }
12379
+ onFlyoutOverlayFocusOut(e) {
12380
+ const related = e.relatedTarget;
12381
+ const panel = e.currentTarget;
12382
+ if (related && panel.contains(related))
12383
+ return;
12384
+ const hostEl = this.navHostRef?.nativeElement;
12385
+ if (related && hostEl?.contains(related))
12386
+ return;
12387
+ this.closeCollapsedFlyout();
12388
+ }
12389
+ closeCollapsedFlyout() {
12390
+ this.clearFlyoutCloseTimer();
12391
+ this.showCollapsedFlyout = false;
12392
+ }
12393
+ onClick() {
12394
+ if (!this.item?.disabled) {
12395
+ this.itemClick.emit(this.item.id);
12396
+ }
12397
+ }
12398
+ onChildRowClick(e, child) {
12399
+ e.stopPropagation();
12400
+ if (child.disabled)
12401
+ return;
12402
+ this.itemClick.emit(child.id);
12403
+ this.closeCollapsedFlyout();
12404
+ }
12405
+ clearFlyoutCloseTimer() {
12406
+ if (this.closeFlyoutTimer) {
12407
+ clearTimeout(this.closeFlyoutTimer);
12408
+ this.closeFlyoutTimer = null;
12409
+ }
12410
+ }
12411
+ scheduleCloseCollapsedFlyout() {
12412
+ this.clearFlyoutCloseTimer();
12413
+ this.closeFlyoutTimer = setTimeout(() => {
12414
+ this.showCollapsedFlyout = false;
12415
+ this.closeFlyoutTimer = null;
12416
+ }, NavItemComponent.FLYOUT_CLOSE_DELAY_MS);
12417
+ }
12418
+ }
12419
+ NavItemComponent.FLYOUT_CLOSE_DELAY_MS = 120;
12420
+ NavItemComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: NavItemComponent, deps: [{ token: i1$6.Overlay }], target: i0.ɵɵFactoryTarget.Component });
12421
+ NavItemComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: NavItemComponent, selector: "cqa-nav-item", inputs: { item: "item", isActive: "isActive", isExpanded: "isExpanded", isOpen: "isOpen", activeNavId: "activeNavId" }, outputs: { itemClick: "itemClick" }, viewQueries: [{ propertyName: "navHostRef", first: true, predicate: ["navHost"], descendants: true }], ngImport: i0, template: "<div class=\"cqa-nav-surface\">\n <div\n #navHost\n class=\"cqa-nav-host\"\n [class.cqa-nav-host--collapsed]=\"!isExpanded\"\n (mouseenter)=\"onHostMouseEnter()\"\n (mouseleave)=\"onHostMouseLeave()\"\n (focusin)=\"onHostFocusIn($event)\"\n (focusout)=\"onHostFocusOut($event)\">\n\n <button\n cdkOverlayOrigin\n #flyoutOrigin=\"cdkOverlayOrigin\"\n class=\"cqa-nav-item\"\n [class.cqa-nav-item--active]=\"isActive\"\n [class.cqa-nav-item--has-children]=\"hasChildren\"\n [class.cqa-nav-item--collapsed]=\"!isExpanded\"\n [class.cqa-nav-item--disabled]=\"item?.disabled\"\n [class.cqa-nav-item--has-live]=\"item?.status === 'live'\"\n [matTooltip]=\"collapsedRailTooltip\"\n [matTooltipDisabled]=\"!collapsedRailTooltip\"\n [matTooltipClass]=\"collapsedRailTooltipClass\"\n matTooltipPosition=\"right\"\n (click)=\"onClick()\"\n type=\"button\"\n [attr.aria-label]=\"!isExpanded ? (item?.label || '') : null\"\n [attr.aria-expanded]=\"!isExpanded && hasChildren ? showCollapsedFlyout : null\"\n [attr.aria-haspopup]=\"!isExpanded && hasChildren ? 'menu' : null\">\n\n <!-- Icon -->\n <span class=\"cqa-nav-icon\">\n <i [class]=\"item?.iconClass\"></i>\n </span>\n\n <!-- Label (hidden when sidebar collapsed) -->\n <span class=\"cqa-nav-label\" [class.cqa-nav-label--visible]=\"isExpanded\">\n {{ item?.label }}\n </span>\n\n <!-- Trailing slot: only shown when expanded -->\n <ng-container *ngIf=\"isExpanded\">\n <span *ngIf=\"item?.badge && !hasChildren\" class=\"cqa-nav-badge\">{{ item.badge }}</span>\n\n <span\n *ngIf=\"item?.status === 'live' && !hasChildren\"\n class=\"cqa-nav-status-dot cqa-nav-status-dot--live\">\n </span>\n\n <span\n *ngIf=\"item?.status === 'danger' && !hasChildren\"\n class=\"cqa-nav-status-dot cqa-nav-status-dot--danger\">\n </span>\n\n <span *ngIf=\"hasChildren\" class=\"cqa-nav-chev\" [class.cqa-nav-chev--open]=\"isOpen\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"14\" height=\"14\">\n <polyline points=\"9,6 15,12 9,18\"/>\n </svg>\n </span>\n </ng-container>\n\n <span\n *ngIf=\"!isExpanded && item?.status === 'live'\"\n class=\"cqa-nav-live-corner\">\n </span>\n </button>\n\n <!-- Collapsed parent submenu: CDK overlay (outside aside / scrolling nav) -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"flyoutOrigin\"\n [cdkConnectedOverlayOpen]=\"collapsedFlyoutOpen\"\n [cdkConnectedOverlayPositions]=\"collapsedFlyoutPositions\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayScrollStrategy]=\"flyoutScrollStrategy\"\n [cdkConnectedOverlayPanelClass]=\"'cqa-nav-flyout-overlay-pane'\"\n (overlayOutsideClick)=\"closeCollapsedFlyout()\"\n (detach)=\"closeCollapsedFlyout()\">\n <div\n class=\"cqa-nav-flyout-overlay cqa-nav-flyout-panel\"\n role=\"menu\"\n [attr.aria-label]=\"item.label\"\n (mouseenter)=\"onFlyoutOverlayPointerEnter()\"\n (mouseleave)=\"onFlyoutOverlayPointerLeave()\"\n (focusout)=\"onFlyoutOverlayFocusOut($event)\">\n <div class=\"cqa-nav-flyout-panel-title\">{{ item.label }}</div>\n <button\n *ngFor=\"let child of item?.children\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-nav-flyout-row\"\n [class.cqa-nav-flyout-row--active]=\"isChildRowActive(child.id)\"\n [disabled]=\"child.disabled\"\n (click)=\"onChildRowClick($event, child)\">\n <span class=\"cqa-nav-flyout-row-icon\">\n <i *ngIf=\"child.iconClass\" [class]=\"child.iconClass\"></i>\n </span>\n <span class=\"cqa-nav-flyout-row-label\">{{ child.label }}</span>\n <span *ngIf=\"child.isNew\" class=\"cqa-nav-flyout-row-new\">New</span>\n </button>\n </div>\n </ng-template>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.cqa-nav-surface,.cqa-nav-host{display:block;width:100%}.cqa-nav-host--collapsed{display:flex;flex-direction:column;align-items:center;position:relative;z-index:1}.cqa-nav-host--collapsed:hover,.cqa-nav-host--collapsed:focus-within{z-index:30}.cqa-nav-item{display:flex;align-items:center;gap:12px;padding:9px 10px;margin:1px 8px;border-radius:9px;color:#ffffffd9;font-size:14px;font-weight:600;line-height:1;letter-spacing:0;width:calc(100% - 16px);text-align:left;background:transparent;border:none;cursor:pointer;position:relative;transition:background .12s,color .12s;overflow:hidden;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif}.cqa-nav-item:not(.cqa-nav-item--collapsed){color:#d8d9fc}.cqa-nav-item:hover:not(.cqa-nav-item--active):not(.cqa-nav-item--disabled){background:rgba(255,255,255,.12);color:#fff}.cqa-nav-item--active:not(.cqa-nav-item--collapsed){background:#8a8cf4;font-weight:600;box-shadow:inset 0 0 0 1px #d8d9fc4d;color:#fff}.cqa-nav-item--active:not(.cqa-nav-item--collapsed).cqa-nav-item--has-children{color:#d8d9fc}.cqa-nav-item--active:not(.cqa-nav-item--collapsed):hover{background:#8a8cf4}.cqa-nav-item--active:not(.cqa-nav-item--collapsed).cqa-nav-item--has-children:hover{color:#d8d9fc}.cqa-nav-item--active:not(.cqa-nav-item--collapsed):not(.cqa-nav-item--has-children):hover{color:#fff}.cqa-nav-item--active.cqa-nav-item--collapsed{background:rgba(177,178,248,.42);color:#fff;font-weight:600;box-shadow:inset 0 0 0 1px #d8d9fc4d}.cqa-nav-item.cqa-nav-item--collapsed:hover:not(.cqa-nav-item--active):not(.cqa-nav-item--disabled){background:#4c50ef;box-shadow:none}.cqa-nav-item--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.cqa-nav-item.cqa-nav-item--collapsed{justify-content:center;align-items:center;gap:0;padding:9px 0;margin:1px 0;width:40px;max-width:100%;box-sizing:border-box;color:#ffffffe0;overflow:visible;z-index:1}.cqa-nav-item.cqa-nav-item--collapsed .cqa-nav-label{flex:0 0 0;width:0;min-width:0;height:0;margin:0;padding:0;overflow:hidden;opacity:0;border:0;pointer-events:none}.cqa-nav-item.cqa-nav-item--collapsed:hover{z-index:auto}.cqa-nav-icon{width:20px;height:20px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:18px;color:inherit}.cqa-nav-item--collapsed .cqa-nav-icon i{display:flex;align-items:center;justify-content:center;width:100%;height:100%;line-height:1}.cqa-nav-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;opacity:0;transition:opacity .16s 80ms;color:inherit}.cqa-nav-label--visible{opacity:1}.cqa-nav-badge{font-size:11px;font-weight:600;background:rgba(255,255,255,.18);color:#fff;padding:1px 7px;border-radius:999px;flex-shrink:0}.cqa-nav-status-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0}.cqa-nav-status-dot--live{background:#0dbd7d;box-shadow:0 0 6px #0dbd7d;animation:cqa-nav-pulse 2s ease-in-out infinite}.cqa-nav-status-dot--danger{background:#ee3f3f}.cqa-nav-chev{width:14px;height:14px;opacity:.6;flex-shrink:0;transition:transform .2s;display:flex;align-items:center;justify-content:center}.cqa-nav-chev--open{transform:rotate(90deg)}.cqa-nav-live-corner{position:absolute;top:5px;right:5px;width:9px;height:9px;background:#0dbd7d;border-radius:50%;border:2px solid #3f43ee;box-shadow:0 0 6px #0dbd7d}@keyframes cqa-nav-pulse{0%,to{opacity:1}50%{opacity:.4}}.cqa-nav-flyout-panel{min-width:188px;max-width:280px;padding:10px 8px 8px;background:#4c50ef;border-radius:10px;box-shadow:0 12px 32px #00000047;border:1px solid rgba(255,255,255,.12);pointer-events:auto;text-align:left;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif}.cqa-nav-flyout-panel-title{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:#ffffff8c;padding:2px 8px 8px;line-height:1.2}.cqa-nav-flyout-row{display:flex;align-items:center;gap:10px;width:100%;padding:8px 10px;margin:0 0 2px;border:none;border-radius:8px;background:transparent;color:#fff;font-size:13px;font-weight:500;text-align:left;cursor:pointer;transition:background .12s,color .12s;font-family:inherit}.cqa-nav-flyout-row:last-child{margin-bottom:0}.cqa-nav-flyout-row:hover:not(:disabled){background:rgba(255,255,255,.1);color:#fff}.cqa-nav-flyout-row:disabled{opacity:.45;cursor:not-allowed}.cqa-nav-flyout-row--active{background:#8a8cf4;color:#fbfcff;font-weight:600}.cqa-nav-flyout-row--active:hover:not(:disabled){background:#8a8cf4;color:#fbfcff}.cqa-nav-flyout-row-icon{width:16px;height:16px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:14px;opacity:.95}.cqa-nav-flyout-row-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cqa-nav-flyout-row-new{flex-shrink:0;font-size:10px;font-weight:700;padding:2px 7px;border-radius:999px;background:#feecbd;color:#7e6012;border:1px solid #fddf92}\n"], directives: [{ type: i1$6.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { type: i6.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
12422
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: NavItemComponent, decorators: [{
12423
+ type: Component,
12424
+ args: [{ selector: 'cqa-nav-item', template: "<div class=\"cqa-nav-surface\">\n <div\n #navHost\n class=\"cqa-nav-host\"\n [class.cqa-nav-host--collapsed]=\"!isExpanded\"\n (mouseenter)=\"onHostMouseEnter()\"\n (mouseleave)=\"onHostMouseLeave()\"\n (focusin)=\"onHostFocusIn($event)\"\n (focusout)=\"onHostFocusOut($event)\">\n\n <button\n cdkOverlayOrigin\n #flyoutOrigin=\"cdkOverlayOrigin\"\n class=\"cqa-nav-item\"\n [class.cqa-nav-item--active]=\"isActive\"\n [class.cqa-nav-item--has-children]=\"hasChildren\"\n [class.cqa-nav-item--collapsed]=\"!isExpanded\"\n [class.cqa-nav-item--disabled]=\"item?.disabled\"\n [class.cqa-nav-item--has-live]=\"item?.status === 'live'\"\n [matTooltip]=\"collapsedRailTooltip\"\n [matTooltipDisabled]=\"!collapsedRailTooltip\"\n [matTooltipClass]=\"collapsedRailTooltipClass\"\n matTooltipPosition=\"right\"\n (click)=\"onClick()\"\n type=\"button\"\n [attr.aria-label]=\"!isExpanded ? (item?.label || '') : null\"\n [attr.aria-expanded]=\"!isExpanded && hasChildren ? showCollapsedFlyout : null\"\n [attr.aria-haspopup]=\"!isExpanded && hasChildren ? 'menu' : null\">\n\n <!-- Icon -->\n <span class=\"cqa-nav-icon\">\n <i [class]=\"item?.iconClass\"></i>\n </span>\n\n <!-- Label (hidden when sidebar collapsed) -->\n <span class=\"cqa-nav-label\" [class.cqa-nav-label--visible]=\"isExpanded\">\n {{ item?.label }}\n </span>\n\n <!-- Trailing slot: only shown when expanded -->\n <ng-container *ngIf=\"isExpanded\">\n <span *ngIf=\"item?.badge && !hasChildren\" class=\"cqa-nav-badge\">{{ item.badge }}</span>\n\n <span\n *ngIf=\"item?.status === 'live' && !hasChildren\"\n class=\"cqa-nav-status-dot cqa-nav-status-dot--live\">\n </span>\n\n <span\n *ngIf=\"item?.status === 'danger' && !hasChildren\"\n class=\"cqa-nav-status-dot cqa-nav-status-dot--danger\">\n </span>\n\n <span *ngIf=\"hasChildren\" class=\"cqa-nav-chev\" [class.cqa-nav-chev--open]=\"isOpen\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"14\" height=\"14\">\n <polyline points=\"9,6 15,12 9,18\"/>\n </svg>\n </span>\n </ng-container>\n\n <span\n *ngIf=\"!isExpanded && item?.status === 'live'\"\n class=\"cqa-nav-live-corner\">\n </span>\n </button>\n\n <!-- Collapsed parent submenu: CDK overlay (outside aside / scrolling nav) -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"flyoutOrigin\"\n [cdkConnectedOverlayOpen]=\"collapsedFlyoutOpen\"\n [cdkConnectedOverlayPositions]=\"collapsedFlyoutPositions\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayScrollStrategy]=\"flyoutScrollStrategy\"\n [cdkConnectedOverlayPanelClass]=\"'cqa-nav-flyout-overlay-pane'\"\n (overlayOutsideClick)=\"closeCollapsedFlyout()\"\n (detach)=\"closeCollapsedFlyout()\">\n <div\n class=\"cqa-nav-flyout-overlay cqa-nav-flyout-panel\"\n role=\"menu\"\n [attr.aria-label]=\"item.label\"\n (mouseenter)=\"onFlyoutOverlayPointerEnter()\"\n (mouseleave)=\"onFlyoutOverlayPointerLeave()\"\n (focusout)=\"onFlyoutOverlayFocusOut($event)\">\n <div class=\"cqa-nav-flyout-panel-title\">{{ item.label }}</div>\n <button\n *ngFor=\"let child of item?.children\"\n type=\"button\"\n role=\"menuitem\"\n class=\"cqa-nav-flyout-row\"\n [class.cqa-nav-flyout-row--active]=\"isChildRowActive(child.id)\"\n [disabled]=\"child.disabled\"\n (click)=\"onChildRowClick($event, child)\">\n <span class=\"cqa-nav-flyout-row-icon\">\n <i *ngIf=\"child.iconClass\" [class]=\"child.iconClass\"></i>\n </span>\n <span class=\"cqa-nav-flyout-row-label\">{{ child.label }}</span>\n <span *ngIf=\"child.isNew\" class=\"cqa-nav-flyout-row-new\">New</span>\n </button>\n </div>\n </ng-template>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.cqa-nav-surface,.cqa-nav-host{display:block;width:100%}.cqa-nav-host--collapsed{display:flex;flex-direction:column;align-items:center;position:relative;z-index:1}.cqa-nav-host--collapsed:hover,.cqa-nav-host--collapsed:focus-within{z-index:30}.cqa-nav-item{display:flex;align-items:center;gap:12px;padding:9px 10px;margin:1px 8px;border-radius:9px;color:#ffffffd9;font-size:14px;font-weight:600;line-height:1;letter-spacing:0;width:calc(100% - 16px);text-align:left;background:transparent;border:none;cursor:pointer;position:relative;transition:background .12s,color .12s;overflow:hidden;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif}.cqa-nav-item:not(.cqa-nav-item--collapsed){color:#d8d9fc}.cqa-nav-item:hover:not(.cqa-nav-item--active):not(.cqa-nav-item--disabled){background:rgba(255,255,255,.12);color:#fff}.cqa-nav-item--active:not(.cqa-nav-item--collapsed){background:#8a8cf4;font-weight:600;box-shadow:inset 0 0 0 1px #d8d9fc4d;color:#fff}.cqa-nav-item--active:not(.cqa-nav-item--collapsed).cqa-nav-item--has-children{color:#d8d9fc}.cqa-nav-item--active:not(.cqa-nav-item--collapsed):hover{background:#8a8cf4}.cqa-nav-item--active:not(.cqa-nav-item--collapsed).cqa-nav-item--has-children:hover{color:#d8d9fc}.cqa-nav-item--active:not(.cqa-nav-item--collapsed):not(.cqa-nav-item--has-children):hover{color:#fff}.cqa-nav-item--active.cqa-nav-item--collapsed{background:rgba(177,178,248,.42);color:#fff;font-weight:600;box-shadow:inset 0 0 0 1px #d8d9fc4d}.cqa-nav-item.cqa-nav-item--collapsed:hover:not(.cqa-nav-item--active):not(.cqa-nav-item--disabled){background:#4c50ef;box-shadow:none}.cqa-nav-item--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.cqa-nav-item.cqa-nav-item--collapsed{justify-content:center;align-items:center;gap:0;padding:9px 0;margin:1px 0;width:40px;max-width:100%;box-sizing:border-box;color:#ffffffe0;overflow:visible;z-index:1}.cqa-nav-item.cqa-nav-item--collapsed .cqa-nav-label{flex:0 0 0;width:0;min-width:0;height:0;margin:0;padding:0;overflow:hidden;opacity:0;border:0;pointer-events:none}.cqa-nav-item.cqa-nav-item--collapsed:hover{z-index:auto}.cqa-nav-icon{width:20px;height:20px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:18px;color:inherit}.cqa-nav-item--collapsed .cqa-nav-icon i{display:flex;align-items:center;justify-content:center;width:100%;height:100%;line-height:1}.cqa-nav-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;opacity:0;transition:opacity .16s 80ms;color:inherit}.cqa-nav-label--visible{opacity:1}.cqa-nav-badge{font-size:11px;font-weight:600;background:rgba(255,255,255,.18);color:#fff;padding:1px 7px;border-radius:999px;flex-shrink:0}.cqa-nav-status-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0}.cqa-nav-status-dot--live{background:#0dbd7d;box-shadow:0 0 6px #0dbd7d;animation:cqa-nav-pulse 2s ease-in-out infinite}.cqa-nav-status-dot--danger{background:#ee3f3f}.cqa-nav-chev{width:14px;height:14px;opacity:.6;flex-shrink:0;transition:transform .2s;display:flex;align-items:center;justify-content:center}.cqa-nav-chev--open{transform:rotate(90deg)}.cqa-nav-live-corner{position:absolute;top:5px;right:5px;width:9px;height:9px;background:#0dbd7d;border-radius:50%;border:2px solid #3f43ee;box-shadow:0 0 6px #0dbd7d}@keyframes cqa-nav-pulse{0%,to{opacity:1}50%{opacity:.4}}.cqa-nav-flyout-panel{min-width:188px;max-width:280px;padding:10px 8px 8px;background:#4c50ef;border-radius:10px;box-shadow:0 12px 32px #00000047;border:1px solid rgba(255,255,255,.12);pointer-events:auto;text-align:left;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif}.cqa-nav-flyout-panel-title{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:#ffffff8c;padding:2px 8px 8px;line-height:1.2}.cqa-nav-flyout-row{display:flex;align-items:center;gap:10px;width:100%;padding:8px 10px;margin:0 0 2px;border:none;border-radius:8px;background:transparent;color:#fff;font-size:13px;font-weight:500;text-align:left;cursor:pointer;transition:background .12s,color .12s;font-family:inherit}.cqa-nav-flyout-row:last-child{margin-bottom:0}.cqa-nav-flyout-row:hover:not(:disabled){background:rgba(255,255,255,.1);color:#fff}.cqa-nav-flyout-row:disabled{opacity:.45;cursor:not-allowed}.cqa-nav-flyout-row--active{background:#8a8cf4;color:#fbfcff;font-weight:600}.cqa-nav-flyout-row--active:hover:not(:disabled){background:#8a8cf4;color:#fbfcff}.cqa-nav-flyout-row-icon{width:16px;height:16px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:14px;opacity:.95}.cqa-nav-flyout-row-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cqa-nav-flyout-row-new{flex-shrink:0;font-size:10px;font-weight:700;padding:2px 7px;border-radius:999px;background:#feecbd;color:#7e6012;border:1px solid #fddf92}\n"] }]
12425
+ }], ctorParameters: function () { return [{ type: i1$6.Overlay }]; }, propDecorators: { item: [{
12426
+ type: Input
12427
+ }], isActive: [{
12428
+ type: Input
12429
+ }], isExpanded: [{
12430
+ type: Input
12431
+ }], isOpen: [{
12432
+ type: Input
12433
+ }], activeNavId: [{
12434
+ type: Input
12435
+ }], itemClick: [{
12436
+ type: Output
12437
+ }], navHostRef: [{
12438
+ type: ViewChild,
12439
+ args: ['navHost']
12440
+ }] } });
12441
+
12442
+ class NavSubItemComponent {
12443
+ constructor() {
12444
+ this.isActive = false;
12445
+ this.itemClick = new EventEmitter();
12446
+ }
12447
+ onClick() {
12448
+ if (!this.item?.disabled) {
12449
+ this.itemClick.emit(this.item.id);
12450
+ }
12451
+ }
12452
+ }
12453
+ NavSubItemComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: NavSubItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
12454
+ NavSubItemComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: NavSubItemComponent, selector: "cqa-nav-sub-item", inputs: { item: "item", isActive: "isActive" }, outputs: { itemClick: "itemClick" }, ngImport: i0, template: "<div class=\"cqa-nav-surface\">\n <button\n class=\"cqa-nav-sub-item\"\n [class.cqa-nav-sub-item--active]=\"isActive\"\n [class.cqa-nav-sub-item--disabled]=\"item?.disabled\"\n (click)=\"onClick()\"\n type=\"button\">\n\n <span class=\"cqa-nav-sub-icon\">\n <i [class]=\"item?.iconClass\"></i>\n </span>\n\n <span class=\"cqa-nav-sub-label\">{{ item?.label }}</span>\n\n <span *ngIf=\"item?.isNew\" class=\"cqa-nav-sub-badge cqa-nav-sub-badge--new\">New</span>\n </button>\n</div>\n", styles: ["@charset \"UTF-8\";.cqa-nav-surface{display:block;width:100%}.cqa-nav-sub-item{display:flex;align-items:center;gap:10px;padding:7px 10px;margin:0;border-radius:7px;color:#d8d9fc;font-size:12px;font-weight:400;line-height:normal;width:100%;text-align:left;background:transparent;border:none;cursor:pointer;transition:background .12s,color .12s;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif}.cqa-nav-sub-item:hover:not(.cqa-nav-sub-item--active){background:rgba(255,255,255,.1);color:#fff}.cqa-nav-sub-item--active{background:#8a8cf4;color:#fbfcff;font-weight:600}.cqa-nav-sub-item--active .cqa-nav-sub-icon{opacity:1;color:#fbfcff}.cqa-nav-sub-item--active .cqa-nav-sub-label{color:#fbfcff;font-weight:600}.cqa-nav-sub-item--active:hover{background:#8a8cf4;color:#fbfcff}.cqa-nav-sub-item--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.cqa-nav-sub-icon{width:15px;height:15px;flex-shrink:0;display:flex;align-items:center;justify-content:center;opacity:.92;font-size:13px;color:inherit}.cqa-nav-sub-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:inherit}.cqa-nav-sub-badge{font-size:11px;font-weight:600;padding:1px 7px;border-radius:999px;flex-shrink:0}.cqa-nav-sub-badge--new{background:#feecbd;color:#7e6012;border:1px solid #fddf92}\n"], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
12455
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: NavSubItemComponent, decorators: [{
12456
+ type: Component,
12457
+ args: [{ selector: 'cqa-nav-sub-item', template: "<div class=\"cqa-nav-surface\">\n <button\n class=\"cqa-nav-sub-item\"\n [class.cqa-nav-sub-item--active]=\"isActive\"\n [class.cqa-nav-sub-item--disabled]=\"item?.disabled\"\n (click)=\"onClick()\"\n type=\"button\">\n\n <span class=\"cqa-nav-sub-icon\">\n <i [class]=\"item?.iconClass\"></i>\n </span>\n\n <span class=\"cqa-nav-sub-label\">{{ item?.label }}</span>\n\n <span *ngIf=\"item?.isNew\" class=\"cqa-nav-sub-badge cqa-nav-sub-badge--new\">New</span>\n </button>\n</div>\n", styles: ["@charset \"UTF-8\";.cqa-nav-surface{display:block;width:100%}.cqa-nav-sub-item{display:flex;align-items:center;gap:10px;padding:7px 10px;margin:0;border-radius:7px;color:#d8d9fc;font-size:12px;font-weight:400;line-height:normal;width:100%;text-align:left;background:transparent;border:none;cursor:pointer;transition:background .12s,color .12s;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif}.cqa-nav-sub-item:hover:not(.cqa-nav-sub-item--active){background:rgba(255,255,255,.1);color:#fff}.cqa-nav-sub-item--active{background:#8a8cf4;color:#fbfcff;font-weight:600}.cqa-nav-sub-item--active .cqa-nav-sub-icon{opacity:1;color:#fbfcff}.cqa-nav-sub-item--active .cqa-nav-sub-label{color:#fbfcff;font-weight:600}.cqa-nav-sub-item--active:hover{background:#8a8cf4;color:#fbfcff}.cqa-nav-sub-item--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.cqa-nav-sub-icon{width:15px;height:15px;flex-shrink:0;display:flex;align-items:center;justify-content:center;opacity:.92;font-size:13px;color:inherit}.cqa-nav-sub-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:inherit}.cqa-nav-sub-badge{font-size:11px;font-weight:600;padding:1px 7px;border-radius:999px;flex-shrink:0}.cqa-nav-sub-badge--new{background:#feecbd;color:#7e6012;border:1px solid #fddf92}\n"] }]
12458
+ }], propDecorators: { item: [{
12459
+ type: Input
12460
+ }], isActive: [{
12461
+ type: Input
12462
+ }], itemClick: [{
12463
+ type: Output
12464
+ }] } });
12465
+
12466
+ class NavMenuComponent {
12467
+ constructor() {
12468
+ this.items = [];
12469
+ this.activeId = '';
12470
+ this.isExpanded = false;
12471
+ /** IDs of parent nav items whose sub-menus are currently open */
12472
+ this.openParents = [];
12473
+ this.itemClick = new EventEmitter();
12474
+ }
12475
+ isSection(item) {
12476
+ return isNavSection(item);
12477
+ }
12478
+ asNavItem(item) {
12479
+ return item;
12480
+ }
12481
+ isItemActive(item) {
12482
+ if (item.id === this.activeId)
12483
+ return true;
12484
+ if (item.children) {
12485
+ return item.children.some(c => c.id === this.activeId);
12486
+ }
12487
+ return false;
12488
+ }
12489
+ isParentOpen(item) {
12490
+ return this.openParents.includes(item.id);
12491
+ }
12492
+ isChildActive(childId) {
12493
+ return childId === this.activeId;
12494
+ }
12495
+ onItemClick(id) {
12496
+ this.itemClick.emit(id);
12497
+ }
12498
+ }
12499
+ NavMenuComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: NavMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
12500
+ NavMenuComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: NavMenuComponent, selector: "cqa-nav-menu", inputs: { items: "items", activeId: "activeId", isExpanded: "isExpanded", openParents: "openParents" }, outputs: { itemClick: "itemClick" }, ngImport: i0, template: "<div class=\"cqa-nav-menu-outer\">\n <nav class=\"cqa-nav-menu\" [class.cqa-nav-menu--collapsed]=\"!isExpanded\">\n <ng-container *ngFor=\"let item of items\">\n\n <!-- Section header (expanded only \u2014 collapsed rail shows icons only) -->\n <ng-container *ngIf=\"isSection(item) && isExpanded\">\n <div class=\"cqa-nav-section\">\n <span class=\"cqa-nav-section-label\">{{ item.label }}</span>\n </div>\n </ng-container>\n\n <!-- Nav item -->\n <ng-container *ngIf=\"!isSection(item)\">\n <cqa-nav-item\n [item]=\"asNavItem(item)\"\n [isActive]=\"isItemActive(asNavItem(item))\"\n [isExpanded]=\"isExpanded\"\n [isOpen]=\"isParentOpen(asNavItem(item))\"\n [activeNavId]=\"activeId\"\n (itemClick)=\"onItemClick($event)\">\n </cqa-nav-item>\n\n <!-- Sub-menu (only rendered when sidebar is expanded) -->\n <div\n *ngIf=\"isExpanded && asNavItem(item).children?.length\"\n class=\"cqa-nav-children\"\n [class.cqa-nav-children--open]=\"isParentOpen(asNavItem(item))\">\n <cqa-nav-sub-item\n *ngFor=\"let child of asNavItem(item).children\"\n [item]=\"child\"\n [isActive]=\"isChildActive(child.id)\"\n (itemClick)=\"onItemClick($event)\">\n </cqa-nav-sub-item>\n </div>\n </ng-container>\n\n </ng-container>\n </nav>\n</div>\n", styles: [":host{display:flex;flex-direction:column;flex:1 1 0;min-height:0;overflow:hidden;width:100%}.cqa-nav-menu-outer{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;overflow:hidden;width:100%}.cqa-nav-menu{flex:1 1 auto;overflow-y:auto;overflow-x:hidden;padding:4px 0 8px;min-height:0;overscroll-behavior:contain}.cqa-nav-menu::-webkit-scrollbar{width:4px}.cqa-nav-menu::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15);border-radius:2px}.cqa-nav-menu--collapsed{overflow-x:visible}.cqa-nav-section{font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;font-size:10px;font-weight:700;letter-spacing:.1em;color:#ffffff8c;padding:14px 18px 6px;text-transform:uppercase;overflow:hidden;transition:opacity .16s 80ms,padding .16s,font-size .16s;opacity:1}.cqa-nav-children{margin:1px 21px;padding:1px 0 1px 15px;border-left:1px solid rgba(255,255,255,.18);overflow:hidden;transition:max-height .25s ease-out,opacity .18s,margin .2s;max-height:0;opacity:0;display:flex;flex-direction:column;gap:1px}.cqa-nav-children--open{max-height:320px;opacity:1}\n"], components: [{ type: NavItemComponent, selector: "cqa-nav-item", inputs: ["item", "isActive", "isExpanded", "isOpen", "activeNavId"], outputs: ["itemClick"] }, { type: NavSubItemComponent, selector: "cqa-nav-sub-item", inputs: ["item", "isActive"], outputs: ["itemClick"] }], directives: [{ type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
12501
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: NavMenuComponent, decorators: [{
12502
+ type: Component,
12503
+ args: [{ selector: 'cqa-nav-menu', template: "<div class=\"cqa-nav-menu-outer\">\n <nav class=\"cqa-nav-menu\" [class.cqa-nav-menu--collapsed]=\"!isExpanded\">\n <ng-container *ngFor=\"let item of items\">\n\n <!-- Section header (expanded only \u2014 collapsed rail shows icons only) -->\n <ng-container *ngIf=\"isSection(item) && isExpanded\">\n <div class=\"cqa-nav-section\">\n <span class=\"cqa-nav-section-label\">{{ item.label }}</span>\n </div>\n </ng-container>\n\n <!-- Nav item -->\n <ng-container *ngIf=\"!isSection(item)\">\n <cqa-nav-item\n [item]=\"asNavItem(item)\"\n [isActive]=\"isItemActive(asNavItem(item))\"\n [isExpanded]=\"isExpanded\"\n [isOpen]=\"isParentOpen(asNavItem(item))\"\n [activeNavId]=\"activeId\"\n (itemClick)=\"onItemClick($event)\">\n </cqa-nav-item>\n\n <!-- Sub-menu (only rendered when sidebar is expanded) -->\n <div\n *ngIf=\"isExpanded && asNavItem(item).children?.length\"\n class=\"cqa-nav-children\"\n [class.cqa-nav-children--open]=\"isParentOpen(asNavItem(item))\">\n <cqa-nav-sub-item\n *ngFor=\"let child of asNavItem(item).children\"\n [item]=\"child\"\n [isActive]=\"isChildActive(child.id)\"\n (itemClick)=\"onItemClick($event)\">\n </cqa-nav-sub-item>\n </div>\n </ng-container>\n\n </ng-container>\n </nav>\n</div>\n", styles: [":host{display:flex;flex-direction:column;flex:1 1 0;min-height:0;overflow:hidden;width:100%}.cqa-nav-menu-outer{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;overflow:hidden;width:100%}.cqa-nav-menu{flex:1 1 auto;overflow-y:auto;overflow-x:hidden;padding:4px 0 8px;min-height:0;overscroll-behavior:contain}.cqa-nav-menu::-webkit-scrollbar{width:4px}.cqa-nav-menu::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15);border-radius:2px}.cqa-nav-menu--collapsed{overflow-x:visible}.cqa-nav-section{font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;font-size:10px;font-weight:700;letter-spacing:.1em;color:#ffffff8c;padding:14px 18px 6px;text-transform:uppercase;overflow:hidden;transition:opacity .16s 80ms,padding .16s,font-size .16s;opacity:1}.cqa-nav-children{margin:1px 21px;padding:1px 0 1px 15px;border-left:1px solid rgba(255,255,255,.18);overflow:hidden;transition:max-height .25s ease-out,opacity .18s,margin .2s;max-height:0;opacity:0;display:flex;flex-direction:column;gap:1px}.cqa-nav-children--open{max-height:320px;opacity:1}\n"] }]
12504
+ }], propDecorators: { items: [{
12505
+ type: Input
12506
+ }], activeId: [{
12507
+ type: Input
12508
+ }], isExpanded: [{
12509
+ type: Input
12510
+ }], openParents: [{
12511
+ type: Input
12512
+ }], itemClick: [{
12513
+ type: Output
12514
+ }] } });
12515
+
12516
+ class SafeHtmlPipe {
12517
+ constructor(sanitizer) {
12518
+ this.sanitizer = sanitizer;
12519
+ }
12520
+ transform(value) {
12521
+ const str = value != null ? String(value) : '';
12522
+ return this.sanitizer.bypassSecurityTrustHtml(str);
12523
+ }
12524
+ }
12525
+ SafeHtmlPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SafeHtmlPipe, deps: [{ token: i1$2.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe });
12526
+ SafeHtmlPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SafeHtmlPipe, name: "cqaSafeHtml" });
12527
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SafeHtmlPipe, decorators: [{
12528
+ type: Pipe,
12529
+ args: [{ name: 'cqaSafeHtml' }]
12530
+ }], ctorParameters: function () { return [{ type: i1$2.DomSanitizer }]; } });
12531
+
12532
+ class ProfileMenuComponent {
12533
+ constructor(overlay, viewContainerRef) {
12534
+ this.overlay = overlay;
12535
+ this.viewContainerRef = viewContainerRef;
12536
+ this.entries = [];
12537
+ this.anchor = null;
12538
+ this.itemClick = new EventEmitter();
12539
+ this.dismissed = new EventEmitter();
12540
+ this.overlayRef = null;
12541
+ this.keySub = null;
12542
+ this.backdropSub = null;
12543
+ this.viewInitialized = false;
12544
+ this.isDivider = isProfileMenuDivider;
12545
+ this.trackByEntry = (index, _entry) => index;
12546
+ }
12547
+ ngAfterViewInit() {
12548
+ this.viewInitialized = true;
12549
+ if (this.anchor) {
12550
+ this.openOverlay();
12551
+ }
12552
+ }
12553
+ ngOnChanges(changes) {
12554
+ if (!this.viewInitialized || !changes['anchor'])
12555
+ return;
12556
+ if (this.anchor) {
12557
+ this.openOverlay();
12558
+ }
12559
+ else {
12560
+ this.closeOverlay();
12561
+ }
12562
+ }
12563
+ ngOnDestroy() {
12564
+ this.closeOverlay();
12565
+ }
12566
+ /** Narrowing helper for the template — Angular's template type checker can't
12567
+ * follow our custom type guard through `*ngIf-else`, so we surface a typed cast
12568
+ * via this method instead. */
12569
+ asItem(entry) {
12570
+ return isProfileMenuDivider(entry) ? null : entry;
12571
+ }
12572
+ onItemClick(item) {
12573
+ if (item.disabled) {
12574
+ return;
12575
+ }
12576
+ this.itemClick.emit(item.id);
12577
+ }
12578
+ openOverlay() {
12579
+ if (!this.anchor) {
12580
+ return;
12581
+ }
12582
+ this.closeOverlay();
12583
+ // Popover floats out to the right of the profile card, bottom-aligned with the card.
12584
+ // `withPush(false)` is critical — otherwise CDK slides the overlay back over the sidebar
12585
+ // when its viewport calculation thinks the popover doesn't fit (e.g. in narrow iframes).
12586
+ const positions = [
12587
+ { originX: 'end', originY: 'bottom', overlayX: 'start', overlayY: 'bottom', offsetX: 0, offsetY: 0 },
12588
+ { originX: 'end', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetX: 0, offsetY: -4 },
12589
+ ];
12590
+ const positionStrategy = this.overlay
12591
+ .position()
12592
+ .flexibleConnectedTo(this.anchor)
12593
+ .withPositions(positions)
12594
+ .withFlexibleDimensions(false)
12595
+ .withViewportMargin(8)
12596
+ .withPush(false);
12597
+ this.overlayRef = this.overlay.create({
12598
+ positionStrategy,
12599
+ scrollStrategy: this.overlay.scrollStrategies.reposition(),
12600
+ hasBackdrop: true,
12601
+ backdropClass: 'cdk-overlay-transparent-backdrop',
12602
+ panelClass: 'cqa-profile-menu-panel',
12603
+ });
12604
+ const portal = new TemplatePortal(this.popoverTpl, this.viewContainerRef);
12605
+ this.overlayRef.attach(portal);
12606
+ this.backdropSub = this.overlayRef.backdropClick().subscribe(() => this.dismissed.emit());
12607
+ this.keySub = this.overlayRef.keydownEvents().subscribe((event) => {
12608
+ if (event.key === 'Escape') {
12609
+ event.preventDefault();
12610
+ this.dismissed.emit();
12611
+ }
12612
+ });
12613
+ }
12614
+ closeOverlay() {
12615
+ this.backdropSub?.unsubscribe();
12616
+ this.backdropSub = null;
12617
+ this.keySub?.unsubscribe();
12618
+ this.keySub = null;
12619
+ if (this.overlayRef) {
12620
+ this.overlayRef.dispose();
12621
+ this.overlayRef = null;
12622
+ }
12623
+ }
12624
+ }
12625
+ ProfileMenuComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ProfileMenuComponent, deps: [{ token: i1$6.Overlay }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component });
12626
+ ProfileMenuComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ProfileMenuComponent, selector: "cqa-profile-menu", inputs: { user: "user", entries: "entries", anchor: "anchor", popoverId: "popoverId" }, outputs: { itemClick: "itemClick", dismissed: "dismissed" }, viewQueries: [{ propertyName: "popoverTpl", first: true, predicate: ["popoverTpl"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<ng-template #popoverTpl>\n <div class=\"cqa-pm\" [attr.id]=\"popoverId\" role=\"menu\" aria-orientation=\"vertical\">\n <!-- ===== Header ===== -->\n <div class=\"cqa-pm-header\">\n <div class=\"cqa-pm-avatar\" [style.background]=\"user?.avatarColor || null\">\n {{ user?.initials }}\n </div>\n <div class=\"cqa-pm-identity\">\n <span class=\"cqa-pm-name\" [title]=\"user?.name\">{{ user?.name }}</span>\n <span *ngIf=\"user?.email\" class=\"cqa-pm-email\" [title]=\"user?.email\">{{ user?.email }}</span>\n <span\n *ngIf=\"user?.badge?.label\"\n class=\"cqa-pm-badge\"\n [class.cqa-pm-badge--admin]=\"(user?.badge?.variant || 'admin') === 'admin'\"\n [class.cqa-pm-badge--default]=\"user?.badge?.variant === 'default'\">\n {{ user?.badge?.label }}\n </span>\n </div>\n </div>\n\n <div class=\"cqa-pm-divider\"></div>\n\n <!-- ===== Entries ===== -->\n <ul class=\"cqa-pm-list\">\n <ng-container *ngFor=\"let entry of entries; trackBy: trackByEntry\">\n <li *ngIf=\"isDivider(entry); else itemTpl\" class=\"cqa-pm-list-divider\" role=\"separator\"></li>\n <ng-template #itemTpl>\n <li *ngIf=\"asItem(entry) as item\">\n <button\n type=\"button\"\n class=\"cqa-pm-item\"\n [class.cqa-pm-item--danger]=\"item.variant === 'danger'\"\n [class.cqa-pm-item--disabled]=\"item.disabled\"\n [disabled]=\"item.disabled\"\n role=\"menuitem\"\n (click)=\"onItemClick(item)\">\n <span\n *ngIf=\"item.iconSvg || item.iconClass\"\n class=\"cqa-pm-item-icon\"\n aria-hidden=\"true\">\n <span\n *ngIf=\"item.iconSvg; else fontIcon\"\n [innerHTML]=\"item.iconSvg | cqaSafeHtml\">\n </span>\n <ng-template #fontIcon>\n <i *ngIf=\"item.iconClass\" [ngClass]=\"item.iconClass\"></i>\n </ng-template>\n </span>\n <span class=\"cqa-pm-item-label\">{{ item.label }}</span>\n <span *ngIf=\"item.shortcut\" class=\"cqa-pm-item-shortcut\">{{ item.shortcut }}</span>\n </button>\n </li>\n </ng-template>\n </ng-container>\n </ul>\n </div>\n</ng-template>\n", styles: ["::ng-deep .cqa-profile-menu-panel{z-index:1200}.cqa-pm{width:270px;background:#fbfcff;border-radius:12px;box-shadow:0 0 0 1px #0f12a80a,0 12px 32px #0f12a82e;padding:6px;font-family:inherit;color:#161617;-webkit-user-select:none;user-select:none;animation:cqaPmFadeIn .12s cubic-bezier(.16,1,.3,1)}@keyframes cqaPmFadeIn{0%{opacity:0;transform:translateY(2px) scale(.985)}to{opacity:1;transform:translateY(0) scale(1)}}.cqa-pm-header{display:flex;align-items:flex-start;gap:10px;padding:10px 10px 12px}.cqa-pm-avatar{width:38px;height:38px;border-radius:50%;background:linear-gradient(135deg,#f472b6,#db2777);color:#fff;font-size:14px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0;letter-spacing:.2px}.cqa-pm-identity{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.cqa-pm-name{font-size:14px;font-weight:600;line-height:1;color:#161617;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cqa-pm-email{font-size:11.5px;font-weight:400;line-height:1;color:#6d6d74;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cqa-pm-badge{display:inline-flex;align-items:center;align-self:flex-start;padding:2px 7px;border-radius:999px;font-size:10px;font-weight:700;line-height:1;white-space:nowrap}.cqa-pm-badge--admin{background:rgba(99,102,241,.1);color:#1216cc}.cqa-pm-badge--default{background:#eef0f3;color:#374151}.cqa-pm-divider{height:1px;background:#f0f0f1;margin:0}.cqa-pm-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}.cqa-pm-list-divider{height:1px;background:#f0f0f1;margin:6px}.cqa-pm-item{width:100%;display:flex;align-items:center;gap:10px;padding:12px 10px 8px;background:transparent;border:none;border-radius:8px;cursor:pointer;font-family:inherit;font-size:13px;font-weight:400;line-height:1;color:#4c4c51;text-align:left;transition:background .12s,color .12s}.cqa-pm-item:hover:not(:disabled){background:#f4f5f7}.cqa-pm-item:focus-visible{outline:2px solid #4f46e5;outline-offset:1px}.cqa-pm-item--danger,.cqa-pm-item--danger .cqa-pm-item-icon{color:#e23a3a}.cqa-pm-item--danger:hover:not(:disabled){background:#fbeaea}.cqa-pm-item--disabled,.cqa-pm-item:disabled{cursor:not-allowed;opacity:.5}.cqa-pm-item-icon{width:16px;height:16px;font-size:16px;color:#161617a6;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}.cqa-pm-item-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cqa-pm-item-shortcut{background:#eef0f3;color:#6b7280;font-size:11px;font-weight:600;line-height:16px;padding:1px 6px;border-radius:4px;flex-shrink:0}\n"], 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"] }], pipes: { "cqaSafeHtml": SafeHtmlPipe } });
12627
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ProfileMenuComponent, decorators: [{
12628
+ type: Component,
12629
+ args: [{ selector: 'cqa-profile-menu', template: "<ng-template #popoverTpl>\n <div class=\"cqa-pm\" [attr.id]=\"popoverId\" role=\"menu\" aria-orientation=\"vertical\">\n <!-- ===== Header ===== -->\n <div class=\"cqa-pm-header\">\n <div class=\"cqa-pm-avatar\" [style.background]=\"user?.avatarColor || null\">\n {{ user?.initials }}\n </div>\n <div class=\"cqa-pm-identity\">\n <span class=\"cqa-pm-name\" [title]=\"user?.name\">{{ user?.name }}</span>\n <span *ngIf=\"user?.email\" class=\"cqa-pm-email\" [title]=\"user?.email\">{{ user?.email }}</span>\n <span\n *ngIf=\"user?.badge?.label\"\n class=\"cqa-pm-badge\"\n [class.cqa-pm-badge--admin]=\"(user?.badge?.variant || 'admin') === 'admin'\"\n [class.cqa-pm-badge--default]=\"user?.badge?.variant === 'default'\">\n {{ user?.badge?.label }}\n </span>\n </div>\n </div>\n\n <div class=\"cqa-pm-divider\"></div>\n\n <!-- ===== Entries ===== -->\n <ul class=\"cqa-pm-list\">\n <ng-container *ngFor=\"let entry of entries; trackBy: trackByEntry\">\n <li *ngIf=\"isDivider(entry); else itemTpl\" class=\"cqa-pm-list-divider\" role=\"separator\"></li>\n <ng-template #itemTpl>\n <li *ngIf=\"asItem(entry) as item\">\n <button\n type=\"button\"\n class=\"cqa-pm-item\"\n [class.cqa-pm-item--danger]=\"item.variant === 'danger'\"\n [class.cqa-pm-item--disabled]=\"item.disabled\"\n [disabled]=\"item.disabled\"\n role=\"menuitem\"\n (click)=\"onItemClick(item)\">\n <span\n *ngIf=\"item.iconSvg || item.iconClass\"\n class=\"cqa-pm-item-icon\"\n aria-hidden=\"true\">\n <span\n *ngIf=\"item.iconSvg; else fontIcon\"\n [innerHTML]=\"item.iconSvg | cqaSafeHtml\">\n </span>\n <ng-template #fontIcon>\n <i *ngIf=\"item.iconClass\" [ngClass]=\"item.iconClass\"></i>\n </ng-template>\n </span>\n <span class=\"cqa-pm-item-label\">{{ item.label }}</span>\n <span *ngIf=\"item.shortcut\" class=\"cqa-pm-item-shortcut\">{{ item.shortcut }}</span>\n </button>\n </li>\n </ng-template>\n </ng-container>\n </ul>\n </div>\n</ng-template>\n", styles: ["::ng-deep .cqa-profile-menu-panel{z-index:1200}.cqa-pm{width:270px;background:#fbfcff;border-radius:12px;box-shadow:0 0 0 1px #0f12a80a,0 12px 32px #0f12a82e;padding:6px;font-family:inherit;color:#161617;-webkit-user-select:none;user-select:none;animation:cqaPmFadeIn .12s cubic-bezier(.16,1,.3,1)}@keyframes cqaPmFadeIn{0%{opacity:0;transform:translateY(2px) scale(.985)}to{opacity:1;transform:translateY(0) scale(1)}}.cqa-pm-header{display:flex;align-items:flex-start;gap:10px;padding:10px 10px 12px}.cqa-pm-avatar{width:38px;height:38px;border-radius:50%;background:linear-gradient(135deg,#f472b6,#db2777);color:#fff;font-size:14px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0;letter-spacing:.2px}.cqa-pm-identity{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.cqa-pm-name{font-size:14px;font-weight:600;line-height:1;color:#161617;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cqa-pm-email{font-size:11.5px;font-weight:400;line-height:1;color:#6d6d74;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cqa-pm-badge{display:inline-flex;align-items:center;align-self:flex-start;padding:2px 7px;border-radius:999px;font-size:10px;font-weight:700;line-height:1;white-space:nowrap}.cqa-pm-badge--admin{background:rgba(99,102,241,.1);color:#1216cc}.cqa-pm-badge--default{background:#eef0f3;color:#374151}.cqa-pm-divider{height:1px;background:#f0f0f1;margin:0}.cqa-pm-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}.cqa-pm-list-divider{height:1px;background:#f0f0f1;margin:6px}.cqa-pm-item{width:100%;display:flex;align-items:center;gap:10px;padding:12px 10px 8px;background:transparent;border:none;border-radius:8px;cursor:pointer;font-family:inherit;font-size:13px;font-weight:400;line-height:1;color:#4c4c51;text-align:left;transition:background .12s,color .12s}.cqa-pm-item:hover:not(:disabled){background:#f4f5f7}.cqa-pm-item:focus-visible{outline:2px solid #4f46e5;outline-offset:1px}.cqa-pm-item--danger,.cqa-pm-item--danger .cqa-pm-item-icon{color:#e23a3a}.cqa-pm-item--danger:hover:not(:disabled){background:#fbeaea}.cqa-pm-item--disabled,.cqa-pm-item:disabled{cursor:not-allowed;opacity:.5}.cqa-pm-item-icon{width:16px;height:16px;font-size:16px;color:#161617a6;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}.cqa-pm-item-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cqa-pm-item-shortcut{background:#eef0f3;color:#6b7280;font-size:11px;font-weight:600;line-height:16px;padding:1px 6px;border-radius:4px;flex-shrink:0}\n"] }]
12630
+ }], ctorParameters: function () { return [{ type: i1$6.Overlay }, { type: i0.ViewContainerRef }]; }, propDecorators: { user: [{
12631
+ type: Input
12632
+ }], entries: [{
12633
+ type: Input
12634
+ }], anchor: [{
12635
+ type: Input
12636
+ }], popoverId: [{
12637
+ type: Input
12638
+ }], itemClick: [{
12639
+ type: Output
12640
+ }], dismissed: [{
12641
+ type: Output
12642
+ }], popoverTpl: [{
12643
+ type: ViewChild,
12644
+ args: ['popoverTpl', { static: true }]
12645
+ }] } });
12646
+
12647
+ class WorkspaceMenuComponent {
12648
+ constructor(overlay, viewContainerRef) {
12649
+ this.overlay = overlay;
12650
+ this.viewContainerRef = viewContainerRef;
12651
+ this.workspaces = [];
12652
+ this.anchor = null;
12653
+ this.workspaceSelected = new EventEmitter();
12654
+ this.manageWorkspacesClick = new EventEmitter();
12655
+ this.dismissed = new EventEmitter();
12656
+ this.overlayRef = null;
12657
+ this.keySub = null;
12658
+ this.backdropSub = null;
12659
+ this.viewInitialized = false;
12660
+ this.trackByWs = (_index, item) => item.id;
12661
+ }
12662
+ ngAfterViewInit() {
12663
+ this.viewInitialized = true;
12664
+ if (this.anchor) {
12665
+ this.openOverlay();
12666
+ }
12667
+ }
12668
+ ngOnChanges(changes) {
12669
+ if (!this.viewInitialized || !changes['anchor'])
12670
+ return;
12671
+ if (this.anchor) {
12672
+ this.openOverlay();
12673
+ }
12674
+ else {
12675
+ this.closeOverlay();
12676
+ }
12677
+ }
12678
+ ngOnDestroy() {
12679
+ this.closeOverlay();
12680
+ }
12681
+ onItemClick(item) {
12682
+ this.workspaceSelected.emit(item.id);
12683
+ }
12684
+ onManageClick() {
12685
+ this.manageWorkspacesClick.emit();
12686
+ }
12687
+ openOverlay() {
12688
+ if (!this.anchor) {
12689
+ return;
12690
+ }
12691
+ this.closeOverlay();
12692
+ // Popover floats out to the right of the workspace button, top-aligned with the button.
12693
+ // Both position pairs pin overlayY: 'top' so the popover always extends downward (mirror of
12694
+ // profile-menu, which always extends upward from a bottom-anchored card).
12695
+ // `withPush(false)` is critical — otherwise CDK slides the overlay back over the sidebar
12696
+ // when its viewport calculation thinks the popover doesn't fit.
12697
+ const positions = [
12698
+ { originX: 'end', originY: 'top', overlayX: 'start', overlayY: 'top', offsetX: 0, offsetY: 0 },
12699
+ { originX: 'end', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetX: 0, offsetY: 4 },
12700
+ ];
12701
+ const positionStrategy = this.overlay
12702
+ .position()
12703
+ .flexibleConnectedTo(this.anchor)
12704
+ .withPositions(positions)
12705
+ .withFlexibleDimensions(false)
12706
+ .withViewportMargin(8)
12707
+ .withPush(false);
12708
+ this.overlayRef = this.overlay.create({
12709
+ positionStrategy,
12710
+ scrollStrategy: this.overlay.scrollStrategies.reposition(),
12711
+ hasBackdrop: true,
12712
+ backdropClass: 'cdk-overlay-transparent-backdrop',
12713
+ panelClass: 'cqa-workspace-menu-panel',
12714
+ });
12715
+ const portal = new TemplatePortal(this.popoverTpl, this.viewContainerRef);
12716
+ this.overlayRef.attach(portal);
12717
+ this.backdropSub = this.overlayRef.backdropClick().subscribe(() => this.dismissed.emit());
12718
+ this.keySub = this.overlayRef.keydownEvents().subscribe((event) => {
12719
+ if (event.key === 'Escape') {
12720
+ event.preventDefault();
12721
+ this.dismissed.emit();
12722
+ }
12723
+ });
12724
+ }
12725
+ closeOverlay() {
12726
+ this.backdropSub?.unsubscribe();
12727
+ this.backdropSub = null;
12728
+ this.keySub?.unsubscribe();
12729
+ this.keySub = null;
12730
+ if (this.overlayRef) {
12731
+ this.overlayRef.dispose();
12732
+ this.overlayRef = null;
12733
+ }
12734
+ }
12735
+ }
12736
+ WorkspaceMenuComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: WorkspaceMenuComponent, deps: [{ token: i1$6.Overlay }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component });
12737
+ WorkspaceMenuComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: WorkspaceMenuComponent, selector: "cqa-workspace-menu", inputs: { workspaces: "workspaces", currentWorkspaceId: "currentWorkspaceId", workspaceName: "workspaceName", anchor: "anchor", popoverId: "popoverId" }, outputs: { workspaceSelected: "workspaceSelected", manageWorkspacesClick: "manageWorkspacesClick", dismissed: "dismissed" }, viewQueries: [{ propertyName: "popoverTpl", first: true, predicate: ["popoverTpl"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<ng-template #popoverTpl>\n <div class=\"cqa-wm\" [attr.id]=\"popoverId\" role=\"dialog\" aria-label=\"Switch workspace\">\n <header class=\"cqa-wm-header\">\n <h2 class=\"cqa-wm-heading\">Workspaces in {{ workspaceName }}</h2>\n </header>\n\n <ul class=\"cqa-wm-list\" role=\"listbox\">\n <li *ngFor=\"let ws of workspaces; trackBy: trackByWs\">\n <button\n type=\"button\"\n class=\"cqa-wm-item\"\n [class.cqa-wm-item--active]=\"ws.id === currentWorkspaceId\"\n role=\"option\"\n [attr.aria-selected]=\"ws.id === currentWorkspaceId\"\n (click)=\"onItemClick(ws)\">\n <span class=\"cqa-wm-avatar\" [style.background]=\"ws.avatarColor || null\">\n <img *ngIf=\"ws.logoUrl; else initialsTpl\" class=\"cqa-wm-logo\" [src]=\"ws.logoUrl\" [alt]=\"ws.name\"/>\n <ng-template #initialsTpl>\n <span class=\"cqa-wm-initials\">{{ ws.initials }}</span>\n </ng-template>\n </span>\n <span class=\"cqa-wm-text\">\n <span class=\"cqa-wm-name\" [title]=\"ws.name\">{{ ws.name }}</span>\n <span *ngIf=\"ws.subtitle\" class=\"cqa-wm-subtitle\" [title]=\"ws.subtitle\">{{ ws.subtitle }}</span>\n </span>\n <span *ngIf=\"ws.id === currentWorkspaceId\" class=\"cqa-wm-check\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"14\" height=\"14\">\n <polyline points=\"3,8.5 6.5,12 13,4.5\"/>\n </svg>\n </span>\n </button>\n </li>\n </ul>\n\n <div class=\"cqa-wm-divider\"></div>\n\n <button type=\"button\" class=\"cqa-wm-footer\" (click)=\"onManageClick()\">\n <span class=\"cqa-wm-footer-icon\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"15\" height=\"15\">\n <circle cx=\"8\" cy=\"8\" r=\"2\"/>\n <path d=\"M13 8a5 5 0 0 0-.1-1l1.4-1-1.4-2.4-1.7.5a5 5 0 0 0-1.7-1L9 1H7l-.5 1.6a5 5 0 0 0-1.7 1L3.1 3.6 1.7 6l1.4 1A5 5 0 0 0 3 8a5 5 0 0 0 .1 1l-1.4 1L3.1 12.4l1.7-.5a5 5 0 0 0 1.7 1L7 15h2l.5-1.6a5 5 0 0 0 1.7-1l1.7.5L14.3 10 13 9a5 5 0 0 0 0-1z\"/>\n </svg>\n </span>\n <span class=\"cqa-wm-footer-label\">Workspace Management</span>\n </button>\n </div>\n</ng-template>\n", styles: ["::ng-deep .cqa-workspace-menu-panel{z-index:1200}.cqa-wm{width:270px;background:#fbfcff;border-radius:12px;box-shadow:0 0 0 1px #0f12a80a,0 12px 32px #0f12a82e;padding:6px;font-family:inherit;color:#161617;-webkit-user-select:none;user-select:none;animation:cqaWmFadeIn .12s cubic-bezier(.16,1,.3,1)}@keyframes cqaWmFadeIn{0%{opacity:0;transform:translateY(2px) scale(.985)}to{opacity:1;transform:translateY(0) scale(1)}}.cqa-wm-header{display:flex;align-items:center;min-height:36px;padding:4px 16px;border-bottom:1px solid #f0f0f1}.cqa-wm-heading{font-size:12px;font-weight:600;line-height:1;color:#99999e;margin:0}.cqa-wm-list{list-style:none;margin:0;padding:0;max-height:208px;overflow-y:auto;display:flex;flex-direction:column}.cqa-wm-list::-webkit-scrollbar{width:6px}.cqa-wm-list::-webkit-scrollbar-thumb{background:rgba(15,18,168,.16);border-radius:3px}.cqa-wm-list::-webkit-scrollbar-track{background:transparent}.cqa-wm-item{width:100%;display:flex;align-items:center;gap:11px;padding:8px 10px 12px;min-height:52px;background:transparent;border:none;border-radius:8px;cursor:pointer;text-align:left;font-family:inherit;color:#161617;transition:background .12s}.cqa-wm-item:hover{background:#f4f5f7}.cqa-wm-item:focus-visible{outline:2px solid #3f43ee;outline-offset:1px}.cqa-wm-item--active,.cqa-wm-item--active:hover{background:#d8d9fc}.cqa-wm-avatar{width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;flex-shrink:0;overflow:hidden;background:linear-gradient(135deg,#a78bfa,#6d28d9);box-shadow:0 1px 2px #0000001f;color:#fff}.cqa-wm-logo{width:100%;height:100%;object-fit:contain;display:block}.cqa-wm-initials{font-family:Nunito Sans,Inter,system-ui,sans-serif;font-size:14px;font-weight:800;letter-spacing:0;line-height:1;color:#fff}.cqa-wm-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.cqa-wm-name{font-size:13px;font-weight:600;line-height:16.2px;color:#161617;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cqa-wm-subtitle{font-size:11px;font-weight:400;line-height:1;color:#6d6d74;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cqa-wm-check{color:#3f43ee;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center}.cqa-wm-divider{height:1px;background:#f0f0f1;margin:0}.cqa-wm-footer{width:100%;display:flex;align-items:center;gap:10px;padding:9px 12px;background:transparent;border:none;border-radius:7px;cursor:pointer;font-family:inherit;font-size:13px;font-weight:400;line-height:1;color:#4c4c51;text-align:left;transition:background .12s}.cqa-wm-footer:hover{background:#f4f5f7}.cqa-wm-footer:focus-visible{outline:2px solid #3f43ee;outline-offset:1px}.cqa-wm-footer-icon{width:15px;height:15px;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;opacity:.7;color:currentColor}.cqa-wm-footer-label{flex:1;min-width:0}\n"], directives: [{ type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
12738
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: WorkspaceMenuComponent, decorators: [{
12739
+ type: Component,
12740
+ args: [{ selector: 'cqa-workspace-menu', template: "<ng-template #popoverTpl>\n <div class=\"cqa-wm\" [attr.id]=\"popoverId\" role=\"dialog\" aria-label=\"Switch workspace\">\n <header class=\"cqa-wm-header\">\n <h2 class=\"cqa-wm-heading\">Workspaces in {{ workspaceName }}</h2>\n </header>\n\n <ul class=\"cqa-wm-list\" role=\"listbox\">\n <li *ngFor=\"let ws of workspaces; trackBy: trackByWs\">\n <button\n type=\"button\"\n class=\"cqa-wm-item\"\n [class.cqa-wm-item--active]=\"ws.id === currentWorkspaceId\"\n role=\"option\"\n [attr.aria-selected]=\"ws.id === currentWorkspaceId\"\n (click)=\"onItemClick(ws)\">\n <span class=\"cqa-wm-avatar\" [style.background]=\"ws.avatarColor || null\">\n <img *ngIf=\"ws.logoUrl; else initialsTpl\" class=\"cqa-wm-logo\" [src]=\"ws.logoUrl\" [alt]=\"ws.name\"/>\n <ng-template #initialsTpl>\n <span class=\"cqa-wm-initials\">{{ ws.initials }}</span>\n </ng-template>\n </span>\n <span class=\"cqa-wm-text\">\n <span class=\"cqa-wm-name\" [title]=\"ws.name\">{{ ws.name }}</span>\n <span *ngIf=\"ws.subtitle\" class=\"cqa-wm-subtitle\" [title]=\"ws.subtitle\">{{ ws.subtitle }}</span>\n </span>\n <span *ngIf=\"ws.id === currentWorkspaceId\" class=\"cqa-wm-check\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"14\" height=\"14\">\n <polyline points=\"3,8.5 6.5,12 13,4.5\"/>\n </svg>\n </span>\n </button>\n </li>\n </ul>\n\n <div class=\"cqa-wm-divider\"></div>\n\n <button type=\"button\" class=\"cqa-wm-footer\" (click)=\"onManageClick()\">\n <span class=\"cqa-wm-footer-icon\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"15\" height=\"15\">\n <circle cx=\"8\" cy=\"8\" r=\"2\"/>\n <path d=\"M13 8a5 5 0 0 0-.1-1l1.4-1-1.4-2.4-1.7.5a5 5 0 0 0-1.7-1L9 1H7l-.5 1.6a5 5 0 0 0-1.7 1L3.1 3.6 1.7 6l1.4 1A5 5 0 0 0 3 8a5 5 0 0 0 .1 1l-1.4 1L3.1 12.4l1.7-.5a5 5 0 0 0 1.7 1L7 15h2l.5-1.6a5 5 0 0 0 1.7-1l1.7.5L14.3 10 13 9a5 5 0 0 0 0-1z\"/>\n </svg>\n </span>\n <span class=\"cqa-wm-footer-label\">Workspace Management</span>\n </button>\n </div>\n</ng-template>\n", styles: ["::ng-deep .cqa-workspace-menu-panel{z-index:1200}.cqa-wm{width:270px;background:#fbfcff;border-radius:12px;box-shadow:0 0 0 1px #0f12a80a,0 12px 32px #0f12a82e;padding:6px;font-family:inherit;color:#161617;-webkit-user-select:none;user-select:none;animation:cqaWmFadeIn .12s cubic-bezier(.16,1,.3,1)}@keyframes cqaWmFadeIn{0%{opacity:0;transform:translateY(2px) scale(.985)}to{opacity:1;transform:translateY(0) scale(1)}}.cqa-wm-header{display:flex;align-items:center;min-height:36px;padding:4px 16px;border-bottom:1px solid #f0f0f1}.cqa-wm-heading{font-size:12px;font-weight:600;line-height:1;color:#99999e;margin:0}.cqa-wm-list{list-style:none;margin:0;padding:0;max-height:208px;overflow-y:auto;display:flex;flex-direction:column}.cqa-wm-list::-webkit-scrollbar{width:6px}.cqa-wm-list::-webkit-scrollbar-thumb{background:rgba(15,18,168,.16);border-radius:3px}.cqa-wm-list::-webkit-scrollbar-track{background:transparent}.cqa-wm-item{width:100%;display:flex;align-items:center;gap:11px;padding:8px 10px 12px;min-height:52px;background:transparent;border:none;border-radius:8px;cursor:pointer;text-align:left;font-family:inherit;color:#161617;transition:background .12s}.cqa-wm-item:hover{background:#f4f5f7}.cqa-wm-item:focus-visible{outline:2px solid #3f43ee;outline-offset:1px}.cqa-wm-item--active,.cqa-wm-item--active:hover{background:#d8d9fc}.cqa-wm-avatar{width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;flex-shrink:0;overflow:hidden;background:linear-gradient(135deg,#a78bfa,#6d28d9);box-shadow:0 1px 2px #0000001f;color:#fff}.cqa-wm-logo{width:100%;height:100%;object-fit:contain;display:block}.cqa-wm-initials{font-family:Nunito Sans,Inter,system-ui,sans-serif;font-size:14px;font-weight:800;letter-spacing:0;line-height:1;color:#fff}.cqa-wm-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.cqa-wm-name{font-size:13px;font-weight:600;line-height:16.2px;color:#161617;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cqa-wm-subtitle{font-size:11px;font-weight:400;line-height:1;color:#6d6d74;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cqa-wm-check{color:#3f43ee;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center}.cqa-wm-divider{height:1px;background:#f0f0f1;margin:0}.cqa-wm-footer{width:100%;display:flex;align-items:center;gap:10px;padding:9px 12px;background:transparent;border:none;border-radius:7px;cursor:pointer;font-family:inherit;font-size:13px;font-weight:400;line-height:1;color:#4c4c51;text-align:left;transition:background .12s}.cqa-wm-footer:hover{background:#f4f5f7}.cqa-wm-footer:focus-visible{outline:2px solid #3f43ee;outline-offset:1px}.cqa-wm-footer-icon{width:15px;height:15px;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;opacity:.7;color:currentColor}.cqa-wm-footer-label{flex:1;min-width:0}\n"] }]
12741
+ }], ctorParameters: function () { return [{ type: i1$6.Overlay }, { type: i0.ViewContainerRef }]; }, propDecorators: { workspaces: [{
12742
+ type: Input
12743
+ }], currentWorkspaceId: [{
12744
+ type: Input
12745
+ }], workspaceName: [{
12746
+ type: Input
12747
+ }], anchor: [{
12748
+ type: Input
12749
+ }], popoverId: [{
12750
+ type: Input
12751
+ }], workspaceSelected: [{
12752
+ type: Output
12753
+ }], manageWorkspacesClick: [{
12754
+ type: Output
12755
+ }], dismissed: [{
12756
+ type: Output
12757
+ }], popoverTpl: [{
12758
+ type: ViewChild,
12759
+ args: ['popoverTpl', { static: true }]
12760
+ }] } });
12761
+
12762
+ class SidebarComponent {
12763
+ constructor(sanitizer) {
12764
+ this.sanitizer = sanitizer;
12765
+ this.config = {};
12766
+ this.navItems = [];
12767
+ this.activeNavId = '';
12768
+ /** Parent item IDs to open by default (in addition to the one containing the active item). */
12769
+ this.initialOpenParentIds = [];
12770
+ /**
12771
+ * Menu entries shown inside the profile-menu popover. Provide at least one entry to
12772
+ * enable the popover; an empty array preserves the legacy `logoutClick` behavior.
12773
+ */
12774
+ this.profileMenuEntries = [];
12775
+ /**
12776
+ * Workspaces shown inside the workspace-switcher popover. Provide at least one entry
12777
+ * to enable the popover; an empty array preserves the legacy `workspaceSwitchClick`
12778
+ * behavior (single emit on click, no UI).
12779
+ */
12780
+ this.workspaces = [];
12781
+ this.navItemClick = new EventEmitter();
12782
+ this.ctaClick = new EventEmitter();
12783
+ this.searchClick = new EventEmitter();
12784
+ this.workspaceSwitchClick = new EventEmitter();
12785
+ this.logoutClick = new EventEmitter();
12786
+ this.notificationsClick = new EventEmitter();
12787
+ this.helpDocsClick = new EventEmitter();
12788
+ this.speakerClick = new EventEmitter();
12789
+ this.liveChatClick = new EventEmitter();
12790
+ this.expandedChange = new EventEmitter();
12791
+ /** Emits `ProfileMenuItem.id` when the user activates an entry in the profile popover. */
12792
+ this.profileMenuItemClick = new EventEmitter();
12793
+ /** Emits the workspace id when the user picks one from the workspace popover. */
12794
+ this.workspaceSelected = new EventEmitter();
12795
+ /** Emits when the user clicks the "Workspace Management" footer row. */
12796
+ this.manageWorkspacesClick = new EventEmitter();
12797
+ this.isExpanded = false;
12798
+ this.isPinned = false;
12799
+ this.openParents = [];
12800
+ this.isProfileMenuOpen = false;
12801
+ this.isWorkspaceMenuOpen = false;
12802
+ this.leaveCollapseTimer = null;
12803
+ }
12804
+ /**
12805
+ * Sanitizer bypass so `data:image/svg+xml;base64,…` URIs render in the workspace
12806
+ * avatar — Angular 13's default URL sanitizer rewrites them to `unsafe:…`.
12807
+ */
12808
+ get workspaceLogoSafe() {
12809
+ const url = this.config?.workspaceLogo;
12810
+ return url ? this.sanitizer.bypassSecurityTrustUrl(url) : null;
12811
+ }
12812
+ ngOnInit() {
12813
+ if (this.config?.defaultPinned) {
12814
+ this.isPinned = true;
12815
+ this.isExpanded = true;
12816
+ }
12817
+ if (this.initialOpenParentIds?.length) {
12818
+ this.openParents = [...this.initialOpenParentIds];
12819
+ }
12820
+ this.ensureActiveParentOpen();
12821
+ }
12822
+ ngOnDestroy() {
12823
+ this.clearLeaveCollapseTimer();
12824
+ }
12825
+ ngOnChanges(changes) {
12826
+ if (changes['activeNavId'] && this.activeNavId) {
12827
+ this.ensureActiveParentOpen();
12828
+ }
12829
+ }
12830
+ onProfileClick() {
12831
+ if (this.profileUser && this.profileMenuEntries?.length) {
12832
+ this.isProfileMenuOpen = !this.isProfileMenuOpen;
12833
+ return;
12834
+ }
12835
+ // Legacy single-action behaviour preserved for consumers that haven't migrated.
12836
+ this.logoutClick.emit();
12837
+ }
12838
+ onProfileMenuItemClick(id) {
12839
+ this.isProfileMenuOpen = false;
12840
+ this.profileMenuItemClick.emit(id);
12841
+ }
12842
+ onProfileMenuDismissed() {
12843
+ this.isProfileMenuOpen = false;
12844
+ }
12845
+ onWorkspaceClick() {
12846
+ if (this.workspaces?.length) {
12847
+ this.isWorkspaceMenuOpen = !this.isWorkspaceMenuOpen;
12848
+ return;
12849
+ }
12850
+ // Legacy single-emit behavior preserved for consumers that haven't migrated.
12851
+ this.workspaceSwitchClick.emit();
12852
+ }
12853
+ onWorkspaceMenuItemClick(id) {
12854
+ this.isWorkspaceMenuOpen = false;
12855
+ this.workspaceSelected.emit(id);
12856
+ }
12857
+ onWorkspaceMenuDismissed() {
12858
+ this.isWorkspaceMenuOpen = false;
12859
+ }
12860
+ onManageWorkspacesClick() {
12861
+ this.isWorkspaceMenuOpen = false;
12862
+ this.manageWorkspacesClick.emit();
12863
+ }
12864
+ /** Burger: wide sidebar without pinning — collapses on mouse leave. */
12865
+ openSidebar() {
12866
+ this.clearLeaveCollapseTimer();
12867
+ this.isExpanded = true;
12868
+ this.isPinned = false;
12869
+ this.expandedChange.emit(true);
12870
+ }
12871
+ /** Header collapse control: always closes and clears pin. */
12872
+ closeSidebar() {
12873
+ this.isExpanded = false;
12874
+ this.isPinned = false;
12875
+ this.clearLeaveCollapseTimer();
12876
+ this.expandedChange.emit(false);
12877
+ }
12878
+ pinSidebar() {
12879
+ this.isPinned = true;
12880
+ this.clearLeaveCollapseTimer();
12881
+ }
12882
+ /** Cancel delayed collapse when the pointer returns to the sidebar. */
12883
+ onAsideMouseEnter() {
12884
+ this.clearLeaveCollapseTimer();
12885
+ }
12886
+ /**
12887
+ * When expanded but not pinned, collapse after the pointer leaves the rail.
12888
+ * Skips scheduling if the pointer is moving into our CDK flyout / rail tooltip overlays.
12889
+ */
12890
+ onAsideMouseLeave(ev) {
12891
+ if (this.isPinned || !this.isExpanded)
12892
+ return;
12893
+ const related = ev.relatedTarget;
12894
+ if (this.isPointerEnteringSidebarOverlay(related))
12895
+ return;
12896
+ this.clearLeaveCollapseTimer();
12897
+ this.leaveCollapseTimer = setTimeout(() => {
12898
+ this.leaveCollapseTimer = null;
12899
+ if (!this.isPinned && this.isExpanded) {
12900
+ this.isExpanded = false;
12901
+ this.expandedChange.emit(false);
12902
+ }
12903
+ }, SidebarComponent.LEAVE_COLLAPSE_MS);
12904
+ }
12905
+ isPointerEnteringSidebarOverlay(node) {
12906
+ if (!(node instanceof Element))
12907
+ return false;
12908
+ return !!(node.closest('.cqa-nav-flyout-overlay') ||
12909
+ node.closest('.cqa-nav-flyout-overlay-pane') ||
12910
+ node.closest('.mat-tooltip.cqa-nav-rail-tooltip') ||
12911
+ node.closest('.mat-tooltip'));
12912
+ }
12913
+ clearLeaveCollapseTimer() {
12914
+ if (this.leaveCollapseTimer) {
12915
+ clearTimeout(this.leaveCollapseTimer);
12916
+ this.leaveCollapseTimer = null;
12917
+ }
12918
+ }
12919
+ onNavItemClick(id) {
12920
+ // Submenu leaf: always emit navigation (child id was wrongly treated as a parent for toggle).
12921
+ if (this.isChildNavId(id)) {
12922
+ this.navItemClick.emit(id);
12923
+ return;
12924
+ }
12925
+ const item = this.findTopLevelNavItem(id);
12926
+ if (!item) {
12927
+ this.navItemClick.emit(id);
12928
+ return;
12929
+ }
12930
+ if (item.children?.length) {
12931
+ // Parent item with children: toggle sub-menu when expanded, navigate when collapsed
12932
+ if (this.isExpanded) {
12933
+ this.toggleParent(id);
12934
+ }
12935
+ else {
12936
+ this.navItemClick.emit(id);
12937
+ }
12938
+ }
12939
+ else {
12940
+ this.navItemClick.emit(id);
12941
+ }
12942
+ }
12943
+ get workspaceInitial() {
12944
+ return this.config?.workspaceName?.charAt(0)?.toUpperCase() || 'W';
12945
+ }
12946
+ toggleParent(id) {
12947
+ const idx = this.openParents.indexOf(id);
12948
+ if (idx > -1) {
12949
+ this.openParents = this.openParents.filter(p => p !== id);
12950
+ }
12951
+ else {
12952
+ this.openParents = [...this.openParents, id];
12953
+ }
12954
+ }
12955
+ /** True if `id` matches a submenu row under some top-level nav item. */
12956
+ isChildNavId(id) {
12957
+ for (const item of this.navItems) {
12958
+ if (isNavSection(item))
12959
+ continue;
12960
+ if (item.children?.some((c) => c.id === id))
12961
+ return true;
12962
+ }
12963
+ return false;
12964
+ }
12965
+ findTopLevelNavItem(id) {
12966
+ for (const item of this.navItems) {
12967
+ if (!isNavSection(item) && item.id === id)
12968
+ return item;
12969
+ }
12970
+ return null;
12971
+ }
12972
+ ensureActiveParentOpen() {
12973
+ for (const item of this.navItems) {
12974
+ if (!isNavSection(item) && item.children) {
12975
+ const hasActiveChild = item.children.some(c => c.id === this.activeNavId);
12976
+ if (hasActiveChild && !this.openParents.includes(item.id)) {
12977
+ this.openParents = [...this.openParents, item.id];
12978
+ }
12979
+ }
12980
+ }
12981
+ }
12982
+ }
12983
+ SidebarComponent.LEAVE_COLLAPSE_MS = 220;
12984
+ SidebarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SidebarComponent, deps: [{ token: i1$2.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component });
12985
+ SidebarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: SidebarComponent, selector: "cqa-sidebar", inputs: { config: "config", navItems: "navItems", activeNavId: "activeNavId", initialOpenParentIds: "initialOpenParentIds", profileUser: "profileUser", profileMenuEntries: "profileMenuEntries", workspaces: "workspaces", currentWorkspaceId: "currentWorkspaceId" }, outputs: { navItemClick: "navItemClick", ctaClick: "ctaClick", searchClick: "searchClick", workspaceSwitchClick: "workspaceSwitchClick", logoutClick: "logoutClick", notificationsClick: "notificationsClick", helpDocsClick: "helpDocsClick", speakerClick: "speakerClick", liveChatClick: "liveChatClick", expandedChange: "expandedChange", profileMenuItemClick: "profileMenuItemClick", workspaceSelected: "workspaceSelected", manageWorkspacesClick: "manageWorkspacesClick" }, viewQueries: [{ propertyName: "profileAnchorRef", first: true, predicate: ["profileAnchor"], descendants: true }, { propertyName: "workspaceAnchorRef", first: true, predicate: ["workspaceAnchor"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div id=\"cqa-ui-root\" class=\"cqa-sb-root\">\n <aside\n class=\"cqa-sb\"\n [class.cqa-sb--expanded]=\"isExpanded\"\n (mouseenter)=\"onAsideMouseEnter()\"\n (mouseleave)=\"onAsideMouseLeave($event)\">\n\n <!-- ===== 1. Workspace header ===== -->\n <div #workspaceAnchor class=\"cqa-sb-header\" [class.cqa-sb-header--expanded]=\"isExpanded\">\n <!-- Collapsed: hamburger chip -->\n <button\n *ngIf=\"!isExpanded\"\n class=\"cqa-sb-burger\"\n (click)=\"openSidebar()\"\n type=\"button\"\n aria-label=\"Open sidebar\">\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.33\" stroke-linecap=\"round\"\n width=\"16\" height=\"16\">\n <line x1=\"2\" y1=\"4\" x2=\"14\" y2=\"4\"/>\n <line x1=\"2\" y1=\"8\" x2=\"14\" y2=\"8\"/>\n <line x1=\"2\" y1=\"12\" x2=\"14\" y2=\"12\"/>\n </svg>\n </button>\n\n <!-- Expanded: workspace selector + pin (unpinned) or close (pinned) -->\n <ng-container *ngIf=\"isExpanded\">\n <button class=\"cqa-sb-ws\" type=\"button\" (click)=\"onWorkspaceClick()\">\n <span class=\"cqa-sb-ws-main\">\n <span class=\"cqa-sb-ws-avatar\">\n <img *ngIf=\"workspaceLogoSafe; else defaultLogoTpl\"\n class=\"cqa-sb-ws-logo\"\n [src]=\"workspaceLogoSafe\"\n [alt]=\"config?.workspaceName || 'Workspace logo'\" />\n <ng-template #defaultLogoTpl>\n <svg class=\"cqa-sb-ws-default\" width=\"36\" height=\"36\" viewBox=\"0 0 40 40\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <rect x=\"2\" y=\"1\" width=\"36\" height=\"36\" rx=\"9\" fill=\"url(#cqa-sb-ws-grad)\"/>\n <g filter=\"url(#cqa-sb-ws-shadow)\">\n <rect x=\"2\" y=\"1\" width=\"36\" height=\"36\" rx=\"9\" fill=\"white\" fill-opacity=\"0.01\" shape-rendering=\"crispEdges\"/>\n </g>\n <rect width=\"8.07969\" height=\"2.59969\" rx=\"1.29985\" transform=\"matrix(0.0555427 -0.998456 0.998194 0.0600698 10.3188 28.9912)\" fill=\"#97AFC5\"/>\n <rect width=\"8.0708\" height=\"2.60278\" rx=\"1.30139\" transform=\"matrix(-0.173269 -0.984874 0.982367 -0.186964 27.3413 29.4043)\" fill=\"#97AFC5\"/>\n <path d=\"M11.1884 23.5958C11.4549 23.7473 11.7865 23.6502 11.9291 23.3789L13.3623 20.6523C13.5049 20.381 13.4045 20.0382 13.1381 19.8867C12.2055 19.3564 11.0448 19.6964 10.5457 20.646L10.4037 20.9162C9.90451 21.8658 10.2559 23.0655 11.1884 23.5958Z\" fill=\"#C2DBF2\"/>\n <path d=\"M11.6714 22.4677C11.6714 20.1863 13.5208 18.3369 15.8022 18.3369H23.9505C26.2319 18.3369 28.0813 20.1863 28.0813 22.4677V23.7953C28.0813 28.3268 24.4078 32.0003 19.8764 32.0003C15.3449 32.0003 11.6714 28.3268 11.6714 23.7953V22.4677Z\" fill=\"#D7E7F9\"/>\n <path d=\"M28.8116 23.7315C28.5451 23.883 28.2135 23.7859 28.0709 23.5146L26.6377 20.7881C26.4951 20.5167 26.5955 20.174 26.8619 20.0225C27.7945 19.4922 28.9552 19.8321 29.4543 20.7817L29.5963 21.0519C30.0955 22.0015 29.7441 23.2012 28.8116 23.7315Z\" fill=\"#C2DBF2\"/>\n <path d=\"M26.3774 19.1758C26.3774 19.8026 23.4762 20.3107 19.8974 20.3107C16.3186 20.3107 13.4175 19.8026 13.4175 19.1758C13.4175 18.5491 16.3186 18.041 19.8974 18.041C23.4762 18.041 26.3774 18.5491 26.3774 19.1758Z\" fill=\"#C2DBF2\"/>\n <path d=\"M21.7507 26.7785L21.6221 26.6448C22.1471 25.7868 22.0506 24.6335 21.3329 23.8869C20.5026 23.0234 19.1473 23.0234 18.317 23.8869C17.4868 24.7505 17.4868 26.1601 18.317 27.0236C19.0348 27.7702 20.1437 27.8705 20.9686 27.3245L21.0972 27.4582L21.2686 27.6365C21.4507 27.8259 21.7453 27.8259 21.9221 27.6365C22.1042 27.4471 22.1042 27.1406 21.9221 26.9568L21.7507 26.7785ZM18.9706 26.3439C18.4992 25.8536 18.4992 25.0569 18.9706 24.5722C19.4419 24.0819 20.208 24.0819 20.674 24.5722C21.0275 24.9399 21.1132 25.4804 20.9365 25.9372C20.8775 26.0876 20.7918 26.2269 20.674 26.3439C20.5561 26.4665 20.4222 26.5556 20.2829 26.6169C19.8491 26.8008 19.3241 26.7116 18.9706 26.3439Z\" fill=\"#6366F1\"/>\n <rect width=\"17.4575\" height=\"10.8035\" rx=\"5.40176\" transform=\"matrix(0.999918 0.0128129 -0.0118443 0.99993 11.1401 6.9248)\" fill=\"#D7E7F9\"/>\n <path d=\"M11.9068 9.74961C12.2603 9.75414 12.5435 10.0444 12.5393 10.3979L12.4926 14.3376C12.4884 14.6911 12.1985 14.974 11.845 14.9694C10.6078 14.9536 9.61668 13.9377 9.63133 12.7005L9.64009 11.9611C9.65475 10.7239 10.6696 9.73376 11.9068 9.74961Z\" fill=\"#C2DBF2\"/>\n <path d=\"M27.7011 15.1723C27.3476 15.1677 27.0644 14.8775 27.0686 14.524L27.1153 10.5843C27.1195 10.2308 27.4094 9.94792 27.7629 9.95245C29.0001 9.9683 29.9912 10.9841 29.9766 12.2214L29.9678 12.9607C29.9532 14.198 28.9383 15.1881 27.7011 15.1723Z\" fill=\"#C2DBF2\"/>\n <rect width=\"13.0931\" height=\"6.80894\" rx=\"3.40447\" transform=\"matrix(0.999918 0.0128129 -0.0118443 0.99993 13.2988 8.9502)\" fill=\"#2F445B\"/>\n <ellipse cx=\"0.872874\" cy=\"0.907858\" rx=\"0.872874\" ry=\"0.907858\" transform=\"matrix(0.999918 0.0128129 -0.0118443 0.99993 22.2153 11.5605)\" fill=\"#6366F1\"/>\n <ellipse cx=\"0.872874\" cy=\"0.907858\" rx=\"0.872874\" ry=\"0.907858\" transform=\"matrix(0.999918 0.0128129 -0.0118443 0.99993 15.6255 11.4766)\" fill=\"#6366F1\"/>\n <path d=\"M16.9047 6.66572C16.9091 6.29805 17.2106 6.00382 17.5783 6.00853L22.1819 6.06752C22.5496 6.07223 22.8441 6.3741 22.8398 6.74177C22.8245 8.02859 21.769 9.05841 20.4822 9.04192L19.2071 9.02558C17.9203 9.00909 16.8895 7.95254 16.9047 6.66572Z\" fill=\"#C2DBF2\"/>\n <rect x=\"2\" y=\"1\" width=\"36\" height=\"36\" rx=\"9\" fill=\"url(#cqa-sb-ws-gloss)\"/>\n <defs>\n <filter id=\"cqa-sb-ws-shadow\" x=\"0\" y=\"0\" width=\"40\" height=\"40\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n <feFlood flood-opacity=\"0\" result=\"BackgroundImageFix\"/>\n <feColorMatrix in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\" result=\"hardAlpha\"/>\n <feOffset dy=\"1\"/>\n <feGaussianBlur stdDeviation=\"1\"/>\n <feComposite in2=\"hardAlpha\" operator=\"out\"/>\n <feColorMatrix type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0\"/>\n <feBlend mode=\"normal\" in2=\"BackgroundImageFix\" result=\"effect1_dropShadow\"/>\n <feColorMatrix in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\" result=\"hardAlpha\"/>\n <feMorphology radius=\"1\" operator=\"erode\" in=\"SourceAlpha\" result=\"effect2_innerShadow\"/>\n <feOffset/>\n <feComposite in2=\"hardAlpha\" operator=\"arithmetic\" k2=\"-1\" k3=\"1\"/>\n <feColorMatrix type=\"matrix\" values=\"0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.4 0\"/>\n <feBlend mode=\"normal\" in2=\"effect1_dropShadow\" result=\"effect2_innerShadow\"/>\n </filter>\n <linearGradient id=\"cqa-sb-ws-grad\" x1=\"2\" y1=\"1\" x2=\"38\" y2=\"37\" gradientUnits=\"userSpaceOnUse\">\n <stop stop-color=\"#CCE1F4\"/>\n <stop offset=\"1\" stop-color=\"#D7E7F9\"/>\n </linearGradient>\n <linearGradient id=\"cqa-sb-ws-gloss\" x1=\"20\" y1=\"1\" x2=\"20\" y2=\"37\" gradientUnits=\"userSpaceOnUse\">\n <stop stop-color=\"white\" stop-opacity=\"0.5\"/>\n <stop offset=\"0.5\" stop-color=\"white\" stop-opacity=\"0\"/>\n </linearGradient>\n </defs>\n </svg>\n </ng-template>\n <span *ngIf=\"config?.workspaceStatus === 'live'\" class=\"cqa-sb-ws-status\"></span>\n </span>\n <span class=\"cqa-sb-ws-info\">\n <span class=\"cqa-sb-ws-name-row\">\n <span class=\"cqa-sb-ws-name\">{{ config?.workspaceName || 'Workspace' }}</span>\n </span>\n </span>\n </span>\n <span class=\"cqa-sb-ws-switch\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.17\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n width=\"14\" height=\"14\">\n <polyline points=\"3,9 7,12 11,9\"/>\n <polyline points=\"3,5 7,2 11,5\"/>\n </svg>\n </span>\n </button>\n\n <button\n *ngIf=\"isPinned || config?.showSidebarPin !== false\"\n class=\"cqa-sb-pin-or-close\"\n type=\"button\"\n (click)=\"isPinned ? closeSidebar() : pinSidebar()\"\n [matTooltip]=\"isPinned ? 'Close sidebar' : 'Pin sidebar'\"\n [matTooltipPosition]=\"isPinned ? 'right' : 'left'\"\n [attr.aria-label]=\"isPinned ? 'Close sidebar' : 'Pin sidebar'\">\n <svg\n *ngIf=\"isPinned\"\n viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"18\" height=\"18\">\n <rect x=\"1.5\" y=\"1.5\" width=\"15\" height=\"15\" rx=\"2.5\"/>\n <line x1=\"6.5\" y1=\"1.5\" x2=\"6.5\" y2=\"16.5\"/>\n <polyline points=\"10.5,12 8.5,9 10.5,6\"/>\n </svg>\n <svg\n *ngIf=\"!isPinned\"\n viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"18\" height=\"18\">\n <path d=\"M9 3v4M7 3h4v4l2 3H5l2-3V3z\"/>\n <line x1=\"9\" y1=\"10\" x2=\"9\" y2=\"15\"/>\n </svg>\n </button>\n </ng-container>\n </div>\n\n <!-- ===== 2. Search ===== -->\n <div *ngIf=\"config?.showSearch !== false\" class=\"cqa-sb-search-wrap\">\n <button class=\"cqa-sb-search\" type=\"button\"\n [matTooltip]=\"!isExpanded ? 'Search' : ''\" matTooltipPosition=\"right\"\n (click)=\"searchClick.emit()\">\n <svg class=\"cqa-sb-search-icon\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.33\" stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"16\" height=\"16\">\n <circle cx=\"7\" cy=\"7\" r=\"4.5\"/>\n <line x1=\"10.5\" y1=\"10.5\" x2=\"13.5\" y2=\"13.5\"/>\n </svg>\n <span class=\"cqa-sb-search-text\" [class.cqa-sb-search-text--visible]=\"isExpanded\">\n {{ config?.searchPlaceholder || 'Search Anything...' }}\n </span>\n <span\n *ngIf=\"config?.showSearchShortcut !== false && isExpanded\"\n class=\"cqa-sb-search-kbd\">\u2318K</span>\n </button>\n </div>\n\n <!-- ===== 3. CTA ===== -->\n <div *ngIf=\"config?.showCta !== false\" class=\"cqa-sb-cta-wrap\">\n <button class=\"cqa-sb-cta\" type=\"button\"\n [matTooltip]=\"!isExpanded ? (config?.ctaLabel || 'New') : ''\" matTooltipPosition=\"right\"\n (click)=\"ctaClick.emit()\">\n <svg viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\"\n stroke-linecap=\"round\" width=\"18\" height=\"18\">\n <line x1=\"9\" y1=\"3.75\" x2=\"9\" y2=\"14.25\"/>\n <line x1=\"3.75\" y1=\"9\" x2=\"14.25\" y2=\"9\"/>\n </svg>\n <span class=\"cqa-sb-cta-text\" [class.cqa-sb-cta-text--visible]=\"isExpanded\">\n {{ config?.ctaLabel || 'New Test Cases' }}\n </span>\n </button>\n </div>\n\n <!-- ===== 4. Nav menu ===== -->\n <cqa-nav-menu\n [items]=\"navItems\"\n [activeId]=\"activeNavId\"\n [isExpanded]=\"isExpanded\"\n [openParents]=\"openParents\"\n (itemClick)=\"onNavItemClick($event)\">\n </cqa-nav-menu>\n\n <!-- ===== 5. Utility bar ===== -->\n <div class=\"cqa-sb-utility\" [class.cqa-sb-utility--expanded]=\"isExpanded\">\n <!-- Expanded: 2 wide tiles (Help & docs + Live chat) -->\n <ng-container *ngIf=\"isExpanded\">\n <button\n *ngIf=\"config?.showHelpDocs !== false\"\n class=\"cqa-sb-util-tile\"\n type=\"button\"\n (click)=\"helpDocsClick.emit()\">\n <svg viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"18\" height=\"18\">\n <circle cx=\"9\" cy=\"9\" r=\"7.25\"/>\n <path d=\"M6.85 7a2.15 2.15 0 0 1 4.18.75c0 1.4-2.15 1.8-2.15 3.05\"/>\n <line x1=\"9\" y1=\"13.4\" x2=\"9.01\" y2=\"13.4\"/>\n </svg>\n <span class=\"cqa-sb-util-tile-label\">{{ config?.helpDocsLabel || 'Help & docs' }}</span>\n </button>\n\n <button\n *ngIf=\"config?.showLiveChat !== false\"\n class=\"cqa-sb-util-tile\"\n type=\"button\"\n (click)=\"liveChatClick.emit()\">\n <svg viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"18\" height=\"18\">\n <path d=\"M16 2H2a1 1 0 0 0-1 1v9a1 1 0 0 0 1 1h3v3l4.5-3H16a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1z\"/>\n </svg>\n <span class=\"cqa-sb-util-tile-label\">Live chat</span>\n </button>\n </ng-container>\n\n <!-- Collapsed: help + live chat only (notifications / speaker are not shown on the rail) -->\n <ng-container *ngIf=\"!isExpanded\">\n <button\n *ngIf=\"config?.showHelpDocs !== false\"\n class=\"cqa-sb-util-compact\"\n type=\"button\"\n [matTooltip]=\"config?.helpDocsLabel || 'Help & docs'\" matTooltipPosition=\"right\"\n (click)=\"helpDocsClick.emit()\">\n <svg viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"18\" height=\"18\">\n <circle cx=\"9\" cy=\"9\" r=\"7.25\"/>\n <path d=\"M6.85 7a2.15 2.15 0 0 1 4.18.75c0 1.4-2.15 1.8-2.15 3.05\"/>\n <line x1=\"9\" y1=\"13.4\" x2=\"9.01\" y2=\"13.4\"/>\n </svg>\n </button>\n\n <button\n *ngIf=\"config?.showLiveChat !== false\"\n class=\"cqa-sb-util-compact\"\n type=\"button\"\n matTooltip=\"Live chat\" matTooltipPosition=\"right\"\n (click)=\"liveChatClick.emit()\">\n <svg viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"18\" height=\"18\">\n <path d=\"M16 2H2a1 1 0 0 0-1 1v9a1 1 0 0 0 1 1h3v3l4.5-3H16a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1z\"/>\n </svg>\n </button>\n </ng-container>\n </div>\n\n <!-- ===== 6. Profile card ===== -->\n <div class=\"cqa-sb-profile\" #profileAnchor>\n <button class=\"cqa-sb-profile-main\" type=\"button\"\n [matTooltip]=\"!isExpanded ? (config?.userName || profileUser?.name || '') : ''\" matTooltipPosition=\"right\"\n [attr.aria-haspopup]=\"(profileUser && profileMenuEntries?.length) ? 'menu' : null\"\n [attr.aria-expanded]=\"(profileUser && profileMenuEntries?.length) ? isProfileMenuOpen : null\"\n (click)=\"onProfileClick()\">\n <div class=\"cqa-sb-profile-avatar\">{{ config?.userInitials || '?' }}</div>\n <div class=\"cqa-sb-profile-info\" [class.cqa-sb-profile-info--visible]=\"isExpanded\">\n <span class=\"cqa-sb-profile-name\">{{ config?.userName }}</span>\n <span *ngIf=\"config?.userRole\" class=\"cqa-sb-profile-role\">{{ config.userRole }}</span>\n </div>\n </button>\n <button *ngIf=\"isExpanded\" class=\"cqa-sb-profile-logout\" type=\"button\"\n aria-label=\"Logout\" (click)=\"logoutClick.emit()\">\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"16\" height=\"16\">\n <path d=\"M6 14H3a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1h3\"/>\n <polyline points=\"11,11 14,8 11,5\"/>\n <line x1=\"14\" y1=\"8\" x2=\"6\" y2=\"8\"/>\n </svg>\n </button>\n </div>\n\n <cqa-profile-menu\n *ngIf=\"isProfileMenuOpen && profileUser && profileMenuEntries?.length\"\n [user]=\"profileUser\"\n [entries]=\"profileMenuEntries\"\n [anchor]=\"profileAnchorRef?.nativeElement || null\"\n (itemClick)=\"onProfileMenuItemClick($event)\"\n (dismissed)=\"onProfileMenuDismissed()\">\n </cqa-profile-menu>\n\n <cqa-workspace-menu\n *ngIf=\"isWorkspaceMenuOpen && workspaces?.length\"\n [workspaces]=\"workspaces\"\n [currentWorkspaceId]=\"currentWorkspaceId\"\n [workspaceName]=\"config?.workspaceName\"\n [anchor]=\"workspaceAnchorRef?.nativeElement || null\"\n (workspaceSelected)=\"onWorkspaceMenuItemClick($event)\"\n (manageWorkspacesClick)=\"onManageWorkspacesClick()\"\n (dismissed)=\"onWorkspaceMenuDismissed()\">\n </cqa-workspace-menu>\n\n </aside>\n</div>\n", styles: ["*{box-sizing:border-box}:host{display:flex;flex-direction:column;flex:1;align-self:stretch;min-height:0;max-height:100%;height:100%;flex-shrink:0}.cqa-sb-root{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;max-height:100%;width:100%}.cqa-sb{background:#3f43ee;color:#fff;flex:1 1 auto;min-height:0;max-height:100%;height:100%;display:flex;flex-direction:column;flex-shrink:0;width:60px;transition:width .24s cubic-bezier(.32,.72,0,1);position:relative;z-index:50;overflow-x:visible;overflow-y:hidden}.cqa-sb--expanded{width:264px;overflow-x:hidden}.cqa-sb>cqa-nav-menu{flex:1 1 0;min-height:0;min-width:0;display:flex;flex-direction:column}.cqa-sb-header{padding:10px;position:relative;border-bottom:1px solid rgba(255,255,255,.08);min-height:51px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.cqa-sb-header--expanded{justify-content:flex-start;padding:12px 40px 10px 12px;height:71px;max-height:71px;gap:0}.cqa-sb-burger{width:28px;height:28px;border-radius:7px;background:rgba(216,217,252,.18);display:flex;align-items:center;justify-content:center;border:none;cursor:pointer;color:#d8d9fc;flex-shrink:0;transition:background .15s,color .15s}.cqa-sb-burger:hover{background:rgba(216,217,252,.28);color:#fff}.cqa-sb-pin-or-close{position:absolute;right:10px;top:50%;transform:translateY(calc(-50% + 1px));width:28px;height:28px;border-radius:7px;display:flex;align-items:center;justify-content:center;background:transparent;border:none;cursor:pointer;color:#d8d9fc;flex-shrink:0;transition:background .15s,color .15s}.cqa-sb-pin-or-close:hover{background:rgba(255,255,255,.1);color:#fff}.cqa-sb-ws{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:6px 14px 6px 6px;border-radius:10px;line-height:1;height:48px;transition:background .12s;flex:1;min-width:0;text-align:left;background:transparent;border:none;cursor:pointer;color:#fff;overflow:hidden}.cqa-sb-ws:hover{background:rgba(255,255,255,.08)}.cqa-sb-ws-main{display:flex;align-items:center;gap:10px;min-width:0}.cqa-sb-ws-avatar{width:36px;height:36px;border-radius:9px;display:flex;align-items:center;justify-content:center;flex-shrink:0;position:relative;overflow:hidden}.cqa-sb-ws-logo{position:relative;z-index:1;width:100%;height:100%;object-fit:contain;display:block}.cqa-sb-ws-default{position:relative;z-index:1;display:block;pointer-events:none}.cqa-sb-ws-status{position:absolute;bottom:-3px;right:-3px;width:12px;height:12px;background:#0dbd7d;border-radius:50%;border:2.5px solid #3f43ee;box-shadow:0 0 6px #0dbd7d}.cqa-sb-ws-info{flex:1;min-width:0;overflow:hidden}.cqa-sb-ws-name-row{display:flex;align-items:center;gap:6px}.cqa-sb-ws-name{font-weight:600;font-size:14px;line-height:16.8px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#fff}.cqa-sb-ws-badge{background:rgba(13,189,125,.18);color:#5ed3a8;font-size:9.5px;font-weight:700;padding:1px 6px 1px 4px;border-radius:4px;display:inline-flex;align-items:center;gap:3px;flex-shrink:0;text-transform:uppercase;letter-spacing:.04em}.cqa-sb-ws-badge:before{content:\"\";width:4px;height:4px;background:#0dbd7d;border-radius:50%;box-shadow:0 0 6px #0dbd7d}.cqa-sb-ws-switch{color:#ffffff8c;flex-shrink:0;padding:4px 0 7px;border-radius:6px;display:flex;align-items:center}.cqa-sb-search-wrap{padding:8px 12px;flex-shrink:0}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-search-wrap{padding:8px 10px 6px;display:flex;justify-content:center}.cqa-sb-search{background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);border-radius:8px;height:38px;padding:0 12px;font-size:12px;line-height:1;letter-spacing:-.31px;color:#ffffff80;display:flex;align-items:center;gap:8px;width:100%;cursor:pointer;transition:all .15s;overflow:hidden;font-family:inherit}.cqa-sb-search:hover{background:rgba(255,255,255,.08);color:#ffffffbf;border-color:#ffffff29}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-search{padding:0;width:40px;max-width:40px;height:40px;min-height:40px;margin:0 auto;justify-content:center;align-items:center;gap:0;background:transparent;border-color:#d8d9fc;border-radius:9px}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-search .cqa-sb-search-text,.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-search .cqa-sb-search-kbd{flex:0 0 0;width:0;min-width:0;height:0;margin:0;padding:0;overflow:hidden;opacity:0;border:0;pointer-events:none}.cqa-sb-search-icon{flex-shrink:0;width:14px;height:14px}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-search-icon{width:16px;height:16px}.cqa-sb-search-text{flex:1;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:400;font-size:12px;line-height:1;letter-spacing:-.31px;color:#ffffff80;opacity:0;transition:opacity .16s 80ms}.cqa-sb-search-text--visible{opacity:1}.cqa-sb-search-kbd{display:inline-flex;align-items:center;justify-content:center;height:16px;font-size:10.5px;line-height:1;letter-spacing:normal;text-align:center;background:rgba(255,255,255,.15);padding:2px 6px;border-radius:4px;color:#ffffffd9;font-family:Menlo,ui-monospace,monospace;flex-shrink:0}.cqa-sb-cta-wrap{padding:8px 12px;flex-shrink:0}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-cta-wrap{padding:0 10px 12px;display:flex;justify-content:center}.cqa-sb-cta{background:#5256f0;color:#fbfcff;border:none;border-radius:8px;height:38px;padding:10px 24px 10px 16px;font-size:14px;font-weight:600;line-height:14px;letter-spacing:0;width:100%;display:flex;align-items:center;justify-content:center;gap:8px;cursor:pointer;transition:background .15s,transform .15s;overflow:hidden;font-family:inherit}.cqa-sb-cta:hover{background:#5b5ff2;transform:translateY(-1px)}.cqa-sb-cta:active{transform:translateY(0)}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-cta{padding:0;width:40px;height:40px;min-height:40px;margin:0 auto;position:relative;background:transparent;color:#fff}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-cta:before{content:\"\";position:absolute;inset:0;border-radius:9px;background:rgba(177,178,248,.22);pointer-events:none}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-cta svg{position:relative;z-index:1;width:16px;height:16px}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-cta{box-shadow:inset 0 0 0 1px #d8d9fc38}.cqa-sb-cta-text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:600;font-size:14px;line-height:1;letter-spacing:0;color:#fbfcff;opacity:0;transition:opacity .16s 80ms;position:relative;z-index:1}.cqa-sb-cta-text--visible{opacity:1}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-cta-text{display:none}.cqa-sb-utility{border-top:none;box-shadow:inset 0 1px #ffffff1a;flex-shrink:0}.cqa-sb-utility--expanded{display:flex;align-items:center;justify-content:space-between;height:68px;gap:0;padding:8px 10px}.cqa-sb-utility:not(.cqa-sb-utility--expanded){display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:1px;padding:6px 10px}.cqa-sb-util-tile{width:110px;max-width:110px;border-radius:9px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:8px 6px 6px;color:#ffffffd9;background:rgba(255,255,255,.06);border:none;cursor:pointer;transition:background .12s,color .12s;font-family:inherit}.cqa-sb-util-tile:hover{background:rgba(177,178,248,.22);color:#fff}.cqa-sb-util-tile-label{font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;font-size:10.5px;font-weight:600;line-height:10.5px;letter-spacing:.1px;color:#ffffffd9;text-align:center;white-space:nowrap}.cqa-sb-util-compact{position:relative;width:36px;height:34px;border-radius:8px;display:flex;align-items:center;justify-content:center;color:#ffffffe0;background:transparent;border:none;cursor:pointer;transition:background .12s,color .12s;padding:0;flex-shrink:0}.cqa-sb-util-compact:hover{background:rgba(255,255,255,.08);color:#fff}.cqa-sb-util-compact-dot{position:absolute;top:6px;right:6px;width:8px;height:8px;background:#ee3f3f;border-radius:4px;border:2px solid #3f43ee;pointer-events:none}.cqa-sb-profile{border-top:1px solid rgba(255,255,255,.1);padding:12px 14px;height:62px;display:flex;align-items:center;gap:12px;background:rgba(0,0,0,.16);overflow:hidden;position:relative;width:100%;flex-shrink:0;color:#fff}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-profile{justify-content:center;padding:12px 0;height:auto;gap:0;background:rgba(0,0,0,.12);border-top-color:#ffffff1f}.cqa-sb-profile-main{flex:1;min-width:0;display:flex;align-items:center;gap:12px;padding:0;background:transparent;border:none;border-radius:8px;cursor:pointer;color:inherit;font-family:inherit;text-align:left;transition:background .15s}.cqa-sb-profile-main:hover{background:rgba(0,0,0,.1)}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-profile-main{justify-content:center;flex:0 0 auto}.cqa-sb-profile-avatar{width:34px;height:34px;border-radius:17px;background:linear-gradient(135deg,#f472b6,#db2777);display:flex;align-items:center;justify-content:center;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;font-size:12px;font-weight:700;line-height:1;letter-spacing:0;color:#fff;flex-shrink:0;box-shadow:0 0 0 2px #ffffff26}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-profile-avatar{width:32px;height:32px;border-radius:16px;font-size:11.5px}.cqa-sb-profile-info{flex:1;min-width:0;overflow:hidden;opacity:0;transition:opacity .16s 80ms;display:flex;flex-direction:column;align-items:flex-start;justify-content:center;gap:4px}.cqa-sb-profile-info--visible{opacity:1}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-profile-info{display:none}.cqa-sb-profile-name{font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:600;font-size:12.5px;line-height:13.75px;letter-spacing:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#fff}.cqa-sb-profile-role{display:inline-block;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;font-size:9px;font-weight:700;line-height:12.6px;letter-spacing:0;background:rgba(216,217,252,.22);padding:2px 7px;border-radius:999px;color:#fff;border:1px solid rgba(216,217,252,.2);white-space:nowrap;align-self:flex-start}.cqa-sb-profile-logout{color:#ffffff8c;padding:6px 6px 9px;border-radius:6px;background:transparent;border:none;cursor:pointer;flex-shrink:0;transition:background .12s,color .12s;display:flex;align-items:center;justify-content:center}.cqa-sb-profile-logout:hover{background:rgba(255,255,255,.12);color:#fff}\n"], components: [{ type: NavMenuComponent, selector: "cqa-nav-menu", inputs: ["items", "activeId", "isExpanded", "openParents"], outputs: ["itemClick"] }, { type: ProfileMenuComponent, selector: "cqa-profile-menu", inputs: ["user", "entries", "anchor", "popoverId"], outputs: ["itemClick", "dismissed"] }, { type: WorkspaceMenuComponent, selector: "cqa-workspace-menu", inputs: ["workspaces", "currentWorkspaceId", "workspaceName", "anchor", "popoverId"], outputs: ["workspaceSelected", "manageWorkspacesClick", "dismissed"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
12986
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SidebarComponent, decorators: [{
12987
+ type: Component,
12988
+ args: [{ selector: 'cqa-sidebar', template: "<div id=\"cqa-ui-root\" class=\"cqa-sb-root\">\n <aside\n class=\"cqa-sb\"\n [class.cqa-sb--expanded]=\"isExpanded\"\n (mouseenter)=\"onAsideMouseEnter()\"\n (mouseleave)=\"onAsideMouseLeave($event)\">\n\n <!-- ===== 1. Workspace header ===== -->\n <div #workspaceAnchor class=\"cqa-sb-header\" [class.cqa-sb-header--expanded]=\"isExpanded\">\n <!-- Collapsed: hamburger chip -->\n <button\n *ngIf=\"!isExpanded\"\n class=\"cqa-sb-burger\"\n (click)=\"openSidebar()\"\n type=\"button\"\n aria-label=\"Open sidebar\">\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.33\" stroke-linecap=\"round\"\n width=\"16\" height=\"16\">\n <line x1=\"2\" y1=\"4\" x2=\"14\" y2=\"4\"/>\n <line x1=\"2\" y1=\"8\" x2=\"14\" y2=\"8\"/>\n <line x1=\"2\" y1=\"12\" x2=\"14\" y2=\"12\"/>\n </svg>\n </button>\n\n <!-- Expanded: workspace selector + pin (unpinned) or close (pinned) -->\n <ng-container *ngIf=\"isExpanded\">\n <button class=\"cqa-sb-ws\" type=\"button\" (click)=\"onWorkspaceClick()\">\n <span class=\"cqa-sb-ws-main\">\n <span class=\"cqa-sb-ws-avatar\">\n <img *ngIf=\"workspaceLogoSafe; else defaultLogoTpl\"\n class=\"cqa-sb-ws-logo\"\n [src]=\"workspaceLogoSafe\"\n [alt]=\"config?.workspaceName || 'Workspace logo'\" />\n <ng-template #defaultLogoTpl>\n <svg class=\"cqa-sb-ws-default\" width=\"36\" height=\"36\" viewBox=\"0 0 40 40\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <rect x=\"2\" y=\"1\" width=\"36\" height=\"36\" rx=\"9\" fill=\"url(#cqa-sb-ws-grad)\"/>\n <g filter=\"url(#cqa-sb-ws-shadow)\">\n <rect x=\"2\" y=\"1\" width=\"36\" height=\"36\" rx=\"9\" fill=\"white\" fill-opacity=\"0.01\" shape-rendering=\"crispEdges\"/>\n </g>\n <rect width=\"8.07969\" height=\"2.59969\" rx=\"1.29985\" transform=\"matrix(0.0555427 -0.998456 0.998194 0.0600698 10.3188 28.9912)\" fill=\"#97AFC5\"/>\n <rect width=\"8.0708\" height=\"2.60278\" rx=\"1.30139\" transform=\"matrix(-0.173269 -0.984874 0.982367 -0.186964 27.3413 29.4043)\" fill=\"#97AFC5\"/>\n <path d=\"M11.1884 23.5958C11.4549 23.7473 11.7865 23.6502 11.9291 23.3789L13.3623 20.6523C13.5049 20.381 13.4045 20.0382 13.1381 19.8867C12.2055 19.3564 11.0448 19.6964 10.5457 20.646L10.4037 20.9162C9.90451 21.8658 10.2559 23.0655 11.1884 23.5958Z\" fill=\"#C2DBF2\"/>\n <path d=\"M11.6714 22.4677C11.6714 20.1863 13.5208 18.3369 15.8022 18.3369H23.9505C26.2319 18.3369 28.0813 20.1863 28.0813 22.4677V23.7953C28.0813 28.3268 24.4078 32.0003 19.8764 32.0003C15.3449 32.0003 11.6714 28.3268 11.6714 23.7953V22.4677Z\" fill=\"#D7E7F9\"/>\n <path d=\"M28.8116 23.7315C28.5451 23.883 28.2135 23.7859 28.0709 23.5146L26.6377 20.7881C26.4951 20.5167 26.5955 20.174 26.8619 20.0225C27.7945 19.4922 28.9552 19.8321 29.4543 20.7817L29.5963 21.0519C30.0955 22.0015 29.7441 23.2012 28.8116 23.7315Z\" fill=\"#C2DBF2\"/>\n <path d=\"M26.3774 19.1758C26.3774 19.8026 23.4762 20.3107 19.8974 20.3107C16.3186 20.3107 13.4175 19.8026 13.4175 19.1758C13.4175 18.5491 16.3186 18.041 19.8974 18.041C23.4762 18.041 26.3774 18.5491 26.3774 19.1758Z\" fill=\"#C2DBF2\"/>\n <path d=\"M21.7507 26.7785L21.6221 26.6448C22.1471 25.7868 22.0506 24.6335 21.3329 23.8869C20.5026 23.0234 19.1473 23.0234 18.317 23.8869C17.4868 24.7505 17.4868 26.1601 18.317 27.0236C19.0348 27.7702 20.1437 27.8705 20.9686 27.3245L21.0972 27.4582L21.2686 27.6365C21.4507 27.8259 21.7453 27.8259 21.9221 27.6365C22.1042 27.4471 22.1042 27.1406 21.9221 26.9568L21.7507 26.7785ZM18.9706 26.3439C18.4992 25.8536 18.4992 25.0569 18.9706 24.5722C19.4419 24.0819 20.208 24.0819 20.674 24.5722C21.0275 24.9399 21.1132 25.4804 20.9365 25.9372C20.8775 26.0876 20.7918 26.2269 20.674 26.3439C20.5561 26.4665 20.4222 26.5556 20.2829 26.6169C19.8491 26.8008 19.3241 26.7116 18.9706 26.3439Z\" fill=\"#6366F1\"/>\n <rect width=\"17.4575\" height=\"10.8035\" rx=\"5.40176\" transform=\"matrix(0.999918 0.0128129 -0.0118443 0.99993 11.1401 6.9248)\" fill=\"#D7E7F9\"/>\n <path d=\"M11.9068 9.74961C12.2603 9.75414 12.5435 10.0444 12.5393 10.3979L12.4926 14.3376C12.4884 14.6911 12.1985 14.974 11.845 14.9694C10.6078 14.9536 9.61668 13.9377 9.63133 12.7005L9.64009 11.9611C9.65475 10.7239 10.6696 9.73376 11.9068 9.74961Z\" fill=\"#C2DBF2\"/>\n <path d=\"M27.7011 15.1723C27.3476 15.1677 27.0644 14.8775 27.0686 14.524L27.1153 10.5843C27.1195 10.2308 27.4094 9.94792 27.7629 9.95245C29.0001 9.9683 29.9912 10.9841 29.9766 12.2214L29.9678 12.9607C29.9532 14.198 28.9383 15.1881 27.7011 15.1723Z\" fill=\"#C2DBF2\"/>\n <rect width=\"13.0931\" height=\"6.80894\" rx=\"3.40447\" transform=\"matrix(0.999918 0.0128129 -0.0118443 0.99993 13.2988 8.9502)\" fill=\"#2F445B\"/>\n <ellipse cx=\"0.872874\" cy=\"0.907858\" rx=\"0.872874\" ry=\"0.907858\" transform=\"matrix(0.999918 0.0128129 -0.0118443 0.99993 22.2153 11.5605)\" fill=\"#6366F1\"/>\n <ellipse cx=\"0.872874\" cy=\"0.907858\" rx=\"0.872874\" ry=\"0.907858\" transform=\"matrix(0.999918 0.0128129 -0.0118443 0.99993 15.6255 11.4766)\" fill=\"#6366F1\"/>\n <path d=\"M16.9047 6.66572C16.9091 6.29805 17.2106 6.00382 17.5783 6.00853L22.1819 6.06752C22.5496 6.07223 22.8441 6.3741 22.8398 6.74177C22.8245 8.02859 21.769 9.05841 20.4822 9.04192L19.2071 9.02558C17.9203 9.00909 16.8895 7.95254 16.9047 6.66572Z\" fill=\"#C2DBF2\"/>\n <rect x=\"2\" y=\"1\" width=\"36\" height=\"36\" rx=\"9\" fill=\"url(#cqa-sb-ws-gloss)\"/>\n <defs>\n <filter id=\"cqa-sb-ws-shadow\" x=\"0\" y=\"0\" width=\"40\" height=\"40\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\">\n <feFlood flood-opacity=\"0\" result=\"BackgroundImageFix\"/>\n <feColorMatrix in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\" result=\"hardAlpha\"/>\n <feOffset dy=\"1\"/>\n <feGaussianBlur stdDeviation=\"1\"/>\n <feComposite in2=\"hardAlpha\" operator=\"out\"/>\n <feColorMatrix type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0\"/>\n <feBlend mode=\"normal\" in2=\"BackgroundImageFix\" result=\"effect1_dropShadow\"/>\n <feColorMatrix in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\" result=\"hardAlpha\"/>\n <feMorphology radius=\"1\" operator=\"erode\" in=\"SourceAlpha\" result=\"effect2_innerShadow\"/>\n <feOffset/>\n <feComposite in2=\"hardAlpha\" operator=\"arithmetic\" k2=\"-1\" k3=\"1\"/>\n <feColorMatrix type=\"matrix\" values=\"0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.4 0\"/>\n <feBlend mode=\"normal\" in2=\"effect1_dropShadow\" result=\"effect2_innerShadow\"/>\n </filter>\n <linearGradient id=\"cqa-sb-ws-grad\" x1=\"2\" y1=\"1\" x2=\"38\" y2=\"37\" gradientUnits=\"userSpaceOnUse\">\n <stop stop-color=\"#CCE1F4\"/>\n <stop offset=\"1\" stop-color=\"#D7E7F9\"/>\n </linearGradient>\n <linearGradient id=\"cqa-sb-ws-gloss\" x1=\"20\" y1=\"1\" x2=\"20\" y2=\"37\" gradientUnits=\"userSpaceOnUse\">\n <stop stop-color=\"white\" stop-opacity=\"0.5\"/>\n <stop offset=\"0.5\" stop-color=\"white\" stop-opacity=\"0\"/>\n </linearGradient>\n </defs>\n </svg>\n </ng-template>\n <span *ngIf=\"config?.workspaceStatus === 'live'\" class=\"cqa-sb-ws-status\"></span>\n </span>\n <span class=\"cqa-sb-ws-info\">\n <span class=\"cqa-sb-ws-name-row\">\n <span class=\"cqa-sb-ws-name\">{{ config?.workspaceName || 'Workspace' }}</span>\n </span>\n </span>\n </span>\n <span class=\"cqa-sb-ws-switch\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.17\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n width=\"14\" height=\"14\">\n <polyline points=\"3,9 7,12 11,9\"/>\n <polyline points=\"3,5 7,2 11,5\"/>\n </svg>\n </span>\n </button>\n\n <button\n *ngIf=\"isPinned || config?.showSidebarPin !== false\"\n class=\"cqa-sb-pin-or-close\"\n type=\"button\"\n (click)=\"isPinned ? closeSidebar() : pinSidebar()\"\n [matTooltip]=\"isPinned ? 'Close sidebar' : 'Pin sidebar'\"\n [matTooltipPosition]=\"isPinned ? 'right' : 'left'\"\n [attr.aria-label]=\"isPinned ? 'Close sidebar' : 'Pin sidebar'\">\n <svg\n *ngIf=\"isPinned\"\n viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"18\" height=\"18\">\n <rect x=\"1.5\" y=\"1.5\" width=\"15\" height=\"15\" rx=\"2.5\"/>\n <line x1=\"6.5\" y1=\"1.5\" x2=\"6.5\" y2=\"16.5\"/>\n <polyline points=\"10.5,12 8.5,9 10.5,6\"/>\n </svg>\n <svg\n *ngIf=\"!isPinned\"\n viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"18\" height=\"18\">\n <path d=\"M9 3v4M7 3h4v4l2 3H5l2-3V3z\"/>\n <line x1=\"9\" y1=\"10\" x2=\"9\" y2=\"15\"/>\n </svg>\n </button>\n </ng-container>\n </div>\n\n <!-- ===== 2. Search ===== -->\n <div *ngIf=\"config?.showSearch !== false\" class=\"cqa-sb-search-wrap\">\n <button class=\"cqa-sb-search\" type=\"button\"\n [matTooltip]=\"!isExpanded ? 'Search' : ''\" matTooltipPosition=\"right\"\n (click)=\"searchClick.emit()\">\n <svg class=\"cqa-sb-search-icon\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.33\" stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"16\" height=\"16\">\n <circle cx=\"7\" cy=\"7\" r=\"4.5\"/>\n <line x1=\"10.5\" y1=\"10.5\" x2=\"13.5\" y2=\"13.5\"/>\n </svg>\n <span class=\"cqa-sb-search-text\" [class.cqa-sb-search-text--visible]=\"isExpanded\">\n {{ config?.searchPlaceholder || 'Search Anything...' }}\n </span>\n <span\n *ngIf=\"config?.showSearchShortcut !== false && isExpanded\"\n class=\"cqa-sb-search-kbd\">\u2318K</span>\n </button>\n </div>\n\n <!-- ===== 3. CTA ===== -->\n <div *ngIf=\"config?.showCta !== false\" class=\"cqa-sb-cta-wrap\">\n <button class=\"cqa-sb-cta\" type=\"button\"\n [matTooltip]=\"!isExpanded ? (config?.ctaLabel || 'New') : ''\" matTooltipPosition=\"right\"\n (click)=\"ctaClick.emit()\">\n <svg viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\"\n stroke-linecap=\"round\" width=\"18\" height=\"18\">\n <line x1=\"9\" y1=\"3.75\" x2=\"9\" y2=\"14.25\"/>\n <line x1=\"3.75\" y1=\"9\" x2=\"14.25\" y2=\"9\"/>\n </svg>\n <span class=\"cqa-sb-cta-text\" [class.cqa-sb-cta-text--visible]=\"isExpanded\">\n {{ config?.ctaLabel || 'New Test Cases' }}\n </span>\n </button>\n </div>\n\n <!-- ===== 4. Nav menu ===== -->\n <cqa-nav-menu\n [items]=\"navItems\"\n [activeId]=\"activeNavId\"\n [isExpanded]=\"isExpanded\"\n [openParents]=\"openParents\"\n (itemClick)=\"onNavItemClick($event)\">\n </cqa-nav-menu>\n\n <!-- ===== 5. Utility bar ===== -->\n <div class=\"cqa-sb-utility\" [class.cqa-sb-utility--expanded]=\"isExpanded\">\n <!-- Expanded: 2 wide tiles (Help & docs + Live chat) -->\n <ng-container *ngIf=\"isExpanded\">\n <button\n *ngIf=\"config?.showHelpDocs !== false\"\n class=\"cqa-sb-util-tile\"\n type=\"button\"\n (click)=\"helpDocsClick.emit()\">\n <svg viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"18\" height=\"18\">\n <circle cx=\"9\" cy=\"9\" r=\"7.25\"/>\n <path d=\"M6.85 7a2.15 2.15 0 0 1 4.18.75c0 1.4-2.15 1.8-2.15 3.05\"/>\n <line x1=\"9\" y1=\"13.4\" x2=\"9.01\" y2=\"13.4\"/>\n </svg>\n <span class=\"cqa-sb-util-tile-label\">{{ config?.helpDocsLabel || 'Help & docs' }}</span>\n </button>\n\n <button\n *ngIf=\"config?.showLiveChat !== false\"\n class=\"cqa-sb-util-tile\"\n type=\"button\"\n (click)=\"liveChatClick.emit()\">\n <svg viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"18\" height=\"18\">\n <path d=\"M16 2H2a1 1 0 0 0-1 1v9a1 1 0 0 0 1 1h3v3l4.5-3H16a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1z\"/>\n </svg>\n <span class=\"cqa-sb-util-tile-label\">Live chat</span>\n </button>\n </ng-container>\n\n <!-- Collapsed: help + live chat only (notifications / speaker are not shown on the rail) -->\n <ng-container *ngIf=\"!isExpanded\">\n <button\n *ngIf=\"config?.showHelpDocs !== false\"\n class=\"cqa-sb-util-compact\"\n type=\"button\"\n [matTooltip]=\"config?.helpDocsLabel || 'Help & docs'\" matTooltipPosition=\"right\"\n (click)=\"helpDocsClick.emit()\">\n <svg viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"18\" height=\"18\">\n <circle cx=\"9\" cy=\"9\" r=\"7.25\"/>\n <path d=\"M6.85 7a2.15 2.15 0 0 1 4.18.75c0 1.4-2.15 1.8-2.15 3.05\"/>\n <line x1=\"9\" y1=\"13.4\" x2=\"9.01\" y2=\"13.4\"/>\n </svg>\n </button>\n\n <button\n *ngIf=\"config?.showLiveChat !== false\"\n class=\"cqa-sb-util-compact\"\n type=\"button\"\n matTooltip=\"Live chat\" matTooltipPosition=\"right\"\n (click)=\"liveChatClick.emit()\">\n <svg viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"18\" height=\"18\">\n <path d=\"M16 2H2a1 1 0 0 0-1 1v9a1 1 0 0 0 1 1h3v3l4.5-3H16a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1z\"/>\n </svg>\n </button>\n </ng-container>\n </div>\n\n <!-- ===== 6. Profile card ===== -->\n <div class=\"cqa-sb-profile\" #profileAnchor>\n <button class=\"cqa-sb-profile-main\" type=\"button\"\n [matTooltip]=\"!isExpanded ? (config?.userName || profileUser?.name || '') : ''\" matTooltipPosition=\"right\"\n [attr.aria-haspopup]=\"(profileUser && profileMenuEntries?.length) ? 'menu' : null\"\n [attr.aria-expanded]=\"(profileUser && profileMenuEntries?.length) ? isProfileMenuOpen : null\"\n (click)=\"onProfileClick()\">\n <div class=\"cqa-sb-profile-avatar\">{{ config?.userInitials || '?' }}</div>\n <div class=\"cqa-sb-profile-info\" [class.cqa-sb-profile-info--visible]=\"isExpanded\">\n <span class=\"cqa-sb-profile-name\">{{ config?.userName }}</span>\n <span *ngIf=\"config?.userRole\" class=\"cqa-sb-profile-role\">{{ config.userRole }}</span>\n </div>\n </button>\n <button *ngIf=\"isExpanded\" class=\"cqa-sb-profile-logout\" type=\"button\"\n aria-label=\"Logout\" (click)=\"logoutClick.emit()\">\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" width=\"16\" height=\"16\">\n <path d=\"M6 14H3a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1h3\"/>\n <polyline points=\"11,11 14,8 11,5\"/>\n <line x1=\"14\" y1=\"8\" x2=\"6\" y2=\"8\"/>\n </svg>\n </button>\n </div>\n\n <cqa-profile-menu\n *ngIf=\"isProfileMenuOpen && profileUser && profileMenuEntries?.length\"\n [user]=\"profileUser\"\n [entries]=\"profileMenuEntries\"\n [anchor]=\"profileAnchorRef?.nativeElement || null\"\n (itemClick)=\"onProfileMenuItemClick($event)\"\n (dismissed)=\"onProfileMenuDismissed()\">\n </cqa-profile-menu>\n\n <cqa-workspace-menu\n *ngIf=\"isWorkspaceMenuOpen && workspaces?.length\"\n [workspaces]=\"workspaces\"\n [currentWorkspaceId]=\"currentWorkspaceId\"\n [workspaceName]=\"config?.workspaceName\"\n [anchor]=\"workspaceAnchorRef?.nativeElement || null\"\n (workspaceSelected)=\"onWorkspaceMenuItemClick($event)\"\n (manageWorkspacesClick)=\"onManageWorkspacesClick()\"\n (dismissed)=\"onWorkspaceMenuDismissed()\">\n </cqa-workspace-menu>\n\n </aside>\n</div>\n", styles: ["*{box-sizing:border-box}:host{display:flex;flex-direction:column;flex:1;align-self:stretch;min-height:0;max-height:100%;height:100%;flex-shrink:0}.cqa-sb-root{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;max-height:100%;width:100%}.cqa-sb{background:#3f43ee;color:#fff;flex:1 1 auto;min-height:0;max-height:100%;height:100%;display:flex;flex-direction:column;flex-shrink:0;width:60px;transition:width .24s cubic-bezier(.32,.72,0,1);position:relative;z-index:50;overflow-x:visible;overflow-y:hidden}.cqa-sb--expanded{width:264px;overflow-x:hidden}.cqa-sb>cqa-nav-menu{flex:1 1 0;min-height:0;min-width:0;display:flex;flex-direction:column}.cqa-sb-header{padding:10px;position:relative;border-bottom:1px solid rgba(255,255,255,.08);min-height:51px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.cqa-sb-header--expanded{justify-content:flex-start;padding:12px 40px 10px 12px;height:71px;max-height:71px;gap:0}.cqa-sb-burger{width:28px;height:28px;border-radius:7px;background:rgba(216,217,252,.18);display:flex;align-items:center;justify-content:center;border:none;cursor:pointer;color:#d8d9fc;flex-shrink:0;transition:background .15s,color .15s}.cqa-sb-burger:hover{background:rgba(216,217,252,.28);color:#fff}.cqa-sb-pin-or-close{position:absolute;right:10px;top:50%;transform:translateY(calc(-50% + 1px));width:28px;height:28px;border-radius:7px;display:flex;align-items:center;justify-content:center;background:transparent;border:none;cursor:pointer;color:#d8d9fc;flex-shrink:0;transition:background .15s,color .15s}.cqa-sb-pin-or-close:hover{background:rgba(255,255,255,.1);color:#fff}.cqa-sb-ws{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:6px 14px 6px 6px;border-radius:10px;line-height:1;height:48px;transition:background .12s;flex:1;min-width:0;text-align:left;background:transparent;border:none;cursor:pointer;color:#fff;overflow:hidden}.cqa-sb-ws:hover{background:rgba(255,255,255,.08)}.cqa-sb-ws-main{display:flex;align-items:center;gap:10px;min-width:0}.cqa-sb-ws-avatar{width:36px;height:36px;border-radius:9px;display:flex;align-items:center;justify-content:center;flex-shrink:0;position:relative;overflow:hidden}.cqa-sb-ws-logo{position:relative;z-index:1;width:100%;height:100%;object-fit:contain;display:block}.cqa-sb-ws-default{position:relative;z-index:1;display:block;pointer-events:none}.cqa-sb-ws-status{position:absolute;bottom:-3px;right:-3px;width:12px;height:12px;background:#0dbd7d;border-radius:50%;border:2.5px solid #3f43ee;box-shadow:0 0 6px #0dbd7d}.cqa-sb-ws-info{flex:1;min-width:0;overflow:hidden}.cqa-sb-ws-name-row{display:flex;align-items:center;gap:6px}.cqa-sb-ws-name{font-weight:600;font-size:14px;line-height:16.8px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#fff}.cqa-sb-ws-badge{background:rgba(13,189,125,.18);color:#5ed3a8;font-size:9.5px;font-weight:700;padding:1px 6px 1px 4px;border-radius:4px;display:inline-flex;align-items:center;gap:3px;flex-shrink:0;text-transform:uppercase;letter-spacing:.04em}.cqa-sb-ws-badge:before{content:\"\";width:4px;height:4px;background:#0dbd7d;border-radius:50%;box-shadow:0 0 6px #0dbd7d}.cqa-sb-ws-switch{color:#ffffff8c;flex-shrink:0;padding:4px 0 7px;border-radius:6px;display:flex;align-items:center}.cqa-sb-search-wrap{padding:8px 12px;flex-shrink:0}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-search-wrap{padding:8px 10px 6px;display:flex;justify-content:center}.cqa-sb-search{background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);border-radius:8px;height:38px;padding:0 12px;font-size:12px;line-height:1;letter-spacing:-.31px;color:#ffffff80;display:flex;align-items:center;gap:8px;width:100%;cursor:pointer;transition:all .15s;overflow:hidden;font-family:inherit}.cqa-sb-search:hover{background:rgba(255,255,255,.08);color:#ffffffbf;border-color:#ffffff29}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-search{padding:0;width:40px;max-width:40px;height:40px;min-height:40px;margin:0 auto;justify-content:center;align-items:center;gap:0;background:transparent;border-color:#d8d9fc;border-radius:9px}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-search .cqa-sb-search-text,.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-search .cqa-sb-search-kbd{flex:0 0 0;width:0;min-width:0;height:0;margin:0;padding:0;overflow:hidden;opacity:0;border:0;pointer-events:none}.cqa-sb-search-icon{flex-shrink:0;width:14px;height:14px}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-search-icon{width:16px;height:16px}.cqa-sb-search-text{flex:1;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:400;font-size:12px;line-height:1;letter-spacing:-.31px;color:#ffffff80;opacity:0;transition:opacity .16s 80ms}.cqa-sb-search-text--visible{opacity:1}.cqa-sb-search-kbd{display:inline-flex;align-items:center;justify-content:center;height:16px;font-size:10.5px;line-height:1;letter-spacing:normal;text-align:center;background:rgba(255,255,255,.15);padding:2px 6px;border-radius:4px;color:#ffffffd9;font-family:Menlo,ui-monospace,monospace;flex-shrink:0}.cqa-sb-cta-wrap{padding:8px 12px;flex-shrink:0}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-cta-wrap{padding:0 10px 12px;display:flex;justify-content:center}.cqa-sb-cta{background:#5256f0;color:#fbfcff;border:none;border-radius:8px;height:38px;padding:10px 24px 10px 16px;font-size:14px;font-weight:600;line-height:14px;letter-spacing:0;width:100%;display:flex;align-items:center;justify-content:center;gap:8px;cursor:pointer;transition:background .15s,transform .15s;overflow:hidden;font-family:inherit}.cqa-sb-cta:hover{background:#5b5ff2;transform:translateY(-1px)}.cqa-sb-cta:active{transform:translateY(0)}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-cta{padding:0;width:40px;height:40px;min-height:40px;margin:0 auto;position:relative;background:transparent;color:#fff}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-cta:before{content:\"\";position:absolute;inset:0;border-radius:9px;background:rgba(177,178,248,.22);pointer-events:none}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-cta svg{position:relative;z-index:1;width:16px;height:16px}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-cta{box-shadow:inset 0 0 0 1px #d8d9fc38}.cqa-sb-cta-text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:600;font-size:14px;line-height:1;letter-spacing:0;color:#fbfcff;opacity:0;transition:opacity .16s 80ms;position:relative;z-index:1}.cqa-sb-cta-text--visible{opacity:1}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-cta-text{display:none}.cqa-sb-utility{border-top:none;box-shadow:inset 0 1px #ffffff1a;flex-shrink:0}.cqa-sb-utility--expanded{display:flex;align-items:center;justify-content:space-between;height:68px;gap:0;padding:8px 10px}.cqa-sb-utility:not(.cqa-sb-utility--expanded){display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:1px;padding:6px 10px}.cqa-sb-util-tile{width:110px;max-width:110px;border-radius:9px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;padding:8px 6px 6px;color:#ffffffd9;background:rgba(255,255,255,.06);border:none;cursor:pointer;transition:background .12s,color .12s;font-family:inherit}.cqa-sb-util-tile:hover{background:rgba(177,178,248,.22);color:#fff}.cqa-sb-util-tile-label{font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;font-size:10.5px;font-weight:600;line-height:10.5px;letter-spacing:.1px;color:#ffffffd9;text-align:center;white-space:nowrap}.cqa-sb-util-compact{position:relative;width:36px;height:34px;border-radius:8px;display:flex;align-items:center;justify-content:center;color:#ffffffe0;background:transparent;border:none;cursor:pointer;transition:background .12s,color .12s;padding:0;flex-shrink:0}.cqa-sb-util-compact:hover{background:rgba(255,255,255,.08);color:#fff}.cqa-sb-util-compact-dot{position:absolute;top:6px;right:6px;width:8px;height:8px;background:#ee3f3f;border-radius:4px;border:2px solid #3f43ee;pointer-events:none}.cqa-sb-profile{border-top:1px solid rgba(255,255,255,.1);padding:12px 14px;height:62px;display:flex;align-items:center;gap:12px;background:rgba(0,0,0,.16);overflow:hidden;position:relative;width:100%;flex-shrink:0;color:#fff}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-profile{justify-content:center;padding:12px 0;height:auto;gap:0;background:rgba(0,0,0,.12);border-top-color:#ffffff1f}.cqa-sb-profile-main{flex:1;min-width:0;display:flex;align-items:center;gap:12px;padding:0;background:transparent;border:none;border-radius:8px;cursor:pointer;color:inherit;font-family:inherit;text-align:left;transition:background .15s}.cqa-sb-profile-main:hover{background:rgba(0,0,0,.1)}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-profile-main{justify-content:center;flex:0 0 auto}.cqa-sb-profile-avatar{width:34px;height:34px;border-radius:17px;background:linear-gradient(135deg,#f472b6,#db2777);display:flex;align-items:center;justify-content:center;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;font-size:12px;font-weight:700;line-height:1;letter-spacing:0;color:#fff;flex-shrink:0;box-shadow:0 0 0 2px #ffffff26}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-profile-avatar{width:32px;height:32px;border-radius:16px;font-size:11.5px}.cqa-sb-profile-info{flex:1;min-width:0;overflow:hidden;opacity:0;transition:opacity .16s 80ms;display:flex;flex-direction:column;align-items:flex-start;justify-content:center;gap:4px}.cqa-sb-profile-info--visible{opacity:1}.cqa-sb:not(.cqa-sb--expanded) .cqa-sb-profile-info{display:none}.cqa-sb-profile-name{font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:600;font-size:12.5px;line-height:13.75px;letter-spacing:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#fff}.cqa-sb-profile-role{display:inline-block;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;font-size:9px;font-weight:700;line-height:12.6px;letter-spacing:0;background:rgba(216,217,252,.22);padding:2px 7px;border-radius:999px;color:#fff;border:1px solid rgba(216,217,252,.2);white-space:nowrap;align-self:flex-start}.cqa-sb-profile-logout{color:#ffffff8c;padding:6px 6px 9px;border-radius:6px;background:transparent;border:none;cursor:pointer;flex-shrink:0;transition:background .12s,color .12s;display:flex;align-items:center;justify-content:center}.cqa-sb-profile-logout:hover{background:rgba(255,255,255,.12);color:#fff}\n"] }]
12989
+ }], ctorParameters: function () { return [{ type: i1$2.DomSanitizer }]; }, propDecorators: { config: [{
12990
+ type: Input
12991
+ }], navItems: [{
12992
+ type: Input
12993
+ }], activeNavId: [{
12994
+ type: Input
12995
+ }], initialOpenParentIds: [{
12996
+ type: Input
12997
+ }], profileUser: [{
12998
+ type: Input
12999
+ }], profileMenuEntries: [{
13000
+ type: Input
13001
+ }], workspaces: [{
13002
+ type: Input
13003
+ }], currentWorkspaceId: [{
13004
+ type: Input
13005
+ }], navItemClick: [{
13006
+ type: Output
13007
+ }], ctaClick: [{
13008
+ type: Output
13009
+ }], searchClick: [{
13010
+ type: Output
13011
+ }], workspaceSwitchClick: [{
13012
+ type: Output
13013
+ }], logoutClick: [{
13014
+ type: Output
13015
+ }], notificationsClick: [{
13016
+ type: Output
13017
+ }], helpDocsClick: [{
13018
+ type: Output
13019
+ }], speakerClick: [{
13020
+ type: Output
13021
+ }], liveChatClick: [{
13022
+ type: Output
13023
+ }], expandedChange: [{
13024
+ type: Output
13025
+ }], profileMenuItemClick: [{
13026
+ type: Output
13027
+ }], workspaceSelected: [{
13028
+ type: Output
13029
+ }], manageWorkspacesClick: [{
13030
+ type: Output
13031
+ }], profileAnchorRef: [{
13032
+ type: ViewChild,
13033
+ args: ['profileAnchor', { static: false }]
13034
+ }], workspaceAnchorRef: [{
13035
+ type: ViewChild,
13036
+ args: ['workspaceAnchor', { static: false }]
13037
+ }] } });
13038
+
12266
13039
  const STEP_COMPONENT_MAP = new InjectionToken('STEP_COMPONENT_MAP');
12267
13040
 
12268
13041
  /**
@@ -32565,22 +33338,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
32565
33338
  args: ['viewDetailsTrigger', { static: false }]
32566
33339
  }] } });
32567
33340
 
32568
- class SafeHtmlPipe {
32569
- constructor(sanitizer) {
32570
- this.sanitizer = sanitizer;
32571
- }
32572
- transform(value) {
32573
- const str = value != null ? String(value) : '';
32574
- return this.sanitizer.bypassSecurityTrustHtml(str);
32575
- }
32576
- }
32577
- SafeHtmlPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SafeHtmlPipe, deps: [{ token: i1$2.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe });
32578
- SafeHtmlPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SafeHtmlPipe, name: "cqaSafeHtml" });
32579
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SafeHtmlPipe, decorators: [{
32580
- type: Pipe,
32581
- args: [{ name: 'cqaSafeHtml' }]
32582
- }], ctorParameters: function () { return [{ type: i1$2.DomSanitizer }]; } });
32583
-
32584
33341
  const CONDITION_BRANCH_EMPTY_STYLES = `
32585
33342
  /* Empty drop zone: ensure min height for drag-drop to work (IF/ELSE IF/ELSE branches) */
32586
33343
  .nested-step-drop-list:has(.step-drag-placeholder-nested:only-child) {
@@ -53561,6 +54318,12 @@ UiKitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "1
53561
54318
  EmptyStateComponent,
53562
54319
  TableTemplateComponent,
53563
54320
  ModularTableTemplateComponent,
54321
+ SidebarComponent,
54322
+ NavMenuComponent,
54323
+ NavItemComponent,
54324
+ NavSubItemComponent,
54325
+ ProfileMenuComponent,
54326
+ WorkspaceMenuComponent,
53564
54327
  FolderSidebarComponent,
53565
54328
  MoveToFolderDialogComponent,
53566
54329
  MoveTestSuiteDialogComponent,
@@ -53757,6 +54520,12 @@ UiKitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "1
53757
54520
  EmptyStateComponent,
53758
54521
  TableTemplateComponent,
53759
54522
  ModularTableTemplateComponent,
54523
+ SidebarComponent,
54524
+ NavMenuComponent,
54525
+ NavItemComponent,
54526
+ NavSubItemComponent,
54527
+ ProfileMenuComponent,
54528
+ WorkspaceMenuComponent,
53760
54529
  FolderSidebarComponent,
53761
54530
  NewFolderDialogComponent,
53762
54531
  DeleteFolderDialogComponent,
@@ -54000,6 +54769,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
54000
54769
  EmptyStateComponent,
54001
54770
  TableTemplateComponent,
54002
54771
  ModularTableTemplateComponent,
54772
+ SidebarComponent,
54773
+ NavMenuComponent,
54774
+ NavItemComponent,
54775
+ NavSubItemComponent,
54776
+ ProfileMenuComponent,
54777
+ WorkspaceMenuComponent,
54003
54778
  FolderSidebarComponent,
54004
54779
  MoveToFolderDialogComponent,
54005
54780
  MoveTestSuiteDialogComponent,
@@ -54202,6 +54977,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
54202
54977
  EmptyStateComponent,
54203
54978
  TableTemplateComponent,
54204
54979
  ModularTableTemplateComponent,
54980
+ SidebarComponent,
54981
+ NavMenuComponent,
54982
+ NavItemComponent,
54983
+ NavSubItemComponent,
54984
+ ProfileMenuComponent,
54985
+ WorkspaceMenuComponent,
54205
54986
  FolderSidebarComponent,
54206
54987
  NewFolderDialogComponent,
54207
54988
  DeleteFolderDialogComponent,
@@ -55050,5 +55831,5 @@ function buildTestCaseDetailsFromApi(data, options) {
55050
55831
  * Generated bundle index. Do not edit.
55051
55832
  */
55052
55833
 
55053
- 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, DEFAULT_TEST_SUITE_LABELS, 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, MoveTestSuiteDialogComponent, 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 };
55834
+ 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, DEFAULT_TEST_SUITE_LABELS, 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, MoveTestSuiteDialogComponent, MoveToFolderDialogComponent, NamePromptModalComponent, NavItemComponent, NavMenuComponent, NavSubItemComponent, NetworkRequestComponent, NewDbConfigDialogComponent, NewEnvironmentDialogComponent, NewEnvironmentVariableDialogComponent, NewFolderDialogComponent, NewGlobalVariableDialogComponent, NewTestDataProfileDialogComponent, NewVersionHistoryDetailComponent, OtherButtonComponent, PRIORITY_COLORS, PaginationComponent, PermissionToggleComponent, ProfileMenuComponent, 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, SidebarComponent, 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, WorkspaceMenuComponent, WorkspaceSelectorComponent, buildTestCaseDetailsFromApi, getDynamicFieldsFromLegacyConfig, getEmptyStatePreset, getMetadataColor, getMetadataValueStyle, getStepDetailsStepType, humanizeVariableKey, isAiAgentStepConfig, isAiVerifyStepConfig, isApiStepConfig, isConditionStepConfig, isCustomCodeStepConfig, isDatabaseStepConfig, isLoopStepConfig, isNavSection, isNormalStepConfig, isProfileMenuDivider, isRestoreSessionStepConfig, isScreenshotStepConfig, isScrollStepConfig, isStepGroupConfig, isUploadStepConfig, isVerifyUrlStepConfig, mapApiVariablesToDynamicFields };
55054
55835
  //# sourceMappingURL=cqa-lib-cqa-ui.mjs.map