@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.
- package/esm2020/lib/sidebar/nav-item.component.mjs +171 -0
- package/esm2020/lib/sidebar/nav-menu.component.mjs +56 -0
- package/esm2020/lib/sidebar/nav-sub-item.component.mjs +27 -0
- package/esm2020/lib/sidebar/profile-menu/profile-menu.component.mjs +122 -0
- package/esm2020/lib/sidebar/profile-menu/profile-menu.models.mjs +4 -0
- package/esm2020/lib/sidebar/sidebar.component.mjs +286 -0
- package/esm2020/lib/sidebar/sidebar.models.mjs +5 -0
- package/esm2020/lib/sidebar/workspace-menu/workspace-menu.component.mjs +120 -0
- package/esm2020/lib/sidebar/workspace-menu/workspace-menu.models.mjs +2 -0
- package/esm2020/lib/templates/modular-table-template/modular-table-template.component.mjs +3 -3
- package/esm2020/lib/ui-kit.module.mjs +31 -1
- package/esm2020/lib/utils/tw-overlay-container.mjs +3 -1
- package/esm2020/public-api.mjs +10 -1
- package/fesm2015/cqa-lib-cqa-ui.mjs +818 -20
- package/fesm2015/cqa-lib-cqa-ui.mjs.map +1 -1
- package/fesm2020/cqa-lib-cqa-ui.mjs +801 -20
- package/fesm2020/cqa-lib-cqa-ui.mjs.map +1 -1
- package/lib/sidebar/nav-item.component.d.ts +48 -0
- package/lib/sidebar/nav-menu.component.d.ts +19 -0
- package/lib/sidebar/nav-sub-item.component.d.ts +11 -0
- package/lib/sidebar/profile-menu/profile-menu.component.d.ts +35 -0
- package/lib/sidebar/profile-menu/profile-menu.models.d.ts +35 -0
- package/lib/sidebar/sidebar.component.d.ts +97 -0
- package/lib/sidebar/sidebar.models.d.ts +63 -0
- package/lib/sidebar/workspace-menu/workspace-menu.component.d.ts +34 -0
- package/lib/sidebar/workspace-menu/workspace-menu.models.d.ts +12 -0
- package/lib/ui-kit.module.d.ts +164 -158
- package/package.json +1 -1
- 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,
|
|
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';
|
|
@@ -11355,10 +11355,10 @@ class ModularTableTemplateComponent {
|
|
|
11355
11355
|
}
|
|
11356
11356
|
ModularTableTemplateComponent.GRID_SCROLL_LOAD_THRESHOLD_PX = 96;
|
|
11357
11357
|
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 });
|
|
11358
|
-
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 });
|
|
11358
|
+
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 });
|
|
11359
11359
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ModularTableTemplateComponent, decorators: [{
|
|
11360
11360
|
type: Component,
|
|
11361
|
-
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: [] }]
|
|
11361
|
+
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: [] }]
|
|
11362
11362
|
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: DialogService }]; }, propDecorators: { searchPlaceholder: [{
|
|
11363
11363
|
type: Input
|
|
11364
11364
|
}], searchValue: [{
|
|
@@ -12359,6 +12359,8 @@ class TailwindOverlayContainer extends OverlayContainer {
|
|
|
12359
12359
|
// Check if this pane itself has library component classes (e.g., backdrop)
|
|
12360
12360
|
const paneHasLibraryClass = pane.classList.contains('cqa-dialog-panel') ||
|
|
12361
12361
|
pane.classList.contains('cqa-dialog-backdrop') ||
|
|
12362
|
+
pane.classList.contains('cqa-profile-menu-panel') ||
|
|
12363
|
+
pane.classList.contains('cqa-workspace-menu-panel') ||
|
|
12362
12364
|
pane.classList.contains('ctc-select-panel') ||
|
|
12363
12365
|
pane.classList.contains('ctc-date-range-panel') ||
|
|
12364
12366
|
pane.classList.contains('visual-difference-dialog') ||
|
|
@@ -12400,6 +12402,794 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
12400
12402
|
type: Injectable
|
|
12401
12403
|
}] });
|
|
12402
12404
|
|
|
12405
|
+
function isProfileMenuDivider(entry) {
|
|
12406
|
+
return entry.type === 'divider';
|
|
12407
|
+
}
|
|
12408
|
+
|
|
12409
|
+
function isNavSection(item) {
|
|
12410
|
+
return item.type === 'section';
|
|
12411
|
+
}
|
|
12412
|
+
|
|
12413
|
+
class NavItemComponent {
|
|
12414
|
+
constructor(overlay) {
|
|
12415
|
+
this.overlay = overlay;
|
|
12416
|
+
this.isActive = false;
|
|
12417
|
+
/** Whether the sidebar is in expanded (wide) mode */
|
|
12418
|
+
this.isExpanded = false;
|
|
12419
|
+
/** Whether this item's sub-menu is open */
|
|
12420
|
+
this.isOpen = false;
|
|
12421
|
+
/** Current route / selection id — used to highlight child in collapsed flyout */
|
|
12422
|
+
this.activeNavId = '';
|
|
12423
|
+
this.itemClick = new EventEmitter();
|
|
12424
|
+
/** Collapsed parent: drives CDK connected overlay for submenu */
|
|
12425
|
+
this.showCollapsedFlyout = false;
|
|
12426
|
+
this.closeFlyoutTimer = null;
|
|
12427
|
+
this.collapsedFlyoutPositions = [
|
|
12428
|
+
{
|
|
12429
|
+
originX: 'end',
|
|
12430
|
+
originY: 'center',
|
|
12431
|
+
overlayX: 'start',
|
|
12432
|
+
overlayY: 'center',
|
|
12433
|
+
offsetX: 8
|
|
12434
|
+
},
|
|
12435
|
+
{
|
|
12436
|
+
originX: 'end',
|
|
12437
|
+
originY: 'top',
|
|
12438
|
+
overlayX: 'start',
|
|
12439
|
+
overlayY: 'top',
|
|
12440
|
+
offsetX: 8
|
|
12441
|
+
},
|
|
12442
|
+
{
|
|
12443
|
+
originX: 'end',
|
|
12444
|
+
originY: 'bottom',
|
|
12445
|
+
overlayX: 'start',
|
|
12446
|
+
overlayY: 'bottom',
|
|
12447
|
+
offsetX: 8
|
|
12448
|
+
}
|
|
12449
|
+
];
|
|
12450
|
+
this.flyoutScrollStrategy = this.overlay.scrollStrategies.reposition();
|
|
12451
|
+
}
|
|
12452
|
+
ngOnDestroy() {
|
|
12453
|
+
this.clearFlyoutCloseTimer();
|
|
12454
|
+
}
|
|
12455
|
+
get hasChildren() {
|
|
12456
|
+
var _a, _b;
|
|
12457
|
+
return !!((_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.children) === null || _b === void 0 ? void 0 : _b.length);
|
|
12458
|
+
}
|
|
12459
|
+
get collapsedFlyoutOpen() {
|
|
12460
|
+
var _a, _b;
|
|
12461
|
+
return (!this.isExpanded &&
|
|
12462
|
+
this.showCollapsedFlyout &&
|
|
12463
|
+
this.hasChildren &&
|
|
12464
|
+
!!((_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.children) === null || _b === void 0 ? void 0 : _b.length));
|
|
12465
|
+
}
|
|
12466
|
+
/**
|
|
12467
|
+
* Collapsed rail: show label (leaf) or disabled copy in MatTooltip so it renders in CDK overlay,
|
|
12468
|
+
* not as an absolute child inside the scrolling nav.
|
|
12469
|
+
*/
|
|
12470
|
+
get collapsedRailTooltip() {
|
|
12471
|
+
var _a, _b, _c;
|
|
12472
|
+
if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.disabled) && ((_b = this.item) === null || _b === void 0 ? void 0 : _b.disabledTooltip)) {
|
|
12473
|
+
return this.item.disabledTooltip;
|
|
12474
|
+
}
|
|
12475
|
+
if (!this.isExpanded && !this.hasChildren && ((_c = this.item) === null || _c === void 0 ? void 0 : _c.label)) {
|
|
12476
|
+
return this.item.label;
|
|
12477
|
+
}
|
|
12478
|
+
return '';
|
|
12479
|
+
}
|
|
12480
|
+
get collapsedRailTooltipClass() {
|
|
12481
|
+
return !this.isExpanded && this.collapsedRailTooltip ? 'cqa-nav-rail-tooltip' : '';
|
|
12482
|
+
}
|
|
12483
|
+
isChildRowActive(childId) {
|
|
12484
|
+
return this.activeNavId === childId;
|
|
12485
|
+
}
|
|
12486
|
+
onHostMouseEnter() {
|
|
12487
|
+
var _a;
|
|
12488
|
+
this.clearFlyoutCloseTimer();
|
|
12489
|
+
if (!this.isExpanded && !((_a = this.item) === null || _a === void 0 ? void 0 : _a.disabled) && this.hasChildren) {
|
|
12490
|
+
this.showCollapsedFlyout = true;
|
|
12491
|
+
}
|
|
12492
|
+
}
|
|
12493
|
+
onHostMouseLeave() {
|
|
12494
|
+
this.scheduleCloseCollapsedFlyout();
|
|
12495
|
+
}
|
|
12496
|
+
onHostFocusIn(_e) {
|
|
12497
|
+
var _a;
|
|
12498
|
+
this.clearFlyoutCloseTimer();
|
|
12499
|
+
if (!this.isExpanded && !((_a = this.item) === null || _a === void 0 ? void 0 : _a.disabled) && this.hasChildren) {
|
|
12500
|
+
this.showCollapsedFlyout = true;
|
|
12501
|
+
}
|
|
12502
|
+
}
|
|
12503
|
+
onHostFocusOut(e) {
|
|
12504
|
+
if (this.isExpanded)
|
|
12505
|
+
return;
|
|
12506
|
+
const related = e.relatedTarget;
|
|
12507
|
+
if (related === null || related === void 0 ? void 0 : related.closest('.cqa-nav-flyout-overlay')) {
|
|
12508
|
+
return;
|
|
12509
|
+
}
|
|
12510
|
+
const host = e.currentTarget;
|
|
12511
|
+
if (related && host.contains(related))
|
|
12512
|
+
return;
|
|
12513
|
+
this.closeCollapsedFlyout();
|
|
12514
|
+
}
|
|
12515
|
+
onFlyoutOverlayPointerEnter() {
|
|
12516
|
+
this.clearFlyoutCloseTimer();
|
|
12517
|
+
}
|
|
12518
|
+
onFlyoutOverlayPointerLeave() {
|
|
12519
|
+
this.scheduleCloseCollapsedFlyout();
|
|
12520
|
+
}
|
|
12521
|
+
onFlyoutOverlayFocusOut(e) {
|
|
12522
|
+
var _a;
|
|
12523
|
+
const related = e.relatedTarget;
|
|
12524
|
+
const panel = e.currentTarget;
|
|
12525
|
+
if (related && panel.contains(related))
|
|
12526
|
+
return;
|
|
12527
|
+
const hostEl = (_a = this.navHostRef) === null || _a === void 0 ? void 0 : _a.nativeElement;
|
|
12528
|
+
if (related && (hostEl === null || hostEl === void 0 ? void 0 : hostEl.contains(related)))
|
|
12529
|
+
return;
|
|
12530
|
+
this.closeCollapsedFlyout();
|
|
12531
|
+
}
|
|
12532
|
+
closeCollapsedFlyout() {
|
|
12533
|
+
this.clearFlyoutCloseTimer();
|
|
12534
|
+
this.showCollapsedFlyout = false;
|
|
12535
|
+
}
|
|
12536
|
+
onClick() {
|
|
12537
|
+
var _a;
|
|
12538
|
+
if (!((_a = this.item) === null || _a === void 0 ? void 0 : _a.disabled)) {
|
|
12539
|
+
this.itemClick.emit(this.item.id);
|
|
12540
|
+
}
|
|
12541
|
+
}
|
|
12542
|
+
onChildRowClick(e, child) {
|
|
12543
|
+
e.stopPropagation();
|
|
12544
|
+
if (child.disabled)
|
|
12545
|
+
return;
|
|
12546
|
+
this.itemClick.emit(child.id);
|
|
12547
|
+
this.closeCollapsedFlyout();
|
|
12548
|
+
}
|
|
12549
|
+
clearFlyoutCloseTimer() {
|
|
12550
|
+
if (this.closeFlyoutTimer) {
|
|
12551
|
+
clearTimeout(this.closeFlyoutTimer);
|
|
12552
|
+
this.closeFlyoutTimer = null;
|
|
12553
|
+
}
|
|
12554
|
+
}
|
|
12555
|
+
scheduleCloseCollapsedFlyout() {
|
|
12556
|
+
this.clearFlyoutCloseTimer();
|
|
12557
|
+
this.closeFlyoutTimer = setTimeout(() => {
|
|
12558
|
+
this.showCollapsedFlyout = false;
|
|
12559
|
+
this.closeFlyoutTimer = null;
|
|
12560
|
+
}, NavItemComponent.FLYOUT_CLOSE_DELAY_MS);
|
|
12561
|
+
}
|
|
12562
|
+
}
|
|
12563
|
+
NavItemComponent.FLYOUT_CLOSE_DELAY_MS = 120;
|
|
12564
|
+
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 });
|
|
12565
|
+
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"] }] });
|
|
12566
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: NavItemComponent, decorators: [{
|
|
12567
|
+
type: Component,
|
|
12568
|
+
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"] }]
|
|
12569
|
+
}], ctorParameters: function () { return [{ type: i1$6.Overlay }]; }, propDecorators: { item: [{
|
|
12570
|
+
type: Input
|
|
12571
|
+
}], isActive: [{
|
|
12572
|
+
type: Input
|
|
12573
|
+
}], isExpanded: [{
|
|
12574
|
+
type: Input
|
|
12575
|
+
}], isOpen: [{
|
|
12576
|
+
type: Input
|
|
12577
|
+
}], activeNavId: [{
|
|
12578
|
+
type: Input
|
|
12579
|
+
}], itemClick: [{
|
|
12580
|
+
type: Output
|
|
12581
|
+
}], navHostRef: [{
|
|
12582
|
+
type: ViewChild,
|
|
12583
|
+
args: ['navHost']
|
|
12584
|
+
}] } });
|
|
12585
|
+
|
|
12586
|
+
class NavSubItemComponent {
|
|
12587
|
+
constructor() {
|
|
12588
|
+
this.isActive = false;
|
|
12589
|
+
this.itemClick = new EventEmitter();
|
|
12590
|
+
}
|
|
12591
|
+
onClick() {
|
|
12592
|
+
var _a;
|
|
12593
|
+
if (!((_a = this.item) === null || _a === void 0 ? void 0 : _a.disabled)) {
|
|
12594
|
+
this.itemClick.emit(this.item.id);
|
|
12595
|
+
}
|
|
12596
|
+
}
|
|
12597
|
+
}
|
|
12598
|
+
NavSubItemComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: NavSubItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12599
|
+
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"] }] });
|
|
12600
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: NavSubItemComponent, decorators: [{
|
|
12601
|
+
type: Component,
|
|
12602
|
+
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"] }]
|
|
12603
|
+
}], propDecorators: { item: [{
|
|
12604
|
+
type: Input
|
|
12605
|
+
}], isActive: [{
|
|
12606
|
+
type: Input
|
|
12607
|
+
}], itemClick: [{
|
|
12608
|
+
type: Output
|
|
12609
|
+
}] } });
|
|
12610
|
+
|
|
12611
|
+
class NavMenuComponent {
|
|
12612
|
+
constructor() {
|
|
12613
|
+
this.items = [];
|
|
12614
|
+
this.activeId = '';
|
|
12615
|
+
this.isExpanded = false;
|
|
12616
|
+
/** IDs of parent nav items whose sub-menus are currently open */
|
|
12617
|
+
this.openParents = [];
|
|
12618
|
+
this.itemClick = new EventEmitter();
|
|
12619
|
+
}
|
|
12620
|
+
isSection(item) {
|
|
12621
|
+
return isNavSection(item);
|
|
12622
|
+
}
|
|
12623
|
+
asNavItem(item) {
|
|
12624
|
+
return item;
|
|
12625
|
+
}
|
|
12626
|
+
isItemActive(item) {
|
|
12627
|
+
if (item.id === this.activeId)
|
|
12628
|
+
return true;
|
|
12629
|
+
if (item.children) {
|
|
12630
|
+
return item.children.some(c => c.id === this.activeId);
|
|
12631
|
+
}
|
|
12632
|
+
return false;
|
|
12633
|
+
}
|
|
12634
|
+
isParentOpen(item) {
|
|
12635
|
+
return this.openParents.includes(item.id);
|
|
12636
|
+
}
|
|
12637
|
+
isChildActive(childId) {
|
|
12638
|
+
return childId === this.activeId;
|
|
12639
|
+
}
|
|
12640
|
+
onItemClick(id) {
|
|
12641
|
+
this.itemClick.emit(id);
|
|
12642
|
+
}
|
|
12643
|
+
}
|
|
12644
|
+
NavMenuComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: NavMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12645
|
+
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"] }] });
|
|
12646
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: NavMenuComponent, decorators: [{
|
|
12647
|
+
type: Component,
|
|
12648
|
+
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"] }]
|
|
12649
|
+
}], propDecorators: { items: [{
|
|
12650
|
+
type: Input
|
|
12651
|
+
}], activeId: [{
|
|
12652
|
+
type: Input
|
|
12653
|
+
}], isExpanded: [{
|
|
12654
|
+
type: Input
|
|
12655
|
+
}], openParents: [{
|
|
12656
|
+
type: Input
|
|
12657
|
+
}], itemClick: [{
|
|
12658
|
+
type: Output
|
|
12659
|
+
}] } });
|
|
12660
|
+
|
|
12661
|
+
class SafeHtmlPipe {
|
|
12662
|
+
constructor(sanitizer) {
|
|
12663
|
+
this.sanitizer = sanitizer;
|
|
12664
|
+
}
|
|
12665
|
+
transform(value) {
|
|
12666
|
+
const str = value != null ? String(value) : '';
|
|
12667
|
+
return this.sanitizer.bypassSecurityTrustHtml(str);
|
|
12668
|
+
}
|
|
12669
|
+
}
|
|
12670
|
+
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 });
|
|
12671
|
+
SafeHtmlPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SafeHtmlPipe, name: "cqaSafeHtml" });
|
|
12672
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SafeHtmlPipe, decorators: [{
|
|
12673
|
+
type: Pipe,
|
|
12674
|
+
args: [{ name: 'cqaSafeHtml' }]
|
|
12675
|
+
}], ctorParameters: function () { return [{ type: i1$2.DomSanitizer }]; } });
|
|
12676
|
+
|
|
12677
|
+
class ProfileMenuComponent {
|
|
12678
|
+
constructor(overlay, viewContainerRef) {
|
|
12679
|
+
this.overlay = overlay;
|
|
12680
|
+
this.viewContainerRef = viewContainerRef;
|
|
12681
|
+
this.entries = [];
|
|
12682
|
+
this.anchor = null;
|
|
12683
|
+
this.itemClick = new EventEmitter();
|
|
12684
|
+
this.dismissed = new EventEmitter();
|
|
12685
|
+
this.overlayRef = null;
|
|
12686
|
+
this.keySub = null;
|
|
12687
|
+
this.backdropSub = null;
|
|
12688
|
+
this.viewInitialized = false;
|
|
12689
|
+
this.isDivider = isProfileMenuDivider;
|
|
12690
|
+
this.trackByEntry = (index, _entry) => index;
|
|
12691
|
+
}
|
|
12692
|
+
ngAfterViewInit() {
|
|
12693
|
+
this.viewInitialized = true;
|
|
12694
|
+
if (this.anchor) {
|
|
12695
|
+
this.openOverlay();
|
|
12696
|
+
}
|
|
12697
|
+
}
|
|
12698
|
+
ngOnChanges(changes) {
|
|
12699
|
+
if (!this.viewInitialized || !changes['anchor'])
|
|
12700
|
+
return;
|
|
12701
|
+
if (this.anchor) {
|
|
12702
|
+
this.openOverlay();
|
|
12703
|
+
}
|
|
12704
|
+
else {
|
|
12705
|
+
this.closeOverlay();
|
|
12706
|
+
}
|
|
12707
|
+
}
|
|
12708
|
+
ngOnDestroy() {
|
|
12709
|
+
this.closeOverlay();
|
|
12710
|
+
}
|
|
12711
|
+
/** Narrowing helper for the template — Angular's template type checker can't
|
|
12712
|
+
* follow our custom type guard through `*ngIf-else`, so we surface a typed cast
|
|
12713
|
+
* via this method instead. */
|
|
12714
|
+
asItem(entry) {
|
|
12715
|
+
return isProfileMenuDivider(entry) ? null : entry;
|
|
12716
|
+
}
|
|
12717
|
+
onItemClick(item) {
|
|
12718
|
+
if (item.disabled) {
|
|
12719
|
+
return;
|
|
12720
|
+
}
|
|
12721
|
+
this.itemClick.emit(item.id);
|
|
12722
|
+
}
|
|
12723
|
+
openOverlay() {
|
|
12724
|
+
if (!this.anchor) {
|
|
12725
|
+
return;
|
|
12726
|
+
}
|
|
12727
|
+
this.closeOverlay();
|
|
12728
|
+
// Popover floats out to the right of the profile card, bottom-aligned with the card.
|
|
12729
|
+
// `withPush(false)` is critical — otherwise CDK slides the overlay back over the sidebar
|
|
12730
|
+
// when its viewport calculation thinks the popover doesn't fit (e.g. in narrow iframes).
|
|
12731
|
+
const positions = [
|
|
12732
|
+
{ originX: 'end', originY: 'bottom', overlayX: 'start', overlayY: 'bottom', offsetX: 0, offsetY: 0 },
|
|
12733
|
+
{ originX: 'end', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetX: 0, offsetY: -4 },
|
|
12734
|
+
];
|
|
12735
|
+
const positionStrategy = this.overlay
|
|
12736
|
+
.position()
|
|
12737
|
+
.flexibleConnectedTo(this.anchor)
|
|
12738
|
+
.withPositions(positions)
|
|
12739
|
+
.withFlexibleDimensions(false)
|
|
12740
|
+
.withViewportMargin(8)
|
|
12741
|
+
.withPush(false);
|
|
12742
|
+
this.overlayRef = this.overlay.create({
|
|
12743
|
+
positionStrategy,
|
|
12744
|
+
scrollStrategy: this.overlay.scrollStrategies.reposition(),
|
|
12745
|
+
hasBackdrop: true,
|
|
12746
|
+
backdropClass: 'cdk-overlay-transparent-backdrop',
|
|
12747
|
+
panelClass: 'cqa-profile-menu-panel',
|
|
12748
|
+
});
|
|
12749
|
+
const portal = new TemplatePortal(this.popoverTpl, this.viewContainerRef);
|
|
12750
|
+
this.overlayRef.attach(portal);
|
|
12751
|
+
this.backdropSub = this.overlayRef.backdropClick().subscribe(() => this.dismissed.emit());
|
|
12752
|
+
this.keySub = this.overlayRef.keydownEvents().subscribe((event) => {
|
|
12753
|
+
if (event.key === 'Escape') {
|
|
12754
|
+
event.preventDefault();
|
|
12755
|
+
this.dismissed.emit();
|
|
12756
|
+
}
|
|
12757
|
+
});
|
|
12758
|
+
}
|
|
12759
|
+
closeOverlay() {
|
|
12760
|
+
var _a, _b;
|
|
12761
|
+
(_a = this.backdropSub) === null || _a === void 0 ? void 0 : _a.unsubscribe();
|
|
12762
|
+
this.backdropSub = null;
|
|
12763
|
+
(_b = this.keySub) === null || _b === void 0 ? void 0 : _b.unsubscribe();
|
|
12764
|
+
this.keySub = null;
|
|
12765
|
+
if (this.overlayRef) {
|
|
12766
|
+
this.overlayRef.dispose();
|
|
12767
|
+
this.overlayRef = null;
|
|
12768
|
+
}
|
|
12769
|
+
}
|
|
12770
|
+
}
|
|
12771
|
+
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 });
|
|
12772
|
+
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 } });
|
|
12773
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ProfileMenuComponent, decorators: [{
|
|
12774
|
+
type: Component,
|
|
12775
|
+
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"] }]
|
|
12776
|
+
}], ctorParameters: function () { return [{ type: i1$6.Overlay }, { type: i0.ViewContainerRef }]; }, propDecorators: { user: [{
|
|
12777
|
+
type: Input
|
|
12778
|
+
}], entries: [{
|
|
12779
|
+
type: Input
|
|
12780
|
+
}], anchor: [{
|
|
12781
|
+
type: Input
|
|
12782
|
+
}], popoverId: [{
|
|
12783
|
+
type: Input
|
|
12784
|
+
}], itemClick: [{
|
|
12785
|
+
type: Output
|
|
12786
|
+
}], dismissed: [{
|
|
12787
|
+
type: Output
|
|
12788
|
+
}], popoverTpl: [{
|
|
12789
|
+
type: ViewChild,
|
|
12790
|
+
args: ['popoverTpl', { static: true }]
|
|
12791
|
+
}] } });
|
|
12792
|
+
|
|
12793
|
+
class WorkspaceMenuComponent {
|
|
12794
|
+
constructor(overlay, viewContainerRef) {
|
|
12795
|
+
this.overlay = overlay;
|
|
12796
|
+
this.viewContainerRef = viewContainerRef;
|
|
12797
|
+
this.workspaces = [];
|
|
12798
|
+
this.anchor = null;
|
|
12799
|
+
this.workspaceSelected = new EventEmitter();
|
|
12800
|
+
this.manageWorkspacesClick = new EventEmitter();
|
|
12801
|
+
this.dismissed = new EventEmitter();
|
|
12802
|
+
this.overlayRef = null;
|
|
12803
|
+
this.keySub = null;
|
|
12804
|
+
this.backdropSub = null;
|
|
12805
|
+
this.viewInitialized = false;
|
|
12806
|
+
this.trackByWs = (_index, item) => item.id;
|
|
12807
|
+
}
|
|
12808
|
+
ngAfterViewInit() {
|
|
12809
|
+
this.viewInitialized = true;
|
|
12810
|
+
if (this.anchor) {
|
|
12811
|
+
this.openOverlay();
|
|
12812
|
+
}
|
|
12813
|
+
}
|
|
12814
|
+
ngOnChanges(changes) {
|
|
12815
|
+
if (!this.viewInitialized || !changes['anchor'])
|
|
12816
|
+
return;
|
|
12817
|
+
if (this.anchor) {
|
|
12818
|
+
this.openOverlay();
|
|
12819
|
+
}
|
|
12820
|
+
else {
|
|
12821
|
+
this.closeOverlay();
|
|
12822
|
+
}
|
|
12823
|
+
}
|
|
12824
|
+
ngOnDestroy() {
|
|
12825
|
+
this.closeOverlay();
|
|
12826
|
+
}
|
|
12827
|
+
onItemClick(item) {
|
|
12828
|
+
this.workspaceSelected.emit(item.id);
|
|
12829
|
+
}
|
|
12830
|
+
onManageClick() {
|
|
12831
|
+
this.manageWorkspacesClick.emit();
|
|
12832
|
+
}
|
|
12833
|
+
openOverlay() {
|
|
12834
|
+
if (!this.anchor) {
|
|
12835
|
+
return;
|
|
12836
|
+
}
|
|
12837
|
+
this.closeOverlay();
|
|
12838
|
+
// Popover floats out to the right of the workspace button, top-aligned with the button.
|
|
12839
|
+
// Both position pairs pin overlayY: 'top' so the popover always extends downward (mirror of
|
|
12840
|
+
// profile-menu, which always extends upward from a bottom-anchored card).
|
|
12841
|
+
// `withPush(false)` is critical — otherwise CDK slides the overlay back over the sidebar
|
|
12842
|
+
// when its viewport calculation thinks the popover doesn't fit.
|
|
12843
|
+
const positions = [
|
|
12844
|
+
{ originX: 'end', originY: 'top', overlayX: 'start', overlayY: 'top', offsetX: 0, offsetY: 0 },
|
|
12845
|
+
{ originX: 'end', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetX: 0, offsetY: 4 },
|
|
12846
|
+
];
|
|
12847
|
+
const positionStrategy = this.overlay
|
|
12848
|
+
.position()
|
|
12849
|
+
.flexibleConnectedTo(this.anchor)
|
|
12850
|
+
.withPositions(positions)
|
|
12851
|
+
.withFlexibleDimensions(false)
|
|
12852
|
+
.withViewportMargin(8)
|
|
12853
|
+
.withPush(false);
|
|
12854
|
+
this.overlayRef = this.overlay.create({
|
|
12855
|
+
positionStrategy,
|
|
12856
|
+
scrollStrategy: this.overlay.scrollStrategies.reposition(),
|
|
12857
|
+
hasBackdrop: true,
|
|
12858
|
+
backdropClass: 'cdk-overlay-transparent-backdrop',
|
|
12859
|
+
panelClass: 'cqa-workspace-menu-panel',
|
|
12860
|
+
});
|
|
12861
|
+
const portal = new TemplatePortal(this.popoverTpl, this.viewContainerRef);
|
|
12862
|
+
this.overlayRef.attach(portal);
|
|
12863
|
+
this.backdropSub = this.overlayRef.backdropClick().subscribe(() => this.dismissed.emit());
|
|
12864
|
+
this.keySub = this.overlayRef.keydownEvents().subscribe((event) => {
|
|
12865
|
+
if (event.key === 'Escape') {
|
|
12866
|
+
event.preventDefault();
|
|
12867
|
+
this.dismissed.emit();
|
|
12868
|
+
}
|
|
12869
|
+
});
|
|
12870
|
+
}
|
|
12871
|
+
closeOverlay() {
|
|
12872
|
+
var _a, _b;
|
|
12873
|
+
(_a = this.backdropSub) === null || _a === void 0 ? void 0 : _a.unsubscribe();
|
|
12874
|
+
this.backdropSub = null;
|
|
12875
|
+
(_b = this.keySub) === null || _b === void 0 ? void 0 : _b.unsubscribe();
|
|
12876
|
+
this.keySub = null;
|
|
12877
|
+
if (this.overlayRef) {
|
|
12878
|
+
this.overlayRef.dispose();
|
|
12879
|
+
this.overlayRef = null;
|
|
12880
|
+
}
|
|
12881
|
+
}
|
|
12882
|
+
}
|
|
12883
|
+
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 });
|
|
12884
|
+
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"] }] });
|
|
12885
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: WorkspaceMenuComponent, decorators: [{
|
|
12886
|
+
type: Component,
|
|
12887
|
+
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"] }]
|
|
12888
|
+
}], ctorParameters: function () { return [{ type: i1$6.Overlay }, { type: i0.ViewContainerRef }]; }, propDecorators: { workspaces: [{
|
|
12889
|
+
type: Input
|
|
12890
|
+
}], currentWorkspaceId: [{
|
|
12891
|
+
type: Input
|
|
12892
|
+
}], workspaceName: [{
|
|
12893
|
+
type: Input
|
|
12894
|
+
}], anchor: [{
|
|
12895
|
+
type: Input
|
|
12896
|
+
}], popoverId: [{
|
|
12897
|
+
type: Input
|
|
12898
|
+
}], workspaceSelected: [{
|
|
12899
|
+
type: Output
|
|
12900
|
+
}], manageWorkspacesClick: [{
|
|
12901
|
+
type: Output
|
|
12902
|
+
}], dismissed: [{
|
|
12903
|
+
type: Output
|
|
12904
|
+
}], popoverTpl: [{
|
|
12905
|
+
type: ViewChild,
|
|
12906
|
+
args: ['popoverTpl', { static: true }]
|
|
12907
|
+
}] } });
|
|
12908
|
+
|
|
12909
|
+
class SidebarComponent {
|
|
12910
|
+
constructor(sanitizer) {
|
|
12911
|
+
this.sanitizer = sanitizer;
|
|
12912
|
+
this.config = {};
|
|
12913
|
+
this.navItems = [];
|
|
12914
|
+
this.activeNavId = '';
|
|
12915
|
+
/** Parent item IDs to open by default (in addition to the one containing the active item). */
|
|
12916
|
+
this.initialOpenParentIds = [];
|
|
12917
|
+
/**
|
|
12918
|
+
* Menu entries shown inside the profile-menu popover. Provide at least one entry to
|
|
12919
|
+
* enable the popover; an empty array preserves the legacy `logoutClick` behavior.
|
|
12920
|
+
*/
|
|
12921
|
+
this.profileMenuEntries = [];
|
|
12922
|
+
/**
|
|
12923
|
+
* Workspaces shown inside the workspace-switcher popover. Provide at least one entry
|
|
12924
|
+
* to enable the popover; an empty array preserves the legacy `workspaceSwitchClick`
|
|
12925
|
+
* behavior (single emit on click, no UI).
|
|
12926
|
+
*/
|
|
12927
|
+
this.workspaces = [];
|
|
12928
|
+
this.navItemClick = new EventEmitter();
|
|
12929
|
+
this.ctaClick = new EventEmitter();
|
|
12930
|
+
this.searchClick = new EventEmitter();
|
|
12931
|
+
this.workspaceSwitchClick = new EventEmitter();
|
|
12932
|
+
this.logoutClick = new EventEmitter();
|
|
12933
|
+
this.notificationsClick = new EventEmitter();
|
|
12934
|
+
this.helpDocsClick = new EventEmitter();
|
|
12935
|
+
this.speakerClick = new EventEmitter();
|
|
12936
|
+
this.liveChatClick = new EventEmitter();
|
|
12937
|
+
this.expandedChange = new EventEmitter();
|
|
12938
|
+
/** Emits `ProfileMenuItem.id` when the user activates an entry in the profile popover. */
|
|
12939
|
+
this.profileMenuItemClick = new EventEmitter();
|
|
12940
|
+
/** Emits the workspace id when the user picks one from the workspace popover. */
|
|
12941
|
+
this.workspaceSelected = new EventEmitter();
|
|
12942
|
+
/** Emits when the user clicks the "Workspace Management" footer row. */
|
|
12943
|
+
this.manageWorkspacesClick = new EventEmitter();
|
|
12944
|
+
this.isExpanded = false;
|
|
12945
|
+
this.isPinned = false;
|
|
12946
|
+
this.openParents = [];
|
|
12947
|
+
this.isProfileMenuOpen = false;
|
|
12948
|
+
this.isWorkspaceMenuOpen = false;
|
|
12949
|
+
this.leaveCollapseTimer = null;
|
|
12950
|
+
}
|
|
12951
|
+
/**
|
|
12952
|
+
* Sanitizer bypass so `data:image/svg+xml;base64,…` URIs render in the workspace
|
|
12953
|
+
* avatar — Angular 13's default URL sanitizer rewrites them to `unsafe:…`.
|
|
12954
|
+
*/
|
|
12955
|
+
get workspaceLogoSafe() {
|
|
12956
|
+
var _a;
|
|
12957
|
+
const url = (_a = this.config) === null || _a === void 0 ? void 0 : _a.workspaceLogo;
|
|
12958
|
+
return url ? this.sanitizer.bypassSecurityTrustUrl(url) : null;
|
|
12959
|
+
}
|
|
12960
|
+
ngOnInit() {
|
|
12961
|
+
var _a, _b;
|
|
12962
|
+
if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.defaultPinned) {
|
|
12963
|
+
this.isPinned = true;
|
|
12964
|
+
this.isExpanded = true;
|
|
12965
|
+
}
|
|
12966
|
+
if ((_b = this.initialOpenParentIds) === null || _b === void 0 ? void 0 : _b.length) {
|
|
12967
|
+
this.openParents = [...this.initialOpenParentIds];
|
|
12968
|
+
}
|
|
12969
|
+
this.ensureActiveParentOpen();
|
|
12970
|
+
}
|
|
12971
|
+
ngOnDestroy() {
|
|
12972
|
+
this.clearLeaveCollapseTimer();
|
|
12973
|
+
}
|
|
12974
|
+
ngOnChanges(changes) {
|
|
12975
|
+
if (changes['activeNavId'] && this.activeNavId) {
|
|
12976
|
+
this.ensureActiveParentOpen();
|
|
12977
|
+
}
|
|
12978
|
+
}
|
|
12979
|
+
onProfileClick() {
|
|
12980
|
+
var _a;
|
|
12981
|
+
if (this.profileUser && ((_a = this.profileMenuEntries) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
12982
|
+
this.isProfileMenuOpen = !this.isProfileMenuOpen;
|
|
12983
|
+
return;
|
|
12984
|
+
}
|
|
12985
|
+
// Legacy single-action behaviour preserved for consumers that haven't migrated.
|
|
12986
|
+
this.logoutClick.emit();
|
|
12987
|
+
}
|
|
12988
|
+
onProfileMenuItemClick(id) {
|
|
12989
|
+
this.isProfileMenuOpen = false;
|
|
12990
|
+
this.profileMenuItemClick.emit(id);
|
|
12991
|
+
}
|
|
12992
|
+
onProfileMenuDismissed() {
|
|
12993
|
+
this.isProfileMenuOpen = false;
|
|
12994
|
+
}
|
|
12995
|
+
onWorkspaceClick() {
|
|
12996
|
+
var _a;
|
|
12997
|
+
if ((_a = this.workspaces) === null || _a === void 0 ? void 0 : _a.length) {
|
|
12998
|
+
this.isWorkspaceMenuOpen = !this.isWorkspaceMenuOpen;
|
|
12999
|
+
return;
|
|
13000
|
+
}
|
|
13001
|
+
// Legacy single-emit behavior preserved for consumers that haven't migrated.
|
|
13002
|
+
this.workspaceSwitchClick.emit();
|
|
13003
|
+
}
|
|
13004
|
+
onWorkspaceMenuItemClick(id) {
|
|
13005
|
+
this.isWorkspaceMenuOpen = false;
|
|
13006
|
+
this.workspaceSelected.emit(id);
|
|
13007
|
+
}
|
|
13008
|
+
onWorkspaceMenuDismissed() {
|
|
13009
|
+
this.isWorkspaceMenuOpen = false;
|
|
13010
|
+
}
|
|
13011
|
+
onManageWorkspacesClick() {
|
|
13012
|
+
this.isWorkspaceMenuOpen = false;
|
|
13013
|
+
this.manageWorkspacesClick.emit();
|
|
13014
|
+
}
|
|
13015
|
+
/** Burger: wide sidebar without pinning — collapses on mouse leave. */
|
|
13016
|
+
openSidebar() {
|
|
13017
|
+
this.clearLeaveCollapseTimer();
|
|
13018
|
+
this.isExpanded = true;
|
|
13019
|
+
this.isPinned = false;
|
|
13020
|
+
this.expandedChange.emit(true);
|
|
13021
|
+
}
|
|
13022
|
+
/** Header collapse control: always closes and clears pin. */
|
|
13023
|
+
closeSidebar() {
|
|
13024
|
+
this.isExpanded = false;
|
|
13025
|
+
this.isPinned = false;
|
|
13026
|
+
this.clearLeaveCollapseTimer();
|
|
13027
|
+
this.expandedChange.emit(false);
|
|
13028
|
+
}
|
|
13029
|
+
pinSidebar() {
|
|
13030
|
+
this.isPinned = true;
|
|
13031
|
+
this.clearLeaveCollapseTimer();
|
|
13032
|
+
}
|
|
13033
|
+
/** Cancel delayed collapse when the pointer returns to the sidebar. */
|
|
13034
|
+
onAsideMouseEnter() {
|
|
13035
|
+
this.clearLeaveCollapseTimer();
|
|
13036
|
+
}
|
|
13037
|
+
/**
|
|
13038
|
+
* When expanded but not pinned, collapse after the pointer leaves the rail.
|
|
13039
|
+
* Skips scheduling if the pointer is moving into our CDK flyout / rail tooltip overlays.
|
|
13040
|
+
*/
|
|
13041
|
+
onAsideMouseLeave(ev) {
|
|
13042
|
+
if (this.isPinned || !this.isExpanded)
|
|
13043
|
+
return;
|
|
13044
|
+
const related = ev.relatedTarget;
|
|
13045
|
+
if (this.isPointerEnteringSidebarOverlay(related))
|
|
13046
|
+
return;
|
|
13047
|
+
this.clearLeaveCollapseTimer();
|
|
13048
|
+
this.leaveCollapseTimer = setTimeout(() => {
|
|
13049
|
+
this.leaveCollapseTimer = null;
|
|
13050
|
+
if (!this.isPinned && this.isExpanded) {
|
|
13051
|
+
this.isExpanded = false;
|
|
13052
|
+
this.expandedChange.emit(false);
|
|
13053
|
+
}
|
|
13054
|
+
}, SidebarComponent.LEAVE_COLLAPSE_MS);
|
|
13055
|
+
}
|
|
13056
|
+
isPointerEnteringSidebarOverlay(node) {
|
|
13057
|
+
if (!(node instanceof Element))
|
|
13058
|
+
return false;
|
|
13059
|
+
return !!(node.closest('.cqa-nav-flyout-overlay') ||
|
|
13060
|
+
node.closest('.cqa-nav-flyout-overlay-pane') ||
|
|
13061
|
+
node.closest('.mat-tooltip.cqa-nav-rail-tooltip') ||
|
|
13062
|
+
node.closest('.mat-tooltip'));
|
|
13063
|
+
}
|
|
13064
|
+
clearLeaveCollapseTimer() {
|
|
13065
|
+
if (this.leaveCollapseTimer) {
|
|
13066
|
+
clearTimeout(this.leaveCollapseTimer);
|
|
13067
|
+
this.leaveCollapseTimer = null;
|
|
13068
|
+
}
|
|
13069
|
+
}
|
|
13070
|
+
onNavItemClick(id) {
|
|
13071
|
+
var _a;
|
|
13072
|
+
// Submenu leaf: always emit navigation (child id was wrongly treated as a parent for toggle).
|
|
13073
|
+
if (this.isChildNavId(id)) {
|
|
13074
|
+
this.navItemClick.emit(id);
|
|
13075
|
+
return;
|
|
13076
|
+
}
|
|
13077
|
+
const item = this.findTopLevelNavItem(id);
|
|
13078
|
+
if (!item) {
|
|
13079
|
+
this.navItemClick.emit(id);
|
|
13080
|
+
return;
|
|
13081
|
+
}
|
|
13082
|
+
if ((_a = item.children) === null || _a === void 0 ? void 0 : _a.length) {
|
|
13083
|
+
// Parent item with children: toggle sub-menu when expanded, navigate when collapsed
|
|
13084
|
+
if (this.isExpanded) {
|
|
13085
|
+
this.toggleParent(id);
|
|
13086
|
+
}
|
|
13087
|
+
else {
|
|
13088
|
+
this.navItemClick.emit(id);
|
|
13089
|
+
}
|
|
13090
|
+
}
|
|
13091
|
+
else {
|
|
13092
|
+
this.navItemClick.emit(id);
|
|
13093
|
+
}
|
|
13094
|
+
}
|
|
13095
|
+
get workspaceInitial() {
|
|
13096
|
+
var _a, _b, _c;
|
|
13097
|
+
return ((_c = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.workspaceName) === null || _b === void 0 ? void 0 : _b.charAt(0)) === null || _c === void 0 ? void 0 : _c.toUpperCase()) || 'W';
|
|
13098
|
+
}
|
|
13099
|
+
toggleParent(id) {
|
|
13100
|
+
const idx = this.openParents.indexOf(id);
|
|
13101
|
+
if (idx > -1) {
|
|
13102
|
+
this.openParents = this.openParents.filter(p => p !== id);
|
|
13103
|
+
}
|
|
13104
|
+
else {
|
|
13105
|
+
this.openParents = [...this.openParents, id];
|
|
13106
|
+
}
|
|
13107
|
+
}
|
|
13108
|
+
/** True if `id` matches a submenu row under some top-level nav item. */
|
|
13109
|
+
isChildNavId(id) {
|
|
13110
|
+
var _a;
|
|
13111
|
+
for (const item of this.navItems) {
|
|
13112
|
+
if (isNavSection(item))
|
|
13113
|
+
continue;
|
|
13114
|
+
if ((_a = item.children) === null || _a === void 0 ? void 0 : _a.some((c) => c.id === id))
|
|
13115
|
+
return true;
|
|
13116
|
+
}
|
|
13117
|
+
return false;
|
|
13118
|
+
}
|
|
13119
|
+
findTopLevelNavItem(id) {
|
|
13120
|
+
for (const item of this.navItems) {
|
|
13121
|
+
if (!isNavSection(item) && item.id === id)
|
|
13122
|
+
return item;
|
|
13123
|
+
}
|
|
13124
|
+
return null;
|
|
13125
|
+
}
|
|
13126
|
+
ensureActiveParentOpen() {
|
|
13127
|
+
for (const item of this.navItems) {
|
|
13128
|
+
if (!isNavSection(item) && item.children) {
|
|
13129
|
+
const hasActiveChild = item.children.some(c => c.id === this.activeNavId);
|
|
13130
|
+
if (hasActiveChild && !this.openParents.includes(item.id)) {
|
|
13131
|
+
this.openParents = [...this.openParents, item.id];
|
|
13132
|
+
}
|
|
13133
|
+
}
|
|
13134
|
+
}
|
|
13135
|
+
}
|
|
13136
|
+
}
|
|
13137
|
+
SidebarComponent.LEAVE_COLLAPSE_MS = 220;
|
|
13138
|
+
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 });
|
|
13139
|
+
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"] }] });
|
|
13140
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SidebarComponent, decorators: [{
|
|
13141
|
+
type: Component,
|
|
13142
|
+
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"] }]
|
|
13143
|
+
}], ctorParameters: function () { return [{ type: i1$2.DomSanitizer }]; }, propDecorators: { config: [{
|
|
13144
|
+
type: Input
|
|
13145
|
+
}], navItems: [{
|
|
13146
|
+
type: Input
|
|
13147
|
+
}], activeNavId: [{
|
|
13148
|
+
type: Input
|
|
13149
|
+
}], initialOpenParentIds: [{
|
|
13150
|
+
type: Input
|
|
13151
|
+
}], profileUser: [{
|
|
13152
|
+
type: Input
|
|
13153
|
+
}], profileMenuEntries: [{
|
|
13154
|
+
type: Input
|
|
13155
|
+
}], workspaces: [{
|
|
13156
|
+
type: Input
|
|
13157
|
+
}], currentWorkspaceId: [{
|
|
13158
|
+
type: Input
|
|
13159
|
+
}], navItemClick: [{
|
|
13160
|
+
type: Output
|
|
13161
|
+
}], ctaClick: [{
|
|
13162
|
+
type: Output
|
|
13163
|
+
}], searchClick: [{
|
|
13164
|
+
type: Output
|
|
13165
|
+
}], workspaceSwitchClick: [{
|
|
13166
|
+
type: Output
|
|
13167
|
+
}], logoutClick: [{
|
|
13168
|
+
type: Output
|
|
13169
|
+
}], notificationsClick: [{
|
|
13170
|
+
type: Output
|
|
13171
|
+
}], helpDocsClick: [{
|
|
13172
|
+
type: Output
|
|
13173
|
+
}], speakerClick: [{
|
|
13174
|
+
type: Output
|
|
13175
|
+
}], liveChatClick: [{
|
|
13176
|
+
type: Output
|
|
13177
|
+
}], expandedChange: [{
|
|
13178
|
+
type: Output
|
|
13179
|
+
}], profileMenuItemClick: [{
|
|
13180
|
+
type: Output
|
|
13181
|
+
}], workspaceSelected: [{
|
|
13182
|
+
type: Output
|
|
13183
|
+
}], manageWorkspacesClick: [{
|
|
13184
|
+
type: Output
|
|
13185
|
+
}], profileAnchorRef: [{
|
|
13186
|
+
type: ViewChild,
|
|
13187
|
+
args: ['profileAnchor', { static: false }]
|
|
13188
|
+
}], workspaceAnchorRef: [{
|
|
13189
|
+
type: ViewChild,
|
|
13190
|
+
args: ['workspaceAnchor', { static: false }]
|
|
13191
|
+
}] } });
|
|
13192
|
+
|
|
12403
13193
|
const STEP_COMPONENT_MAP = new InjectionToken('STEP_COMPONENT_MAP');
|
|
12404
13194
|
|
|
12405
13195
|
/**
|
|
@@ -32612,22 +33402,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
32612
33402
|
args: ['viewDetailsTrigger', { static: false }]
|
|
32613
33403
|
}] } });
|
|
32614
33404
|
|
|
32615
|
-
class SafeHtmlPipe {
|
|
32616
|
-
constructor(sanitizer) {
|
|
32617
|
-
this.sanitizer = sanitizer;
|
|
32618
|
-
}
|
|
32619
|
-
transform(value) {
|
|
32620
|
-
const str = value != null ? String(value) : '';
|
|
32621
|
-
return this.sanitizer.bypassSecurityTrustHtml(str);
|
|
32622
|
-
}
|
|
32623
|
-
}
|
|
32624
|
-
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 });
|
|
32625
|
-
SafeHtmlPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SafeHtmlPipe, name: "cqaSafeHtml" });
|
|
32626
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SafeHtmlPipe, decorators: [{
|
|
32627
|
-
type: Pipe,
|
|
32628
|
-
args: [{ name: 'cqaSafeHtml' }]
|
|
32629
|
-
}], ctorParameters: function () { return [{ type: i1$2.DomSanitizer }]; } });
|
|
32630
|
-
|
|
32631
33405
|
const CONDITION_BRANCH_EMPTY_STYLES = `
|
|
32632
33406
|
/* Empty drop zone: ensure min height for drag-drop to work (IF/ELSE IF/ELSE branches) */
|
|
32633
33407
|
.nested-step-drop-list:has(.step-drag-placeholder-nested:only-child) {
|
|
@@ -53760,6 +54534,12 @@ UiKitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "1
|
|
|
53760
54534
|
EmptyStateComponent,
|
|
53761
54535
|
TableTemplateComponent,
|
|
53762
54536
|
ModularTableTemplateComponent,
|
|
54537
|
+
SidebarComponent,
|
|
54538
|
+
NavMenuComponent,
|
|
54539
|
+
NavItemComponent,
|
|
54540
|
+
NavSubItemComponent,
|
|
54541
|
+
ProfileMenuComponent,
|
|
54542
|
+
WorkspaceMenuComponent,
|
|
53763
54543
|
FolderSidebarComponent,
|
|
53764
54544
|
MoveToFolderDialogComponent,
|
|
53765
54545
|
MoveTestSuiteDialogComponent,
|
|
@@ -53956,6 +54736,12 @@ UiKitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "1
|
|
|
53956
54736
|
EmptyStateComponent,
|
|
53957
54737
|
TableTemplateComponent,
|
|
53958
54738
|
ModularTableTemplateComponent,
|
|
54739
|
+
SidebarComponent,
|
|
54740
|
+
NavMenuComponent,
|
|
54741
|
+
NavItemComponent,
|
|
54742
|
+
NavSubItemComponent,
|
|
54743
|
+
ProfileMenuComponent,
|
|
54744
|
+
WorkspaceMenuComponent,
|
|
53959
54745
|
FolderSidebarComponent,
|
|
53960
54746
|
NewFolderDialogComponent,
|
|
53961
54747
|
DeleteFolderDialogComponent,
|
|
@@ -54199,6 +54985,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
54199
54985
|
EmptyStateComponent,
|
|
54200
54986
|
TableTemplateComponent,
|
|
54201
54987
|
ModularTableTemplateComponent,
|
|
54988
|
+
SidebarComponent,
|
|
54989
|
+
NavMenuComponent,
|
|
54990
|
+
NavItemComponent,
|
|
54991
|
+
NavSubItemComponent,
|
|
54992
|
+
ProfileMenuComponent,
|
|
54993
|
+
WorkspaceMenuComponent,
|
|
54202
54994
|
FolderSidebarComponent,
|
|
54203
54995
|
MoveToFolderDialogComponent,
|
|
54204
54996
|
MoveTestSuiteDialogComponent,
|
|
@@ -54401,6 +55193,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
54401
55193
|
EmptyStateComponent,
|
|
54402
55194
|
TableTemplateComponent,
|
|
54403
55195
|
ModularTableTemplateComponent,
|
|
55196
|
+
SidebarComponent,
|
|
55197
|
+
NavMenuComponent,
|
|
55198
|
+
NavItemComponent,
|
|
55199
|
+
NavSubItemComponent,
|
|
55200
|
+
ProfileMenuComponent,
|
|
55201
|
+
WorkspaceMenuComponent,
|
|
54404
55202
|
FolderSidebarComponent,
|
|
54405
55203
|
NewFolderDialogComponent,
|
|
54406
55204
|
DeleteFolderDialogComponent,
|
|
@@ -55253,5 +56051,5 @@ function buildTestCaseDetailsFromApi(data, options) {
|
|
|
55253
56051
|
* Generated bundle index. Do not edit.
|
|
55254
56052
|
*/
|
|
55255
56053
|
|
|
55256
|
-
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 };
|
|
56054
|
+
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 };
|
|
55257
56055
|
//# sourceMappingURL=cqa-lib-cqa-ui.mjs.map
|