@memberjunction/ng-explorer-settings 5.49.0 → 5.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/module.d.ts +27 -26
- package/dist/lib/module.d.ts.map +1 -1
- package/dist/lib/module.js +5 -0
- package/dist/lib/module.js.map +1 -1
- package/dist/lib/user-app-config/user-app-config-content.component.d.ts +138 -0
- package/dist/lib/user-app-config/user-app-config-content.component.d.ts.map +1 -0
- package/dist/lib/user-app-config/user-app-config-content.component.js +753 -0
- package/dist/lib/user-app-config/user-app-config-content.component.js.map +1 -0
- package/dist/lib/user-app-config/user-app-config.component.d.ts +18 -97
- package/dist/lib/user-app-config/user-app-config.component.d.ts.map +1 -1
- package/dist/lib/user-app-config/user-app-config.component.js +39 -697
- package/dist/lib/user-app-config/user-app-config.component.js.map +1 -1
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +20 -20
|
@@ -1,329 +1,7 @@
|
|
|
1
|
-
import { Component, Input, Output, EventEmitter
|
|
2
|
-
import { LogError, LogStatus, LogStatusEx } from '@memberjunction/core';
|
|
3
|
-
import { UserInfoEngine } from '@memberjunction/core-entities';
|
|
4
|
-
import { ApplicationManager } from '@memberjunction/ng-base-application';
|
|
5
|
-
import { SharedService } from '@memberjunction/ng-shared';
|
|
6
|
-
import { UUIDsEqual } from '@memberjunction/global';
|
|
1
|
+
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
7
2
|
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
8
|
-
import { moveAndResequence, resequenceItems } from './user-app-config-reorder';
|
|
9
3
|
import * as i0 from "@angular/core";
|
|
10
|
-
import * as i1 from "
|
|
11
|
-
import * as i2 from "@memberjunction/ng-ui-components";
|
|
12
|
-
const _forTrack0 = ($index, $item) => $item.app.ID;
|
|
13
|
-
function UserAppConfigComponent_Conditional_0_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
14
|
-
i0.ɵɵelementStart(0, "div", 8);
|
|
15
|
-
i0.ɵɵelement(1, "mj-loading", 17);
|
|
16
|
-
i0.ɵɵelementEnd();
|
|
17
|
-
} }
|
|
18
|
-
function UserAppConfigComponent_Conditional_0_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
19
|
-
i0.ɵɵelementStart(0, "mj-alert", 9);
|
|
20
|
-
i0.ɵɵtext(1);
|
|
21
|
-
i0.ɵɵelementEnd();
|
|
22
|
-
} if (rf & 2) {
|
|
23
|
-
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
24
|
-
i0.ɵɵadvance();
|
|
25
|
-
i0.ɵɵtextInterpolate(ctx_r1.ErrorMessage);
|
|
26
|
-
} }
|
|
27
|
-
function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
28
|
-
i0.ɵɵelement(0, "mj-empty-state", 26);
|
|
29
|
-
} }
|
|
30
|
-
function UserAppConfigComponent_Conditional_0_Conditional_11_For_15_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
31
|
-
i0.ɵɵelementStart(0, "span", 39);
|
|
32
|
-
i0.ɵɵtext(1);
|
|
33
|
-
i0.ɵɵelementEnd();
|
|
34
|
-
} if (rf & 2) {
|
|
35
|
-
const item_r5 = i0.ɵɵnextContext().$implicit;
|
|
36
|
-
i0.ɵɵadvance();
|
|
37
|
-
i0.ɵɵtextInterpolate(item_r5.app.Description);
|
|
38
|
-
} }
|
|
39
|
-
function UserAppConfigComponent_Conditional_0_Conditional_11_For_15_Template(rf, ctx) { if (rf & 1) {
|
|
40
|
-
const _r4 = i0.ɵɵgetCurrentView();
|
|
41
|
-
i0.ɵɵelementStart(0, "div", 34);
|
|
42
|
-
i0.ɵɵlistener("dblclick", function UserAppConfigComponent_Conditional_0_Conditional_11_For_15_Template_div_dblclick_0_listener() { const item_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.AddApp(item_r5)); });
|
|
43
|
-
i0.ɵɵelementStart(1, "div", 35);
|
|
44
|
-
i0.ɵɵelement(2, "i", 36);
|
|
45
|
-
i0.ɵɵelementEnd();
|
|
46
|
-
i0.ɵɵelementStart(3, "div", 37)(4, "span", 38);
|
|
47
|
-
i0.ɵɵtext(5);
|
|
48
|
-
i0.ɵɵelementEnd();
|
|
49
|
-
i0.ɵɵconditionalCreate(6, UserAppConfigComponent_Conditional_0_Conditional_11_For_15_Conditional_6_Template, 2, 1, "span", 39);
|
|
50
|
-
i0.ɵɵelementEnd();
|
|
51
|
-
i0.ɵɵelementStart(7, "button", 40);
|
|
52
|
-
i0.ɵɵlistener("click", function UserAppConfigComponent_Conditional_0_Conditional_11_For_15_Template_button_click_7_listener() { const item_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.AddApp(item_r5)); });
|
|
53
|
-
i0.ɵɵelement(8, "i", 41);
|
|
54
|
-
i0.ɵɵtext(9, " Add ");
|
|
55
|
-
i0.ɵɵelementEnd()();
|
|
56
|
-
} if (rf & 2) {
|
|
57
|
-
const item_r5 = ctx.$implicit;
|
|
58
|
-
i0.ɵɵadvance();
|
|
59
|
-
i0.ɵɵstyleProp("background-color", item_r5.app.GetColor());
|
|
60
|
-
i0.ɵɵadvance();
|
|
61
|
-
i0.ɵɵclassMap(item_r5.app.Icon || "fa-solid fa-cube");
|
|
62
|
-
i0.ɵɵadvance(3);
|
|
63
|
-
i0.ɵɵtextInterpolate(item_r5.app.Name);
|
|
64
|
-
i0.ɵɵadvance();
|
|
65
|
-
i0.ɵɵconditional(item_r5.app.Description ? 6 : -1);
|
|
66
|
-
i0.ɵɵadvance();
|
|
67
|
-
i0.ɵɵattribute("aria-label", "Add " + item_r5.app.Name);
|
|
68
|
-
} }
|
|
69
|
-
function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_25_Template(rf, ctx) { if (rf & 1) {
|
|
70
|
-
i0.ɵɵelement(0, "mj-empty-state", 30);
|
|
71
|
-
} }
|
|
72
|
-
function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_26_For_2_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
73
|
-
i0.ɵɵelementStart(0, "span", 39);
|
|
74
|
-
i0.ɵɵtext(1);
|
|
75
|
-
i0.ɵɵelementEnd();
|
|
76
|
-
} if (rf & 2) {
|
|
77
|
-
const item_r9 = i0.ɵɵnextContext().$implicit;
|
|
78
|
-
i0.ɵɵadvance();
|
|
79
|
-
i0.ɵɵtextInterpolate(item_r9.app.Description);
|
|
80
|
-
} }
|
|
81
|
-
function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_26_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
82
|
-
const _r7 = i0.ɵɵgetCurrentView();
|
|
83
|
-
i0.ɵɵelementStart(0, "div", 44);
|
|
84
|
-
i0.ɵɵlistener("dragstart", function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_26_For_2_Template_div_dragstart_0_listener($event) { const ctx_r7 = i0.ɵɵrestoreView(_r7); const item_r9 = ctx_r7.$implicit; const ɵ$index_98_r10 = ctx_r7.$index; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.OnDragStart($event, item_r9, ɵ$index_98_r10)); })("dragend", function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_26_For_2_Template_div_dragend_0_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.OnDragEnd()); })("dragenter", function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_26_For_2_Template_div_dragenter_0_listener($event) { const ɵ$index_98_r10 = i0.ɵɵrestoreView(_r7).$index; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.OnDragEnter($event, ɵ$index_98_r10)); })("dblclick", function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_26_For_2_Template_div_dblclick_0_listener($event) { const item_r9 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); ctx_r1.RemoveApp(item_r9); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
85
|
-
i0.ɵɵelementStart(1, "div", 45)(2, "div", 46);
|
|
86
|
-
i0.ɵɵelement(3, "i", 47);
|
|
87
|
-
i0.ɵɵelementEnd();
|
|
88
|
-
i0.ɵɵelementStart(4, "div", 35);
|
|
89
|
-
i0.ɵɵelement(5, "i", 36);
|
|
90
|
-
i0.ɵɵelementEnd();
|
|
91
|
-
i0.ɵɵelementStart(6, "div", 37)(7, "span", 38);
|
|
92
|
-
i0.ɵɵtext(8);
|
|
93
|
-
i0.ɵɵelementEnd();
|
|
94
|
-
i0.ɵɵconditionalCreate(9, UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_26_For_2_Conditional_9_Template, 2, 1, "span", 39);
|
|
95
|
-
i0.ɵɵelementEnd();
|
|
96
|
-
i0.ɵɵelementStart(10, "div", 48)(11, "button", 49);
|
|
97
|
-
i0.ɵɵlistener("click", function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_26_For_2_Template_button_click_11_listener($event) { const item_r9 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); ctx_r1.MoveUp(item_r9); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
98
|
-
i0.ɵɵelement(12, "i", 50);
|
|
99
|
-
i0.ɵɵelementEnd();
|
|
100
|
-
i0.ɵɵelementStart(13, "button", 51);
|
|
101
|
-
i0.ɵɵlistener("click", function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_26_For_2_Template_button_click_13_listener($event) { const item_r9 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); ctx_r1.MoveDown(item_r9); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
102
|
-
i0.ɵɵelement(14, "i", 52);
|
|
103
|
-
i0.ɵɵelementEnd();
|
|
104
|
-
i0.ɵɵelementStart(15, "button", 53);
|
|
105
|
-
i0.ɵɵlistener("click", function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_26_For_2_Template_button_click_15_listener($event) { const item_r9 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); ctx_r1.RemoveApp(item_r9); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
106
|
-
i0.ɵɵelement(16, "i", 6);
|
|
107
|
-
i0.ɵɵelementEnd()()()();
|
|
108
|
-
} if (rf & 2) {
|
|
109
|
-
const item_r9 = ctx.$implicit;
|
|
110
|
-
const ɵ$index_98_r10 = ctx.$index;
|
|
111
|
-
const ctx_r1 = i0.ɵɵnextContext(4);
|
|
112
|
-
i0.ɵɵclassProp("dragging", ctx_r1.DraggedItem === item_r9);
|
|
113
|
-
i0.ɵɵadvance();
|
|
114
|
-
i0.ɵɵstyleProp("border-left-color", item_r9.app.GetColor());
|
|
115
|
-
i0.ɵɵadvance(3);
|
|
116
|
-
i0.ɵɵstyleProp("background-color", item_r9.app.GetColor());
|
|
117
|
-
i0.ɵɵadvance();
|
|
118
|
-
i0.ɵɵclassMap(item_r9.app.Icon || "fa-solid fa-cube");
|
|
119
|
-
i0.ɵɵadvance(3);
|
|
120
|
-
i0.ɵɵtextInterpolate(item_r9.app.Name);
|
|
121
|
-
i0.ɵɵadvance();
|
|
122
|
-
i0.ɵɵconditional(item_r9.app.Description ? 9 : -1);
|
|
123
|
-
i0.ɵɵadvance(2);
|
|
124
|
-
i0.ɵɵproperty("disabled", ɵ$index_98_r10 === 0);
|
|
125
|
-
i0.ɵɵattribute("aria-label", "Move " + item_r9.app.Name + " up");
|
|
126
|
-
i0.ɵɵadvance(2);
|
|
127
|
-
i0.ɵɵproperty("disabled", ɵ$index_98_r10 === ctx_r1.ActiveApps.length - 1);
|
|
128
|
-
i0.ɵɵattribute("aria-label", "Move " + item_r9.app.Name + " down");
|
|
129
|
-
i0.ɵɵadvance(2);
|
|
130
|
-
i0.ɵɵattribute("aria-label", "Remove " + item_r9.app.Name);
|
|
131
|
-
} }
|
|
132
|
-
function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_26_Template(rf, ctx) { if (rf & 1) {
|
|
133
|
-
const _r6 = i0.ɵɵgetCurrentView();
|
|
134
|
-
i0.ɵɵelementStart(0, "div", 42);
|
|
135
|
-
i0.ɵɵlistener("dragover", function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_26_Template_div_dragover_0_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnDragOver($event)); })("drop", function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_26_Template_div_drop_0_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnDrop($event)); });
|
|
136
|
-
i0.ɵɵrepeaterCreate(1, UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_26_For_2_Template, 17, 15, "div", 43, _forTrack0);
|
|
137
|
-
i0.ɵɵelementEnd();
|
|
138
|
-
} if (rf & 2) {
|
|
139
|
-
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
140
|
-
i0.ɵɵadvance();
|
|
141
|
-
i0.ɵɵrepeater(ctx_r1.ActiveApps);
|
|
142
|
-
} }
|
|
143
|
-
function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_29_For_3_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
144
|
-
i0.ɵɵelement(0, "div", 55);
|
|
145
|
-
} }
|
|
146
|
-
function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_29_For_3_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
147
|
-
i0.ɵɵelement(0, "div", 55);
|
|
148
|
-
} }
|
|
149
|
-
function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_29_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
150
|
-
const _r11 = i0.ɵɵgetCurrentView();
|
|
151
|
-
i0.ɵɵconditionalCreate(0, UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_29_For_3_Conditional_0_Template, 1, 0, "div", 55);
|
|
152
|
-
i0.ɵɵelementStart(1, "div", 56)(2, "div", 57);
|
|
153
|
-
i0.ɵɵlistener("touchstart", function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_29_For_3_Template_div_touchstart_2_listener($event) { const ɵ$index_142_r12 = i0.ɵɵrestoreView(_r11).$index; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.OnTouchDragStart($event, ɵ$index_142_r12)); });
|
|
154
|
-
i0.ɵɵelement(3, "i", 47);
|
|
155
|
-
i0.ɵɵelementEnd();
|
|
156
|
-
i0.ɵɵelementStart(4, "div", 35);
|
|
157
|
-
i0.ɵɵelement(5, "i", 36);
|
|
158
|
-
i0.ɵɵelementEnd();
|
|
159
|
-
i0.ɵɵelementStart(6, "span", 58);
|
|
160
|
-
i0.ɵɵtext(7);
|
|
161
|
-
i0.ɵɵelementEnd();
|
|
162
|
-
i0.ɵɵelementStart(8, "button", 59);
|
|
163
|
-
i0.ɵɵlistener("click", function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_29_For_3_Template_button_click_8_listener() { const item_r13 = i0.ɵɵrestoreView(_r11).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.ToggleApp(item_r13)); });
|
|
164
|
-
i0.ɵɵelement(9, "i", 60);
|
|
165
|
-
i0.ɵɵelementEnd()();
|
|
166
|
-
i0.ɵɵconditionalCreate(10, UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_29_For_3_Conditional_10_Template, 1, 0, "div", 55);
|
|
167
|
-
} if (rf & 2) {
|
|
168
|
-
const item_r13 = ctx.$implicit;
|
|
169
|
-
const ɵ$index_142_r12 = ctx.$index;
|
|
170
|
-
const ctx_r1 = i0.ɵɵnextContext(4);
|
|
171
|
-
i0.ɵɵconditional(ctx_r1.TouchDragActive && ctx_r1.TouchDropIndex === ɵ$index_142_r12 && ctx_r1.TouchDragIndex > ɵ$index_142_r12 ? 0 : -1);
|
|
172
|
-
i0.ɵɵadvance();
|
|
173
|
-
i0.ɵɵclassProp("touch-ghost", ctx_r1.TouchDragActive && ctx_r1.TouchDragIndex === ɵ$index_142_r12);
|
|
174
|
-
i0.ɵɵadvance(3);
|
|
175
|
-
i0.ɵɵstyleProp("background-color", item_r13.app.GetColor());
|
|
176
|
-
i0.ɵɵadvance();
|
|
177
|
-
i0.ɵɵclassMap(item_r13.app.Icon || "fa-solid fa-cube");
|
|
178
|
-
i0.ɵɵadvance(2);
|
|
179
|
-
i0.ɵɵtextInterpolate(item_r13.app.Name);
|
|
180
|
-
i0.ɵɵadvance();
|
|
181
|
-
i0.ɵɵariaProperty("aria-label", i0.ɵɵinterpolate1("Remove ", item_r13.app.Name));
|
|
182
|
-
i0.ɵɵadvance(2);
|
|
183
|
-
i0.ɵɵconditional(ctx_r1.TouchDragActive && ctx_r1.TouchDropIndex === ɵ$index_142_r12 && ctx_r1.TouchDragIndex < ɵ$index_142_r12 ? 10 : -1);
|
|
184
|
-
} }
|
|
185
|
-
function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_29_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
186
|
-
i0.ɵɵelement(0, "div", 55);
|
|
187
|
-
} }
|
|
188
|
-
function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_29_Template(rf, ctx) { if (rf & 1) {
|
|
189
|
-
i0.ɵɵelementStart(0, "div", 54);
|
|
190
|
-
i0.ɵɵtext(1, "Your Apps");
|
|
191
|
-
i0.ɵɵelementEnd();
|
|
192
|
-
i0.ɵɵrepeaterCreate(2, UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_29_For_3_Template, 11, 11, null, null, _forTrack0);
|
|
193
|
-
i0.ɵɵconditionalCreate(4, UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_29_Conditional_4_Template, 1, 0, "div", 55);
|
|
194
|
-
} if (rf & 2) {
|
|
195
|
-
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
196
|
-
i0.ɵɵadvance(2);
|
|
197
|
-
i0.ɵɵrepeater(ctx_r1.ActiveApps);
|
|
198
|
-
i0.ɵɵadvance(2);
|
|
199
|
-
i0.ɵɵconditional(ctx_r1.TouchDragActive && ctx_r1.TouchDropIndex === ctx_r1.ActiveApps.length - 1 && ctx_r1.TouchDragIndex < ctx_r1.TouchDropIndex ? 4 : -1);
|
|
200
|
-
} }
|
|
201
|
-
function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_30_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
202
|
-
const _r14 = i0.ɵɵgetCurrentView();
|
|
203
|
-
i0.ɵɵelementStart(0, "div", 61)(1, "div", 35);
|
|
204
|
-
i0.ɵɵelement(2, "i", 36);
|
|
205
|
-
i0.ɵɵelementEnd();
|
|
206
|
-
i0.ɵɵelementStart(3, "span", 58);
|
|
207
|
-
i0.ɵɵtext(4);
|
|
208
|
-
i0.ɵɵelementEnd();
|
|
209
|
-
i0.ɵɵelementStart(5, "button", 62);
|
|
210
|
-
i0.ɵɵlistener("click", function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_30_For_3_Template_button_click_5_listener() { const item_r15 = i0.ɵɵrestoreView(_r14).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.ToggleApp(item_r15)); });
|
|
211
|
-
i0.ɵɵelement(6, "i", 63);
|
|
212
|
-
i0.ɵɵelementEnd()();
|
|
213
|
-
} if (rf & 2) {
|
|
214
|
-
const item_r15 = ctx.$implicit;
|
|
215
|
-
i0.ɵɵadvance();
|
|
216
|
-
i0.ɵɵstyleProp("background-color", item_r15.app.GetColor());
|
|
217
|
-
i0.ɵɵadvance();
|
|
218
|
-
i0.ɵɵclassMap(item_r15.app.Icon || "fa-solid fa-cube");
|
|
219
|
-
i0.ɵɵadvance(2);
|
|
220
|
-
i0.ɵɵtextInterpolate(item_r15.app.Name);
|
|
221
|
-
i0.ɵɵadvance();
|
|
222
|
-
i0.ɵɵariaProperty("aria-label", i0.ɵɵinterpolate1("Add ", item_r15.app.Name));
|
|
223
|
-
} }
|
|
224
|
-
function UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_30_Template(rf, ctx) { if (rf & 1) {
|
|
225
|
-
i0.ɵɵelementStart(0, "div", 54);
|
|
226
|
-
i0.ɵɵtext(1, "Available");
|
|
227
|
-
i0.ɵɵelementEnd();
|
|
228
|
-
i0.ɵɵrepeaterCreate(2, UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_30_For_3_Template, 7, 7, "div", 61, _forTrack0);
|
|
229
|
-
} if (rf & 2) {
|
|
230
|
-
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
231
|
-
i0.ɵɵadvance(2);
|
|
232
|
-
i0.ɵɵrepeater(ctx_r1.AvailableApps);
|
|
233
|
-
} }
|
|
234
|
-
function UserAppConfigComponent_Conditional_0_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
235
|
-
const _r3 = i0.ɵɵgetCurrentView();
|
|
236
|
-
i0.ɵɵelementStart(0, "div", 10)(1, "p", 18);
|
|
237
|
-
i0.ɵɵtext(2, " Select which applications appear in your app switcher and arrange them in your preferred order. Double-click to quickly add or remove. Drag and drop to reorder, or use the arrow buttons. ");
|
|
238
|
-
i0.ɵɵelementEnd();
|
|
239
|
-
i0.ɵɵelementStart(3, "div", 19)(4, "div", 20)(5, "div", 21);
|
|
240
|
-
i0.ɵɵlistener("click", function UserAppConfigComponent_Conditional_0_Conditional_11_Template_div_click_5_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.AvailablePanelCollapsed = !ctx_r1.AvailablePanelCollapsed); });
|
|
241
|
-
i0.ɵɵelement(6, "i", 22);
|
|
242
|
-
i0.ɵɵelementStart(7, "h3");
|
|
243
|
-
i0.ɵɵtext(8, "Available Applications");
|
|
244
|
-
i0.ɵɵelementEnd();
|
|
245
|
-
i0.ɵɵelementStart(9, "span", 23);
|
|
246
|
-
i0.ɵɵtext(10);
|
|
247
|
-
i0.ɵɵelementEnd();
|
|
248
|
-
i0.ɵɵelement(11, "i", 24);
|
|
249
|
-
i0.ɵɵelementEnd();
|
|
250
|
-
i0.ɵɵelementStart(12, "div", 25);
|
|
251
|
-
i0.ɵɵconditionalCreate(13, UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_13_Template, 1, 0, "mj-empty-state", 26);
|
|
252
|
-
i0.ɵɵrepeaterCreate(14, UserAppConfigComponent_Conditional_0_Conditional_11_For_15_Template, 10, 7, "div", 27, _forTrack0);
|
|
253
|
-
i0.ɵɵelementEnd()();
|
|
254
|
-
i0.ɵɵelementStart(16, "div", 28)(17, "div", 21);
|
|
255
|
-
i0.ɵɵlistener("click", function UserAppConfigComponent_Conditional_0_Conditional_11_Template_div_click_17_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SelectedPanelCollapsed = !ctx_r1.SelectedPanelCollapsed); });
|
|
256
|
-
i0.ɵɵelement(18, "i", 29);
|
|
257
|
-
i0.ɵɵelementStart(19, "h3");
|
|
258
|
-
i0.ɵɵtext(20, "Your Applications");
|
|
259
|
-
i0.ɵɵelementEnd();
|
|
260
|
-
i0.ɵɵelementStart(21, "span", 23);
|
|
261
|
-
i0.ɵɵtext(22);
|
|
262
|
-
i0.ɵɵelementEnd();
|
|
263
|
-
i0.ɵɵelement(23, "i", 24);
|
|
264
|
-
i0.ɵɵelementEnd();
|
|
265
|
-
i0.ɵɵelementStart(24, "div", 25);
|
|
266
|
-
i0.ɵɵconditionalCreate(25, UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_25_Template, 1, 0, "mj-empty-state", 30);
|
|
267
|
-
i0.ɵɵconditionalCreate(26, UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_26_Template, 3, 0, "div", 31);
|
|
268
|
-
i0.ɵɵelementEnd()()();
|
|
269
|
-
i0.ɵɵelementStart(27, "div", 32);
|
|
270
|
-
i0.ɵɵlistener("touchmove", function UserAppConfigComponent_Conditional_0_Conditional_11_Template_div_touchmove_27_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnTouchDragMove($event)); })("touchend", function UserAppConfigComponent_Conditional_0_Conditional_11_Template_div_touchend_27_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnTouchDragEnd()); })("touchcancel", function UserAppConfigComponent_Conditional_0_Conditional_11_Template_div_touchcancel_27_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnTouchDragEnd()); });
|
|
271
|
-
i0.ɵɵelementStart(28, "div", 33);
|
|
272
|
-
i0.ɵɵconditionalCreate(29, UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_29_Template, 5, 1);
|
|
273
|
-
i0.ɵɵconditionalCreate(30, UserAppConfigComponent_Conditional_0_Conditional_11_Conditional_30_Template, 4, 0);
|
|
274
|
-
i0.ɵɵelementEnd()()();
|
|
275
|
-
} if (rf & 2) {
|
|
276
|
-
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
277
|
-
i0.ɵɵadvance(4);
|
|
278
|
-
i0.ɵɵclassProp("collapsed", ctx_r1.AvailablePanelCollapsed);
|
|
279
|
-
i0.ɵɵadvance(6);
|
|
280
|
-
i0.ɵɵtextInterpolate(ctx_r1.AvailableApps.length);
|
|
281
|
-
i0.ɵɵadvance();
|
|
282
|
-
i0.ɵɵclassProp("fa-chevron-down", ctx_r1.AvailablePanelCollapsed)("fa-chevron-up", !ctx_r1.AvailablePanelCollapsed);
|
|
283
|
-
i0.ɵɵadvance(2);
|
|
284
|
-
i0.ɵɵconditional(ctx_r1.AvailableApps.length === 0 ? 13 : -1);
|
|
285
|
-
i0.ɵɵadvance();
|
|
286
|
-
i0.ɵɵrepeater(ctx_r1.AvailableApps);
|
|
287
|
-
i0.ɵɵadvance(2);
|
|
288
|
-
i0.ɵɵclassProp("collapsed", ctx_r1.SelectedPanelCollapsed);
|
|
289
|
-
i0.ɵɵadvance(6);
|
|
290
|
-
i0.ɵɵtextInterpolate(ctx_r1.ActiveApps.length);
|
|
291
|
-
i0.ɵɵadvance();
|
|
292
|
-
i0.ɵɵclassProp("fa-chevron-down", ctx_r1.SelectedPanelCollapsed)("fa-chevron-up", !ctx_r1.SelectedPanelCollapsed);
|
|
293
|
-
i0.ɵɵadvance(2);
|
|
294
|
-
i0.ɵɵconditional(ctx_r1.ActiveApps.length === 0 ? 25 : -1);
|
|
295
|
-
i0.ɵɵadvance();
|
|
296
|
-
i0.ɵɵconditional(ctx_r1.ActiveApps.length > 0 ? 26 : -1);
|
|
297
|
-
i0.ɵɵadvance(3);
|
|
298
|
-
i0.ɵɵconditional(ctx_r1.ActiveApps.length > 0 ? 29 : -1);
|
|
299
|
-
i0.ɵɵadvance();
|
|
300
|
-
i0.ɵɵconditional(ctx_r1.AvailableApps.length > 0 ? 30 : -1);
|
|
301
|
-
} }
|
|
302
|
-
function UserAppConfigComponent_Conditional_0_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
303
|
-
const _r16 = i0.ɵɵgetCurrentView();
|
|
304
|
-
i0.ɵɵelementStart(0, "button", 16);
|
|
305
|
-
i0.ɵɵlistener("click", function UserAppConfigComponent_Conditional_0_Conditional_14_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.Reset()); });
|
|
306
|
-
i0.ɵɵelement(1, "i", 64);
|
|
307
|
-
i0.ɵɵtext(2, " Reset Changes ");
|
|
308
|
-
i0.ɵɵelementEnd();
|
|
309
|
-
} if (rf & 2) {
|
|
310
|
-
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
311
|
-
i0.ɵɵproperty("disabled", ctx_r1.IsLoading || ctx_r1.IsSaving);
|
|
312
|
-
} }
|
|
313
|
-
function UserAppConfigComponent_Conditional_0_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
314
|
-
i0.ɵɵelement(0, "mj-loading", 65);
|
|
315
|
-
i0.ɵɵelementStart(1, "span");
|
|
316
|
-
i0.ɵɵtext(2, "Saving...");
|
|
317
|
-
i0.ɵɵelementEnd();
|
|
318
|
-
} if (rf & 2) {
|
|
319
|
-
i0.ɵɵproperty("showText", false);
|
|
320
|
-
} }
|
|
321
|
-
function UserAppConfigComponent_Conditional_0_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
322
|
-
i0.ɵɵelement(0, "i", 66);
|
|
323
|
-
i0.ɵɵelementStart(1, "span");
|
|
324
|
-
i0.ɵɵtext(2, "Save Changes");
|
|
325
|
-
i0.ɵɵelementEnd();
|
|
326
|
-
} }
|
|
4
|
+
import * as i1 from "./user-app-config-content.component";
|
|
327
5
|
function UserAppConfigComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
328
6
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
329
7
|
i0.ɵɵelementStart(0, "div", 0);
|
|
@@ -337,55 +15,37 @@ function UserAppConfigComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
|
337
15
|
i0.ɵɵlistener("click", function UserAppConfigComponent_Conditional_0_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Close()); });
|
|
338
16
|
i0.ɵɵelement(7, "i", 6);
|
|
339
17
|
i0.ɵɵelementEnd()();
|
|
340
|
-
i0.ɵɵelementStart(8, "
|
|
341
|
-
i0.ɵɵ
|
|
342
|
-
i0.ɵɵ
|
|
343
|
-
i0.ɵɵconditionalCreate(11, UserAppConfigComponent_Conditional_0_Conditional_11_Template, 31, 19, "div", 10);
|
|
344
|
-
i0.ɵɵelementStart(12, "div", 11)(13, "div", 12);
|
|
345
|
-
i0.ɵɵconditionalCreate(14, UserAppConfigComponent_Conditional_0_Conditional_14_Template, 3, 1, "button", 13);
|
|
346
|
-
i0.ɵɵelementEnd();
|
|
347
|
-
i0.ɵɵelementStart(15, "div", 14)(16, "button", 15);
|
|
348
|
-
i0.ɵɵlistener("click", function UserAppConfigComponent_Conditional_0_Template_button_click_16_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Save()); });
|
|
349
|
-
i0.ɵɵconditionalCreate(17, UserAppConfigComponent_Conditional_0_Conditional_17_Template, 3, 1)(18, UserAppConfigComponent_Conditional_0_Conditional_18_Template, 3, 0);
|
|
350
|
-
i0.ɵɵelementEnd();
|
|
351
|
-
i0.ɵɵelementStart(19, "button", 16);
|
|
352
|
-
i0.ɵɵlistener("click", function UserAppConfigComponent_Conditional_0_Template_button_click_19_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Close()); });
|
|
353
|
-
i0.ɵɵtext(20, " Cancel ");
|
|
354
|
-
i0.ɵɵelementEnd()()()()();
|
|
18
|
+
i0.ɵɵelementStart(8, "mj-user-app-config-content", 7);
|
|
19
|
+
i0.ɵɵlistener("Saved", function UserAppConfigComponent_Conditional_0_Template_mj_user_app_config_content_Saved_8_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnContentSaved()); })("Cancelled", function UserAppConfigComponent_Conditional_0_Template_mj_user_app_config_content_Cancelled_8_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Close()); });
|
|
20
|
+
i0.ɵɵelementEnd()();
|
|
355
21
|
} if (rf & 2) {
|
|
356
22
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
357
|
-
i0.ɵɵadvance(
|
|
358
|
-
i0.ɵɵ
|
|
359
|
-
i0.ɵɵadvance();
|
|
360
|
-
i0.ɵɵconditional(ctx_r1.ErrorMessage ? 10 : -1);
|
|
361
|
-
i0.ɵɵadvance();
|
|
362
|
-
i0.ɵɵconditional(!ctx_r1.IsLoading ? 11 : -1);
|
|
363
|
-
i0.ɵɵadvance(3);
|
|
364
|
-
i0.ɵɵconditional(ctx_r1.HasChanges() ? 14 : -1);
|
|
365
|
-
i0.ɵɵadvance(2);
|
|
366
|
-
i0.ɵɵproperty("disabled", ctx_r1.IsLoading || ctx_r1.IsSaving || !ctx_r1.HasChanges());
|
|
367
|
-
i0.ɵɵadvance();
|
|
368
|
-
i0.ɵɵconditional(ctx_r1.IsSaving ? 17 : 18);
|
|
369
|
-
i0.ɵɵadvance(2);
|
|
370
|
-
i0.ɵɵproperty("disabled", ctx_r1.IsSaving);
|
|
23
|
+
i0.ɵɵadvance(8);
|
|
24
|
+
i0.ɵɵproperty("Provider", ctx_r1.Provider);
|
|
371
25
|
} }
|
|
372
26
|
/**
|
|
373
|
-
* Full-screen modal dialog for configuring user's application visibility and
|
|
374
|
-
*
|
|
375
|
-
* -
|
|
376
|
-
*
|
|
377
|
-
*
|
|
27
|
+
* Full-screen modal dialog for configuring user's application visibility and
|
|
28
|
+
* order. Thin wrapper: the actual configuration UI (list/reorder/persistence)
|
|
29
|
+
* lives in `mj-user-app-config-content`, which the shell's app launcher also
|
|
30
|
+
* embeds directly as an in-panel view. This wrapper only provides the modal
|
|
31
|
+
* chrome + the `ShowDialog`/`Open()`/`Close()` API its dialog consumers use
|
|
32
|
+
* (e.g. the Home dashboard).
|
|
33
|
+
*
|
|
34
|
+
* The content component loads its data in ngOnInit — because it is created
|
|
35
|
+
* fresh under this template's `@if (ShowDialog)`, every `Open()` gets a fresh
|
|
36
|
+
* load with no stale-list flash (the concern bug F1's resetLists() addressed
|
|
37
|
+
* in the pre-split monolith is solved structurally here).
|
|
378
38
|
*/
|
|
379
39
|
export class UserAppConfigComponent extends BaseAngularComponent {
|
|
380
|
-
appManager = inject(ApplicationManager);
|
|
381
|
-
sharedService = inject(SharedService);
|
|
382
|
-
cdr = inject(ChangeDetectorRef);
|
|
383
|
-
ngZone = inject(NgZone);
|
|
384
|
-
el = inject(ElementRef);
|
|
385
40
|
_showDialog = false;
|
|
386
41
|
set ShowDialog(value) {
|
|
387
42
|
if (value !== this._showDialog) {
|
|
388
43
|
this._showDialog = value;
|
|
44
|
+
// Emit on EVERY change so the parent's `[(ShowDialog)]` two-way binding round-trips (bug F1).
|
|
45
|
+
// Previously the setter never emitted, so when child and parent state diverged the dialog got
|
|
46
|
+
// stuck in a state only a full browser refresh could clear. This is the single emit path —
|
|
47
|
+
// Open()/Close() route through this setter rather than emitting themselves.
|
|
48
|
+
this.ShowDialogChange.emit(value);
|
|
389
49
|
}
|
|
390
50
|
}
|
|
391
51
|
get ShowDialog() {
|
|
@@ -393,353 +53,35 @@ export class UserAppConfigComponent extends BaseAngularComponent {
|
|
|
393
53
|
}
|
|
394
54
|
ShowDialogChange = new EventEmitter();
|
|
395
55
|
ConfigSaved = new EventEmitter();
|
|
396
|
-
AllApps = [];
|
|
397
|
-
ActiveApps = [];
|
|
398
|
-
AvailableApps = [];
|
|
399
|
-
IsLoading = false;
|
|
400
|
-
IsSaving = false;
|
|
401
|
-
ErrorMessage = '';
|
|
402
|
-
AvailablePanelCollapsed = false;
|
|
403
|
-
SelectedPanelCollapsed = false;
|
|
404
|
-
DraggedItem = null;
|
|
405
|
-
DraggedIndex = -1;
|
|
406
|
-
DropTargetIndex = -1;
|
|
407
56
|
/**
|
|
408
|
-
* Opens the dialog
|
|
57
|
+
* Opens the dialog (the embedded content component loads on creation).
|
|
58
|
+
* Routes through the setter — the single ShowDialogChange emit path.
|
|
409
59
|
*/
|
|
410
|
-
|
|
411
|
-
this.
|
|
412
|
-
this.ShowDialogChange.emit(true);
|
|
413
|
-
this.ErrorMessage = '';
|
|
414
|
-
await this.loadConfiguration();
|
|
60
|
+
Open() {
|
|
61
|
+
this.ShowDialog = true;
|
|
415
62
|
}
|
|
416
63
|
/**
|
|
417
|
-
* Closes the dialog without saving
|
|
64
|
+
* Closes the dialog without saving. Routes through the setter — the single
|
|
65
|
+
* ShowDialogChange emit path.
|
|
418
66
|
*/
|
|
419
67
|
Close() {
|
|
420
|
-
this.
|
|
421
|
-
this.ShowDialogChange.emit(false);
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* Adds an app to the user's active list
|
|
425
|
-
*/
|
|
426
|
-
AddApp(item) {
|
|
427
|
-
item.isActive = true;
|
|
428
|
-
item.sequence = this.ActiveApps.length;
|
|
429
|
-
item.isDirty = true;
|
|
430
|
-
this.refreshAppLists();
|
|
431
|
-
}
|
|
432
|
-
/**
|
|
433
|
-
* Removes an app from the user's active list
|
|
434
|
-
*/
|
|
435
|
-
RemoveApp(item) {
|
|
436
|
-
item.isActive = false;
|
|
437
|
-
item.sequence = 999;
|
|
438
|
-
item.isDirty = true;
|
|
439
|
-
this.refreshAppLists();
|
|
440
|
-
this.resequenceActiveApps();
|
|
441
|
-
}
|
|
442
|
-
/**
|
|
443
|
-
* Toggles an app between active and inactive
|
|
444
|
-
*/
|
|
445
|
-
ToggleApp(item) {
|
|
446
|
-
if (item.isActive) {
|
|
447
|
-
this.RemoveApp(item);
|
|
448
|
-
}
|
|
449
|
-
else {
|
|
450
|
-
this.AddApp(item);
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
/**
|
|
454
|
-
* Moves an app up in the order. Positional (splice + renumber), NOT a sequence-value
|
|
455
|
-
* swap: rows can carry duplicate Sequence values (issue #3027 — e.g. a re-enabled app
|
|
456
|
-
* kept a stale value), and swapping two equal values is a silent no-op. Reordering by
|
|
457
|
-
* position then renumbering 0..n-1 always works and heals duplicates as a side effect.
|
|
458
|
-
*/
|
|
459
|
-
MoveUp(item) {
|
|
460
|
-
const index = this.ActiveApps.indexOf(item);
|
|
461
|
-
if (index > 0) {
|
|
462
|
-
this.moveActiveApp(index, index - 1);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
/**
|
|
466
|
-
* Moves an app down in the order. Positional — see {@link MoveUp} for why.
|
|
467
|
-
*/
|
|
468
|
-
MoveDown(item) {
|
|
469
|
-
const index = this.ActiveApps.indexOf(item);
|
|
470
|
-
if (index >= 0 && index < this.ActiveApps.length - 1) {
|
|
471
|
-
this.moveActiveApp(index, index + 1);
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
moveActiveApp(fromIndex, toIndex) {
|
|
475
|
-
this.ActiveApps = moveAndResequence(this.ActiveApps, fromIndex, toIndex);
|
|
476
|
-
}
|
|
477
|
-
/**
|
|
478
|
-
* Checks if there are any unsaved changes
|
|
479
|
-
*/
|
|
480
|
-
HasChanges() {
|
|
481
|
-
return this.AllApps.some(item => item.isDirty);
|
|
482
|
-
}
|
|
483
|
-
/**
|
|
484
|
-
* Saves the user's app configuration
|
|
485
|
-
*/
|
|
486
|
-
async Save() {
|
|
487
|
-
if (!this.HasChanges()) {
|
|
488
|
-
this.Close();
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
this.IsSaving = true;
|
|
492
|
-
this.ErrorMessage = '';
|
|
493
|
-
try {
|
|
494
|
-
// Self-heal: renumber active apps 0..n-1 before persisting. Existing rows can
|
|
495
|
-
// carry duplicate Sequence values from older data (issue #3027); renumbering in
|
|
496
|
-
// display order marks any corrected rows dirty so this save fixes them for good.
|
|
497
|
-
this.resequenceActiveApps();
|
|
498
|
-
const md = this.ProviderToUse;
|
|
499
|
-
for (const item of this.AllApps) {
|
|
500
|
-
if (!item.isDirty)
|
|
501
|
-
continue;
|
|
502
|
-
if (item.userAppId) {
|
|
503
|
-
await this.updateUserApplication(md, item);
|
|
504
|
-
}
|
|
505
|
-
else if (item.isActive) {
|
|
506
|
-
await this.createUserApplication(md, item);
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
// Each userApp.Save() above fires a BaseEntity 'save' event, which UserInfoEngine
|
|
510
|
-
// catches via HandleIndividualBaseEntityEvent → debounced refresh → NotifyDataChange.
|
|
511
|
-
// ApplicationManager.subscribeToEngineChanges then propagates to the shell app
|
|
512
|
-
// switcher. No explicit reload needed here — and avoiding it sidesteps NG0100
|
|
513
|
-
// from observable emissions interleaving with this method's save loop.
|
|
514
|
-
LogStatusEx({
|
|
515
|
-
message: 'User app configuration saved',
|
|
516
|
-
verboseOnly: true
|
|
517
|
-
});
|
|
518
|
-
this.sharedService.CreateSimpleNotification('App configuration saved successfully!', 'success', 3000);
|
|
519
|
-
this.ConfigSaved.emit();
|
|
520
|
-
this.Close();
|
|
521
|
-
}
|
|
522
|
-
catch (error) {
|
|
523
|
-
this.ErrorMessage = 'Failed to save configuration. Please try again.';
|
|
524
|
-
LogError('Error saving app configuration:', undefined, error instanceof Error ? error.message : String(error));
|
|
525
|
-
}
|
|
526
|
-
finally {
|
|
527
|
-
this.ngZone.run(() => {
|
|
528
|
-
this.IsSaving = false;
|
|
529
|
-
this.cdr.detectChanges();
|
|
530
|
-
});
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
/**
|
|
534
|
-
* Resets all changes and reloads the configuration
|
|
535
|
-
*/
|
|
536
|
-
async Reset() {
|
|
537
|
-
await this.loadConfiguration();
|
|
538
|
-
}
|
|
539
|
-
// ---------------------------------------------------------------------------
|
|
540
|
-
// Drag-and-drop handlers (desktop only)
|
|
541
|
-
// ---------------------------------------------------------------------------
|
|
542
|
-
OnDragStart(event, item, index) {
|
|
543
|
-
this.DraggedItem = item;
|
|
544
|
-
this.DraggedIndex = index;
|
|
545
|
-
if (event.dataTransfer) {
|
|
546
|
-
event.dataTransfer.effectAllowed = 'move';
|
|
547
|
-
event.dataTransfer.setData('text/plain', index.toString());
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
OnDragOver(event) {
|
|
551
|
-
event.preventDefault();
|
|
552
|
-
if (event.dataTransfer) {
|
|
553
|
-
event.dataTransfer.dropEffect = 'move';
|
|
554
|
-
}
|
|
68
|
+
this.ShowDialog = false;
|
|
555
69
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
this.
|
|
559
|
-
|
|
560
|
-
OnDragEnd() {
|
|
561
|
-
this.DraggedItem = null;
|
|
562
|
-
this.DraggedIndex = -1;
|
|
563
|
-
this.DropTargetIndex = -1;
|
|
564
|
-
}
|
|
565
|
-
OnDrop(event) {
|
|
566
|
-
event.preventDefault();
|
|
567
|
-
if (this.DraggedIndex >= 0 && this.DropTargetIndex >= 0 && this.DraggedIndex !== this.DropTargetIndex) {
|
|
568
|
-
const [movedItem] = this.ActiveApps.splice(this.DraggedIndex, 1);
|
|
569
|
-
this.ActiveApps.splice(this.DropTargetIndex, 0, movedItem);
|
|
570
|
-
this.resequenceActiveApps();
|
|
571
|
-
this.cdr.detectChanges();
|
|
572
|
-
}
|
|
573
|
-
this.OnDragEnd();
|
|
574
|
-
}
|
|
575
|
-
// ---------------------------------------------------------------------------
|
|
576
|
-
// Touch drag-and-drop handlers (mobile)
|
|
577
|
-
// ---------------------------------------------------------------------------
|
|
578
|
-
TouchDragIndex = -1;
|
|
579
|
-
TouchDropIndex = -1;
|
|
580
|
-
TouchDragActive = false;
|
|
581
|
-
touchStartY = 0;
|
|
582
|
-
touchCurrentY = 0;
|
|
583
|
-
touchRowHeight = 0;
|
|
584
|
-
touchDragElement = null;
|
|
585
|
-
touchScrollContainer = null;
|
|
586
|
-
OnTouchDragStart(event, index) {
|
|
587
|
-
const touch = event.touches[0];
|
|
588
|
-
const row = event.target.closest('.mobile-app-row');
|
|
589
|
-
if (!row)
|
|
590
|
-
return;
|
|
591
|
-
event.preventDefault();
|
|
592
|
-
this.TouchDragIndex = index;
|
|
593
|
-
this.TouchDropIndex = index;
|
|
594
|
-
this.TouchDragActive = true;
|
|
595
|
-
this.touchStartY = touch.clientY;
|
|
596
|
-
this.touchCurrentY = touch.clientY;
|
|
597
|
-
this.touchDragElement = row;
|
|
598
|
-
this.touchRowHeight = row.offsetHeight;
|
|
599
|
-
this.touchScrollContainer = this.el.nativeElement.querySelector('.mobile-list');
|
|
600
|
-
row.classList.add('touch-dragging');
|
|
601
|
-
}
|
|
602
|
-
OnTouchDragMove(event) {
|
|
603
|
-
if (!this.TouchDragActive || !this.touchDragElement)
|
|
604
|
-
return;
|
|
605
|
-
event.preventDefault();
|
|
606
|
-
const touch = event.touches[0];
|
|
607
|
-
this.touchCurrentY = touch.clientY;
|
|
608
|
-
const deltaY = this.touchCurrentY - this.touchStartY;
|
|
609
|
-
this.touchDragElement.style.transform = `translateY(${deltaY}px)`;
|
|
610
|
-
this.touchDragElement.style.zIndex = '100';
|
|
611
|
-
this.updateTouchDropTarget(deltaY);
|
|
612
|
-
this.autoScrollIfNeeded();
|
|
613
|
-
}
|
|
614
|
-
OnTouchDragEnd() {
|
|
615
|
-
if (!this.TouchDragActive)
|
|
616
|
-
return;
|
|
617
|
-
if (this.touchDragElement) {
|
|
618
|
-
this.touchDragElement.style.transform = '';
|
|
619
|
-
this.touchDragElement.style.zIndex = '';
|
|
620
|
-
this.touchDragElement.classList.remove('touch-dragging');
|
|
621
|
-
}
|
|
622
|
-
if (this.TouchDragIndex >= 0 && this.TouchDropIndex >= 0 && this.TouchDragIndex !== this.TouchDropIndex) {
|
|
623
|
-
const [movedItem] = this.ActiveApps.splice(this.TouchDragIndex, 1);
|
|
624
|
-
this.ActiveApps.splice(this.TouchDropIndex, 0, movedItem);
|
|
625
|
-
this.resequenceActiveApps();
|
|
626
|
-
}
|
|
627
|
-
this.resetTouchDragState();
|
|
628
|
-
this.cdr.detectChanges();
|
|
629
|
-
}
|
|
630
|
-
updateTouchDropTarget(deltaY) {
|
|
631
|
-
const rowsToMove = Math.round(deltaY / this.touchRowHeight);
|
|
632
|
-
const newIndex = Math.max(0, Math.min(this.ActiveApps.length - 1, this.TouchDragIndex + rowsToMove));
|
|
633
|
-
this.TouchDropIndex = newIndex;
|
|
634
|
-
}
|
|
635
|
-
autoScrollIfNeeded() {
|
|
636
|
-
if (!this.touchScrollContainer)
|
|
637
|
-
return;
|
|
638
|
-
const rect = this.touchScrollContainer.getBoundingClientRect();
|
|
639
|
-
const edgeZone = 40;
|
|
640
|
-
if (this.touchCurrentY < rect.top + edgeZone) {
|
|
641
|
-
this.touchScrollContainer.scrollTop -= 8;
|
|
642
|
-
}
|
|
643
|
-
else if (this.touchCurrentY > rect.bottom - edgeZone) {
|
|
644
|
-
this.touchScrollContainer.scrollTop += 8;
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
resetTouchDragState() {
|
|
648
|
-
this.TouchDragIndex = -1;
|
|
649
|
-
this.TouchDropIndex = -1;
|
|
650
|
-
this.TouchDragActive = false;
|
|
651
|
-
this.touchDragElement = null;
|
|
652
|
-
this.touchScrollContainer = null;
|
|
653
|
-
}
|
|
654
|
-
// ---------------------------------------------------------------------------
|
|
655
|
-
// Private helpers
|
|
656
|
-
// ---------------------------------------------------------------------------
|
|
657
|
-
async loadConfiguration() {
|
|
658
|
-
this.IsLoading = true;
|
|
659
|
-
this.ErrorMessage = '';
|
|
660
|
-
try {
|
|
661
|
-
// Read directly from UserInfoEngine's cache. The engine already loaded
|
|
662
|
-
// and maintains MJ: User Applications via its event-driven refresh — no
|
|
663
|
-
// need to re-query the DB on every dialog open. EnsureLoaded is idempotent
|
|
664
|
-
// and instant when the engine is already loaded (the typical case here,
|
|
665
|
-
// since UserInfoEngine fires at startup).
|
|
666
|
-
await UserInfoEngine.Instance.EnsureLoaded();
|
|
667
|
-
const systemApps = this.appManager.GetAuthorizedSystemApps();
|
|
668
|
-
const userApps = UserInfoEngine.Instance.UserApplications;
|
|
669
|
-
this.AllApps = this.buildAppConfigItems(systemApps, userApps);
|
|
670
|
-
this.refreshAppLists();
|
|
671
|
-
}
|
|
672
|
-
catch (error) {
|
|
673
|
-
this.ErrorMessage = 'Failed to load app configuration. Please try again.';
|
|
674
|
-
LogError('Error loading app configuration:', undefined, error instanceof Error ? error.message : String(error));
|
|
675
|
-
}
|
|
676
|
-
finally {
|
|
677
|
-
this.ngZone.run(() => {
|
|
678
|
-
this.IsLoading = false;
|
|
679
|
-
this.cdr.detectChanges();
|
|
680
|
-
});
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
buildAppConfigItems(systemApps, userApps) {
|
|
684
|
-
return systemApps.map(app => {
|
|
685
|
-
const userApp = userApps.find(ua => UUIDsEqual(ua.ApplicationID, app.ID));
|
|
686
|
-
return {
|
|
687
|
-
app,
|
|
688
|
-
userAppId: userApp?.ID ?? null,
|
|
689
|
-
sequence: userApp?.Sequence ?? 999,
|
|
690
|
-
isActive: userApp?.IsActive ?? false,
|
|
691
|
-
isDirty: false
|
|
692
|
-
};
|
|
693
|
-
});
|
|
694
|
-
}
|
|
695
|
-
refreshAppLists() {
|
|
696
|
-
this.ActiveApps = this.AllApps
|
|
697
|
-
.filter(item => item.isActive)
|
|
698
|
-
.sort((a, b) => a.sequence - b.sequence);
|
|
699
|
-
this.AvailableApps = this.AllApps
|
|
700
|
-
.filter(item => !item.isActive)
|
|
701
|
-
.sort((a, b) => a.app.Name.localeCompare(b.app.Name));
|
|
702
|
-
}
|
|
703
|
-
resequenceActiveApps() {
|
|
704
|
-
resequenceItems(this.ActiveApps);
|
|
705
|
-
}
|
|
706
|
-
async updateUserApplication(md, item) {
|
|
707
|
-
const userApp = await md.GetEntityObject('MJ: User Applications');
|
|
708
|
-
await userApp.Load(item.userAppId);
|
|
709
|
-
userApp.Sequence = item.sequence;
|
|
710
|
-
userApp.IsActive = item.isActive;
|
|
711
|
-
const saved = await userApp.Save();
|
|
712
|
-
if (!saved) {
|
|
713
|
-
throw new Error(`Failed to update UserApplication for ${item.app.Name}: ${userApp.LatestResult}`);
|
|
714
|
-
}
|
|
715
|
-
item.isDirty = false;
|
|
716
|
-
LogStatus(`Updated UserApplication for ${item.app.Name}: sequence=${item.sequence}, isActive=${item.isActive}`);
|
|
717
|
-
}
|
|
718
|
-
async createUserApplication(md, item) {
|
|
719
|
-
const userApp = await md.GetEntityObject('MJ: User Applications');
|
|
720
|
-
userApp.NewRecord();
|
|
721
|
-
userApp.UserID = md.CurrentUser.ID;
|
|
722
|
-
userApp.ApplicationID = item.app.ID;
|
|
723
|
-
userApp.Sequence = item.sequence;
|
|
724
|
-
userApp.IsActive = item.isActive;
|
|
725
|
-
const saved = await userApp.Save();
|
|
726
|
-
if (!saved) {
|
|
727
|
-
throw new Error(`Failed to create UserApplication for ${item.app.Name}: ${userApp.LatestResult}`);
|
|
728
|
-
}
|
|
729
|
-
item.userAppId = userApp.ID;
|
|
730
|
-
item.isDirty = false;
|
|
731
|
-
LogStatus(`Created UserApplication for ${item.app.Name}: sequence=${item.sequence}`);
|
|
70
|
+
/** Content saved successfully — surface it and close */
|
|
71
|
+
OnContentSaved() {
|
|
72
|
+
this.ConfigSaved.emit();
|
|
73
|
+
this.Close();
|
|
732
74
|
}
|
|
733
75
|
static ɵfac = /*@__PURE__*/ (() => { let ɵUserAppConfigComponent_BaseFactory; return function UserAppConfigComponent_Factory(__ngFactoryType__) { return (ɵUserAppConfigComponent_BaseFactory || (ɵUserAppConfigComponent_BaseFactory = i0.ɵɵgetInheritedFactory(UserAppConfigComponent)))(__ngFactoryType__ || UserAppConfigComponent); }; })();
|
|
734
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: UserAppConfigComponent, selectors: [["mj-user-app-config"]], inputs: { ShowDialog: "ShowDialog" }, outputs: { ShowDialogChange: "ShowDialogChange", ConfigSaved: "ConfigSaved" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 1, consts: [["role", "presentation", 1, "modal-backdrop", 3, "click"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "app-config-title", 1, "modal-dialog", "full-screen-dialog"], [1, "modal-header"], ["id", "app-config-title", 1, "modal-title"], ["aria-hidden", "true", 1, "fa-solid", "fa-
|
|
735
|
-
i0.ɵɵconditionalCreate(0, UserAppConfigComponent_Conditional_0_Template,
|
|
76
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: UserAppConfigComponent, selectors: [["mj-user-app-config"]], inputs: { ShowDialog: "ShowDialog" }, outputs: { ShowDialogChange: "ShowDialogChange", ConfigSaved: "ConfigSaved" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 1, consts: [["role", "presentation", 1, "modal-backdrop", 3, "click"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "app-config-title", 1, "modal-dialog", "full-screen-dialog"], [1, "modal-header"], ["id", "app-config-title", 1, "modal-title"], ["aria-hidden", "true", 1, "fa-solid", "fa-grip"], ["aria-label", "Close dialog", 1, "modal-close", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-xmark"], [3, "Saved", "Cancelled", "Provider"]], template: function UserAppConfigComponent_Template(rf, ctx) { if (rf & 1) {
|
|
77
|
+
i0.ɵɵconditionalCreate(0, UserAppConfigComponent_Conditional_0_Template, 9, 1);
|
|
736
78
|
} if (rf & 2) {
|
|
737
79
|
i0.ɵɵconditional(ctx.ShowDialog ? 0 : -1);
|
|
738
|
-
} }, dependencies: [i1.LoadingComponent, i2.MJButtonDirective, i2.MJEmptyStateComponent, i2.MJAlertComponent], styles: ["\n\n\n\n\n\n\n.modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n background: rgba(0, 0, 0, 0.5);\n z-index: 1000;\n}\n\n\n\n.full-screen-dialog[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n background: var(--mat-sys-surface);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n}\n\n\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 1rem 1.5rem;\n background: var(--mat-sys-surface);\n border-bottom: 1px solid var(--mat-sys-outline-variant);\n}\n\n.modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n margin: 0;\n font: var(--mat-sys-title-large);\n color: var(--mat-sys-on-surface);\n}\n\n.modal-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mat-sys-primary);\n}\n\n.modal-close[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.5rem;\n height: 2.5rem;\n border: none;\n border-radius: var(--mat-sys-corner-full);\n background: transparent;\n color: var(--mat-sys-on-surface-variant);\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.modal-close[_ngcontent-%COMP%]:hover {\n background: var(--mat-sys-surface-container);\n color: var(--mat-sys-on-surface);\n}\n\n.modal-close[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mat-sys-primary);\n outline-offset: 2px;\n}\n\n\n\n.app-config-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n flex: 1;\n overflow: hidden;\n background: var(--mat-sys-surface-container-lowest);\n}\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 1rem;\n color: var(--mat-sys-on-surface-variant);\n}\n\n\n\n\n.config-content[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n padding: 1.5rem;\n overflow: hidden;\n}\n\n.config-description[_ngcontent-%COMP%] {\n margin: 0 0 1.5rem 0;\n color: var(--mat-sys-on-surface-variant);\n font: var(--mat-sys-body-large);\n line-height: 1.5;\n}\n\n\n\n.panels-container[_ngcontent-%COMP%] {\n flex: 1;\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 1.5rem;\n overflow: hidden;\n}\n\n@media (max-width: 900px) {\n .panels-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n overflow-y: auto;\n }\n\n \n\n .panel-header[_ngcontent-%COMP%] .collapse-toggle[_ngcontent-%COMP%] {\n display: inline-block !important;\n color: var(--mat-sys-on-surface-variant) !important;\n }\n\n \n\n .panel-header[_ngcontent-%COMP%] {\n cursor: pointer;\n user-select: none;\n }\n\n .panel-header[_ngcontent-%COMP%]:hover {\n background: var(--mat-sys-surface-container);\n }\n\n \n\n .panel.collapsed[_ngcontent-%COMP%] {\n flex: 0 0 auto !important;\n }\n\n .panel.collapsed[_ngcontent-%COMP%] .panel-content[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .panel.collapsed[_ngcontent-%COMP%] .panel-header[_ngcontent-%COMP%] {\n border-bottom: none;\n }\n\n \n\n .panel[_ngcontent-%COMP%]:not(.collapsed) {\n flex: 1 1 auto;\n min-height: 150px;\n }\n}\n\n\n\n.panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n background: var(--mat-sys-surface);\n border: 1px solid var(--mat-sys-outline-variant);\n border-radius: var(--mat-sys-corner-medium);\n overflow: hidden;\n}\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n padding: 1rem 1.25rem;\n background: var(--mat-sys-surface-container);\n border-bottom: 1px solid var(--mat-sys-outline-variant);\n}\n\n.panel-header[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:first-child {\n font-size: 1.1rem;\n color: var(--mat-sys-primary);\n}\n\n.panel-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font: var(--mat-sys-title-medium);\n color: var(--mat-sys-on-surface);\n flex: 1;\n}\n\n.panel-header[_ngcontent-%COMP%] .badge[_ngcontent-%COMP%] {\n background: var(--mat-sys-primary);\n color: var(--mat-sys-on-primary);\n padding: 0.125rem 0.625rem;\n border-radius: var(--mat-sys-corner-full);\n font: var(--mat-sys-label-medium);\n font-weight: 500;\n}\n\n\n\n.panel-header[_ngcontent-%COMP%] .collapse-toggle[_ngcontent-%COMP%] {\n display: none;\n color: var(--mat-sys-on-surface-variant);\n font-size: 0.9rem;\n margin-left: 0.5rem;\n}\n\n.panel-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 0.75rem;\n}\n\n\n\n\n.sortable-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n\n\n.app-item[_ngcontent-%COMP%] {\n cursor: grab;\n transition: transform 0.2s, opacity 0.2s;\n}\n\n.app-item[_ngcontent-%COMP%]:active {\n cursor: grabbing;\n}\n\n.app-item.dragging[_ngcontent-%COMP%] {\n opacity: 0.5;\n transform: scale(0.98);\n}\n\n.app-item-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n background: var(--mat-sys-surface);\n border: 1px solid var(--mat-sys-outline-variant);\n border-left-width: 4px;\n border-radius: var(--mat-sys-corner-small);\n transition: all 0.2s ease;\n}\n\n.app-item-content[_ngcontent-%COMP%]:hover {\n border-color: var(--mat-sys-primary);\n box-shadow: var(--mat-sys-elevation-1);\n}\n\n.drag-handle[_ngcontent-%COMP%] {\n color: var(--mat-sys-on-surface-variant);\n cursor: grab;\n padding: 0.25rem;\n}\n\n.drag-handle[_ngcontent-%COMP%]:active {\n cursor: grabbing;\n}\n\n.app-icon[_ngcontent-%COMP%] {\n width: 2.5rem;\n height: 2.5rem;\n border-radius: var(--mat-sys-corner-small);\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n font-size: 1.1rem;\n flex-shrink: 0;\n}\n\n.app-info[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n min-width: 0;\n}\n\n.app-name[_ngcontent-%COMP%] {\n font: var(--mat-sys-body-large);\n font-weight: 500;\n color: var(--mat-sys-on-surface);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.app-description[_ngcontent-%COMP%] {\n font: var(--mat-sys-body-small);\n color: var(--mat-sys-on-surface-variant);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.app-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.25rem;\n flex-shrink: 0;\n}\n\n\n.app-actions[_ngcontent-%COMP%] .mj-btn-ghost[_ngcontent-%COMP%] {\n background: transparent;\n color: var(--mj-text-secondary);\n}\n\n.app-actions[_ngcontent-%COMP%] .mj-btn-ghost[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.app-actions[_ngcontent-%COMP%] .mj-btn-ghost[_ngcontent-%COMP%]:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n}\n\n.app-actions[_ngcontent-%COMP%] .mj-btn-sm[_ngcontent-%COMP%] {\n width: 1.75rem;\n height: 1.75rem;\n padding: 0;\n font-size: 0.8rem;\n}\n\n.app-actions[_ngcontent-%COMP%] .mj-btn-danger[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n}\n\n\n\n.available-app-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n margin-bottom: 0.5rem;\n background: var(--mat-sys-surface);\n border: 1px solid var(--mat-sys-outline-variant);\n border-radius: var(--mat-sys-corner-small);\n transition: all 0.2s ease;\n}\n\n.available-app-item[_ngcontent-%COMP%]:hover {\n border-color: var(--mat-sys-primary);\n background: var(--mat-sys-surface-container);\n}\n\n.available-app-item[_ngcontent-%COMP%] .app-info[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n\n\n.dialog-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1rem 1.5rem;\n background: var(--mat-sys-surface);\n border-top: 1px solid var(--mat-sys-outline-variant);\n}\n\n.footer-left[_ngcontent-%COMP%], \n.footer-right[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.75rem;\n}\n\n.dialog-footer[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n\n\n\n\n\n\n\n.mobile-view[_ngcontent-%COMP%] {\n display: none;\n}\n\n@media (max-width: 600px) {\n \n\n .desktop-only[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .config-description[_ngcontent-%COMP%] {\n display: none;\n }\n\n .mobile-view[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n flex: 1;\n overflow: hidden;\n }\n\n .mobile-list[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 0.5rem;\n }\n\n \n\n .mobile-section-label[_ngcontent-%COMP%] {\n padding: 0.5rem 0.625rem 0.25rem;\n font-size: 0.6875rem;\n font-weight: 600;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n color: var(--mj-text-secondary);\n }\n\n \n\n .mobile-app-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n padding: 0.625rem;\n border-radius: var(--mj-radius-md);\n transition: background-color 0.15s ease;\n }\n\n .mobile-app-row.inactive[_ngcontent-%COMP%] {\n opacity: 0.7;\n }\n\n .mobile-app-row[_ngcontent-%COMP%] .app-icon[_ngcontent-%COMP%] {\n width: 2rem;\n height: 2rem;\n font-size: 0.875rem;\n flex-shrink: 0;\n }\n\n .mobile-app-name[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n font-size: 0.875rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n \n\n .mobile-drag-handle[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n flex-shrink: 0;\n color: var(--mj-text-muted);\n font-size: 0.875rem;\n touch-action: none;\n cursor: grab;\n padding: 0.5rem 0;\n }\n\n .mobile-drag-handle[_ngcontent-%COMP%]:active {\n cursor: grabbing;\n color: var(--mj-text-primary);\n }\n\n \n\n .mobile-app-row.touch-dragging[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-hover);\n box-shadow: var(--mj-shadow-lg);\n border-radius: var(--mj-radius-md);\n position: relative;\n z-index: 100;\n opacity: 0.95;\n }\n\n \n\n .mobile-app-row.touch-ghost[_ngcontent-%COMP%] {\n opacity: 0.3;\n }\n\n \n\n .mobile-drop-indicator[_ngcontent-%COMP%] {\n height: 2px;\n background: var(--mj-brand-primary);\n border-radius: 1px;\n margin: 0 0.625rem;\n }\n\n \n\n .mobile-toggle[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: transparent;\n padding: 0.25rem;\n cursor: pointer;\n font-size: 1.5rem;\n flex-shrink: 0;\n transition: color 0.15s ease;\n min-width: 44px;\n min-height: 44px;\n }\n\n .mobile-toggle.on[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n }\n\n .mobile-toggle.off[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n }\n\n \n\n .modal-header[_ngcontent-%COMP%] {\n padding: 0.75rem 1rem;\n }\n\n .modal-title[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n }\n\n \n\n .config-content[_ngcontent-%COMP%] {\n padding: 0;\n }\n\n \n\n .dialog-footer[_ngcontent-%COMP%] {\n padding: 0.75rem;\n gap: 0.5rem;\n }\n\n .footer-left[_ngcontent-%COMP%], \n .footer-right[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n }\n\n}\n\n\n\n@media (prefers-reduced-motion: reduce) {\n .app-item[_ngcontent-%COMP%], \n .app-item-content[_ngcontent-%COMP%], \n .available-app-item[_ngcontent-%COMP%], \n .modal-close[_ngcontent-%COMP%] {\n transition: none;\n }\n}"] });
|
|
80
|
+
} }, dependencies: [i1.UserAppConfigContentComponent], styles: ["\n\n\n\n\n\n\n\n.modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n background: var(--mj-bg-overlay);\n z-index: 1000;\n}\n\n\n\n.full-screen-dialog[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n background: var(--mat-sys-surface);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n}\n\n\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 1rem 1.5rem;\n background: var(--mat-sys-surface);\n border-bottom: 1px solid var(--mat-sys-outline-variant);\n}\n\n.modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n margin: 0;\n font: var(--mat-sys-title-large);\n color: var(--mat-sys-on-surface);\n}\n\n.modal-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mat-sys-primary);\n}\n\n.modal-close[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.5rem;\n height: 2.5rem;\n border: none;\n border-radius: var(--mat-sys-corner-full);\n background: transparent;\n color: var(--mat-sys-on-surface-variant);\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.modal-close[_ngcontent-%COMP%]:hover {\n background: var(--mat-sys-surface-container);\n color: var(--mat-sys-on-surface);\n}\n\n.modal-close[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mat-sys-primary);\n outline-offset: 2px;\n}\n\n@media (max-width: 600px) {\n .modal-header[_ngcontent-%COMP%] {\n padding: 0.75rem 1rem;\n }\n\n .modal-title[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .modal-close[_ngcontent-%COMP%] {\n transition: none;\n }\n}"] });
|
|
739
81
|
}
|
|
740
82
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UserAppConfigComponent, [{
|
|
741
83
|
type: Component,
|
|
742
|
-
args: [{ standalone: false, selector: 'mj-user-app-config', template: "<!-- Modal Backdrop -->\n@if (ShowDialog) {\n <div class=\"modal-backdrop\" (click)=\"Close()\" role=\"presentation\"></div>\n <div\n class=\"modal-dialog full-screen-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"app-config-title\"\n >\n <!-- Dialog Header -->\n <div class=\"modal-header\">\n <h2 class=\"modal-title\" id=\"app-config-title\">\n <i class=\"fa-solid fa-grid-2\" aria-hidden=\"true\"></i>\n Configure Apps\n </h2>\n <button\n class=\"modal-close\"\n (click)=\"Close()\"\n aria-label=\"Close dialog\"\n >\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n </div>\n\n <div class=\"app-config-container\">\n <!-- Loading State -->\n @if (IsLoading) {\n <div class=\"loading-container\" role=\"status\" aria-live=\"polite\">\n <mj-loading text=\"Loading your app configuration...\" size=\"medium\"></mj-loading>\n </div>\n }\n\n <!-- Error Message -->\n @if (ErrorMessage) {\n <mj-alert Variant=\"error\">{{ ErrorMessage }}</mj-alert>\n }\n\n <!-- Main Content -->\n @if (!IsLoading) {\n <div class=\"config-content\">\n <p class=\"config-description\">\n Select which applications appear in your app switcher and arrange them in your preferred order.\n Double-click to quickly add or remove. Drag and drop to reorder, or use the arrow buttons.\n </p>\n\n <!-- Desktop: two-panel layout with drag-and-drop -->\n <div class=\"panels-container desktop-only\">\n <!-- Available Apps Panel -->\n <div class=\"panel available-apps-panel\" [class.collapsed]=\"AvailablePanelCollapsed\">\n <div class=\"panel-header\" (click)=\"AvailablePanelCollapsed = !AvailablePanelCollapsed\">\n <i class=\"fa-solid fa-layer-group\" aria-hidden=\"true\"></i>\n <h3>Available Applications</h3>\n <span class=\"badge\">{{ AvailableApps.length }}</span>\n <i\n class=\"collapse-toggle fa-solid\"\n [class.fa-chevron-down]=\"AvailablePanelCollapsed\"\n [class.fa-chevron-up]=\"!AvailablePanelCollapsed\"\n aria-hidden=\"true\"\n ></i>\n </div>\n\n <div class=\"panel-content\">\n @if (AvailableApps.length === 0) {\n <mj-empty-state\n Size=\"compact\"\n Icon=\"fa-solid fa-check-double\"\n Title=\"All applications added!\" />\n }\n\n @for (item of AvailableApps; track item.app.ID) {\n <div class=\"available-app-item\" (dblclick)=\"AddApp(item)\">\n <div class=\"app-icon\" [style.background-color]=\"item.app.GetColor()\">\n <i [class]=\"item.app.Icon || 'fa-solid fa-cube'\" aria-hidden=\"true\"></i>\n </div>\n\n <div class=\"app-info\">\n <span class=\"app-name\">{{ item.app.Name }}</span>\n @if (item.app.Description) {\n <span class=\"app-description\">{{ item.app.Description }}</span>\n }\n </div>\n\n <button\n mjButton variant=\"outline\" size=\"sm\"\n (click)=\"AddApp(item)\"\n title=\"Add to your apps\"\n [attr.aria-label]=\"'Add ' + item.app.Name\"\n >\n <i class=\"fa-solid fa-plus\" aria-hidden=\"true\"></i>\n Add\n </button>\n </div>\n }\n </div>\n </div>\n\n <!-- Selected Apps Panel -->\n <div class=\"panel selected-apps-panel\" [class.collapsed]=\"SelectedPanelCollapsed\">\n <div class=\"panel-header\" (click)=\"SelectedPanelCollapsed = !SelectedPanelCollapsed\">\n <i class=\"fa-solid fa-check-circle\" aria-hidden=\"true\"></i>\n <h3>Your Applications</h3>\n <span class=\"badge\">{{ ActiveApps.length }}</span>\n <i\n class=\"collapse-toggle fa-solid\"\n [class.fa-chevron-down]=\"SelectedPanelCollapsed\"\n [class.fa-chevron-up]=\"!SelectedPanelCollapsed\"\n aria-hidden=\"true\"\n ></i>\n </div>\n\n <div class=\"panel-content\">\n @if (ActiveApps.length === 0) {\n <mj-empty-state\n Size=\"compact\"\n Icon=\"fa-solid fa-inbox\"\n Title=\"No applications selected\"\n Message=\"Add apps from the available list\" />\n }\n\n @if (ActiveApps.length > 0) {\n <div\n class=\"sortable-list\"\n (dragover)=\"OnDragOver($event)\"\n (drop)=\"OnDrop($event)\"\n >\n @for (item of ActiveApps; track item.app.ID; let i = $index) {\n <div\n class=\"app-item\"\n [class.dragging]=\"DraggedItem === item\"\n draggable=\"true\"\n (dragstart)=\"OnDragStart($event, item, i)\"\n (dragend)=\"OnDragEnd()\"\n (dragenter)=\"OnDragEnter($event, i)\"\n (dblclick)=\"RemoveApp(item); $event.stopPropagation()\"\n >\n <div class=\"app-item-content\" [style.border-left-color]=\"item.app.GetColor()\">\n <div class=\"drag-handle\">\n <i class=\"fa-solid fa-grip-vertical\" aria-hidden=\"true\"></i>\n </div>\n\n <div class=\"app-icon\" [style.background-color]=\"item.app.GetColor()\">\n <i [class]=\"item.app.Icon || 'fa-solid fa-cube'\" aria-hidden=\"true\"></i>\n </div>\n\n <div class=\"app-info\">\n <span class=\"app-name\">{{ item.app.Name }}</span>\n @if (item.app.Description) {\n <span class=\"app-description\">{{ item.app.Description }}</span>\n }\n </div>\n\n <div class=\"app-actions\">\n <button\n mjButton variant=\"flat\" size=\"sm\"\n [disabled]=\"i === 0\"\n (click)=\"MoveUp(item); $event.stopPropagation()\"\n title=\"Move up\"\n [attr.aria-label]=\"'Move ' + item.app.Name + ' up'\"\n >\n <i class=\"fa-solid fa-chevron-up\" aria-hidden=\"true\"></i>\n </button>\n <button\n mjButton variant=\"flat\" size=\"sm\"\n [disabled]=\"i === ActiveApps.length - 1\"\n (click)=\"MoveDown(item); $event.stopPropagation()\"\n title=\"Move down\"\n [attr.aria-label]=\"'Move ' + item.app.Name + ' down'\"\n >\n <i class=\"fa-solid fa-chevron-down\" aria-hidden=\"true\"></i>\n </button>\n <button\n mjButton variant=\"danger\" size=\"sm\"\n (click)=\"RemoveApp(item); $event.stopPropagation()\"\n title=\"Remove from your apps\"\n [attr.aria-label]=\"'Remove ' + item.app.Name\"\n >\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Mobile: single list with toggles + touch drag reorder -->\n <div\n class=\"mobile-view\"\n (touchmove)=\"OnTouchDragMove($event)\"\n (touchend)=\"OnTouchDragEnd()\"\n (touchcancel)=\"OnTouchDragEnd()\"\n >\n <div class=\"mobile-list\">\n @if (ActiveApps.length > 0) {\n <div class=\"mobile-section-label\">Your Apps</div>\n @for (item of ActiveApps; track item.app.ID; let i = $index) {\n @if (TouchDragActive && TouchDropIndex === i && TouchDragIndex > i) {\n <div class=\"mobile-drop-indicator\"></div>\n }\n <div\n class=\"mobile-app-row\"\n [class.touch-ghost]=\"TouchDragActive && TouchDragIndex === i\"\n >\n <div\n class=\"mobile-drag-handle\"\n (touchstart)=\"OnTouchDragStart($event, i)\"\n aria-label=\"Drag to reorder\"\n >\n <i class=\"fa-solid fa-grip-vertical\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"app-icon\" [style.background-color]=\"item.app.GetColor()\">\n <i [class]=\"item.app.Icon || 'fa-solid fa-cube'\" aria-hidden=\"true\"></i>\n </div>\n <span class=\"mobile-app-name\">{{ item.app.Name }}</span>\n <button\n class=\"mobile-toggle on\"\n (click)=\"ToggleApp(item)\"\n aria-label=\"Remove {{ item.app.Name }}\"\n >\n <i class=\"fa-solid fa-toggle-on\" aria-hidden=\"true\"></i>\n </button>\n </div>\n @if (TouchDragActive && TouchDropIndex === i && TouchDragIndex < i) {\n <div class=\"mobile-drop-indicator\"></div>\n }\n }\n @if (TouchDragActive && TouchDropIndex === ActiveApps.length - 1 && TouchDragIndex < TouchDropIndex) {\n <div class=\"mobile-drop-indicator\"></div>\n }\n }\n\n @if (AvailableApps.length > 0) {\n <div class=\"mobile-section-label\">Available</div>\n @for (item of AvailableApps; track item.app.ID) {\n <div class=\"mobile-app-row inactive\">\n <div class=\"app-icon\" [style.background-color]=\"item.app.GetColor()\">\n <i [class]=\"item.app.Icon || 'fa-solid fa-cube'\" aria-hidden=\"true\"></i>\n </div>\n <span class=\"mobile-app-name\">{{ item.app.Name }}</span>\n <button\n class=\"mobile-toggle off\"\n (click)=\"ToggleApp(item)\"\n aria-label=\"Add {{ item.app.Name }}\"\n >\n <i class=\"fa-solid fa-toggle-off\" aria-hidden=\"true\"></i>\n </button>\n </div>\n }\n }\n </div>\n </div>\n </div>\n }\n\n <!-- Footer Actions -->\n <div class=\"dialog-footer\">\n <div class=\"footer-left\">\n @if (HasChanges()) {\n <button\n mjButton\n (click)=\"Reset()\"\n [disabled]=\"IsLoading || IsSaving\"\n >\n <i class=\"fa-solid fa-rotate-left\" aria-hidden=\"true\"></i>\n Reset Changes\n </button>\n }\n </div>\n <div class=\"footer-right\">\n <button\n mjButton variant=\"primary\"\n (click)=\"Save()\"\n [disabled]=\"IsLoading || IsSaving || !HasChanges()\"\n >\n @if (IsSaving) {\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n <span>Saving...</span>\n } @else {\n <i class=\"fa-solid fa-check\" aria-hidden=\"true\"></i>\n <span>Save Changes</span>\n }\n </button>\n <button\n mjButton\n (click)=\"Close()\"\n [disabled]=\"IsSaving\"\n >\n Cancel\n </button>\n </div>\n </div>\n </div>\n </div>\n}\n", styles: ["/* ============================================\n User App Config - MD3 Design System\n ============================================ */\n\n/* Modal Backdrop */\n.modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n background: rgba(0, 0, 0, 0.5);\n z-index: 1000;\n}\n\n/* Full-screen dialog */\n.full-screen-dialog {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n background: var(--mat-sys-surface);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n}\n\n/* Modal Header */\n.modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 1rem 1.5rem;\n background: var(--mat-sys-surface);\n border-bottom: 1px solid var(--mat-sys-outline-variant);\n}\n\n.modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n margin: 0;\n font: var(--mat-sys-title-large);\n color: var(--mat-sys-on-surface);\n}\n\n.modal-title i {\n color: var(--mat-sys-primary);\n}\n\n.modal-close {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.5rem;\n height: 2.5rem;\n border: none;\n border-radius: var(--mat-sys-corner-full);\n background: transparent;\n color: var(--mat-sys-on-surface-variant);\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.modal-close:hover {\n background: var(--mat-sys-surface-container);\n color: var(--mat-sys-on-surface);\n}\n\n.modal-close:focus-visible {\n outline: 2px solid var(--mat-sys-primary);\n outline-offset: 2px;\n}\n\n/* Main container */\n.app-config-container {\n display: flex;\n flex-direction: column;\n flex: 1;\n overflow: hidden;\n background: var(--mat-sys-surface-container-lowest);\n}\n\n/* Loading state */\n.loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 1rem;\n color: var(--mat-sys-on-surface-variant);\n}\n\n\n/* Config content */\n.config-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n padding: 1.5rem;\n overflow: hidden;\n}\n\n.config-description {\n margin: 0 0 1.5rem 0;\n color: var(--mat-sys-on-surface-variant);\n font: var(--mat-sys-body-large);\n line-height: 1.5;\n}\n\n/* Panels container */\n.panels-container {\n flex: 1;\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 1.5rem;\n overflow: hidden;\n}\n\n@media (max-width: 900px) {\n .panels-container {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n overflow-y: auto;\n }\n\n /* Show collapse toggle on mobile */\n .panel-header .collapse-toggle {\n display: inline-block !important;\n color: var(--mat-sys-on-surface-variant) !important;\n }\n\n /* Make header clickable on mobile */\n .panel-header {\n cursor: pointer;\n user-select: none;\n }\n\n .panel-header:hover {\n background: var(--mat-sys-surface-container);\n }\n\n /* Collapsed panel - just show header */\n .panel.collapsed {\n flex: 0 0 auto !important;\n }\n\n .panel.collapsed .panel-content {\n display: none !important;\n }\n\n .panel.collapsed .panel-header {\n border-bottom: none;\n }\n\n /* Non-collapsed panel takes available space */\n .panel:not(.collapsed) {\n flex: 1 1 auto;\n min-height: 150px;\n }\n}\n\n/* Panel styles */\n.panel {\n display: flex;\n flex-direction: column;\n background: var(--mat-sys-surface);\n border: 1px solid var(--mat-sys-outline-variant);\n border-radius: var(--mat-sys-corner-medium);\n overflow: hidden;\n}\n\n.panel-header {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n padding: 1rem 1.25rem;\n background: var(--mat-sys-surface-container);\n border-bottom: 1px solid var(--mat-sys-outline-variant);\n}\n\n.panel-header i:first-child {\n font-size: 1.1rem;\n color: var(--mat-sys-primary);\n}\n\n.panel-header h3 {\n margin: 0;\n font: var(--mat-sys-title-medium);\n color: var(--mat-sys-on-surface);\n flex: 1;\n}\n\n.panel-header .badge {\n background: var(--mat-sys-primary);\n color: var(--mat-sys-on-primary);\n padding: 0.125rem 0.625rem;\n border-radius: var(--mat-sys-corner-full);\n font: var(--mat-sys-label-medium);\n font-weight: 500;\n}\n\n/* Collapse toggle - hidden by default, shown on mobile */\n.panel-header .collapse-toggle {\n display: none;\n color: var(--mat-sys-on-surface-variant);\n font-size: 0.9rem;\n margin-left: 0.5rem;\n}\n\n.panel-content {\n flex: 1;\n overflow-y: auto;\n padding: 0.75rem;\n}\n\n\n/* Sortable list container */\n.sortable-list {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n/* App items */\n.app-item {\n cursor: grab;\n transition: transform 0.2s, opacity 0.2s;\n}\n\n.app-item:active {\n cursor: grabbing;\n}\n\n.app-item.dragging {\n opacity: 0.5;\n transform: scale(0.98);\n}\n\n.app-item-content {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n background: var(--mat-sys-surface);\n border: 1px solid var(--mat-sys-outline-variant);\n border-left-width: 4px;\n border-radius: var(--mat-sys-corner-small);\n transition: all 0.2s ease;\n}\n\n.app-item-content:hover {\n border-color: var(--mat-sys-primary);\n box-shadow: var(--mat-sys-elevation-1);\n}\n\n.drag-handle {\n color: var(--mat-sys-on-surface-variant);\n cursor: grab;\n padding: 0.25rem;\n}\n\n.drag-handle:active {\n cursor: grabbing;\n}\n\n.app-icon {\n width: 2.5rem;\n height: 2.5rem;\n border-radius: var(--mat-sys-corner-small);\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n font-size: 1.1rem;\n flex-shrink: 0;\n}\n\n.app-info {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 0.125rem;\n min-width: 0;\n}\n\n.app-name {\n font: var(--mat-sys-body-large);\n font-weight: 500;\n color: var(--mat-sys-on-surface);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.app-description {\n font: var(--mat-sys-body-small);\n color: var(--mat-sys-on-surface-variant);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.app-actions {\n display: flex;\n gap: 0.25rem;\n flex-shrink: 0;\n}\n\n\n.app-actions .mj-btn-ghost {\n background: transparent;\n color: var(--mj-text-secondary);\n}\n\n.app-actions .mj-btn-ghost:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.app-actions .mj-btn-ghost:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n}\n\n.app-actions .mj-btn-sm {\n width: 1.75rem;\n height: 1.75rem;\n padding: 0;\n font-size: 0.8rem;\n}\n\n.app-actions .mj-btn-danger:hover:not(:disabled) {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n}\n\n/* Available app items */\n.available-app-item {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n margin-bottom: 0.5rem;\n background: var(--mat-sys-surface);\n border: 1px solid var(--mat-sys-outline-variant);\n border-radius: var(--mat-sys-corner-small);\n transition: all 0.2s ease;\n}\n\n.available-app-item:hover {\n border-color: var(--mat-sys-primary);\n background: var(--mat-sys-surface-container);\n}\n\n.available-app-item .app-info {\n flex: 1;\n}\n\n/* Dialog footer */\n.dialog-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1rem 1.5rem;\n background: var(--mat-sys-surface);\n border-top: 1px solid var(--mat-sys-outline-variant);\n}\n\n.footer-left,\n.footer-right {\n display: flex;\n gap: 0.75rem;\n}\n\n.dialog-footer button {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n/* ==============================================\n Mobile: single list with toggles\n ============================================== */\n\n/* Hidden by default on desktop */\n.mobile-view {\n display: none;\n}\n\n@media (max-width: 600px) {\n /* Swap layouts */\n .desktop-only {\n display: none !important;\n }\n\n .config-description {\n display: none;\n }\n\n .mobile-view {\n display: flex;\n flex-direction: column;\n flex: 1;\n overflow: hidden;\n }\n\n .mobile-list {\n flex: 1;\n overflow-y: auto;\n padding: 0.5rem;\n }\n\n /* Section labels */\n .mobile-section-label {\n padding: 0.5rem 0.625rem 0.25rem;\n font-size: 0.6875rem;\n font-weight: 600;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n color: var(--mj-text-secondary);\n }\n\n /* App rows */\n .mobile-app-row {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n padding: 0.625rem;\n border-radius: var(--mj-radius-md);\n transition: background-color 0.15s ease;\n }\n\n .mobile-app-row.inactive {\n opacity: 0.7;\n }\n\n .mobile-app-row .app-icon {\n width: 2rem;\n height: 2rem;\n font-size: 0.875rem;\n flex-shrink: 0;\n }\n\n .mobile-app-name {\n flex: 1;\n min-width: 0;\n font-size: 0.875rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n /* Drag handle */\n .mobile-drag-handle {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n flex-shrink: 0;\n color: var(--mj-text-muted);\n font-size: 0.875rem;\n touch-action: none;\n cursor: grab;\n padding: 0.5rem 0;\n }\n\n .mobile-drag-handle:active {\n cursor: grabbing;\n color: var(--mj-text-primary);\n }\n\n /* Dragging row */\n .mobile-app-row.touch-dragging {\n background: var(--mj-bg-surface-hover);\n box-shadow: var(--mj-shadow-lg);\n border-radius: var(--mj-radius-md);\n position: relative;\n z-index: 100;\n opacity: 0.95;\n }\n\n /* Ghost placeholder for the original position */\n .mobile-app-row.touch-ghost {\n opacity: 0.3;\n }\n\n /* Drop indicator line */\n .mobile-drop-indicator {\n height: 2px;\n background: var(--mj-brand-primary);\n border-radius: 1px;\n margin: 0 0.625rem;\n }\n\n /* Toggle button */\n .mobile-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: transparent;\n padding: 0.25rem;\n cursor: pointer;\n font-size: 1.5rem;\n flex-shrink: 0;\n transition: color 0.15s ease;\n min-width: 44px;\n min-height: 44px;\n }\n\n .mobile-toggle.on {\n color: var(--mj-brand-primary);\n }\n\n .mobile-toggle.off {\n color: var(--mj-text-muted);\n }\n\n /* Header compact */\n .modal-header {\n padding: 0.75rem 1rem;\n }\n\n .modal-title {\n font-size: 1.125rem;\n }\n\n /* Content compact */\n .config-content {\n padding: 0;\n }\n\n /* Footer compact */\n .dialog-footer {\n padding: 0.75rem;\n gap: 0.5rem;\n }\n\n .footer-left,\n .footer-right {\n display: flex;\n gap: 0.5rem;\n }\n\n}\n\n/* Accessibility - Reduced Motion */\n@media (prefers-reduced-motion: reduce) {\n .app-item,\n .app-item-content,\n .available-app-item,\n .modal-close {\n transition: none;\n }\n}\n"] }]
|
|
84
|
+
args: [{ standalone: false, selector: 'mj-user-app-config', template: "<!-- Modal Backdrop -->\n@if (ShowDialog) {\n <div class=\"modal-backdrop\" (click)=\"Close()\" role=\"presentation\"></div>\n <div\n class=\"modal-dialog full-screen-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"app-config-title\"\n >\n <!-- Dialog Header -->\n <div class=\"modal-header\">\n <h2 class=\"modal-title\" id=\"app-config-title\">\n <i class=\"fa-solid fa-grip\" aria-hidden=\"true\"></i>\n Configure Apps\n </h2>\n <button\n class=\"modal-close\"\n (click)=\"Close()\"\n aria-label=\"Close dialog\"\n >\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n </div>\n\n <mj-user-app-config-content\n [Provider]=\"Provider\"\n (Saved)=\"OnContentSaved()\"\n (Cancelled)=\"Close()\">\n </mj-user-app-config-content>\n </div>\n}\n", styles: ["/* ============================================\n User App Config \u2014 full-screen modal chrome.\n Content styles live in user-app-config-content.component.css\n ============================================ */\n\n/* Modal Backdrop */\n.modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n background: var(--mj-bg-overlay);\n z-index: 1000;\n}\n\n/* Full-screen dialog */\n.full-screen-dialog {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n background: var(--mat-sys-surface);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n}\n\n/* Modal Header */\n.modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 1rem 1.5rem;\n background: var(--mat-sys-surface);\n border-bottom: 1px solid var(--mat-sys-outline-variant);\n}\n\n.modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n margin: 0;\n font: var(--mat-sys-title-large);\n color: var(--mat-sys-on-surface);\n}\n\n.modal-title i {\n color: var(--mat-sys-primary);\n}\n\n.modal-close {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.5rem;\n height: 2.5rem;\n border: none;\n border-radius: var(--mat-sys-corner-full);\n background: transparent;\n color: var(--mat-sys-on-surface-variant);\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.modal-close:hover {\n background: var(--mat-sys-surface-container);\n color: var(--mat-sys-on-surface);\n}\n\n.modal-close:focus-visible {\n outline: 2px solid var(--mat-sys-primary);\n outline-offset: 2px;\n}\n\n@media (max-width: 600px) {\n .modal-header {\n padding: 0.75rem 1rem;\n }\n\n .modal-title {\n font-size: 1.125rem;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .modal-close {\n transition: none;\n }\n}\n"] }]
|
|
743
85
|
}], null, { ShowDialog: [{
|
|
744
86
|
type: Input
|
|
745
87
|
}], ShowDialogChange: [{
|
|
@@ -747,5 +89,5 @@ export class UserAppConfigComponent extends BaseAngularComponent {
|
|
|
747
89
|
}], ConfigSaved: [{
|
|
748
90
|
type: Output
|
|
749
91
|
}] }); })();
|
|
750
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserAppConfigComponent, { className: "UserAppConfigComponent", filePath: "src/lib/user-app-config/user-app-config.component.ts", lineNumber:
|
|
92
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserAppConfigComponent, { className: "UserAppConfigComponent", filePath: "src/lib/user-app-config/user-app-config.component.ts", lineNumber: 23 }); })();
|
|
751
93
|
//# sourceMappingURL=user-app-config.component.js.map
|