@cqa-lib/cqa-ui 1.1.525 → 1.1.527

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/esm2020/lib/assets/images/image-assets.constants.mjs +3 -1
  2. package/esm2020/lib/compare-runs/compare-runs.component.mjs +1 -1
  3. package/esm2020/lib/execution-screen/db-query-execution-item/db-query-execution-item.component.mjs +1 -1
  4. package/esm2020/lib/execution-screen/db-verification-step/db-verification-step.component.mjs +1 -1
  5. package/esm2020/lib/iterations-loop/iterations-loop.component.mjs +1 -1
  6. package/esm2020/lib/segment-control/segment-control.component.mjs +6 -3
  7. package/esm2020/lib/simulator/simulator.component.mjs +3 -3
  8. package/esm2020/lib/step-builder/step-builder-document-generation-template-step/step-builder-document-generation-template-step.component.mjs +1 -1
  9. package/esm2020/lib/table/dynamic-table/dynamic-table.component.mjs +148 -4
  10. package/esm2020/lib/templates/modular-table-template/dialogs/delete-folder-dialog.component.mjs +181 -0
  11. package/esm2020/lib/templates/modular-table-template/dialogs/move-to-folder-dialog.component.mjs +264 -0
  12. package/esm2020/lib/templates/modular-table-template/dialogs/new-folder-dialog.component.mjs +352 -0
  13. package/esm2020/lib/templates/modular-table-template/directives/folder-drag.directive.mjs +45 -0
  14. package/esm2020/lib/templates/modular-table-template/directives/folder-drop.directive.mjs +95 -0
  15. package/esm2020/lib/templates/modular-table-template/directives/row-drag.directive.mjs +44 -0
  16. package/esm2020/lib/templates/modular-table-template/folder-sidebar/folder-sidebar.component.mjs +479 -0
  17. package/esm2020/lib/templates/modular-table-template/modular-table-template.component.mjs +1475 -0
  18. package/esm2020/lib/templates/modular-table-template/modular-table-template.models.mjs +79 -0
  19. package/esm2020/lib/templates/table-template.component.mjs +88 -12
  20. package/esm2020/lib/test-case-details/api-edit-step/api-edit-step.component.mjs +1 -1
  21. package/esm2020/lib/ui-kit.module.mjs +41 -1
  22. package/esm2020/public-api.mjs +10 -1
  23. package/fesm2015/cqa-lib-cqa-ui.mjs +3409 -179
  24. package/fesm2015/cqa-lib-cqa-ui.mjs.map +1 -1
  25. package/fesm2020/cqa-lib-cqa-ui.mjs +3389 -177
  26. package/fesm2020/cqa-lib-cqa-ui.mjs.map +1 -1
  27. package/lib/assets/images/image-assets.constants.d.ts +1 -0
  28. package/lib/segment-control/segment-control.component.d.ts +2 -1
  29. package/lib/table/dynamic-table/dynamic-table.component.d.ts +43 -1
  30. package/lib/templates/modular-table-template/dialogs/delete-folder-dialog.component.d.ts +34 -0
  31. package/lib/templates/modular-table-template/dialogs/move-to-folder-dialog.component.d.ts +57 -0
  32. package/lib/templates/modular-table-template/dialogs/new-folder-dialog.component.d.ts +79 -0
  33. package/lib/templates/modular-table-template/directives/folder-drag.directive.d.ts +10 -0
  34. package/lib/templates/modular-table-template/directives/folder-drop.directive.d.ts +22 -0
  35. package/lib/templates/modular-table-template/directives/row-drag.directive.d.ts +10 -0
  36. package/lib/templates/modular-table-template/folder-sidebar/folder-sidebar.component.d.ts +149 -0
  37. package/lib/templates/modular-table-template/modular-table-template.component.d.ts +453 -0
  38. package/lib/templates/modular-table-template/modular-table-template.models.d.ts +150 -0
  39. package/lib/templates/table-template.component.d.ts +40 -2
  40. package/lib/ui-kit.module.d.ts +153 -145
  41. package/package.json +1 -1
  42. package/public-api.d.ts +9 -0
  43. package/src/lib/assets/images/EmptyFolderState.png +0 -0
  44. package/src/lib/assets/images/image-assets.constants.ts +3 -0
  45. package/styles.css +1 -1
