@memberjunction/ng-conversations 5.33.0 → 5.34.0

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 (23) hide show
  1. package/dist/lib/components/collection/artifact-collection-picker-modal.component.d.ts +75 -30
  2. package/dist/lib/components/collection/artifact-collection-picker-modal.component.d.ts.map +1 -1
  3. package/dist/lib/components/collection/artifact-collection-picker-modal.component.js +1026 -478
  4. package/dist/lib/components/collection/artifact-collection-picker-modal.component.js.map +1 -1
  5. package/dist/lib/components/collection/collection-form-modal.component.d.ts.map +1 -1
  6. package/dist/lib/components/collection/collection-form-modal.component.js +5 -5
  7. package/dist/lib/components/collection/collection-form-modal.component.js.map +1 -1
  8. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +8 -1
  9. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  10. package/dist/lib/components/conversation/conversation-chat-area.component.js +30 -16
  11. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  12. package/dist/lib/components/conversation/conversation-list.component.d.ts.map +1 -1
  13. package/dist/lib/components/conversation/conversation-list.component.js +3 -3
  14. package/dist/lib/components/conversation/conversation-list.component.js.map +1 -1
  15. package/dist/lib/components/message/message-item.component.d.ts +12 -1
  16. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  17. package/dist/lib/components/message/message-item.component.js +34 -15
  18. package/dist/lib/components/message/message-item.component.js.map +1 -1
  19. package/dist/lib/components/search/search-panel.component.d.ts +1 -7
  20. package/dist/lib/components/search/search-panel.component.d.ts.map +1 -1
  21. package/dist/lib/components/search/search-panel.component.js +4 -14
  22. package/dist/lib/components/search/search-panel.component.js.map +1 -1
  23. package/package.json +22 -22
@@ -1,268 +1,475 @@
1
- import { Component, Input, Output, EventEmitter } from '@angular/core';
1
+ import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
2
2
  import { BaseAngularComponent } from '@memberjunction/ng-base-types';
3
3
  import { FormsModule } from '@angular/forms';
4
- import { RunView } from '@memberjunction/core';
4
+ import { RunView, LogError } from '@memberjunction/core';
5
5
  import { MJDialogComponent, MJDialogActionsComponent, MJButtonDirective } from '@memberjunction/ng-ui-components';
6
6
  import { SharedGenericModule } from '@memberjunction/ng-shared-generic';
7
- import { UUIDsEqual } from '@memberjunction/global';
7
+ import { UUIDsEqual, NormalizeUUID } from '@memberjunction/global';
8
8
  import * as i0 from "@angular/core";
9
9
  import * as i1 from "../../services/toast.service";
10
10
  import * as i2 from "../../services/collection-permission.service";
11
11
  import * as i3 from "@angular/forms";
12
12
  import * as i4 from "@memberjunction/ng-shared-generic";
13
+ const _c0 = ["searchInput"];
14
+ const _c1 = ["newNameInput"];
13
15
  const _forTrack0 = ($index, $item) => $item.collection.ID;
14
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_2_For_5_Template(rf, ctx) { if (rf & 1) {
15
- const _r4 = i0.ɵɵgetCurrentView();
16
- i0.ɵɵelement(0, "i", 20);
17
- i0.ɵɵelementStart(1, "button", 18);
18
- i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_2_For_5_Template_button_click_1_listener() { const item_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.navigateToCollection(item_r5.collection)); });
19
- i0.ɵɵtext(2);
20
- i0.ɵɵelementEnd();
21
- } if (rf & 2) {
22
- const item_r5 = ctx.$implicit;
23
- i0.ɵɵadvance(2);
24
- i0.ɵɵtextInterpolate1(" ", item_r5.collection.Name, " ");
25
- } }
26
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_2_Template(rf, ctx) { if (rf & 1) {
16
+ const _forTrack1 = ($index, $item) => $item.collectionId;
17
+ const _forTrack2 = ($index, $item) => $item.ID;
18
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_8_Template(rf, ctx) { if (rf & 1) {
27
19
  const _r3 = i0.ɵɵgetCurrentView();
28
- i0.ɵɵelementStart(0, "div", 4)(1, "button", 18);
29
- i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_2_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.navigateToRoot()); });
30
- i0.ɵɵelement(2, "i", 19);
31
- i0.ɵɵtext(3, " Root ");
20
+ i0.ɵɵelementStart(0, "button", 34);
21
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_8_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.clearSearch()); });
22
+ i0.ɵɵelement(1, "i", 35);
32
23
  i0.ɵɵelementEnd();
33
- i0.ɵɵrepeaterCreate(4, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_2_For_5_Template, 3, 1, null, null, _forTrack0);
24
+ } }
25
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_16_Template(rf, ctx) { if (rf & 1) {
26
+ i0.ɵɵelementStart(0, "div", 15);
27
+ i0.ɵɵelement(1, "mj-loading", 36);
34
28
  i0.ɵɵelementEnd();
29
+ } }
30
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_17_Template(rf, ctx) { if (rf & 1) {
31
+ i0.ɵɵelementStart(0, "div", 16);
32
+ i0.ɵɵelement(1, "i", 37);
33
+ i0.ɵɵelementStart(2, "span");
34
+ i0.ɵɵtext(3);
35
+ i0.ɵɵelementEnd()();
35
36
  } if (rf & 2) {
36
37
  const ctx_r1 = i0.ɵɵnextContext(2);
37
- i0.ɵɵadvance(4);
38
- i0.ɵɵrepeater(ctx_r1.navigationPath);
38
+ i0.ɵɵadvance(3);
39
+ i0.ɵɵtextInterpolate(ctx_r1.errorMessage);
39
40
  } }
40
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
41
- i0.ɵɵelement(0, "i", 22);
41
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_18_Conditional_1_Template(rf, ctx) { if (rf & 1) {
42
+ const _r4 = i0.ɵɵgetCurrentView();
43
+ i0.ɵɵelement(0, "i", 8);
42
44
  i0.ɵɵelementStart(1, "p");
43
45
  i0.ɵɵtext(2);
44
46
  i0.ɵɵelementEnd();
47
+ i0.ɵɵelementStart(3, "button", 38);
48
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_18_Conditional_1_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.clearSearch()); });
49
+ i0.ɵɵtext(4, "Clear search");
50
+ i0.ɵɵelementEnd();
45
51
  } if (rf & 2) {
46
- const ctx_r1 = i0.ɵɵnextContext(4);
52
+ const ctx_r1 = i0.ɵɵnextContext(3);
47
53
  i0.ɵɵadvance(2);
48
- i0.ɵɵtextInterpolate1("No collections found matching \"", ctx_r1.searchQuery, "\"");
54
+ i0.ɵɵtextInterpolate1("No collections match \u201C", ctx_r1.searchQuery, "\u201D");
49
55
  } }
50
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_1_Conditional_2_Template(rf, ctx) { if (rf & 1) {
51
- i0.ɵɵelement(0, "i", 23);
56
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_18_Conditional_2_Template(rf, ctx) { if (rf & 1) {
57
+ i0.ɵɵelement(0, "i", 39);
52
58
  i0.ɵɵelementStart(1, "p");
53
- i0.ɵɵtext(2, "No sub-collections available");
59
+ i0.ɵɵtext(2, "No editable collections yet");
54
60
  i0.ɵɵelementEnd();
55
- } }
56
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
57
- i0.ɵɵelement(0, "i", 24);
58
- i0.ɵɵelementStart(1, "p");
59
- i0.ɵɵtext(2, "No collections available");
60
- i0.ɵɵelementEnd();
61
- i0.ɵɵelementStart(3, "p", 25);
62
- i0.ɵɵtext(4, "Create a new collection to get started");
61
+ i0.ɵɵelementStart(3, "p", 40);
62
+ i0.ɵɵtext(4, "Create one to get started");
63
63
  i0.ɵɵelementEnd();
64
64
  } }
65
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_1_Template(rf, ctx) { if (rf & 1) {
66
- i0.ɵɵelementStart(0, "div", 21);
67
- i0.ɵɵconditionalCreate(1, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_1_Conditional_1_Template, 3, 1)(2, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_1_Conditional_2_Template, 3, 0)(3, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_1_Conditional_3_Template, 5, 0);
65
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_18_Template(rf, ctx) { if (rf & 1) {
66
+ i0.ɵɵelementStart(0, "div", 17);
67
+ i0.ɵɵconditionalCreate(1, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_18_Conditional_1_Template, 5, 1)(2, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_18_Conditional_2_Template, 5, 0);
68
68
  i0.ɵɵelementEnd();
69
69
  } if (rf & 2) {
70
- const ctx_r1 = i0.ɵɵnextContext(3);
70
+ const ctx_r1 = i0.ɵɵnextContext(2);
71
71
  i0.ɵɵadvance();
72
- i0.ɵɵconditional(ctx_r1.searchQuery ? 1 : ctx_r1.currentParentId ? 2 : 3);
72
+ i0.ɵɵconditional(ctx_r1.searchQuery ? 1 : 2);
73
+ } }
74
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_For_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
75
+ i0.ɵɵelement(0, "i", 53);
76
+ } if (rf & 2) {
77
+ const node_r6 = i0.ɵɵnextContext().$implicit;
78
+ i0.ɵɵclassProp("fa-chevron-down", node_r6.expanded)("fa-chevron-right", !node_r6.expanded);
73
79
  } }
74
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_2_For_1_Conditional_6_Template(rf, ctx) { if (rf & 1) {
75
- i0.ɵɵelementStart(0, "span", 32);
76
- i0.ɵɵelement(1, "i", 34);
77
- i0.ɵɵtext(2, " Already added ");
80
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_For_2_Conditional_4_Template(rf, ctx) { if (rf & 1) {
81
+ i0.ɵɵelement(0, "i", 48);
82
+ } }
83
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_For_2_Conditional_8_Template(rf, ctx) { if (rf & 1) {
84
+ i0.ɵɵelementStart(0, "span", 51);
85
+ i0.ɵɵtext(1);
78
86
  i0.ɵɵelementEnd();
87
+ } if (rf & 2) {
88
+ const node_r6 = i0.ɵɵnextContext().$implicit;
89
+ i0.ɵɵadvance();
90
+ i0.ɵɵtextInterpolate1("\u00B7 ", node_r6.ancestry);
79
91
  } }
80
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_2_For_1_Conditional_7_Template(rf, ctx) { if (rf & 1) {
81
- const _r8 = i0.ɵɵgetCurrentView();
82
- i0.ɵɵelementStart(0, "button", 35);
83
- i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_2_For_1_Conditional_7_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r8); const node_r7 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(4); $event.stopPropagation(); return i0.ɵɵresetView(ctx_r1.drillIntoCollection(node_r7.collection)); });
84
- i0.ɵɵelement(1, "i", 36);
92
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_For_2_Conditional_9_Template(rf, ctx) { if (rf & 1) {
93
+ i0.ɵɵelementStart(0, "span", 52);
94
+ i0.ɵɵtext(1, "Already saved");
85
95
  i0.ɵɵelementEnd();
86
96
  } }
87
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_2_For_1_Template(rf, ctx) { if (rf & 1) {
88
- const _r6 = i0.ɵɵgetCurrentView();
89
- i0.ɵɵelementStart(0, "div", 27);
90
- i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_2_For_1_Template_div_click_0_listener() { const node_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.toggleSelection(node_r7)); });
91
- i0.ɵɵelementStart(1, "div", 28)(2, "input", 29);
92
- i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_2_For_1_Template_input_click_2_listener($event) { const node_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); $event.stopPropagation(); return i0.ɵɵresetView(ctx_r1.toggleSelection(node_r7)); });
93
- i0.ɵɵelementEnd()();
94
- i0.ɵɵelement(3, "i", 30);
95
- i0.ɵɵelementStart(4, "span", 31);
96
- i0.ɵɵtext(5);
97
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_For_2_Template(rf, ctx) { if (rf & 1) {
98
+ const _r5 = i0.ɵɵgetCurrentView();
99
+ i0.ɵɵelementStart(0, "div", 44);
100
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_For_2_Template_div_click_0_listener() { const node_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onRowClick(node_r6)); });
101
+ i0.ɵɵelementStart(1, "span", 45);
102
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_For_2_Template_span_click_1_listener($event) { const node_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); $event.stopPropagation(); return i0.ɵɵresetView(ctx_r1.toggleExpand(node_r6)); });
103
+ i0.ɵɵconditionalCreate(2, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_For_2_Conditional_2_Template, 1, 4, "i", 46);
104
+ i0.ɵɵelementEnd();
105
+ i0.ɵɵelementStart(3, "span", 47);
106
+ i0.ɵɵconditionalCreate(4, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_For_2_Conditional_4_Template, 1, 0, "i", 48);
107
+ i0.ɵɵelementEnd();
108
+ i0.ɵɵelement(5, "i", 49);
109
+ i0.ɵɵelementStart(6, "span", 50);
110
+ i0.ɵɵtext(7);
111
+ i0.ɵɵconditionalCreate(8, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_For_2_Conditional_8_Template, 2, 1, "span", 51);
97
112
  i0.ɵɵelementEnd();
98
- i0.ɵɵconditionalCreate(6, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_2_For_1_Conditional_6_Template, 3, 0, "span", 32);
99
- i0.ɵɵconditionalCreate(7, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_2_For_1_Conditional_7_Template, 2, 0, "button", 33);
113
+ i0.ɵɵconditionalCreate(9, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_For_2_Conditional_9_Template, 2, 0, "span", 52);
100
114
  i0.ɵɵelementEnd();
101
115
  } if (rf & 2) {
102
- const node_r7 = ctx.$implicit;
103
- i0.ɵɵclassProp("already-added", node_r7.alreadyContainsArtifact);
116
+ const node_r6 = ctx.$implicit;
117
+ const ctx_r1 = i0.ɵɵnextContext(3);
118
+ i0.ɵɵstyleProp("padding-left", ctx_r1.searchQuery ? 12 : 12 + node_r6.depth * 18, "px");
119
+ i0.ɵɵclassProp("selected", ctx_r1.isSelected(node_r6.collection.ID))("already", node_r6.alreadyContainsArtifact);
104
120
  i0.ɵɵadvance(2);
105
- i0.ɵɵproperty("checked", node_r7.selected)("disabled", node_r7.alreadyContainsArtifact);
121
+ i0.ɵɵconditional(node_r6.hasChildren && !ctx_r1.searchQuery ? 2 : -1);
122
+ i0.ɵɵadvance();
123
+ i0.ɵɵclassProp("checked", ctx_r1.isSelected(node_r6.collection.ID))("locked", node_r6.alreadyContainsArtifact);
124
+ i0.ɵɵattribute("aria-label", node_r6.alreadyContainsArtifact ? "Already saved" : "Toggle selection");
106
125
  i0.ɵɵadvance();
107
- i0.ɵɵstyleProp("color", node_r7.collection.Color || "var(--mj-brand-primary)");
126
+ i0.ɵɵconditional(ctx_r1.isSelected(node_r6.collection.ID) || node_r6.alreadyContainsArtifact ? 4 : -1);
127
+ i0.ɵɵadvance();
128
+ i0.ɵɵstyleProp("color", node_r6.collection.Color || "var(--mj-brand-primary)");
108
129
  i0.ɵɵadvance(2);
109
- i0.ɵɵtextInterpolate(node_r7.collection.Name);
130
+ i0.ɵɵtextInterpolate1(" ", node_r6.collection.Name, " ");
110
131
  i0.ɵɵadvance();
111
- i0.ɵɵconditional(node_r7.alreadyContainsArtifact ? 6 : -1);
132
+ i0.ɵɵconditional(ctx_r1.searchQuery && node_r6.ancestry ? 8 : -1);
112
133
  i0.ɵɵadvance();
113
- i0.ɵɵconditional(node_r7.hasChildren ? 7 : -1);
134
+ i0.ɵɵconditional(node_r6.alreadyContainsArtifact ? 9 : -1);
135
+ } }
136
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Conditional_3_Template(rf, ctx) { if (rf & 1) {
137
+ const _r7 = i0.ɵɵgetCurrentView();
138
+ i0.ɵɵelementStart(0, "button", 54);
139
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Conditional_3_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.openCreateForm()); });
140
+ i0.ɵɵelement(1, "span", 55);
141
+ i0.ɵɵelementStart(2, "span", 56);
142
+ i0.ɵɵelement(3, "i", 57);
143
+ i0.ɵɵelementEnd();
144
+ i0.ɵɵelementStart(4, "span", 50);
145
+ i0.ɵɵtext(5, "Create new collection\u2026");
146
+ i0.ɵɵelementEnd()();
114
147
  } }
