@memberjunction/ng-resource-permissions 6.1.4 → 6.2.0-edge.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/available-resources.component.d.ts +24 -4
- package/dist/lib/available-resources.component.d.ts.map +1 -1
- package/dist/lib/available-resources.component.js +54 -14
- package/dist/lib/available-resources.component.js.map +1 -1
- package/dist/lib/request-access.component.d.ts +2 -0
- package/dist/lib/request-access.component.d.ts.map +1 -1
- package/dist/lib/request-access.component.js +5 -1
- package/dist/lib/request-access.component.js.map +1 -1
- package/dist/lib/resource-permissions.component.d.ts +16 -2
- package/dist/lib/resource-permissions.component.d.ts.map +1 -1
- package/dist/lib/resource-permissions.component.js +44 -16
- package/dist/lib/resource-permissions.component.js.map +1 -1
- package/dist/lib/resource-share-adapter.d.ts +20 -0
- package/dist/lib/resource-share-adapter.d.ts.map +1 -1
- package/dist/lib/resource-share-adapter.js.map +1 -1
- package/dist/lib/resource-share-dialog.component.d.ts +65 -12
- package/dist/lib/resource-share-dialog.component.d.ts.map +1 -1
- package/dist/lib/resource-share-dialog.component.js +340 -148
- package/dist/lib/resource-share-dialog.component.js.map +1 -1
- package/dist/lib/user-sharing-center.component.d.ts +29 -0
- package/dist/lib/user-sharing-center.component.d.ts.map +1 -1
- package/dist/lib/user-sharing-center.component.js +51 -5
- package/dist/lib/user-sharing-center.component.js.map +1 -1
- package/package.json +12 -12
|
@@ -17,8 +17,19 @@ function GenericShareDialogComponent_Conditional_0_Conditional_7_Template(rf, ct
|
|
|
17
17
|
i0.ɵɵadvance();
|
|
18
18
|
i0.ɵɵtextInterpolate(ctx_r1.Error);
|
|
19
19
|
} }
|
|
20
|
-
function
|
|
21
|
-
i0.ɵɵelementStart(0, "
|
|
20
|
+
function GenericShareDialogComponent_Conditional_0_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
21
|
+
i0.ɵɵelementStart(0, "div", 6);
|
|
22
|
+
i0.ɵɵelement(1, "i", 23);
|
|
23
|
+
i0.ɵɵelementStart(2, "span");
|
|
24
|
+
i0.ɵɵtext(3);
|
|
25
|
+
i0.ɵɵelementEnd()();
|
|
26
|
+
} if (rf & 2) {
|
|
27
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
28
|
+
i0.ɵɵadvance(3);
|
|
29
|
+
i0.ɵɵtextInterpolate(ctx_r1.Notice);
|
|
30
|
+
} }
|
|
31
|
+
function GenericShareDialogComponent_Conditional_0_Conditional_13_For_2_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
32
|
+
i0.ɵɵelementStart(0, "span", 28);
|
|
22
33
|
i0.ɵɵtext(1);
|
|
23
34
|
i0.ɵɵelementEnd();
|
|
24
35
|
} if (rf & 2) {
|
|
@@ -26,67 +37,67 @@ function GenericShareDialogComponent_Conditional_0_Conditional_12_For_2_Conditio
|
|
|
26
37
|
i0.ɵɵadvance();
|
|
27
38
|
i0.ɵɵtextInterpolate(user_r4.Email);
|
|
28
39
|
} }
|
|
29
|
-
function
|
|
40
|
+
function GenericShareDialogComponent_Conditional_0_Conditional_13_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
30
41
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
31
|
-
i0.ɵɵelementStart(0, "button",
|
|
32
|
-
i0.ɵɵlistener("click", function
|
|
33
|
-
i0.ɵɵelementStart(1, "span",
|
|
42
|
+
i0.ɵɵelementStart(0, "button", 25);
|
|
43
|
+
i0.ɵɵlistener("click", function GenericShareDialogComponent_Conditional_0_Conditional_13_For_2_Template_button_click_0_listener() { const user_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.AddUserShare(user_r4)); });
|
|
44
|
+
i0.ɵɵelementStart(1, "span", 26);
|
|
34
45
|
i0.ɵɵtext(2);
|
|
35
46
|
i0.ɵɵelementEnd();
|
|
36
|
-
i0.ɵɵelementStart(3, "span",
|
|
47
|
+
i0.ɵɵelementStart(3, "span", 27);
|
|
37
48
|
i0.ɵɵtext(4);
|
|
38
49
|
i0.ɵɵelementEnd();
|
|
39
|
-
i0.ɵɵconditionalCreate(5,
|
|
40
|
-
i0.ɵɵelement(6, "i",
|
|
50
|
+
i0.ɵɵconditionalCreate(5, GenericShareDialogComponent_Conditional_0_Conditional_13_For_2_Conditional_5_Template, 2, 1, "span", 28);
|
|
51
|
+
i0.ɵɵelement(6, "i", 29);
|
|
41
52
|
i0.ɵɵelementEnd();
|
|
42
53
|
} if (rf & 2) {
|
|
43
54
|
const user_r4 = ctx.$implicit;
|
|
44
55
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
45
56
|
i0.ɵɵproperty("disabled", ctx_r1.IsLoading);
|
|
46
57
|
i0.ɵɵadvance(2);
|
|
47
|
-
i0.ɵɵtextInterpolate(ctx_r1.
|
|
58
|
+
i0.ɵɵtextInterpolate(ctx_r1.GetUserInitials(user_r4));
|
|
48
59
|
i0.ɵɵadvance(2);
|
|
49
60
|
i0.ɵɵtextInterpolate(user_r4.Name);
|
|
50
61
|
i0.ɵɵadvance();
|
|
51
62
|
i0.ɵɵconditional(user_r4.Email ? 5 : -1);
|
|
52
63
|
} }
|
|
53
|
-
function
|
|
54
|
-
i0.ɵɵelementStart(0, "div",
|
|
55
|
-
i0.ɵɵrepeaterCreate(1,
|
|
64
|
+
function GenericShareDialogComponent_Conditional_0_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
65
|
+
i0.ɵɵelementStart(0, "div", 11);
|
|
66
|
+
i0.ɵɵrepeaterCreate(1, GenericShareDialogComponent_Conditional_0_Conditional_13_For_2_Template, 7, 4, "button", 24, _forTrack1);
|
|
56
67
|
i0.ɵɵelementEnd();
|
|
57
68
|
} if (rf & 2) {
|
|
58
69
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
59
70
|
i0.ɵɵadvance();
|
|
60
71
|
i0.ɵɵrepeater(ctx_r1.FilteredAvailableUsers);
|
|
61
72
|
} }
|
|
62
|
-
function
|
|
63
|
-
i0.ɵɵelement(0, "mj-empty-state",
|
|
73
|
+
function GenericShareDialogComponent_Conditional_0_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
74
|
+
i0.ɵɵelement(0, "mj-empty-state", 12);
|
|
64
75
|
} if (rf & 2) {
|
|
65
76
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
66
77
|
i0.ɵɵproperty("Title", ctx_r1.NoUsersFoundMessage);
|
|
67
78
|
} }
|
|
68
|
-
function
|
|
69
|
-
i0.ɵɵelementStart(0, "div",
|
|
70
|
-
i0.ɵɵelement(2, "i",
|
|
79
|
+
function GenericShareDialogComponent_Conditional_0_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
80
|
+
i0.ɵɵelementStart(0, "div", 14)(1, "span", 30);
|
|
81
|
+
i0.ɵɵelement(2, "i", 31);
|
|
71
82
|
i0.ɵɵelementEnd();
|
|
72
|
-
i0.ɵɵelementStart(3, "div",
|
|
83
|
+
i0.ɵɵelementStart(3, "div", 32)(4, "span", 33);
|
|
73
84
|
i0.ɵɵtext(5);
|
|
74
85
|
i0.ɵɵelementEnd();
|
|
75
|
-
i0.ɵɵelementStart(6, "span",
|
|
86
|
+
i0.ɵɵelementStart(6, "span", 34);
|
|
76
87
|
i0.ɵɵtext(7, "Owner");
|
|
77
88
|
i0.ɵɵelementEnd()()();
|
|
78
89
|
} if (rf & 2) {
|
|
79
90
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
80
91
|
i0.ɵɵadvance(5);
|
|
81
|
-
i0.ɵɵtextInterpolate(ctx_r1.
|
|
92
|
+
i0.ɵɵtextInterpolate(ctx_r1.PrimaryContext == null ? null : ctx_r1.PrimaryContext.OwnerDisplayName);
|
|
82
93
|
} }
|
|
83
|
-
function
|
|
84
|
-
i0.ɵɵelementStart(0, "span",
|
|
94
|
+
function GenericShareDialogComponent_Conditional_0_For_20_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
95
|
+
i0.ɵɵelementStart(0, "span", 36);
|
|
85
96
|
i0.ɵɵtext(1, "New");
|
|
86
97
|
i0.ɵɵelementEnd();
|
|
87
98
|
} }
|
|
88
|
-
function
|
|
89
|
-
i0.ɵɵelementStart(0, "span",
|
|
99
|
+
function GenericShareDialogComponent_Conditional_0_For_20_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
100
|
+
i0.ɵɵelementStart(0, "span", 37);
|
|
90
101
|
i0.ɵɵtext(1);
|
|
91
102
|
i0.ɵɵelementEnd();
|
|
92
103
|
} if (rf & 2) {
|
|
@@ -94,97 +105,111 @@ function GenericShareDialogComponent_Conditional_0_For_19_Conditional_7_Template
|
|
|
94
105
|
i0.ɵɵadvance();
|
|
95
106
|
i0.ɵɵtextInterpolate(share_r6.User.Email);
|
|
96
107
|
} }
|
|
97
|
-
function
|
|
108
|
+
function GenericShareDialogComponent_Conditional_0_For_20_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
109
|
+
i0.ɵɵelementStart(0, "span", 38);
|
|
110
|
+
i0.ɵɵtext(1);
|
|
111
|
+
i0.ɵɵelementEnd();
|
|
112
|
+
} if (rf & 2) {
|
|
113
|
+
const share_r6 = i0.ɵɵnextContext().$implicit;
|
|
114
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
115
|
+
i0.ɵɵadvance();
|
|
116
|
+
i0.ɵɵtextInterpolate(ctx_r1.ScopeLabel(share_r6));
|
|
117
|
+
} }
|
|
118
|
+
function GenericShareDialogComponent_Conditional_0_For_20_For_11_Template(rf, ctx) { if (rf & 1) {
|
|
98
119
|
const _r7 = i0.ɵɵgetCurrentView();
|
|
99
|
-
i0.ɵɵelementStart(0, "button",
|
|
100
|
-
i0.ɵɵlistener("click", function
|
|
120
|
+
i0.ɵɵelementStart(0, "button", 43);
|
|
121
|
+
i0.ɵɵlistener("click", function GenericShareDialogComponent_Conditional_0_For_20_For_11_Template_button_click_0_listener() { const level_r8 = i0.ɵɵrestoreView(_r7).$implicit; const share_r6 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SetLevel(share_r6, level_r8)); });
|
|
101
122
|
i0.ɵɵtext(1);
|
|
102
123
|
i0.ɵɵelementEnd();
|
|
103
124
|
} if (rf & 2) {
|
|
104
125
|
const level_r8 = ctx.$implicit;
|
|
105
126
|
const share_r6 = i0.ɵɵnextContext().$implicit;
|
|
106
|
-
i0.ɵɵ
|
|
127
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
128
|
+
i0.ɵɵclassProp("active", ctx_r1.IsLevelActive(share_r6, level_r8));
|
|
107
129
|
i0.ɵɵproperty("title", level_r8 + " access");
|
|
108
130
|
i0.ɵɵadvance();
|
|
109
131
|
i0.ɵɵtextInterpolate1(" ", level_r8, " ");
|
|
110
132
|
} }
|
|
111
|
-
function
|
|
133
|
+
function GenericShareDialogComponent_Conditional_0_For_20_Template(rf, ctx) { if (rf & 1) {
|
|
112
134
|
const _r5 = i0.ɵɵgetCurrentView();
|
|
113
|
-
i0.ɵɵelementStart(0, "div",
|
|
135
|
+
i0.ɵɵelementStart(0, "div", 35)(1, "span", 26);
|
|
114
136
|
i0.ɵɵtext(2);
|
|
115
137
|
i0.ɵɵelementEnd();
|
|
116
|
-
i0.ɵɵelementStart(3, "div",
|
|
138
|
+
i0.ɵɵelementStart(3, "div", 32)(4, "span", 33);
|
|
117
139
|
i0.ɵɵtext(5);
|
|
118
|
-
i0.ɵɵconditionalCreate(6,
|
|
140
|
+
i0.ɵɵconditionalCreate(6, GenericShareDialogComponent_Conditional_0_For_20_Conditional_6_Template, 2, 0, "span", 36);
|
|
119
141
|
i0.ɵɵelementEnd();
|
|
120
|
-
i0.ɵɵconditionalCreate(7,
|
|
142
|
+
i0.ɵɵconditionalCreate(7, GenericShareDialogComponent_Conditional_0_For_20_Conditional_7_Template, 2, 1, "span", 37);
|
|
143
|
+
i0.ɵɵconditionalCreate(8, GenericShareDialogComponent_Conditional_0_For_20_Conditional_8_Template, 2, 1, "span", 38);
|
|
121
144
|
i0.ɵɵelementEnd();
|
|
122
|
-
i0.ɵɵelementStart(
|
|
123
|
-
i0.ɵɵrepeaterCreate(
|
|
145
|
+
i0.ɵɵelementStart(9, "div", 39);
|
|
146
|
+
i0.ɵɵrepeaterCreate(10, GenericShareDialogComponent_Conditional_0_For_20_For_11_Template, 2, 4, "button", 40, i0.ɵɵrepeaterTrackByIdentity);
|
|
124
147
|
i0.ɵɵelementEnd();
|
|
125
|
-
i0.ɵɵelementStart(
|
|
126
|
-
i0.ɵɵlistener("click", function
|
|
127
|
-
i0.ɵɵelement(
|
|
148
|
+
i0.ɵɵelementStart(12, "button", 41);
|
|
149
|
+
i0.ɵɵlistener("click", function GenericShareDialogComponent_Conditional_0_For_20_Template_button_click_12_listener() { const share_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.RemoveUserShare(share_r6)); });
|
|
150
|
+
i0.ɵɵelement(13, "i", 42);
|
|
128
151
|
i0.ɵɵelementEnd()();
|
|
129
152
|
} if (rf & 2) {
|
|
130
153
|
const share_r6 = ctx.$implicit;
|
|
131
154
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
132
|
-
i0.ɵɵclassProp("share-person-new", share_r6.IsNew)("share-person-modified", ctx_r1.
|
|
155
|
+
i0.ɵɵclassProp("share-person-new", share_r6.IsNew)("share-person-modified", ctx_r1.IsModified(share_r6));
|
|
133
156
|
i0.ɵɵadvance(2);
|
|
134
|
-
i0.ɵɵtextInterpolate(ctx_r1.
|
|
157
|
+
i0.ɵɵtextInterpolate(ctx_r1.GetUserInitials(share_r6.User));
|
|
135
158
|
i0.ɵɵadvance(3);
|
|
136
159
|
i0.ɵɵtextInterpolate1(" ", share_r6.User.Name, " ");
|
|
137
160
|
i0.ɵɵadvance();
|
|
138
161
|
i0.ɵɵconditional(share_r6.IsNew ? 6 : -1);
|
|
139
162
|
i0.ɵɵadvance();
|
|
140
163
|
i0.ɵɵconditional(share_r6.User.Email ? 7 : -1);
|
|
164
|
+
i0.ɵɵadvance();
|
|
165
|
+
i0.ɵɵconditional(ctx_r1.ScopeLabel(share_r6) ? 8 : -1);
|
|
141
166
|
i0.ɵɵadvance(2);
|
|
142
167
|
i0.ɵɵrepeater(ctx_r1.Levels);
|
|
143
168
|
} }
|
|
144
|
-
function
|
|
145
|
-
i0.ɵɵelement(0, "mj-empty-state",
|
|
169
|
+
function GenericShareDialogComponent_Conditional_0_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
170
|
+
i0.ɵɵelement(0, "mj-empty-state", 16);
|
|
146
171
|
} }
|
|
147
|
-
function
|
|
172
|
+
function GenericShareDialogComponent_Conditional_0_Conditional_22_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
148
173
|
const _r9 = i0.ɵɵgetCurrentView();
|
|
149
|
-
i0.ɵɵelementStart(0, "div",
|
|
174
|
+
i0.ɵɵelementStart(0, "div", 44)(1, "span", 45);
|
|
150
175
|
i0.ɵɵtext(2);
|
|
151
176
|
i0.ɵɵelementEnd();
|
|
152
|
-
i0.ɵɵelementStart(3, "span",
|
|
177
|
+
i0.ɵɵelementStart(3, "span", 46);
|
|
153
178
|
i0.ɵɵtext(4);
|
|
154
179
|
i0.ɵɵelementEnd();
|
|
155
|
-
i0.ɵɵelementStart(5, "button",
|
|
156
|
-
i0.ɵɵlistener("click", function
|
|
157
|
-
i0.ɵɵelement(6, "i",
|
|
180
|
+
i0.ɵɵelementStart(5, "button", 47);
|
|
181
|
+
i0.ɵɵlistener("click", function GenericShareDialogComponent_Conditional_0_Conditional_22_For_2_Template_button_click_5_listener() { const share_r10 = i0.ɵɵrestoreView(_r9).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.UndoRemove(share_r10)); });
|
|
182
|
+
i0.ɵɵelement(6, "i", 48);
|
|
158
183
|
i0.ɵɵtext(7, " Undo ");
|
|
159
184
|
i0.ɵɵelementEnd()();
|
|
160
185
|
} if (rf & 2) {
|
|
161
186
|
const share_r10 = ctx.$implicit;
|
|
162
187
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
163
188
|
i0.ɵɵadvance(2);
|
|
164
|
-
i0.ɵɵtextInterpolate(ctx_r1.
|
|
189
|
+
i0.ɵɵtextInterpolate(ctx_r1.GetUserInitials(share_r10.User));
|
|
165
190
|
i0.ɵɵadvance(2);
|
|
166
191
|
i0.ɵɵtextInterpolate(share_r10.User.Name);
|
|
167
192
|
} }
|
|
168
|
-
function
|
|
169
|
-
i0.ɵɵelementStart(0, "div",
|
|
170
|
-
i0.ɵɵrepeaterCreate(1,
|
|
193
|
+
function GenericShareDialogComponent_Conditional_0_Conditional_22_Template(rf, ctx) { if (rf & 1) {
|
|
194
|
+
i0.ɵɵelementStart(0, "div", 17);
|
|
195
|
+
i0.ɵɵrepeaterCreate(1, GenericShareDialogComponent_Conditional_0_Conditional_22_For_2_Template, 8, 2, "div", 44, _forTrack0);
|
|
171
196
|
i0.ɵɵelementEnd();
|
|
172
197
|
} if (rf & 2) {
|
|
173
198
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
174
199
|
i0.ɵɵadvance();
|
|
175
200
|
i0.ɵɵrepeater(ctx_r1.RemovedShares);
|
|
176
201
|
} }
|
|
177
|
-
function
|
|
178
|
-
i0.ɵɵelementStart(0, "span",
|
|
179
|
-
i0.ɵɵelement(1, "i",
|
|
202
|
+
function GenericShareDialogComponent_Conditional_0_Conditional_24_Template(rf, ctx) { if (rf & 1) {
|
|
203
|
+
i0.ɵɵelementStart(0, "span", 19);
|
|
204
|
+
i0.ɵɵelement(1, "i", 49);
|
|
180
205
|
i0.ɵɵtext(2, " Unsaved changes ");
|
|
181
206
|
i0.ɵɵelementEnd();
|
|
182
207
|
} }
|
|
183
|
-
function
|
|
184
|
-
i0.ɵɵelement(0, "i",
|
|
208
|
+
function GenericShareDialogComponent_Conditional_0_Conditional_29_Template(rf, ctx) { if (rf & 1) {
|
|
209
|
+
i0.ɵɵelement(0, "i", 50);
|
|
185
210
|
i0.ɵɵtext(1, " Saving... ");
|
|
186
211
|
} }
|
|
187
|
-
function
|
|
212
|
+
function GenericShareDialogComponent_Conditional_0_Conditional_30_Template(rf, ctx) { if (rf & 1) {
|
|
188
213
|
i0.ɵɵtext(0, " Save ");
|
|
189
214
|
} }
|
|
190
215
|
function GenericShareDialogComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
@@ -198,60 +223,63 @@ function GenericShareDialogComponent_Conditional_0_Template(rf, ctx) { if (rf &
|
|
|
198
223
|
i0.ɵɵelementEnd()()();
|
|
199
224
|
i0.ɵɵelementStart(6, "div", 4);
|
|
200
225
|
i0.ɵɵconditionalCreate(7, GenericShareDialogComponent_Conditional_0_Conditional_7_Template, 2, 1, "mj-alert", 5);
|
|
201
|
-
i0.ɵɵ
|
|
202
|
-
i0.ɵɵ
|
|
203
|
-
i0.ɵɵ
|
|
204
|
-
i0.ɵɵ
|
|
226
|
+
i0.ɵɵconditionalCreate(8, GenericShareDialogComponent_Conditional_0_Conditional_8_Template, 4, 1, "div", 6);
|
|
227
|
+
i0.ɵɵelementStart(9, "div", 7)(10, "div", 8);
|
|
228
|
+
i0.ɵɵelement(11, "i", 9);
|
|
229
|
+
i0.ɵɵelementStart(12, "input", 10);
|
|
230
|
+
i0.ɵɵtwoWayListener("ngModelChange", function GenericShareDialogComponent_Conditional_0_Template_input_ngModelChange_12_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.UserSearchFilter, $event) || (ctx_r1.UserSearchFilter = $event); return i0.ɵɵresetView($event); });
|
|
205
231
|
i0.ɵɵelementEnd()();
|
|
206
|
-
i0.ɵɵconditionalCreate(
|
|
207
|
-
i0.ɵɵconditionalCreate(
|
|
232
|
+
i0.ɵɵconditionalCreate(13, GenericShareDialogComponent_Conditional_0_Conditional_13_Template, 3, 0, "div", 11);
|
|
233
|
+
i0.ɵɵconditionalCreate(14, GenericShareDialogComponent_Conditional_0_Conditional_14_Template, 1, 1, "mj-empty-state", 12);
|
|
208
234
|
i0.ɵɵelementEnd();
|
|
209
|
-
i0.ɵɵelementStart(
|
|
210
|
-
i0.ɵɵtext(
|
|
235
|
+
i0.ɵɵelementStart(15, "div", 7)(16, "div", 13);
|
|
236
|
+
i0.ɵɵtext(17, "People with access");
|
|
211
237
|
i0.ɵɵelementEnd();
|
|
212
|
-
i0.ɵɵconditionalCreate(
|
|
213
|
-
i0.ɵɵrepeaterCreate(
|
|
214
|
-
i0.ɵɵconditionalCreate(
|
|
215
|
-
i0.ɵɵconditionalCreate(
|
|
238
|
+
i0.ɵɵconditionalCreate(18, GenericShareDialogComponent_Conditional_0_Conditional_18_Template, 8, 1, "div", 14);
|
|
239
|
+
i0.ɵɵrepeaterCreate(19, GenericShareDialogComponent_Conditional_0_For_20_Template, 14, 9, "div", 15, _forTrack0);
|
|
240
|
+
i0.ɵɵconditionalCreate(21, GenericShareDialogComponent_Conditional_0_Conditional_21_Template, 1, 0, "mj-empty-state", 16);
|
|
241
|
+
i0.ɵɵconditionalCreate(22, GenericShareDialogComponent_Conditional_0_Conditional_22_Template, 3, 0, "div", 17);
|
|
216
242
|
i0.ɵɵelementEnd();
|
|
217
|
-
i0.ɵɵelementStart(
|
|
218
|
-
i0.ɵɵconditionalCreate(
|
|
219
|
-
i0.ɵɵelementStart(
|
|
220
|
-
i0.ɵɵlistener("click", function
|
|
221
|
-
i0.ɵɵtext(
|
|
243
|
+
i0.ɵɵelementStart(23, "div", 18);
|
|
244
|
+
i0.ɵɵconditionalCreate(24, GenericShareDialogComponent_Conditional_0_Conditional_24_Template, 3, 0, "span", 19);
|
|
245
|
+
i0.ɵɵelementStart(25, "div", 20)(26, "button", 21);
|
|
246
|
+
i0.ɵɵlistener("click", function GenericShareDialogComponent_Conditional_0_Template_button_click_26_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onCancel()); });
|
|
247
|
+
i0.ɵɵtext(27, " Cancel ");
|
|
222
248
|
i0.ɵɵelementEnd();
|
|
223
|
-
i0.ɵɵelementStart(
|
|
224
|
-
i0.ɵɵlistener("click", function
|
|
225
|
-
i0.ɵɵconditionalCreate(
|
|
249
|
+
i0.ɵɵelementStart(28, "button", 22);
|
|
250
|
+
i0.ɵɵlistener("click", function GenericShareDialogComponent_Conditional_0_Template_button_click_28_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnSave()); });
|
|
251
|
+
i0.ɵɵconditionalCreate(29, GenericShareDialogComponent_Conditional_0_Conditional_29_Template, 2, 0)(30, GenericShareDialogComponent_Conditional_0_Conditional_30_Template, 1, 0);
|
|
226
252
|
i0.ɵɵelementEnd()()()()();
|
|
227
253
|
} if (rf & 2) {
|
|
228
254
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
229
255
|
i0.ɵɵproperty("Visible", true)("Width", 560)("MinHeight", 200)("Resizable", false)("Draggable", true);
|
|
230
256
|
i0.ɵɵadvance(5);
|
|
231
|
-
i0.ɵɵ
|
|
257
|
+
i0.ɵɵtextInterpolate(ctx_r1.Title);
|
|
232
258
|
i0.ɵɵadvance(2);
|
|
233
259
|
i0.ɵɵconditional(ctx_r1.Error ? 7 : -1);
|
|
260
|
+
i0.ɵɵadvance();
|
|
261
|
+
i0.ɵɵconditional(ctx_r1.Notice ? 8 : -1);
|
|
234
262
|
i0.ɵɵadvance(4);
|
|
235
263
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.UserSearchFilter);
|
|
236
264
|
i0.ɵɵproperty("disabled", ctx_r1.IsLoading);
|
|
237
265
|
i0.ɵɵadvance();
|
|
238
|
-
i0.ɵɵconditional(ctx_r1.FilteredAvailableUsers.length > 0 ?
|
|
266
|
+
i0.ɵɵconditional(ctx_r1.FilteredAvailableUsers.length > 0 ? 13 : -1);
|
|
239
267
|
i0.ɵɵadvance();
|
|
240
|
-
i0.ɵɵconditional(ctx_r1.UserSearchFilter && ctx_r1.FilteredAvailableUsers.length === 0 ?
|
|
268
|
+
i0.ɵɵconditional(ctx_r1.UserSearchFilter && ctx_r1.FilteredAvailableUsers.length === 0 ? 14 : -1);
|
|
241
269
|
i0.ɵɵadvance(4);
|
|
242
|
-
i0.ɵɵconditional((ctx_r1.
|
|
270
|
+
i0.ɵɵconditional((ctx_r1.PrimaryContext == null ? null : ctx_r1.PrimaryContext.OwnerDisplayName) ? 18 : -1);
|
|
243
271
|
i0.ɵɵadvance();
|
|
244
272
|
i0.ɵɵrepeater(ctx_r1.ActiveShares);
|
|
245
273
|
i0.ɵɵadvance(2);
|
|
246
|
-
i0.ɵɵconditional(ctx_r1.ActiveShares.length === 0 ?
|
|
274
|
+
i0.ɵɵconditional(ctx_r1.ActiveShares.length === 0 ? 21 : -1);
|
|
247
275
|
i0.ɵɵadvance();
|
|
248
|
-
i0.ɵɵconditional(ctx_r1.RemovedShares.length > 0 ?
|
|
276
|
+
i0.ɵɵconditional(ctx_r1.RemovedShares.length > 0 ? 22 : -1);
|
|
249
277
|
i0.ɵɵadvance(2);
|
|
250
|
-
i0.ɵɵconditional(ctx_r1.HasChanges ?
|
|
278
|
+
i0.ɵɵconditional(ctx_r1.HasChanges ? 24 : -1);
|
|
251
279
|
i0.ɵɵadvance(4);
|
|
252
280
|
i0.ɵɵproperty("disabled", !ctx_r1.HasChanges || ctx_r1.IsLoading);
|
|
253
281
|
i0.ɵɵadvance();
|
|
254
|
-
i0.ɵɵconditional(ctx_r1.IsLoading ?
|
|
282
|
+
i0.ɵɵconditional(ctx_r1.IsLoading ? 29 : 30);
|
|
255
283
|
} }
|
|
256
284
|
/**
|
|
257
285
|
* Resource-type-agnostic share dialog. Every resource's sharing UX collapses to
|
|
@@ -262,16 +290,40 @@ function GenericShareDialogComponent_Conditional_0_Template(rf, ctx) { if (rf &
|
|
|
262
290
|
export class GenericShareDialogComponent extends BaseAngularComponent {
|
|
263
291
|
cdr;
|
|
264
292
|
Visible = false;
|
|
293
|
+
/** The single resource being shared. Ignored when `Contexts` is supplied. */
|
|
265
294
|
Context = null;
|
|
295
|
+
/** Several resources to share at once; every action applies to all of them. */
|
|
296
|
+
Contexts = null;
|
|
266
297
|
Adapter = null;
|
|
298
|
+
/** Singular noun for the title when sharing several ("3 conversations"). */
|
|
299
|
+
ResourceLabel = 'item';
|
|
300
|
+
/** Optional line shown above the dialog body — e.g. what the caller left out. */
|
|
301
|
+
Notice = null;
|
|
267
302
|
Result = new EventEmitter();
|
|
268
303
|
Levels = RESOURCE_SHARE_LEVELS;
|
|
269
|
-
|
|
304
|
+
Grants = [];
|
|
270
305
|
AvailableUsers = [];
|
|
271
306
|
allUsers = [];
|
|
272
307
|
IsLoading = false;
|
|
273
308
|
Error = null;
|
|
274
309
|
UserSearchFilter = '';
|
|
310
|
+
/** Every resource this dialog is operating on. */
|
|
311
|
+
get ActiveContexts() {
|
|
312
|
+
if (this.Contexts && this.Contexts.length > 0)
|
|
313
|
+
return this.Contexts;
|
|
314
|
+
return this.Context ? [this.Context] : [];
|
|
315
|
+
}
|
|
316
|
+
/** The resource whose owner row is shown — only meaningful for a single resource. */
|
|
317
|
+
get PrimaryContext() {
|
|
318
|
+
const contexts = this.ActiveContexts;
|
|
319
|
+
return contexts.length === 1 ? contexts[0] : null;
|
|
320
|
+
}
|
|
321
|
+
get Title() {
|
|
322
|
+
const contexts = this.ActiveContexts;
|
|
323
|
+
if (contexts.length === 1)
|
|
324
|
+
return `Share "${contexts[0].ResourceName}"`;
|
|
325
|
+
return `Share ${contexts.length} ${this.ResourceLabel}s`;
|
|
326
|
+
}
|
|
275
327
|
/** Message for the no-results empty-state, echoing the current search term. */
|
|
276
328
|
get NoUsersFoundMessage() {
|
|
277
329
|
return `No users found matching "${this.UserSearchFilter}"`;
|
|
@@ -281,34 +333,29 @@ export class GenericShareDialogComponent extends BaseAngularComponent {
|
|
|
281
333
|
this.cdr = cdr;
|
|
282
334
|
}
|
|
283
335
|
ngOnChanges(changes) {
|
|
284
|
-
if (changes['Visible'] && this.Visible && this.
|
|
336
|
+
if (changes['Visible'] && this.Visible && this.ActiveContexts.length > 0 && this.Adapter) {
|
|
285
337
|
this.resetDialog();
|
|
286
|
-
this.
|
|
338
|
+
void this.Reload();
|
|
287
339
|
}
|
|
288
340
|
}
|
|
289
341
|
resetDialog() {
|
|
290
342
|
this.Error = null;
|
|
291
343
|
this.IsLoading = false;
|
|
292
|
-
this.
|
|
344
|
+
this.Grants = [];
|
|
293
345
|
this.AvailableUsers = [];
|
|
294
346
|
this.UserSearchFilter = '';
|
|
295
347
|
}
|
|
296
|
-
|
|
297
|
-
|
|
348
|
+
/** Loads the people list and every resource's existing shares, merged per person. */
|
|
349
|
+
async Reload() {
|
|
350
|
+
const contexts = this.ActiveContexts;
|
|
351
|
+
if (contexts.length === 0 || !this.Adapter)
|
|
298
352
|
return;
|
|
299
353
|
this.IsLoading = true;
|
|
300
354
|
this.cdr.detectChanges();
|
|
301
355
|
try {
|
|
302
|
-
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
ExtraFilter: 'IsActive = 1',
|
|
306
|
-
OrderBy: 'Name',
|
|
307
|
-
ResultType: 'entity_object'
|
|
308
|
-
});
|
|
309
|
-
this.allUsers = usersResult.Success ? usersResult.Results : [];
|
|
310
|
-
this.UserShares = await this.Adapter.LoadShares(this.Context);
|
|
311
|
-
this.UserShares.forEach((s) => (s._InitialLevel = s.Level));
|
|
356
|
+
await this.loadUsers();
|
|
357
|
+
const perResource = await Promise.all(contexts.map((ctx) => this.Adapter.LoadShares(ctx)));
|
|
358
|
+
this.Grants = this.mergeIntoGrants(contexts, perResource);
|
|
312
359
|
this.updateAvailableUsers();
|
|
313
360
|
}
|
|
314
361
|
catch (error) {
|
|
@@ -320,17 +367,60 @@ export class GenericShareDialogComponent extends BaseAngularComponent {
|
|
|
320
367
|
this.cdr.detectChanges();
|
|
321
368
|
}
|
|
322
369
|
}
|
|
370
|
+
async loadUsers() {
|
|
371
|
+
const rv = RunView.FromMetadataProvider(this.ProviderToUse);
|
|
372
|
+
const usersResult = await rv.RunView({
|
|
373
|
+
EntityName: 'MJ: Users',
|
|
374
|
+
ExtraFilter: 'IsActive = 1',
|
|
375
|
+
OrderBy: 'Name',
|
|
376
|
+
ResultType: 'entity_object'
|
|
377
|
+
});
|
|
378
|
+
this.allUsers = usersResult.Success ? usersResult.Results : [];
|
|
379
|
+
}
|
|
380
|
+
/** One grant per person, carrying their row on each resource that has one. */
|
|
381
|
+
mergeIntoGrants(contexts, perResource) {
|
|
382
|
+
const byUser = new Map();
|
|
383
|
+
perResource.forEach((rows, index) => {
|
|
384
|
+
const resourceId = contexts[index].ResourceID;
|
|
385
|
+
for (const row of rows) {
|
|
386
|
+
row._InitialLevel = row.Level;
|
|
387
|
+
const key = row.UserID.toLowerCase();
|
|
388
|
+
const grant = byUser.get(key) ?? {
|
|
389
|
+
User: row.User,
|
|
390
|
+
UserID: row.UserID,
|
|
391
|
+
Rows: new Map(),
|
|
392
|
+
InitialLevel: row.Level,
|
|
393
|
+
Level: row.Level,
|
|
394
|
+
LevelTouched: false,
|
|
395
|
+
IsNew: false,
|
|
396
|
+
MarkedForRemoval: false
|
|
397
|
+
};
|
|
398
|
+
grant.Rows.set(resourceId, row);
|
|
399
|
+
if (grant.InitialLevel !== row.Level) {
|
|
400
|
+
grant.InitialLevel = null; // levels differ across resources
|
|
401
|
+
}
|
|
402
|
+
byUser.set(key, grant);
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
// A person on some but not all resources has no single level to show either.
|
|
406
|
+
for (const grant of byUser.values()) {
|
|
407
|
+
grant.Level = grant.InitialLevel ?? 'View';
|
|
408
|
+
}
|
|
409
|
+
return Array.from(byUser.values());
|
|
410
|
+
}
|
|
411
|
+
/** Everyone who owns none of the resources and doesn't already hold a (live) grant. */
|
|
323
412
|
updateAvailableUsers() {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
413
|
+
const sharedUserIds = new Set(this.Grants.filter((g) => !g.MarkedForRemoval).map((g) => g.User.ID));
|
|
414
|
+
const ownerIds = this.ActiveContexts
|
|
415
|
+
.map((ctx) => ctx.OwnerUserID)
|
|
416
|
+
.filter((id) => !!id);
|
|
328
417
|
this.AvailableUsers = this.allUsers.filter((user) => {
|
|
329
|
-
if (ownerId
|
|
418
|
+
if (ownerIds.some((ownerId) => UUIDsEqual(user.ID, ownerId)))
|
|
330
419
|
return false;
|
|
331
420
|
return !sharedUserIds.has(user.ID);
|
|
332
421
|
});
|
|
333
422
|
}
|
|
423
|
+
/** The first ten matches for the search box, or the first ten people. */
|
|
334
424
|
get FilteredAvailableUsers() {
|
|
335
425
|
if (!this.UserSearchFilter.trim()) {
|
|
336
426
|
return this.AvailableUsers.slice(0, 10);
|
|
@@ -341,49 +431,84 @@ export class GenericShareDialogComponent extends BaseAngularComponent {
|
|
|
341
431
|
.slice(0, 10);
|
|
342
432
|
}
|
|
343
433
|
get HasChanges() {
|
|
344
|
-
return this.
|
|
434
|
+
return this.Grants.some((g) => g.IsNew || g.MarkedForRemoval || g.LevelTouched);
|
|
345
435
|
}
|
|
346
436
|
get ActiveShares() {
|
|
347
|
-
return this.
|
|
437
|
+
return this.Grants.filter((g) => !g.MarkedForRemoval);
|
|
348
438
|
}
|
|
349
439
|
get RemovedShares() {
|
|
350
|
-
return this.
|
|
440
|
+
return this.Grants.filter((g) => g.MarkedForRemoval);
|
|
351
441
|
}
|
|
352
|
-
/** Highlight
|
|
353
|
-
|
|
354
|
-
return !
|
|
442
|
+
/** Highlight grants whose level has been changed from their loaded state. */
|
|
443
|
+
IsModified(grant) {
|
|
444
|
+
return !grant.IsNew && grant.LevelTouched;
|
|
355
445
|
}
|
|
356
|
-
|
|
357
|
-
|
|
446
|
+
/** A level button lights up only when the grant has one level to show. */
|
|
447
|
+
IsLevelActive(grant, level) {
|
|
448
|
+
if (!grant.LevelTouched && grant.InitialLevel === null && !grant.IsNew)
|
|
449
|
+
return false;
|
|
450
|
+
return grant.Level === level;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Why a grant does not simply read as "everyone, one level": levels that
|
|
454
|
+
* differ across resources, or access held on only some of them.
|
|
455
|
+
*/
|
|
456
|
+
ScopeLabel(grant) {
|
|
457
|
+
if (grant.IsNew || this.ActiveContexts.length < 2)
|
|
458
|
+
return '';
|
|
459
|
+
const parts = [];
|
|
460
|
+
if (!grant.LevelTouched && grant.InitialLevel === null)
|
|
461
|
+
parts.push('Mixed');
|
|
462
|
+
if (grant.Rows.size < this.ActiveContexts.length) {
|
|
463
|
+
parts.push(`${grant.Rows.size} of ${this.ActiveContexts.length}`);
|
|
464
|
+
}
|
|
465
|
+
return parts.join(' · ');
|
|
466
|
+
}
|
|
467
|
+
/** Adds a person, to every resource the dialog is sharing. */
|
|
468
|
+
async AddUserShare(user) {
|
|
469
|
+
if (this.ActiveContexts.length === 0 || !this.Adapter)
|
|
358
470
|
return;
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
471
|
+
this.Grants = [
|
|
472
|
+
...this.Grants,
|
|
473
|
+
{
|
|
474
|
+
User: user,
|
|
475
|
+
UserID: user.ID,
|
|
476
|
+
Rows: new Map(),
|
|
477
|
+
InitialLevel: null,
|
|
478
|
+
Level: 'View',
|
|
479
|
+
LevelTouched: false,
|
|
480
|
+
IsNew: true,
|
|
481
|
+
MarkedForRemoval: false
|
|
482
|
+
}
|
|
483
|
+
];
|
|
362
484
|
this.updateAvailableUsers();
|
|
363
485
|
this.UserSearchFilter = '';
|
|
364
486
|
this.cdr.detectChanges();
|
|
365
487
|
}
|
|
366
|
-
|
|
367
|
-
if (
|
|
368
|
-
this.
|
|
488
|
+
RemoveUserShare(grant) {
|
|
489
|
+
if (grant.IsNew) {
|
|
490
|
+
this.Grants = this.Grants.filter((g) => g !== grant);
|
|
369
491
|
}
|
|
370
492
|
else {
|
|
371
|
-
|
|
493
|
+
grant.MarkedForRemoval = true;
|
|
372
494
|
}
|
|
373
495
|
this.updateAvailableUsers();
|
|
374
496
|
this.cdr.detectChanges();
|
|
375
497
|
}
|
|
376
|
-
|
|
377
|
-
|
|
498
|
+
UndoRemove(grant) {
|
|
499
|
+
grant.MarkedForRemoval = false;
|
|
378
500
|
this.updateAvailableUsers();
|
|
379
501
|
this.cdr.detectChanges();
|
|
380
502
|
}
|
|
381
|
-
|
|
382
|
-
|
|
503
|
+
/** Sets one level for the person across every resource, filling in any gaps. */
|
|
504
|
+
SetLevel(grant, level) {
|
|
505
|
+
grant.Level = level;
|
|
506
|
+
grant.LevelTouched = true;
|
|
383
507
|
this.cdr.detectChanges();
|
|
384
508
|
}
|
|
385
|
-
async
|
|
386
|
-
|
|
509
|
+
async OnSave() {
|
|
510
|
+
const contexts = this.ActiveContexts;
|
|
511
|
+
if (!this.Adapter || contexts.length === 0)
|
|
387
512
|
return;
|
|
388
513
|
if (!this.HasChanges) {
|
|
389
514
|
this.onCancel();
|
|
@@ -393,22 +518,16 @@ export class GenericShareDialogComponent extends BaseAngularComponent {
|
|
|
393
518
|
this.Error = null;
|
|
394
519
|
this.cdr.detectChanges();
|
|
395
520
|
try {
|
|
396
|
-
for (const
|
|
397
|
-
|
|
398
|
-
if (!deleted) {
|
|
399
|
-
throw new Error(`Failed to remove share for ${share.User.Name}: ${share.PermissionEntity.LatestResult?.Message ?? 'unknown error'}`);
|
|
400
|
-
}
|
|
521
|
+
for (const grant of this.Grants.filter((g) => g.MarkedForRemoval && !g.IsNew)) {
|
|
522
|
+
await this.withdrawGrant(grant);
|
|
401
523
|
}
|
|
402
|
-
const
|
|
403
|
-
|
|
404
|
-
this.Adapter.SyncLevelToEntity(share);
|
|
405
|
-
const saved = await share.PermissionEntity.Save();
|
|
406
|
-
if (!saved) {
|
|
407
|
-
throw new Error(`Failed to save share for ${share.User.Name}: ${share.PermissionEntity.LatestResult?.Message ?? 'unknown error'}`);
|
|
408
|
-
}
|
|
524
|
+
for (const grant of this.Grants.filter((g) => !g.MarkedForRemoval && (g.IsNew || g.LevelTouched))) {
|
|
525
|
+
await this.applyGrant(grant, contexts);
|
|
409
526
|
}
|
|
410
527
|
if (this.Adapter.AfterSave) {
|
|
411
|
-
|
|
528
|
+
for (const context of contexts) {
|
|
529
|
+
await this.Adapter.AfterSave(context);
|
|
530
|
+
}
|
|
412
531
|
}
|
|
413
532
|
this.Result.emit({ Action: 'save' });
|
|
414
533
|
}
|
|
@@ -421,10 +540,49 @@ export class GenericShareDialogComponent extends BaseAngularComponent {
|
|
|
421
540
|
this.cdr.detectChanges();
|
|
422
541
|
}
|
|
423
542
|
}
|
|
543
|
+
/**
|
|
544
|
+
* Withdraws a person's access from every resource that granted it. Each row
|
|
545
|
+
* leaves the grant once deleted, so a retry after a failure deletes only the
|
|
546
|
+
* rows still left.
|
|
547
|
+
*/
|
|
548
|
+
async withdrawGrant(grant) {
|
|
549
|
+
for (const [resourceId, row] of Array.from(grant.Rows.entries())) {
|
|
550
|
+
const deleted = await row.PermissionEntity.Delete();
|
|
551
|
+
if (!deleted) {
|
|
552
|
+
throw new Error(`Failed to remove share for ${grant.User.Name}: ${row.PermissionEntity.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
553
|
+
}
|
|
554
|
+
grant.Rows.delete(resourceId);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Writes the grant's level to every resource, creating a permission row for
|
|
559
|
+
* the ones this person did not already have access to. A row stays `IsNew`
|
|
560
|
+
* until it saves, so a retry after a failure saves the rows still unsaved.
|
|
561
|
+
*/
|
|
562
|
+
async applyGrant(grant, contexts) {
|
|
563
|
+
for (const context of contexts) {
|
|
564
|
+
let row = grant.Rows.get(context.ResourceID);
|
|
565
|
+
if (!row) {
|
|
566
|
+
row = await this.Adapter.CreateShare(context, grant.User);
|
|
567
|
+
row._InitialLevel = row.Level;
|
|
568
|
+
grant.Rows.set(context.ResourceID, row);
|
|
569
|
+
}
|
|
570
|
+
else if (!grant.LevelTouched && !row.IsNew) {
|
|
571
|
+
continue; // nothing changed for this resource
|
|
572
|
+
}
|
|
573
|
+
row.Level = grant.Level;
|
|
574
|
+
this.Adapter.SyncLevelToEntity(row);
|
|
575
|
+
const saved = await row.PermissionEntity.Save();
|
|
576
|
+
if (!saved) {
|
|
577
|
+
throw new Error(`Failed to save share for ${grant.User.Name}: ${row.PermissionEntity.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
578
|
+
}
|
|
579
|
+
row.IsNew = false;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
424
582
|
onCancel() {
|
|
425
583
|
this.Result.emit({ Action: 'cancel' });
|
|
426
584
|
}
|
|
427
|
-
|
|
585
|
+
GetUserInitials(user) {
|
|
428
586
|
const name = user.Name || user.Email || '?';
|
|
429
587
|
const parts = name.split(' ');
|
|
430
588
|
if (parts.length >= 2) {
|
|
@@ -432,24 +590,58 @@ export class GenericShareDialogComponent extends BaseAngularComponent {
|
|
|
432
590
|
}
|
|
433
591
|
return name.substring(0, 2).toUpperCase();
|
|
434
592
|
}
|
|
593
|
+
/** @deprecated Use {@link IsModified}. */
|
|
594
|
+
isModified(grant) {
|
|
595
|
+
return this.IsModified(grant);
|
|
596
|
+
}
|
|
597
|
+
/** @deprecated Use {@link AddUserShare}. */
|
|
598
|
+
async addUserShare(user) {
|
|
599
|
+
return this.AddUserShare(user);
|
|
600
|
+
}
|
|
601
|
+
/** @deprecated Use {@link RemoveUserShare}. */
|
|
602
|
+
removeUserShare(grant) {
|
|
603
|
+
return this.RemoveUserShare(grant);
|
|
604
|
+
}
|
|
605
|
+
/** @deprecated Use {@link UndoRemove}. */
|
|
606
|
+
undoRemove(grant) {
|
|
607
|
+
return this.UndoRemove(grant);
|
|
608
|
+
}
|
|
609
|
+
/** @deprecated Use {@link SetLevel}. */
|
|
610
|
+
setLevel(grant, level) {
|
|
611
|
+
return this.SetLevel(grant, level);
|
|
612
|
+
}
|
|
613
|
+
/** @deprecated Use {@link OnSave}. */
|
|
614
|
+
async onSave() {
|
|
615
|
+
return this.OnSave();
|
|
616
|
+
}
|
|
617
|
+
/** @deprecated Use {@link GetUserInitials}. */
|
|
618
|
+
getUserInitials(user) {
|
|
619
|
+
return this.GetUserInitials(user);
|
|
620
|
+
}
|
|
435
621
|
static ɵfac = function GenericShareDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || GenericShareDialogComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
436
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: GenericShareDialogComponent, selectors: [["mj-resource-share-dialog"]], inputs: { Visible: "Visible", Context: "Context", Adapter: "Adapter" }, outputs: { Result: "Result" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 1, vars: 1, consts: [[1, "mj-share-dialog-window", 3, "Visible", "Width", "MinHeight", "Resizable", "Draggable"], [1, "mj-share-dialog-window", 3, "Close", "Visible", "Width", "MinHeight", "Resizable", "Draggable"], [1, "share-dialog-header"], [1, "fa-solid", "fa-share-nodes"], [1, "share-dialog-body"], ["Variant", "error"], [1, "share-section"], [1, "share-search-box"], [1, "fa-solid", "fa-search"], ["type", "text", "placeholder", "Add people by name or email...", 3, "ngModelChange", "ngModel", "disabled"], [1, "share-user-dropdown"], ["Variant", "no-results", "Icon", "fa-solid fa-user-slash", "Size", "compact", 3, "Title"], [1, "share-section-label"], [1, "share-person", "share-owner"], [1, "share-person", 3, "share-person-new", "share-person-modified"], ["Icon", "fa-solid fa-user-lock", "Title", "Not shared with anyone yet", "Size", "compact"], [1, "share-removed-section"], [1, "share-footer"], [1, "share-changes-hint"], [1, "share-footer-actions"], ["type", "button", 1, "share-btn", "share-btn-secondary", 3, "click"], ["type", "button", 1, "share-btn", "share-btn-primary", 3, "click", "disabled"], ["type", "button", 1, "share-user-option", 3, "disabled"], ["type", "button", 1, "share-user-option", 3, "click", "disabled"], [1, "share-avatar"], [1, "share-user-name"], [1, "share-user-email"], [1, "fa-solid", "fa-plus"], [1, "share-avatar", "share-avatar-owner"], [1, "fa-solid", "fa-crown"], [1, "share-person-info"], [1, "share-person-name"], [1, "share-person-role"], [1, "share-person"], [1, "share-badge-new"], [1, "share-person-email"], ["role", "group", "aria-label", "Permission level", 1, "share-level-select"], ["type", "button", 1, "share-level-btn", 3, "active", "title"], ["type", "button", "title", "Remove", 1, "share-remove-btn", 3, "click"], [1, "fa-solid", "fa-times"], ["type", "button", 1, "share-level-btn", 3, "click", "title"], [1, "share-removed-item"], [1, "share-avatar", "share-avatar-removed"], [1, "share-removed-name"], ["type", "button", 1, "share-undo-btn", 3, "click"], [1, "fa-solid", "fa-undo"], [1, "fa-solid", "fa-circle"], [1, "fa-solid", "fa-spinner", "fa-spin"]], template: function GenericShareDialogComponent_Template(rf, ctx) { if (rf & 1) {
|
|
437
|
-
i0.ɵɵconditionalCreate(0, GenericShareDialogComponent_Conditional_0_Template,
|
|
622
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: GenericShareDialogComponent, selectors: [["mj-resource-share-dialog"]], inputs: { Visible: "Visible", Context: "Context", Contexts: "Contexts", Adapter: "Adapter", ResourceLabel: "ResourceLabel", Notice: "Notice" }, outputs: { Result: "Result" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 1, vars: 1, consts: [[1, "mj-share-dialog-window", 3, "Visible", "Width", "MinHeight", "Resizable", "Draggable"], [1, "mj-share-dialog-window", 3, "Close", "Visible", "Width", "MinHeight", "Resizable", "Draggable"], [1, "share-dialog-header"], [1, "fa-solid", "fa-share-nodes"], [1, "share-dialog-body"], ["Variant", "error"], [1, "share-notice"], [1, "share-section"], [1, "share-search-box"], [1, "fa-solid", "fa-search"], ["type", "text", "placeholder", "Add people by name or email...", 3, "ngModelChange", "ngModel", "disabled"], [1, "share-user-dropdown"], ["Variant", "no-results", "Icon", "fa-solid fa-user-slash", "Size", "compact", 3, "Title"], [1, "share-section-label"], [1, "share-person", "share-owner"], [1, "share-person", 3, "share-person-new", "share-person-modified"], ["Icon", "fa-solid fa-user-lock", "Title", "Not shared with anyone yet", "Size", "compact"], [1, "share-removed-section"], [1, "share-footer"], [1, "share-changes-hint"], [1, "share-footer-actions"], ["type", "button", 1, "share-btn", "share-btn-secondary", 3, "click"], ["type", "button", 1, "share-btn", "share-btn-primary", 3, "click", "disabled"], [1, "fa-solid", "fa-circle-info"], ["type", "button", 1, "share-user-option", 3, "disabled"], ["type", "button", 1, "share-user-option", 3, "click", "disabled"], [1, "share-avatar"], [1, "share-user-name"], [1, "share-user-email"], [1, "fa-solid", "fa-plus"], [1, "share-avatar", "share-avatar-owner"], [1, "fa-solid", "fa-crown"], [1, "share-person-info"], [1, "share-person-name"], [1, "share-person-role"], [1, "share-person"], [1, "share-badge-new"], [1, "share-person-email"], [1, "share-person-scope"], ["role", "group", "aria-label", "Permission level", 1, "share-level-select"], ["type", "button", 1, "share-level-btn", 3, "active", "title"], ["type", "button", "title", "Remove", 1, "share-remove-btn", 3, "click"], [1, "fa-solid", "fa-times"], ["type", "button", 1, "share-level-btn", 3, "click", "title"], [1, "share-removed-item"], [1, "share-avatar", "share-avatar-removed"], [1, "share-removed-name"], ["type", "button", 1, "share-undo-btn", 3, "click"], [1, "fa-solid", "fa-undo"], [1, "fa-solid", "fa-circle"], [1, "fa-solid", "fa-spinner", "fa-spin"]], template: function GenericShareDialogComponent_Template(rf, ctx) { if (rf & 1) {
|
|
623
|
+
i0.ɵɵconditionalCreate(0, GenericShareDialogComponent_Conditional_0_Template, 31, 18, "mj-window", 0);
|
|
438
624
|
} if (rf & 2) {
|
|
439
625
|
i0.ɵɵconditional(ctx.Visible ? 0 : -1);
|
|
440
|
-
} }, dependencies: [i1.DefaultValueAccessor, i1.NgControlStatus, i1.NgModel, i2.MJEmptyStateComponent, i2.MJWindowComponent, i2.MJWindowTitlebarComponent, i2.MJAlertComponent], styles: ["/* Generic Resource Share Dialog - Compact Design */\n\n/* Window container \u2014 overrides the default `<mj-window>` surface styling with a\n * larger radius + accent shadow so the dialog reads as an \"action surface\". */\n.mj-share-dialog-window .mj-window {\n border-radius: 12px !important;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2) !important;\n overflow: hidden !important;\n}\n\n/* Branded titlebar: accent background so the header reads as chrome rather than\n * another surface panel. Text uses `--mj-text-inverse` because the background is\n * `--mj-brand-primary` \u2014 `--mj-text-inverse` is defined as \"legible on a\n * colored/dark accent\", not \"light mode-only white\". */\n.mj-share-dialog-window .mj-window-titlebar {\n background: var(--mj-brand-primary) !important;\n border: none !important;\n padding: 16px 20px !important;\n cursor: move;\n}\n\n/* The default title slot isn't rendered (we pass no `Title` input), but hide\n * it defensively in case a future refactor sets one \u2014 we already show our own\n * branded header via `<mj-window-titlebar>`. */\n.mj-share-dialog-window .mj-window-title {\n display: none !important;\n}\n\n/* Close button: tint against the accent titlebar to match the inverse text color. */\n.mj-share-dialog-window .mj-window-close {\n background: color-mix(in srgb, var(--mj-bg-surface) 15%, transparent) !important;\n border: none !important;\n color: var(--mj-text-inverse) !important;\n border-radius: 4px !important;\n}\n\n.mj-share-dialog-window .mj-window-close:hover {\n background: color-mix(in srgb, var(--mj-bg-surface) 25%, transparent) !important;\n color: var(--mj-text-inverse) !important;\n}\n\n.mj-share-dialog-window .mj-window-body {\n padding: 0 !important;\n background: var(--mj-bg-surface) !important;\n}\n\n/* Header */\n.share-dialog-header {\n display: flex;\n align-items: center;\n gap: 10px;\n color: var(--mj-text-inverse);\n font-size: 16px;\n font-weight: 500;\n}\n\n.share-dialog-header i {\n font-size: 18px;\n opacity: 0.9;\n}\n\n/* Body */\n.share-dialog-body {\n padding: 0;\n}\n\n/* Sections */\n.share-section {\n padding: 16px 20px;\n}\n\n.share-section:not(:last-child) {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.share-section-label {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 12px;\n}\n\n/* Search Box */\n.share-search-box {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n border: 1px solid transparent;\n transition: all 0.15s;\n}\n\n.share-search-box:focus-within {\n background: var(--mj-bg-surface);\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.share-search-box i {\n color: var(--mj-text-disabled);\n font-size: 14px;\n}\n\n.share-search-box input {\n flex: 1;\n border: none;\n background: transparent;\n font-size: 14px;\n outline: none;\n}\n\n.share-search-box input::placeholder {\n color: var(--mj-text-disabled);\n}\n\n/* User Dropdown */\n.share-user-dropdown {\n margin-top: 8px;\n max-height: 180px;\n overflow-y: auto;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface-card);\n}\n\n/* User Option */\n.share-user-option {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 10px 12px;\n border: none;\n background: transparent;\n cursor: pointer;\n text-align: left;\n transition: background 0.1s;\n}\n\n.share-user-option:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.share-user-option:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.share-user-option .share-user-name {\n flex: 1;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.share-user-option .share-user-email {\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-right: auto;\n}\n\n.share-user-option i.fa-plus {\n color: var(--mj-brand-primary);\n font-size: 12px;\n opacity: 0;\n transition: opacity 0.1s;\n}\n\n.share-user-option:hover i.fa-plus {\n opacity: 1;\n}\n\n/* Avatar */\n.share-avatar {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 12px;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.share-avatar-owner {\n background: var(--mj-status-warning);\n font-size: 14px;\n}\n\n.share-avatar-removed {\n background: var(--mj-border-strong);\n}\n\n/* Person Row */\n.share-person {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 0;\n}\n\n.share-person:not(:last-child) {\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n}\n\n.share-person-new {\n background: color-mix(in srgb, var(--mj-status-success) 5%, transparent);\n margin: 0 -20px;\n padding: 10px 20px;\n}\n\n.share-person-modified {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n margin: 0 -20px;\n padding: 10px 20px;\n}\n\n.share-person-info {\n flex: 1;\n min-width: 0;\n}\n\n.share-person-name {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.share-person-email {\n font-size: 12px;\n color: var(--mj-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.share-person-role {\n font-size: 12px;\n color: var(--mj-status-warning);\n font-weight: 500;\n}\n\n.share-badge-new {\n padding: 2px 6px;\n background: var(--mj-status-success);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n border-radius: 4px;\n}\n\n/* Level selector (segmented control) */\n.share-level-select {\n display: inline-flex;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n.share-level-btn {\n padding: 4px 12px;\n border: none;\n background: transparent;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: background 0.1s, color 0.1s;\n}\n\n.share-level-btn:not(:last-child) {\n border-right: 1px solid var(--mj-border-default);\n}\n\n.share-level-btn:hover:not(.active) {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n color: var(--mj-text-primary);\n}\n\n.share-level-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n/* Legacy checkbox classes (kept but unused now). */\n.share-permissions {\n display: flex;\n gap: 4px;\n}\n\n.share-perm {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.1s;\n position: relative;\n}\n\n.share-perm input {\n position: absolute;\n opacity: 0;\n cursor: pointer;\n}\n\n.share-perm i {\n font-size: 12px;\n color: var(--mj-border-strong);\n transition: color 0.1s;\n}\n\n.share-perm:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.share-perm input:checked + i {\n color: var(--mj-brand-primary);\n}\n\n.share-perm input:disabled + i {\n color: var(--mj-brand-primary);\n opacity: 0.7;\n}\n\n/* Remove Button */\n.share-remove-btn {\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: var(--mj-border-strong);\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.1s;\n}\n\n.share-remove-btn:hover {\n background: var(--mj-bg-error);\n color: var(--mj-status-error);\n}\n\n/* Removed Section */\n.share-removed-section {\n margin-top: 12px;\n padding: 12px;\n background: var(--mj-bg-warning);\n border-radius: 8px;\n border: 1px solid var(--mj-border-warning);\n}\n\n.share-removed-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 6px 0;\n}\n\n.share-removed-name {\n flex: 1;\n font-size: 13px;\n color: var(--mj-text-secondary);\n text-decoration: line-through;\n}\n\n.share-undo-btn {\n padding: 4px 10px;\n border: none;\n background: transparent;\n color: var(--mj-status-warning);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.share-undo-btn:hover {\n text-decoration: underline;\n}\n\n/* Footer */\n.share-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-default);\n}\n\n.share-changes-hint {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-brand-primary);\n}\n\n.share-changes-hint i {\n font-size: 6px;\n}\n\n.share-footer-actions {\n display: flex;\n gap: 10px;\n margin-left: auto;\n}\n\n.share-btn {\n padding: 8px 18px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.share-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.share-btn-secondary {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n color: var(--mj-text-secondary);\n}\n\n.share-btn-secondary:hover:not(:disabled) {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n}\n\n.share-btn-primary {\n background: var(--mj-brand-primary);\n border: none;\n color: var(--mj-text-inverse);\n}\n\n.share-btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n}\n\n/* Owner row specific styling */\n.share-owner {\n background: var(--mj-bg-warning);\n margin: 0 -20px;\n padding: 10px 20px;\n border-radius: 0;\n}\n"], encapsulation: 2 });
|
|
626
|
+
} }, dependencies: [i1.DefaultValueAccessor, i1.NgControlStatus, i1.NgModel, i2.MJEmptyStateComponent, i2.MJWindowComponent, i2.MJWindowTitlebarComponent, i2.MJAlertComponent], styles: ["/* Generic Resource Share Dialog - Compact Design */\n\n/* Window container \u2014 overrides the default `<mj-window>` surface styling with a\n * larger radius + accent shadow so the dialog reads as an \"action surface\". */\n.mj-share-dialog-window .mj-window {\n border-radius: 12px !important;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2) !important;\n overflow: hidden !important;\n}\n\n/* Branded titlebar: accent background so the header reads as chrome rather than\n * another surface panel. Text uses `--mj-text-inverse` because the background is\n * `--mj-brand-primary` \u2014 `--mj-text-inverse` is defined as \"legible on a\n * colored/dark accent\", not \"light mode-only white\". */\n.mj-share-dialog-window .mj-window-titlebar {\n background: var(--mj-brand-primary) !important;\n border: none !important;\n padding: 16px 20px !important;\n cursor: move;\n}\n\n/* The default title slot isn't rendered (we pass no `Title` input), but hide\n * it defensively in case a future refactor sets one \u2014 we already show our own\n * branded header via `<mj-window-titlebar>`. */\n.mj-share-dialog-window .mj-window-title {\n display: none !important;\n}\n\n/* Close button: tint against the accent titlebar to match the inverse text color. */\n.mj-share-dialog-window .mj-window-close {\n background: color-mix(in srgb, var(--mj-bg-surface) 15%, transparent) !important;\n border: none !important;\n color: var(--mj-text-inverse) !important;\n border-radius: 4px !important;\n}\n\n.mj-share-dialog-window .mj-window-close:hover {\n background: color-mix(in srgb, var(--mj-bg-surface) 25%, transparent) !important;\n color: var(--mj-text-inverse) !important;\n}\n\n.mj-share-dialog-window .mj-window-body {\n padding: 0 !important;\n background: var(--mj-bg-surface) !important;\n}\n\n/* Header */\n.share-dialog-header {\n display: flex;\n align-items: center;\n gap: 10px;\n color: var(--mj-text-inverse);\n font-size: 16px;\n font-weight: 500;\n}\n\n.share-dialog-header i {\n font-size: 18px;\n opacity: 0.9;\n}\n\n/* Body */\n.share-dialog-body {\n padding: 0;\n}\n\n/* Sections */\n.share-section {\n padding: 16px 20px;\n}\n\n.share-section:not(:last-child) {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.share-section-label {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 12px;\n}\n\n/* Search Box */\n.share-search-box {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n border: 1px solid transparent;\n transition: all 0.15s;\n}\n\n.share-search-box:focus-within {\n background: var(--mj-bg-surface);\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.share-search-box i {\n color: var(--mj-text-disabled);\n font-size: 14px;\n}\n\n.share-search-box input {\n flex: 1;\n border: none;\n background: transparent;\n font-size: 14px;\n outline: none;\n}\n\n.share-search-box input::placeholder {\n color: var(--mj-text-disabled);\n}\n\n/* User Dropdown */\n.share-user-dropdown {\n margin-top: 8px;\n max-height: 180px;\n overflow-y: auto;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface-card);\n}\n\n/* User Option */\n.share-user-option {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 10px 12px;\n border: none;\n background: transparent;\n cursor: pointer;\n text-align: left;\n transition: background 0.1s;\n}\n\n.share-user-option:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.share-user-option:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.share-user-option .share-user-name {\n flex: 1;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.share-user-option .share-user-email {\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-right: auto;\n}\n\n.share-user-option i.fa-plus {\n color: var(--mj-brand-primary);\n font-size: 12px;\n opacity: 0;\n transition: opacity 0.1s;\n}\n\n.share-user-option:hover i.fa-plus {\n opacity: 1;\n}\n\n/* Avatar */\n.share-avatar {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 12px;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.share-avatar-owner {\n background: var(--mj-status-warning);\n font-size: 14px;\n}\n\n.share-avatar-removed {\n background: var(--mj-border-strong);\n}\n\n/* Person Row */\n.share-person {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 0;\n}\n\n.share-person:not(:last-child) {\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n}\n\n.share-person-new {\n background: color-mix(in srgb, var(--mj-status-success) 5%, transparent);\n margin: 0 -20px;\n padding: 10px 20px;\n}\n\n.share-person-modified {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n margin: 0 -20px;\n padding: 10px 20px;\n}\n\n.share-person-info {\n flex: 1;\n min-width: 0;\n}\n\n.share-person-name {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.share-person-email {\n font-size: 12px;\n color: var(--mj-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.share-person-role {\n font-size: 12px;\n color: var(--mj-status-warning);\n font-weight: 500;\n}\n\n.share-badge-new {\n padding: 2px 6px;\n background: var(--mj-status-success);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n border-radius: 4px;\n}\n\n/* Level selector (segmented control) */\n.share-level-select {\n display: inline-flex;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n.share-level-btn {\n padding: 4px 12px;\n border: none;\n background: transparent;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: background 0.1s, color 0.1s;\n}\n\n.share-level-btn:not(:last-child) {\n border-right: 1px solid var(--mj-border-default);\n}\n\n.share-level-btn:hover:not(.active) {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n color: var(--mj-text-primary);\n}\n\n.share-level-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n/* Legacy checkbox classes (kept but unused now). */\n.share-permissions {\n display: flex;\n gap: 4px;\n}\n\n.share-perm {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.1s;\n position: relative;\n}\n\n.share-perm input {\n position: absolute;\n opacity: 0;\n cursor: pointer;\n}\n\n.share-perm i {\n font-size: 12px;\n color: var(--mj-border-strong);\n transition: color 0.1s;\n}\n\n.share-perm:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.share-perm input:checked + i {\n color: var(--mj-brand-primary);\n}\n\n.share-perm input:disabled + i {\n color: var(--mj-brand-primary);\n opacity: 0.7;\n}\n\n/* Remove Button */\n.share-remove-btn {\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: var(--mj-border-strong);\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.1s;\n}\n\n.share-remove-btn:hover {\n background: var(--mj-bg-error);\n color: var(--mj-status-error);\n}\n\n/* Removed Section */\n.share-removed-section {\n margin-top: 12px;\n padding: 12px;\n background: var(--mj-bg-warning);\n border-radius: 8px;\n border: 1px solid var(--mj-border-warning);\n}\n\n.share-removed-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 6px 0;\n}\n\n.share-removed-name {\n flex: 1;\n font-size: 13px;\n color: var(--mj-text-secondary);\n text-decoration: line-through;\n}\n\n.share-undo-btn {\n padding: 4px 10px;\n border: none;\n background: transparent;\n color: var(--mj-status-warning);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.share-undo-btn:hover {\n text-decoration: underline;\n}\n\n/* Footer */\n.share-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-default);\n}\n\n.share-changes-hint {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-brand-primary);\n}\n\n.share-changes-hint i {\n font-size: 6px;\n}\n\n.share-footer-actions {\n display: flex;\n gap: 10px;\n margin-left: auto;\n}\n\n.share-btn {\n padding: 8px 18px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.share-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.share-btn-secondary {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n color: var(--mj-text-secondary);\n}\n\n.share-btn-secondary:hover:not(:disabled) {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n}\n\n.share-btn-primary {\n background: var(--mj-brand-primary);\n border: none;\n color: var(--mj-text-inverse);\n}\n\n.share-btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n}\n\n/* Owner row specific styling */\n.share-owner {\n background: var(--mj-bg-warning);\n margin: 0 -20px;\n padding: 10px 20px;\n border-radius: 0;\n}\n\n/* Caller-supplied line above the body \u2014 e.g. what a bulk share left out. */\n.mj-share-dialog-window .share-notice {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n padding: 8px 12px;\n margin-bottom: 12px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-status-warning) 12%, transparent);\n color: var(--mj-text-primary);\n font-size: 13px;\n}\n\n/* Why a grant is not simply \"everyone, one level\": mixed levels or partial coverage. */\n.mj-share-dialog-window .share-person-scope {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n"], encapsulation: 2 });
|
|
441
627
|
}
|
|
442
628
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(GenericShareDialogComponent, [{
|
|
443
629
|
type: Component,
|
|
444
|
-
args: [{ standalone: false, selector: 'mj-resource-share-dialog', encapsulation: ViewEncapsulation.None, template: "@if (Visible) {\n <mj-window\n [Visible]=\"true\"\n [Width]=\"560\"\n [MinHeight]=\"200\"\n [Resizable]=\"false\"\n [Draggable]=\"true\"\n (Close)=\"onCancel()\"\n class=\"mj-share-dialog-window\">\n <mj-window-titlebar>\n <div class=\"share-dialog-header\">\n <i class=\"fa-solid fa-share-nodes\"></i>\n <span>Share \"{{ Context?.ResourceName }}\"</span>\n </div>\n </mj-window-titlebar>\n <div class=\"share-dialog-body\">\n @if (Error) {\n <mj-alert Variant=\"error\">{{ Error }}</mj-alert>\n }\n <!-- Add Users Section -->\n <div class=\"share-section\">\n <div class=\"share-search-box\">\n <i class=\"fa-solid fa-search\"></i>\n <input\n type=\"text\"\n placeholder=\"Add people by name or email...\"\n [(ngModel)]=\"UserSearchFilter\"\n [disabled]=\"IsLoading\">\n </div>\n @if (FilteredAvailableUsers.length > 0) {\n <div class=\"share-user-dropdown\">\n @for (user of FilteredAvailableUsers; track user.ID) {\n <button type=\"button\" class=\"share-user-option\" (click)=\"addUserShare(user)\" [disabled]=\"IsLoading\">\n <span class=\"share-avatar\">{{ getUserInitials(user) }}</span>\n <span class=\"share-user-name\">{{ user.Name }}</span>\n @if (user.Email) {\n <span class=\"share-user-email\">{{ user.Email }}</span>\n }\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n }\n </div>\n }\n @if (UserSearchFilter && FilteredAvailableUsers.length === 0) {\n <mj-empty-state\n Variant=\"no-results\"\n Icon=\"fa-solid fa-user-slash\"\n [Title]=\"NoUsersFoundMessage\"\n Size=\"compact\" />\n }\n </div>\n <!-- People with Access -->\n <div class=\"share-section\">\n <div class=\"share-section-label\">People with access</div>\n @if (Context?.OwnerDisplayName) {\n <div class=\"share-person share-owner\">\n <span class=\"share-avatar share-avatar-owner\">\n <i class=\"fa-solid fa-crown\"></i>\n </span>\n <div class=\"share-person-info\">\n <span class=\"share-person-name\">{{ Context?.OwnerDisplayName }}</span>\n <span class=\"share-person-role\">Owner</span>\n </div>\n </div>\n }\n @for (share of ActiveShares; track share.User.ID) {\n <div class=\"share-person\" [class.share-person-new]=\"share.IsNew\" [class.share-person-modified]=\"isModified(share)\">\n <span class=\"share-avatar\">{{ getUserInitials(share.User) }}</span>\n <div class=\"share-person-info\">\n <span class=\"share-person-name\">\n {{ share.User.Name }}\n @if (share.IsNew) {\n <span class=\"share-badge-new\">New</span>\n }\n </span>\n @if (share.User.Email) {\n <span class=\"share-person-email\">{{ share.User.Email }}</span>\n }\n </div>\n <div class=\"share-level-select\" role=\"group\" aria-label=\"Permission level\">\n @for (level of Levels; track level) {\n <button type=\"button\"\n class=\"share-level-btn\"\n [class.active]=\"share.Level === level\"\n (click)=\"setLevel(share, level)\"\n [title]=\"level + ' access'\">\n {{ level }}\n </button>\n }\n </div>\n <button type=\"button\" class=\"share-remove-btn\" (click)=\"removeUserShare(share)\" title=\"Remove\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n @if (ActiveShares.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-user-lock\"\n Title=\"Not shared with anyone yet\"\n Size=\"compact\" />\n }\n @if (RemovedShares.length > 0) {\n <div class=\"share-removed-section\">\n @for (share of RemovedShares; track share.User.ID) {\n <div class=\"share-removed-item\">\n <span class=\"share-avatar share-avatar-removed\">{{ getUserInitials(share.User) }}</span>\n <span class=\"share-removed-name\">{{ share.User.Name }}</span>\n <button type=\"button\" class=\"share-undo-btn\" (click)=\"undoRemove(share)\">\n <i class=\"fa-solid fa-undo\"></i> Undo\n </button>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"share-footer\">\n @if (HasChanges) {\n <span class=\"share-changes-hint\">\n <i class=\"fa-solid fa-circle\"></i> Unsaved changes\n </span>\n }\n <div class=\"share-footer-actions\">\n <button type=\"button\" class=\"share-btn share-btn-secondary\" (click)=\"onCancel()\">\n Cancel\n </button>\n <button\n type=\"button\"\n class=\"share-btn share-btn-primary\"\n (click)=\"onSave()\"\n [disabled]=\"!HasChanges || IsLoading\">\n @if (IsLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving...\n } @else {\n Save\n }\n </button>\n </div>\n </div>\n </div>\n </mj-window>\n}\n", styles: ["/* Generic Resource Share Dialog - Compact Design */\n\n/* Window container \u2014 overrides the default `<mj-window>` surface styling with a\n * larger radius + accent shadow so the dialog reads as an \"action surface\". */\n.mj-share-dialog-window .mj-window {\n border-radius: 12px !important;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2) !important;\n overflow: hidden !important;\n}\n\n/* Branded titlebar: accent background so the header reads as chrome rather than\n * another surface panel. Text uses `--mj-text-inverse` because the background is\n * `--mj-brand-primary` \u2014 `--mj-text-inverse` is defined as \"legible on a\n * colored/dark accent\", not \"light mode-only white\". */\n.mj-share-dialog-window .mj-window-titlebar {\n background: var(--mj-brand-primary) !important;\n border: none !important;\n padding: 16px 20px !important;\n cursor: move;\n}\n\n/* The default title slot isn't rendered (we pass no `Title` input), but hide\n * it defensively in case a future refactor sets one \u2014 we already show our own\n * branded header via `<mj-window-titlebar>`. */\n.mj-share-dialog-window .mj-window-title {\n display: none !important;\n}\n\n/* Close button: tint against the accent titlebar to match the inverse text color. */\n.mj-share-dialog-window .mj-window-close {\n background: color-mix(in srgb, var(--mj-bg-surface) 15%, transparent) !important;\n border: none !important;\n color: var(--mj-text-inverse) !important;\n border-radius: 4px !important;\n}\n\n.mj-share-dialog-window .mj-window-close:hover {\n background: color-mix(in srgb, var(--mj-bg-surface) 25%, transparent) !important;\n color: var(--mj-text-inverse) !important;\n}\n\n.mj-share-dialog-window .mj-window-body {\n padding: 0 !important;\n background: var(--mj-bg-surface) !important;\n}\n\n/* Header */\n.share-dialog-header {\n display: flex;\n align-items: center;\n gap: 10px;\n color: var(--mj-text-inverse);\n font-size: 16px;\n font-weight: 500;\n}\n\n.share-dialog-header i {\n font-size: 18px;\n opacity: 0.9;\n}\n\n/* Body */\n.share-dialog-body {\n padding: 0;\n}\n\n/* Sections */\n.share-section {\n padding: 16px 20px;\n}\n\n.share-section:not(:last-child) {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.share-section-label {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 12px;\n}\n\n/* Search Box */\n.share-search-box {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n border: 1px solid transparent;\n transition: all 0.15s;\n}\n\n.share-search-box:focus-within {\n background: var(--mj-bg-surface);\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.share-search-box i {\n color: var(--mj-text-disabled);\n font-size: 14px;\n}\n\n.share-search-box input {\n flex: 1;\n border: none;\n background: transparent;\n font-size: 14px;\n outline: none;\n}\n\n.share-search-box input::placeholder {\n color: var(--mj-text-disabled);\n}\n\n/* User Dropdown */\n.share-user-dropdown {\n margin-top: 8px;\n max-height: 180px;\n overflow-y: auto;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface-card);\n}\n\n/* User Option */\n.share-user-option {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 10px 12px;\n border: none;\n background: transparent;\n cursor: pointer;\n text-align: left;\n transition: background 0.1s;\n}\n\n.share-user-option:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.share-user-option:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.share-user-option .share-user-name {\n flex: 1;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.share-user-option .share-user-email {\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-right: auto;\n}\n\n.share-user-option i.fa-plus {\n color: var(--mj-brand-primary);\n font-size: 12px;\n opacity: 0;\n transition: opacity 0.1s;\n}\n\n.share-user-option:hover i.fa-plus {\n opacity: 1;\n}\n\n/* Avatar */\n.share-avatar {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 12px;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.share-avatar-owner {\n background: var(--mj-status-warning);\n font-size: 14px;\n}\n\n.share-avatar-removed {\n background: var(--mj-border-strong);\n}\n\n/* Person Row */\n.share-person {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 0;\n}\n\n.share-person:not(:last-child) {\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n}\n\n.share-person-new {\n background: color-mix(in srgb, var(--mj-status-success) 5%, transparent);\n margin: 0 -20px;\n padding: 10px 20px;\n}\n\n.share-person-modified {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n margin: 0 -20px;\n padding: 10px 20px;\n}\n\n.share-person-info {\n flex: 1;\n min-width: 0;\n}\n\n.share-person-name {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.share-person-email {\n font-size: 12px;\n color: var(--mj-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.share-person-role {\n font-size: 12px;\n color: var(--mj-status-warning);\n font-weight: 500;\n}\n\n.share-badge-new {\n padding: 2px 6px;\n background: var(--mj-status-success);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n border-radius: 4px;\n}\n\n/* Level selector (segmented control) */\n.share-level-select {\n display: inline-flex;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n.share-level-btn {\n padding: 4px 12px;\n border: none;\n background: transparent;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: background 0.1s, color 0.1s;\n}\n\n.share-level-btn:not(:last-child) {\n border-right: 1px solid var(--mj-border-default);\n}\n\n.share-level-btn:hover:not(.active) {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n color: var(--mj-text-primary);\n}\n\n.share-level-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n/* Legacy checkbox classes (kept but unused now). */\n.share-permissions {\n display: flex;\n gap: 4px;\n}\n\n.share-perm {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.1s;\n position: relative;\n}\n\n.share-perm input {\n position: absolute;\n opacity: 0;\n cursor: pointer;\n}\n\n.share-perm i {\n font-size: 12px;\n color: var(--mj-border-strong);\n transition: color 0.1s;\n}\n\n.share-perm:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.share-perm input:checked + i {\n color: var(--mj-brand-primary);\n}\n\n.share-perm input:disabled + i {\n color: var(--mj-brand-primary);\n opacity: 0.7;\n}\n\n/* Remove Button */\n.share-remove-btn {\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: var(--mj-border-strong);\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.1s;\n}\n\n.share-remove-btn:hover {\n background: var(--mj-bg-error);\n color: var(--mj-status-error);\n}\n\n/* Removed Section */\n.share-removed-section {\n margin-top: 12px;\n padding: 12px;\n background: var(--mj-bg-warning);\n border-radius: 8px;\n border: 1px solid var(--mj-border-warning);\n}\n\n.share-removed-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 6px 0;\n}\n\n.share-removed-name {\n flex: 1;\n font-size: 13px;\n color: var(--mj-text-secondary);\n text-decoration: line-through;\n}\n\n.share-undo-btn {\n padding: 4px 10px;\n border: none;\n background: transparent;\n color: var(--mj-status-warning);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.share-undo-btn:hover {\n text-decoration: underline;\n}\n\n/* Footer */\n.share-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-default);\n}\n\n.share-changes-hint {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-brand-primary);\n}\n\n.share-changes-hint i {\n font-size: 6px;\n}\n\n.share-footer-actions {\n display: flex;\n gap: 10px;\n margin-left: auto;\n}\n\n.share-btn {\n padding: 8px 18px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.share-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.share-btn-secondary {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n color: var(--mj-text-secondary);\n}\n\n.share-btn-secondary:hover:not(:disabled) {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n}\n\n.share-btn-primary {\n background: var(--mj-brand-primary);\n border: none;\n color: var(--mj-text-inverse);\n}\n\n.share-btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n}\n\n/* Owner row specific styling */\n.share-owner {\n background: var(--mj-bg-warning);\n margin: 0 -20px;\n padding: 10px 20px;\n border-radius: 0;\n}\n"] }]
|
|
630
|
+
args: [{ standalone: false, selector: 'mj-resource-share-dialog', encapsulation: ViewEncapsulation.None, template: "@if (Visible) {\n <mj-window\n [Visible]=\"true\"\n [Width]=\"560\"\n [MinHeight]=\"200\"\n [Resizable]=\"false\"\n [Draggable]=\"true\"\n (Close)=\"onCancel()\"\n class=\"mj-share-dialog-window\">\n <mj-window-titlebar>\n <div class=\"share-dialog-header\">\n <i class=\"fa-solid fa-share-nodes\"></i>\n <span>{{ Title }}</span>\n </div>\n </mj-window-titlebar>\n <div class=\"share-dialog-body\">\n @if (Error) {\n <mj-alert Variant=\"error\">{{ Error }}</mj-alert>\n }\n @if (Notice) {\n <div class=\"share-notice\">\n <i class=\"fa-solid fa-circle-info\"></i>\n <span>{{ Notice }}</span>\n </div>\n }\n <!-- Add Users Section -->\n <div class=\"share-section\">\n <div class=\"share-search-box\">\n <i class=\"fa-solid fa-search\"></i>\n <input\n type=\"text\"\n placeholder=\"Add people by name or email...\"\n [(ngModel)]=\"UserSearchFilter\"\n [disabled]=\"IsLoading\">\n </div>\n @if (FilteredAvailableUsers.length > 0) {\n <div class=\"share-user-dropdown\">\n @for (user of FilteredAvailableUsers; track user.ID) {\n <button type=\"button\" class=\"share-user-option\" (click)=\"AddUserShare(user)\" [disabled]=\"IsLoading\">\n <span class=\"share-avatar\">{{ GetUserInitials(user) }}</span>\n <span class=\"share-user-name\">{{ user.Name }}</span>\n @if (user.Email) {\n <span class=\"share-user-email\">{{ user.Email }}</span>\n }\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n }\n </div>\n }\n @if (UserSearchFilter && FilteredAvailableUsers.length === 0) {\n <mj-empty-state\n Variant=\"no-results\"\n Icon=\"fa-solid fa-user-slash\"\n [Title]=\"NoUsersFoundMessage\"\n Size=\"compact\" />\n }\n </div>\n <!-- People with Access -->\n <div class=\"share-section\">\n <div class=\"share-section-label\">People with access</div>\n @if (PrimaryContext?.OwnerDisplayName) {\n <div class=\"share-person share-owner\">\n <span class=\"share-avatar share-avatar-owner\">\n <i class=\"fa-solid fa-crown\"></i>\n </span>\n <div class=\"share-person-info\">\n <span class=\"share-person-name\">{{ PrimaryContext?.OwnerDisplayName }}</span>\n <span class=\"share-person-role\">Owner</span>\n </div>\n </div>\n }\n @for (share of ActiveShares; track share.User.ID) {\n <div class=\"share-person\" [class.share-person-new]=\"share.IsNew\" [class.share-person-modified]=\"IsModified(share)\">\n <span class=\"share-avatar\">{{ GetUserInitials(share.User) }}</span>\n <div class=\"share-person-info\">\n <span class=\"share-person-name\">\n {{ share.User.Name }}\n @if (share.IsNew) {\n <span class=\"share-badge-new\">New</span>\n }\n </span>\n @if (share.User.Email) {\n <span class=\"share-person-email\">{{ share.User.Email }}</span>\n }\n @if (ScopeLabel(share)) {\n <span class=\"share-person-scope\">{{ ScopeLabel(share) }}</span>\n }\n </div>\n <div class=\"share-level-select\" role=\"group\" aria-label=\"Permission level\">\n @for (level of Levels; track level) {\n <button type=\"button\"\n class=\"share-level-btn\"\n [class.active]=\"IsLevelActive(share, level)\"\n (click)=\"SetLevel(share, level)\"\n [title]=\"level + ' access'\">\n {{ level }}\n </button>\n }\n </div>\n <button type=\"button\" class=\"share-remove-btn\" (click)=\"RemoveUserShare(share)\" title=\"Remove\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n @if (ActiveShares.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-user-lock\"\n Title=\"Not shared with anyone yet\"\n Size=\"compact\" />\n }\n @if (RemovedShares.length > 0) {\n <div class=\"share-removed-section\">\n @for (share of RemovedShares; track share.User.ID) {\n <div class=\"share-removed-item\">\n <span class=\"share-avatar share-avatar-removed\">{{ GetUserInitials(share.User) }}</span>\n <span class=\"share-removed-name\">{{ share.User.Name }}</span>\n <button type=\"button\" class=\"share-undo-btn\" (click)=\"UndoRemove(share)\">\n <i class=\"fa-solid fa-undo\"></i> Undo\n </button>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"share-footer\">\n @if (HasChanges) {\n <span class=\"share-changes-hint\">\n <i class=\"fa-solid fa-circle\"></i> Unsaved changes\n </span>\n }\n <div class=\"share-footer-actions\">\n <button type=\"button\" class=\"share-btn share-btn-secondary\" (click)=\"onCancel()\">\n Cancel\n </button>\n <button\n type=\"button\"\n class=\"share-btn share-btn-primary\"\n (click)=\"OnSave()\"\n [disabled]=\"!HasChanges || IsLoading\">\n @if (IsLoading) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving...\n } @else {\n Save\n }\n </button>\n </div>\n </div>\n </div>\n </mj-window>\n}\n", styles: ["/* Generic Resource Share Dialog - Compact Design */\n\n/* Window container \u2014 overrides the default `<mj-window>` surface styling with a\n * larger radius + accent shadow so the dialog reads as an \"action surface\". */\n.mj-share-dialog-window .mj-window {\n border-radius: 12px !important;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2) !important;\n overflow: hidden !important;\n}\n\n/* Branded titlebar: accent background so the header reads as chrome rather than\n * another surface panel. Text uses `--mj-text-inverse` because the background is\n * `--mj-brand-primary` \u2014 `--mj-text-inverse` is defined as \"legible on a\n * colored/dark accent\", not \"light mode-only white\". */\n.mj-share-dialog-window .mj-window-titlebar {\n background: var(--mj-brand-primary) !important;\n border: none !important;\n padding: 16px 20px !important;\n cursor: move;\n}\n\n/* The default title slot isn't rendered (we pass no `Title` input), but hide\n * it defensively in case a future refactor sets one \u2014 we already show our own\n * branded header via `<mj-window-titlebar>`. */\n.mj-share-dialog-window .mj-window-title {\n display: none !important;\n}\n\n/* Close button: tint against the accent titlebar to match the inverse text color. */\n.mj-share-dialog-window .mj-window-close {\n background: color-mix(in srgb, var(--mj-bg-surface) 15%, transparent) !important;\n border: none !important;\n color: var(--mj-text-inverse) !important;\n border-radius: 4px !important;\n}\n\n.mj-share-dialog-window .mj-window-close:hover {\n background: color-mix(in srgb, var(--mj-bg-surface) 25%, transparent) !important;\n color: var(--mj-text-inverse) !important;\n}\n\n.mj-share-dialog-window .mj-window-body {\n padding: 0 !important;\n background: var(--mj-bg-surface) !important;\n}\n\n/* Header */\n.share-dialog-header {\n display: flex;\n align-items: center;\n gap: 10px;\n color: var(--mj-text-inverse);\n font-size: 16px;\n font-weight: 500;\n}\n\n.share-dialog-header i {\n font-size: 18px;\n opacity: 0.9;\n}\n\n/* Body */\n.share-dialog-body {\n padding: 0;\n}\n\n/* Sections */\n.share-section {\n padding: 16px 20px;\n}\n\n.share-section:not(:last-child) {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.share-section-label {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 12px;\n}\n\n/* Search Box */\n.share-search-box {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n border: 1px solid transparent;\n transition: all 0.15s;\n}\n\n.share-search-box:focus-within {\n background: var(--mj-bg-surface);\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.share-search-box i {\n color: var(--mj-text-disabled);\n font-size: 14px;\n}\n\n.share-search-box input {\n flex: 1;\n border: none;\n background: transparent;\n font-size: 14px;\n outline: none;\n}\n\n.share-search-box input::placeholder {\n color: var(--mj-text-disabled);\n}\n\n/* User Dropdown */\n.share-user-dropdown {\n margin-top: 8px;\n max-height: 180px;\n overflow-y: auto;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface-card);\n}\n\n/* User Option */\n.share-user-option {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 10px 12px;\n border: none;\n background: transparent;\n cursor: pointer;\n text-align: left;\n transition: background 0.1s;\n}\n\n.share-user-option:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.share-user-option:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.share-user-option .share-user-name {\n flex: 1;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.share-user-option .share-user-email {\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-right: auto;\n}\n\n.share-user-option i.fa-plus {\n color: var(--mj-brand-primary);\n font-size: 12px;\n opacity: 0;\n transition: opacity 0.1s;\n}\n\n.share-user-option:hover i.fa-plus {\n opacity: 1;\n}\n\n/* Avatar */\n.share-avatar {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 12px;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.share-avatar-owner {\n background: var(--mj-status-warning);\n font-size: 14px;\n}\n\n.share-avatar-removed {\n background: var(--mj-border-strong);\n}\n\n/* Person Row */\n.share-person {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 0;\n}\n\n.share-person:not(:last-child) {\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n}\n\n.share-person-new {\n background: color-mix(in srgb, var(--mj-status-success) 5%, transparent);\n margin: 0 -20px;\n padding: 10px 20px;\n}\n\n.share-person-modified {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n margin: 0 -20px;\n padding: 10px 20px;\n}\n\n.share-person-info {\n flex: 1;\n min-width: 0;\n}\n\n.share-person-name {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.share-person-email {\n font-size: 12px;\n color: var(--mj-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.share-person-role {\n font-size: 12px;\n color: var(--mj-status-warning);\n font-weight: 500;\n}\n\n.share-badge-new {\n padding: 2px 6px;\n background: var(--mj-status-success);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n border-radius: 4px;\n}\n\n/* Level selector (segmented control) */\n.share-level-select {\n display: inline-flex;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n.share-level-btn {\n padding: 4px 12px;\n border: none;\n background: transparent;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: background 0.1s, color 0.1s;\n}\n\n.share-level-btn:not(:last-child) {\n border-right: 1px solid var(--mj-border-default);\n}\n\n.share-level-btn:hover:not(.active) {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n color: var(--mj-text-primary);\n}\n\n.share-level-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n/* Legacy checkbox classes (kept but unused now). */\n.share-permissions {\n display: flex;\n gap: 4px;\n}\n\n.share-perm {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.1s;\n position: relative;\n}\n\n.share-perm input {\n position: absolute;\n opacity: 0;\n cursor: pointer;\n}\n\n.share-perm i {\n font-size: 12px;\n color: var(--mj-border-strong);\n transition: color 0.1s;\n}\n\n.share-perm:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.share-perm input:checked + i {\n color: var(--mj-brand-primary);\n}\n\n.share-perm input:disabled + i {\n color: var(--mj-brand-primary);\n opacity: 0.7;\n}\n\n/* Remove Button */\n.share-remove-btn {\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: var(--mj-border-strong);\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.1s;\n}\n\n.share-remove-btn:hover {\n background: var(--mj-bg-error);\n color: var(--mj-status-error);\n}\n\n/* Removed Section */\n.share-removed-section {\n margin-top: 12px;\n padding: 12px;\n background: var(--mj-bg-warning);\n border-radius: 8px;\n border: 1px solid var(--mj-border-warning);\n}\n\n.share-removed-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 6px 0;\n}\n\n.share-removed-name {\n flex: 1;\n font-size: 13px;\n color: var(--mj-text-secondary);\n text-decoration: line-through;\n}\n\n.share-undo-btn {\n padding: 4px 10px;\n border: none;\n background: transparent;\n color: var(--mj-status-warning);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.share-undo-btn:hover {\n text-decoration: underline;\n}\n\n/* Footer */\n.share-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-default);\n}\n\n.share-changes-hint {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-brand-primary);\n}\n\n.share-changes-hint i {\n font-size: 6px;\n}\n\n.share-footer-actions {\n display: flex;\n gap: 10px;\n margin-left: auto;\n}\n\n.share-btn {\n padding: 8px 18px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.share-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.share-btn-secondary {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n color: var(--mj-text-secondary);\n}\n\n.share-btn-secondary:hover:not(:disabled) {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-border-strong);\n}\n\n.share-btn-primary {\n background: var(--mj-brand-primary);\n border: none;\n color: var(--mj-text-inverse);\n}\n\n.share-btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n}\n\n/* Owner row specific styling */\n.share-owner {\n background: var(--mj-bg-warning);\n margin: 0 -20px;\n padding: 10px 20px;\n border-radius: 0;\n}\n\n/* Caller-supplied line above the body \u2014 e.g. what a bulk share left out. */\n.mj-share-dialog-window .share-notice {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n padding: 8px 12px;\n margin-bottom: 12px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-status-warning) 12%, transparent);\n color: var(--mj-text-primary);\n font-size: 13px;\n}\n\n/* Why a grant is not simply \"everyone, one level\": mixed levels or partial coverage. */\n.mj-share-dialog-window .share-person-scope {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n"] }]
|
|
445
631
|
}], () => [{ type: i0.ChangeDetectorRef }], { Visible: [{
|
|
446
632
|
type: Input
|
|
447
633
|
}], Context: [{
|
|
448
634
|
type: Input
|
|
635
|
+
}], Contexts: [{
|
|
636
|
+
type: Input
|
|
449
637
|
}], Adapter: [{
|
|
450
638
|
type: Input
|
|
639
|
+
}], ResourceLabel: [{
|
|
640
|
+
type: Input
|
|
641
|
+
}], Notice: [{
|
|
642
|
+
type: Input
|
|
451
643
|
}], Result: [{
|
|
452
644
|
type: Output
|
|
453
645
|
}] }); })();
|
|
454
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(GenericShareDialogComponent, { className: "GenericShareDialogComponent", filePath: "src/lib/resource-share-dialog.component.ts", lineNumber:
|
|
646
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(GenericShareDialogComponent, { className: "GenericShareDialogComponent", filePath: "src/lib/resource-share-dialog.component.ts", lineNumber: 35 }); })();
|
|
455
647
|
//# sourceMappingURL=resource-share-dialog.component.js.map
|