@@ -17,5 +17,6 @@ export declare const EMPTY_STATE_IMAGES: {
17
17
  readonly ANALYTICS_CHART: "assets/images/ReportsIcon.png";
18
18
  readonly DEFAULT: "assets/images/SearchIcon.png";
19
19
  readonly COMPARE_RUNS: "assets/images/CompareRunsIcon.png";
20
+ readonly EMPTY_FOLDER_STATE: "assets/images/EmptyFolderState.png";
20
21
  };
21
22
  export declare type EmptyStateImageKey = keyof typeof EMPTY_STATE_IMAGES;
@@ -18,6 +18,7 @@ export declare class SegmentControlComponent implements OnChanges, AfterViewInit
18
18
  containerBgColor: string;
19
19
  /** When true, the control stretches to fill its parent and buttons share equal width. */
20
20
  fullWidth: boolean;
21
+ size: 'md' | 'lg';
21
22
  get hostDisplay(): string;
22
23
  get hostWidth(): string;
23
24
  valueChange: EventEmitter<string>;
@@ -47,6 +48,6 @@ export declare class SegmentControlComponent implements OnChanges, AfterViewInit
47
48
  private updateIndicator;
48
49
  get isIndicatorVisible(): boolean;
49
50
  static ɵfac: i0.ɵɵFactoryDeclaration<SegmentControlComponent, never>;
50
- static ɵcmp: i0.ɵɵComponentDeclaration<SegmentControlComponent, "cqa-segment-control", never, { "segments": "segments"; "value": "value"; "disabled": "disabled"; "containerBgColor": "containerBgColor"; "fullWidth": "fullWidth"; }, { "valueChange": "valueChange"; }, never, never>;
51
+ static ɵcmp: i0.ɵɵComponentDeclaration<SegmentControlComponent, "cqa-segment-control", never, { "segments": "segments"; "value": "value"; "disabled": "disabled"; "containerBgColor": "containerBgColor"; "fullWidth": "fullWidth"; "size": "size"; }, { "valueChange": "valueChange"; }, never, never>;
51
52
  }
52
53
  export {};
@@ -1,5 +1,6 @@
1
1
  import { QueryList, TemplateRef, EventEmitter, ViewContainerRef, Type, OnDestroy, ChangeDetectorRef, OnChanges, SimpleChanges } from "@angular/core";
2
2
  import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
3
+ import { DndDropEvent } from "ngx-drag-drop";
3
4
  import { DynamicCellTemplateDirective, DynamicHeaderTemplateDirective } from "./dynamic-cell.directive";
4
5
  import { ComponentRenderConfig } from "./component-render-config.interface";
5
6
  import * as i0 from "@angular/core";
@@ -60,6 +61,30 @@ export declare class DynamicTableComponent implements OnDestroy, OnChanges {
60
61
  path: string;
61
62
  source: string;
62
63
  }) => void;
64
+ /**
65
+ * When true, renders a drag-handle column as the leftmost cell and enables
66
+ * row drag-and-drop reordering via ngx-drag-drop. Off by default so existing
67
+ * consumers are unaffected.
68
+ */
69
+ enableRowReorder: boolean;
70
+ /** Tooltip for the drag handle icon. */
71
+ reorderHandleTooltip: string;
72
+ /**
73
+ * Emitted after a successful row drop. `orderedData` is a freshly allocated
74
+ * array reflecting the new order — parents should assign it back to `[data]`
75
+ * rather than relying on in-place mutation.
76
+ */
77
+ rowReorder: EventEmitter<{
78
+ previousIndex: number;
79
+ currentIndex: number;
80
+ orderedData: any[];
81
+ }>;
82
+ /** Index of the row the cursor is currently hovering during a reorder drag. */
83
+ dropHoverIndex: number | null;
84
+ /** Whether the cursor is in the top or bottom half of the hovered row. */
85
+ dropPosition: 'above' | 'below' | null;
86
+ /** The row currently being dragged — used to suppress the indicator on the source row. */
87
+ private draggedRow;
63
88
  cellTemplates: QueryList<DynamicCellTemplateDirective>;