115
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_2_Template(rf, ctx) { if (rf & 1) {
116
- i0.ɵɵrepeaterCreate(0, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_2_For_1_Template, 8, 9, "div", 26, _forTrack0);
148
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Conditional_4_Conditional_7_Template(rf, ctx) { if (rf & 1) {
149
+ i0.ɵɵelement(0, "i", 60);
150
+ } }
151
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Conditional_4_Conditional_8_Template(rf, ctx) { if (rf & 1) {
152
+ i0.ɵɵtext(0, " Create ");
153
+ } }
154
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Conditional_4_Template(rf, ctx) { if (rf & 1) {
155
+ const _r8 = i0.ɵɵgetCurrentView();
156
+ i0.ɵɵelementStart(0, "div", 43);
157
+ i0.ɵɵelement(1, "span", 55);
158
+ i0.ɵɵelementStart(2, "span", 56);
159
+ i0.ɵɵelement(3, "i", 57);
160
+ i0.ɵɵelementEnd();
161
+ i0.ɵɵelementStart(4, "input", 58, 1);
162
+ i0.ɵɵtwoWayListener("ngModelChange", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Conditional_4_Template_input_ngModelChange_4_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.newCollectionName, $event) || (ctx_r1.newCollectionName = $event); return i0.ɵɵresetView($event); });
163
+ i0.ɵɵlistener("keydown.enter", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Conditional_4_Template_input_keydown_enter_4_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.createCollection()); })("keydown.escape", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Conditional_4_Template_input_keydown_escape_4_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.cancelCreate()); });
164
+ i0.ɵɵelementEnd();
165
+ i0.ɵɵelementStart(6, "button", 59);
166
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Conditional_4_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.createCollection()); });
167
+ i0.ɵɵconditionalCreate(7, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Conditional_4_Conditional_7_Template, 1, 0, "i", 60)(8, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Conditional_4_Conditional_8_Template, 1, 0);
168
+ i0.ɵɵelementEnd();
169
+ i0.ɵɵelementStart(9, "button", 61);
170
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Conditional_4_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.cancelCreate()); });
171
+ i0.ɵɵtext(10, " Cancel ");
172
+ i0.ɵɵelementEnd()();
117
173
  } if (rf & 2) {
118
174
  const ctx_r1 = i0.ɵɵnextContext(3);
119
- i0.ɵɵrepeater(ctx_r1.displayedCollections);
175
+ i0.ɵɵadvance(4);
176
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.newCollectionName);
177
+ i0.ɵɵproperty("disabled", ctx_r1.isCreatingCollection);
178
+ i0.ɵɵadvance(2);
179
+ i0.ɵɵproperty("disabled", ctx_r1.isCreatingCollection || !ctx_r1.newCollectionName.trim());
180
+ i0.ɵɵadvance();
181
+ i0.ɵɵconditional(ctx_r1.isCreatingCollection ? 7 : 8);
182
+ i0.ɵɵadvance(2);
183
+ i0.ɵɵproperty("disabled", ctx_r1.isCreatingCollection);
120
184
  } }
121
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Template(rf, ctx) { if (rf & 1) {
122
- i0.ɵɵelementStart(0, "div", 8);
123
- i0.ɵɵconditionalCreate(1, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_1_Template, 4, 1, "div", 21)(2, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Conditional_2_Template, 2, 0);
185
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Template(rf, ctx) { if (rf & 1) {
186
+ i0.ɵɵelementStart(0, "div", 18);
187
+ i0.ɵɵrepeaterCreate(1, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_For_2_Template, 10, 18, "div", 41, _forTrack0);
188
+ i0.ɵɵconditionalCreate(3, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Conditional_3_Template, 6, 0, "button", 42)(4, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Conditional_4_Template, 11, 5, "div", 43);
124
189
  i0.ɵɵelementEnd();
125
190
  } if (rf & 2) {
126
191
  const ctx_r1 = i0.ɵɵnextContext(2);
127
192
  i0.ɵɵadvance();
128
- i0.ɵɵconditional(ctx_r1.displayedCollections.length === 0 ? 1 : 2);
193
+ i0.ɵɵrepeater(ctx_r1.visibleNodes);
194
+ i0.ɵɵadvance(2);
195
+ i0.ɵɵconditional(!ctx_r1.isSaving && !ctx_r1.searchQuery && !ctx_r1.showCreateForm ? 3 : ctx_r1.showCreateForm ? 4 : -1);
129
196
  } }
130
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_7_Template(rf, ctx) { if (rf & 1) {
131
- i0.ɵɵelementStart(0, "div", 9);
132
- i0.ɵɵelement(1, "mj-loading", 37);
197
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_30_Template(rf, ctx) { if (rf & 1) {
198
+ i0.ɵɵelementStart(0, "span", 27);
199
+ i0.ɵɵtext(1);
133
200
  i0.ɵɵelementEnd();
201
+ } if (rf & 2) {
202
+ const ctx_r1 = i0.ɵɵnextContext(2);
203
+ i0.ɵɵadvance();
204
+ i0.ɵɵtextInterpolate1("v", ctx_r1.artifactVersionNumber);
134
205
  } }
135
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_8_Template(rf, ctx) { if (rf & 1) {
136
- i0.ɵɵelementStart(0, "div", 10);
137
- i0.ɵɵelement(1, "i", 38);
138
- i0.ɵɵelementStart(2, "span");
206
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_33_Template(rf, ctx) { if (rf & 1) {
207
+ i0.ɵɵelementStart(0, "span");
208
+ i0.ɵɵtext(1, "Results");
209
+ i0.ɵɵelementEnd();
210
+ i0.ɵɵelementStart(2, "span", 62);
139
211
  i0.ɵɵtext(3);
140
- i0.ɵɵelementEnd()();
212
+ i0.ɵɵelementEnd();
141
213
  } if (rf & 2) {
142
214
  const ctx_r1 = i0.ɵɵnextContext(2);
143
215
  i0.ɵɵadvance(3);
144
- i0.ɵɵtextInterpolate(ctx_r1.errorMessage);
216
+ i0.ɵɵtextInterpolate2("", ctx_r1.successCount, " / ", ctx_r1.saveResults.size);
145
217
  } }
146
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_9_Template(rf, ctx) { if (rf & 1) {
147
- i0.ɵɵelementStart(0, "div", 11);
148
- i0.ɵɵelement(1, "i", 34);
149
- i0.ɵɵelementStart(2, "span");
218
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_34_Template(rf, ctx) { if (rf & 1) {
219
+ i0.ɵɵelementStart(0, "span");
220
+ i0.ɵɵtext(1, "Selected");
221
+ i0.ɵɵelementEnd();
222
+ i0.ɵɵelementStart(2, "span", 62);
150
223
  i0.ɵɵtext(3);
151
- i0.ɵɵelementEnd()();
224
+ i0.ɵɵelementEnd();
152
225
  } if (rf & 2) {
153
226
  const ctx_r1 = i0.ɵɵnextContext(2);
154
227
  i0.ɵɵadvance(3);
155
- i0.ɵɵtextInterpolate1("", ctx_r1.selectedCollections.length, " collection(s) selected");
228
+ i0.ɵɵtextInterpolate(ctx_r1.selectedIds.size);
156
229
  } }
157
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_14_Template(rf, ctx) { if (rf & 1) {
158
- const _r9 = i0.ɵɵgetCurrentView();
159
- i0.ɵɵelementStart(0, "button", 39);
160
- i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_14_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.showCreateForm = true); });
161
- i0.ɵɵelement(1, "i", 40);
162
- i0.ɵɵtext(2, " Create New Collection ");
163
- i0.ɵɵelementEnd();
230
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_For_2_Case_2_Template(rf, ctx) { if (rf & 1) {
231
+ i0.ɵɵelement(0, "i", 60);
164
232
  } }
165
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_15_Conditional_5_Template(rf, ctx) { if (rf & 1) {
166
- i0.ɵɵelement(0, "i", 44);
233
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_For_2_Case_3_Template(rf, ctx) { if (rf & 1) {
234
+ i0.ɵɵelement(0, "i", 48);
167
235
  } }
168
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_15_Conditional_6_Template(rf, ctx) { if (rf & 1) {
169
- i0.ɵɵtext(0, " Create ");
236
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_For_2_Case_4_Template(rf, ctx) { if (rf & 1) {
237
+ i0.ɵɵelement(0, "i", 37);
238
+ } }
239
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_For_2_Case_5_Template(rf, ctx) { if (rf & 1) {
240
+ i0.ɵɵelement(0, "i", 66);
170
241
  } }
171
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_15_Template(rf, ctx) { if (rf & 1) {
242
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_For_2_Conditional_9_Template(rf, ctx) { if (rf & 1) {
243
+ i0.ɵɵelementStart(0, "div", 69);
244
+ i0.ɵɵtext(1);
245
+ i0.ɵɵelementEnd();
246
+ } if (rf & 2) {
247
+ const r_r9 = i0.ɵɵnextContext().$implicit;
248
+ i0.ɵɵadvance();
249
+ i0.ɵɵtextInterpolate(r_r9.errorMessage);
250
+ } }
251
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_For_2_Conditional_10_Template(rf, ctx) { if (rf & 1) {
172
252
  const _r10 = i0.ɵɵgetCurrentView();
173
- i0.ɵɵelementStart(0, "div", 15)(1, "input", 41, 0);
174
- i0.ɵɵtwoWayListener("ngModelChange", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_15_Template_input_ngModelChange_1_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.newCollectionName, $event) || (ctx_r1.newCollectionName = $event); return i0.ɵɵresetView($event); });
175
- i0.ɵɵlistener("keydown.enter", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_15_Template_input_keydown_enter_1_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.createCollection()); });
253
+ i0.ɵɵelementStart(0, "button", 71);
254
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_For_2_Conditional_10_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r10); const r_r9 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.retryOne(r_r9.collectionId)); });
255
+ i0.ɵɵelement(1, "i", 72);
176
256
  i0.ɵɵelementEnd();
177
- i0.ɵɵelementStart(3, "div", 42)(4, "button", 43);
178
- i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_15_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.createCollection()); });
179
- i0.ɵɵconditionalCreate(5, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_15_Conditional_5_Template, 1, 0, "i", 44)(6, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_15_Conditional_6_Template, 1, 0);
257
+ } }
258
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_For_2_Template(rf, ctx) { if (rf & 1) {
259
+ i0.ɵɵelementStart(0, "div", 64)(1, "span", 65);
260
+ i0.ɵɵconditionalCreate(2, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_For_2_Case_2_Template, 1, 0, "i", 60)(3, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_For_2_Case_3_Template, 1, 0, "i", 48)(4, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_For_2_Case_4_Template, 1, 0, "i", 37)(5, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_For_2_Case_5_Template, 1, 0, "i", 66);
261
+ i0.ɵɵelementEnd();
262
+ i0.ɵɵelementStart(6, "div", 67)(7, "div", 68);
263
+ i0.ɵɵtext(8);
264
+ i0.ɵɵelementEnd();
265
+ i0.ɵɵconditionalCreate(9, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_For_2_Conditional_9_Template, 2, 1, "div", 69);
266
+ i0.ɵɵelementEnd();
267
+ i0.ɵɵconditionalCreate(10, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_For_2_Conditional_10_Template, 2, 0, "button", 70);
268
+ i0.ɵɵelementEnd();
269
+ } if (rf & 2) {
270
+ let tmp_16_0;
271
+ const r_r9 = ctx.$implicit;
272
+ i0.ɵɵclassProp("success", r_r9.status === "success")("error", r_r9.status === "error")("saving", r_r9.status === "saving");
273
+ i0.ɵɵadvance(2);
274
+ i0.ɵɵconditional((tmp_16_0 = r_r9.status) === "saving" ? 2 : tmp_16_0 === "success" ? 3 : tmp_16_0 === "error" ? 4 : 5);
275
+ i0.ɵɵadvance(6);
276
+ i0.ɵɵtextInterpolate(r_r9.collectionName);
277
+ i0.ɵɵadvance();
278
+ i0.ɵɵconditional(r_r9.status === "error" && r_r9.errorMessage ? 9 : -1);
279
+ i0.ɵɵadvance();
280
+ i0.ɵɵconditional(r_r9.status === "error" ? 10 : -1);
281
+ } }
282
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_Template(rf, ctx) { if (rf & 1) {
283
+ i0.ɵɵelementStart(0, "div", 29);
284
+ i0.ɵɵrepeaterCreate(1, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_For_2_Template, 11, 10, "div", 63, _forTrack1);
180
285
  i0.ɵɵelementEnd();
181
- i0.ɵɵelementStart(7, "button", 45);
182
- i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_15_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); ctx_r1.showCreateForm = false; return i0.ɵɵresetView(ctx_r1.newCollectionName = ""); });
183
- i0.ɵɵtext(8, " Cancel ");
184
- i0.ɵɵelementEnd()()();
185
286
  } if (rf & 2) {
186
287
  const ctx_r1 = i0.ɵɵnextContext(2);
187
288
  i0.ɵɵadvance();
188
- i0.ɵɵtwoWayProperty("ngModel", ctx_r1.newCollectionName);
289
+ i0.ɵɵrepeater(ctx_r1.resultsList);
290
+ } }
291
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_36_For_2_Template(rf, ctx) { if (rf & 1) {
292
+ const _r11 = i0.ɵɵgetCurrentView();
293
+ i0.ɵɵelementStart(0, "div", 73);
294
+ i0.ɵɵelement(1, "i", 49);
295
+ i0.ɵɵelementStart(2, "div", 67)(3, "div", 68);
296
+ i0.ɵɵtext(4);
297
+ i0.ɵɵelementEnd()();
298
+ i0.ɵɵelementStart(5, "button", 74);
299
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_36_For_2_Template_button_click_5_listener() { const c_r12 = i0.ɵɵrestoreView(_r11).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.deselect(c_r12.ID)); });
300
+ i0.ɵɵelement(6, "i", 35);
301
+ i0.ɵɵelementEnd()();
302
+ } if (rf & 2) {
303
+ const c_r12 = ctx.$implicit;
304
+ const ctx_r1 = i0.ɵɵnextContext(3);
305
+ i0.ɵɵadvance();
306
+ i0.ɵɵstyleProp("color", c_r12.Color || "var(--mj-brand-primary)");
189
307
  i0.ɵɵadvance(3);
190
- i0.ɵɵproperty("disabled", ctx_r1.isCreatingCollection || !ctx_r1.newCollectionName.trim());
308
+ i0.ɵɵtextInterpolate(c_r12.Name);
309
+ i0.ɵɵadvance();
310
+ i0.ɵɵproperty("disabled", ctx_r1.isSaving);
311
+ } }
312
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_36_Template(rf, ctx) { if (rf & 1) {
313
+ i0.ɵɵelementStart(0, "div", 29);
314
+ i0.ɵɵrepeaterCreate(1, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_36_For_2_Template, 7, 4, "div", 73, _forTrack2);
315
+ i0.ɵɵelementEnd();
316
+ } if (rf & 2) {
317
+ const ctx_r1 = i0.ɵɵnextContext(2);
191
318
  i0.ɵɵadvance();
192
- i0.ɵɵconditional(ctx_r1.isCreatingCollection ? 5 : 6);
319
+ i0.ɵɵrepeater(ctx_r1.selectedCollections);
320
+ } }
321
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_37_Template(rf, ctx) { if (rf & 1) {
322
+ i0.ɵɵelementStart(0, "div", 30);
323
+ i0.ɵɵelement(1, "i", 75);
324
+ i0.ɵɵelementStart(2, "p");
325
+ i0.ɵɵtext(3, "Pick a collection on the left");
326
+ i0.ɵɵelementEnd()();
193
327
  } }
