@cqa-lib/cqa-ui 1.1.525 → 1.1.526

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 +1 -1
  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 +3408 -178
  24. package/fesm2015/cqa-lib-cqa-ui.mjs.map +1 -1
  25. package/fesm2020/cqa-lib-cqa-ui.mjs +3388 -176
  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
@@ -0,0 +1,181 @@
1
+ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, } from '@angular/core';
2
+ import { DEFAULT_MODULAR_LABELS, } from '../modular-table-template.models';
3
+ import * as i0 from "@angular/core";
4
+ import * as i1 from "@angular/common";
5
+ /**
6
+ * Body of the "Delete folder" dialog — a radio-card picker for what happens to
7
+ * the folder's contained test cases.
8
+ *
9
+ * Designed to be usable two ways:
10
+ *
11
+ * 1. **From within this library** via `DialogService.open(...)`. The outer
12
+ * `cqa-dialog` supplies the title/Cancel/Delete-folder buttons; the Delete
13
+ * button reads `strategy` via `getComponentInstance()`.
14
+ *
15
+ * 2. **From the host/UI layer directly** — hosts render this inside their own
16
+ * modal and observe `(strategyChange)`.
17
+ */
18
+ export class DeleteFolderDialogComponent {
19
+ constructor(cdr) {
20
+ this.cdr = cdr;
21
+ this.folderName = '';
22
+ this.testCount = 0;
23
+ this.hasParent = false;
24
+ this.labels = { ...DEFAULT_MODULAR_LABELS };
25
+ this.strategy = 'MOVE_TO_PARENT';
26
+ this.strategyChange = new EventEmitter();
27
+ }
28
+ ngOnInit() {
29
+ this.normaliseStrategy();
30
+ }
31
+ ngOnChanges(changes) {
32
+ if (changes['hasParent'])
33
+ this.normaliseStrategy();
34
+ }
35
+ /** If the folder has no parent, the "move to parent" option isn't available — fall back. */
36
+ normaliseStrategy() {
37
+ if (!this.hasParent && this.strategy === 'MOVE_TO_PARENT') {
38
+ this.strategy = 'MOVE_TO_UNORGANISED';
39
+ }
40
+ }
41
+ get bodyText() {
42
+ const template = this.testCount === 1
43
+ ? this.labels.deleteFolderDialogBodySingular
44
+ : this.labels.deleteFolderDialogBodyPlural;
45
+ return template.replace('{n}', '' + this.testCount);
46
+ }
47
+ setStrategy(value) {
48
+ if (this.strategy === value)
49
+ return;
50
+ this.strategy = value;
51
+ this.strategyChange.emit(value);
52
+ this.cdr.markForCheck();
53
+ }
54
+ }
55
+ DeleteFolderDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: DeleteFolderDialogComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
56
+ DeleteFolderDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: DeleteFolderDialogComponent, selector: "cqa-delete-folder-dialog", inputs: { folderName: "folderName", testCount: "testCount", hasParent: "hasParent", labels: "labels", strategy: "strategy" }, outputs: { strategyChange: "strategyChange" }, host: { classAttribute: "cqa-ui-root" }, usesOnChanges: true, ngImport: i0, template: `
57
+ <div class="cqa-flex cqa-flex-col cqa-gap-4 cqa-w-full">
58
+ <p class="cqa-text-sm cqa-text-neutral-800 cqa-m-0">{{ bodyText }}</p>
59
+
60
+ <div class="cqa-flex cqa-flex-col cqa-gap-3">
61
+ <!-- Option 1: Move to parent folder (hidden when folder has no parent) -->
62
+ <button
63
+ *ngIf="hasParent"
64
+ type="button"
65
+ class="cqa-flex cqa-items-start cqa-gap-3 cqa-text-left cqa-p-4 cqa-rounded-[10px] cqa-border-solid cqa-border cqa-transition-colors cqa-w-full"
66
+ [ngClass]="strategy === 'MOVE_TO_PARENT' ? 'cqa-border-indigo-500 cqa-bg-indigo-50' : 'cqa-border-[#E2E2E3] hover:cqa-border-neutral-300 cqa-bg-white'"
67
+ (click)="setStrategy('MOVE_TO_PARENT')"
68
+ >
69
+ <ng-container *ngTemplateOutlet="radio; context: { checked: strategy === 'MOVE_TO_PARENT' }"></ng-container>
70
+ <div class="cqa-flex cqa-flex-col cqa-gap-1 cqa-min-w-0">
71
+ <span class="cqa-text-sm cqa-font-semibold cqa-text-neutral-900">
72
+ {{ labels.deleteFolderDialogMoveToParentTitle }}
73
+ </span>
74
+ <span class="cqa-text-sm cqa-text-neutral-500">
75
+ {{ labels.deleteFolderDialogMoveToParentDescription }}
76
+ </span>
77
+ </div>
78
+ </button>
79
+
80
+ <!-- Option 2: Move to Unorganised -->
81
+ <button
82
+ type="button"
83
+ class="cqa-flex cqa-items-start cqa-gap-3 cqa-text-left cqa-p-4 cqa-rounded-[10px] cqa-border-solid cqa-border cqa-transition-colors cqa-w-full"
84
+ [ngClass]="strategy === 'MOVE_TO_UNORGANISED' ? 'cqa-border-indigo-500 cqa-bg-indigo-50' : 'cqa-border-[#E2E2E3] hover:cqa-border-neutral-300 cqa-bg-white'"
85
+ (click)="setStrategy('MOVE_TO_UNORGANISED')"
86
+ >
87
+ <ng-container *ngTemplateOutlet="radio; context: { checked: strategy === 'MOVE_TO_UNORGANISED' }"></ng-container>
88
+ <div class="cqa-flex cqa-flex-col cqa-gap-1 cqa-min-w-0">
89
+ <span class="cqa-text-sm cqa-font-semibold cqa-text-neutral-900">
90
+ {{ labels.deleteFolderDialogMoveToUnorganisedTitle }}
91
+ </span>
92
+ <span class="cqa-text-sm cqa-text-neutral-500">
93
+ {{ labels.deleteFolderDialogMoveToUnorganisedDescription }}
94
+ </span>
95
+ </div>
96
+ </button>
97
+ </div>
98
+ </div>
99
+
100
+ <!-- Reusable radio bullet -->
101
+ <ng-template #radio let-checked="checked">
102
+ <span
103
+ class="cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-5 cqa-h-5 cqa-rounded-full cqa-border-solid cqa-shrink-0 cqa-mt-0.5"
104
+ [ngClass]="checked ? 'cqa-border-indigo-600' : 'cqa-border-neutral-400'"
105
+ [style.borderWidth]="'2px'"
106
+ >
107
+ <span *ngIf="checked" class="cqa-w-2.5 cqa-h-2.5 cqa-rounded-full cqa-bg-indigo-600"></span>
108
+ </span>
109
+ </ng-template>
110
+ `, isInline: true, directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
111
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: DeleteFolderDialogComponent, decorators: [{
112
+ type: Component,
113
+ args: [{ selector: 'cqa-delete-folder-dialog', template: `
114
+ <div class="cqa-flex cqa-flex-col cqa-gap-4 cqa-w-full">
115
+ <p class="cqa-text-sm cqa-text-neutral-800 cqa-m-0">{{ bodyText }}</p>
116
+
117
+ <div class="cqa-flex cqa-flex-col cqa-gap-3">
118
+ <!-- Option 1: Move to parent folder (hidden when folder has no parent) -->
119
+ <button
120
+ *ngIf="hasParent"
121
+ type="button"
122
+ class="cqa-flex cqa-items-start cqa-gap-3 cqa-text-left cqa-p-4 cqa-rounded-[10px] cqa-border-solid cqa-border cqa-transition-colors cqa-w-full"
123
+ [ngClass]="strategy === 'MOVE_TO_PARENT' ? 'cqa-border-indigo-500 cqa-bg-indigo-50' : 'cqa-border-[#E2E2E3] hover:cqa-border-neutral-300 cqa-bg-white'"
124
+ (click)="setStrategy('MOVE_TO_PARENT')"
125
+ >
126
+ <ng-container *ngTemplateOutlet="radio; context: { checked: strategy === 'MOVE_TO_PARENT' }"></ng-container>
127
+ <div class="cqa-flex cqa-flex-col cqa-gap-1 cqa-min-w-0">
128
+ <span class="cqa-text-sm cqa-font-semibold cqa-text-neutral-900">
129
+ {{ labels.deleteFolderDialogMoveToParentTitle }}
130
+ </span>
131
+ <span class="cqa-text-sm cqa-text-neutral-500">
132
+ {{ labels.deleteFolderDialogMoveToParentDescription }}
133
+ </span>
134
+ </div>
135
+ </button>
136
+
137
+ <!-- Option 2: Move to Unorganised -->
138
+ <button
139
+ type="button"
140
+ class="cqa-flex cqa-items-start cqa-gap-3 cqa-text-left cqa-p-4 cqa-rounded-[10px] cqa-border-solid cqa-border cqa-transition-colors cqa-w-full"
141
+ [ngClass]="strategy === 'MOVE_TO_UNORGANISED' ? 'cqa-border-indigo-500 cqa-bg-indigo-50' : 'cqa-border-[#E2E2E3] hover:cqa-border-neutral-300 cqa-bg-white'"
142
+ (click)="setStrategy('MOVE_TO_UNORGANISED')"
143
+ >
144
+ <ng-container *ngTemplateOutlet="radio; context: { checked: strategy === 'MOVE_TO_UNORGANISED' }"></ng-container>
145
+ <div class="cqa-flex cqa-flex-col cqa-gap-1 cqa-min-w-0">
146
+ <span class="cqa-text-sm cqa-font-semibold cqa-text-neutral-900">
147
+ {{ labels.deleteFolderDialogMoveToUnorganisedTitle }}
148
+ </span>
149
+ <span class="cqa-text-sm cqa-text-neutral-500">
150
+ {{ labels.deleteFolderDialogMoveToUnorganisedDescription }}
151
+ </span>
152
+ </div>
153
+ </button>
154
+ </div>
155
+ </div>
156
+
157
+ <!-- Reusable radio bullet -->
158
+ <ng-template #radio let-checked="checked">
159
+ <span
160
+ class="cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-5 cqa-h-5 cqa-rounded-full cqa-border-solid cqa-shrink-0 cqa-mt-0.5"
161
+ [ngClass]="checked ? 'cqa-border-indigo-600' : 'cqa-border-neutral-400'"
162
+ [style.borderWidth]="'2px'"
163
+ >
164
+ <span *ngIf="checked" class="cqa-w-2.5 cqa-h-2.5 cqa-rounded-full cqa-bg-indigo-600"></span>
165
+ </span>
166
+ </ng-template>
167
+ `, host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [] }]
168
+ }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { folderName: [{
169
+ type: Input
170
+ }], testCount: [{
171
+ type: Input
172
+ }], hasParent: [{
173
+ type: Input
174
+ }], labels: [{
175
+ type: Input
176
+ }], strategy: [{
177
+ type: Input
178
+ }], strategyChange: [{
179
+ type: Output
180
+ }] } });
181
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVsZXRlLWZvbGRlci1kaWFsb2cuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi90ZW1wbGF0ZXMvbW9kdWxhci10YWJsZS10ZW1wbGF0ZS9kaWFsb2dzL2RlbGV0ZS1mb2xkZXItZGlhbG9nLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsdUJBQXVCLEVBRXZCLFNBQVMsRUFDVCxZQUFZLEVBQ1osS0FBSyxFQUdMLE1BQU0sR0FFUCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQ0wsc0JBQXNCLEdBR3ZCLE1BQU0sa0NBQWtDLENBQUM7OztBQUUxQzs7Ozs7Ozs7Ozs7O0dBWUc7QUE4REgsTUFBTSxPQUFPLDJCQUEyQjtJQVN0QyxZQUFvQixHQUFzQjtRQUF0QixRQUFHLEdBQUgsR0FBRyxDQUFtQjtRQVJqQyxlQUFVLEdBQVcsRUFBRSxDQUFDO1FBQ3hCLGNBQVMsR0FBVyxDQUFDLENBQUM7UUFDdEIsY0FBUyxHQUFZLEtBQUssQ0FBQztRQUMzQixXQUFNLEdBQWtCLEVBQUUsR0FBRyxzQkFBc0IsRUFBRSxDQUFDO1FBQ3RELGFBQVEsR0FBeUIsZ0JBQWdCLENBQUM7UUFFakQsbUJBQWMsR0FBRyxJQUFJLFlBQVksRUFBd0IsQ0FBQztJQUV2QixDQUFDO0lBRTlDLFFBQVE7UUFDTixJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRUQsV0FBVyxDQUFDLE9BQXNCO1FBQ2hDLElBQUksT0FBTyxDQUFDLFdBQVcsQ0FBQztZQUFFLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO0lBQ3JELENBQUM7SUFFRCw0RkFBNEY7SUFDcEYsaUJBQWlCO1FBQ3ZCLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxJQUFJLElBQUksQ0FBQyxRQUFRLEtBQUssZ0JBQWdCLEVBQUU7WUFDekQsSUFBSSxDQUFDLFFBQVEsR0FBRyxxQkFBcUIsQ0FBQztTQUN2QztJQUNILENBQUM7SUFFRCxJQUFJLFFBQVE7UUFDVixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsU0FBUyxLQUFLLENBQUM7WUFDbkMsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsOEJBQThCO1lBQzVDLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLDRCQUE0QixDQUFDO1FBQzdDLE9BQU8sUUFBUSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRUQsV0FBVyxDQUFDLEtBQTJCO1FBQ3JDLElBQUksSUFBSSxDQUFDLFFBQVEsS0FBSyxLQUFLO1lBQUUsT0FBTztRQUNwQyxJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztRQUN0QixJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNoQyxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQzFCLENBQUM7O3dIQXRDVSwyQkFBMkI7NEdBQTNCLDJCQUEyQiwyU0EzRDVCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FzRFQ7MkZBS1UsMkJBQTJCO2tCQTdEdkMsU0FBUzsrQkFDRSwwQkFBMEIsWUFDMUI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNEVCxRQUVLLEVBQUUsS0FBSyxFQUFFLGFBQWEsRUFBRSxtQkFDYix1QkFBdUIsQ0FBQyxNQUFNO3dHQUd0QyxVQUFVO3NCQUFsQixLQUFLO2dCQUNHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFFSSxjQUFjO3NCQUF2QixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gIENoYW5nZURldGVjdG9yUmVmLFxuICBDb21wb25lbnQsXG4gIEV2ZW50RW1pdHRlcixcbiAgSW5wdXQsXG4gIE9uQ2hhbmdlcyxcbiAgT25Jbml0LFxuICBPdXRwdXQsXG4gIFNpbXBsZUNoYW5nZXMsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgREVGQVVMVF9NT0RVTEFSX0xBQkVMUyxcbiAgRm9sZGVyRGVsZXRlU3RyYXRlZ3ksXG4gIE1vZHVsYXJMYWJlbHMsXG59IGZyb20gJy4uL21vZHVsYXItdGFibGUtdGVtcGxhdGUubW9kZWxzJztcblxuLyoqXG4gKiBCb2R5IG9mIHRoZSBcIkRlbGV0ZSBmb2xkZXJcIiBkaWFsb2cg4oCUIGEgcmFkaW8tY2FyZCBwaWNrZXIgZm9yIHdoYXQgaGFwcGVucyB0b1xuICogdGhlIGZvbGRlcidzIGNvbnRhaW5lZCB0ZXN0IGNhc2VzLlxuICpcbiAqIERlc2lnbmVkIHRvIGJlIHVzYWJsZSB0d28gd2F5czpcbiAqXG4gKiAgMS4gKipGcm9tIHdpdGhpbiB0aGlzIGxpYnJhcnkqKiB2aWEgYERpYWxvZ1NlcnZpY2Uub3BlbiguLi4pYC4gVGhlIG91dGVyXG4gKiAgICAgYGNxYS1kaWFsb2dgIHN1cHBsaWVzIHRoZSB0aXRsZS9DYW5jZWwvRGVsZXRlLWZvbGRlciBidXR0b25zOyB0aGUgRGVsZXRlXG4gKiAgICAgYnV0dG9uIHJlYWRzIGBzdHJhdGVneWAgdmlhIGBnZXRDb21wb25lbnRJbnN0YW5jZSgpYC5cbiAqXG4gKiAgMi4gKipGcm9tIHRoZSBob3N0L1VJIGxheWVyIGRpcmVjdGx5Kiog4oCUIGhvc3RzIHJlbmRlciB0aGlzIGluc2lkZSB0aGVpciBvd25cbiAqICAgICBtb2RhbCBhbmQgb2JzZXJ2ZSBgKHN0cmF0ZWd5Q2hhbmdlKWAuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2NxYS1kZWxldGUtZm9sZGVyLWRpYWxvZycsXG4gIHRlbXBsYXRlOiBgXG4gICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1mbGV4LWNvbCBjcWEtZ2FwLTQgY3FhLXctZnVsbFwiPlxuICAgICAgPHAgY2xhc3M9XCJjcWEtdGV4dC1zbSBjcWEtdGV4dC1uZXV0cmFsLTgwMCBjcWEtbS0wXCI+e3sgYm9keVRleHQgfX08L3A+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtZmxleC1jb2wgY3FhLWdhcC0zXCI+XG4gICAgICAgIDwhLS0gT3B0aW9uIDE6IE1vdmUgdG8gcGFyZW50IGZvbGRlciAoaGlkZGVuIHdoZW4gZm9sZGVyIGhhcyBubyBwYXJlbnQpIC0tPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgKm5nSWY9XCJoYXNQYXJlbnRcIlxuICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgIGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLXN0YXJ0IGNxYS1nYXAtMyBjcWEtdGV4dC1sZWZ0IGNxYS1wLTQgY3FhLXJvdW5kZWQtWzEwcHhdIGNxYS1ib3JkZXItc29saWQgY3FhLWJvcmRlciBjcWEtdHJhbnNpdGlvbi1jb2xvcnMgY3FhLXctZnVsbFwiXG4gICAgICAgICAgW25nQ2xhc3NdPVwic3RyYXRlZ3kgPT09ICdNT1ZFX1RPX1BBUkVOVCcgPyAnY3FhLWJvcmRlci1pbmRpZ28tNTAwIGNxYS1iZy1pbmRpZ28tNTAnIDogJ2NxYS1ib3JkZXItWyNFMkUyRTNdIGhvdmVyOmNxYS1ib3JkZXItbmV1dHJhbC0zMDAgY3FhLWJnLXdoaXRlJ1wiXG4gICAgICAgICAgKGNsaWNrKT1cInNldFN0cmF0ZWd5KCdNT1ZFX1RPX1BBUkVOVCcpXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJyYWRpbzsgY29udGV4dDogeyBjaGVja2VkOiBzdHJhdGVneSA9PT0gJ01PVkVfVE9fUEFSRU5UJyB9XCI+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1mbGV4LWNvbCBjcWEtZ2FwLTEgY3FhLW1pbi13LTBcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiY3FhLXRleHQtc20gY3FhLWZvbnQtc2VtaWJvbGQgY3FhLXRleHQtbmV1dHJhbC05MDBcIj5cbiAgICAgICAgICAgICAge3sgbGFiZWxzLmRlbGV0ZUZvbGRlckRpYWxvZ01vdmVUb1BhcmVudFRpdGxlIH19XG4gICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImNxYS10ZXh0LXNtIGNxYS10ZXh0LW5ldXRyYWwtNTAwXCI+XG4gICAgICAgICAgICAgIHt7IGxhYmVscy5kZWxldGVGb2xkZXJEaWFsb2dNb3ZlVG9QYXJlbnREZXNjcmlwdGlvbiB9fVxuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2J1dHRvbj5cblxuICAgICAgICA8IS0tIE9wdGlvbiAyOiBNb3ZlIHRvIFVub3JnYW5pc2VkIC0tPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgY2xhc3M9XCJjcWEtZmxleCBjcWEtaXRlbXMtc3RhcnQgY3FhLWdhcC0zIGNxYS10ZXh0LWxlZnQgY3FhLXAtNCBjcWEtcm91bmRlZC1bMTBweF0gY3FhLWJvcmRlci1zb2xpZCBjcWEtYm9yZGVyIGNxYS10cmFuc2l0aW9uLWNvbG9ycyBjcWEtdy1mdWxsXCJcbiAgICAgICAgICBbbmdDbGFzc109XCJzdHJhdGVneSA9PT0gJ01PVkVfVE9fVU5PUkdBTklTRUQnID8gJ2NxYS1ib3JkZXItaW5kaWdvLTUwMCBjcWEtYmctaW5kaWdvLTUwJyA6ICdjcWEtYm9yZGVyLVsjRTJFMkUzXSBob3ZlcjpjcWEtYm9yZGVyLW5ldXRyYWwtMzAwIGNxYS1iZy13aGl0ZSdcIlxuICAgICAgICAgIChjbGljayk9XCJzZXRTdHJhdGVneSgnTU9WRV9UT19VTk9SR0FOSVNFRCcpXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJyYWRpbzsgY29udGV4dDogeyBjaGVja2VkOiBzdHJhdGVneSA9PT0gJ01PVkVfVE9fVU5PUkdBTklTRUQnIH1cIj48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWZsZXgtY29sIGNxYS1nYXAtMSBjcWEtbWluLXctMFwiPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtdGV4dC1zbSBjcWEtZm9udC1zZW1pYm9sZCBjcWEtdGV4dC1uZXV0cmFsLTkwMFwiPlxuICAgICAgICAgICAgICB7eyBsYWJlbHMuZGVsZXRlRm9sZGVyRGlhbG9nTW92ZVRvVW5vcmdhbmlzZWRUaXRsZSB9fVxuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtdGV4dC1zbSBjcWEtdGV4dC1uZXV0cmFsLTUwMFwiPlxuICAgICAgICAgICAgICB7eyBsYWJlbHMuZGVsZXRlRm9sZGVyRGlhbG9nTW92ZVRvVW5vcmdhbmlzZWREZXNjcmlwdGlvbiB9fVxuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPCEtLSBSZXVzYWJsZSByYWRpbyBidWxsZXQgLS0+XG4gICAgPG5nLXRlbXBsYXRlICNyYWRpbyBsZXQtY2hlY2tlZD1cImNoZWNrZWRcIj5cbiAgICAgIDxzcGFuXG4gICAgICAgIGNsYXNzPVwiY3FhLWlubGluZS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyIGNxYS13LTUgY3FhLWgtNSBjcWEtcm91bmRlZC1mdWxsIGNxYS1ib3JkZXItc29saWQgY3FhLXNocmluay0wIGNxYS1tdC0wLjVcIlxuICAgICAgICBbbmdDbGFzc109XCJjaGVja2VkID8gJ2NxYS1ib3JkZXItaW5kaWdvLTYwMCcgOiAnY3FhLWJvcmRlci1uZXV0cmFsLTQwMCdcIlxuICAgICAgICBbc3R5bGUuYm9yZGVyV2lkdGhdPVwiJzJweCdcIlxuICAgICAgPlxuICAgICAgICA8c3BhbiAqbmdJZj1cImNoZWNrZWRcIiBjbGFzcz1cImNxYS13LTIuNSBjcWEtaC0yLjUgY3FhLXJvdW5kZWQtZnVsbCBjcWEtYmctaW5kaWdvLTYwMFwiPjwvc3Bhbj5cbiAgICAgIDwvc3Bhbj5cbiAgICA8L25nLXRlbXBsYXRlPlxuICBgLFxuICBzdHlsZVVybHM6IFtdLFxuICBob3N0OiB7IGNsYXNzOiAnY3FhLXVpLXJvb3QnIH0sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBEZWxldGVGb2xkZXJEaWFsb2dDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uQ2hhbmdlcyB7XG4gIEBJbnB1dCgpIGZvbGRlck5hbWU6IHN0cmluZyA9ICcnO1xuICBASW5wdXQoKSB0ZXN0Q291bnQ6IG51bWJlciA9IDA7XG4gIEBJbnB1dCgpIGhhc1BhcmVudDogYm9vbGVhbiA9IGZhbHNlO1xuICBASW5wdXQoKSBsYWJlbHM6IE1vZHVsYXJMYWJlbHMgPSB7IC4uLkRFRkFVTFRfTU9EVUxBUl9MQUJFTFMgfTtcbiAgQElucHV0KCkgc3RyYXRlZ3k6IEZvbGRlckRlbGV0ZVN0cmF0ZWd5ID0gJ01PVkVfVE9fUEFSRU5UJztcblxuICBAT3V0cHV0KCkgc3RyYXRlZ3lDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPEZvbGRlckRlbGV0ZVN0cmF0ZWd5PigpO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgY2RyOiBDaGFuZ2VEZXRlY3RvclJlZikge31cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLm5vcm1hbGlzZVN0cmF0ZWd5KCk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgaWYgKGNoYW5nZXNbJ2hhc1BhcmVudCddKSB0aGlzLm5vcm1hbGlzZVN0cmF0ZWd5KCk7XG4gIH1cblxuICAvKiogSWYgdGhlIGZvbGRlciBoYXMgbm8gcGFyZW50LCB0aGUgXCJtb3ZlIHRvIHBhcmVudFwiIG9wdGlvbiBpc24ndCBhdmFpbGFibGUg4oCUIGZhbGwgYmFjay4gKi9cbiAgcHJpdmF0ZSBub3JtYWxpc2VTdHJhdGVneSgpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaGFzUGFyZW50ICYmIHRoaXMuc3RyYXRlZ3kgPT09ICdNT1ZFX1RPX1BBUkVOVCcpIHtcbiAgICAgIHRoaXMuc3RyYXRlZ3kgPSAnTU9WRV9UT19VTk9SR0FOSVNFRCc7XG4gICAgfVxuICB9XG5cbiAgZ2V0IGJvZHlUZXh0KCk6IHN0cmluZyB7XG4gICAgY29uc3QgdGVtcGxhdGUgPSB0aGlzLnRlc3RDb3VudCA9PT0gMVxuICAgICAgPyB0aGlzLmxhYmVscy5kZWxldGVGb2xkZXJEaWFsb2dCb2R5U2luZ3VsYXJcbiAgICAgIDogdGhpcy5sYWJlbHMuZGVsZXRlRm9sZGVyRGlhbG9nQm9keVBsdXJhbDtcbiAgICByZXR1cm4gdGVtcGxhdGUucmVwbGFjZSgne259JywgJycgKyB0aGlzLnRlc3RDb3VudCk7XG4gIH1cblxuICBzZXRTdHJhdGVneSh2YWx1ZTogRm9sZGVyRGVsZXRlU3RyYXRlZ3kpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5zdHJhdGVneSA9PT0gdmFsdWUpIHJldHVybjtcbiAgICB0aGlzLnN0cmF0ZWd5ID0gdmFsdWU7XG4gICAgdGhpcy5zdHJhdGVneUNoYW5nZS5lbWl0KHZhbHVlKTtcbiAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgfVxufVxuIl19
@@ -0,0 +1,264 @@
1
+ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, } from '@angular/core';
2
+ import { DEFAULT_MODULAR_LABELS } from '../modular-table-template.models';
3
+ import * as i0 from "@angular/core";
4
+ import * as i1 from "@angular/common";
5
+ /**
6
+ * Folder-picker body used inside the Move-to-Folder dialog.
7
+ *
8
+ * This component is designed to be usable two ways:
9
+ *
10
+ * 1. **From inside the library** via `DialogService.open({ content: { type: 'component', component: MoveToFolderDialogComponent, inputs: {...} } })`.
11
+ * The outer `cqa-dialog` provides the title, description, Cancel and "Move here"
12
+ * buttons; the Move button reads `pickedFolderId` via `dialogRef.getComponentInstance()`.
13
+ *
14
+ * 2. **From the host/UI layer directly** once API ownership moves up. The host
15
+ * renders `<cqa-move-to-folder-dialog>` inside its own modal shell and
16
+ * listens to `(folderPicked)` (fires on every pick) to drive its own "Move here"
17
+ * button. All visual state lives on `pickedFolderId` so hosts can also two-way
18
+ * bind if they prefer.
19
+ */
20
+ export class MoveToFolderDialogComponent {
21
+ constructor(cdr) {
22
+ this.cdr = cdr;
23
+ /** Folder tree to pick from. */
24
+ this.folders = [];
25
+ /** Label overrides. */
26
+ this.labels = { ...DEFAULT_MODULAR_LABELS };
27
+ /** The folder the tests currently live in — rendered as disabled (can't move into itself). */
28
+ this.currentFolderId = null;
29
+ /** Controls which folder is visually selected. Two-way-bind friendly via `pickedFolderIdChange`. */
30
+ this.pickedFolderId = null;
31
+ /** Fires whenever the user picks a destination. */
32
+ this.folderPicked = new EventEmitter();
33
+ /** Companion output for banana-in-the-box `[(pickedFolderId)]` binding. */
34
+ this.pickedFolderIdChange = new EventEmitter();
35
+ this.expandedIds = new Set();
36
+ this.trackById = (_, row) => row.id ?? -1;
37
+ }
38
+ ngOnInit() {
39
+ this.seedExpandedIds();
40
+ }
41
+ ngOnChanges(changes) {
42
+ if (changes['initialExpandedIds'] || changes['currentFolderId'] || changes['folders']) {
43
+ this.seedExpandedIds();
44
+ }
45
+ }
46
+ seedExpandedIds() {
47
+ if (this.initialExpandedIds?.length) {
48
+ this.expandedIds = new Set(this.initialExpandedIds);
49
+ return;
50
+ }
51
+ this.expandedIds = new Set();
52
+ if (this.currentFolderId != null) {
53
+ const trail = [];
54
+ this.collectAncestors(this.folders, this.currentFolderId, trail);
55
+ trail.forEach(id => this.expandedIds.add(id));
56
+ }
57
+ }
58
+ collectAncestors(nodes, targetId, acc) {
59
+ for (const n of nodes || []) {
60
+ acc.push(n.id);
61
+ if (n.id === targetId)
62
+ return true;
63
+ if (n.children && this.collectAncestors(n.children, targetId, acc))
64
+ return true;
65
+ acc.pop();
66
+ }
67
+ return false;
68
+ }
69
+ get flatRows() {
70
+ const out = [];
71
+ const walk = (nodes, depth) => {
72
+ for (const n of nodes || []) {
73
+ const hasChildren = !!(n.children && n.children.length);
74
+ const expanded = this.expandedIds.has(n.id);
75
+ out.push({
76
+ id: n.id,
77
+ name: n.name,
78
+ depth,
79
+ disabled: n.id === this.currentFolderId,
80
+ hasChildren,
81
+ expanded,
82
+ });
83
+ if (hasChildren && expanded)
84
+ walk(n.children, depth + 1);
85
+ }
86
+ };
87
+ walk(this.folders, 0);
88
+ return out;
89
+ }
90
+ isPicked(id) {
91
+ return this.pickedFolderId === id;
92
+ }
93
+ pick(id) {
94
+ this.pickedFolderId = id;
95
+ this.folderPicked.emit(id);
96
+ this.pickedFolderIdChange.emit(id);
97
+ this.cdr.markForCheck();
98
+ }
99
+ toggleExpanded(id, event) {
100
+ event.stopPropagation();
101
+ if (this.expandedIds.has(id)) {
102
+ this.expandedIds.delete(id);
103
+ }
104
+ else {
105
+ this.expandedIds.add(id);
106
+ }
107
+ this.cdr.markForCheck();
108
+ }
109
+ }
110
+ MoveToFolderDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: MoveToFolderDialogComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
111
+ MoveToFolderDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: MoveToFolderDialogComponent, selector: "cqa-move-to-folder-dialog", inputs: { folders: "folders", labels: "labels", currentFolderId: "currentFolderId", pickedFolderId: "pickedFolderId", initialExpandedIds: "initialExpandedIds" }, outputs: { folderPicked: "folderPicked", pickedFolderIdChange: "pickedFolderIdChange" }, host: { classAttribute: "cqa-ui-root" }, usesOnChanges: true, ngImport: i0, template: `
112
+ <!-- Reusable outlined folder icon. Stroke uses currentColor so the row's text color drives the icon. -->
113
+ <ng-template #folderIconTpl>
114
+ <svg width="17" height="15" viewBox="0 0 17 15" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="cqa-shrink-0">
115
+ <path d="M15.6375 12.6377C15.6375 13.0355 15.4794 13.4171 15.1981 13.6984C14.9168 13.9797 14.5353 14.1377 14.1375 14.1377H2.13745C1.73963 14.1377 1.3581 13.9797 1.07679 13.6984C0.795486 13.4171 0.637451 13.0355 0.637451 12.6377V2.1377C0.637451 1.73987 0.795486 1.35834 1.07679 1.07704C1.3581 0.795731 1.73963 0.637695 2.13745 0.637695H5.88745L7.38745 2.8877H14.1375C14.5353 2.8877 14.9168 3.04573 15.1981 3.32704C15.4794 3.60834 15.6375 3.98987 15.6375 4.3877V12.6377Z" stroke="currentColor" stroke-width="1.275" stroke-linecap="round" stroke-linejoin="round"/>
116
+ </svg>
117
+ </ng-template>
118
+
119
+ <!-- Reusable outlined archive/inbox icon for the "Unorganised" entry. -->
120
+ <ng-template #unorganisedIconTpl>
121
+ <svg width="17" height="15" viewBox="0 0 17 15" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="cqa-shrink-0">
122
+ <path d="M14.6875 5.5V12.5C14.6875 13.3 14.0375 14 13.1875 14H3.8125C2.9625 14 2.3125 13.3 2.3125 12.5V5.5M14.6875 5.5L12.7875 1.7C12.5375 1.2 12.0875 1 11.5875 1H5.4125C4.9125 1 4.4625 1.2 4.2125 1.7L2.3125 5.5M14.6875 5.5H2.3125M6.1875 8.5H10.8125" stroke="currentColor" stroke-width="1.275" stroke-linecap="round" stroke-linejoin="round"/>
123
+ </svg>
124
+ </ng-template>
125
+
126
+ <div class="cqa-flex cqa-flex-col cqa-border-solid cqa-border cqa-border-[#E2E2E3] cqa-rounded-[10px] cqa-py-2 cqa-w-full cqa-h-[360px] cqa-overflow-y-auto cqa-bg-white cqa-scrollbar-thin">
127
+ <!-- Unorganised (root / no folder) -->
128
+ <div
129
+ role="button"
130
+ tabindex="0"
131
+ class="cqa-flex cqa-items-center cqa-gap-2.5 cqa-px-4 cqa-py-2 cqa-cursor-pointer cqa-transition-colors cqa-text-sm"
132
+ [ngClass]="isPicked(null) ? 'cqa-bg-indigo-50 cqa-text-indigo-700' : 'cqa-text-neutral-800 hover:cqa-bg-neutral-50'"
133
+ (click)="pick(null)"
134
+ (keydown.enter)="pick(null)"
135
+ (keydown.space)="$event.preventDefault(); pick(null)"
136
+ >
137
+ <!-- chevron-slot placeholder so all rows line up -->
138
+ <span class="cqa-inline-block cqa-w-5 cqa-h-5 cqa-shrink-0"></span>
139
+ <ng-container *ngTemplateOutlet="unorganisedIconTpl"></ng-container>
140
+ <span>{{ labels.moveDialogRoot }}</span>
141
+ </div>
142
+
143
+ <!-- Folder rows (flattened, depth-indented, collapsible) -->
144
+ <div
145
+ *ngFor="let row of flatRows; trackBy: trackById"
146
+ role="button"
147
+ tabindex="0"
148
+ class="cqa-flex cqa-items-center cqa-gap-2.5 cqa-py-2 cqa-pr-4 cqa-cursor-pointer cqa-transition-colors cqa-text-sm"
149
+ [ngClass]="isPicked(row.id) ? 'cqa-bg-indigo-50 cqa-text-indigo-700' : 'cqa-text-neutral-800 hover:cqa-bg-neutral-50'"
150
+ [class.cqa-opacity-40]="row.disabled"
151
+ [class.cqa-cursor-not-allowed]="row.disabled"
152
+ [style.paddingLeft.px]="16 + row.depth * 24"
153
+ (click)="!row.disabled && pick(row.id)"
154
+ (keydown.enter)="!row.disabled && pick(row.id)"
155
+ (keydown.space)="!row.disabled && $event.preventDefault(); !row.disabled && pick(row.id)"
156
+ >
157
+ <!-- Chevron toggle for expandable folders (placeholder otherwise so alignment stays) -->
158
+ <button
159
+ *ngIf="row.hasChildren; else chevronPlaceholder"
160
+ type="button"
161
+ class="cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-5 cqa-h-5 cqa-shrink-0 cqa-rounded cqa-text-neutral-600 hover:cqa-bg-neutral-100 hover:cqa-text-neutral-900"
162
+ [attr.aria-label]="row.expanded ? 'Collapse ' + row.name : 'Expand ' + row.name"
163
+ (click)="toggleExpanded(row.id!, $event)"
164
+ >
165
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"
166
+ [class.cqa-rotate-90]="row.expanded" style="transition: transform 120ms ease;">
167
+ <path d="M5 3L9 7L5 11" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
168
+ </svg>
169
+ </button>
170
+ <ng-template #chevronPlaceholder>
171
+ <span class="cqa-inline-block cqa-w-5 cqa-h-5 cqa-shrink-0"></span>
172
+ </ng-template>
173
+
174
+ <ng-container *ngTemplateOutlet="folderIconTpl"></ng-container>
175
+ <span class="cqa-truncate">{{ row.name }}</span>
176
+ </div>
177
+ </div>
178
+ `, isInline: true, directives: [{ type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
179
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: MoveToFolderDialogComponent, decorators: [{
180
+ type: Component,
181
+ args: [{ selector: 'cqa-move-to-folder-dialog', template: `
182
+ <!-- Reusable outlined folder icon. Stroke uses currentColor so the row's text color drives the icon. -->
183
+ <ng-template #folderIconTpl>
184
+ <svg width="17" height="15" viewBox="0 0 17 15" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="cqa-shrink-0">
185
+ <path d="M15.6375 12.6377C15.6375 13.0355 15.4794 13.4171 15.1981 13.6984C14.9168 13.9797 14.5353 14.1377 14.1375 14.1377H2.13745C1.73963 14.1377 1.3581 13.9797 1.07679 13.6984C0.795486 13.4171 0.637451 13.0355 0.637451 12.6377V2.1377C0.637451 1.73987 0.795486 1.35834 1.07679 1.07704C1.3581 0.795731 1.73963 0.637695 2.13745 0.637695H5.88745L7.38745 2.8877H14.1375C14.5353 2.8877 14.9168 3.04573 15.1981 3.32704C15.4794 3.60834 15.6375 3.98987 15.6375 4.3877V12.6377Z" stroke="currentColor" stroke-width="1.275" stroke-linecap="round" stroke-linejoin="round"/>
186
+ </svg>
187
+ </ng-template>
188
+
189
+ <!-- Reusable outlined archive/inbox icon for the "Unorganised" entry. -->
190
+ <ng-template #unorganisedIconTpl>
191
+ <svg width="17" height="15" viewBox="0 0 17 15" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="cqa-shrink-0">
192
+ <path d="M14.6875 5.5V12.5C14.6875 13.3 14.0375 14 13.1875 14H3.8125C2.9625 14 2.3125 13.3 2.3125 12.5V5.5M14.6875 5.5L12.7875 1.7C12.5375 1.2 12.0875 1 11.5875 1H5.4125C4.9125 1 4.4625 1.2 4.2125 1.7L2.3125 5.5M14.6875 5.5H2.3125M6.1875 8.5H10.8125" stroke="currentColor" stroke-width="1.275" stroke-linecap="round" stroke-linejoin="round"/>
193
+ </svg>
194
+ </ng-template>
195
+
196
+ <div class="cqa-flex cqa-flex-col cqa-border-solid cqa-border cqa-border-[#E2E2E3] cqa-rounded-[10px] cqa-py-2 cqa-w-full cqa-h-[360px] cqa-overflow-y-auto cqa-bg-white cqa-scrollbar-thin">
197
+ <!-- Unorganised (root / no folder) -->
198
+ <div
199
+ role="button"
200
+ tabindex="0"
201
+ class="cqa-flex cqa-items-center cqa-gap-2.5 cqa-px-4 cqa-py-2 cqa-cursor-pointer cqa-transition-colors cqa-text-sm"
202
+ [ngClass]="isPicked(null) ? 'cqa-bg-indigo-50 cqa-text-indigo-700' : 'cqa-text-neutral-800 hover:cqa-bg-neutral-50'"
203
+ (click)="pick(null)"
204
+ (keydown.enter)="pick(null)"
205
+ (keydown.space)="$event.preventDefault(); pick(null)"
206
+ >
207
+ <!-- chevron-slot placeholder so all rows line up -->
208
+ <span class="cqa-inline-block cqa-w-5 cqa-h-5 cqa-shrink-0"></span>
209
+ <ng-container *ngTemplateOutlet="unorganisedIconTpl"></ng-container>
210
+ <span>{{ labels.moveDialogRoot }}</span>
211
+ </div>
212
+
213
+ <!-- Folder rows (flattened, depth-indented, collapsible) -->
214
+ <div
215
+ *ngFor="let row of flatRows; trackBy: trackById"
216
+ role="button"
217
+ tabindex="0"
218
+ class="cqa-flex cqa-items-center cqa-gap-2.5 cqa-py-2 cqa-pr-4 cqa-cursor-pointer cqa-transition-colors cqa-text-sm"
219
+ [ngClass]="isPicked(row.id) ? 'cqa-bg-indigo-50 cqa-text-indigo-700' : 'cqa-text-neutral-800 hover:cqa-bg-neutral-50'"
220
+ [class.cqa-opacity-40]="row.disabled"
221
+ [class.cqa-cursor-not-allowed]="row.disabled"
222
+ [style.paddingLeft.px]="16 + row.depth * 24"
223
+ (click)="!row.disabled && pick(row.id)"
224
+ (keydown.enter)="!row.disabled && pick(row.id)"
225
+ (keydown.space)="!row.disabled && $event.preventDefault(); !row.disabled && pick(row.id)"
226
+ >
227
+ <!-- Chevron toggle for expandable folders (placeholder otherwise so alignment stays) -->
228
+ <button
229
+ *ngIf="row.hasChildren; else chevronPlaceholder"
230
+ type="button"
231
+ class="cqa-inline-flex cqa-items-center cqa-justify-center cqa-w-5 cqa-h-5 cqa-shrink-0 cqa-rounded cqa-text-neutral-600 hover:cqa-bg-neutral-100 hover:cqa-text-neutral-900"
232
+ [attr.aria-label]="row.expanded ? 'Collapse ' + row.name : 'Expand ' + row.name"
233
+ (click)="toggleExpanded(row.id!, $event)"
234
+ >
235
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"
236
+ [class.cqa-rotate-90]="row.expanded" style="transition: transform 120ms ease;">
237
+ <path d="M5 3L9 7L5 11" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
238
+ </svg>
239
+ </button>
240
+ <ng-template #chevronPlaceholder>
241
+ <span class="cqa-inline-block cqa-w-5 cqa-h-5 cqa-shrink-0"></span>
242
+ </ng-template>
243
+
244
+ <ng-container *ngTemplateOutlet="folderIconTpl"></ng-container>
245
+ <span class="cqa-truncate">{{ row.name }}</span>
246
+ </div>
247
+ </div>
248
+ `, host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [] }]
249
+ }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { folders: [{
250
+ type: Input
251
+ }], labels: [{
252
+ type: Input
253
+ }], currentFolderId: [{
254
+ type: Input
255
+ }], pickedFolderId: [{
256
+ type: Input
257
+ }], initialExpandedIds: [{
258
+ type: Input
259
+ }], folderPicked: [{
260
+ type: Output
261
+ }], pickedFolderIdChange: [{
262
+ type: Output
263
+ }] } });
264
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW92ZS10by1mb2xkZXItZGlhbG9nLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9saWIvdGVtcGxhdGVzL21vZHVsYXItdGFibGUtdGVtcGxhdGUvZGlhbG9ncy9tb3ZlLXRvLWZvbGRlci1kaWFsb2cuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCx1QkFBdUIsRUFFdkIsU0FBUyxFQUNULFlBQVksRUFDWixLQUFLLEVBR0wsTUFBTSxHQUVQLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxzQkFBc0IsRUFBNkIsTUFBTSxrQ0FBa0MsQ0FBQzs7O0FBV3JHOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBMkVILE1BQU0sT0FBTywyQkFBMkI7SUFtQnRDLFlBQW9CLEdBQXNCO1FBQXRCLFFBQUcsR0FBSCxHQUFHLENBQW1CO1FBbEIxQyxnQ0FBZ0M7UUFDdkIsWUFBTyxHQUFpQixFQUFFLENBQUM7UUFDcEMsdUJBQXVCO1FBQ2QsV0FBTSxHQUFrQixFQUFFLEdBQUcsc0JBQXNCLEVBQUUsQ0FBQztRQUMvRCw4RkFBOEY7UUFDckYsb0JBQWUsR0FBa0IsSUFBSSxDQUFDO1FBQy9DLG9HQUFvRztRQUMzRixtQkFBYyxHQUFrQixJQUFJLENBQUM7UUFJOUMsbURBQW1EO1FBQ3pDLGlCQUFZLEdBQUcsSUFBSSxZQUFZLEVBQWlCLENBQUM7UUFDM0QsMkVBQTJFO1FBQ2pFLHlCQUFvQixHQUFHLElBQUksWUFBWSxFQUFpQixDQUFDO1FBRTNELGdCQUFXLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztRQStFeEMsY0FBUyxHQUFHLENBQUMsQ0FBUyxFQUFFLEdBQWtCLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7SUE3RWYsQ0FBQztJQUU5QyxRQUFRO1FBQ04sSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO0lB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LCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBJbnB1dCxcbiAgT25DaGFuZ2VzLFxuICBPbkluaXQsXG4gIE91dHB1dCxcbiAgU2ltcGxlQ2hhbmdlcyxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBERUZBVUxUX01PRFVMQVJfTEFCRUxTLCBGb2xkZXJOb2RlLCBNb2R1bGFyTGFiZWxzIH0gZnJvbSAnLi4vbW9kdWxhci10YWJsZS10ZW1wbGF0ZS5tb2RlbHMnO1xuXG5pbnRlcmZhY2UgRmxhdEZvbGRlclJvdyB7XG4gIGlkOiBudW1iZXIgfCBudWxsO1xuICBuYW1lOiBzdHJpbmc7XG4gIGRlcHRoOiBudW1iZXI7XG4gIGRpc2FibGVkOiBib29sZWFuO1xuICBoYXNDaGlsZHJlbjogYm9vbGVhbjtcbiAgZXhwYW5kZWQ6IGJvb2xlYW47XG59XG5cbi8qKlxuICogRm9sZGVyLXBpY2tlciBib2R5IHVzZWQgaW5zaWRlIHRoZSBNb3ZlLXRvLUZvbGRlciBkaWFsb2cuXG4gKlxuICogVGhpcyBjb21wb25lbnQgaXMgZGVzaWduZWQgdG8gYmUgdXNhYmxlIHR3byB3YXlzOlxuICpcbiAqICAxLiAqKkZyb20gaW5zaWRlIHRoZSBsaWJyYXJ5KiogdmlhIGBEaWFsb2dTZXJ2aWNlLm9wZW4oeyBjb250ZW50OiB7IHR5cGU6ICdjb21wb25lbnQnLCBjb21wb25lbnQ6IE1vdmVUb0ZvbGRlckRpYWxvZ0NvbXBvbmVudCwgaW5wdXRzOiB7Li4ufSB9IH0pYC5cbiAqICAgICBUaGUgb3V0ZXIgYGNxYS1kaWFsb2dgIHByb3ZpZGVzIHRoZSB0aXRsZSwgZGVzY3JpcHRpb24sIENhbmNlbCBhbmQgXCJNb3ZlIGhlcmVcIlxuICogICAgIGJ1dHRvbnM7IHRoZSBNb3ZlIGJ1dHRvbiByZWFkcyBgcGlja2VkRm9sZGVySWRgIHZpYSBgZGlhbG9nUmVmLmdldENvbXBvbmVudEluc3RhbmNlKClgLlxuICpcbiAqICAyLiAqKkZyb20gdGhlIGhvc3QvVUkgbGF5ZXIgZGlyZWN0bHkqKiBvbmNlIEFQSSBvd25lcnNoaXAgbW92ZXMgdXAuIFRoZSBob3N0XG4gKiAgICAgcmVuZGVycyBgPGNxYS1tb3ZlLXRvLWZvbGRlci1kaWFsb2c+YCBpbnNpZGUgaXRzIG93biBtb2RhbCBzaGVsbCBhbmRcbiAqICAgICBsaXN0ZW5zIHRvIGAoZm9sZGVyUGlja2VkKWAgKGZpcmVzIG9uIGV2ZXJ5IHBpY2spIHRvIGRyaXZlIGl0cyBvd24gXCJNb3ZlIGhlcmVcIlxuICogICAgIGJ1dHRvbi4gQWxsIHZpc3VhbCBzdGF0ZSBsaXZlcyBvbiBgcGlja2VkRm9sZGVySWRgIHNvIGhvc3RzIGNhbiBhbHNvIHR3by13YXlcbiAqICAgICBiaW5kIGlmIHRoZXkgcHJlZmVyLlxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjcWEtbW92ZS10by1mb2xkZXItZGlhbG9nJyxcbiAgdGVtcGxhdGU6IGBcbiAgICA8IS0tIFJldXNhYmxlIG91dGxpbmVkIGZvbGRlciBpY29uLiBTdHJva2UgdXNlcyBjdXJyZW50Q29sb3Igc28gdGhlIHJvdydzIHRleHQgY29sb3IgZHJpdmVzIHRoZSBpY29uLiAtLT5cbiAgICA8bmctdGVtcGxhdGUgI2ZvbGRlckljb25UcGw+XG4gICAgICA8c3ZnIHdpZHRoPVwiMTdcIiBoZWlnaHQ9XCIxNVwiIHZpZXdCb3g9XCIwIDAgMTcgMTVcIiBmaWxsPVwibm9uZVwiIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiBhcmlhLWhpZGRlbj1cInRydWVcIiBjbGFzcz1cImNxYS1zaHJpbmstMFwiPlxuICAgICAgICA8cGF0aCBkPVwiTTE1LjYzNzUgMTIuNjM3N0MxNS42Mzc1IDEzLjAzNTUgMTUuNDc5NCAxMy40MTcxIDE1LjE5ODEgMTMuNjk4NEMxNC45MTY4IDEzLjk3OTcgMTQuNTM1MyAxNC4xMzc3IDE0LjEzNzUgMTQuMTM3N0gyLjEzNzQ1QzEuNzM5NjMgMTQuMTM3NyAxLjM1ODEgMTMuOTc5NyAxLjA3Njc5IDEzLjY5ODRDMC43OTU0ODYgMTMuNDE3MSAwLjYzNzQ1MSAxMy4wMzU1IDAuNjM3NDUxIDEyLjYzNzdWMi4xMzc3QzAuNjM3NDUxIDEuNzM5ODcgMC43OTU0ODYgMS4zNTgzNCAxLjA3Njc5IDEuMDc3MDRDMS4zNTgxIDAuNzk1NzMxIDEuNzM5NjMgMC42Mzc2OTUgMi4xMzc0NSAwLjYzNzY5NUg1Ljg4NzQ1TDcuMzg3NDUgMi44ODc3SDE0LjEzNzVDMTQuNTM1MyAyLjg4NzcgMTQuOTE2OCAzLjA0NTczIDE1LjE5ODEgMy4zMjcwNEMxNS40Nzk0IDMuNjA4MzQgMTUuNjM3NSAzLjk4OTg3IDE1LjYzNzUgNC4zODc3VjEyLjYzNzdaXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMS4yNzVcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIi8+XG4gICAgICA8L3N2Zz5cbiAgICA8L25nLXRlbXBsYXRlPlxuXG4gICAgPCEtLSBSZXVzYWJsZSBvdXRsaW5lZCBhcmNoaXZlL2luYm94IGljb24gZm9yIHRoZSBcIlVub3JnYW5pc2VkXCIgZW50cnkuIC0tPlxuICAgIDxuZy10ZW1wbGF0ZSAjdW5vcmdhbmlzZWRJY29uVHBsPlxuICAgICAgPHN2ZyB3aWR0aD1cIjE3XCIgaGVpZ2h0PVwiMTVcIiB2aWV3Qm94PVwiMCAwIDE3IDE1XCIgZmlsbD1cIm5vbmVcIiB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCIgY2xhc3M9XCJjcWEtc2hyaW5rLTBcIj5cbiAgICAgICAgPHBhdGggZD1cIk0xNC42ODc1IDUuNVYxMi41QzE0LjY4NzUgMTMuMyAxNC4wMzc1IDE0IDEzLjE4NzUgMTRIMy44MTI1QzIuOTYyNSAxNCAyLjMxMjUgMTMuMyAyLjMxMjUgMTIuNVY1LjVNMTQuNjg3NSA1LjVMMTIuNzg3NSAxLjdDMTIuNTM3NSAxLjIgMTIuMDg3NSAxIDExLjU4NzUgMUg1LjQxMjVDNC45MTI1IDEgNC40NjI1IDEuMiA0LjIxMjUgMS43TDIuMzEyNSA1LjVNMTQuNjg3NSA1LjVIMi4zMTI1TTYuMTg3NSA4LjVIMTAuODEyNVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjEuMjc1XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPlxuICAgICAgPC9zdmc+XG4gICAgPC9uZy10ZW1wbGF0ZT5cblxuICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtZmxleC1jb2wgY3FhLWJvcmRlci1zb2xpZCBjcWEtYm9yZGVyIGNxYS1ib3JkZXItWyNFMkUyRTNdIGNxYS1yb3VuZGVkLVsxMHB4XSBjcWEtcHktMiBjcWEtdy1mdWxsIGNxYS1oLVszNjBweF0gY3FhLW92ZXJmbG93LXktYXV0byBjcWEtYmctd2hpdGUgY3FhLXNjcm9sbGJhci10aGluXCI+XG4gICAgICA8IS0tIFVub3JnYW5pc2VkIChyb290IC8gbm8gZm9sZGVyKSAtLT5cbiAgICAgIDxkaXZcbiAgICAgICAgcm9sZT1cImJ1dHRvblwiXG4gICAgICAgIHRhYmluZGV4PVwiMFwiXG4gICAgICAgIGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtZ2FwLTIuNSBjcWEtcHgtNCBjcWEtcHktMiBjcWEtY3Vyc29yLXBvaW50ZXIgY3FhLXRyYW5zaXRpb24tY29sb3JzIGNxYS10ZXh0LXNtXCJcbiAgICAgICAgW25nQ2xhc3NdPVwiaXNQaWNrZWQobnVsbCkgPyAnY3FhLWJnLWluZGlnby01MCBjcWEtdGV4dC1pbmRpZ28tNzAwJyA6ICdjcWEtdGV4dC1uZXV0cmFsLTgwMCBob3ZlcjpjcWEtYmctbmV1dHJhbC01MCdcIlxuICAgICAgICAoY2xpY2spPVwicGljayhudWxsKVwiXG4gICAgICAgIChrZXlkb3duLmVudGVyKT1cInBpY2sobnVsbClcIlxuICAgICAgICAoa2V5ZG93bi5zcGFjZSk9XCIkZXZlbnQucHJldmVudERlZmF1bHQoKTsgcGljayhudWxsKVwiXG4gICAgICA+XG4gICAgICAgIDwhLS0gY2hldnJvbi1zbG90IHBsYWNlaG9sZGVyIHNvIGFsbCByb3dzIGxpbmUgdXAgLS0+XG4gICAgICAgIDxzcGFuIGNsYXNzPVwiY3FhLWlubGluZS1ibG9jayBjcWEtdy01IGNxYS1oLTUgY3FhLXNocmluay0wXCI+PC9zcGFuPlxuICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwidW5vcmdhbmlzZWRJY29uVHBsXCI+PC9uZy1jb250YWluZXI+XG4gICAgICAgIDxzcGFuPnt7IGxhYmVscy5tb3ZlRGlhbG9nUm9vdCB9fTwvc3Bhbj5cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8IS0tIEZvbGRlciByb3dzIChmbGF0dGVuZWQsIGRlcHRoLWluZGVudGVkLCBjb2xsYXBzaWJsZSkgLS0+XG4gICAgICA8ZGl2XG4gICAgICAgICpuZ0Zvcj1cImxldCByb3cgb2YgZmxhdFJvd3M7IHRyYWNrQnk6IHRyYWNrQnlJZFwiXG4gICAgICAgIHJvbGU9XCJidXR0b25cIlxuICAgICAgICB0YWJpbmRleD1cIjBcIlxuICAgICAgICBjbGFzcz1cImNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC0yLjUgY3FhLXB5LTIgY3FhLXByLTQgY3FhLWN1cnNvci1wb2ludGVyIGNxYS10cmFuc2l0aW9uLWNvbG9ycyBjcWEtdGV4dC1zbVwiXG4gICAgICAgIFtuZ0NsYXNzXT1cImlzUGlja2VkKHJvdy5pZCkgPyAnY3FhLWJnLWluZGlnby01MCBjcWEtdGV4dC1pbmRpZ28tNzAwJyA6ICdjcWEtdGV4dC1uZXV0cmFsLTgwMCBob3ZlcjpjcWEtYmctbmV1dHJhbC01MCdcIlxuICAgICAgICBbY2xhc3MuY3FhLW9wYWNpdHktNDBdPVwicm93LmRpc2FibGVkXCJcbiAgICAgICAgW2NsYXNzLmNxYS1jdXJzb3Itbm90LWFsbG93ZWRdPVwicm93LmRpc2FibGVkXCJcbiAgICAgICAgW3N0eWxlLnBhZGRpbmdMZWZ0LnB4XT1cIjE2ICsgcm93LmRlcHRoICogMjRcIlxuICAgICAgICAoY2xpY2spPVwiIXJvdy5kaXNhYmxlZCAmJiBwaWNrKHJvdy5pZClcIlxuICAgICAgICAoa2V5ZG93bi5lbnRlcik9XCIhcm93LmRpc2FibGVkICYmIHBpY2socm93LmlkKVwiXG4gICAgICAgIChrZXlkb3duLnNwYWNlKT1cIiFyb3cuZGlzYWJsZWQgJiYgJGV2ZW50LnByZXZlbnREZWZhdWx0KCk7ICFyb3cuZGlzYWJsZWQgJiYgcGljayhyb3cuaWQpXCJcbiAgICAgID5cbiAgICAgICAgPCEtLSBDaGV2cm9uIHRvZ2dsZSBmb3IgZXhwYW5kYWJsZSBmb2xkZXJzIChwbGFjZWhvbGRlciBvdGhlcndpc2Ugc28gYWxpZ25tZW50IHN0YXlzKSAtLT5cbiAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICpuZ0lmPVwicm93Lmhhc0NoaWxkcmVuOyBlbHNlIGNoZXZyb25QbGFjZWhvbGRlclwiXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgY2xhc3M9XCJjcWEtaW5saW5lLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXIgY3FhLXctNSBjcWEtaC01IGNxYS1zaHJpbmstMCBjcWEtcm91bmRlZCBjcWEtdGV4dC1uZXV0cmFsLTYwMCBob3ZlcjpjcWEtYmctbmV1dHJhbC0xMDAgaG92ZXI6Y3FhLXRleHQtbmV1dHJhbC05MDBcIlxuICAgICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwicm93LmV4cGFuZGVkID8gJ0NvbGxhcHNlICcgKyByb3cubmFtZSA6ICdFeHBhbmQgJyArIHJvdy5uYW1lXCJcbiAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlRXhwYW5kZWQocm93LmlkISwgJGV2ZW50KVwiXG4gICAgICAgID5cbiAgICAgICAgICA8c3ZnIHdpZHRoPVwiMTRcIiBoZWlnaHQ9XCIxNFwiIHZpZXdCb3g9XCIwIDAgMTQgMTRcIiBmaWxsPVwibm9uZVwiIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiBhcmlhLWhpZGRlbj1cInRydWVcIlxuICAgICAgICAgICAgICAgW2NsYXNzLmNxYS1yb3RhdGUtOTBdPVwicm93LmV4cGFuZGVkXCIgc3R5bGU9XCJ0cmFuc2l0aW9uOiB0cmFuc2Zvcm0gMTIwbXMgZWFzZTtcIj5cbiAgICAgICAgICAgIDxwYXRoIGQ9XCJNNSAzTDkgN0w1IDExXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMS44XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPlxuICAgICAgICAgIDwvc3ZnPlxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPG5nLXRlbXBsYXRlICNjaGV2cm9uUGxhY2Vob2xkZXI+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtaW5saW5lLWJsb2NrIGNxYS13LTUgY3FhLWgtNSBjcWEtc2hyaW5rLTBcIj48L3NwYW4+XG4gICAgICAgIDwvbmctdGVtcGxhdGU+XG5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImZvbGRlckljb25UcGxcIj48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtdHJ1bmNhdGVcIj57eyByb3cubmFtZSB9fTwvc3Bhbj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICBgLFxuICBzdHlsZVVybHM6IFtdLFxuICBob3N0OiB7IGNsYXNzOiAnY3FhLXVpLXJvb3QnIH0sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBNb3ZlVG9Gb2xkZXJEaWFsb2dDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uQ2hhbmdlcyB7XG4gIC8qKiBGb2xkZXIgdHJlZSB0byBwaWNrIGZyb20uICovXG4gIEBJbnB1dCgpIGZvbGRlcnM6IEZvbGRlck5vZGVbXSA9IFtdO1xuICAvKiogTGFiZWwgb3ZlcnJpZGVzLiAqL1xuICBASW5wdXQoKSBsYWJlbHM6IE1vZHVsYXJMYWJlbHMgPSB7IC4uLkRFRkFVTFRfTU9EVUxBUl9MQUJFTFMgfTtcbiAgLyoqIFRoZSBmb2xkZXIgdGhlIHRlc3RzIGN1cnJlbnRseSBsaXZlIGluIOKAlCByZW5kZXJlZCBhcyBkaXNhYmxlZCAoY2FuJ3QgbW92ZSBpbnRvIGl0c2VsZikuICovXG4gIEBJbnB1dCgpIGN1cnJlbnRGb2xkZXJJZDogbnVtYmVyIHwgbnVsbCA9IG51bGw7XG4gIC8qKiBDb250cm9scyB3aGljaCBmb2xkZXIgaXMgdmlzdWFsbHkgc2VsZWN0ZWQuIFR3by13YXktYmluZCBmcmllbmRseSB2aWEgYHBpY2tlZEZvbGRlcklkQ2hhbmdlYC4gKi9cbiAgQElucHV0KCkgcGlja2VkRm9sZGVySWQ6IG51bWJlciB8IG51bGwgPSBudWxsO1xuICAvKiogRm9sZGVyIGlkcyB0byBleHBhbmQgYnkgZGVmYXVsdC4gSWYgbm90IHByb3ZpZGVkLCBhbmNlc3RvcnMgb2YgYGN1cnJlbnRGb2xkZXJJZGAgYXJlIGV4cGFuZGVkLiAqL1xuICBASW5wdXQoKSBpbml0aWFsRXhwYW5kZWRJZHM/OiBudW1iZXJbXTtcblxuICAvKiogRmlyZXMgd2hlbmV2ZXIgdGhlIHVzZXIgcGlja3MgYSBkZXN0aW5hdGlvbi4gKi9cbiAgQE91dHB1dCgpIGZvbGRlclBpY2tlZCA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyIHwgbnVsbD4oKTtcbiAgLyoqIENvbXBhbmlvbiBvdXRwdXQgZm9yIGJhbmFuYS1pbi10aGUtYm94IGBbKHBpY2tlZEZvbGRlcklkKV1gIGJpbmRpbmcuICovXG4gIEBPdXRwdXQoKSBwaWNrZWRGb2xkZXJJZENoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyIHwgbnVsbD4oKTtcblxuICBwcml2YXRlIGV4cGFuZGVkSWRzID0gbmV3IFNldDxudW1iZXI+KCk7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBjZHI6IENoYW5nZURldGVjdG9yUmVmKSB7fVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuc2VlZEV4cGFuZGVkSWRzKCk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgaWYgKGNoYW5nZXNbJ2luaXRpYWxFeHBhbmRlZElkcyddIHx8IGNoYW5nZXNbJ2N1cnJlbnRGb2xkZXJJZCddIHx8IGNoYW5nZXNbJ2ZvbGRlcnMnXSkge1xuICAgICAgdGhpcy5zZWVkRXhwYW5kZWRJZHMoKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHNlZWRFeHBhbmRlZElkcygpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5pbml0aWFsRXhwYW5kZWRJZHM/Lmxlbmd0aCkge1xuICAgICAgdGhpcy5leHBhbmRlZElkcyA9IG5ldyBTZXQodGhpcy5pbml0aWFsRXhwYW5kZWRJZHMpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmV4cGFuZGVkSWRzID0gbmV3IFNldCgpO1xuICAgIGlmICh0aGlzLmN1cnJlbnRGb2xkZXJJZCAhPSBudWxsKSB7XG4gICAgICBjb25zdCB0cmFpbDogbnVtYmVyW10gPSBbXTtcbiAgICAgIHRoaXMuY29sbGVjdEFuY2VzdG9ycyh0aGlzLmZvbGRlcnMsIHRoaXMuY3VycmVudEZvbGRlcklkLCB0cmFpbCk7XG4gICAgICB0cmFpbC5mb3JFYWNoKGlkID0+IHRoaXMuZXhwYW5kZWRJZHMuYWRkKGlkKSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjb2xsZWN0QW5jZXN0b3JzKG5vZGVzOiBGb2xkZXJOb2RlW10sIHRhcmdldElkOiBudW1iZXIsIGFjYzogbnVtYmVyW10pOiBib29sZWFuIHtcbiAgICBmb3IgKGNvbnN0IG4gb2Ygbm9kZXMgfHwgW10pIHtcbiAgICAgIGFjYy5wdXNoKG4uaWQpO1xuICAgICAgaWYgKG4uaWQgPT09IHRhcmdldElkKSByZXR1cm4gdHJ1ZTtcbiAgICAgIGlmIChuLmNoaWxkcmVuICYmIHRoaXMuY29sbGVjdEFuY2VzdG9ycyhuLmNoaWxkcmVuLCB0YXJnZXRJZCwgYWNjKSkgcmV0dXJuIHRydWU7XG4gICAgICBhY2MucG9wKCk7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGdldCBmbGF0Um93cygpOiBGbGF0Rm9sZGVyUm93W10ge1xuICAgIGNvbnN0IG91dDogRmxhdEZvbGRlclJvd1tdID0gW107XG4gICAgY29uc3Qgd2FsayA9IChub2RlczogRm9sZGVyTm9kZVtdLCBkZXB0aDogbnVtYmVyKSA9PiB7XG4gICAgICBmb3IgKGNvbnN0IG4gb2Ygbm9kZXMgfHwgW10pIHtcbiAgICAgICAgY29uc3QgaGFzQ2hpbGRyZW4gPSAhIShuLmNoaWxkcmVuICYmIG4uY2hpbGRyZW4ubGVuZ3RoKTtcbiAgICAgICAgY29uc3QgZXhwYW5kZWQgPSB0aGlzLmV4cGFuZGVkSWRzLmhhcyhuLmlkKTtcbiAgICAgICAgb3V0LnB1c2goe1xuICAgICAgICAgIGlkOiBuLmlkLFxuICAgICAgICAgIG5hbWU6IG4ubmFtZSxcbiAgICAgICAgICBkZXB0aCxcbiAgICAgICAgICBkaXNhYmxlZDogbi5pZCA9PT0gdGhpcy5jdXJyZW50Rm9sZGVySWQsXG4gICAgICAgICAgaGFzQ2hpbGRyZW4sXG4gICAgICAgICAgZXhwYW5kZWQsXG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoaGFzQ2hpbGRyZW4gJiYgZXhwYW5kZWQpIHdhbGsobi5jaGlsZHJlbiEsIGRlcHRoICsgMSk7XG4gICAgICB9XG4gICAgfTtcbiAgICB3YWxrKHRoaXMuZm9sZGVycywgMCk7XG4gICAgcmV0dXJuIG91dDtcbiAgfVxuXG4gIGlzUGlja2VkKGlkOiBudW1iZXIgfCBudWxsKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMucGlja2VkRm9sZGVySWQgPT09IGlkO1xuICB9XG5cbiAgcGljayhpZDogbnVtYmVyIHwgbnVsbCk6IHZvaWQge1xuICAgIHRoaXMucGlja2VkRm9sZGVySWQgPSBpZDtcbiAgICB0aGlzLmZvbGRlclBpY2tlZC5lbWl0KGlkKTtcbiAgICB0aGlzLnBpY2tlZEZvbGRlcklkQ2hhbmdlLmVtaXQoaWQpO1xuICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgdG9nZ2xlRXhwYW5kZWQoaWQ6IG51bWJlciwgZXZlbnQ6IEV2ZW50KTogdm9pZCB7XG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgaWYgKHRoaXMuZXhwYW5kZWRJZHMuaGFzKGlkKSkge1xuICAgICAgdGhpcy5leHBhbmRlZElkcy5kZWxldGUoaWQpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmV4cGFuZGVkSWRzLmFkZChpZCk7XG4gICAgfVxuICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgdHJhY2tCeUlkID0gKF86IG51bWJlciwgcm93OiBGbGF0Rm9sZGVyUm93KSA9PiByb3cuaWQgPz8gLTE7XG59XG4iXX0=