64
89
  headerTemplates: QueryList<DynamicHeaderTemplateDirective>;
65
90
  emptyTableTpl?: TemplateRef<any>;
@@ -122,6 +147,23 @@ export declare class DynamicTableComponent implements OnDestroy, OnChanges {
122
147
  getSanitizedHtml(value: string): SafeHtml;
123
148
  getCellValue(row: any, path?: string): any;
124
149
  trackByIndex(index: number): number;
150
+ onRowDragStart(row: any): void;
151
+ onRowDragEnd(): void;
152
+ /**
153
+ * Fires continuously while a drag is over a row. Computes whether the cursor
154
+ * is in the top or bottom half of the row and updates the indicator state.
155
+ * Suppresses the indicator on the dragged row itself.
156
+ */
157
+ onRowDragOver(event: Event, rowIndex: number): void;
158
+ /** Clears the indicator when the cursor leaves the tbody entirely. */
159
+ onTbodyDragLeave(event: Event): void;
160
+ private clearDropIndicator;
161
+ /**
162
+ * Handles a row drop from ngx-drag-drop. Prefers the tracked dragover position
163
+ * (which the user can see live via the insertion line) over `event.index` when
164
+ * computing the final insert slot. Emits a fresh array — does not mutate `data`.
165
+ */
166
+ onRowDndDrop(event: DndDropEvent): void;
125
167
  copyCellJsonPath(path: string, event: Event, source?: string): void;
126
168
  private updateGridTemplate;
127
169
  isRowSelectable(row: any): boolean;
@@ -141,5 +183,5 @@ export declare class DynamicTableComponent implements OnDestroy, OnChanges {
141
183
  toggleSort(col: DynamicTableColumn): void;
142
184
  private compareValues;
143
185
  static ɵfac: i0.ɵɵFactoryDeclaration<DynamicTableComponent, never>;
144
- static ɵcmp: i0.ɵɵComponentDeclaration<DynamicTableComponent, "app-dynamic-table", never, { "data": "data"; "columns": "columns"; "emptyState": "emptyState"; "gridTemplateColumns": "gridTemplateColumns"; "screenWidth": "screenWidth"; "enableSelectAll": "enableSelectAll"; "rowSelectable": "rowSelectable"; "enableLocalSort": "enableLocalSort"; "isTableLoading": "isTableLoading"; "isTableDataLoading": "isTableDataLoading"; "cellJsonPathGetter": "cellJsonPathGetter"; "onJsonPathCopiedHandler": "onJsonPathCopiedHandler"; }, { "sortChange": "sortChange"; }, ["emptyTableTpl", "cellTemplates", "headerTemplates"], never>;
186
+ static ɵcmp: i0.ɵɵComponentDeclaration<DynamicTableComponent, "app-dynamic-table", never, { "data": "data"; "columns": "columns"; "emptyState": "emptyState"; "gridTemplateColumns": "gridTemplateColumns"; "screenWidth": "screenWidth"; "enableSelectAll": "enableSelectAll"; "rowSelectable": "rowSelectable"; "enableLocalSort": "enableLocalSort"; "isTableLoading": "isTableLoading"; "isTableDataLoading": "isTableDataLoading"; "cellJsonPathGetter": "cellJsonPathGetter"; "onJsonPathCopiedHandler": "onJsonPathCopiedHandler"; "enableRowReorder": "enableRowReorder"; "reorderHandleTooltip": "reorderHandleTooltip"; }, { "sortChange": "sortChange"; "rowReorder": "rowReorder"; }, ["emptyTableTpl", "cellTemplates", "headerTemplates"], never>;
145
187
  }
@@ -0,0 +1,34 @@
1
+ import { ChangeDetectorRef, EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';
2
+ import { FolderDeleteStrategy, ModularLabels } from '../modular-table-template.models';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Body of the "Delete folder" dialog — a radio-card picker for what happens to
6
+ * the folder's contained test cases.
7
+ *
8
+ * Designed to be usable two ways:
9
+ *
10
+ * 1. **From within this library** via `DialogService.open(...)`. The outer
11
+ * `cqa-dialog` supplies the title/Cancel/Delete-folder buttons; the Delete
12
+ * button reads `strategy` via `getComponentInstance()`.
13
+ *
14
+ * 2. **From the host/UI layer directly** — hosts render this inside their own
15
+ * modal and observe `(strategyChange)`.
16
+ */
17
+ export declare class DeleteFolderDialogComponent implements OnInit, OnChanges {
18
+ private cdr;
19
+ folderName: string;
20
+ testCount: number;
21
+ hasParent: boolean;
22
+ labels: ModularLabels;
23
+ strategy: FolderDeleteStrategy;
24
+ strategyChange: EventEmitter<FolderDeleteStrategy>;
25
+ constructor(cdr: ChangeDetectorRef);
26
+ ngOnInit(): void;
27
+ ngOnChanges(changes: SimpleChanges): void;
28
+ /** If the folder has no parent, the "move to parent" option isn't available — fall back. */
29
+ private normaliseStrategy;
30
+ get bodyText(): string;
31
+ setStrategy(value: FolderDeleteStrategy): void;
32
+ static ɵfac: i0.ɵɵFactoryDeclaration<DeleteFolderDialogComponent, never>;
33
+ static ɵcmp: i0.ɵɵComponentDeclaration<DeleteFolderDialogComponent, "cqa-delete-folder-dialog", never, { "folderName": "folderName"; "testCount": "testCount"; "hasParent": "hasParent"; "labels": "labels"; "strategy": "strategy"; }, { "strategyChange": "strategyChange"; }, never, never>;
34
+ }
@@ -0,0 +1,57 @@
1
+ import { ChangeDetectorRef, EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';
2
+ import { FolderNode, ModularLabels } from '../modular-table-template.models';
3
+ import * as i0 from "@angular/core";
4
+ interface FlatFolderRow {
5
+ id: number | null;
6
+ name: string;
7
+ depth: number;
8
+ disabled: boolean;
9
+ hasChildren: boolean;
10
+ expanded: boolean;
11
+ }
12
+ /**
13
+ * Folder-picker body used inside the Move-to-Folder dialog.
14
+ *
15
+ * This component is designed to be usable two ways:
16
+ *
17
+ * 1. **From inside the library** via `DialogService.open({ content: { type: 'component', component: MoveToFolderDialogComponent, inputs: {...} } })`.
18
+ * The outer `cqa-dialog` provides the title, description, Cancel and "Move here"
19
+ * buttons; the Move button reads `pickedFolderId` via `dialogRef.getComponentInstance()`.
20
+ *
21
+ * 2. **From the host/UI layer directly** once API ownership moves up. The host
22
+ * renders `<cqa-move-to-folder-dialog>` inside its own modal shell and
23
+ * listens to `(folderPicked)` (fires on every pick) to drive its own "Move here"
24
+ * button. All visual state lives on `pickedFolderId` so hosts can also two-way
25
+ * bind if they prefer.
26
+ */
27
+ export declare class MoveToFolderDialogComponent implements OnInit, OnChanges {
28
+ private cdr;
29
+ /** Folder tree to pick from. */
30
+ folders: FolderNode[];
31
+ /** Label overrides. */
32
+ labels: ModularLabels;
33
+ /** The folder the tests currently live in — rendered as disabled (can't move into itself). */
34
+ currentFolderId: number | null;
35
+ /** Controls which folder is visually selected. Two-way-bind friendly via `pickedFolderIdChange`. */
36
+ pickedFolderId: number | null;
37
+ /** Folder ids to expand by default. If not provided, ancestors of `currentFolderId` are expanded. */
38
+ initialExpandedIds?: number[];
39
+ /** Fires whenever the user picks a destination. */
40
+ folderPicked: EventEmitter<number>;
41
+ /** Companion output for banana-in-the-box `[(pickedFolderId)]` binding. */
42
+ pickedFolderIdChange: EventEmitter<number>;
43
+ private expandedIds;
44
+ constructor(cdr: ChangeDetectorRef);
45
+ ngOnInit(): void;
46
+ ngOnChanges(changes: SimpleChanges): void;
47
+ private seedExpandedIds;
48
+ private collectAncestors;
49
+ get flatRows(): FlatFolderRow[];
50
+ isPicked(id: number | null): boolean;
51
+ pick(id: number | null): void;
52
+ toggleExpanded(id: number, event: Event): void;
53
+ trackById: (_: number, row: FlatFolderRow) => number;
54
+ static ɵfac: i0.ɵɵFactoryDeclaration<MoveToFolderDialogComponent, never>;
55
+ static ɵcmp: i0.ɵɵComponentDeclaration<MoveToFolderDialogComponent, "cqa-move-to-folder-dialog", never, { "folders": "folders"; "labels": "labels"; "currentFolderId": "currentFolderId"; "pickedFolderId": "pickedFolderId"; "initialExpandedIds": "initialExpandedIds"; }, { "folderPicked": "folderPicked"; "pickedFolderIdChange": "pickedFolderIdChange"; }, never, never>;
56
+ }
57
+ export {};
@@ -0,0 +1,79 @@
1
+ import { ChangeDetectorRef, EventEmitter, OnInit } from '@angular/core';
2
+ import { FormGroup } from '@angular/forms';
3
+ import { DynamicSelectFieldConfig } from '../../../dynamic-select/dynamic-select-field.component';
4
+ import { FolderNode, ModularLabels } from '../modular-table-template.models';
5
+ import * as i0 from "@angular/core";
6
+ export declare const DEFAULT_FOLDER_COLOR = "#99999E";
7
+ /**
8
+ * Body of the "New Folder" dialog.
9
+ *
10
+ * Uses reusable library components (`cqa-custom-input` for the name field,
11
+ * `cqa-dynamic-select` for the parent dropdown) so hosts can drop this dialog
12
+ * into their own modal shell without worrying about styling drift.
13
+ *
14
+ * Two integration paths:
15
+ *
16
+ * 1. **From within this library** via `DialogService.open(...)`. The outer
17
+ * `cqa-dialog` supplies title/description/Cancel/Create-folder buttons; the
18
+ * Create button reads `name` + `parentId` via `getComponentInstance()`.
19
+ *
20
+ * 2. **Host-driven** — host renders `<cqa-new-folder-dialog>` inside its own
21
+ * modal and listens to `(submitted)` / `(cancelled)` / `(nameChange)` /
22
+ * `(parentIdChange)`.
23
+ */
24
+ export declare class NewFolderDialogComponent implements OnInit {
25
+ private cdr;
26
+ private _folders;
27
+ set folders(value: FolderNode[]);
28
+ get folders(): FolderNode[];
29
+ private _labels;
30
+ set labels(value: ModularLabels);
31
+ get labels(): ModularLabels;
32
+ name: string;
33
+ private _parentId;
34
+ set parentId(value: number | null);
35
+ get parentId(): number | null;
36
+ color: string;
37
+ readonly presetColors: string[];
38
+ readonly rainbowBorder: string;
39
+ nameChange: EventEmitter<string>;
40
+ parentIdChange: EventEmitter<number>;
41
+ colorChange: EventEmitter<string>;
42
+ submitted: EventEmitter<{
43
+ name: string;
44
+ parentId: number | null;
45
+ color: string;
46
+ }>;
47
+ cancelled: EventEmitter<void>;
48
+ /** Reactive form used by cqa-dynamic-select. Untyped to match the project's Angular 13.4 forms API. */
49
+ parentForm: FormGroup;
50
+ /**
51
+ * Config passed to `cqa-dynamic-select`. Stored as a field (not a getter) so
52
+ * the object reference is stable across change-detection passes — a getter
53
+ * returns a fresh object every CD tick and causes
54
+ * `ExpressionChangedAfterItHasBeenCheckedError` + repeated `ngOnChanges` on
55
+ * the child select. Other consumers in this lib (e.g. `loop-step`) follow
56
+ * the same pattern.
57
+ */
58
+ parentSelectConfig: DynamicSelectFieldConfig;
59
+ private parentOptions;
60
+ constructor(cdr: ChangeDetectorRef);
61
+ ngOnInit(): void;
62
+ private rebuildSelectConfig;
63
+ private rebuildOptions;
64
+ private syncParentControl;
65
+ onNameChange(value: string): void;
66
+ onParentSelectionChange(event: {
67
+ key: string;
68
+ value: any;
69
+ }): void;
70
+ isColor(c: string): boolean;
71
+ get isCustomColor(): boolean;
72
+ onColorChange(value: string): void;
73
+ onColorInputEvent(event: Event): void;
74
+ /** Returns true when the current state is a valid submission (non-empty, trimmed name). */
75
+ get isValid(): boolean;
76
+ submit(): void;
77
+ static ɵfac: i0.ɵɵFactoryDeclaration<NewFolderDialogComponent, never>;
78
+ static ɵcmp: i0.ɵɵComponentDeclaration<NewFolderDialogComponent, "cqa-new-folder-dialog", never, { "folders": "folders"; "labels": "labels"; "name": "name"; "parentId": "parentId"; "color": "color"; }, { "nameChange": "nameChange"; "parentIdChange": "parentIdChange"; "colorChange": "colorChange"; "submitted": "submitted"; "cancelled": "cancelled"; }, never, never>;
79
+ }
@@ -0,0 +1,10 @@
1
+ import * as i0 from "@angular/core";
2
+ export declare class FolderDragDirective {
3
+ /** Folder id being dragged. */
4
+ folderId: number | null;
5
+ dragEnabled: boolean;
6
+ get draggable(): string;
7
+ onDragStart(event: DragEvent): void;
8
+ static ɵfac: i0.ɵɵFactoryDeclaration<FolderDragDirective, never>;
9
+ static ɵdir: i0.ɵɵDirectiveDeclaration<FolderDragDirective, "[cqaFolderDrag]", never, { "folderId": "cqaFolderDrag"; "dragEnabled": "dragEnabled"; }, {}, never>;
10
+ }
@@ -0,0 +1,22 @@
1
+ import { EventEmitter } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ export declare class FolderDropDirective {
4
+ /** Folder id this drop target represents. `null` means "unorganised / root". */
5
+ targetFolderId: number | null;
6
+ dropEnabled: boolean;
7
+ testsDropped: EventEmitter<{
8
+ testIds: Array<string | number>;
9
+ targetFolderId: number | null;
10
+ }>;
11
+ /** Fires when a folder row is dropped here. `folderId` is the dragged folder's id. */
12
+ folderDropped: EventEmitter<{
13
+ folderId: number;
14
+ targetFolderId: number | null;
15
+ }>;
16
+ isOver: boolean;
17
+ onDragOver(event: DragEvent): void;
18
+ onDragLeave(): void;
19
+ onDrop(event: DragEvent): void;
20
+ static ɵfac: i0.ɵɵFactoryDeclaration<FolderDropDirective, never>;
21
+ static ɵdir: i0.ɵɵDirectiveDeclaration<FolderDropDirective, "[cqaFolderDrop]", never, { "targetFolderId": "cqaFolderDrop"; "dropEnabled": "dropEnabled"; }, { "testsDropped": "testsDropped"; "folderDropped": "folderDropped"; }, never>;
22
+ }
@@ -0,0 +1,10 @@
1
+ import * as i0 from "@angular/core";
2
+ export declare class RowDragDirective {
3
+ /** Function that returns the test id payload for this row (array of ids). */
4
+ buildPayload: () => Array<string | number>;
5
+ dragEnabled: boolean;
6
+ get draggable(): string;
7
+ onDragStart(event: DragEvent): void;
8
+ static ɵfac: i0.ɵɵFactoryDeclaration<RowDragDirective, never>;
9
+ static ɵdir: i0.ɵɵDirectiveDeclaration<RowDragDirective, "[cqaRowDrag]", never, { "buildPayload": "cqaRowDrag"; "dragEnabled": "dragEnabled"; }, {}, never>;
10
+ }
@@ -0,0 +1,149 @@
1
+ import { ChangeDetectorRef, EventEmitter, OnDestroy } from '@angular/core';
2
+ import { FolderNode, FolderRenamedPayload, ModularLabels } from '../modular-table-template.models';
3
+ import * as i0 from "@angular/core";
4
+ interface RenderNode {
5
+ node: FolderNode;
6
+ depth: number;
7
+ visible: boolean;
8
+ hasChildren: boolean;
9
+ }
10
+ export declare class FolderSidebarComponent implements OnDestroy {
11
+ private cdr;
12
+ folders: FolderNode[];
13
+ selectedFolderId: number | null;
14
+ expandedFolderIds: number[];
15
+ unorganisedCount: number;
16
+ allowCreate: boolean;
17
+ allowRename: boolean;
18
+ allowDelete: boolean;
19
+ allowMove: boolean;
20
+ allowDuplicate: boolean;
21
+ allowDrop: boolean;
22
+ showCounts: boolean;
23
+ collapsed: boolean;
24
+ labels: ModularLabels;
25
+ folderSelected: EventEmitter<number>;
26
+ folderExpansionToggled: EventEmitter<{
27
+ id: number;
28
+ expanded: boolean;
29
+ }>;
30
+ /** Emitted after the host completes folder creation (e.g., inline rename flow). Reserved for future use. */
31
+ folderCreated: EventEmitter<{
32
+ parentId: number | null;
33
+ name: string;
34
+ }>;
35
+ /** Emitted when the user clicks the "+" header button. Host should open a creation modal. */
36
+ folderCreateRequested: EventEmitter<{
37
+ parentId: number | null;
38
+ }>;
39
+ /** Carries the full renamed folder node + parent id so hosts can issue complete update requests. */
40
+ folderRenamed: EventEmitter<FolderRenamedPayload>;
41
+ folderDeleted: EventEmitter<{
42
+ id: number;
43
+ }>;
44
+ /** User picked "Move folder" from the context menu. Host opens the folder picker. */
45
+ folderMoveRequested: EventEmitter<{
46
+ id: number;
47
+ }>;
48
+ /** User picked "Duplicate folder" from the context menu. Host clones the subtree (tests referenced, not copied). */
49
+ folderDuplicateRequested: EventEmitter<{
50
+ id: number;
51
+ }>;
52
+ testsDropped: EventEmitter<{
53
+ testIds: Array<string | number>;
54
+ targetFolderId: number | null;
55
+ }>;
56
+ /** Fires when a folder row is dropped onto another folder (or the Unorganised row). */
57
+ folderDropped: EventEmitter<{
58
+ id: number;
59
+ newParentId: number | null;
60
+ }>;
61
+ collapsedChange: EventEmitter<boolean>;
62
+ searchValue: string;
63
+ renamingId: number | null;
64
+ renameDraft: string;
65
+ /** Id of the folder whose context menu is open, or null when closed. */
66
+ contextMenuFolderId: number | null;
67
+ /** Viewport-anchored position (client coordinates) for the floating menu. */
68
+ contextMenuPosition: {
69
+ x: number;
70
+ y: number;
71
+ };
72
+ /** Pending auto-expand timers while a folder drag is hovered over collapsed rows. */
73
+ private dragExpandTimers;
74
+ private readonly DRAG_EXPAND_DELAY_MS;
75
+ /** Id of the folder currently being dragged; used to skip cycle targets and source-hover expansion. */
76
+ private activeFolderDragId;
77
+ constructor(cdr: ChangeDetectorRef);
78
+ get expandedSet(): Set<number>;
79
+ /** Flattened, depth-aware list of rows to render in order. Ancestors of matches are kept. */
80
+ get rows(): RenderNode[];
81
+ isExpanded(id: number): boolean;
82
+ isSelected(id: number | null): boolean;
83
+ onToggle(n: FolderNode, event: Event): void;
84
+ onSelect(n: FolderNode | null): void;
85
+ onSelectUnorganised(): void;
86
+ beginRename(n: FolderNode, event: Event): void;
87
+ commitRename(n: FolderNode): void;
88
+ cancelRename(): void;
89
+ onRenameKey(event: KeyboardEvent, n: FolderNode): void;
90
+ deleteFolder(n: FolderNode, event: Event): void;
91
+ /**
92
+ * Opens the folder context menu anchored at the given client coordinates.
93
+ * Called from both (contextmenu) on the row and (click) on the ellipsis button.
94
+ * Menu visibility is clamped in the template via CSS transforms so it never leaves the viewport.
95
+ */
96
+ openContextMenu(n: FolderNode, event: MouseEvent): void;
97
+ closeContextMenu(): void;
98
+ /** True when at least one menu entry is enabled — otherwise the trigger is suppressed entirely. */
99
+ get hasAnyContextAction(): boolean;
100
+ onContextCreateSubfolder(n: FolderNode): void;
101
+ onContextRename(n: FolderNode): void;
102
+ onContextMove(n: FolderNode): void;
103
+ onContextDuplicate(n: FolderNode): void;
104
+ onContextDelete(n: FolderNode): void;
105
+ onDocumentClick(): void;
106
+ onEscape(): void;
107
+ /** Template helper: resolve a folder node by id from the input tree. */
108
+ folderById(id: number | null): FolderNode | null;
109
+ /** Returns the parent id of `id`, or null when `id` is a root folder / not found. */
110
+ private parentIdOf;
111
+ requestCreate(parentId?: number | null): void;
112
+ togglePanel(): void;
113
+ rowDropped(targetId: number | null, event: {
114
+ testIds: Array<string | number>;
115
+ targetFolderId: number | null;
116
+ }): void;
117
+ /**
118
+ * Drop target received a folder drag. Validate against self/descendant cycles and
119
+ * emit `folderDropped` if the move is legal. Called from the directive's
120
+ * `(folderDropped)` output on every row and on the Unorganised row.
121
+ */
122
+ onFolderRowDropped(targetId: number | null, event: {
123
+ folderId: number;
124
+ targetFolderId: number | null;
125
+ }): void;
126
+ /** Remember the dragged folder so we can block self-hover expansion and cycle drops. */
127
+ onFolderDragStart(n: FolderNode): void;
128
+ onFolderDragEnd(): void;
129
+ /** Schedule an auto-expand for a collapsed folder that has children during drag-hover. */
130
+ onFolderRowDragOver(row: RenderNode): void;
131
+ onFolderRowDragLeave(row: RenderNode): void;
132
+ onDocumentDragEnd(): void;
133
+ /** True when `candidateId` is `sourceId` itself or any descendant of it. */
134
+ private isDescendantOf;
135
+ private clearAllExpandTimers;
136
+ ngOnDestroy(): void;
137
+ trackByRow: (_: number, row: RenderNode) => number;
138
+ onRowKeydown(event: KeyboardEvent, row: RenderNode, index: number): void;
139
+ private focusRowElement;
140
+ /**
141
+ * Focuses the inline rename input for the given folder. Uses `setTimeout` (not
142
+ * microtask) because the input is gated by `*ngIf="renamingId === ..."` and
143
+ * must survive the next OnPush change-detection cycle before it's in the DOM.
144
+ */
145
+ private focusRenameInput;
146
+ static ɵfac: i0.ɵɵFactoryDeclaration<FolderSidebarComponent, never>;
147
+ static ɵcmp: i0.ɵɵComponentDeclaration<FolderSidebarComponent, "cqa-folder-sidebar", never, { "folders": "folders"; "selectedFolderId": "selectedFolderId"; "expandedFolderIds": "expandedFolderIds"; "unorganisedCount": "unorganisedCount"; "allowCreate": "allowCreate"; "allowRename": "allowRename"; "allowDelete": "allowDelete"; "allowMove": "allowMove"; "allowDuplicate": "allowDuplicate"; "allowDrop": "allowDrop"; "showCounts": "showCounts"; "collapsed": "collapsed"; "labels": "labels"; }, { "folderSelected": "folderSelected"; "folderExpansionToggled": "folderExpansionToggled"; "folderCreated": "folderCreated"; "folderCreateRequested": "folderCreateRequested"; "folderRenamed": "folderRenamed"; "folderDeleted": "folderDeleted"; "folderMoveRequested": "folderMoveRequested"; "folderDuplicateRequested": "folderDuplicateRequested"; "testsDropped": "testsDropped"; "folderDropped": "folderDropped"; "collapsedChange": "collapsedChange"; }, never, never>;
148
+ }
149
+ export {};