194
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_20_Template(rf, ctx) { if (rf & 1) {
195
- i0.ɵɵelement(0, "i", 44);
196
- i0.ɵɵtext(1, " Saving... ");
328
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_42_Template(rf, ctx) { if (rf & 1) {
329
+ const _r13 = i0.ɵɵgetCurrentView();
330
+ i0.ɵɵelementStart(0, "button", 76);
331
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_42_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.retryFailed()); });
332
+ i0.ɵɵelement(1, "i", 72);
333
+ i0.ɵɵtext(2);
334
+ i0.ɵɵelementEnd();
335
+ i0.ɵɵelementStart(3, "button", 77);
336
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_42_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onAcknowledgeAndClose()); });
337
+ i0.ɵɵtext(4, "Done");
338
+ i0.ɵɵelementEnd();
339
+ } if (rf & 2) {
340
+ const ctx_r1 = i0.ɵɵnextContext(2);
341
+ i0.ɵɵadvance(2);
342
+ i0.ɵɵtextInterpolate1(" Retry ", ctx_r1.failedCount, " failed ");
343
+ } }
344
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_43_Template(rf, ctx) { if (rf & 1) {
345
+ const _r14 = i0.ɵɵgetCurrentView();
346
+ i0.ɵɵelementStart(0, "button", 76);
347
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_43_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r14); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onAcknowledgeAndClose()); });
348
+ i0.ɵɵelement(1, "i", 48);
349
+ i0.ɵɵtext(2, " Done ");
350
+ i0.ɵɵelementEnd();
351
+ } }
352
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_44_Conditional_1_Template(rf, ctx) { if (rf & 1) {
353
+ i0.ɵɵelement(0, "i", 60);
354
+ i0.ɵɵtext(1);
355
+ } if (rf & 2) {
356
+ const ctx_r1 = i0.ɵɵnextContext(3);
357
+ i0.ɵɵadvance();
358
+ i0.ɵɵtextInterpolate1(" Saving to ", ctx_r1.selectedIds.size, "\u2026 ");
197
359
  } }
198
- function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_21_Template(rf, ctx) { if (rf & 1) {
199
- i0.ɵɵelement(0, "i", 46);
360
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_44_Conditional_2_Template(rf, ctx) { if (rf & 1) {
361
+ i0.ɵɵelement(0, "i", 80);
200
362
  i0.ɵɵtext(1);
363
+ } if (rf & 2) {
364
+ const ctx_r1 = i0.ɵɵnextContext(3);
365
+ i0.ɵɵadvance();
366
+ i0.ɵɵtextInterpolate2(" Save to ", ctx_r1.selectedIds.size, " ", ctx_r1.selectedIds.size === 1 ? "collection" : "collections", " ");
367
+ } }
368
+ function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_44_Template(rf, ctx) { if (rf & 1) {
369
+ const _r15 = i0.ɵɵgetCurrentView();
370
+ i0.ɵɵelementStart(0, "button", 78);
371
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_44_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r15); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onSave()); });
372
+ i0.ɵɵconditionalCreate(1, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_44_Conditional_1_Template, 2, 1)(2, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_44_Conditional_2_Template, 2, 2);
373
+ i0.ɵɵelementEnd();
374
+ i0.ɵɵelementStart(3, "button", 79);
375
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_44_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r15); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onCancel()); });
376
+ i0.ɵɵtext(4, "Cancel");
377
+ i0.ɵɵelementEnd();
201
378
  } if (rf & 2) {
202
379
  const ctx_r1 = i0.ɵɵnextContext(2);
380
+ i0.ɵɵproperty("disabled", ctx_r1.selectedIds.size === 0 || ctx_r1.isSaving);
203
381
  i0.ɵɵadvance();
204
- i0.ɵɵtextInterpolate1(" Save to ", ctx_r1.selectedCollections.length, " Collection(s) ");
382
+ i0.ɵɵconditional(ctx_r1.isSaving ? 1 : 2);
383
+ i0.ɵɵadvance(2);
384
+ i0.ɵɵproperty("disabled", ctx_r1.isSaving);
205
385
  } }
206
386
  function ArtifactCollectionPickerModalComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
207
387
  const _r1 = i0.ɵɵgetCurrentView();
208
- i0.ɵɵelementStart(0, "mj-dialog", 2);
388
+ i0.ɵɵelementStart(0, "mj-dialog", 3);
209
389
  i0.ɵɵlistener("Close", function ArtifactCollectionPickerModalComponent_Conditional_0_Template_mj_dialog_Close_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onCancel()); });
210
- i0.ɵɵelementStart(1, "div", 3);
211
- i0.ɵɵconditionalCreate(2, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_2_Template, 6, 0, "div", 4);
212
- i0.ɵɵelementStart(3, "div", 5);
213
- i0.ɵɵelement(4, "i", 6);
214
- i0.ɵɵelementStart(5, "input", 7);
215
- i0.ɵɵtwoWayListener("ngModelChange", function ArtifactCollectionPickerModalComponent_Conditional_0_Template_input_ngModelChange_5_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.searchQuery, $event) || (ctx_r1.searchQuery = $event); return i0.ɵɵresetView($event); });
216
- i0.ɵɵlistener("input", function ArtifactCollectionPickerModalComponent_Conditional_0_Template_input_input_5_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onSearchChange()); });
217
- i0.ɵɵelementEnd()();
218
- i0.ɵɵconditionalCreate(6, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_6_Template, 3, 1, "div", 8);
219
- i0.ɵɵconditionalCreate(7, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_7_Template, 2, 0, "div", 9);
220
- i0.ɵɵconditionalCreate(8, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_8_Template, 4, 1, "div", 10);
221
- i0.ɵɵconditionalCreate(9, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_9_Template, 4, 1, "div", 11);
222
- i0.ɵɵelementStart(10, "div", 12)(11, "div", 13)(12, "span");
223
- i0.ɵɵtext(13, "OR CREATE NEW");
390
+ i0.ɵɵelementStart(1, "div", 4)(2, "div", 5)(3, "div", 6)(4, "div", 7);
391
+ i0.ɵɵelement(5, "i", 8);
392
+ i0.ɵɵelementStart(6, "input", 9, 0);
393
+ i0.ɵɵtwoWayListener("ngModelChange", function ArtifactCollectionPickerModalComponent_Conditional_0_Template_input_ngModelChange_6_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.searchQuery, $event) || (ctx_r1.searchQuery = $event); return i0.ɵɵresetView($event); });
394
+ i0.ɵɵlistener("ngModelChange", function ArtifactCollectionPickerModalComponent_Conditional_0_Template_input_ngModelChange_6_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onSearchChange()); });
395
+ i0.ɵɵelementEnd();
396
+ i0.ɵɵconditionalCreate(8, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_8_Template, 2, 0, "button", 10);
397
+ i0.ɵɵelementEnd();
398
+ i0.ɵɵelementStart(9, "button", 11);
399
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.setFilter("editable")); });
400
+ i0.ɵɵelement(10, "i", 12);
401
+ i0.ɵɵtext(11, " Editable ");
402
+ i0.ɵɵelementEnd();
403
+ i0.ɵɵelementStart(12, "button", 11);
404
+ i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.setFilter("recent")); });
405
+ i0.ɵɵelement(13, "i", 13);
406
+ i0.ɵɵtext(14, " Recent ");
224
407
  i0.ɵɵelementEnd()();
225
- i0.ɵɵconditionalCreate(14, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_14_Template, 3, 0, "button", 14)(15, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_15_Template, 9, 3, "div", 15);
408
+ i0.ɵɵelementStart(15, "div", 14);
409
+ i0.ɵɵconditionalCreate(16, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_16_Template, 2, 0, "div", 15)(17, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_17_Template, 4, 1, "div", 16)(18, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_18_Template, 3, 1, "div", 17)(19, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_19_Template, 5, 1, "div", 18);
226
410
  i0.ɵɵelementEnd()();
227
- i0.ɵɵelementStart(16, "mj-dialog-actions")(17, "button", 16);
228
- i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Template_button_click_17_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onCancel()); });
229
- i0.ɵɵtext(18, " Cancel ");
411
+ i0.ɵɵelementStart(20, "div", 19)(21, "div", 20)(22, "div", 21);
412
+ i0.ɵɵtext(23, "Saving");
413
+ i0.ɵɵelementEnd();
414
+ i0.ɵɵelementStart(24, "div", 22)(25, "div", 23);
415
+ i0.ɵɵelement(26, "i", 24);
416
+ i0.ɵɵelementEnd();
417
+ i0.ɵɵelementStart(27, "div", 25)(28, "div", 26);
418
+ i0.ɵɵtext(29);
230
419
  i0.ɵɵelementEnd();
231
- i0.ɵɵelementStart(19, "button", 17);
232
- i0.ɵɵlistener("click", function ArtifactCollectionPickerModalComponent_Conditional_0_Template_button_click_19_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onSave()); });
233
- i0.ɵɵconditionalCreate(20, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_20_Template, 2, 0)(21, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_21_Template, 2, 1);
420
+ i0.ɵɵconditionalCreate(30, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_30_Template, 2, 1, "span", 27);
234
421
  i0.ɵɵelementEnd()()();
422
+ i0.ɵɵelementStart(31, "div", 28)(32, "div", 21);
423
+ i0.ɵɵconditionalCreate(33, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_33_Template, 4, 2)(34, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_34_Template, 4, 1);
424
+ i0.ɵɵelementEnd();
425
+ i0.ɵɵconditionalCreate(35, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_35_Template, 3, 0, "div", 29)(36, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_36_Template, 3, 0, "div", 29)(37, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_37_Template, 4, 0, "div", 30);
426
+ i0.ɵɵelementEnd();
427
+ i0.ɵɵelementStart(38, "div", 31);
428
+ i0.ɵɵelement(39, "i", 32);
429
+ i0.ɵɵtext(40, " Only collections you can edit are shown ");
430
+ i0.ɵɵelementEnd()()();
431
+ i0.ɵɵelementStart(41, "mj-dialog-actions");
432
+ i0.ɵɵconditionalCreate(42, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_42_Template, 5, 1)(43, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_43_Template, 3, 0, "button", 33)(44, ArtifactCollectionPickerModalComponent_Conditional_0_Conditional_44_Template, 5, 3);
433
+ i0.ɵɵelementEnd()();
235
434
  } if (rf & 2) {
236
435
  const ctx_r1 = i0.ɵɵnextContext();
237
- i0.ɵɵproperty("Visible", true)("Width", 700)("MinWidth", 500);
238
- i0.ɵɵadvance(2);
239
- i0.ɵɵconditional(ctx_r1.navigationPath.length > 0 ? 2 : -1);
240
- i0.ɵɵadvance(3);
436
+ i0.ɵɵproperty("Visible", true)("Width", 960)("MinWidth", 720);
437
+ i0.ɵɵadvance(6);
241
438
  i0.ɵɵtwoWayProperty("ngModel", ctx_r1.searchQuery);
242
- i0.ɵɵproperty("disabled", ctx_r1.isLoading);
243
- i0.ɵɵadvance();
244
- i0.ɵɵconditional(!ctx_r1.isLoading && !ctx_r1.errorMessage ? 6 : -1);
245
- i0.ɵɵadvance();
246
- i0.ɵɵconditional(ctx_r1.isLoading ? 7 : -1);
439
+ i0.ɵɵproperty("disabled", ctx_r1.isLoading || ctx_r1.isSaving);
440
+ i0.ɵɵadvance(2);
441
+ i0.ɵɵconditional(ctx_r1.searchQuery ? 8 : -1);
247
442
  i0.ɵɵadvance();
248
- i0.ɵɵconditional(ctx_r1.errorMessage ? 8 : -1);
443
+ i0.ɵɵclassProp("active", ctx_r1.filterMode === "editable");
444
+ i0.ɵɵproperty("disabled", ctx_r1.isSaving);
445
+ i0.ɵɵadvance(3);
446
+ i0.ɵɵclassProp("active", ctx_r1.filterMode === "recent");
447
+ i0.ɵɵproperty("disabled", ctx_r1.isSaving);
448
+ i0.ɵɵadvance(4);
449
+ i0.ɵɵconditional(ctx_r1.isLoading ? 16 : ctx_r1.errorMessage ? 17 : ctx_r1.visibleNodes.length === 0 ? 18 : 19);
450
+ i0.ɵɵadvance(12);
451
+ i0.ɵɵproperty("title", ctx_r1.artifactName);
249
452
  i0.ɵɵadvance();
250
- i0.ɵɵconditional(ctx_r1.selectedCollections.length > 0 ? 9 : -1);
251
- i0.ɵɵadvance(5);
252
- i0.ɵɵconditional(!ctx_r1.showCreateForm ? 14 : 15);
253
- i0.ɵɵadvance(5);
254
- i0.ɵɵproperty("disabled", ctx_r1.selectedCollections.length === 0 || ctx_r1.isSaving);
453
+ i0.ɵɵtextInterpolate(ctx_r1.artifactName || "Artifact");
255
454
  i0.ɵɵadvance();
256
- i0.ɵɵconditional(ctx_r1.isSaving ? 20 : 21);
455
+ i0.ɵɵconditional(ctx_r1.artifactVersionNumber != null ? 30 : -1);
456
+ i0.ɵɵadvance(3);
457
+ i0.ɵɵconditional(ctx_r1.saveResults.size > 0 ? 33 : 34);
458
+ i0.ɵɵadvance(2);
459
+ i0.ɵɵconditional(ctx_r1.saveResults.size > 0 ? 35 : ctx_r1.selectedIds.size > 0 ? 36 : 37);
460
+ i0.ɵɵadvance(7);
461
+ i0.ɵɵconditional(ctx_r1.failedCount > 0 && !ctx_r1.isSaving ? 42 : ctx_r1.saveResults.size > 0 && ctx_r1.successCount === ctx_r1.saveResults.size && !ctx_r1.isSaving ? 43 : 44);
257
462
  } }
258
463
  /**
259
- * Modal for selecting collections to save artifacts to.
260
- * Features:
261
- * - Permission-aware: only shows collections where user has Edit permission
262
- * - Hierarchical navigation: start with root collections, drill down as needed
263
- * - Search by name
264
- * - Multi-selection support
265
- * - Create new collection with proper permission logic
464
+ * Modal for saving an artifact version to one or more collections.
465
+ *
466
+ * Owns the full UX *and* the writes:
467
+ * - Left pane: searchable, expandable tree of collections the user can edit
468
+ * - Right pane: artifact preview + live selection chips, and (post-save) per-collection results
469
+ * - Save runs inline (modal stays open during writes) and reports per-collection success/failure with retry
470
+ *
471
+ * Emits {@link completed} on full success (parent should reload bookmark state) and on user-acknowledged
472
+ * partial failure. Emits {@link cancelled} when the user backs out without saving anything.
266
473
  */
