import { EventEmitter, OnChanges, OnInit, SimpleChanges, OnDestroy, ChangeDetectorRef, TemplateRef } from '@angular/core'; import { DynamicFilterItem, DynamicFilterComponent } from '../../filters/dynamic-filter/dynamic-filter.component'; import { DynamicTableColumn } from '../../table/dynamic-table/dynamic-table.component'; import { ColumnVisibilityConfig } from '../../column-visibility/column-visibility.component'; import { TableAction } from '../../table-action-toolbar/table-action-toolbar.component'; import { EmptyStateConfig } from '../../empty-state/empty-state-config.interface'; import { DialogService } from '../../dialog/dialog.service'; import { FolderCreatedPayload, FolderDeleteRequestedPayload, FolderDeletedPayload, FolderIdAccessor, FolderNode, FolderRenamedPayload, FolderMoveRequestedPayload, FolderMovedPayload, FolderDuplicateRequestedPayload, ModularConfig, ModularLabels, ReorderLabels, ReorderSavePayload, TestsMovedPayload, BulkActionInvokedPayload } from './modular-table-template.models'; import * as i0 from "@angular/core"; export declare class ModularTableTemplateComponent implements OnInit, OnChanges, OnDestroy { private cdr; private dialogService; searchPlaceholder: string; searchValue: string; showClear: boolean; showSearchBar: boolean; showExportButton: boolean; isExporting: boolean; onSearchChange: EventEmitter; onExportClick: EventEmitter; onApplyFilterClick: EventEmitter; onResetFilterClick: EventEmitter; onClearAll: EventEmitter; removeChip: EventEmitter; filterConfig: DynamicFilterItem[]; filterModel: Record; showFilterPanel: boolean; showFilterButton: boolean; otherButtons: TemplateRef[]; otherDropDownButtons: TemplateRef[]; otherSelectDropDownButtons: TemplateRef[]; /** @deprecated Use otherButtons array instead */ otherButtonLabel: string; /** @deprecated Use otherButtons array instead */ otherButtonVariant: 'filled' | 'outlined' | 'text' | 'elevated' | 'tonal' | 'grey-solid'; /** @deprecated Use otherButtons array instead */ showOtherButton: boolean; showActionButton: boolean; showSettingsButton: boolean; showAutoRefreshButton: boolean; showViewModeToggle: boolean; viewMode: 'list' | 'modular'; viewModeLabels: { list: string; modular: string; }; viewModeChange: EventEmitter<"list" | "modular">; viewModeSegments: Array<{ label: string; value: string; icon?: string; }>; onViewModeChange(value: string): void; data: any[]; isEmptyState: boolean; emptyStateConfig: EmptyStateConfig; actions: TableAction[]; chips: Array<{ key?: string; label?: string; text: string; fullText?: string; hasMore?: boolean; }>; filterApplied: boolean; columns: DynamicTableColumn[]; rowSelectable?: (row: any) => boolean; selectedAutoRefreshInterval: number; pageIndex: number; pageSize: number; pageSizeOptions: number[]; pageSizeMenuDirection: 'auto' | 'up' | 'down'; serverSidePagination: boolean; totalElements: number; pageChange: EventEmitter<{ pageIndex: number; pageSize: number; }>; /** * When false, header sort does not reorder rows locally (use with serverSidePagination + sortChange). * Default true for backward compatibility. */ enableLocalSort: boolean; sortChange: EventEmitter<{ fieldId: string; fieldValue?: string; direction: 'asc' | 'desc' | null; }>; isTableLoading?: boolean; isTableDataLoading?: boolean; cellJsonPathGetter?: (rowIndex: number, colId: string, row: any) => string; onJsonPathCopiedHandler?: (event: { path: string; source: string; }) => void; selectedItems: any[]; /** * When true, the action toolbar renders the "Select all" affordance. Defaults to false * for now — host opts in. Matches the current product requirement to hide Select All. */ showSelectAllInToolbar: boolean; /** * When true, the action toolbar renders the dismiss (×) affordance. Defaults to false * for now — host opts in. Matches the current product requirement to hide Cancel. */ showDismissInToolbar: boolean; /** Bound to the toolbar's "Select all" checkbox — drives the checked state. */ allSelectedInToolbar: boolean; private _columnVisibility; private _cachedVisibilityColumns; filteredRows: any[]; pagedRows: any[]; folders: FolderNode[]; /** Host-provided snapshot of root-level folders for the "Organized" grid. * When set, takes precedence over `this.folders` for `rootFolderTiles` so * the Organized section stays stable while sidebar search swaps `folders` * to a filtered result set. Mirrors the host-driven fallback pattern used * by `selectedFolderNode` (subfolders) and `selectedFolderTrail` (breadcrumb). */ rootFolders: FolderNode[] | null; selectedFolderId: number | null; expandedFolderIds: number[]; unorganizedCount: number; folderIdAccessor: FolderIdAccessor; modularConfig: ModularConfig; modularLabels: ModularLabels; bulkActions: TableAction[]; sidebarCollapsed: boolean; /** Controls whether the "Subfolders in {parent}" section is expanded. * Two-way bindable as `[(subfolderSectionExpanded)]`. Defaults to true. */ subfolderSectionExpanded: boolean; /** Controls whether the root-view "Organized" folder grid is expanded. * Two-way bindable as `[(organizedSectionExpanded)]`. Defaults to true. */ organizedSectionExpanded: boolean; /** Lazy-load: when true, the sidebar emits `searchChange` and skips its * local name filter so the host can serve search results from the backend. */ serverSideSearch: boolean; /** Lazy-load: backend-reported total root folders. Drives the sidebar's * top-level "Load more" affordance when `folders.length < rootTotal`. */ rootTotal: number; /** Lazy-load: true while the host is fetching server-side folder-search * results. Forwarded to the sidebar so it can render a search spinner. */ folderSearchLoading: boolean; /** Seeded value for the sidebar's search input. Exposed so hosts can restore * an in-flight folder-search across sidebar destroy/re-create cycles (e.g., * toggling out of and back into modular view). */ folderSearchValue: string; /** Lazy-load: true while a root-page fetch is in flight (initial load OR * the scroll-driven "load more" pagination). Drives the loading indicator * the modular grid renders at the right edge of the Organized row, and is * forwarded to the sidebar for its own loading affordance. */ rootFoldersLoading: boolean; /** Folder ids whose host-side save (rename / move / etc.) is in flight. * Forwarded to the sidebar for loading state. */ savingFolderIds: Array; /** Override for the currently-selected folder node. Used as a fallback when * `findFolder(folders, selectedFolderId)` misses — e.g., during sidebar * search when `folders` holds only the matched results, the selected * folder may not be among them, but its breadcrumb / header label still * needs to render. The host owns the lookup against its full folder map. */ selectedFolderNode: FolderNode | null; /** Host-provided breadcrumb snapshot for the selected folder. Used as a * fallback in `breadcrumbTrail` when `buildTrail` against `this.folders` * yields empty — the canonical case is sidebar search, where `folders` * is the search-results list and the selected folder's ancestors aren't * present. The host walks `parentId` chains to build this; partial trails * are acceptable when ancestors haven't been fetched yet. */ selectedFolderTrail: FolderNode[] | null; /** * When true (default), the library opens its own Move dialog for convenience * during testing. Hosts taking over API + UX should set this to `false` and * listen on `moveRequested` to render their own. */ useInternalDialogs: boolean; folderSelected: EventEmitter; folderExpansionToggled: EventEmitter<{ id: number; expanded: boolean; }>; /** Lazy-load: re-emitted from the sidebar when the user expands a node whose * children haven't been fetched yet. Host responds by fetching that subtree. */ folderChildrenRequested: EventEmitter; /** Lazy-load: re-emitted when the user clicks the per-folder "Load more". */ folderLoadMoreRequested: EventEmitter<{ id: number; nextPage: number; }>; /** Lazy-load: re-emitted when the user clicks the top-level "Load more". */ rootLoadMoreRequested: EventEmitter; /** Lazy-load: debounced sidebar-search term. Consumed by hosts that have * set `serverSideSearch=true` to refetch the tree from the backend. */ folderSearchChange: EventEmitter; folderCreated: EventEmitter; /** Emitted when the user clicks "+ New folder"; host should open a creation modal. */ folderCreateRequested: EventEmitter<{ parentId: number | null; }>; folderRenamed: EventEmitter; /** * Fires after the user confirms folder deletion via the internal dialog (or * immediately, when `useInternalDialogs` is false and the host drives the UX). * Payload now includes the user's chosen `strategy` for what happens to the * folder's test cases. */ folderDeleted: EventEmitter; testsMoved: EventEmitter; /** Fires on raw toolbar action click — *before* any internal dialog opens. */ bulkActionClick: EventEmitter<{ id: string; selected: any[]; }>; /** Fires when the toolbar's "Select all" is toggled. */ bulkSelectAllChange: EventEmitter; /** Fires when the toolbar's dismiss (×) is clicked. */ bulkDismiss: EventEmitter; /** * Fires *after* the library-internal move-to-folder dialog resolves with a * user confirmation, OR immediately for non-dialog bulk actions supplied by * the host. Hosts with their own UX should listen on `bulkActionClick` + * `moveRequested` and treat this as the "confirmed" signal. */ bulkActionInvoked: EventEmitter; sidebarCollapsedChange: EventEmitter; subfolderSectionExpandedChange: EventEmitter; organizedSectionExpandedChange: EventEmitter; toggleSubfolderSection(): void; toggleOrganizedSection(): void; /** When true, renders a "Reorder" button in the toolbar. Host-driven. */ showReorderButton: boolean; /** * Host flips this true while its bulk-update API call is in-flight. The * component keeps the reorder UI pinned ("Saving...") while true and exits * reorder mode when it flips back to false (the "future API call" hook). */ reorderSaving: boolean; /** Partial override for the default reorder labels ("Reorder", "Done", etc.). */ set reorderLabels(partial: Partial | undefined); get reorderLabels(): ReorderLabels; private _reorderLabels; /** Fires when the user clicks "Reorder" and the component enters reorder mode. */ reorderStart: EventEmitter; /** Fires when the user clicks "Cancel" — the original order is already restored. */ reorderCancel: EventEmitter; /** * Fires when the user clicks "Done". Host should take `orderedItems`, call its * bulk-update API, refresh `[data]`, and flip `reorderSaving` back to `false` — * the component will then exit reorder mode. * * Note: for server-side pagination, `orderedItems` is the *current page slice*, * not the full dataset — same as the in-memory view the user was dragging. */ reorderSave: EventEmitter; /** Internal — true while the user is in reorder mode. */ isReordering: boolean; /** Snapshot of `pagedRows` taken on enter; used to revert on cancel. */ private reorderSnapshot; /** Draft of the reordered rows (current working state). */ private reorderDraft; /** Auto-refresh interval captured on enter, so we can restore on cancel/done. */ private reorderSavedAutoRefresh; /** True after Done has been clicked, awaiting the host's `reorderSaving` → false flip. */ private reorderAwaitingSaveFlip; /** * Fires when the user clicks the "Move to folder" bulk action — *before* the * internal dialog opens. Hosts that want to render their own modal should * set `useInternalDialogs = false` and listen here. */ moveRequested: EventEmitter<{ testIds: Array; selected: any[]; currentFolderId: number | null; folders: FolderNode[]; }>; /** Fires whenever the component's `selectedItems` changes from within (Select All / Dismiss). */ selectedItemsChange: EventEmitter; /** * Fires when the user clicks a folder's delete affordance — *before* the * internal confirmation dialog opens. Hosts owning the UX listen here. * Payload includes `testCount` + `hasParent` so hosts can render the right * options in their own modal. */ folderDeleteRequested: EventEmitter; /** * Fires when the user picks "Move folder" from a folder row's context menu — * *before* any dialog opens. Hosts owning the UX listen here with * `useInternalDialogs = false` and open their own folder picker. */ folderMoveRequested: EventEmitter; /** * Fires after the user confirms a folder move via the internal picker * (or immediately when `useInternalDialogs = false` and the host drives it). */ folderMoved: EventEmitter; /** * Fires when the user picks "Duplicate folder" from a folder row's context menu. * The library doesn't own persistence, so the host is expected to clone the * folder's subtree server-side and *reference* (not copy) the test cases. */ folderDuplicateRequested: EventEmitter; constructor(cdr: ChangeDetectorRef, dialogService: DialogService); private pendingFilters; private appliedFilters; private autoRefreshTimer?; onReload: EventEmitter; onAutoRefreshClick: EventEmitter; columnVisibilityChange: EventEmitter; autoRefreshIntervalChange: EventEmitter; dynamicFilterComponent?: DynamicFilterComponent; computedColumns: DynamicTableColumn[]; visibilityColumns: Array<{ id: string; label: string; }>; private updateComputedColumns; private buildFolderColumn; private resolveFolderName; /** * Attach a derived `folderName` to each row when the host hasn't supplied * one. Mutates in place so the value is available everywhere the row flows * — sort, filter, column renders, exports — alongside fields like priority. */ private enrichRowsWithFolderName; private renderFolderCell; private updateVisibilityColumns; set columnVisibility(cfg: ColumnVisibilityConfig | undefined); get columnVisibility(): ColumnVisibilityConfig; ngOnInit(): void; ngOnChanges(changes: SimpleChanges): void; private initializeComponent; /** * Build `filteredRows` from `data` by applying (a) the field filters (status/priority/etc.) * and (b) the folder filter derived from `selectedFolderId` + `folderIdAccessor`. */ private rebuildFilteredRows; private passFolder; /** True when the component should render the modular (folder-aware) UI. */ get isModularView(): boolean; /** * Get selected IDs from selectedItems (objects) */ private getSelectedIds; private restoreSelectionState; private initializeColumnVisibility; get anyRowSelected(): boolean; get currentSelectedItems(): any[]; actionClick(data: any): void; view(id: number | string): void; edit(row: any): void; delete(row: any): void; toggleFilter(): void; onColumnVisibilityChange(cfg: ColumnVisibilityConfig): void; onAutoRefreshChange(intervalMs: number): void; valueChange(value: string): void; search(value: string): void; cleared(): void; onEmptyAction(action: any): void; onFiltersChanged(current: any): void; onFiltersApplied(applied: any): void; handleResetFilterClick(): void; handleRefreshClick(): void; private triggerReload; private setupAutoRefresh; private clearAutoRefresh; ngOnDestroy(): void; onPaginate(e: { pageIndex: number; pageSize: number; }): void; onPageSizeChange(size: number): void; onRemoveChip(chip: any): void; onClearAllChips(): void; private applyPagination; private mapVisibilityColumns; private normalizeDate; private passFilters; trackByTemplateRef(index: number): number; trackByDropdownTemplateRef(index: number): number; trackBySelectDropdownTemplateRef(index: number): number; isExportModalOpen: boolean; exportCodeClick(): void; closeExportModal(): void; onExportModalExport(result: { type: 'local' | 'email'; emails?: string[]; framework: 'WEBDRIVER_IO' | 'SELENIUM_JAVA'; }): void; get selectedCasesForExport(): Array<{ id?: number; name?: string; }>; get arrowClasses(): string; /** * Flat list of root-level folders for the "Organized" grid on the root view. * Prefers the host-provided `rootFolders` snapshot when set — analogous to * how `subfolderTiles` falls back to `selectedFolderNode` and `breadcrumbTrail` * falls back to `selectedFolderTrail` when `folders` has been swapped to a * search-results list. Falls back to `this.folders` otherwise. */ get rootFolderTiles(): FolderNode[]; /** * Subfolders of the currently-selected folder (for the "Subfolders in ..." grid). */ get subfolderTiles(): FolderNode[]; /** * Breadcrumb trail from "All folders" down to the currently-selected folder. */ get breadcrumbTrail(): FolderNode[]; private buildTrail; private findFolder; /** * Whether the component is in "root" view (no folder selected). Controls which * sections render on the right-hand pane. */ get isRootView(): boolean; /** The currently-selected folder node (or null at root). */ get currentFolderNode(): FolderNode | null; /** Count of test cases directly under the currently-selected folder (excluding descendants). * Reads `FolderNode.count` so the header badge matches the sidebar row count * (folder-sidebar.component.html renders the same `row.node.count`). Using * `filteredRows.length` here would only reflect the currently-rendered page. */ get currentFolderDirectCount(): number; /** * Renders the empty-state slot when the host explicitly opts in, OR when the * table would otherwise render blank (no loading + no rows). Using a derived * flag keeps the host contract identical to `cqa-table-template` while letting * the modular view show "No Test Case Found" out of the box — the earlier ask. */ get effectiveIsEmptyState(): boolean; /** * Picks the host-provided `emptyStateConfig` when the host flagged the state * itself; otherwise falls back to a library-owned "No Test Case Found" config * driven by `modularLabels`. */ get effectiveEmptyStateConfig(): EmptyStateConfig; onFolderSelected(id: number | null): void; onFolderExpansionToggled(event: { id: number; expanded: boolean; }): void; /** Tracks the `folders.length` at which we last emitted `rootLoadMoreRequested` * from the Organized grid scroll, so rapid scroll events don't spam the host * before it has had a chance to append the next page. */ private lastRootGridLoadAt; /** Tracks the `currentFolderNode.children.length` at which we last emitted * `folderLoadMoreRequested` from the Subfolders grid scroll, for the same * reason as `lastRootGridLoadAt`. */ private lastSubfolderGridLoadAt; private static readonly GRID_SCROLL_LOAD_THRESHOLD_PX; /** Horizontal-scroll handler for the "Organized" root tiles. Emits * `rootLoadMoreRequested` when the user scrolls within * `GRID_SCROLL_LOAD_THRESHOLD_PX` of the right edge AND more roots are * available on the backend. Throttled by `lastRootGridLoadAt`. * Uses `rootFolderTiles.length` (not `folders.length`) so the gate stays * correct when `rootFolders` decouples the Organized grid from the * search-filtered `folders` input. */ onRootGridScroll(event: Event): void; /** Horizontal-scroll handler for the "Subfolders in X" tiles. Emits * `folderLoadMoreRequested({ id: selectedFolderId, nextPage })` when the * user scrolls within threshold of the right edge AND the active folder * has more children on the backend than have been loaded. */ onSubfolderGridScroll(event: Event): void; onFolderCreated(payload: FolderCreatedPayload): void; onFolderCreateRequested(payload: { parentId: number | null; }): void; onFolderRenamed(payload: FolderRenamedPayload): void; /** * Wired to the sidebar's `folderDeleted` output — which fires on delete-icon * *click*, not on confirmation. We re-emit a `folderDeleteRequested` event * first (so hosts can intercept) and, when `useInternalDialogs` is enabled, * open the confirmation dialog. `folderDeleted` now only fires after confirm. */ onFolderDeleted(payload: { id: number; }): void; /** Builds the { id, name, testCount, hasParent } payload used by delete events/dialogs. */ private buildDeleteContext; private countTestsInFolder; /** Returns true when the folder is nested (i.e. not a root-level folder). */ private folderHasParent; onTestsDropped(event: { testIds: Array; targetFolderId: number | null; }): void; /** * Folder-to-folder drag-drop. The sidebar has already validated against self/descendant * cycles, so the drop is its own confirmation — we emit `folderMoved` directly without * opening the move dialog. Gated on `allowTestDragDrop` (same flag as test drag-drop). */ onFolderDropped(event: { id: number; newParentId: number | null; }): void; /** * Sidebar emitted `folderMoveRequested` (user picked "Move folder" from the context menu). * We re-emit a richer payload for hosts, and — when running with internal dialogs — * open the existing move-to-folder picker configured for a folder-move (self and * descendants are disabled to prevent cycles). */ onFolderMoveRequested(payload: { id: number; }): void; /** * Sidebar emitted `folderDuplicateRequested`. The library can't persist — * emit the host-level event so the host clones the subtree server-side. * Test cases should be *referenced* from the new folders, not duplicated. */ onFolderDuplicateRequested(payload: { id: number; }): void; onSidebarCollapsedChange(collapsed: boolean): void; toggleSidebar(): void; /** * Default bulk actions shown in the toolbar merged with any host-supplied * `bulkActions`. Currently only "Move to folder" ships by default — * Delete / Add Tag are opt-in per the current product requirement. Hosts * that want them back pass them via `bulkActions`. */ get effectiveBulkActions(): TableAction[]; onBulkAction(event: { id: string; selected: any[]; }): void; onBulkSelectAll(checked: boolean): void; onBulkDismiss(): void; private openMoveDialog; /** * Opens the folder-picker dialog configured for moving a folder (rather than tests). * The source folder itself is marked as the "current" folder so it's rendered as * disabled in the picker. On confirm, emits `folderMoved` with the chosen parent. */ private openMoveFolderDialog; private openCreateFolderDialog; private openDeleteFolderDialog; startReorder(): void; cancelReorder(): void; saveReorder(): void; onRowReorder(event: { previousIndex: number; currentIndex: number; orderedData: any[]; }): void; private exitReorderMode; /** * Row-drag payload builder used by the [cqaRowDrag] directive via (buildPayload). */ buildRowDragPayload: (row: any) => Array; static ɵfac: i0.ɵɵFactoryDeclaration; static ɵcmp: i0.ɵɵComponentDeclaration; }