267
474
  export class ArtifactCollectionPickerModalComponent extends BaseAngularComponent {
268
475
  toastService;
@@ -271,30 +478,50 @@ export class ArtifactCollectionPickerModalComponent extends BaseAngularComponent
271
478
  isOpen = false;
272
479
  environmentId;
273
480
  currentUser;
274
- excludeCollectionIds = []; // Collections to exclude (e.g., already contains artifact)
275
- saved = new EventEmitter(); // Emits selected collection IDs
481
+ /** Collections that already contain the *current version* rendered with a green check and locked. */
482
+ excludeCollectionIds = [];
483
+ /** ID of the artifact version being saved. Required for writes. */
484
+ artifactVersionId = null;
485
+ /** Display-only: artifact name shown in the preview pane. */
486
+ artifactName = '';
487
+ /** Display-only: version number shown in the preview pane. */
488
+ artifactVersionNumber = null;
489
+ /** Fired when the save flow finishes (fully successful, or user acknowledged partial result). */
490
+ completed = new EventEmitter();
276
491
  cancelled = new EventEmitter();
492
+ searchInputRef;
493
+ newNameInputRef;
494
+ // Data
277
495
  allCollections = [];
278
- displayedCollections = [];
279
- selectedCollections = [];
496
+ editableCollections = [];
280
497
  userPermissions = new Map();
281
- navigationPath = []; // Breadcrumb trail
282
- currentParentId = null;
283
- currentParentCollection = undefined;
498
+ collectionById = new Map();
499
+ expandedIds = new Set();
500
+ // Selection (normalized UUIDs so SQL Server vs Postgres casing doesn't bite us)
501
+ selectedIds = new Set();
502
+ // Filter / search
284
503
  searchQuery = '';
504
+ filterMode = 'editable';
505
+ // Render output
506
+ visibleNodes = [];
507
+ // States
285
508
  isLoading = false;
286
509
  isSaving = false;
287
510
  errorMessage = '';
288
- // Create collection form state
289
511
  showCreateForm = false;
290
512
  newCollectionName = '';
291
513
  isCreatingCollection = false;
514
+ // Per-collection save outcomes
515
+ saveResults = new Map();
292
516
  constructor(toastService, permissionService, cdr) {
293
517
  super();
294
518
  this.toastService = toastService;
295
519
  this.permissionService = permissionService;
296
520
  this.cdr = cdr;
297
521
  }
522
+ // ============================================================
523
+ // Lifecycle
524
+ // ============================================================
298
525
  async ngOnInit() {
299
526
  this.permissionService.Provider = this.ProviderToUse;
300
527
  if (this.isOpen) {
@@ -302,27 +529,76 @@ export class ArtifactCollectionPickerModalComponent extends BaseAngularComponent
302
529
  }
303
530
  }
304
531
  async ngOnChanges(changes) {
305
- if (changes['isOpen'] && this.isOpen) {
306
- this.reset();
307
- await this.loadCollections();
532
+ if (changes['isOpen']) {
533
+ if (this.isOpen) {
534
+ this.resetState();
535
+ await this.loadCollections();
536
+ // Autofocus search on next tick
537
+ Promise.resolve().then(() => this.searchInputRef?.nativeElement?.focus());
538
+ }
308
539
  }
309
540
  }
310
- reset() {
541
+ ngAfterViewInit() {
542
+ if (this.isOpen) {
543
+ this.searchInputRef?.nativeElement?.focus();
544
+ }
545
+ }
546
+ // ============================================================
547
+ // Selection helpers (normalized UUIDs)
548
+ // ============================================================
549
+ isSelected(id) {
550
+ return this.selectedIds.has(NormalizeUUID(id));
551
+ }
552
+ get selectedCollections() {
553
+ const list = [];
554
+ for (const id of this.selectedIds) {
555
+ const c = this.collectionById.get(id);
556
+ if (c)
557
+ list.push(c);
558
+ }
559
+ return list;
560
+ }
561
+ get resultsList() {
562
+ return Array.from(this.saveResults.values());
563
+ }
564
+ get successCount() {
565
+ let n = 0;
566
+ for (const r of this.saveResults.values())
567
+ if (r.status === 'success')
568
+ n++;
569
+ return n;
570
+ }
571
+ get failedCount() {
572
+ let n = 0;
573
+ for (const r of this.saveResults.values())
574
+ if (r.status === 'error')
575
+ n++;
576
+ return n;
577
+ }
578
+ // ============================================================
579
+ // Load + tree build
580
+ // ============================================================
581
+ resetState() {
311
582
  this.allCollections = [];
312
- this.displayedCollections = [];
313
- this.selectedCollections = [];
583
+ this.editableCollections = [];
314
584
  this.userPermissions.clear();
315
- this.navigationPath = [];
316
- this.currentParentId = null;
317
- this.currentParentCollection = undefined;
585
+ this.collectionById.clear();
586
+ this.expandedIds.clear();
587
+ this.selectedIds.clear();
588
+ this.visibleNodes = [];
318
589
  this.searchQuery = '';
590
+ this.filterMode = 'editable';
319
591
  this.errorMessage = '';
592
+ this.showCreateForm = false;
593
+ this.newCollectionName = '';
594
+ this.saveResults.clear();
595
+ this.isSaving = false;
596
+ this.isCreatingCollection = false;
320
597
  }
321
598
  async loadCollections() {
322
599
  try {
323
600
  this.isLoading = true;
324
601
  this.errorMessage = '';
325
- // Load all collections in environment
326
602
  const rv = RunView.FromMetadataProvider(this.ProviderToUse);
327
603
  const result = await rv.RunView({
328
604
  EntityName: 'MJ: Collections',
@@ -335,18 +611,16 @@ export class ArtifactCollectionPickerModalComponent extends BaseAngularComponent
335
611
  return;
336
612
  }
337
613
  this.allCollections = result.Results || [];
338
- // Load user permissions for all collections
339
614
  await this.loadUserPermissions();
340
- // Filter to collections with Edit permission
341
- // Include collections that already contain the artifact (will be shown as disabled)
342
- const editableCollections = this.allCollections.filter(c => {
343
- return this.canEdit(c);
344
- });
345
- // Show root collections initially
346
- this.displayRootCollections(editableCollections);
615
+ this.editableCollections = this.allCollections.filter(c => this.canEdit(c));
616
+ this.collectionById.clear();
617
+ for (const c of this.editableCollections) {
618
+ this.collectionById.set(NormalizeUUID(c.ID), c);
619
+ }
620
+ this.rebuildVisibleNodes();
347
621
  }
348
622
  catch (error) {
349
- console.error('Error loading collections:', error);
623
+ LogError(error);
350
624
  this.errorMessage = 'An error occurred while loading collections';
351
625
  }
352
626
  finally {
@@ -355,204 +629,367 @@ export class ArtifactCollectionPickerModalComponent extends BaseAngularComponent
355
629
  }
356
630
  }
357
631
  async loadUserPermissions() {
358
- // Load permissions for collections not owned by current user
359
- const nonOwnedCollections = this.allCollections.filter(c => c.OwnerID && !UUIDsEqual(c.OwnerID, this.currentUser.ID));
360
- if (nonOwnedCollections.length === 0) {
632
+ const nonOwned = this.allCollections.filter(c => c.OwnerID && !UUIDsEqual(c.OwnerID, this.currentUser.ID));
633
+ if (nonOwned.length === 0)
361
634
  return;
635
+ const ids = nonOwned.map(c => c.ID);
636
+ const permissions = await this.permissionService.checkBulkPermissions(ids, this.currentUser.ID, this.currentUser);
637
+ permissions.forEach((permission, id) => this.userPermissions.set(id, permission));
638
+ }
639
+ canEdit(c) {
640
+ if (!c.OwnerID || UUIDsEqual(c.OwnerID, this.currentUser.ID))
641
+ return true;
642
+ return this.userPermissions.get(c.ID)?.canEdit || false;
643
+ }
644
+ // ============================================================
645
+ // Tree rendering — flat list of CollectionNode, ordered DFS
646
+ // ============================================================
647
+ rebuildVisibleNodes() {
648
+ const q = this.searchQuery.trim().toLowerCase();
649
+ if (q) {
650
+ this.visibleNodes = this.buildSearchNodes(q);
362
651
  }
363
- const collectionIds = nonOwnedCollections.map(c => c.ID);
364
- const permissions = await this.permissionService.checkBulkPermissions(collectionIds, this.currentUser.ID, this.currentUser);
365
- permissions.forEach((permission, collectionId) => {
366
- this.userPermissions.set(collectionId, permission);
367
- });
368
- }
369
- displayRootCollections(editableCollections) {
370
- const rootCollections = editableCollections.filter(c => !c.ParentID);
371
- this.displayedCollections = rootCollections.map(c => this.createNode(c, editableCollections));
372
- }
373
- displayChildCollections(parentId, editableCollections) {
374
- const childCollections = editableCollections.filter(c => UUIDsEqual(c.ParentID, parentId));
375
- this.displayedCollections = childCollections.map(c => this.createNode(c, editableCollections));
376
- }
377
- createNode(collection, allEditableCollections) {
378
- const hasChildren = allEditableCollections.some(c => UUIDsEqual(c.ParentID, collection.ID));
379
- const alreadyContainsArtifact = this.excludeCollectionIds.some(id => UUIDsEqual(id, collection.ID));
380
- return {
381
- collection,
382
- selected: this.selectedCollections.some(sc => UUIDsEqual(sc.ID, collection.ID)),
383
- hasChildren,
384
- alreadyContainsArtifact
652
+ else {
653
+ this.visibleNodes = this.buildTreeNodes();
654
+ }
655
+ }
656
+ buildTreeNodes() {
657
+ const byParent = new Map();
658
+ for (const c of this.editableCollections) {
659
+ const key = c.ParentID ? NormalizeUUID(c.ParentID) : null;
660
+ const arr = byParent.get(key) || [];
661
+ arr.push(c);
662
+ byParent.set(key, arr);
663
+ }
664
+ const out = [];
665
+ const walk = (parentId, depth) => {
666
+ const children = byParent.get(parentId) || [];
667
+ for (const c of children) {
668
+ const id = NormalizeUUID(c.ID);
669
+ const kids = byParent.get(id) || [];
670
+ const hasChildren = kids.length > 0;
671
+ out.push({
672
+ collection: c,
673
+ depth,
674
+ expanded: this.expandedIds.has(id),
675
+ hasChildren,
676
+ alreadyContainsArtifact: this.isAlreadyAdded(c.ID),
677
+ ancestry: ''
678
+ });
679
+ if (hasChildren && this.expandedIds.has(id)) {
680
+ walk(id, depth + 1);
681
+ }
682
+ }
385
683
  };
684
+ walk(null, 0);
685
+ return out;
386
686
  }
387
- canEdit(collection) {
388
- // Backwards compatibility: treat null OwnerID as owned by current user
389
- if (!collection.OwnerID || UUIDsEqual(collection.OwnerID, this.currentUser.ID)) {
390
- return true;
687
+ buildSearchNodes(query) {
688
+ const matches = this.editableCollections.filter(c => c.Name.toLowerCase().includes(query));
689
+ return matches.map(c => ({
690
+ collection: c,
691
+ depth: 0,
692
+ expanded: false,
693
+ hasChildren: false,
694
+ alreadyContainsArtifact: this.isAlreadyAdded(c.ID),
695
+ ancestry: this.buildAncestry(c)
696
+ }));
697
+ }
698
+ buildAncestry(c) {
699
+ const names = [];
700
+ let parentId = c.ParentID;
701
+ let guard = 0;
702
+ while (parentId && guard++ < 32) {
703
+ const p = this.collectionById.get(NormalizeUUID(parentId));
704
+ if (!p)
705
+ break;
706
+ names.unshift(p.Name);
707
+ parentId = p.ParentID;
391
708
  }
392
- // Check permission record
393
- const permission = this.userPermissions.get(collection.ID);
394
- return permission?.canEdit || false;
709
+ return names.join(' / ');
710
+ }
711
+ isAlreadyAdded(id) {
712
+ return this.excludeCollectionIds.some(eid => UUIDsEqual(eid, id));
395
713
  }
396
- toggleSelection(node) {
397
- // Don't allow selection of collections that already contain the artifact
398
- if (node.alreadyContainsArtifact) {
714
+ // ============================================================
715
+ // Tree interactions
716
+ // ============================================================
717
+ onRowClick(node) {
718
+ if (this.isSaving)
399
719
  return;
400
- }
401
- const index = this.selectedCollections.findIndex(c => UUIDsEqual(c.ID, node.collection.ID));
402
- if (index >= 0) {
403
- this.selectedCollections.splice(index, 1);
404
- node.selected = false;
720
+ if (node.alreadyContainsArtifact)
721
+ return;
722
+ this.toggleSelection(node.collection);
723
+ }
724
+ toggleSelection(c) {
725
+ const id = NormalizeUUID(c.ID);
726
+ if (this.selectedIds.has(id)) {
727
+ this.selectedIds.delete(id);
405
728
  }
406
729
  else {
407
- this.selectedCollections.push(node.collection);
408
- node.selected = true;
409
- }
410
- }
411
- drillIntoCollection(collection) {
412
- // Add current location to navigation path
413
- const editableCollections = this.allCollections.filter(c => {
414
- return this.canEdit(c);
415
- });
416
- const node = this.createNode(collection, editableCollections);
417
- this.navigationPath.push(node);
418
- this.currentParentId = collection.ID;
419
- this.currentParentCollection = collection;
420
- // Display child collections
421
- this.displayChildCollections(collection.ID, editableCollections);
422
- // Clear search when drilling down
423
- this.searchQuery = '';
730
+ this.selectedIds.add(id);
731
+ }
424
732
  }
425
- navigateToRoot() {
426
- this.navigationPath = [];
427
- this.currentParentId = null;
428
- this.currentParentCollection = undefined;
429
- const editableCollections = this.allCollections.filter(c => {
430
- return this.canEdit(c);
431
- });
432
- this.displayRootCollections(editableCollections);
433
- this.searchQuery = '';
733
+ deselect(id) {
734
+ if (this.isSaving)
735
+ return;
736
+ this.selectedIds.delete(NormalizeUUID(id));
434
737
  }
435
- navigateToCollection(collection) {
436
- // Find the index of this collection in the navigation path
437
- const index = this.navigationPath.findIndex(n => UUIDsEqual(n.collection.ID, collection.ID));
438
- if (index >= 0) {
439
- // Trim navigation path to this level
440
- this.navigationPath = this.navigationPath.slice(0, index + 1);
441
- this.currentParentId = collection.ID;
442
- this.currentParentCollection = collection;
443
- const editableCollections = this.allCollections.filter(c => {
444
- return this.canEdit(c);
445
- });
446
- this.displayChildCollections(collection.ID, editableCollections);
447
- this.searchQuery = '';
738
+ toggleExpand(node) {
739
+ if (!node.hasChildren)
740
+ return;
741
+ const id = NormalizeUUID(node.collection.ID);
742
+ if (this.expandedIds.has(id)) {
743
+ this.expandedIds.delete(id);
744
+ }
745
+ else {
746
+ this.expandedIds.add(id);
448
747
  }
748
+ this.rebuildVisibleNodes();
449
749
  }
450
750
  onSearchChange() {
451
- if (!this.searchQuery.trim()) {
452
- // Reset to current navigation context
453
- if (this.currentParentId) {
454
- const editableCollections = this.allCollections.filter(c => {
455
- return this.canEdit(c);
456
- });
457
- this.displayChildCollections(this.currentParentId, editableCollections);
458
- }
459
- else {
460
- const editableCollections = this.allCollections.filter(c => {
461
- return this.canEdit(c);
462
- });
463
- this.displayRootCollections(editableCollections);
464
- }
465
- return;
466
- }
467
- // Search across all editable collections
468
- const query = this.searchQuery.toLowerCase();
469
- const editableCollections = this.allCollections.filter(c => {
470
- return this.canEdit(c) && c.Name.toLowerCase().includes(query);
471
- });
472
- this.displayedCollections = editableCollections.map(c => this.createNode(c, editableCollections));
751
+ this.rebuildVisibleNodes();
752
+ }
753
+ clearSearch() {
754
+ this.searchQuery = '';
755
+ this.rebuildVisibleNodes();
756
+ this.searchInputRef?.nativeElement?.focus();
757
+ }
758
+ setFilter(mode) {
759
+ this.filterMode = mode;
760
+ // 'recent' filter is a placeholder for now — same data, future sort change.
761
+ // Keeping the chip wired so the UI is honest and a future PR can flip the sort.
762
+ this.rebuildVisibleNodes();
763
+ }
764
+ // ============================================================
765
+ // Create new collection (root-level only — keeps the picker simple)
766
+ // ============================================================
767
+ openCreateForm() {
768
+ this.showCreateForm = true;
769
+ // Force the @if branch to render now, then focus the input it created.
770
+ // A microtask alone isn't enough — Angular hasn't run change detection by then,
771
+ // so the @ViewChild ref is still undefined.
772
+ this.cdr.detectChanges();
773
+ this.newNameInputRef?.nativeElement?.focus();
774
+ }
775
+ cancelCreate() {
776
+ this.showCreateForm = false;
777
+ this.newCollectionName = '';
473
778
  }
474
779
  async createCollection() {
475
- if (!this.newCollectionName.trim()) {
780
+ const name = this.newCollectionName.trim();
781
+ if (!name) {
476
782
  this.toastService.warning('Please enter a collection name');
477
783
  return;
478
784
  }
479
785
  try {
480
786
  this.isCreatingCollection = true;
481
- const md = this.ProviderToUse;
482
- const collection = await md.GetEntityObject('MJ: Collections', this.currentUser);
483
- collection.Name = this.newCollectionName.trim();
787
+ const p = this.ProviderToUse;
788
+ const collection = await p.GetEntityObject('MJ: Collections', this.currentUser);
789
+ collection.Name = name;
484
790
  collection.EnvironmentID = this.environmentId;
485
- // Set parent and owner based on current navigation context
486
- if (this.currentParentCollection) {
487
- // Creating sub-collection - inherit parent's owner
488
- collection.ParentID = this.currentParentCollection.ID;
489
- collection.OwnerID = this.currentParentCollection.OwnerID || this.currentUser.ID;
490
- }
491
- else {
492
- // Creating root collection - current user becomes owner
493
- collection.OwnerID = this.currentUser.ID;
494
- }
791
+ collection.OwnerID = this.currentUser.ID;
495
792
  const saved = await collection.Save();
496
- if (saved) {
497
- // Create owner permission or copy parent permissions
498
- if (this.currentParentCollection) {
499
- // Copy permissions from parent
500
- await this.permissionService.copyParentPermissions(this.currentParentCollection.ID, collection.ID, this.currentUser);
501
- }
502
- else {
503
- // Create owner permission
504
- await this.permissionService.createOwnerPermission(collection.ID, this.currentUser.ID, this.currentUser);
505
- }
506
- this.toastService.success('Collection created successfully');
507
- // Reset form
508
- this.showCreateForm = false;
509
- this.newCollectionName = '';
510
- // Reload collections to include the new one
511
- await this.loadCollections();
512
- // Auto-select the newly created collection
513
- this.selectedCollections.push(collection);
514
- }
515
- else {
516
- this.toastService.error(collection.LatestResult?.Message || 'Failed to create collection');
793
+ if (!saved) {
794
+ this.toastService.error(collection.LatestResult?.CompleteMessage || 'Failed to create collection');
795
+ return;
517
796
  }
797
+ // No explicit owner permission row needed — CollectionPermissionProvider treats the
798
+ // OwnerID as an implicit full-access grant. Writing a self-share row was both redundant
799
+ // and triggering a server-side auth failure on freshly-created collections.
800
+ this.toastService.success('Collection created');
801
+ this.cancelCreate();
802
+ // Splice the new collection into local state directly. Re-running loadCollections() here
803
+ // races with the server's cache-invalidation propagation and intermittently returns the
804
+ // pre-create result; we already own the freshly-saved entity, so just use it.
805
+ this.allCollections = [...this.allCollections, collection];
806
+ this.editableCollections = [...this.editableCollections, collection];
807
+ this.collectionById.set(NormalizeUUID(collection.ID), collection);
808
+ // Auto-select the new one
809
+ this.selectedIds.add(NormalizeUUID(collection.ID));
810
+ this.rebuildVisibleNodes();
518
811
  }
519
812
  catch (error) {
520
- console.error('Error creating collection:', error);
521
- this.toastService.error('An error occurred while creating the collection');
813
+ LogError(error);
814
+ this.toastService.error('Failed to create collection');
522
815
  }
523
816
  finally {
524
817
  this.isCreatingCollection = false;
525
818
  this.cdr.detectChanges();
526
819
  }
527
820
  }
821
+ // ============================================================
822
+ // Save flow (writes happen here, dialog stays open until done)
823
+ // ============================================================
528
824
  async onSave() {
529
- if (this.selectedCollections.length === 0) {
530
- this.toastService.warning('Please select at least one collection');
825
+ if (this.isSaving)
826
+ return;
827
+ if (this.selectedIds.size === 0) {
828
+ this.toastService.warning('Pick at least one collection');
829
+ return;
830
+ }
831
+ if (!this.artifactVersionId) {
832
+ this.toastService.error('No version selected to save');
531
833
  return;
532
834
  }
533
835
  this.isSaving = true;
534
- try {
535
- // Emit the selected collection IDs - parent handles actual saving and modal close
536
- const collectionIds = this.selectedCollections.map(c => c.ID);
537
- this.saved.emit(collectionIds);
836
+ this.saveResults.clear();
837
+ // Seed each result as pending so they render in order
838
+ for (const c of this.selectedCollections) {
839
+ this.saveResults.set(NormalizeUUID(c.ID), {
840
+ collectionId: c.ID,
841
+ collectionName: c.Name,
842
+ status: 'pending'
843
+ });
538
844
  }
539
- finally {
540
- this.isSaving = false;
845
+ this.cdr.detectChanges();
846
+ for (const c of this.selectedCollections) {
847
+ await this.saveOne(c);
848
+ }
849
+ this.isSaving = false;
850
+ // Auto-close on full success
851
+ if (this.failedCount === 0) {
852
+ this.emitCompleted();
853
+ }
854
+ else {
855
+ this.toastService.warning(`Saved to ${this.successCount} of ${this.saveResults.size} collections`);
856
+ this.cdr.detectChanges();
857
+ }
858
+ }
859
+ async retryFailed() {
860
+ if (this.isSaving)
861
+ return;
862
+ const toRetry = [];
863
+ for (const r of this.saveResults.values()) {
864
+ if (r.status === 'error') {
865
+ const c = this.collectionById.get(NormalizeUUID(r.collectionId));
866
+ if (c)
867
+ toRetry.push(c);
868
+ }
869
+ }
870
+ if (toRetry.length === 0)
871
+ return;
872
+ this.isSaving = true;
873
+ this.cdr.detectChanges();
874
+ for (const c of toRetry) {
875
+ await this.saveOne(c);
876
+ }
877
+ this.isSaving = false;
878
+ if (this.failedCount === 0) {
879
+ this.emitCompleted();
880
+ }
881
+ else {
541
882
  this.cdr.detectChanges();
542
883
  }
543
884
  }
885
+ async retryOne(collectionId) {
886
+ if (this.isSaving)
887
+ return;
888
+ const c = this.collectionById.get(NormalizeUUID(collectionId));
889
+ if (!c)
890
+ return;
891
+ this.isSaving = true;
892
+ this.cdr.detectChanges();
893
+ await this.saveOne(c);
894
+ this.isSaving = false;
895
+ if (this.failedCount === 0 && this.successCount === this.saveResults.size) {
896
+ this.emitCompleted();
897
+ }
898
+ else {
899
+ this.cdr.detectChanges();
900
+ }
901
+ }
902
+ async saveOne(collection) {
903
+ const key = NormalizeUUID(collection.ID);
904
+ const r = this.saveResults.get(key);
905
+ if (!r)
906
+ return;
907
+ r.status = 'saving';
908
+ r.errorMessage = undefined;
909
+ this.cdr.detectChanges();
910
+ try {
911
+ const versionId = this.artifactVersionId;
912
+ if (!versionId) {
913
+ r.status = 'error';
914
+ r.errorMessage = 'No artifact version selected';
915
+ return;
916
+ }
917
+ const p = this.ProviderToUse;
918
+ // Server-side cache + remote-invalidation make this idempotent in practice,
919
+ // but we still pre-check to avoid creating duplicate junction rows in races.
920
+ const rv = RunView.FromMetadataProvider(p);
921
+ const existing = await rv.RunView({
922
+ EntityName: 'MJ: Collection Artifacts',
923
+ ExtraFilter: `CollectionID='${collection.ID}' AND ArtifactVersionID='${versionId}'`,
924
+ ResultType: 'simple',
925
+ Fields: ['ID']
926
+ }, this.currentUser);
927
+ if (existing.Success && (existing.Results?.length ?? 0) > 0) {
928
+ r.status = 'success';
929
+ return;
930
+ }
931
+ const junction = await p.GetEntityObject('MJ: Collection Artifacts', this.currentUser);
932
+ junction.CollectionID = collection.ID;
933
+ junction.ArtifactVersionID = versionId;
934
+ junction.Sequence = 0;
935
+ const ok = await junction.Save();
936
+ if (ok) {
937
+ r.status = 'success';
938
+ }
939
+ else {
940
+ r.status = 'error';
941
+ r.errorMessage = junction.LatestResult?.CompleteMessage || 'Save failed';
942
+ }
943
+ }
944
+ catch (err) {
945
+ LogError(err);
946
+ r.status = 'error';
947
+ r.errorMessage = err instanceof Error ? err.message : 'Unexpected error';
948
+ }
949
+ }
950
+ // ============================================================
951
+ // Close paths
952
+ // ============================================================
544
953
  onCancel() {
545
- this.cancelled.emit();
954
+ if (this.isSaving)
955
+ return; // can't close while writes are in flight
956
+ // If any saves completed before cancel, treat it as completion so the viewer reloads
957
+ if (this.successCount > 0) {
958
+ this.emitCompleted();
959
+ }
960
+ else {
961
+ this.cancelled.emit();
962
+ }
963
+ }
964
+ onAcknowledgeAndClose() {
965
+ this.emitCompleted();
966
+ }
967
+ emitCompleted() {
968
+ const successIds = [];
969
+ const failedIds = [];
970
+ for (const r of this.saveResults.values()) {
971
+ if (r.status === 'success')
972
+ successIds.push(r.collectionId);
973
+ else if (r.status === 'error')
974
+ failedIds.push(r.collectionId);
975
+ }
976
+ this.completed.emit({ successIds, failedIds });
546
977
  }
547
978
  static ɵfac = function ArtifactCollectionPickerModalComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ArtifactCollectionPickerModalComponent)(i0.ɵɵdirectiveInject(i1.ToastService), i0.ɵɵdirectiveInject(i2.CollectionPermissionService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
548
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ArtifactCollectionPickerModalComponent, selectors: [["mj-artifact-collection-picker-modal"]], inputs: { isOpen: "isOpen", environmentId: "environmentId", currentUser: "currentUser", excludeCollectionIds: "excludeCollectionIds" }, outputs: { saved: "saved", cancelled: "cancelled" }, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 1, vars: 1, consts: [["newCollectionInput", ""], ["Title", "Save to Collection", 3, "Visible", "Width", "MinWidth"], ["Title", "Save to Collection", 3, "Close", "Visible", "Width", "MinWidth"], [1, "picker-modal"], [1, "breadcrumb-nav"], [1, "search-bar"], [1, "fas", "fa-search", "search-icon"], ["type", "text", "placeholder", "Search collections...", 1, "k-textbox", "search-input", 3, "ngModelChange", "input", "ngModel", "disabled"], [1, "collections-list"], [1, "loading-state"], [1, "error-state"], [1, "selected-summary"], [1, "create-section"], [1, "divider"], [1, "btn-create-collection"], [1, "create-form"], ["mjButton", "", 3, "click"], ["mjButton", "", "variant", "primary", 3, "click", "disabled"], [1, "breadcrumb-btn", 3, "click"], [1, "fas", "fa-home"], [1, "fas", "fa-chevron-right", "breadcrumb-separator"], [1, "empty-state"], [1, "fas", "fa-search"], [1, "fas", "fa-folder-open"], [1, "fas", "fa-folder"], [1, "hint"], [1, "collection-item", 3, "already-added"], [1, "collection-item", 3, "click"], [1, "collection-checkbox"], ["type", "checkbox", 3, "click", "checked", "disabled"], [1, "fas", "fa-folder", "collection-icon"], [1, "collection-name"], [1, "already-added-badge"], ["title", "View sub-collections", 1, "drill-down-btn"], [1, "fas", "fa-check-circle"], ["title", "View sub-collections", 1, "drill-down-btn", 3, "click"], [1, "fas", "fa-chevron-right"], ["text", "Loading collections...", "size", "medium"], [1, "fas", "fa-exclamation-triangle"], [1, "btn-create-collection", 3, "click"], [1, "fas", "fa-plus"], ["type", "text", "placeholder", "Enter collection name", 1, "k-textbox", "create-input", 3, "ngModelChange", "keydown.enter", "ngModel"], [1, "create-actions"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click", "disabled"], [1, "fas", "fa-spinner", "fa-spin"], ["mjButton", "", "size", "sm", 3, "click"], [1, "fas", "fa-save"]], template: function ArtifactCollectionPickerModalComponent_Template(rf, ctx) { if (rf & 1) {
549
- i0.ɵɵconditionalCreate(0, ArtifactCollectionPickerModalComponent_Conditional_0_Template, 22, 13, "mj-dialog", 1);
979
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ArtifactCollectionPickerModalComponent, selectors: [["mj-artifact-collection-picker-modal"]], viewQuery: function ArtifactCollectionPickerModalComponent_Query(rf, ctx) { if (rf & 1) {
980
+ i0.ɵɵviewQuery(_c0, 5)(_c1, 5);
981
+ } if (rf & 2) {
982
+ let _t;
983
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.searchInputRef = _t.first);
984
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.newNameInputRef = _t.first);
985
+ } }, inputs: { isOpen: "isOpen", environmentId: "environmentId", currentUser: "currentUser", excludeCollectionIds: "excludeCollectionIds", artifactVersionId: "artifactVersionId", artifactName: "artifactName", artifactVersionNumber: "artifactVersionNumber" }, outputs: { completed: "completed", cancelled: "cancelled" }, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 1, vars: 1, consts: [["searchInput", ""], ["newNameInput", ""], ["Title", "Save to Collection", 3, "Visible", "Width", "MinWidth"], ["Title", "Save to Collection", 3, "Close", "Visible", "Width", "MinWidth"], [1, "picker-shell"], [1, "pane", "pane-left"], [1, "toolbar"], [1, "search"], [1, "fa-solid", "fa-magnifying-glass"], ["type", "text", "placeholder", "Search collections\u2026", 3, "ngModelChange", "ngModel", "disabled"], ["title", "Clear", 1, "search-clear"], [1, "chip-btn", 3, "click", "disabled"], [1, "fa-solid", "fa-user-pen"], [1, "fa-solid", "fa-clock"], [1, "tree-wrap"], [1, "state-block"], [1, "state-block", "error"], [1, "state-block", "muted"], ["role", "tree", 1, "tree"], [1, "pane", "pane-right"], [1, "preview-block"], [1, "block-label"], [1, "preview-card"], [1, "preview-thumb"], [1, "fa-solid", "fa-file-lines"], [1, "preview-meta"], [1, "preview-name", 3, "title"], [1, "badge", "neutral"], [1, "chips-block"], [1, "chips"], [1, "chips-empty"], [1, "footnote"], [1, "fa-solid", "fa-shield-halved"], ["mjButton", "", "variant", "primary"], ["title", "Clear", 1, "search-clear", 3, "click"], [1, "fa-solid", "fa-xmark"], ["text", "Loading collections\u2026", "size", "medium"], [1, "fa-solid", "fa-triangle-exclamation"], [1, "link-btn", 3, "click"], [1, "fa-solid", "fa-folder-open"], [1, "hint"], ["role", "treeitem", 1, "row", 3, "selected", "already", "padding-left"], [1, "row", "create-row"], [1, "row", "create-form-row"], ["role", "treeitem", 1, "row", 3, "click"], [1, "caret", 3, "click"], [1, "fa-solid", 3, "fa-chevron-down", "fa-chevron-right"], [1, "check"], [1, "fa-solid", "fa-check"], [1, "fa-solid", "fa-folder", "folder-icon"], [1, "row-title"], [1, "row-ancestry"], [1, "row-tag", "success"], [1, "fa-solid"], [1, "row", "create-row", 3, "click"], [1, "caret"], [1, "check", "dashed"], [1, "fa-solid", "fa-plus"], ["type", "text", "placeholder", "Collection name", 1, "create-input", 3, "ngModelChange", "keydown.enter", "keydown.escape", "ngModel", "disabled"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click", "disabled"], [1, "fa-solid", "fa-spinner", "fa-spin"], ["mjButton", "", "size", "sm", 3, "click", "disabled"], [1, "block-count"], [1, "chip", "result", 3, "success", "error", "saving"], [1, "chip", "result"], [1, "chip-status"], [1, "fa-solid", "fa-circle"], [1, "chip-body"], [1, "chip-name"], [1, "chip-error"], ["title", "Retry", 1, "chip-action"], ["title", "Retry", 1, "chip-action", 3, "click"], [1, "fa-solid", "fa-rotate-right"], [1, "chip"], ["title", "Remove", 1, "chip-action", 3, "click", "disabled"], [1, "fa-solid", "fa-hand-pointer"], ["mjButton", "", "variant", "primary", 3, "click"], ["mjButton", "", 3, "click"], ["mjButton", "", "variant", "primary", 3, "click", "disabled"], ["mjButton", "", 3, "click", "disabled"], [1, "fa-solid", "fa-bookmark"]], template: function ArtifactCollectionPickerModalComponent_Template(rf, ctx) { if (rf & 1) {
986
+ i0.ɵɵconditionalCreate(0, ArtifactCollectionPickerModalComponent_Conditional_0_Template, 45, 19, "mj-dialog", 2);
550
987
  } if (rf & 2) {
551
988
  i0.ɵɵconditional(ctx.isOpen ? 0 : -1);
552
989
  } }, dependencies: [FormsModule, i3.DefaultValueAccessor, i3.NgControlStatus, i3.NgModel, MJDialogComponent,
553
990
  MJDialogActionsComponent,
554
991
  MJButtonDirective,
555
- SharedGenericModule, i4.LoadingComponent], styles: [".picker-modal[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 20px 0;\n min-height: 400px;\n max-height: 600px;\n }\n\n .breadcrumb-nav[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow-x: auto;\n }\n\n .breadcrumb-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: var(--mj-brand-primary);\n cursor: pointer;\n white-space: nowrap;\n font-size: 14px;\n }\n\n .breadcrumb-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n }\n\n .breadcrumb-separator[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n font-size: 12px;\n }\n\n .search-bar[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n }\n\n .search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 12px;\n color: var(--mj-text-disabled);\n pointer-events: none;\n }\n\n .search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding-left: 36px;\n }\n\n .collections-list[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n min-height: 250px;\n max-height: 350px;\n }\n\n .collection-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n transition: background 0.2s;\n }\n\n .collection-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n }\n\n .collection-item[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n }\n\n .collection-item.already-added[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n opacity: 0.7;\n cursor: not-allowed;\n }\n\n .collection-item.already-added[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n }\n\n .collection-checkbox[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n }\n\n .collection-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n width: 18px;\n height: 18px;\n cursor: pointer;\n }\n\n .collection-icon[_ngcontent-%COMP%] {\n font-size: 18px;\n flex-shrink: 0;\n }\n\n .collection-name[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 14px;\n color: var(--mj-text-primary);\n }\n\n .already-added-badge[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 4px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n border-radius: 12px;\n color: var(--mj-brand-primary);\n font-size: 12px;\n font-weight: 500;\n white-space: nowrap;\n }\n\n .already-added-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-brand-primary);\n }\n\n .drill-down-btn[_ngcontent-%COMP%] {\n padding: 6px 10px;\n background: transparent;\n border: 1px solid var(--mj-border-strong);\n border-radius: 4px;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .drill-down-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-text-disabled);\n color: var(--mj-text-secondary);\n }\n\n .empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 24px;\n color: var(--mj-text-muted);\n text-align: center;\n }\n\n .empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.4;\n }\n\n .empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 4px 0;\n font-size: 14px;\n }\n\n .empty-state[_ngcontent-%COMP%] .hint[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-disabled);\n }\n\n .loading-state[_ngcontent-%COMP%], .error-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 24px;\n gap: 12px;\n color: var(--mj-text-muted);\n }\n\n .error-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n }\n\n .error-state[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n }\n\n .selected-summary[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n border-radius: 6px;\n color: var(--mj-brand-primary);\n font-size: 14px;\n font-weight: 500;\n }\n\n .selected-summary[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n }\n\n .create-section[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .divider[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n text-align: center;\n color: var(--mj-text-disabled);\n font-size: 12px;\n font-weight: 500;\n }\n\n .divider[_ngcontent-%COMP%]::before, \n .divider[_ngcontent-%COMP%]::after {\n content: '';\n flex: 1;\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .divider[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n padding: 0 12px;\n }\n\n .btn-create-collection[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 10px 16px;\n background: var(--mj-bg-surface-sunken);\n border: 2px dashed var(--mj-border-strong);\n border-radius: 6px;\n color: var(--mj-brand-primary);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .btn-create-collection[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-brand-primary);\n }\n\n .btn-create-collection[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n }\n\n .create-form[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n }\n\n .create-input[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .create-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n }\n\n .btn-create[_ngcontent-%COMP%], .btn-cancel[_ngcontent-%COMP%] {\n padding: 8px 16px;\n font-size: 14px;\n }"] });
992
+ SharedGenericModule, i4.LoadingComponent], styles: ["\n\n .picker-shell[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr 300px;\n min-height: 460px;\n max-height: 70vh;\n gap: 0;\n margin: -8px -4px 0;\n }\n .pane[_ngcontent-%COMP%] { display:flex; flex-direction:column; min-height: 0; }\n .pane-left[_ngcontent-%COMP%] { border-right: 1px solid var(--mj-border-subtle); }\n .pane-right[_ngcontent-%COMP%] { background: var(--mj-bg-surface-card); }\n\n \n\n .toolbar[_ngcontent-%COMP%] {\n display:flex; gap: 8px; padding: 10px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n flex-wrap: wrap;\n }\n .search[_ngcontent-%COMP%] {\n flex: 1; min-width: 200px;\n display:flex; align-items:center; gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid transparent;\n border-radius: 8px;\n transition: all .15s ease;\n }\n .search[_ngcontent-%COMP%]:focus-within {\n background: var(--mj-bg-surface);\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n }\n .search[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { color: var(--mj-text-muted); font-size: 13px; }\n .search[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n flex: 1; border: 0; outline: 0; background: transparent;\n font-size: 13.5px; color: var(--mj-text-primary);\n min-width: 0;\n }\n .search[_ngcontent-%COMP%] input[_ngcontent-%COMP%]::placeholder { color: var(--mj-text-disabled); }\n .search-clear[_ngcontent-%COMP%] {\n background: transparent; border: 0; cursor: pointer;\n color: var(--mj-text-muted); padding: 2px 4px; border-radius: 4px;\n }\n .search-clear[_ngcontent-%COMP%]:hover { color: var(--mj-text-primary); background: var(--mj-bg-surface-hover); }\n\n .chip-btn[_ngcontent-%COMP%] {\n display:inline-flex; align-items:center; gap: 6px;\n padding: 7px 11px; border-radius: 8px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n color: var(--mj-text-secondary);\n font-size: 12.5px; font-weight: 600; cursor: pointer;\n transition: all .15s ease;\n }\n .chip-btn[_ngcontent-%COMP%]:hover:not(:disabled) { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); }\n .chip-btn.active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n }\n .chip-btn[_ngcontent-%COMP%]:disabled { opacity: .55; cursor: not-allowed; }\n\n \n\n .tree-wrap[_ngcontent-%COMP%] { flex: 1; overflow-y: auto; padding: 8px 8px 16px; }\n .tree[_ngcontent-%COMP%] { display:flex; flex-direction: column; gap: 1px; }\n .row[_ngcontent-%COMP%] {\n display:flex; align-items:center; gap: 10px;\n padding: 7px 12px; border-radius: 8px; cursor: pointer;\n user-select: none;\n border: 1px solid transparent;\n background: transparent;\n text-align: left;\n transition: background .12s ease;\n min-height: 36px;\n }\n .row[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-hover); }\n .row.selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 9%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n }\n .row.already[_ngcontent-%COMP%] { cursor: default; }\n .row.already[_ngcontent-%COMP%]:hover { background: transparent; }\n .row.already[_ngcontent-%COMP%] .row-title[_ngcontent-%COMP%] { color: var(--mj-text-secondary); }\n\n .caret[_ngcontent-%COMP%] {\n width: 16px; flex-shrink: 0; text-align: center;\n color: var(--mj-text-muted); font-size: 10px;\n cursor: pointer;\n }\n .caret[_ngcontent-%COMP%]:hover { color: var(--mj-text-primary); }\n\n .check[_ngcontent-%COMP%] {\n width: 18px; height: 18px; border-radius: 5px;\n border: 1.5px solid var(--mj-border-strong);\n background: var(--mj-bg-surface);\n display:flex; align-items:center; justify-content:center;\n color: transparent; font-size: 10px; flex-shrink: 0;\n transition: all .12s ease;\n }\n .check.checked[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: #fff;\n }\n .check.locked[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n color: #fff;\n }\n .check.dashed[_ngcontent-%COMP%] {\n border-style: dashed;\n color: var(--mj-text-muted);\n }\n\n .folder-icon[_ngcontent-%COMP%] { font-size: 14px; flex-shrink: 0; }\n\n .row-title[_ngcontent-%COMP%] {\n flex: 1; font-size: 13.5px; font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .row-ancestry[_ngcontent-%COMP%] {\n font-weight: 500; color: var(--mj-text-muted); font-size: 12px;\n margin-left: 2px;\n }\n .row-tag[_ngcontent-%COMP%] {\n font-size: 11px; font-weight: 600; padding: 2px 8px;\n border-radius: 999px; flex-shrink: 0;\n }\n .row-tag.success[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid color-mix(in srgb, var(--mj-status-success) 35%, transparent);\n }\n\n .create-row[_ngcontent-%COMP%] {\n width: 100%;\n border: 1.5px dashed var(--mj-border-strong);\n color: var(--mj-text-secondary);\n margin-top: 8px;\n background: transparent;\n }\n .create-row[_ngcontent-%COMP%] .row-title[_ngcontent-%COMP%] { color: var(--mj-text-secondary); font-weight: 600; }\n .create-row[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 4%, var(--mj-bg-surface));\n }\n .create-row[_ngcontent-%COMP%]:hover .row-title[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n\n .create-form-row[_ngcontent-%COMP%] {\n margin-top: 8px;\n border: 1.5px solid var(--mj-border-focus);\n background: var(--mj-bg-surface);\n cursor: default;\n gap: 8px;\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n }\n .create-input[_ngcontent-%COMP%] {\n flex: 1; min-width: 0;\n padding: 7px 10px;\n font-size: 13.5px; color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n border: 1.5px solid var(--mj-border-strong);\n border-radius: 6px;\n outline: 0;\n transition: all .12s ease;\n }\n .create-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n }\n .create-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n }\n\n \n\n .state-block[_ngcontent-%COMP%] {\n display:flex; flex-direction:column; align-items:center; justify-content:center;\n padding: 48px 24px; gap: 8px; color: var(--mj-text-muted);\n text-align: center;\n }\n .state-block[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 28px; opacity: .6; }\n .state-block.error[_ngcontent-%COMP%] { color: var(--mj-status-error-text); }\n .state-block[_ngcontent-%COMP%] .hint[_ngcontent-%COMP%] { font-size: 12.5px; color: var(--mj-text-disabled); margin: 0; }\n .state-block[_ngcontent-%COMP%] .link-btn[_ngcontent-%COMP%] {\n background: transparent; border: 0; color: var(--mj-text-link);\n font-weight: 600; cursor: pointer; font-size: 13px; padding: 6px 12px;\n }\n .state-block[_ngcontent-%COMP%] .link-btn[_ngcontent-%COMP%]:hover { color: var(--mj-text-link-hover); text-decoration: underline; }\n .state-block[_ngcontent-%COMP%] p[_ngcontent-%COMP%] { margin: 0; font-size: 13.5px; }\n\n \n\n .preview-block[_ngcontent-%COMP%] { padding: 16px 18px; border-bottom: 1px solid var(--mj-border-subtle); }\n .block-label[_ngcontent-%COMP%] {\n font-size: 11px; text-transform: uppercase; letter-spacing: .08em;\n font-weight: 700; color: var(--mj-text-muted); margin-bottom: 8px;\n display:flex; justify-content:space-between; align-items:center;\n }\n .block-count[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary); font-size: 12px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n padding: 2px 8px; border-radius: 999px;\n }\n .preview-card[_ngcontent-%COMP%] {\n display:flex; gap: 12px; align-items:center;\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default);\n border-radius: 10px; padding: 12px;\n box-shadow: 0 1px 2px rgba(15,23,42,.04);\n }\n .preview-thumb[_ngcontent-%COMP%] {\n width: 38px; height: 38px; border-radius: 9px; flex-shrink: 0;\n background: linear-gradient(135deg, var(--mj-color-accent-400), var(--mj-brand-primary));\n color: #fff; display:flex; align-items:center; justify-content:center;\n font-size: 14px;\n }\n .preview-meta[_ngcontent-%COMP%] { flex: 1; min-width: 0; display:flex; flex-direction: column; gap: 4px; }\n .preview-name[_ngcontent-%COMP%] {\n font-weight: 700; font-size: 13.5px; color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .badge[_ngcontent-%COMP%] {\n display:inline-flex; align-items:center; gap: 4px;\n padding: 2px 8px; border-radius: 999px; font-size: 11px; font-weight: 600;\n width: fit-content;\n }\n .badge.neutral[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n }\n\n .chips-block[_ngcontent-%COMP%] { flex: 1; min-height: 0; display:flex; flex-direction: column;\n padding: 16px 18px 8px; overflow-y: auto; }\n .chips[_ngcontent-%COMP%] { display:flex; flex-direction: column; gap: 6px; }\n .chip[_ngcontent-%COMP%] {\n display:flex; align-items:center; gap: 10px; padding: 8px 10px;\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n }\n .chip-body[_ngcontent-%COMP%] { flex: 1; min-width: 0; }\n .chip-name[_ngcontent-%COMP%] {\n font-weight: 600; font-size: 13px; color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .chip-error[_ngcontent-%COMP%] {\n font-size: 11.5px; color: var(--mj-status-error-text); margin-top: 2px;\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .chip-action[_ngcontent-%COMP%] {\n width: 24px; height: 24px; border-radius: 6px;\n background: transparent; border: 0; cursor: pointer;\n color: var(--mj-text-muted); font-size: 11px;\n display:flex; align-items:center; justify-content:center;\n }\n .chip-action[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover); color: var(--mj-text-primary);\n }\n .chip-action[_ngcontent-%COMP%]:disabled { opacity: .4; cursor: not-allowed; }\n .chip-status[_ngcontent-%COMP%] {\n width: 20px; flex-shrink: 0; text-align: center; font-size: 12px;\n }\n .chip.result.success[_ngcontent-%COMP%] { border-color: color-mix(in srgb, var(--mj-status-success) 35%, transparent);\n background: var(--mj-status-success-bg); }\n .chip.result.success[_ngcontent-%COMP%] .chip-status[_ngcontent-%COMP%] { color: var(--mj-status-success-text); }\n .chip.result.error[_ngcontent-%COMP%] { border-color: color-mix(in srgb, var(--mj-status-error) 35%, transparent);\n background: var(--mj-status-error-bg); }\n .chip.result.error[_ngcontent-%COMP%] .chip-status[_ngcontent-%COMP%] { color: var(--mj-status-error-text); }\n .chip.result.saving[_ngcontent-%COMP%] .chip-status[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n\n .chips-empty[_ngcontent-%COMP%] {\n flex: 1; display:flex; flex-direction: column; align-items: center; justify-content: center;\n padding: 32px 16px; text-align: center; color: var(--mj-text-muted);\n border: 1.5px dashed var(--mj-border-default); border-radius: 10px;\n }\n .chips-empty[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 22px; margin-bottom: 8px; opacity: .55; }\n .chips-empty[_ngcontent-%COMP%] p[_ngcontent-%COMP%] { margin: 0; font-size: 12.5px; }\n\n .footnote[_ngcontent-%COMP%] {\n padding: 12px 18px;\n font-size: 11.5px; color: var(--mj-text-muted);\n display:flex; align-items:center; gap: 6px;\n border-top: 1px solid var(--mj-border-subtle);\n }\n .footnote[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 11px; }\n\n \n\n [_nghost-%COMP%] mj-dialog .k-window-content, \n [_nghost-%COMP%] mj-dialog .mj-dialog-content {\n padding: 0 !important;\n }"] });
556
993
  }
557
994
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ArtifactCollectionPickerModalComponent, [{
558
995
  type: Component,
@@ -568,156 +1005,255 @@ export class ArtifactCollectionPickerModalComponent extends BaseAngularComponent
568
1005
  Title="Save to Collection"
569
1006
  (Close)="onCancel()"
570
1007
  [Visible]="true"
571
- [Width]="700"
572
- [MinWidth]="500">
573
- <div class="picker-modal">
574
- <!-- Breadcrumb Navigation -->
575
- @if (navigationPath.length > 0) {
576
- <div class="breadcrumb-nav">
577
- <button class="breadcrumb-btn" (click)="navigateToRoot()">
578
- <i class="fas fa-home"></i> Root
1008
+ [Width]="960"
1009
+ [MinWidth]="720">
1010
+ <div class="picker-shell">
1011
+ <!-- ============================================================ -->
1012
+ <!-- LEFT PANE · search + tree -->
1013
+ <!-- ============================================================ -->
1014
+ <div class="pane pane-left">
1015
+ <div class="toolbar">
1016
+ <div class="search">
1017
+ <i class="fa-solid fa-magnifying-glass"></i>
1018
+ <input
1019
+ #searchInput
1020
+ type="text"
1021
+ [(ngModel)]="searchQuery"
1022
+ (ngModelChange)="onSearchChange()"
1023
+ placeholder="Search collections…"
1024
+ [disabled]="isLoading || isSaving" />
1025
+ @if (searchQuery) {
1026
+ <button class="search-clear" (click)="clearSearch()" title="Clear">
1027
+ <i class="fa-solid fa-xmark"></i>
1028
+ </button>
1029
+ }
1030
+ </div>
1031
+ <button class="chip-btn"
1032
+ [class.active]="filterMode === 'editable'"
1033
+ (click)="setFilter('editable')"
1034
+ [disabled]="isSaving">
1035
+ <i class="fa-solid fa-user-pen"></i> Editable
1036
+ </button>
1037
+ <button class="chip-btn"
1038
+ [class.active]="filterMode === 'recent'"
1039
+ (click)="setFilter('recent')"
1040
+ [disabled]="isSaving">
1041
+ <i class="fa-solid fa-clock"></i> Recent
579
1042
  </button>
580
- @for (item of navigationPath; track item.collection.ID) {
581
- <i class="fas fa-chevron-right breadcrumb-separator"></i>
582
- <button class="breadcrumb-btn" (click)="navigateToCollection(item.collection)">
583
- {{ item.collection.Name }}
584
- </button>
585
- }
586
1043
  </div>
587
- }
588
- <!-- Search Bar -->
589
- <div class="search-bar">
590
- <i class="fas fa-search search-icon"></i>
591
- <input
592
- type="text"
593
- class="k-textbox search-input"
594
- [(ngModel)]="searchQuery"
595
- (input)="onSearchChange()"
596
- placeholder="Search collections..."
597
- [disabled]="isLoading">
598
- </div>
599
- <!-- Collections List -->
600
- @if (!isLoading && !errorMessage) {
601
- <div class="collections-list">
602
- @if (displayedCollections.length === 0) {
603
- <div class="empty-state">
1044
+
1045
+ <div class="tree-wrap">
1046
+ @if (isLoading) {
1047
+ <div class="state-block">
1048
+ <mj-loading text="Loading collections…" size="medium"></mj-loading>
1049
+ </div>
1050
+ } @else if (errorMessage) {
1051
+ <div class="state-block error">
1052
+ <i class="fa-solid fa-triangle-exclamation"></i>
1053
+ <span>{{ errorMessage }}</span>
1054
+ </div>
1055
+ } @else if (visibleNodes.length === 0) {
1056
+ <div class="state-block muted">
604
1057
  @if (searchQuery) {
605
- <i class="fas fa-search"></i>
606
- <p>No collections found matching "{{ searchQuery }}"</p>
607
- } @else if (currentParentId) {
608
- <i class="fas fa-folder-open"></i>
609
- <p>No sub-collections available</p>
1058
+ <i class="fa-solid fa-magnifying-glass"></i>
1059
+ <p>No collections match &ldquo;{{ searchQuery }}&rdquo;</p>
1060
+ <button class="link-btn" (click)="clearSearch()">Clear search</button>
610
1061
  } @else {
611
- <i class="fas fa-folder"></i>
612
- <p>No collections available</p>
613
- <p class="hint">Create a new collection to get started</p>
1062
+ <i class="fa-solid fa-folder-open"></i>
1063
+ <p>No editable collections yet</p>
1064
+ <p class="hint">Create one to get started</p>
614
1065
  }
615
1066
  </div>
616
1067
  } @else {
617
- @for (node of displayedCollections; track node.collection.ID) {
618
- <div class="collection-item"
619
- [class.already-added]="node.alreadyContainsArtifact"
620
- (click)="toggleSelection(node)">
621
- <div class="collection-checkbox">
622
- <input
623
- type="checkbox"
624
- [checked]="node.selected"
625
- [disabled]="node.alreadyContainsArtifact"
626
- (click)="$event.stopPropagation(); toggleSelection(node)">
627
- </div>
628
- <i class="fas fa-folder collection-icon" [style.color]="node.collection.Color || 'var(--mj-brand-primary)'"></i>
629
- <span class="collection-name">{{ node.collection.Name }}</span>
630
- @if (node.alreadyContainsArtifact) {
631
- <span class="already-added-badge">
632
- <i class="fas fa-check-circle"></i> Already added
1068
+ <div class="tree" role="tree">
1069
+ @for (node of visibleNodes; track node.collection.ID) {
1070
+ <div class="row"
1071
+ role="treeitem"
1072
+ [class.selected]="isSelected(node.collection.ID)"
1073
+ [class.already]="node.alreadyContainsArtifact"
1074
+ [style.padding-left.px]="searchQuery ? 12 : 12 + node.depth * 18"
1075
+ (click)="onRowClick(node)">
1076
+ <span class="caret" (click)="$event.stopPropagation(); toggleExpand(node)">
1077
+ @if (node.hasChildren && !searchQuery) {
1078
+ <i class="fa-solid" [class.fa-chevron-down]="node.expanded" [class.fa-chevron-right]="!node.expanded"></i>
1079
+ }
1080
+ </span>
1081
+ <span class="check"
1082
+ [class.checked]="isSelected(node.collection.ID)"
1083
+ [class.locked]="node.alreadyContainsArtifact"
1084
+ [attr.aria-label]="node.alreadyContainsArtifact ? 'Already saved' : 'Toggle selection'">
1085
+ @if (isSelected(node.collection.ID) || node.alreadyContainsArtifact) {
1086
+ <i class="fa-solid fa-check"></i>
1087
+ }
1088
+ </span>
1089
+ <i class="fa-solid fa-folder folder-icon"
1090
+ [style.color]="node.collection.Color || 'var(--mj-brand-primary)'"></i>
1091
+ <span class="row-title">
1092
+ {{ node.collection.Name }}
1093
+ @if (searchQuery && node.ancestry) {
1094
+ <span class="row-ancestry">· {{ node.ancestry }}</span>
1095
+ }
633
1096
  </span>
634
- }
635
- @if (node.hasChildren) {
636
- <button
637
- class="drill-down-btn"
638
- (click)="$event.stopPropagation(); drillIntoCollection(node.collection)"
639
- title="View sub-collections">
640
- <i class="fas fa-chevron-right"></i>
1097
+ @if (node.alreadyContainsArtifact) {
1098
+ <span class="row-tag success">Already saved</span>
1099
+ }
1100
+ </div>
1101
+ }
1102
+
1103
+ <!-- Inline "create new" row -->
1104
+ @if (!isSaving && !searchQuery && !showCreateForm) {
1105
+ <button class="row create-row" (click)="openCreateForm()">
1106
+ <span class="caret"></span>
1107
+ <span class="check dashed"><i class="fa-solid fa-plus"></i></span>
1108
+ <span class="row-title">Create new collection…</span>
1109
+ </button>
1110
+ } @else if (showCreateForm) {
1111
+ <div class="row create-form-row">
1112
+ <span class="caret"></span>
1113
+ <span class="check dashed"><i class="fa-solid fa-plus"></i></span>
1114
+ <input #newNameInput type="text"
1115
+ class="create-input"
1116
+ [(ngModel)]="newCollectionName"
1117
+ (keydown.enter)="createCollection()"
1118
+ (keydown.escape)="cancelCreate()"
1119
+ placeholder="Collection name"
1120
+ [disabled]="isCreatingCollection" />
1121
+ <button mjButton variant="primary" size="sm"
1122
+ (click)="createCollection()"
1123
+ [disabled]="isCreatingCollection || !newCollectionName.trim()">
1124
+ @if (isCreatingCollection) {
1125
+ <i class="fa-solid fa-spinner fa-spin"></i>
1126
+ } @else {
1127
+ Create
1128
+ }
641
1129
  </button>
642
- }
643
- </div>
644
- }
1130
+ <button mjButton size="sm" (click)="cancelCreate()" [disabled]="isCreatingCollection">
1131
+ Cancel
1132
+ </button>
1133
+ </div>
1134
+ }
1135
+ </div>
645
1136
  }
646
1137
  </div>
647
- }
648
- <!-- Loading State -->
649
- @if (isLoading) {
650
- <div class="loading-state">
651
- <mj-loading text="Loading collections..." size="medium"></mj-loading>
652
- </div>
653
- }
654
- <!-- Error State -->
655
- @if (errorMessage) {
656
- <div class="error-state">
657
- <i class="fas fa-exclamation-triangle"></i>
658
- <span>{{ errorMessage }}</span>
1138
+ </div>
1139
+
1140
+ <!-- ============================================================ -->
1141
+ <!-- RIGHT PANE · preview + chips / results -->
1142
+ <!-- ============================================================ -->
1143
+ <div class="pane pane-right">
1144
+ <div class="preview-block">
1145
+ <div class="block-label">Saving</div>
1146
+ <div class="preview-card">
1147
+ <div class="preview-thumb"><i class="fa-solid fa-file-lines"></i></div>
1148
+ <div class="preview-meta">
1149
+ <div class="preview-name" [title]="artifactName">{{ artifactName || 'Artifact' }}</div>
1150
+ @if (artifactVersionNumber != null) {
1151
+ <span class="badge neutral">v{{ artifactVersionNumber }}</span>
1152
+ }
1153
+ </div>
1154
+ </div>
659
1155
  </div>
660
- }
661
- <!-- Selected Collections Summary -->
662
- @if (selectedCollections.length > 0) {
663
- <div class="selected-summary">
664
- <i class="fas fa-check-circle"></i>
665
- <span>{{ selectedCollections.length }} collection(s) selected</span>
1156
+
1157
+ <div class="chips-block">
1158
+ <div class="block-label">
1159
+ @if (saveResults.size > 0) {
1160
+ <span>Results</span>
1161
+ <span class="block-count">{{ successCount }} / {{ saveResults.size }}</span>
1162
+ } @else {
1163
+ <span>Selected</span>
1164
+ <span class="block-count">{{ selectedIds.size }}</span>
1165
+ }
1166
+ </div>
1167
+
1168
+ @if (saveResults.size > 0) {
1169
+ <!-- Per-collection results -->
1170
+ <div class="chips">
1171
+ @for (r of resultsList; track r.collectionId) {
1172
+ <div class="chip result" [class.success]="r.status === 'success'"
1173
+ [class.error]="r.status === 'error'"
1174
+ [class.saving]="r.status === 'saving'">
1175
+ <span class="chip-status">
1176
+ @switch (r.status) {
1177
+ @case ('saving') { <i class="fa-solid fa-spinner fa-spin"></i> }
1178
+ @case ('success') { <i class="fa-solid fa-check"></i> }
1179
+ @case ('error') { <i class="fa-solid fa-triangle-exclamation"></i> }
1180
+ @default { <i class="fa-solid fa-circle"></i> }
1181
+ }
1182
+ </span>
1183
+ <div class="chip-body">
1184
+ <div class="chip-name">{{ r.collectionName }}</div>
1185
+ @if (r.status === 'error' && r.errorMessage) {
1186
+ <div class="chip-error">{{ r.errorMessage }}</div>
1187
+ }
1188
+ </div>
1189
+ @if (r.status === 'error') {
1190
+ <button class="chip-action" (click)="retryOne(r.collectionId)" title="Retry">
1191
+ <i class="fa-solid fa-rotate-right"></i>
1192
+ </button>
1193
+ }
1194
+ </div>
1195
+ }
1196
+ </div>
1197
+ } @else if (selectedIds.size > 0) {
1198
+ <div class="chips">
1199
+ @for (c of selectedCollections; track c.ID) {
1200
+ <div class="chip">
1201
+ <i class="fa-solid fa-folder folder-icon" [style.color]="c.Color || 'var(--mj-brand-primary)'"></i>
1202
+ <div class="chip-body">
1203
+ <div class="chip-name">{{ c.Name }}</div>
1204
+ </div>
1205
+ <button class="chip-action" (click)="deselect(c.ID)"
1206
+ [disabled]="isSaving"
1207
+ title="Remove">
1208
+ <i class="fa-solid fa-xmark"></i>
1209
+ </button>
1210
+ </div>
1211
+ }
1212
+ </div>
1213
+ } @else {
1214
+ <div class="chips-empty">
1215
+ <i class="fa-solid fa-hand-pointer"></i>
1216
+ <p>Pick a collection on the left</p>
1217
+ </div>
1218
+ }
666
1219
  </div>
667
- }
668
- <!-- Create New Collection Section -->
669
- <div class="create-section">
670
- <div class="divider">
671
- <span>OR CREATE NEW</span>
1220
+
1221
+ <div class="footnote">
1222
+ <i class="fa-solid fa-shield-halved"></i>
1223
+ Only collections you can edit are shown
672
1224
  </div>
673
- @if (!showCreateForm) {
674
- <button class="btn-create-collection" (click)="showCreateForm = true">
675
- <i class="fas fa-plus"></i>
676
- Create New Collection
677
- </button>
678
- } @else {
679
- <div class="create-form">
680
- <input
681
- type="text"
682
- class="k-textbox create-input"
683
- [(ngModel)]="newCollectionName"
684
- placeholder="Enter collection name"
685
- (keydown.enter)="createCollection()"
686
- #newCollectionInput>
687
- <div class="create-actions">
688
- <button mjButton variant="primary" size="sm" (click)="createCollection()" [disabled]="isCreatingCollection || !newCollectionName.trim()">
689
- @if (isCreatingCollection) {
690
- <i class="fas fa-spinner fa-spin"></i>
691
- } @else {
692
- Create
693
- }
694
- </button>
695
- <button mjButton size="sm" (click)="showCreateForm = false; newCollectionName = ''">
696
- Cancel
697
- </button>
698
- </div>
699
- </div>
700
- }
701
1225
  </div>
702
1226
  </div>
1227
+
703
1228
  <mj-dialog-actions>
704
- <button mjButton (click)="onCancel()">
705
- Cancel
706
- </button>
707
- <button mjButton
708
- variant="primary"
709
- (click)="onSave()"
710
- [disabled]="selectedCollections.length === 0 || isSaving">
711
- @if (isSaving) {
712
- <i class="fas fa-spinner fa-spin"></i> Saving...
713
- } @else {
714
- <i class="fas fa-save"></i> Save to {{ selectedCollections.length }} Collection(s)
715
- }
716
- </button>
1229
+ <!-- Primary on the LEFT per MJ convention -->
1230
+ @if (failedCount > 0 && !isSaving) {
1231
+ <button mjButton variant="primary" (click)="retryFailed()">
1232
+ <i class="fa-solid fa-rotate-right"></i> Retry {{ failedCount }} failed
1233
+ </button>
1234
+ <button mjButton (click)="onAcknowledgeAndClose()">Done</button>
1235
+ } @else if (saveResults.size > 0 && successCount === saveResults.size && !isSaving) {
1236
+ <!-- All succeeded — auto-closes, but render fallback button just in case -->
1237
+ <button mjButton variant="primary" (click)="onAcknowledgeAndClose()">
1238
+ <i class="fa-solid fa-check"></i> Done
1239
+ </button>
1240
+ } @else {
1241
+ <button mjButton variant="primary"
1242
+ (click)="onSave()"
1243
+ [disabled]="selectedIds.size === 0 || isSaving">
1244
+ @if (isSaving) {
1245
+ <i class="fa-solid fa-spinner fa-spin"></i> Saving to {{ selectedIds.size }}…
1246
+ } @else {
1247
+ <i class="fa-solid fa-bookmark"></i>
1248
+ Save to {{ selectedIds.size }} {{ selectedIds.size === 1 ? 'collection' : 'collections' }}
1249
+ }
1250
+ </button>
1251
+ <button mjButton (click)="onCancel()" [disabled]="isSaving">Cancel</button>
1252
+ }
717
1253
  </mj-dialog-actions>
718
1254
  </mj-dialog>
719
1255
  }
720
- `, styles: ["\n .picker-modal {\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 20px 0;\n min-height: 400px;\n max-height: 600px;\n }\n\n .breadcrumb-nav {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow-x: auto;\n }\n\n .breadcrumb-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: var(--mj-brand-primary);\n cursor: pointer;\n white-space: nowrap;\n font-size: 14px;\n }\n\n .breadcrumb-btn:hover {\n background: var(--mj-border-default);\n }\n\n .breadcrumb-separator {\n color: var(--mj-text-disabled);\n font-size: 12px;\n }\n\n .search-bar {\n position: relative;\n display: flex;\n align-items: center;\n }\n\n .search-icon {\n position: absolute;\n left: 12px;\n color: var(--mj-text-disabled);\n pointer-events: none;\n }\n\n .search-input {\n width: 100%;\n padding-left: 36px;\n }\n\n .collections-list {\n flex: 1;\n overflow-y: auto;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n min-height: 250px;\n max-height: 350px;\n }\n\n .collection-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n transition: background 0.2s;\n }\n\n .collection-item:hover {\n background: var(--mj-bg-surface-sunken);\n }\n\n .collection-item:last-child {\n border-bottom: none;\n }\n\n .collection-item.already-added {\n background: var(--mj-bg-surface-sunken);\n opacity: 0.7;\n cursor: not-allowed;\n }\n\n .collection-item.already-added:hover {\n background: var(--mj-bg-surface-sunken);\n }\n\n .collection-checkbox {\n display: flex;\n align-items: center;\n }\n\n .collection-checkbox input[type=\"checkbox\"] {\n width: 18px;\n height: 18px;\n cursor: pointer;\n }\n\n .collection-icon {\n font-size: 18px;\n flex-shrink: 0;\n }\n\n .collection-name {\n flex: 1;\n font-size: 14px;\n color: var(--mj-text-primary);\n }\n\n .already-added-badge {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 4px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n border-radius: 12px;\n color: var(--mj-brand-primary);\n font-size: 12px;\n font-weight: 500;\n white-space: nowrap;\n }\n\n .already-added-badge i {\n font-size: 12px;\n color: var(--mj-brand-primary);\n }\n\n .drill-down-btn {\n padding: 6px 10px;\n background: transparent;\n border: 1px solid var(--mj-border-strong);\n border-radius: 4px;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .drill-down-btn:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-text-disabled);\n color: var(--mj-text-secondary);\n }\n\n .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 24px;\n color: var(--mj-text-muted);\n text-align: center;\n }\n\n .empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.4;\n }\n\n .empty-state p {\n margin: 4px 0;\n font-size: 14px;\n }\n\n .empty-state .hint {\n font-size: 13px;\n color: var(--mj-text-disabled);\n }\n\n .loading-state, .error-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 24px;\n gap: 12px;\n color: var(--mj-text-muted);\n }\n\n .error-state i {\n font-size: 32px;\n }\n\n .error-state {\n color: var(--mj-status-error);\n }\n\n .selected-summary {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n border-radius: 6px;\n color: var(--mj-brand-primary);\n font-size: 14px;\n font-weight: 500;\n }\n\n .selected-summary i {\n color: var(--mj-brand-primary);\n }\n\n .create-section {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .divider {\n display: flex;\n align-items: center;\n text-align: center;\n color: var(--mj-text-disabled);\n font-size: 12px;\n font-weight: 500;\n }\n\n .divider::before,\n .divider::after {\n content: '';\n flex: 1;\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .divider span {\n padding: 0 12px;\n }\n\n .btn-create-collection {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 10px 16px;\n background: var(--mj-bg-surface-sunken);\n border: 2px dashed var(--mj-border-strong);\n border-radius: 6px;\n color: var(--mj-brand-primary);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .btn-create-collection:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-brand-primary);\n }\n\n .btn-create-collection i {\n font-size: 16px;\n }\n\n .create-form {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n }\n\n .create-input {\n width: 100%;\n }\n\n .create-actions {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n }\n\n .btn-create, .btn-cancel {\n padding: 8px 16px;\n font-size: 14px;\n }\n "] }]
1256
+ `, styles: ["\n /* ===== Shell ===== */\n .picker-shell {\n display: grid;\n grid-template-columns: 1fr 300px;\n min-height: 460px;\n max-height: 70vh;\n gap: 0;\n margin: -8px -4px 0;\n }\n .pane { display:flex; flex-direction:column; min-height: 0; }\n .pane-left { border-right: 1px solid var(--mj-border-subtle); }\n .pane-right { background: var(--mj-bg-surface-card); }\n\n /* ===== Toolbar / search / chip filters ===== */\n .toolbar {\n display:flex; gap: 8px; padding: 10px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n flex-wrap: wrap;\n }\n .search {\n flex: 1; min-width: 200px;\n display:flex; align-items:center; gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid transparent;\n border-radius: 8px;\n transition: all .15s ease;\n }\n .search:focus-within {\n background: var(--mj-bg-surface);\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n }\n .search i { color: var(--mj-text-muted); font-size: 13px; }\n .search input {\n flex: 1; border: 0; outline: 0; background: transparent;\n font-size: 13.5px; color: var(--mj-text-primary);\n min-width: 0;\n }\n .search input::placeholder { color: var(--mj-text-disabled); }\n .search-clear {\n background: transparent; border: 0; cursor: pointer;\n color: var(--mj-text-muted); padding: 2px 4px; border-radius: 4px;\n }\n .search-clear:hover { color: var(--mj-text-primary); background: var(--mj-bg-surface-hover); }\n\n .chip-btn {\n display:inline-flex; align-items:center; gap: 6px;\n padding: 7px 11px; border-radius: 8px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n color: var(--mj-text-secondary);\n font-size: 12.5px; font-weight: 600; cursor: pointer;\n transition: all .15s ease;\n }\n .chip-btn:hover:not(:disabled) { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); }\n .chip-btn.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n }\n .chip-btn:disabled { opacity: .55; cursor: not-allowed; }\n\n /* ===== Tree ===== */\n .tree-wrap { flex: 1; overflow-y: auto; padding: 8px 8px 16px; }\n .tree { display:flex; flex-direction: column; gap: 1px; }\n .row {\n display:flex; align-items:center; gap: 10px;\n padding: 7px 12px; border-radius: 8px; cursor: pointer;\n user-select: none;\n border: 1px solid transparent;\n background: transparent;\n text-align: left;\n transition: background .12s ease;\n min-height: 36px;\n }\n .row:hover { background: var(--mj-bg-surface-hover); }\n .row.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 9%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n }\n .row.already { cursor: default; }\n .row.already:hover { background: transparent; }\n .row.already .row-title { color: var(--mj-text-secondary); }\n\n .caret {\n width: 16px; flex-shrink: 0; text-align: center;\n color: var(--mj-text-muted); font-size: 10px;\n cursor: pointer;\n }\n .caret:hover { color: var(--mj-text-primary); }\n\n .check {\n width: 18px; height: 18px; border-radius: 5px;\n border: 1.5px solid var(--mj-border-strong);\n background: var(--mj-bg-surface);\n display:flex; align-items:center; justify-content:center;\n color: transparent; font-size: 10px; flex-shrink: 0;\n transition: all .12s ease;\n }\n .check.checked {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: #fff;\n }\n .check.locked {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n color: #fff;\n }\n .check.dashed {\n border-style: dashed;\n color: var(--mj-text-muted);\n }\n\n .folder-icon { font-size: 14px; flex-shrink: 0; }\n\n .row-title {\n flex: 1; font-size: 13.5px; font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .row-ancestry {\n font-weight: 500; color: var(--mj-text-muted); font-size: 12px;\n margin-left: 2px;\n }\n .row-tag {\n font-size: 11px; font-weight: 600; padding: 2px 8px;\n border-radius: 999px; flex-shrink: 0;\n }\n .row-tag.success {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid color-mix(in srgb, var(--mj-status-success) 35%, transparent);\n }\n\n .create-row {\n width: 100%;\n border: 1.5px dashed var(--mj-border-strong);\n color: var(--mj-text-secondary);\n margin-top: 8px;\n background: transparent;\n }\n .create-row .row-title { color: var(--mj-text-secondary); font-weight: 600; }\n .create-row:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 4%, var(--mj-bg-surface));\n }\n .create-row:hover .row-title { color: var(--mj-brand-primary); }\n\n .create-form-row {\n margin-top: 8px;\n border: 1.5px solid var(--mj-border-focus);\n background: var(--mj-bg-surface);\n cursor: default;\n gap: 8px;\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n }\n .create-input {\n flex: 1; min-width: 0;\n padding: 7px 10px;\n font-size: 13.5px; color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n border: 1.5px solid var(--mj-border-strong);\n border-radius: 6px;\n outline: 0;\n transition: all .12s ease;\n }\n .create-input::placeholder {\n color: var(--mj-text-muted);\n }\n .create-input:focus {\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n }\n\n /* ===== State blocks ===== */\n .state-block {\n display:flex; flex-direction:column; align-items:center; justify-content:center;\n padding: 48px 24px; gap: 8px; color: var(--mj-text-muted);\n text-align: center;\n }\n .state-block i { font-size: 28px; opacity: .6; }\n .state-block.error { color: var(--mj-status-error-text); }\n .state-block .hint { font-size: 12.5px; color: var(--mj-text-disabled); margin: 0; }\n .state-block .link-btn {\n background: transparent; border: 0; color: var(--mj-text-link);\n font-weight: 600; cursor: pointer; font-size: 13px; padding: 6px 12px;\n }\n .state-block .link-btn:hover { color: var(--mj-text-link-hover); text-decoration: underline; }\n .state-block p { margin: 0; font-size: 13.5px; }\n\n /* ===== Right pane ===== */\n .preview-block { padding: 16px 18px; border-bottom: 1px solid var(--mj-border-subtle); }\n .block-label {\n font-size: 11px; text-transform: uppercase; letter-spacing: .08em;\n font-weight: 700; color: var(--mj-text-muted); margin-bottom: 8px;\n display:flex; justify-content:space-between; align-items:center;\n }\n .block-count {\n color: var(--mj-brand-primary); font-size: 12px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n padding: 2px 8px; border-radius: 999px;\n }\n .preview-card {\n display:flex; gap: 12px; align-items:center;\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default);\n border-radius: 10px; padding: 12px;\n box-shadow: 0 1px 2px rgba(15,23,42,.04);\n }\n .preview-thumb {\n width: 38px; height: 38px; border-radius: 9px; flex-shrink: 0;\n background: linear-gradient(135deg, var(--mj-color-accent-400), var(--mj-brand-primary));\n color: #fff; display:flex; align-items:center; justify-content:center;\n font-size: 14px;\n }\n .preview-meta { flex: 1; min-width: 0; display:flex; flex-direction: column; gap: 4px; }\n .preview-name {\n font-weight: 700; font-size: 13.5px; color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .badge {\n display:inline-flex; align-items:center; gap: 4px;\n padding: 2px 8px; border-radius: 999px; font-size: 11px; font-weight: 600;\n width: fit-content;\n }\n .badge.neutral {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n }\n\n .chips-block { flex: 1; min-height: 0; display:flex; flex-direction: column;\n padding: 16px 18px 8px; overflow-y: auto; }\n .chips { display:flex; flex-direction: column; gap: 6px; }\n .chip {\n display:flex; align-items:center; gap: 10px; padding: 8px 10px;\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n }\n .chip-body { flex: 1; min-width: 0; }\n .chip-name {\n font-weight: 600; font-size: 13px; color: var(--mj-text-primary);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .chip-error {\n font-size: 11.5px; color: var(--mj-status-error-text); margin-top: 2px;\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n }\n .chip-action {\n width: 24px; height: 24px; border-radius: 6px;\n background: transparent; border: 0; cursor: pointer;\n color: var(--mj-text-muted); font-size: 11px;\n display:flex; align-items:center; justify-content:center;\n }\n .chip-action:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover); color: var(--mj-text-primary);\n }\n .chip-action:disabled { opacity: .4; cursor: not-allowed; }\n .chip-status {\n width: 20px; flex-shrink: 0; text-align: center; font-size: 12px;\n }\n .chip.result.success { border-color: color-mix(in srgb, var(--mj-status-success) 35%, transparent);\n background: var(--mj-status-success-bg); }\n .chip.result.success .chip-status { color: var(--mj-status-success-text); }\n .chip.result.error { border-color: color-mix(in srgb, var(--mj-status-error) 35%, transparent);\n background: var(--mj-status-error-bg); }\n .chip.result.error .chip-status { color: var(--mj-status-error-text); }\n .chip.result.saving .chip-status { color: var(--mj-brand-primary); }\n\n .chips-empty {\n flex: 1; display:flex; flex-direction: column; align-items: center; justify-content: center;\n padding: 32px 16px; text-align: center; color: var(--mj-text-muted);\n border: 1.5px dashed var(--mj-border-default); border-radius: 10px;\n }\n .chips-empty i { font-size: 22px; margin-bottom: 8px; opacity: .55; }\n .chips-empty p { margin: 0; font-size: 12.5px; }\n\n .footnote {\n padding: 12px 18px;\n font-size: 11.5px; color: var(--mj-text-muted);\n display:flex; align-items:center; gap: 6px;\n border-top: 1px solid var(--mj-border-subtle);\n }\n .footnote i { font-size: 11px; }\n\n /* Tighten dialog content padding so panes meet edges cleanly */\n :host ::ng-deep mj-dialog .k-window-content,\n :host ::ng-deep mj-dialog .mj-dialog-content {\n padding: 0 !important;\n }\n "] }]
721
1257
  }], () => [{ type: i1.ToastService }, { type: i2.CollectionPermissionService }, { type: i0.ChangeDetectorRef }], { isOpen: [{
722
1258
  type: Input
723
1259
  }], environmentId: [{
@@ -726,10 +1262,22 @@ export class ArtifactCollectionPickerModalComponent extends BaseAngularComponent
726
1262
  type: Input
727
1263
  }], excludeCollectionIds: [{
728
1264
  type: Input
729
- }], saved: [{
1265
+ }], artifactVersionId: [{
1266
+ type: Input
1267
+ }], artifactName: [{
1268
+ type: Input
1269
+ }], artifactVersionNumber: [{
1270
+ type: Input
1271
+ }], completed: [{
730
1272
  type: Output
731
1273
  }], cancelled: [{
732
1274
  type: Output
1275
+ }], searchInputRef: [{
1276
+ type: ViewChild,
1277
+ args: ['searchInput']
1278
+ }], newNameInputRef: [{
1279
+ type: ViewChild,
1280
+ args: ['newNameInput']
733
1281
  }] }); })();
734
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArtifactCollectionPickerModalComponent, { className: "ArtifactCollectionPickerModalComponent", filePath: "src/lib/components/collection/artifact-collection-picker-modal.component.ts", lineNumber: 489 }); })();
1282
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArtifactCollectionPickerModalComponent, { className: "ArtifactCollectionPickerModalComponent", filePath: "src/lib/components/collection/artifact-collection-picker-modal.component.ts", lineNumber: 604 }); })();
735
1283
  //# sourceMappingURL=artifact-collection-picker-modal.component.js.map