@memberjunction/ng-explorer-core 2.128.0 → 2.129.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/dist/app-routing.module.d.ts +7 -1
  2. package/dist/app-routing.module.d.ts.map +1 -1
  3. package/dist/app-routing.module.js +41 -74
  4. package/dist/app-routing.module.js.map +1 -1
  5. package/dist/generic/Item.types.d.ts +0 -54
  6. package/dist/generic/Item.types.d.ts.map +1 -1
  7. package/dist/generic/Item.types.js +0 -79
  8. package/dist/generic/Item.types.js.map +1 -1
  9. package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts +49 -2
  10. package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts.map +1 -1
  11. package/dist/lib/resource-wrappers/chat-conversations-resource.component.js +263 -27
  12. package/dist/lib/resource-wrappers/chat-conversations-resource.component.js.map +1 -1
  13. package/dist/lib/resource-wrappers/dashboard-resource.component.d.ts.map +1 -1
  14. package/dist/lib/resource-wrappers/dashboard-resource.component.js +20 -26
  15. package/dist/lib/resource-wrappers/dashboard-resource.component.js.map +1 -1
  16. package/dist/lib/shell/components/dialogs/app-access-dialog.component.d.ts +108 -0
  17. package/dist/lib/shell/components/dialogs/app-access-dialog.component.d.ts.map +1 -0
  18. package/dist/lib/shell/components/dialogs/app-access-dialog.component.js +371 -0
  19. package/dist/lib/shell/components/dialogs/app-access-dialog.component.js.map +1 -0
  20. package/dist/lib/shell/components/tabs/tab-container.component.d.ts +22 -2
  21. package/dist/lib/shell/components/tabs/tab-container.component.d.ts.map +1 -1
  22. package/dist/lib/shell/components/tabs/tab-container.component.js +40 -14
  23. package/dist/lib/shell/components/tabs/tab-container.component.js.map +1 -1
  24. package/dist/lib/shell/loading-themes.d.ts +160 -0
  25. package/dist/lib/shell/loading-themes.d.ts.map +1 -0
  26. package/dist/lib/shell/loading-themes.js +838 -0
  27. package/dist/lib/shell/loading-themes.js.map +1 -0
  28. package/dist/lib/shell/shell.component.d.ts +118 -0
  29. package/dist/lib/shell/shell.component.d.ts.map +1 -1
  30. package/dist/lib/shell/shell.component.js +744 -226
  31. package/dist/lib/shell/shell.component.js.map +1 -1
  32. package/dist/lib/shell/shell.module.d.ts +8 -7
  33. package/dist/lib/shell/shell.module.d.ts.map +1 -1
  34. package/dist/lib/shell/shell.module.js +5 -2
  35. package/dist/lib/shell/shell.module.js.map +1 -1
  36. package/dist/lib/single-dashboard/single-dashboard.component.d.ts +1 -0
  37. package/dist/lib/single-dashboard/single-dashboard.component.d.ts.map +1 -1
  38. package/dist/lib/single-dashboard/single-dashboard.component.js +4 -0
  39. package/dist/lib/single-dashboard/single-dashboard.component.js.map +1 -1
  40. package/dist/lib/single-list-detail/single-list-detail.component.js +1 -1
  41. package/dist/lib/single-list-detail/single-list-detail.component.js.map +1 -1
  42. package/dist/module.d.ts +62 -88
  43. package/dist/module.d.ts.map +1 -1
  44. package/dist/module.js +9 -149
  45. package/dist/module.js.map +1 -1
  46. package/dist/public-api.d.ts +0 -19
  47. package/dist/public-api.d.ts.map +1 -1
  48. package/dist/public-api.js +0 -19
  49. package/dist/public-api.js.map +1 -1
  50. package/package.json +35 -40
  51. package/dist/generic/Events.types.d.ts +0 -174
  52. package/dist/generic/Events.types.d.ts.map +0 -1
  53. package/dist/generic/Events.types.js +0 -220
  54. package/dist/generic/Events.types.js.map +0 -1
  55. package/dist/lib/app-view/application-view.component.d.ts +0 -65
  56. package/dist/lib/app-view/application-view.component.d.ts.map +0 -1
  57. package/dist/lib/app-view/application-view.component.js +0 -611
  58. package/dist/lib/app-view/application-view.component.js.map +0 -1
  59. package/dist/lib/auth-button/auth-button.component.d.ts +0 -13
  60. package/dist/lib/auth-button/auth-button.component.d.ts.map +0 -1
  61. package/dist/lib/auth-button/auth-button.component.js +0 -36
  62. package/dist/lib/auth-button/auth-button.component.js.map +0 -1
  63. package/dist/lib/base-browser-component/base-browser-component.d.ts +0 -44
  64. package/dist/lib/base-browser-component/base-browser-component.d.ts.map +0 -1
  65. package/dist/lib/base-browser-component/base-browser-component.js +0 -195
  66. package/dist/lib/base-browser-component/base-browser-component.js.map +0 -1
  67. package/dist/lib/chat-wrapper/chat-wrapper.component.d.ts +0 -54
  68. package/dist/lib/chat-wrapper/chat-wrapper.component.d.ts.map +0 -1
  69. package/dist/lib/chat-wrapper/chat-wrapper.component.js +0 -257
  70. package/dist/lib/chat-wrapper/chat-wrapper.component.js.map +0 -1
  71. package/dist/lib/dashboard-browser-component/dashboard-browser.component.d.ts +0 -32
  72. package/dist/lib/dashboard-browser-component/dashboard-browser.component.d.ts.map +0 -1
  73. package/dist/lib/dashboard-browser-component/dashboard-browser.component.js +0 -244
  74. package/dist/lib/dashboard-browser-component/dashboard-browser.component.js.map +0 -1
  75. package/dist/lib/data-browser-component/data-browser.component.d.ts +0 -23
  76. package/dist/lib/data-browser-component/data-browser.component.d.ts.map +0 -1
  77. package/dist/lib/data-browser-component/data-browser.component.js +0 -267
  78. package/dist/lib/data-browser-component/data-browser.component.js.map +0 -1
  79. package/dist/lib/expansion-panel-component/expansion-panel-component.d.ts +0 -21
  80. package/dist/lib/expansion-panel-component/expansion-panel-component.d.ts.map +0 -1
  81. package/dist/lib/expansion-panel-component/expansion-panel-component.js +0 -158
  82. package/dist/lib/expansion-panel-component/expansion-panel-component.js.map +0 -1
  83. package/dist/lib/favorites/favorites.component.d.ts +0 -15
  84. package/dist/lib/favorites/favorites.component.d.ts.map +0 -1
  85. package/dist/lib/favorites/favorites.component.js +0 -135
  86. package/dist/lib/favorites/favorites.component.js.map +0 -1
  87. package/dist/lib/files/files.component.d.ts +0 -10
  88. package/dist/lib/files/files.component.d.ts.map +0 -1
  89. package/dist/lib/files/files.component.js +0 -41
  90. package/dist/lib/files/files.component.js.map +0 -1
  91. package/dist/lib/generic-browse-list/generic-browse-list.component.d.ts +0 -30
  92. package/dist/lib/generic-browse-list/generic-browse-list.component.d.ts.map +0 -1
  93. package/dist/lib/generic-browse-list/generic-browse-list.component.js +0 -171
  94. package/dist/lib/generic-browse-list/generic-browse-list.component.js.map +0 -1
  95. package/dist/lib/generic-browser-list/generic-browser-list.component.d.ts +0 -120
  96. package/dist/lib/generic-browser-list/generic-browser-list.component.d.ts.map +0 -1
  97. package/dist/lib/generic-browser-list/generic-browser-list.component.js +0 -1093
  98. package/dist/lib/generic-browser-list/generic-browser-list.component.js.map +0 -1
  99. package/dist/lib/header/MSFT_UserImageService.d.ts +0 -12
  100. package/dist/lib/header/MSFT_UserImageService.d.ts.map +0 -1
  101. package/dist/lib/header/MSFT_UserImageService.js +0 -25
  102. package/dist/lib/header/MSFT_UserImageService.js.map +0 -1
  103. package/dist/lib/header/header.component.d.ts +0 -69
  104. package/dist/lib/header/header.component.d.ts.map +0 -1
  105. package/dist/lib/header/header.component.js +0 -342
  106. package/dist/lib/header/header.component.js.map +0 -1
  107. package/dist/lib/home-component/home.component.d.ts +0 -22
  108. package/dist/lib/home-component/home.component.d.ts.map +0 -1
  109. package/dist/lib/home-component/home.component.js +0 -194
  110. package/dist/lib/home-component/home.component.js.map +0 -1
  111. package/dist/lib/home-wrapper/home-wrapper.component.d.ts +0 -7
  112. package/dist/lib/home-wrapper/home-wrapper.component.d.ts.map +0 -1
  113. package/dist/lib/home-wrapper/home-wrapper.component.js +0 -30
  114. package/dist/lib/home-wrapper/home-wrapper.component.js.map +0 -1
  115. package/dist/lib/list-view/list-view.component.d.ts +0 -45
  116. package/dist/lib/list-view/list-view.component.d.ts.map +0 -1
  117. package/dist/lib/list-view/list-view.component.js +0 -329
  118. package/dist/lib/list-view/list-view.component.js.map +0 -1
  119. package/dist/lib/navigation/navigation.component.d.ts +0 -142
  120. package/dist/lib/navigation/navigation.component.d.ts.map +0 -1
  121. package/dist/lib/navigation/navigation.component.js +0 -1212
  122. package/dist/lib/navigation/navigation.component.js.map +0 -1
  123. package/dist/lib/query-browser-component/query-browser.component.d.ts +0 -75
  124. package/dist/lib/query-browser-component/query-browser.component.d.ts.map +0 -1
  125. package/dist/lib/query-browser-component/query-browser.component.js +0 -908
  126. package/dist/lib/query-browser-component/query-browser.component.js.map +0 -1
  127. package/dist/lib/report-browser-component/report-browser.component.d.ts +0 -22
  128. package/dist/lib/report-browser-component/report-browser.component.d.ts.map +0 -1
  129. package/dist/lib/report-browser-component/report-browser.component.js +0 -80
  130. package/dist/lib/report-browser-component/report-browser.component.js.map +0 -1
  131. package/dist/lib/resource-browser/resource-browser.component.d.ts +0 -178
  132. package/dist/lib/resource-browser/resource-browser.component.d.ts.map +0 -1
  133. package/dist/lib/resource-browser/resource-browser.component.js +0 -1012
  134. package/dist/lib/resource-browser/resource-browser.component.js.map +0 -1
  135. package/dist/lib/shared/custom-icon/custom-icon.component.d.ts +0 -11
  136. package/dist/lib/shared/custom-icon/custom-icon.component.d.ts.map +0 -1
  137. package/dist/lib/shared/custom-icon/custom-icon.component.js +0 -44
  138. package/dist/lib/shared/custom-icon/custom-icon.component.js.map +0 -1
  139. package/dist/lib/single-application/single-application.component.d.ts +0 -24
  140. package/dist/lib/single-application/single-application.component.d.ts.map +0 -1
  141. package/dist/lib/single-application/single-application.component.js +0 -122
  142. package/dist/lib/single-application/single-application.component.js.map +0 -1
  143. package/dist/lib/single-entity/single-entity.component.d.ts +0 -34
  144. package/dist/lib/single-entity/single-entity.component.d.ts.map +0 -1
  145. package/dist/lib/single-entity/single-entity.component.js +0 -245
  146. package/dist/lib/single-entity/single-entity.component.js.map +0 -1
  147. package/dist/lib/style-guide-test/style-guide-test.component.d.ts +0 -70
  148. package/dist/lib/style-guide-test/style-guide-test.component.d.ts.map +0 -1
  149. package/dist/lib/style-guide-test/style-guide-test.component.js +0 -1024
  150. package/dist/lib/style-guide-test/style-guide-test.component.js.map +0 -1
  151. package/dist/lib/tabbed-dashboard/tabbed-dashboard.component.d.ts +0 -46
  152. package/dist/lib/tabbed-dashboard/tabbed-dashboard.component.d.ts.map +0 -1
  153. package/dist/lib/tabbed-dashboard/tabbed-dashboard.component.js +0 -547
  154. package/dist/lib/tabbed-dashboard/tabbed-dashboard.component.js.map +0 -1
@@ -1,11 +1,12 @@
1
1
  import { Component, ViewChild } from '@angular/core';
2
2
  import { NavigationEnd } from '@angular/router';
3
- import { firstValueFrom } from 'rxjs';
3
+ import { firstValueFrom, combineLatest } from 'rxjs';
4
4
  import { filter } from 'rxjs/operators';
5
- import { Metadata } from '@memberjunction/core';
5
+ import { Metadata, LogStatus, StartupManager } from '@memberjunction/core';
6
6
  import { MJEventType, MJGlobal, uuidv4 } from '@memberjunction/global';
7
7
  import { EventCodes, SYSTEM_APP_ID } from '@memberjunction/ng-shared';
8
8
  import { MJNotificationService } from '@memberjunction/ng-notifications';
9
+ import { getActiveTheme } from './loading-themes';
9
10
  import * as i0 from "@angular/core";
10
11
  import * as i1 from "@memberjunction/ng-base-application";
11
12
  import * as i2 from "@memberjunction/ng-shared";
@@ -21,285 +22,187 @@ import * as i11 from "@memberjunction/ng-shared-generic";
21
22
  import * as i12 from "./components/header/app-switcher.component";
22
23
  import * as i13 from "./components/header/app-nav.component";
23
24
  import * as i14 from "./components/tabs/tab-container.component";
25
+ import * as i15 from "./components/dialogs/app-access-dialog.component";
24
26
  const _c0 = ["searchInput"];
25
- function ShellComponent_div_0_div_5_button_1_Template(rf, ctx) { if (rf & 1) {
26
- const _r3 = i0.ɵɵgetCurrentView();
27
- i0.ɵɵelementStart(0, "button", 42);
28
- i0.ɵɵlistener("click", function ShellComponent_div_0_div_5_button_1_Template_button_click_0_listener($event) { const app_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onNavBarAppClick(app_r4, $event)); })("dblclick", function ShellComponent_div_0_div_5_button_1_Template_button_dblclick_0_listener($event) { const app_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onNavBarAppDblClick(app_r4, $event)); });
27
+ const _c1 = ["appAccessDialog"];
28
+ function ShellComponent_div_5_button_1_Template(rf, ctx) { if (rf & 1) {
29
+ const _r2 = i0.ɵɵgetCurrentView();
30
+ i0.ɵɵelementStart(0, "button", 44);
31
+ i0.ɵɵlistener("click", function ShellComponent_div_5_button_1_Template_button_click_0_listener($event) { const app_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.onNavBarAppClick(app_r3, $event)); })("dblclick", function ShellComponent_div_5_button_1_Template_button_dblclick_0_listener($event) { const app_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.onNavBarAppDblClick(app_r3, $event)); });
29
32
  i0.ɵɵelement(1, "i");
30
33
  i0.ɵɵelementEnd();
31
34
  } if (rf & 2) {
32
- const app_r4 = ctx.$implicit;
33
- const ctx_r1 = i0.ɵɵnextContext(3);
34
- i0.ɵɵstyleProp("--app-color", app_r4.GetColor());
35
- i0.ɵɵclassProp("active", app_r4.ID === (ctx_r1.activeApp == null ? null : ctx_r1.activeApp.ID));
36
- i0.ɵɵproperty("title", app_r4.Name);
35
+ const app_r3 = ctx.$implicit;
36
+ const ctx_r3 = i0.ɵɵnextContext(2);
37
+ i0.ɵɵstyleProp("--app-color", app_r3.GetColor());
38
+ i0.ɵɵclassProp("active", app_r3.ID === (ctx_r3.activeApp == null ? null : ctx_r3.activeApp.ID));
39
+ i0.ɵɵproperty("title", app_r3.Name);
37
40
  i0.ɵɵadvance();
38
- i0.ɵɵclassMap(app_r4.Icon);
41
+ i0.ɵɵclassMap(app_r3.Icon);
39
42
  } }
40
- function ShellComponent_div_0_div_5_Template(rf, ctx) { if (rf & 1) {
41
- i0.ɵɵelementStart(0, "div", 40);
42
- i0.ɵɵtemplate(1, ShellComponent_div_0_div_5_button_1_Template, 2, 7, "button", 41);
43
+ function ShellComponent_div_5_Template(rf, ctx) { if (rf & 1) {
44
+ i0.ɵɵelementStart(0, "div", 42);
45
+ i0.ɵɵtemplate(1, ShellComponent_div_5_button_1_Template, 2, 7, "button", 43);
43
46
  i0.ɵɵelementEnd();
44
47
  } if (rf & 2) {
45
- const ctx_r1 = i0.ɵɵnextContext(2);
48
+ const ctx_r3 = i0.ɵɵnextContext();
46
49
  i0.ɵɵadvance();
47
- i0.ɵɵproperty("ngForOf", ctx_r1.leftOfSwitcherApps);
50
+ i0.ɵɵproperty("ngForOf", ctx_r3.leftOfSwitcherApps);
48
51
  } }
49
- function ShellComponent_div_0_mj_app_nav_7_Template(rf, ctx) { if (rf & 1) {
52
+ function ShellComponent_mj_app_nav_7_Template(rf, ctx) { if (rf & 1) {
50
53
  const _r5 = i0.ɵɵgetCurrentView();
51
- i0.ɵɵelementStart(0, "mj-app-nav", 43);
52
- i0.ɵɵlistener("navItemClick", function ShellComponent_div_0_mj_app_nav_7_Template_mj_app_nav_navItemClick_0_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onNavItemClick($event)); });
54
+ i0.ɵɵelementStart(0, "mj-app-nav", 45);
55
+ i0.ɵɵlistener("navItemClick", function ShellComponent_mj_app_nav_7_Template_mj_app_nav_navItemClick_0_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onNavItemClick($event)); });
53
56
  i0.ɵɵelementEnd();
54
57
  } if (rf & 2) {
55
- const ctx_r1 = i0.ɵɵnextContext(2);
56
- i0.ɵɵproperty("app", ctx_r1.activeApp);
58
+ const ctx_r3 = i0.ɵɵnextContext();
59
+ i0.ɵɵproperty("app", ctx_r3.activeApp);
57
60
  } }
58
- function ShellComponent_div_0_span_14_Template(rf, ctx) { if (rf & 1) {
59
- i0.ɵɵelementStart(0, "span", 44);
61
+ function ShellComponent_span_14_Template(rf, ctx) { if (rf & 1) {
62
+ i0.ɵɵelementStart(0, "span", 46);
60
63
  i0.ɵɵtext(1);
61
64
  i0.ɵɵelementEnd();
62
65
  } if (rf & 2) {
63
- const ctx_r1 = i0.ɵɵnextContext(2);
66
+ const ctx_r3 = i0.ɵɵnextContext();
64
67
  i0.ɵɵadvance();
65
- i0.ɵɵtextInterpolate1(" ", ctx_r1.unreadNotificationCount > 99 ? "99+" : ctx_r1.unreadNotificationCount, " ");
68
+ i0.ɵɵtextInterpolate1(" ", ctx_r3.unreadNotificationCount > 99 ? "99+" : ctx_r3.unreadNotificationCount, " ");
66
69
  } }
67
- function ShellComponent_div_0_div_15_button_1_Template(rf, ctx) { if (rf & 1) {
70
+ function ShellComponent_div_15_button_1_Template(rf, ctx) { if (rf & 1) {
68
71
  const _r6 = i0.ɵɵgetCurrentView();
69
- i0.ɵɵelementStart(0, "button", 42);
70
- i0.ɵɵlistener("click", function ShellComponent_div_0_div_15_button_1_Template_button_click_0_listener($event) { const app_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onNavBarAppClick(app_r7, $event)); })("dblclick", function ShellComponent_div_0_div_15_button_1_Template_button_dblclick_0_listener($event) { const app_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onNavBarAppDblClick(app_r7, $event)); });
72
+ i0.ɵɵelementStart(0, "button", 44);
73
+ i0.ɵɵlistener("click", function ShellComponent_div_15_button_1_Template_button_click_0_listener($event) { const app_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.onNavBarAppClick(app_r7, $event)); })("dblclick", function ShellComponent_div_15_button_1_Template_button_dblclick_0_listener($event) { const app_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.onNavBarAppDblClick(app_r7, $event)); });
71
74
  i0.ɵɵelement(1, "i");
72
75
  i0.ɵɵelementEnd();
73
76
  } if (rf & 2) {
74
77
  const app_r7 = ctx.$implicit;
75
- const ctx_r1 = i0.ɵɵnextContext(3);
78
+ const ctx_r3 = i0.ɵɵnextContext(2);
76
79
  i0.ɵɵstyleProp("--app-color", app_r7.GetColor());
77
- i0.ɵɵclassProp("active", app_r7.ID === (ctx_r1.activeApp == null ? null : ctx_r1.activeApp.ID));
80
+ i0.ɵɵclassProp("active", app_r7.ID === (ctx_r3.activeApp == null ? null : ctx_r3.activeApp.ID));
78
81
  i0.ɵɵproperty("title", app_r7.Name);
79
82
  i0.ɵɵadvance();
80
83
  i0.ɵɵclassMap(app_r7.Icon);
81
84
  } }
82
- function ShellComponent_div_0_div_15_Template(rf, ctx) { if (rf & 1) {
83
- i0.ɵɵelementStart(0, "div", 45);
84
- i0.ɵɵtemplate(1, ShellComponent_div_0_div_15_button_1_Template, 2, 7, "button", 41);
85
+ function ShellComponent_div_15_Template(rf, ctx) { if (rf & 1) {
86
+ i0.ɵɵelementStart(0, "div", 47);
87
+ i0.ɵɵtemplate(1, ShellComponent_div_15_button_1_Template, 2, 7, "button", 43);
85
88
  i0.ɵɵelementEnd();
86
89
  } if (rf & 2) {
87
- const ctx_r1 = i0.ɵɵnextContext(2);
90
+ const ctx_r3 = i0.ɵɵnextContext();
88
91
  i0.ɵɵadvance();
89
- i0.ɵɵproperty("ngForOf", ctx_r1.leftOfUserMenuApps);
92
+ i0.ɵɵproperty("ngForOf", ctx_r3.leftOfUserMenuApps);
90
93
  } }
91
- function ShellComponent_div_0_ng_container_18_Template(rf, ctx) { if (rf & 1) {
94
+ function ShellComponent_ng_container_18_Template(rf, ctx) { if (rf & 1) {
92
95
  i0.ɵɵelementContainerStart(0);
93
- i0.ɵɵelement(1, "img", 46);
96
+ i0.ɵɵelement(1, "img", 48);
94
97
  i0.ɵɵelementContainerEnd();
95
98
  } if (rf & 2) {
96
- const ctx_r1 = i0.ɵɵnextContext(2);
99
+ const ctx_r3 = i0.ɵɵnextContext();
97
100
  i0.ɵɵadvance();
98
- i0.ɵɵproperty("src", ctx_r1.userImageURL, i0.ɵɵsanitizeUrl);
101
+ i0.ɵɵproperty("src", ctx_r3.userImageURL, i0.ɵɵsanitizeUrl);
99
102
  } }
100
- function ShellComponent_div_0_ng_template_19_Template(rf, ctx) { if (rf & 1) {
101
- i0.ɵɵelementStart(0, "div", 47);
103
+ function ShellComponent_ng_template_19_Template(rf, ctx) { if (rf & 1) {
104
+ i0.ɵɵelementStart(0, "div", 49);
102
105
  i0.ɵɵelement(1, "i");
103
106
  i0.ɵɵelementEnd();
104
107
  } if (rf & 2) {
105
- const ctx_r1 = i0.ɵɵnextContext(2);
108
+ const ctx_r3 = i0.ɵɵnextContext();
106
109
  i0.ɵɵadvance();
107
- i0.ɵɵclassMap(ctx_r1.userIconClass || "fa-solid fa-user");
110
+ i0.ɵɵclassMap(ctx_r3.userIconClass || "fa-solid fa-user");
108
111
  } }
109
- function ShellComponent_div_0_div_21_div_1_Template(rf, ctx) { if (rf & 1) {
110
- i0.ɵɵelementStart(0, "div", 58)(1, "span", 59);
112
+ function ShellComponent_div_21_div_1_Template(rf, ctx) { if (rf & 1) {
113
+ i0.ɵɵelementStart(0, "div", 60)(1, "span", 61);
111
114
  i0.ɵɵtext(2);
112
115
  i0.ɵɵelementEnd()();
113
116
  } if (rf & 2) {
114
- const ctx_r1 = i0.ɵɵnextContext(3);
117
+ const ctx_r3 = i0.ɵɵnextContext(2);
115
118
  i0.ɵɵadvance(2);
116
- i0.ɵɵtextInterpolate(ctx_r1.userName);
119
+ i0.ɵɵtextInterpolate(ctx_r3.userName);
117
120
  } }
118
- function ShellComponent_div_0_div_21_div_2_Template(rf, ctx) { if (rf & 1) {
119
- i0.ɵɵelement(0, "div", 53);
121
+ function ShellComponent_div_21_div_2_Template(rf, ctx) { if (rf & 1) {
122
+ i0.ɵɵelement(0, "div", 55);
120
123
  } }
121
- function ShellComponent_div_0_div_21_Template(rf, ctx) { if (rf & 1) {
124
+ function ShellComponent_div_21_Template(rf, ctx) { if (rf & 1) {
122
125
  const _r8 = i0.ɵɵgetCurrentView();
123
- i0.ɵɵelementStart(0, "div", 48);
124
- i0.ɵɵtemplate(1, ShellComponent_div_0_div_21_div_1_Template, 3, 1, "div", 49)(2, ShellComponent_div_0_div_21_div_2_Template, 1, 0, "div", 50);
125
- i0.ɵɵelementStart(3, "div", 51);
126
- i0.ɵɵlistener("click", function ShellComponent_div_0_div_21_Template_div_click_3_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onSettings()); });
127
- i0.ɵɵelement(4, "i", 52);
126
+ i0.ɵɵelementStart(0, "div", 50);
127
+ i0.ɵɵtemplate(1, ShellComponent_div_21_div_1_Template, 3, 1, "div", 51)(2, ShellComponent_div_21_div_2_Template, 1, 0, "div", 52);
128
+ i0.ɵɵelementStart(3, "div", 53);
129
+ i0.ɵɵlistener("click", function ShellComponent_div_21_Template_div_click_3_listener() { i0.ɵɵrestoreView(_r8); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onSettings()); });
130
+ i0.ɵɵelement(4, "i", 54);
128
131
  i0.ɵɵelementStart(5, "span");
129
132
  i0.ɵɵtext(6, "Settings");
130
133
  i0.ɵɵelementEnd()();
131
- i0.ɵɵelement(7, "div", 53);
132
- i0.ɵɵelementStart(8, "div", 51);
133
- i0.ɵɵlistener("click", function ShellComponent_div_0_div_21_Template_div_click_8_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onLogLayout()); });
134
- i0.ɵɵelement(9, "i", 54);
134
+ i0.ɵɵelement(7, "div", 55);
135
+ i0.ɵɵelementStart(8, "div", 53);
136
+ i0.ɵɵlistener("click", function ShellComponent_div_21_Template_div_click_8_listener() { i0.ɵɵrestoreView(_r8); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onLogLayout()); });
137
+ i0.ɵɵelement(9, "i", 56);
135
138
  i0.ɵɵelementStart(10, "span");
136
139
  i0.ɵɵtext(11, "Log Layout (Debug)");
137
140
  i0.ɵɵelementEnd()();
138
- i0.ɵɵelement(12, "div", 53);
139
- i0.ɵɵelementStart(13, "div", 55);
140
- i0.ɵɵlistener("click", function ShellComponent_div_0_div_21_Template_div_click_13_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onResetLayout()); });
141
- i0.ɵɵelement(14, "i", 56);
141
+ i0.ɵɵelement(12, "div", 55);
142
+ i0.ɵɵelementStart(13, "div", 57);
143
+ i0.ɵɵlistener("click", function ShellComponent_div_21_Template_div_click_13_listener() { i0.ɵɵrestoreView(_r8); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onResetLayout()); });
144
+ i0.ɵɵelement(14, "i", 58);
142
145
  i0.ɵɵelementStart(15, "span");
143
146
  i0.ɵɵtext(16, "Reset Layout");
144
147
  i0.ɵɵelementEnd()();
145
- i0.ɵɵelement(17, "div", 53);
146
- i0.ɵɵelementStart(18, "div", 51);
147
- i0.ɵɵlistener("click", function ShellComponent_div_0_div_21_Template_div_click_18_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onLogout()); });
148
- i0.ɵɵelement(19, "i", 57);
148
+ i0.ɵɵelement(17, "div", 55);
149
+ i0.ɵɵelementStart(18, "div", 53);
150
+ i0.ɵɵlistener("click", function ShellComponent_div_21_Template_div_click_18_listener() { i0.ɵɵrestoreView(_r8); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onLogout()); });
151
+ i0.ɵɵelement(19, "i", 59);
149
152
  i0.ɵɵelementStart(20, "span");
150
153
  i0.ɵɵtext(21, "Logout");
151
154
  i0.ɵɵelementEnd()()();
152
155
  } if (rf & 2) {
153
- const ctx_r1 = i0.ɵɵnextContext(2);
156
+ const ctx_r3 = i0.ɵɵnextContext();
154
157
  i0.ɵɵadvance();
155
- i0.ɵɵproperty("ngIf", ctx_r1.userName);
158
+ i0.ɵɵproperty("ngIf", ctx_r3.userName);
156
159
  i0.ɵɵadvance();
157
- i0.ɵɵproperty("ngIf", ctx_r1.userName);
160
+ i0.ɵɵproperty("ngIf", ctx_r3.userName);
158
161
  } }
159
- function ShellComponent_div_0_div_22_Template(rf, ctx) { if (rf & 1) {
162
+ function ShellComponent_div_22_Template(rf, ctx) { if (rf & 1) {
160
163
  const _r9 = i0.ɵɵgetCurrentView();
161
- i0.ɵɵelementStart(0, "div", 60);
162
- i0.ɵɵlistener("click", function ShellComponent_div_0_div_22_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.closeSearch()); });
164
+ i0.ɵɵelementStart(0, "div", 62);
165
+ i0.ɵɵlistener("click", function ShellComponent_div_22_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r9); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.closeSearch()); });
163
166
  i0.ɵɵelementEnd();
164
167
  } }
165
- function ShellComponent_div_0_div_30_Template(rf, ctx) { if (rf & 1) {
168
+ function ShellComponent_div_30_Template(rf, ctx) { if (rf & 1) {
166
169
  const _r10 = i0.ɵɵgetCurrentView();
167
- i0.ɵɵelementStart(0, "div", 61);
168
- i0.ɵɵlistener("click", function ShellComponent_div_0_div_30_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.closeMobileNav()); });
170
+ i0.ɵɵelementStart(0, "div", 63);
171
+ i0.ɵɵlistener("click", function ShellComponent_div_30_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.closeMobileNav()); });
169
172
  i0.ɵɵelementEnd();
170
173
  } }
171
- function ShellComponent_div_0_div_37_Template(rf, ctx) { if (rf & 1) {
174
+ function ShellComponent_div_37_Template(rf, ctx) { if (rf & 1) {
172
175
  const _r11 = i0.ɵɵgetCurrentView();
173
- i0.ɵɵelementStart(0, "div", 62)(1, "div", 63);
176
+ i0.ɵɵelementStart(0, "div", 64)(1, "div", 65);
174
177
  i0.ɵɵtext(2);
175
178
  i0.ɵɵelementEnd();
176
- i0.ɵɵelementStart(3, "mj-app-nav", 64);
177
- i0.ɵɵlistener("navItemClick", function ShellComponent_div_0_div_37_Template_mj_app_nav_navItemClick_3_listener($event) { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onNavItemClick($event)); });
179
+ i0.ɵɵelementStart(3, "mj-app-nav", 66);
180
+ i0.ɵɵlistener("navItemClick", function ShellComponent_div_37_Template_mj_app_nav_navItemClick_3_listener($event) { i0.ɵɵrestoreView(_r11); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onNavItemClick($event)); });
178
181
  i0.ɵɵelementEnd()();
179
182
  } if (rf & 2) {
180
- const ctx_r1 = i0.ɵɵnextContext(2);
183
+ const ctx_r3 = i0.ɵɵnextContext();
181
184
  i0.ɵɵadvance(2);
182
- i0.ɵɵtextInterpolate(ctx_r1.activeApp.Name);
185
+ i0.ɵɵtextInterpolate(ctx_r3.activeApp.Name);
183
186
  i0.ɵɵadvance();
184
- i0.ɵɵproperty("app", ctx_r1.activeApp);
187
+ i0.ɵɵproperty("app", ctx_r3.activeApp);
185
188
  } }
186
- function ShellComponent_div_0_span_47_Template(rf, ctx) { if (rf & 1) {
187
- i0.ɵɵelementStart(0, "span", 65);
189
+ function ShellComponent_span_47_Template(rf, ctx) { if (rf & 1) {
190
+ i0.ɵɵelementStart(0, "span", 67);
188
191
  i0.ɵɵtext(1);
189
192
  i0.ɵɵelementEnd();
190
193
  } if (rf & 2) {
191
- const ctx_r1 = i0.ɵɵnextContext(2);
194
+ const ctx_r3 = i0.ɵɵnextContext();
192
195
  i0.ɵɵadvance();
193
- i0.ɵɵtextInterpolate1(" ", ctx_r1.unreadNotificationCount > 99 ? "99+" : ctx_r1.unreadNotificationCount, " ");
196
+ i0.ɵɵtextInterpolate1(" ", ctx_r3.unreadNotificationCount > 99 ? "99+" : ctx_r3.unreadNotificationCount, " ");
194
197
  } }
195
- function ShellComponent_div_0_Template(rf, ctx) { if (rf & 1) {
196
- const _r1 = i0.ɵɵgetCurrentView();
197
- i0.ɵɵelementStart(0, "div", 4)(1, "header", 5);
198
- i0.ɵɵelement(2, "div", 6);
199
- i0.ɵɵelementStart(3, "button", 7);
200
- i0.ɵɵlistener("click", function ShellComponent_div_0_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleMobileNav()); });
201
- i0.ɵɵelement(4, "i", 8);
202
- i0.ɵɵelementEnd();
203
- i0.ɵɵtemplate(5, ShellComponent_div_0_div_5_Template, 2, 1, "div", 9);
204
- i0.ɵɵelementStart(6, "mj-app-switcher", 10);
205
- i0.ɵɵlistener("appSelected", function ShellComponent_div_0_Template_mj_app_switcher_appSelected_6_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onAppSwitch($event)); });
206
- i0.ɵɵelementEnd();
207
- i0.ɵɵtemplate(7, ShellComponent_div_0_mj_app_nav_7_Template, 1, 1, "mj-app-nav", 11);
208
- i0.ɵɵelement(8, "div", 12);
209
- i0.ɵɵelementStart(9, "div", 13)(10, "button", 14);
210
- i0.ɵɵlistener("click", function ShellComponent_div_0_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleSearch()); });
211
- i0.ɵɵelement(11, "i", 15);
212
- i0.ɵɵelementEnd();
213
- i0.ɵɵelementStart(12, "button", 16);
214
- i0.ɵɵlistener("click", function ShellComponent_div_0_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.showNotifications()); });
215
- i0.ɵɵelement(13, "i", 17);
216
- i0.ɵɵtemplate(14, ShellComponent_div_0_span_14_Template, 2, 1, "span", 18);
217
- i0.ɵɵelementEnd();
218
- i0.ɵɵtemplate(15, ShellComponent_div_0_div_15_Template, 2, 1, "div", 19);
219
- i0.ɵɵelementStart(16, "div", 20)(17, "button", 21);
220
- i0.ɵɵlistener("click", function ShellComponent_div_0_Template_button_click_17_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleUserMenu($event)); });
221
- i0.ɵɵtemplate(18, ShellComponent_div_0_ng_container_18_Template, 2, 1, "ng-container", 22)(19, ShellComponent_div_0_ng_template_19_Template, 2, 2, "ng-template", null, 0, i0.ɵɵtemplateRefExtractor);
222
- i0.ɵɵelementEnd();
223
- i0.ɵɵtemplate(21, ShellComponent_div_0_div_21_Template, 22, 2, "div", 23);
224
- i0.ɵɵelementEnd()()();
225
- i0.ɵɵtemplate(22, ShellComponent_div_0_div_22_Template, 1, 0, "div", 24);
226
- i0.ɵɵelementStart(23, "div", 25)(24, "div", 26);
227
- i0.ɵɵlistener("click", function ShellComponent_div_0_Template_div_click_24_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView($event.stopPropagation()); });
228
- i0.ɵɵelementStart(25, "kendo-dropdownlist", 27);
229
- i0.ɵɵtwoWayListener("ngModelChange", function ShellComponent_div_0_Template_kendo_dropdownlist_ngModelChange_25_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.selectedEntity, $event) || (ctx_r1.selectedEntity = $event); return i0.ɵɵresetView($event); });
230
- i0.ɵɵelementEnd();
231
- i0.ɵɵelementStart(26, "input", 28, 1);
232
- i0.ɵɵlistener("keydown.enter", function ShellComponent_div_0_Template_input_keydown_enter_26_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onSearch($event)); });
233
- i0.ɵɵelementEnd();
234
- i0.ɵɵelementStart(28, "button", 29);
235
- i0.ɵɵlistener("click", function ShellComponent_div_0_Template_button_click_28_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onSearch($event)); });
236
- i0.ɵɵelement(29, "i", 15);
237
- i0.ɵɵelementEnd()()();
238
- i0.ɵɵtemplate(30, ShellComponent_div_0_div_30_Template, 1, 0, "div", 30);
239
- i0.ɵɵelementStart(31, "div", 31)(32, "div", 32)(33, "span");
240
- i0.ɵɵtext(34, "Navigation");
241
- i0.ɵɵelementEnd();
242
- i0.ɵɵelementStart(35, "button", 33);
243
- i0.ɵɵlistener("click", function ShellComponent_div_0_Template_button_click_35_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.closeMobileNav()); });
244
- i0.ɵɵelement(36, "i", 34);
245
- i0.ɵɵelementEnd()();
246
- i0.ɵɵtemplate(37, ShellComponent_div_0_div_37_Template, 4, 2, "div", 35);
247
- i0.ɵɵelementStart(38, "div", 36)(39, "button", 37);
248
- i0.ɵɵlistener("click", function ShellComponent_div_0_Template_button_click_39_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.toggleSearch(); return i0.ɵɵresetView(ctx_r1.closeMobileNav()); });
249
- i0.ɵɵelement(40, "i", 15);
250
- i0.ɵɵelementStart(41, "span");
251
- i0.ɵɵtext(42, "Search");
252
- i0.ɵɵelementEnd()();
253
- i0.ɵɵelementStart(43, "button", 38);
254
- i0.ɵɵlistener("click", function ShellComponent_div_0_Template_button_click_43_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.showNotifications(); return i0.ɵɵresetView(ctx_r1.closeMobileNav()); });
255
- i0.ɵɵelement(44, "i", 17);
256
- i0.ɵɵelementStart(45, "span");
257
- i0.ɵɵtext(46, "Notifications");
258
- i0.ɵɵelementEnd();
259
- i0.ɵɵtemplate(47, ShellComponent_div_0_span_47_Template, 2, 1, "span", 39);
260
- i0.ɵɵelementEnd()()();
261
- i0.ɵɵelement(48, "mj-tab-container");
198
+ function ShellComponent_div_49_Template(rf, ctx) { if (rf & 1) {
199
+ i0.ɵɵelementStart(0, "div", 68);
200
+ i0.ɵɵelement(1, "mj-loading", 69);
262
201
  i0.ɵɵelementEnd();
263
202
  } if (rf & 2) {
264
- const iconAvatar_r12 = i0.ɵɵreference(20);
265
- const ctx_r1 = i0.ɵɵnextContext();
266
- i0.ɵɵclassProp("tabs-visible", ctx_r1.tabBarVisible);
267
- i0.ɵɵadvance(5);
268
- i0.ɵɵproperty("ngIf", ctx_r1.leftOfSwitcherApps.length > 0);
269
- i0.ɵɵadvance();
270
- i0.ɵɵproperty("activeApp", ctx_r1.activeApp)("isViewingSystemTab", ctx_r1.isViewingSystemTab)("loadingAppId", ctx_r1.loadingAppId);
271
- i0.ɵɵadvance();
272
- i0.ɵɵproperty("ngIf", ctx_r1.activeApp);
273
- i0.ɵɵadvance(7);
274
- i0.ɵɵproperty("ngIf", ctx_r1.unreadNotificationCount > 0);
203
+ const ctx_r3 = i0.ɵɵnextContext();
275
204
  i0.ɵɵadvance();
276
- i0.ɵɵproperty("ngIf", ctx_r1.leftOfUserMenuApps.length > 0);
277
- i0.ɵɵadvance(3);
278
- i0.ɵɵproperty("ngIf", ctx_r1.userImageURL)("ngIfElse", iconAvatar_r12);
279
- i0.ɵɵadvance(3);
280
- i0.ɵɵproperty("ngIf", ctx_r1.userMenuVisible);
281
- i0.ɵɵadvance();
282
- i0.ɵɵproperty("ngIf", ctx_r1.isSearchOpen);
283
- i0.ɵɵadvance();
284
- i0.ɵɵclassProp("open", ctx_r1.isSearchOpen);
285
- i0.ɵɵadvance(2);
286
- i0.ɵɵproperty("data", ctx_r1.searchableEntities);
287
- i0.ɵɵtwoWayProperty("ngModel", ctx_r1.selectedEntity);
288
- i0.ɵɵadvance(5);
289
- i0.ɵɵproperty("ngIf", ctx_r1.mobileNavOpen);
290
- i0.ɵɵadvance();
291
- i0.ɵɵclassProp("open", ctx_r1.mobileNavOpen);
292
- i0.ɵɵadvance(6);
293
- i0.ɵɵproperty("ngIf", ctx_r1.activeApp);
294
- i0.ɵɵadvance(10);
295
- i0.ɵɵproperty("ngIf", ctx_r1.unreadNotificationCount > 0);
296
- i0.ɵɵadvance();
297
- i0.ɵɵclassProp("hide-tab-bar", !ctx_r1.tabBarVisible);
298
- } }
299
- function ShellComponent_div_1_Template(rf, ctx) { if (rf & 1) {
300
- i0.ɵɵelementStart(0, "div", 66);
301
- i0.ɵɵelement(1, "mj-loading", 67);
302
- i0.ɵɵelementEnd();
205
+ i0.ɵɵproperty("text", ctx_r3.currentLoadingText)("textColor", ctx_r3.currentLoadingTextColor)("logoColor", ctx_r3.currentLoadingColor)("logoGradient", ctx_r3.currentLoadingGradient)("animation", ctx_r3.currentLoadingAnimation);
303
206
  } }
304
207
  /**
305
208
  * Main shell component for the new Explorer UX.
@@ -330,12 +233,33 @@ export class ShellComponent {
330
233
  activeApp = null;
331
234
  loading = true;
332
235
  initialized = false;
236
+ waitingForFirstResource = false;
333
237
  tabBarVisible = true; // Controlled by workspace manager
334
238
  userMenuVisible = false; // User avatar context menu
335
239
  mobileNavOpen = false; // Mobile navigation drawer
336
240
  unreadNotificationCount = 0; // Notification badge count
337
241
  isViewingSystemTab = false; // True when viewing a resource tab (not associated with a registered app)
338
242
  loadingAppId = null; // ID of app currently being loaded (for app switcher loading indicator)
243
+ // Loading animation state
244
+ loadingMessageInterval = null;
245
+ loadingMessageIndex = 0;
246
+ usedMessageIndices = [];
247
+ usedGradientIndices = [];
248
+ messageCycleCount = 0; // Track message cycles for color changes
249
+ activeTheme;
250
+ messageIntervalMs = 2500; // 2.5 seconds per message
251
+ colorChangeEveryNMessages = 2; // Change color every 2 messages (5 seconds)
252
+ // All available animation types (used for random selection when theme doesn't specify)
253
+ allAnimationTypes = ['pulse', 'spin', 'bounce', 'pulse-spin'];
254
+ // Animation sequencing
255
+ animationSequence = [];
256
+ currentAnimationIndex = 0;
257
+ animationSequenceTimeout = null;
258
+ currentLoadingText;
259
+ currentLoadingColor;
260
+ currentLoadingTextColor;
261
+ currentLoadingGradient;
262
+ currentLoadingAnimation = 'pulse';
339
263
  // User avatar state
340
264
  userImageURL = '';
341
265
  userIconClass = null;
@@ -345,6 +269,9 @@ export class ShellComponent {
345
269
  searchableEntities = [];
346
270
  selectedEntity = null;
347
271
  searchInput;
272
+ // App access dialog
273
+ appAccessDialog;
274
+ pendingAppPath = null; // Store the app path we tried to access
348
275
  /**
349
276
  * Get Nav Bar apps positioned to the left of the app switcher
350
277
  * Filters out apps that have HideNavBarIconWhenActive=true and are currently active
@@ -375,6 +302,30 @@ export class ShellComponent {
375
302
  this.settingsDialogService = settingsDialogService;
376
303
  this.viewContainerRef = viewContainerRef;
377
304
  this.titleService = titleService;
305
+ // Initialize theme immediately so loading UI shows correct colors from the start
306
+ this.activeTheme = getActiveTheme();
307
+ // Initialize animation based on theme configuration
308
+ this.initializeAnimationFromTheme();
309
+ // Set first message
310
+ this.currentLoadingText = this.activeTheme.messages[0];
311
+ if (this.activeTheme.staticColors) {
312
+ // Standard theme: keep MJ blue, no gradient
313
+ this.currentLoadingColor = this.activeTheme.colors[0];
314
+ this.currentLoadingTextColor = '#757575'; // Default gray text
315
+ this.currentLoadingGradient = null;
316
+ }
317
+ else {
318
+ // Themed period: use theme colors and first gradient from the start
319
+ this.currentLoadingColor = this.activeTheme.colors[0];
320
+ this.currentLoadingTextColor = this.activeTheme.colors[0];
321
+ // Set initial gradient if theme has gradients
322
+ if (this.activeTheme.gradients && this.activeTheme.gradients.length > 0) {
323
+ this.currentLoadingGradient = this.activeTheme.gradients[0];
324
+ }
325
+ else {
326
+ this.currentLoadingGradient = null;
327
+ }
328
+ }
378
329
  }
379
330
  async ngOnInit() {
380
331
  try {
@@ -400,8 +351,11 @@ export class ShellComponent {
400
351
  }
401
352
  }
402
353
  async initializeShell() {
354
+ // Start the loading animation with cycling messages
355
+ this.startLoadingAnimation();
403
356
  // Initialize application manager (subscribes to LoggedIn event)
404
357
  this.appManager.Initialize();
358
+ await StartupManager.Instance.Startup();
405
359
  // Get current user
406
360
  const md = new Metadata();
407
361
  const user = md.CurrentUser;
@@ -446,38 +400,51 @@ export class ShellComponent {
446
400
  }
447
401
  }));
448
402
  // Subscribe to applications loading - set app based on URL or default to first
449
- this.subscriptions.push(this.appManager.Applications.subscribe(async (apps) => {
450
- if (apps.length > 0) {
451
- // Check if URL specifies an app by parsing the browser URL
452
- const currentUrl = this.router.url;
453
- const appMatch = currentUrl.match(/\/app\/([^\/]+)/);
454
- if (appMatch) {
455
- const routeAppPath = decodeURIComponent(appMatch[1]);
456
- // Find the app from the URL by Path (or Name for backwards compatibility)
457
- const urlApp = this.appManager.GetAppByPath(routeAppPath);
458
- if (urlApp) {
459
- // Set the app from URL - takes precedence over workspace restoration
460
- await this.appManager.SetActiveApp(urlApp.ID);
461
- // If the URL is just /app/:appName (no nav item), create default tab
462
- const hasNavItem = currentUrl.match(/\/app\/[^\/]+\/[^\/]+/);
463
- if (!hasNavItem) {
464
- const existingTabs = this.workspaceManager.GetAppTabs(urlApp.ID);
465
- if (existingTabs.length === 0) {
466
- const tabRequest = await urlApp.CreateDefaultTab();
467
- if (tabRequest) {
468
- this.tabService.OpenTab(tabRequest);
469
- }
403
+ // Use combineLatest to wait for loading to complete before deciding there are no apps
404
+ this.subscriptions.push(combineLatest([this.appManager.Applications, this.appManager.Loading]).subscribe(async ([apps, isLoading]) => {
405
+ // Don't make decisions while still loading - wait for load to complete
406
+ if (isLoading) {
407
+ return;
408
+ }
409
+ // Handle the case where user has no apps at all (only after loading is complete)
410
+ if (apps.length === 0) {
411
+ await this.handleNoAppsAvailable();
412
+ return;
413
+ }
414
+ // Check if URL specifies an app by parsing the browser URL
415
+ const currentUrl = this.router.url;
416
+ const appMatch = currentUrl.match(/\/app\/([^\/]+)/);
417
+ if (appMatch) {
418
+ const routeAppPath = decodeURIComponent(appMatch[1]);
419
+ // Find the app from the URL by Path (or Name for backwards compatibility)
420
+ const urlApp = this.appManager.GetAppByPath(routeAppPath);
421
+ if (urlApp) {
422
+ // Set the app from URL - takes precedence over workspace restoration
423
+ await this.appManager.SetActiveApp(urlApp.ID);
424
+ // If the URL is just /app/:appName (no nav item), create default tab
425
+ const hasNavItem = currentUrl.match(/\/app\/[^\/]+\/[^\/]+/);
426
+ if (!hasNavItem) {
427
+ const existingTabs = this.workspaceManager.GetAppTabs(urlApp.ID);
428
+ if (existingTabs.length === 0) {
429
+ const tabRequest = await urlApp.CreateDefaultTab();
430
+ if (tabRequest) {
431
+ this.tabService.OpenTab(tabRequest);
470
432
  }
471
433
  }
472
- return;
473
434
  }
435
+ return;
474
436
  }
475
- // Set default app if URL doesn't specify one AND no app is active yet
476
- const currentActiveApp = this.appManager.GetActiveApp();
477
- if (!appMatch && !currentActiveApp) {
478
- await this.appManager.SetActiveApp(apps[0].ID);
437
+ else {
438
+ // App not found in user's list - check why and show appropriate dialog
439
+ await this.handleAppAccessError(routeAppPath, apps);
440
+ return;
479
441
  }
480
442
  }
443
+ // Set default app if URL doesn't specify one AND no app is active yet
444
+ const currentActiveApp = this.appManager.GetActiveApp();
445
+ if (!appMatch && !currentActiveApp) {
446
+ await this.appManager.SetActiveApp(apps[0].ID);
447
+ }
481
448
  }));
482
449
  // Subscribe to tab open requests from TabService
483
450
  this.subscriptions.push(this.tabService.TabRequests.subscribe(async (request) => {
@@ -532,7 +499,7 @@ export class ShellComponent {
532
499
  // Load searchable entities for search functionality
533
500
  await this.loadSearchableEntities();
534
501
  this.initialized = true;
535
- this.loading = false;
502
+ this.waitingForFirstResource = true;
536
503
  }
537
504
  /**
538
505
  * Handle deep links from URL
@@ -943,7 +910,228 @@ export class ShellComponent {
943
910
  ngAfterViewInit() {
944
911
  // Layout initialization happens in TabContainerComponent
945
912
  }
913
+ /**
914
+ * Called when the first resource component finishes loading.
915
+ * We accept subsequent calls to this method in ordre to ensure we are
916
+ * not forever showing animation for loading - this can happen if there is
917
+ * a race condition in components we DO NOT control, so while the naming
918
+ * is intended to imply the goal it doesn't "hurt" to have this work this way
919
+ */
920
+ onFirstResourceLoadComplete() {
921
+ this.waitingForFirstResource = false;
922
+ this.loading = false;
923
+ this.stopLoadingAnimation();
924
+ this.cdr.detectChanges();
925
+ }
926
+ /**
927
+ * Start the loading message cycling animation.
928
+ * Messages cycle every 2.5 seconds without repeating until all are used.
929
+ * Colors change every 5 seconds (every 2nd message cycle).
930
+ * For themed periods: use theme colors/gradients from the start.
931
+ * For standard theme: keep MJ blue throughout (no color changes).
932
+ * Animation is randomly selected from pulse, spin, and pulse-spin.
933
+ * Theme is selected based on current date and user's browser locale.
934
+ */
935
+ startLoadingAnimation() {
936
+ // Select the appropriate theme based on date and locale
937
+ this.activeTheme = getActiveTheme();
938
+ console.log(`🎨 Loading theme: ${this.activeTheme.name}`);
939
+ // Reset state
940
+ this.usedMessageIndices = [0]; // Mark first message as used
941
+ this.usedGradientIndices = [];
942
+ this.loadingMessageIndex = 0;
943
+ this.messageCycleCount = 0;
944
+ // Initialize display with first message and initial color/gradient
945
+ this.initializeLoadingDisplay();
946
+ // Initialize animation based on theme configuration
947
+ this.initializeAnimationFromTheme();
948
+ // Start the animation sequence (if there are multiple steps)
949
+ this.startAnimationSequence();
950
+ // Start cycling every 2.5 seconds
951
+ this.loadingMessageInterval = setInterval(() => {
952
+ this.cycleToNextMessage();
953
+ this.cdr.detectChanges();
954
+ }, this.messageIntervalMs);
955
+ }
956
+ /**
957
+ * Stop the loading message cycling animation.
958
+ */
959
+ stopLoadingAnimation() {
960
+ if (this.loadingMessageInterval) {
961
+ clearInterval(this.loadingMessageInterval);
962
+ this.loadingMessageInterval = null;
963
+ }
964
+ // Also clear any animation sequence timeout
965
+ if (this.animationSequenceTimeout) {
966
+ clearTimeout(this.animationSequenceTimeout);
967
+ this.animationSequenceTimeout = null;
968
+ }
969
+ }
970
+ /**
971
+ * Initialize the loading display with first message and initial color/gradient.
972
+ * For themed periods, applies theme styling from the start.
973
+ * For standard theme, keeps MJ blue throughout.
974
+ */
975
+ initializeLoadingDisplay() {
976
+ // Set first message
977
+ this.currentLoadingText = this.activeTheme.messages[0];
978
+ if (this.activeTheme.staticColors) {
979
+ // Standard theme: keep MJ blue, no gradient
980
+ this.currentLoadingColor = this.activeTheme.colors[0];
981
+ this.currentLoadingTextColor = '#757575'; // Default gray text
982
+ this.currentLoadingGradient = null;
983
+ }
984
+ else {
985
+ // Themed period: use theme colors and first gradient from the start
986
+ this.currentLoadingColor = this.activeTheme.colors[0];
987
+ this.currentLoadingTextColor = this.activeTheme.colors[0];
988
+ // Set initial gradient if theme has gradients
989
+ if (this.activeTheme.gradients && this.activeTheme.gradients.length > 0) {
990
+ this.currentLoadingGradient = this.activeTheme.gradients[0];
991
+ this.usedGradientIndices = [0];
992
+ }
993
+ else {
994
+ this.currentLoadingGradient = null;
995
+ }
996
+ }
997
+ }
998
+ /**
999
+ * Cycle to the next loading message, avoiding repeats until all are used.
1000
+ * Colors change every colorChangeEveryNMessages cycles (5 seconds).
1001
+ * For standard theme, colors remain static.
1002
+ */
1003
+ cycleToNextMessage() {
1004
+ const messages = this.activeTheme.messages;
1005
+ this.messageCycleCount++;
1006
+ // If we've used all messages, reset the used list (but exclude current to avoid immediate repeat)
1007
+ if (this.usedMessageIndices.length >= messages.length) {
1008
+ this.usedMessageIndices = [this.loadingMessageIndex];
1009
+ }
1010
+ // Find a random unused message index
1011
+ const availableIndices = messages
1012
+ .map((_, i) => i)
1013
+ .filter(i => !this.usedMessageIndices.includes(i));
1014
+ if (availableIndices.length > 0) {
1015
+ const randomIndex = availableIndices[Math.floor(Math.random() * availableIndices.length)];
1016
+ this.usedMessageIndices.push(randomIndex);
1017
+ this.loadingMessageIndex = randomIndex;
1018
+ // Update the message
1019
+ this.currentLoadingText = this.activeTheme.messages[randomIndex];
1020
+ // Check if it's time to change colors (every 2nd message = every 5 seconds)
1021
+ // But only for non-static themes
1022
+ if (!this.activeTheme.staticColors && this.messageCycleCount % this.colorChangeEveryNMessages === 0) {
1023
+ this.cycleToNextColor();
1024
+ }
1025
+ }
1026
+ }
1027
+ /**
1028
+ * Cycle to the next color/gradient from the theme.
1029
+ * Alternates through gradients if available.
1030
+ */
1031
+ cycleToNextColor() {
1032
+ // Cycle to next gradient if available
1033
+ if (this.activeTheme.gradients && this.activeTheme.gradients.length > 0) {
1034
+ const gradients = this.activeTheme.gradients;
1035
+ // If we've used all gradients, reset (but exclude current to avoid immediate repeat)
1036
+ if (this.usedGradientIndices.length >= gradients.length) {
1037
+ const lastUsed = this.usedGradientIndices[this.usedGradientIndices.length - 1];
1038
+ this.usedGradientIndices = [lastUsed];
1039
+ }
1040
+ // Find next gradient (simple rotation for gradients)
1041
+ const currentIndex = this.usedGradientIndices[this.usedGradientIndices.length - 1] ?? -1;
1042
+ const nextIndex = (currentIndex + 1) % gradients.length;
1043
+ this.usedGradientIndices.push(nextIndex);
1044
+ this.currentLoadingGradient = gradients[nextIndex];
1045
+ }
1046
+ // Also cycle text color through theme colors
1047
+ const colors = this.activeTheme.colors;
1048
+ if (colors.length > 1) {
1049
+ // Get a random color from the theme for text
1050
+ const randomIndex = Math.floor(Math.random() * colors.length);
1051
+ this.currentLoadingColor = colors[randomIndex];
1052
+ this.currentLoadingTextColor = colors[randomIndex];
1053
+ }
1054
+ }
1055
+ /**
1056
+ * Initialize animation configuration from the current theme.
1057
+ * Converts the theme's animation config (string or array) to a normalized sequence.
1058
+ */
1059
+ initializeAnimationFromTheme() {
1060
+ this.currentAnimationIndex = 0;
1061
+ const themeAnimations = this.activeTheme.animations;
1062
+ if (!themeAnimations) {
1063
+ // No animation config - use random selection for non-standard themes
1064
+ if (this.activeTheme.id === 'standard') {
1065
+ // Standard theme defaults to pulse only
1066
+ this.animationSequence = [{ type: 'pulse' }];
1067
+ }
1068
+ else {
1069
+ // Random selection for themed holidays without explicit config
1070
+ const randomType = this.allAnimationTypes[Math.floor(Math.random() * this.allAnimationTypes.length)];
1071
+ this.animationSequence = [{ type: randomType }];
1072
+ }
1073
+ }
1074
+ else if (typeof themeAnimations === 'string') {
1075
+ // Single animation type specified
1076
+ this.animationSequence = [{ type: themeAnimations }];
1077
+ }
1078
+ else {
1079
+ // Array of animation steps
1080
+ this.animationSequence = themeAnimations;
1081
+ }
1082
+ // Set initial animation
1083
+ if (this.animationSequence.length > 0) {
1084
+ this.currentLoadingAnimation = this.animationSequence[0].type;
1085
+ }
1086
+ }
1087
+ /**
1088
+ * Start the animation sequence, scheduling transitions between animation steps.
1089
+ */
1090
+ startAnimationSequence() {
1091
+ // Clear any existing timeout
1092
+ if (this.animationSequenceTimeout) {
1093
+ clearTimeout(this.animationSequenceTimeout);
1094
+ this.animationSequenceTimeout = null;
1095
+ }
1096
+ this.currentAnimationIndex = 0;
1097
+ this.scheduleNextAnimationStep();
1098
+ }
1099
+ /**
1100
+ * Schedule the transition to the next animation step based on current step's duration.
1101
+ */
1102
+ scheduleNextAnimationStep() {
1103
+ if (this.animationSequence.length <= 1) {
1104
+ // Only one step - no transitions needed
1105
+ return;
1106
+ }
1107
+ const currentStep = this.animationSequence[this.currentAnimationIndex];
1108
+ const durationMs = currentStep.durationMs;
1109
+ // If no duration specified (or 0), this step runs indefinitely
1110
+ if (!durationMs || durationMs <= 0) {
1111
+ return;
1112
+ }
1113
+ // Schedule transition to next step
1114
+ this.animationSequenceTimeout = setTimeout(() => {
1115
+ this.transitionToNextAnimation();
1116
+ }, durationMs);
1117
+ }
1118
+ /**
1119
+ * Transition to the next animation in the sequence.
1120
+ */
1121
+ transitionToNextAnimation() {
1122
+ this.currentAnimationIndex++;
1123
+ if (this.currentAnimationIndex >= this.animationSequence.length) {
1124
+ // Sequence complete - stay on last animation
1125
+ return;
1126
+ }
1127
+ const nextStep = this.animationSequence[this.currentAnimationIndex];
1128
+ this.currentLoadingAnimation = nextStep.type;
1129
+ this.cdr.detectChanges();
1130
+ // Schedule the next transition if this step has a duration
1131
+ this.scheduleNextAnimationStep();
1132
+ }
946
1133
  ngOnDestroy() {
1134
+ this.stopLoadingAnimation();
947
1135
  this.subscriptions.forEach(sub => sub.unsubscribe());
948
1136
  this.layoutManager.Destroy();
949
1137
  }
@@ -1315,26 +1503,356 @@ export class ShellComponent {
1315
1503
  IsPinned: false
1316
1504
  });
1317
1505
  }
1506
+ // ========================================
1507
+ // APP ACCESS ERROR HANDLING
1508
+ // ========================================
1509
+ /**
1510
+ * Handle app access error by showing the appropriate dialog based on the access check result.
1511
+ * IMPORTANT: This keeps the loading screen visible and does NOT navigate to any app
1512
+ * until the user makes a decision in the dialog.
1513
+ * @param appPath The app path from the URL that the user tried to access
1514
+ * @param availableApps The list of apps the user has access to (for fallback)
1515
+ */
1516
+ async handleAppAccessError(appPath, availableApps) {
1517
+ // Prevent showing the dialog multiple times for the same app path
1518
+ // This can happen when the applications$ observable emits multiple times during reload
1519
+ if (this.pendingAppPath === appPath) {
1520
+ return;
1521
+ }
1522
+ const accessResult = this.appManager.CheckAppAccess(appPath);
1523
+ this.pendingAppPath = appPath;
1524
+ LogStatus(`App access check for "${appPath}": ${accessResult.status} - ${accessResult.message}`);
1525
+ const dialogConfig = this.mapAccessResultToDialogConfig(accessResult);
1526
+ // IMPORTANT: Keep loading screen visible while dialog is shown
1527
+ // Do NOT set any active app or create any tabs yet
1528
+ // The loading screen stays visible because we haven't called onFirstResourceLoadComplete
1529
+ // Show the dialog on top of the loading screen
1530
+ // Use setTimeout to ensure the dialog component is ready after view init
1531
+ setTimeout(() => {
1532
+ if (this.appAccessDialog) {
1533
+ this.appAccessDialog.show(dialogConfig);
1534
+ }
1535
+ else {
1536
+ // Fallback if dialog not available - redirect to first app
1537
+ console.warn('App access dialog not available, redirecting to first app');
1538
+ this.redirectToFirstApp(availableApps);
1539
+ }
1540
+ }, 0);
1541
+ }
1542
+ /**
1543
+ * Map an AppAccessResult to the dialog configuration
1544
+ */
1545
+ mapAccessResultToDialogConfig(accessResult) {
1546
+ switch (accessResult.status) {
1547
+ case 'not_found':
1548
+ return {
1549
+ type: 'not_found',
1550
+ appName: accessResult.appName
1551
+ };
1552
+ case 'inactive':
1553
+ return {
1554
+ type: 'inactive',
1555
+ appName: accessResult.appName,
1556
+ appId: accessResult.appId
1557
+ };
1558
+ case 'not_installed':
1559
+ return {
1560
+ type: 'not_installed',
1561
+ appName: accessResult.appName,
1562
+ appId: accessResult.appId
1563
+ };
1564
+ case 'disabled':
1565
+ return {
1566
+ type: 'disabled',
1567
+ appName: accessResult.appName,
1568
+ appId: accessResult.appId
1569
+ };
1570
+ default:
1571
+ // 'accessible' shouldn't reach here, but handle it as a generic error
1572
+ return {
1573
+ type: 'no_access',
1574
+ appName: accessResult.appName
1575
+ };
1576
+ }
1577
+ }
1578
+ /**
1579
+ * Handle when user has no apps available at all
1580
+ */
1581
+ async handleNoAppsAvailable() {
1582
+ LogStatus('User has no applications available');
1583
+ // Stop loading animation and show the dialog
1584
+ this.stopLoadingAnimation();
1585
+ this.loading = false;
1586
+ this.cdr.detectChanges();
1587
+ setTimeout(() => {
1588
+ if (this.appAccessDialog) {
1589
+ this.appAccessDialog.show({ type: 'no_apps' });
1590
+ }
1591
+ }, 0);
1592
+ }
1593
+ /**
1594
+ * Handle Golden Layout initialization failure
1595
+ */
1596
+ handleLayoutError() {
1597
+ LogStatus('Golden Layout initialization failed');
1598
+ const availableApps = this.appManager.GetAllApps();
1599
+ if (availableApps.length > 0) {
1600
+ setTimeout(() => {
1601
+ if (this.appAccessDialog) {
1602
+ this.appAccessDialog.show({ type: 'layout_error' });
1603
+ }
1604
+ else {
1605
+ // Direct redirect if dialog not available
1606
+ this.redirectToFirstApp(availableApps);
1607
+ }
1608
+ }, 0);
1609
+ }
1610
+ }
1611
+ /**
1612
+ * Handle dialog result (install, enable, or redirect)
1613
+ */
1614
+ async onAppAccessDialogResult(result) {
1615
+ const availableApps = this.appManager.GetAllApps();
1616
+ switch (result.action) {
1617
+ case 'install':
1618
+ if (result.appId) {
1619
+ await this.installAndNavigateToApp(result.appId);
1620
+ }
1621
+ break;
1622
+ case 'enable':
1623
+ if (result.appId) {
1624
+ await this.enableAndNavigateToApp(result.appId);
1625
+ }
1626
+ break;
1627
+ case 'redirect':
1628
+ case 'dismissed':
1629
+ default:
1630
+ this.redirectToFirstApp(availableApps);
1631
+ break;
1632
+ }
1633
+ }
1634
+ /**
1635
+ * Install an app for the user and navigate to it
1636
+ */
1637
+ async installAndNavigateToApp(appId) {
1638
+ // Clear pendingAppPath to allow fresh handling after installation
1639
+ this.pendingAppPath = null;
1640
+ try {
1641
+ const userApp = await this.appManager.InstallAppForUser(appId);
1642
+ if (userApp) {
1643
+ // App installed successfully - navigate to it
1644
+ const app = this.appManager.GetAppById(appId);
1645
+ if (app) {
1646
+ await this.navigateToApp(app);
1647
+ this.appAccessDialog?.completeProcessing();
1648
+ }
1649
+ else {
1650
+ // Fallback - reload might be needed
1651
+ console.warn(`[ShellComponent] App ${appId} not found after install, redirecting to first app`);
1652
+ this.appAccessDialog?.completeProcessing();
1653
+ this.redirectToFirstApp(this.appManager.GetAllApps());
1654
+ }
1655
+ }
1656
+ else {
1657
+ // Installation failed
1658
+ console.error('[ShellComponent] Installation failed');
1659
+ this.appAccessDialog?.completeProcessing();
1660
+ this.redirectToFirstApp(this.appManager.GetAllApps());
1661
+ }
1662
+ }
1663
+ catch (error) {
1664
+ console.error('Error installing app:', error);
1665
+ this.appAccessDialog?.completeProcessing();
1666
+ this.redirectToFirstApp(this.appManager.GetAllApps());
1667
+ }
1668
+ }
1669
+ /**
1670
+ * Enable a disabled app for the user and navigate to it
1671
+ */
1672
+ async enableAndNavigateToApp(appId) {
1673
+ try {
1674
+ const success = await this.appManager.EnableAppForUser(appId);
1675
+ if (success) {
1676
+ // App enabled successfully - navigate to it
1677
+ const app = this.appManager.GetAppById(appId);
1678
+ if (app) {
1679
+ await this.navigateToApp(app);
1680
+ this.appAccessDialog?.completeProcessing();
1681
+ }
1682
+ else {
1683
+ this.appAccessDialog?.completeProcessing();
1684
+ this.redirectToFirstApp(this.appManager.GetAllApps());
1685
+ }
1686
+ }
1687
+ else {
1688
+ this.appAccessDialog?.completeProcessing();
1689
+ this.redirectToFirstApp(this.appManager.GetAllApps());
1690
+ }
1691
+ }
1692
+ catch (error) {
1693
+ console.error('Error enabling app:', error);
1694
+ this.appAccessDialog?.completeProcessing();
1695
+ this.redirectToFirstApp(this.appManager.GetAllApps());
1696
+ }
1697
+ }
1698
+ /**
1699
+ * Navigate to a specific app and create its default tab
1700
+ */
1701
+ async navigateToApp(app) {
1702
+ await this.appManager.SetActiveApp(app.ID);
1703
+ const existingTabs = this.workspaceManager.GetAppTabs(app.ID);
1704
+ if (existingTabs.length === 0) {
1705
+ const tabRequest = await app.CreateDefaultTab();
1706
+ if (tabRequest) {
1707
+ this.tabService.OpenTab(tabRequest);
1708
+ }
1709
+ }
1710
+ // Update URL to reflect the new app
1711
+ const appPath = app.Path || app.Name;
1712
+ this.router.navigateByUrl(`/app/${encodeURIComponent(appPath)}`, { replaceUrl: true });
1713
+ }
1714
+ /**
1715
+ * Redirect to the first available app (fallback)
1716
+ */
1717
+ async redirectToFirstApp(apps) {
1718
+ if (apps.length > 0) {
1719
+ const firstApp = apps[0];
1720
+ await this.navigateToApp(firstApp);
1721
+ }
1722
+ else {
1723
+ // No apps available - this shouldn't happen, but handle gracefully
1724
+ this.loading = false;
1725
+ this.cdr.detectChanges();
1726
+ }
1727
+ }
1318
1728
  static ɵfac = function ShellComponent_Factory(t) { return new (t || ShellComponent)(i0.ɵɵdirectiveInject(i1.ApplicationManager), i0.ɵɵdirectiveInject(i1.WorkspaceStateManager), i0.ɵɵdirectiveInject(i1.GoldenLayoutManager), i0.ɵɵdirectiveInject(i1.TabService), i0.ɵɵdirectiveInject(i2.NavigationService), i0.ɵɵdirectiveInject(i3.ActivatedRoute), i0.ɵɵdirectiveInject(i3.Router), i0.ɵɵdirectiveInject(i4.MJAuthBase), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i5.UserAvatarService), i0.ɵɵdirectiveInject(i6.SettingsDialogService), i0.ɵɵdirectiveInject(i0.ViewContainerRef), i0.ɵɵdirectiveInject(i2.TitleService)); };
1319
1729
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ShellComponent, selectors: [["mj-shell"]], viewQuery: function ShellComponent_Query(rf, ctx) { if (rf & 1) {
1320
1730
  i0.ɵɵviewQuery(_c0, 5);
1731
+ i0.ɵɵviewQuery(_c1, 5);
1321
1732
  } if (rf & 2) {
1322
1733
  let _t;
1323
1734
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.searchInput = _t.first);
1324
- } }, decls: 2, vars: 2, consts: [["iconAvatar", ""], ["searchInput", ""], ["class", "shell-container", "kendoDialogContainer", "", 3, "tabs-visible", 4, "ngIf"], ["class", "shell-loading", 4, "ngIf"], ["kendoDialogContainer", "", 1, "shell-container"], [1, "shell-header"], ["title", "MemberJunction", 1, "mj-logo"], ["title", "Menu", 1, "hamburger-btn", 3, "click"], [1, "fa-solid", "fa-bars"], ["class", "nav-bar-apps left-of-switcher", 4, "ngIf"], [3, "appSelected", "activeApp", "isViewingSystemTab", "loadingAppId"], ["class", "desktop-nav", 3, "app", "navItemClick", 4, "ngIf"], [1, "spacer"], [1, "header-actions"], ["title", "Search", 1, "icon-btn", "desktop-only", "search-toggle-btn", 3, "click"], [1, "fa-solid", "fa-search"], ["title", "Notifications", 1, "icon-btn", "desktop-only", "notification-btn", 3, "click"], [1, "fa-solid", "fa-bell"], ["class", "notification-badge", 4, "ngIf"], ["class", "nav-bar-apps left-of-user-menu", 4, "ngIf"], [1, "user-menu"], [1, "avatar-btn", 3, "click"], [4, "ngIf", "ngIfElse"], ["class", "user-context-menu", 4, "ngIf"], ["class", "search-popup-overlay", 3, "click", 4, "ngIf"], [1, "search-popup"], [1, "search-popup-content", 3, "click"], ["textField", "Name", "valueField", "ID", 1, "search-entity-dropdown", 3, "ngModelChange", "data", "ngModel"], ["type", "text", "placeholder", "Search...", "kendoTextBox", "", 1, "search-input", 3, "keydown.enter"], ["title", "Search", 1, "search-submit-btn", 3, "click"], ["class", "mobile-nav-overlay", 3, "click", 4, "ngIf"], [1, "mobile-nav-drawer"], [1, "mobile-nav-header"], [1, "close-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], ["class", "mobile-nav-content", 4, "ngIf"], [1, "mobile-nav-footer"], ["title", "Search", 1, "mobile-nav-action", 3, "click"], ["title", "Notifications", 1, "mobile-nav-action", 3, "click"], ["class", "notification-badge-mobile", 4, "ngIf"], [1, "nav-bar-apps", "left-of-switcher"], ["class", "nav-bar-app-btn", 3, "active", "title", "--app-color", "click", "dblclick", 4, "ngFor", "ngForOf"], [1, "nav-bar-app-btn", 3, "click", "dblclick", "title"], [1, "desktop-nav", 3, "navItemClick", "app"], [1, "notification-badge"], [1, "nav-bar-apps", "left-of-user-menu"], ["alt", "User avatar", 1, "avatar-img", 3, "src"], [1, "icon-fallback"], [1, "user-context-menu"], ["class", "user-menu-header", 4, "ngIf"], ["class", "user-menu-divider", 4, "ngIf"], [1, "user-menu-item", 3, "click"], [1, "fa-solid", "fa-gear"], [1, "user-menu-divider"], [1, "fa-solid", "fa-code"], [1, "user-menu-item", "danger", 3, "click"], [1, "fa-solid", "fa-rotate-left"], [1, "fa-solid", "fa-sign-out-alt"], [1, "user-menu-header"], [1, "user-name"], [1, "search-popup-overlay", 3, "click"], [1, "mobile-nav-overlay", 3, "click"], [1, "mobile-nav-content"], [1, "mobile-nav-section-title"], [3, "navItemClick", "app"], [1, "notification-badge-mobile"], [1, "shell-loading"], ["text", "Loading workspace...", "size", "large"]], template: function ShellComponent_Template(rf, ctx) { if (rf & 1) {
1325
- i0.ɵɵtemplate(0, ShellComponent_div_0_Template, 49, 24, "div", 2)(1, ShellComponent_div_1_Template, 2, 0, "div", 3);
1735
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.appAccessDialog = _t.first);
1736
+ } }, decls: 52, vars: 27, consts: [["iconAvatar", ""], ["searchInput", ""], ["appAccessDialog", ""], ["kendoDialogContainer", "", 1, "shell-container"], [1, "shell-header"], ["title", "MemberJunction", 1, "mj-logo"], ["title", "Menu", 1, "hamburger-btn", 3, "click"], [1, "fa-solid", "fa-bars"], ["class", "nav-bar-apps left-of-switcher", 4, "ngIf"], [3, "appSelected", "activeApp", "isViewingSystemTab", "loadingAppId"], ["class", "desktop-nav", 3, "app", "navItemClick", 4, "ngIf"], [1, "spacer"], [1, "header-actions"], ["title", "Search", 1, "icon-btn", "desktop-only", "search-toggle-btn", 3, "click"], [1, "fa-solid", "fa-search"], ["title", "Notifications", 1, "icon-btn", "desktop-only", "notification-btn", 3, "click"], [1, "fa-solid", "fa-bell"], ["class", "notification-badge", 4, "ngIf"], ["class", "nav-bar-apps left-of-user-menu", 4, "ngIf"], [1, "user-menu"], [1, "avatar-btn", 3, "click"], [4, "ngIf", "ngIfElse"], ["class", "user-context-menu", 4, "ngIf"], ["class", "search-popup-overlay", 3, "click", 4, "ngIf"], [1, "search-popup"], [1, "search-popup-content", 3, "click"], ["textField", "Name", "valueField", "ID", 1, "search-entity-dropdown", 3, "ngModelChange", "data", "ngModel"], ["type", "text", "placeholder", "Search...", "kendoTextBox", "", 1, "search-input", 3, "keydown.enter"], ["title", "Search", 1, "search-submit-btn", 3, "click"], ["class", "mobile-nav-overlay", 3, "click", 4, "ngIf"], [1, "mobile-nav-drawer"], [1, "mobile-nav-header"], [1, "close-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], ["class", "mobile-nav-content", 4, "ngIf"], [1, "mobile-nav-footer"], ["title", "Search", 1, "mobile-nav-action", 3, "click"], ["title", "Notifications", 1, "mobile-nav-action", 3, "click"], ["class", "notification-badge-mobile", 4, "ngIf"], [3, "firstResourceLoadComplete", "layoutInitError"], ["class", "shell-loading", 4, "ngIf"], [3, "result"], [1, "nav-bar-apps", "left-of-switcher"], ["class", "nav-bar-app-btn", 3, "active", "title", "--app-color", "click", "dblclick", 4, "ngFor", "ngForOf"], [1, "nav-bar-app-btn", 3, "click", "dblclick", "title"], [1, "desktop-nav", 3, "navItemClick", "app"], [1, "notification-badge"], [1, "nav-bar-apps", "left-of-user-menu"], ["alt", "User avatar", 1, "avatar-img", 3, "src"], [1, "icon-fallback"], [1, "user-context-menu"], ["class", "user-menu-header", 4, "ngIf"], ["class", "user-menu-divider", 4, "ngIf"], [1, "user-menu-item", 3, "click"], [1, "fa-solid", "fa-gear"], [1, "user-menu-divider"], [1, "fa-solid", "fa-code"], [1, "user-menu-item", "danger", 3, "click"], [1, "fa-solid", "fa-rotate-left"], [1, "fa-solid", "fa-sign-out-alt"], [1, "user-menu-header"], [1, "user-name"], [1, "search-popup-overlay", 3, "click"], [1, "mobile-nav-overlay", 3, "click"], [1, "mobile-nav-content"], [1, "mobile-nav-section-title"], [3, "navItemClick", "app"], [1, "notification-badge-mobile"], [1, "shell-loading"], ["size", "large", 3, "text", "textColor", "logoColor", "logoGradient", "animation"]], template: function ShellComponent_Template(rf, ctx) { if (rf & 1) {
1737
+ const _r1 = i0.ɵɵgetCurrentView();
1738
+ i0.ɵɵelementStart(0, "div", 3)(1, "header", 4);
1739
+ i0.ɵɵelement(2, "div", 5);
1740
+ i0.ɵɵelementStart(3, "button", 6);
1741
+ i0.ɵɵlistener("click", function ShellComponent_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.toggleMobileNav()); });
1742
+ i0.ɵɵelement(4, "i", 7);
1743
+ i0.ɵɵelementEnd();
1744
+ i0.ɵɵtemplate(5, ShellComponent_div_5_Template, 2, 1, "div", 8);
1745
+ i0.ɵɵelementStart(6, "mj-app-switcher", 9);
1746
+ i0.ɵɵlistener("appSelected", function ShellComponent_Template_mj_app_switcher_appSelected_6_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onAppSwitch($event)); });
1747
+ i0.ɵɵelementEnd();
1748
+ i0.ɵɵtemplate(7, ShellComponent_mj_app_nav_7_Template, 1, 1, "mj-app-nav", 10);
1749
+ i0.ɵɵelement(8, "div", 11);
1750
+ i0.ɵɵelementStart(9, "div", 12)(10, "button", 13);
1751
+ i0.ɵɵlistener("click", function ShellComponent_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.toggleSearch()); });
1752
+ i0.ɵɵelement(11, "i", 14);
1753
+ i0.ɵɵelementEnd();
1754
+ i0.ɵɵelementStart(12, "button", 15);
1755
+ i0.ɵɵlistener("click", function ShellComponent_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.showNotifications()); });
1756
+ i0.ɵɵelement(13, "i", 16);
1757
+ i0.ɵɵtemplate(14, ShellComponent_span_14_Template, 2, 1, "span", 17);
1758
+ i0.ɵɵelementEnd();
1759
+ i0.ɵɵtemplate(15, ShellComponent_div_15_Template, 2, 1, "div", 18);
1760
+ i0.ɵɵelementStart(16, "div", 19)(17, "button", 20);
1761
+ i0.ɵɵlistener("click", function ShellComponent_Template_button_click_17_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.toggleUserMenu($event)); });
1762
+ i0.ɵɵtemplate(18, ShellComponent_ng_container_18_Template, 2, 1, "ng-container", 21)(19, ShellComponent_ng_template_19_Template, 2, 2, "ng-template", null, 0, i0.ɵɵtemplateRefExtractor);
1763
+ i0.ɵɵelementEnd();
1764
+ i0.ɵɵtemplate(21, ShellComponent_div_21_Template, 22, 2, "div", 22);
1765
+ i0.ɵɵelementEnd()()();
1766
+ i0.ɵɵtemplate(22, ShellComponent_div_22_Template, 1, 0, "div", 23);
1767
+ i0.ɵɵelementStart(23, "div", 24)(24, "div", 25);
1768
+ i0.ɵɵlistener("click", function ShellComponent_Template_div_click_24_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView($event.stopPropagation()); });
1769
+ i0.ɵɵelementStart(25, "kendo-dropdownlist", 26);
1770
+ i0.ɵɵtwoWayListener("ngModelChange", function ShellComponent_Template_kendo_dropdownlist_ngModelChange_25_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.selectedEntity, $event) || (ctx.selectedEntity = $event); return i0.ɵɵresetView($event); });
1771
+ i0.ɵɵelementEnd();
1772
+ i0.ɵɵelementStart(26, "input", 27, 1);
1773
+ i0.ɵɵlistener("keydown.enter", function ShellComponent_Template_input_keydown_enter_26_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onSearch($event)); });
1774
+ i0.ɵɵelementEnd();
1775
+ i0.ɵɵelementStart(28, "button", 28);
1776
+ i0.ɵɵlistener("click", function ShellComponent_Template_button_click_28_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onSearch($event)); });
1777
+ i0.ɵɵelement(29, "i", 14);
1778
+ i0.ɵɵelementEnd()()();
1779
+ i0.ɵɵtemplate(30, ShellComponent_div_30_Template, 1, 0, "div", 29);
1780
+ i0.ɵɵelementStart(31, "div", 30)(32, "div", 31)(33, "span");
1781
+ i0.ɵɵtext(34, "Navigation");
1782
+ i0.ɵɵelementEnd();
1783
+ i0.ɵɵelementStart(35, "button", 32);
1784
+ i0.ɵɵlistener("click", function ShellComponent_Template_button_click_35_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.closeMobileNav()); });
1785
+ i0.ɵɵelement(36, "i", 33);
1786
+ i0.ɵɵelementEnd()();
1787
+ i0.ɵɵtemplate(37, ShellComponent_div_37_Template, 4, 2, "div", 34);
1788
+ i0.ɵɵelementStart(38, "div", 35)(39, "button", 36);
1789
+ i0.ɵɵlistener("click", function ShellComponent_Template_button_click_39_listener() { i0.ɵɵrestoreView(_r1); ctx.toggleSearch(); return i0.ɵɵresetView(ctx.closeMobileNav()); });
1790
+ i0.ɵɵelement(40, "i", 14);
1791
+ i0.ɵɵelementStart(41, "span");
1792
+ i0.ɵɵtext(42, "Search");
1793
+ i0.ɵɵelementEnd()();
1794
+ i0.ɵɵelementStart(43, "button", 37);
1795
+ i0.ɵɵlistener("click", function ShellComponent_Template_button_click_43_listener() { i0.ɵɵrestoreView(_r1); ctx.showNotifications(); return i0.ɵɵresetView(ctx.closeMobileNav()); });
1796
+ i0.ɵɵelement(44, "i", 16);
1797
+ i0.ɵɵelementStart(45, "span");
1798
+ i0.ɵɵtext(46, "Notifications");
1799
+ i0.ɵɵelementEnd();
1800
+ i0.ɵɵtemplate(47, ShellComponent_span_47_Template, 2, 1, "span", 38);
1801
+ i0.ɵɵelementEnd()()();
1802
+ i0.ɵɵelementStart(48, "mj-tab-container", 39);
1803
+ i0.ɵɵlistener("firstResourceLoadComplete", function ShellComponent_Template_mj_tab_container_firstResourceLoadComplete_48_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onFirstResourceLoadComplete()); })("layoutInitError", function ShellComponent_Template_mj_tab_container_layoutInitError_48_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.handleLayoutError()); });
1804
+ i0.ɵɵelementEnd()();
1805
+ i0.ɵɵtemplate(49, ShellComponent_div_49_Template, 2, 5, "div", 40);
1806
+ i0.ɵɵelementStart(50, "mj-app-access-dialog", 41, 2);
1807
+ i0.ɵɵlistener("result", function ShellComponent_Template_mj_app_access_dialog_result_50_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onAppAccessDialogResult($event)); });
1808
+ i0.ɵɵelementEnd();
1326
1809
  } if (rf & 2) {
1327
- i0.ɵɵproperty("ngIf", !ctx.loading);
1810
+ const iconAvatar_r12 = i0.ɵɵreference(20);
1811
+ i0.ɵɵclassProp("hidden", ctx.loading)("tabs-visible", ctx.tabBarVisible);
1812
+ i0.ɵɵadvance(5);
1813
+ i0.ɵɵproperty("ngIf", ctx.leftOfSwitcherApps.length > 0);
1814
+ i0.ɵɵadvance();
1815
+ i0.ɵɵproperty("activeApp", ctx.activeApp)("isViewingSystemTab", ctx.isViewingSystemTab)("loadingAppId", ctx.loadingAppId);
1816
+ i0.ɵɵadvance();
1817
+ i0.ɵɵproperty("ngIf", ctx.activeApp);
1818
+ i0.ɵɵadvance(7);
1819
+ i0.ɵɵproperty("ngIf", ctx.unreadNotificationCount > 0);
1820
+ i0.ɵɵadvance();
1821
+ i0.ɵɵproperty("ngIf", ctx.leftOfUserMenuApps.length > 0);
1822
+ i0.ɵɵadvance(3);
1823
+ i0.ɵɵproperty("ngIf", ctx.userImageURL)("ngIfElse", iconAvatar_r12);
1824
+ i0.ɵɵadvance(3);
1825
+ i0.ɵɵproperty("ngIf", ctx.userMenuVisible);
1826
+ i0.ɵɵadvance();
1827
+ i0.ɵɵproperty("ngIf", ctx.isSearchOpen);
1828
+ i0.ɵɵadvance();
1829
+ i0.ɵɵclassProp("open", ctx.isSearchOpen);
1830
+ i0.ɵɵadvance(2);
1831
+ i0.ɵɵproperty("data", ctx.searchableEntities);
1832
+ i0.ɵɵtwoWayProperty("ngModel", ctx.selectedEntity);
1833
+ i0.ɵɵadvance(5);
1834
+ i0.ɵɵproperty("ngIf", ctx.mobileNavOpen);
1835
+ i0.ɵɵadvance();
1836
+ i0.ɵɵclassProp("open", ctx.mobileNavOpen);
1837
+ i0.ɵɵadvance(6);
1838
+ i0.ɵɵproperty("ngIf", ctx.activeApp);
1839
+ i0.ɵɵadvance(10);
1840
+ i0.ɵɵproperty("ngIf", ctx.unreadNotificationCount > 0);
1841
+ i0.ɵɵadvance();
1842
+ i0.ɵɵclassProp("hide-tab-bar", !ctx.tabBarVisible);
1328
1843
  i0.ɵɵadvance();
1329
1844
  i0.ɵɵproperty("ngIf", ctx.loading);
1330
- } }, dependencies: [i7.NgForOf, i7.NgIf, i8.NgControlStatus, i8.NgModel, i9.DropDownListComponent, i10.TextBoxDirective, i11.LoadingComponent, i12.AppSwitcherComponent, i13.AppNavComponent, i14.TabContainerComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100vh;\n width: 100%;\n overflow: hidden;\n}\n\n\n\n.mj-logo[_ngcontent-%COMP%] {\n width: 32px;\n height: 18px;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='230' height='128' viewBox='0 0 230 128'%3E%3Cpath d='M0 0 C1.197 0.668 2.394 1.336 3.592 2.004 C12.234 6.837 20.792 11.805 29.327 16.824 C37.26 21.476 45.269 25.98 53.312 30.438 C53.91 30.769 54.507 31.1 55.122 31.441 C61.234 34.87 61.234 34.87 67.438 38.125 C69.709 37.16 69.709 37.16 72.258 35.652 C73.255 35.09 74.253 34.527 75.281 33.948 C76.364 33.325 77.447 32.703 78.562 32.062 C79.685 31.426 80.808 30.789 81.965 30.133 C90.435 25.322 98.84 20.401 107.239 15.469 C118.242 9.027 129.394 2.857 140.566 -3.286 C142.41 -4.306 144.248 -5.338 146.079 -6.382 C146.869 -6.832 147.659 -7.282 148.473 -7.746 C149.148 -8.136 149.824 -8.526 150.52 -8.927 C156.448 -11.856 163.036 -11.676 169.188 -9.625 C175.638 -6.152 178.915 -2.712 181.438 4.125 C181.951 7.259 181.946 10.308 181.892 13.479 C181.892 14.377 181.893 15.276 181.893 16.201 C181.891 19.145 181.86 22.088 181.828 25.031 C181.821 27.082 181.815 29.134 181.811 31.185 C181.796 36.564 181.757 41.943 181.712 47.322 C181.671 52.819 181.653 58.316 181.633 63.812 C181.59 74.584 181.522 85.354 181.438 96.125 C178.573 94.739 175.729 93.326 172.901 91.867 C170.644 90.732 168.349 89.671 166.018 88.7 C162.628 87.127 160.12 85.736 157.438 83.125 C155.741 78.082 155.893 73.244 156.047 68.004 C156.047 66.534 156.041 65.064 156.031 63.595 C156.018 59.745 156.076 55.899 156.15 52.049 C156.213 48.114 156.207 44.18 156.207 40.244 C156.217 32.536 156.303 24.832 156.438 17.125 C152.485 19.335 148.534 21.546 144.582 23.758 C143.476 24.376 142.37 24.995 141.231 25.632 C131.895 30.857 122.601 36.151 113.321 41.472 C107.737 44.673 102.15 47.868 96.562 51.062 C95.965 51.404 95.367 51.746 94.751 52.098 C86.826 56.629 78.889 61.14 70.938 65.625 C62.527 70.37 54.133 75.144 45.75 79.938 C45.166 80.271 44.581 80.605 43.979 80.95 C37.987 84.375 31.996 87.803 26.011 91.241 C14.366 97.93 2.707 104.594 -9.062 111.062 C-9.97 111.565 -10.878 112.067 -11.814 112.585 C-12.649 113.04 -13.484 113.496 -14.344 113.965 C-15.066 114.36 -15.789 114.756 -16.533 115.164 C-22.269 117.881 -28.602 117.949 -34.625 116.125 C-39.398 114.15 -42.881 110.491 -45.562 106.125 C-45.562 104.805 -45.562 103.485 -45.562 102.125 C-45.022 101.835 -44.481 101.545 -43.924 101.246 C-32.122 94.897 -20.456 88.363 -8.907 81.566 C-0.017 76.35 8.975 71.333 18.003 66.362 C24.427 62.82 30.777 59.186 37.065 55.408 C39.438 54.125 39.438 54.125 41.438 54.125 C41.438 53.465 41.438 52.805 41.438 52.125 C40.704 51.843 39.971 51.561 39.216 51.271 C36.702 50.234 34.368 49.093 31.98 47.797 C30.7 47.102 30.7 47.102 29.395 46.394 C28.481 45.892 27.567 45.391 26.625 44.875 C25.666 44.351 24.707 43.826 23.719 43.286 C14.477 38.202 5.37 32.897 -3.719 27.547 C-8.103 24.968 -12.509 22.431 -16.928 19.911 C-17.89 19.362 -17.89 19.362 -18.871 18.802 C-20.435 17.909 -21.999 17.017 -23.562 16.125 C-23.525 16.942 -23.487 17.759 -23.448 18.601 C-23.106 26.338 -22.848 34.071 -22.682 41.814 C-22.593 45.794 -22.474 49.768 -22.28 53.745 C-21.06 79.461 -21.06 79.461 -25.205 85.53 C-29.148 89.11 -33.517 90.996 -38.581 92.49 C-41.159 93.316 -43.282 94.688 -45.562 96.125 C-46.222 96.125 -46.882 96.125 -47.562 96.125 C-47.655 84.546 -47.726 72.967 -47.77 61.388 C-47.791 56.01 -47.819 50.633 -47.864 45.256 C-47.908 40.062 -47.932 34.869 -47.942 29.675 C-47.949 27.698 -47.964 25.721 -47.985 23.744 C-48.015 20.965 -48.018 18.187 -48.017 15.408 C-48.031 14.599 -48.045 13.79 -48.06 12.956 C-48.013 6.348 -46.391 0.196 -41.823 -4.764 C-27.895 -17.466 -13.817 -7.747 0 0 Z' fill='%23264FAF' transform='translate(47.5625,10.875)'/%3E%3Cpath d='M0 0 C2.051 0.961 2.051 0.961 4.098 2.16 C5.278 2.843 5.278 2.843 6.481 3.541 C7.333 4.043 8.185 4.545 9.062 5.062 C10.954 6.16 12.846 7.258 14.738 8.355 C16.255 9.24 16.255 9.24 17.803 10.142 C22.848 13.074 27.913 15.969 32.979 18.863 C34.753 19.877 36.525 20.892 38.297 21.907 C44.243 25.311 50.205 28.681 56.203 31.992 C57.347 32.625 58.491 33.258 59.669 33.911 C61.837 35.108 64.008 36.299 66.183 37.484 C67.154 38.02 68.125 38.557 69.125 39.109 C69.973 39.573 70.821 40.037 71.695 40.515 C74.149 42.096 76.015 43.87 78 46 C74.984 51.808 72.395 55.457 66.25 58.25 C54.159 61.04 44.857 55.778 34.625 49.75 C32.781 48.681 30.938 47.612 29.094 46.543 C28.114 45.972 27.134 45.402 26.125 44.814 C21.068 41.878 15.989 38.98 10.91 36.082 C9.13 35.065 7.35 34.048 5.57 33.03 C-5.598 26.648 -16.794 20.315 -28 14 C-28 13.34 -28 12.68 -28 12 C-24.284 9.789 -20.551 7.61 -16.812 5.438 C-15.757 4.809 -14.702 4.181 -13.615 3.533 C-12.083 2.649 -12.083 2.649 -10.52 1.746 C-9.582 1.196 -8.645 0.646 -7.679 0.08 C-4.518 -1.194 -3.196 -1.069 0 0 Z' fill='%23264FAF' transform='translate(150,69)'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n flex-shrink: 0;\n}\n\n.shell-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100vh;\n width: 100%;\n overflow: hidden;\n}\n\nmj-tab-container[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n transition: all 0.2s ease-in-out;\n}\n\n\n\nmj-tab-container.hide-tab-bar[_ngcontent-%COMP%] .lm_header {\n display: none;\n}\n\n\n\nmj-tab-container[_ngcontent-%COMP%]:not(.hide-tab-bar) .lm_header {\n opacity: 1;\n max-height: 40px;\n transition: opacity 0.2s ease-in-out, max-height 0.2s ease-in-out;\n}\n\n\n\nmj-tab-container.hide-tab-bar[_ngcontent-%COMP%] .lm_content {\n height: 100% !important;\n}\n\n\n\nmj-tab-container[_ngcontent-%COMP%] .lm_stack {\n transition: all 0.2s ease-in-out;\n}\n\n.shell-header[_ngcontent-%COMP%] {\n height: 60px;\n background: white;\n border-bottom: 1px solid #e0e0e0;\n display: flex;\n align-items: center;\n padding: 0 16px;\n gap: 16px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n flex-shrink: 0;\n}\n\n\n\n.nav-bar-apps[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.nav-bar-apps.left-of-switcher[_ngcontent-%COMP%] {\n \n\n \n\n}\n\n.nav-bar-apps.left-of-user-menu[_ngcontent-%COMP%] {\n margin-right: 8px;\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%] {\n --app-color: #757575;\n width: 40px;\n height: 40px;\n border-radius: 10px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #616161;\n font-size: 18px;\n transition: all 0.15s ease;\n position: relative;\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--app-color) 15%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--app-color) 20%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active[_ngcontent-%COMP%]::after {\n content: '';\n position: absolute;\n bottom: 6px;\n left: 50%;\n transform: translateX(-50%);\n width: 16px;\n height: 3px;\n background: var(--app-color);\n border-radius: 2px;\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transition: transform 0.15s ease;\n margin-top: 2px; \n\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n transform: scale(1.1);\n}\n\n.spacer[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.icon-btn[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #757575;\n font-size: 18px;\n transition: background 0.15s;\n}\n\n.icon-btn[_ngcontent-%COMP%]:hover {\n background: #f5f5f5;\n}\n\n\n\n.notification-btn[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.notification-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: 4px;\n right: 4px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: #e53935;\n color: white;\n font-size: 10px;\n font-weight: 600;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n.user-menu[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: box-shadow 0.15s, transform 0.15s;\n padding: 0;\n overflow: hidden;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover {\n transform: scale(1.05);\n}\n\n\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .icon-fallback[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 2px solid #e0e0e0;\n background: #f5f5f5;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: border-color 0.15s;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover .icon-fallback[_ngcontent-%COMP%] {\n border-color: #1976d2;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .icon-fallback[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #757575;\n font-size: 16px;\n}\n\n\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .avatar-img[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: cover;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover .avatar-img[_ngcontent-%COMP%] {\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);\n}\n\n\n\n.user-menu-header[_ngcontent-%COMP%] {\n padding: 12px 16px;\n background: #fafafa;\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: #424242;\n}\n\n\n\n.user-context-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 8px;\n background: white;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);\n min-width: 180px;\n z-index: 10000;\n overflow: hidden;\n}\n\n.user-menu-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n cursor: pointer;\n font-size: 14px;\n color: #424242;\n transition: background 0.15s;\n}\n\n.user-menu-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 18px;\n text-align: center;\n color: #757575;\n font-size: 14px;\n}\n\n.user-menu-item[_ngcontent-%COMP%]:hover {\n background: #f5f5f5;\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%] {\n color: #c62828;\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #c62828;\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%]:hover {\n background: #ffebee;\n}\n\n.user-menu-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: #e0e0e0;\n margin: 4px 0;\n}\n\n.shell-loading[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100vh;\n background: #fafafa;\n}\n\n\n\n.hamburger-btn[_ngcontent-%COMP%] {\n display: none;\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: none;\n cursor: pointer;\n align-items: center;\n justify-content: center;\n color: #616161;\n font-size: 20px;\n transition: background 0.15s;\n}\n.hamburger-btn[_ngcontent-%COMP%]:hover {\n background: #f5f5f5;\n}\n\n\n\n.mobile-nav-overlay[_ngcontent-%COMP%] {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 9998;\n}\n\n\n\n.mobile-nav-drawer[_ngcontent-%COMP%] {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n width: 280px;\n max-width: 85vw;\n background: white;\n box-shadow: 2px 0 12px rgba(0, 0, 0, 0.15);\n z-index: 9999;\n flex-direction: column;\n transform: translateX(-100%);\n transition: transform 0.3s ease;\n}\n.mobile-nav-drawer.open[_ngcontent-%COMP%] {\n transform: translateX(0);\n}\n\n.mobile-nav-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid #e0e0e0;\n background: #fafafa;\n}\n.mobile-nav-header[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 16px;\n color: #424242;\n}\n.mobile-nav-header[_ngcontent-%COMP%] .close-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #757575;\n font-size: 18px;\n transition: background 0.15s;\n}\n.mobile-nav-header[_ngcontent-%COMP%] .close-btn[_ngcontent-%COMP%]:hover {\n background: #e0e0e0;\n}\n\n.mobile-nav-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 16px 0;\n}\n\n.mobile-nav-section-title[_ngcontent-%COMP%] {\n padding: 8px 20px;\n font-size: 12px;\n font-weight: 600;\n color: #9e9e9e;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.mobile-nav-footer[_ngcontent-%COMP%] {\n border-top: 1px solid #e0e0e0;\n padding: 12px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.mobile-nav-action[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n border: none;\n background: none;\n cursor: pointer;\n border-radius: 8px;\n color: #616161;\n font-size: 14px;\n font-weight: 500;\n transition: background 0.15s;\n width: 100%;\n text-align: left;\n}\n.mobile-nav-action[_ngcontent-%COMP%]:hover {\n background: #f5f5f5;\n}\n.mobile-nav-action[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n width: 20px;\n text-align: center;\n}\n\n\n\n@media (max-width: 768px) {\n .hamburger-btn[_ngcontent-%COMP%] {\n display: flex;\n }\n\n .desktop-nav[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .desktop-only[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .mobile-nav-overlay[_ngcontent-%COMP%] {\n display: block;\n }\n\n .mobile-nav-drawer[_ngcontent-%COMP%] {\n display: flex;\n }\n\n .shell-header[_ngcontent-%COMP%] {\n padding: 0 12px;\n gap: 8px;\n }\n}\n\n\n\n .settings-fullscreen-window {\n \n\n box-shadow: none !important;\n border: none !important;\n}\n\n .settings-fullscreen-window .k-window-titlebar {\n background: #ffffff;\n border-bottom: 1px solid #e0e0e0;\n padding: 12px 16px;\n}\n\n .settings-fullscreen-window .k-window-title {\n font-size: 18px;\n font-weight: 600;\n color: #212121;\n}\n\n .settings-fullscreen-window .k-window-titlebar-actions {\n gap: 4px;\n}\n\n .settings-fullscreen-window .k-window-titlebar-action {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n}\n\n .settings-fullscreen-window .k-window-titlebar-action:hover {\n background: #f5f5f5;\n}\n\n .settings-fullscreen-window .k-window-content {\n padding: 0;\n overflow: auto;\n background: #fafafa;\n}\n\n\n\n .settings-fullscreen-window .k-window-titlebar-action[title=\"Minimize\"], \n .settings-fullscreen-window .k-window-titlebar-action[title=\"Maximize\"], \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window-minimize, \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window-maximize, \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window {\n display: none !important;\n}\n\n\n\n\n\n\n.search-popup-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 9999;\n animation: _ngcontent-%COMP%_fadeIn 0.15s ease;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.search-popup[_ngcontent-%COMP%] {\n position: fixed;\n top: 60px; \n\n right: 16px;\n width: 480px;\n max-width: calc(100vw - 32px);\n background: white;\n border-radius: 12px;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);\n z-index: 10000;\n opacity: 0;\n transform: translateY(-10px);\n pointer-events: none;\n transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.search-popup.open[_ngcontent-%COMP%] {\n opacity: 1;\n transform: translateY(0);\n pointer-events: all;\n}\n\n.search-popup-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n}\n\n.search-entity-dropdown[_ngcontent-%COMP%] {\n min-width: 140px;\n max-width: 180px;\n flex-shrink: 0;\n}\n\n.search-input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n height: 40px;\n padding: 8px 12px;\n font-size: 14px;\n border: 1px solid #d4d4d4;\n border-radius: 4px;\n outline: none;\n display: block !important;\n box-sizing: border-box;\n}\n\n.search-input[_ngcontent-%COMP%]:focus {\n border-color: #1976d2;\n box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.1);\n}\n\n.search-submit-btn[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: #1976d2;\n color: white;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n transition: background 0.15s;\n flex-shrink: 0;\n}\n\n.search-submit-btn[_ngcontent-%COMP%]:hover {\n background: #1565c0;\n}\n\n.search-submit-btn[_ngcontent-%COMP%]:active {\n background: #0d47a1;\n}\n\n\n\n.notification-badge-mobile[_ngcontent-%COMP%] {\n position: absolute;\n top: 8px;\n right: 8px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: #e53935;\n color: white;\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n\n\n@media (max-width: 768px) {\n .search-popup[_ngcontent-%COMP%] {\n top: 60px;\n left: 16px;\n right: 16px;\n width: auto;\n max-width: none;\n }\n\n .search-popup-content[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n }\n\n .search-entity-dropdown[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .search-input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n }\n}"] });
1845
+ } }, dependencies: [i7.NgForOf, i7.NgIf, i8.NgControlStatus, i8.NgModel, i9.DropDownListComponent, i10.TextBoxDirective, i11.LoadingComponent, i12.AppSwitcherComponent, i13.AppNavComponent, i14.TabContainerComponent, i15.AppAccessDialogComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100vh;\n width: 100%;\n overflow: hidden;\n}\n\n\n\n.mj-logo[_ngcontent-%COMP%] {\n width: 32px;\n height: 18px;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='230' height='128' viewBox='0 0 230 128'%3E%3Cpath d='M0 0 C1.197 0.668 2.394 1.336 3.592 2.004 C12.234 6.837 20.792 11.805 29.327 16.824 C37.26 21.476 45.269 25.98 53.312 30.438 C53.91 30.769 54.507 31.1 55.122 31.441 C61.234 34.87 61.234 34.87 67.438 38.125 C69.709 37.16 69.709 37.16 72.258 35.652 C73.255 35.09 74.253 34.527 75.281 33.948 C76.364 33.325 77.447 32.703 78.562 32.062 C79.685 31.426 80.808 30.789 81.965 30.133 C90.435 25.322 98.84 20.401 107.239 15.469 C118.242 9.027 129.394 2.857 140.566 -3.286 C142.41 -4.306 144.248 -5.338 146.079 -6.382 C146.869 -6.832 147.659 -7.282 148.473 -7.746 C149.148 -8.136 149.824 -8.526 150.52 -8.927 C156.448 -11.856 163.036 -11.676 169.188 -9.625 C175.638 -6.152 178.915 -2.712 181.438 4.125 C181.951 7.259 181.946 10.308 181.892 13.479 C181.892 14.377 181.893 15.276 181.893 16.201 C181.891 19.145 181.86 22.088 181.828 25.031 C181.821 27.082 181.815 29.134 181.811 31.185 C181.796 36.564 181.757 41.943 181.712 47.322 C181.671 52.819 181.653 58.316 181.633 63.812 C181.59 74.584 181.522 85.354 181.438 96.125 C178.573 94.739 175.729 93.326 172.901 91.867 C170.644 90.732 168.349 89.671 166.018 88.7 C162.628 87.127 160.12 85.736 157.438 83.125 C155.741 78.082 155.893 73.244 156.047 68.004 C156.047 66.534 156.041 65.064 156.031 63.595 C156.018 59.745 156.076 55.899 156.15 52.049 C156.213 48.114 156.207 44.18 156.207 40.244 C156.217 32.536 156.303 24.832 156.438 17.125 C152.485 19.335 148.534 21.546 144.582 23.758 C143.476 24.376 142.37 24.995 141.231 25.632 C131.895 30.857 122.601 36.151 113.321 41.472 C107.737 44.673 102.15 47.868 96.562 51.062 C95.965 51.404 95.367 51.746 94.751 52.098 C86.826 56.629 78.889 61.14 70.938 65.625 C62.527 70.37 54.133 75.144 45.75 79.938 C45.166 80.271 44.581 80.605 43.979 80.95 C37.987 84.375 31.996 87.803 26.011 91.241 C14.366 97.93 2.707 104.594 -9.062 111.062 C-9.97 111.565 -10.878 112.067 -11.814 112.585 C-12.649 113.04 -13.484 113.496 -14.344 113.965 C-15.066 114.36 -15.789 114.756 -16.533 115.164 C-22.269 117.881 -28.602 117.949 -34.625 116.125 C-39.398 114.15 -42.881 110.491 -45.562 106.125 C-45.562 104.805 -45.562 103.485 -45.562 102.125 C-45.022 101.835 -44.481 101.545 -43.924 101.246 C-32.122 94.897 -20.456 88.363 -8.907 81.566 C-0.017 76.35 8.975 71.333 18.003 66.362 C24.427 62.82 30.777 59.186 37.065 55.408 C39.438 54.125 39.438 54.125 41.438 54.125 C41.438 53.465 41.438 52.805 41.438 52.125 C40.704 51.843 39.971 51.561 39.216 51.271 C36.702 50.234 34.368 49.093 31.98 47.797 C30.7 47.102 30.7 47.102 29.395 46.394 C28.481 45.892 27.567 45.391 26.625 44.875 C25.666 44.351 24.707 43.826 23.719 43.286 C14.477 38.202 5.37 32.897 -3.719 27.547 C-8.103 24.968 -12.509 22.431 -16.928 19.911 C-17.89 19.362 -17.89 19.362 -18.871 18.802 C-20.435 17.909 -21.999 17.017 -23.562 16.125 C-23.525 16.942 -23.487 17.759 -23.448 18.601 C-23.106 26.338 -22.848 34.071 -22.682 41.814 C-22.593 45.794 -22.474 49.768 -22.28 53.745 C-21.06 79.461 -21.06 79.461 -25.205 85.53 C-29.148 89.11 -33.517 90.996 -38.581 92.49 C-41.159 93.316 -43.282 94.688 -45.562 96.125 C-46.222 96.125 -46.882 96.125 -47.562 96.125 C-47.655 84.546 -47.726 72.967 -47.77 61.388 C-47.791 56.01 -47.819 50.633 -47.864 45.256 C-47.908 40.062 -47.932 34.869 -47.942 29.675 C-47.949 27.698 -47.964 25.721 -47.985 23.744 C-48.015 20.965 -48.018 18.187 -48.017 15.408 C-48.031 14.599 -48.045 13.79 -48.06 12.956 C-48.013 6.348 -46.391 0.196 -41.823 -4.764 C-27.895 -17.466 -13.817 -7.747 0 0 Z' fill='%23264FAF' transform='translate(47.5625,10.875)'/%3E%3Cpath d='M0 0 C2.051 0.961 2.051 0.961 4.098 2.16 C5.278 2.843 5.278 2.843 6.481 3.541 C7.333 4.043 8.185 4.545 9.062 5.062 C10.954 6.16 12.846 7.258 14.738 8.355 C16.255 9.24 16.255 9.24 17.803 10.142 C22.848 13.074 27.913 15.969 32.979 18.863 C34.753 19.877 36.525 20.892 38.297 21.907 C44.243 25.311 50.205 28.681 56.203 31.992 C57.347 32.625 58.491 33.258 59.669 33.911 C61.837 35.108 64.008 36.299 66.183 37.484 C67.154 38.02 68.125 38.557 69.125 39.109 C69.973 39.573 70.821 40.037 71.695 40.515 C74.149 42.096 76.015 43.87 78 46 C74.984 51.808 72.395 55.457 66.25 58.25 C54.159 61.04 44.857 55.778 34.625 49.75 C32.781 48.681 30.938 47.612 29.094 46.543 C28.114 45.972 27.134 45.402 26.125 44.814 C21.068 41.878 15.989 38.98 10.91 36.082 C9.13 35.065 7.35 34.048 5.57 33.03 C-5.598 26.648 -16.794 20.315 -28 14 C-28 13.34 -28 12.68 -28 12 C-24.284 9.789 -20.551 7.61 -16.812 5.438 C-15.757 4.809 -14.702 4.181 -13.615 3.533 C-12.083 2.649 -12.083 2.649 -10.52 1.746 C-9.582 1.196 -8.645 0.646 -7.679 0.08 C-4.518 -1.194 -3.196 -1.069 0 0 Z' fill='%23264FAF' transform='translate(150,69)'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n flex-shrink: 0;\n}\n\n.shell-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100vh;\n width: 100%;\n overflow: hidden;\n}\n\n\n\n\n.shell-container.hidden[_ngcontent-%COMP%] {\n visibility: hidden;\n position: absolute;\n pointer-events: none;\n}\n\nmj-tab-container[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n transition: all 0.2s ease-in-out;\n}\n\n\n\nmj-tab-container.hide-tab-bar[_ngcontent-%COMP%] .lm_header {\n display: none;\n}\n\n\n\nmj-tab-container[_ngcontent-%COMP%]:not(.hide-tab-bar) .lm_header {\n opacity: 1;\n max-height: 40px;\n transition: opacity 0.2s ease-in-out, max-height 0.2s ease-in-out;\n}\n\n\n\nmj-tab-container.hide-tab-bar[_ngcontent-%COMP%] .lm_content {\n height: 100% !important;\n}\n\n\n\nmj-tab-container[_ngcontent-%COMP%] .lm_stack {\n transition: all 0.2s ease-in-out;\n}\n\n.shell-header[_ngcontent-%COMP%] {\n height: 60px;\n background: white;\n border-bottom: 1px solid #e0e0e0;\n display: flex;\n align-items: center;\n padding: 0 16px;\n gap: 16px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n flex-shrink: 0;\n}\n\n\n\n.nav-bar-apps[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.nav-bar-apps.left-of-switcher[_ngcontent-%COMP%] {\n \n\n \n\n}\n\n.nav-bar-apps.left-of-user-menu[_ngcontent-%COMP%] {\n margin-right: 8px;\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%] {\n --app-color: #757575;\n width: 40px;\n height: 40px;\n border-radius: 10px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #616161;\n font-size: 18px;\n transition: all 0.15s ease;\n position: relative;\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--app-color) 15%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--app-color) 20%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active[_ngcontent-%COMP%]::after {\n content: '';\n position: absolute;\n bottom: 6px;\n left: 50%;\n transform: translateX(-50%);\n width: 16px;\n height: 3px;\n background: var(--app-color);\n border-radius: 2px;\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transition: transform 0.15s ease;\n margin-top: 2px; \n\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n transform: scale(1.1);\n}\n\n.spacer[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.icon-btn[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #757575;\n font-size: 18px;\n transition: background 0.15s;\n}\n\n.icon-btn[_ngcontent-%COMP%]:hover {\n background: #f5f5f5;\n}\n\n\n\n.notification-btn[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.notification-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: 4px;\n right: 4px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: #e53935;\n color: white;\n font-size: 10px;\n font-weight: 600;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n.user-menu[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: box-shadow 0.15s, transform 0.15s;\n padding: 0;\n overflow: hidden;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover {\n transform: scale(1.05);\n}\n\n\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .icon-fallback[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 2px solid #e0e0e0;\n background: #f5f5f5;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: border-color 0.15s;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover .icon-fallback[_ngcontent-%COMP%] {\n border-color: #1976d2;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .icon-fallback[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #757575;\n font-size: 16px;\n}\n\n\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .avatar-img[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: cover;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover .avatar-img[_ngcontent-%COMP%] {\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);\n}\n\n\n\n.user-menu-header[_ngcontent-%COMP%] {\n padding: 12px 16px;\n background: #fafafa;\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: #424242;\n}\n\n\n\n.user-context-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 8px;\n background: white;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);\n min-width: 180px;\n z-index: 10000;\n overflow: hidden;\n}\n\n.user-menu-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n cursor: pointer;\n font-size: 14px;\n color: #424242;\n transition: background 0.15s;\n}\n\n.user-menu-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 18px;\n text-align: center;\n color: #757575;\n font-size: 14px;\n}\n\n.user-menu-item[_ngcontent-%COMP%]:hover {\n background: #f5f5f5;\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%] {\n color: #c62828;\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #c62828;\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%]:hover {\n background: #ffebee;\n}\n\n.user-menu-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: #e0e0e0;\n margin: 4px 0;\n}\n\n.shell-loading[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100vh;\n background: #fafafa;\n}\n\n\n\n.hamburger-btn[_ngcontent-%COMP%] {\n display: none;\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: none;\n cursor: pointer;\n align-items: center;\n justify-content: center;\n color: #616161;\n font-size: 20px;\n transition: background 0.15s;\n}\n.hamburger-btn[_ngcontent-%COMP%]:hover {\n background: #f5f5f5;\n}\n\n\n\n.mobile-nav-overlay[_ngcontent-%COMP%] {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 9998;\n}\n\n\n\n.mobile-nav-drawer[_ngcontent-%COMP%] {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n width: 280px;\n max-width: 85vw;\n background: white;\n box-shadow: 2px 0 12px rgba(0, 0, 0, 0.15);\n z-index: 9999;\n flex-direction: column;\n transform: translateX(-100%);\n transition: transform 0.3s ease;\n}\n.mobile-nav-drawer.open[_ngcontent-%COMP%] {\n transform: translateX(0);\n}\n\n.mobile-nav-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid #e0e0e0;\n background: #fafafa;\n}\n.mobile-nav-header[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 16px;\n color: #424242;\n}\n.mobile-nav-header[_ngcontent-%COMP%] .close-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #757575;\n font-size: 18px;\n transition: background 0.15s;\n}\n.mobile-nav-header[_ngcontent-%COMP%] .close-btn[_ngcontent-%COMP%]:hover {\n background: #e0e0e0;\n}\n\n.mobile-nav-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 16px 0;\n}\n\n.mobile-nav-section-title[_ngcontent-%COMP%] {\n padding: 8px 20px;\n font-size: 12px;\n font-weight: 600;\n color: #9e9e9e;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.mobile-nav-footer[_ngcontent-%COMP%] {\n border-top: 1px solid #e0e0e0;\n padding: 12px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.mobile-nav-action[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n border: none;\n background: none;\n cursor: pointer;\n border-radius: 8px;\n color: #616161;\n font-size: 14px;\n font-weight: 500;\n transition: background 0.15s;\n width: 100%;\n text-align: left;\n}\n.mobile-nav-action[_ngcontent-%COMP%]:hover {\n background: #f5f5f5;\n}\n.mobile-nav-action[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n width: 20px;\n text-align: center;\n}\n\n\n\n@media (max-width: 768px) {\n .hamburger-btn[_ngcontent-%COMP%] {\n display: flex;\n }\n\n .desktop-nav[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .desktop-only[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .mobile-nav-overlay[_ngcontent-%COMP%] {\n display: block;\n }\n\n .mobile-nav-drawer[_ngcontent-%COMP%] {\n display: flex;\n }\n\n .shell-header[_ngcontent-%COMP%] {\n padding: 0 12px;\n gap: 8px;\n }\n}\n\n\n\n .settings-fullscreen-window {\n \n\n box-shadow: none !important;\n border: none !important;\n}\n\n .settings-fullscreen-window .k-window-titlebar {\n background: #ffffff;\n border-bottom: 1px solid #e0e0e0;\n padding: 12px 16px;\n}\n\n .settings-fullscreen-window .k-window-title {\n font-size: 18px;\n font-weight: 600;\n color: #212121;\n}\n\n .settings-fullscreen-window .k-window-titlebar-actions {\n gap: 4px;\n}\n\n .settings-fullscreen-window .k-window-titlebar-action {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n}\n\n .settings-fullscreen-window .k-window-titlebar-action:hover {\n background: #f5f5f5;\n}\n\n .settings-fullscreen-window .k-window-content {\n padding: 0;\n overflow: auto;\n background: #fafafa;\n}\n\n\n\n .settings-fullscreen-window .k-window-titlebar-action[title=\"Minimize\"], \n .settings-fullscreen-window .k-window-titlebar-action[title=\"Maximize\"], \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window-minimize, \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window-maximize, \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window {\n display: none !important;\n}\n\n\n\n\n\n\n.search-popup-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 9999;\n animation: _ngcontent-%COMP%_fadeIn 0.15s ease;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.search-popup[_ngcontent-%COMP%] {\n position: fixed;\n top: 60px; \n\n right: 16px;\n width: 480px;\n max-width: calc(100vw - 32px);\n background: white;\n border-radius: 12px;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);\n z-index: 10000;\n opacity: 0;\n transform: translateY(-10px);\n pointer-events: none;\n transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.search-popup.open[_ngcontent-%COMP%] {\n opacity: 1;\n transform: translateY(0);\n pointer-events: all;\n}\n\n.search-popup-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n}\n\n.search-entity-dropdown[_ngcontent-%COMP%] {\n min-width: 140px;\n max-width: 180px;\n flex-shrink: 0;\n}\n\n.search-input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n height: 40px;\n padding: 8px 12px;\n font-size: 14px;\n border: 1px solid #d4d4d4;\n border-radius: 4px;\n outline: none;\n display: block !important;\n box-sizing: border-box;\n}\n\n.search-input[_ngcontent-%COMP%]:focus {\n border-color: #1976d2;\n box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.1);\n}\n\n.search-submit-btn[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: #1976d2;\n color: white;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n transition: background 0.15s;\n flex-shrink: 0;\n}\n\n.search-submit-btn[_ngcontent-%COMP%]:hover {\n background: #1565c0;\n}\n\n.search-submit-btn[_ngcontent-%COMP%]:active {\n background: #0d47a1;\n}\n\n\n\n.notification-badge-mobile[_ngcontent-%COMP%] {\n position: absolute;\n top: 8px;\n right: 8px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: #e53935;\n color: white;\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n\n\n@media (max-width: 768px) {\n .search-popup[_ngcontent-%COMP%] {\n top: 60px;\n left: 16px;\n right: 16px;\n width: auto;\n max-width: none;\n }\n\n .search-popup-content[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n }\n\n .search-entity-dropdown[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .search-input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n }\n}"] });
1331
1846
  }
1332
1847
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ShellComponent, [{
1333
1848
  type: Component,
1334
- args: [{ selector: 'mj-shell', template: "<div class=\"shell-container\" *ngIf=\"!loading\" [class.tabs-visible]=\"tabBarVisible\" kendoDialogContainer>\n <!-- Header -->\n <header class=\"shell-header\">\n <!-- MJ Logo -->\n <div class=\"mj-logo\" title=\"MemberJunction\"></div>\n\n <!-- Mobile Hamburger Button -->\n <button class=\"hamburger-btn\" (click)=\"toggleMobileNav()\" title=\"Menu\">\n <i class=\"fa-solid fa-bars\"></i>\n </button>\n\n <!-- Nav Bar Apps: Left of App Switcher -->\n <div class=\"nav-bar-apps left-of-switcher\" *ngIf=\"leftOfSwitcherApps.length > 0\">\n <button *ngFor=\"let app of leftOfSwitcherApps\"\n class=\"nav-bar-app-btn\"\n [class.active]=\"app.ID === activeApp?.ID\"\n [title]=\"app.Name\"\n [style.--app-color]=\"app.GetColor()\"\n (click)=\"onNavBarAppClick(app, $event)\"\n (dblclick)=\"onNavBarAppDblClick(app, $event)\">\n <i [class]=\"app.Icon\"></i>\n </button>\n </div>\n\n <!-- App Switcher -->\n <mj-app-switcher\n [activeApp]=\"activeApp\"\n [isViewingSystemTab]=\"isViewingSystemTab\"\n [loadingAppId]=\"loadingAppId\"\n (appSelected)=\"onAppSwitch($event)\">\n </mj-app-switcher>\n\n <!-- App Navigation (desktop only) -->\n <mj-app-nav\n *ngIf=\"activeApp\"\n class=\"desktop-nav\"\n [app]=\"activeApp\"\n (navItemClick)=\"onNavItemClick($event)\">\n </mj-app-nav>\n\n <!-- Spacer -->\n <div class=\"spacer\"></div>\n\n <!-- Actions (search, notifications, user menu) -->\n <div class=\"header-actions\">\n <button class=\"icon-btn desktop-only search-toggle-btn\" title=\"Search\" (click)=\"toggleSearch()\">\n <i class=\"fa-solid fa-search\"></i>\n </button>\n <button class=\"icon-btn desktop-only notification-btn\" title=\"Notifications\" (click)=\"showNotifications()\">\n <i class=\"fa-solid fa-bell\"></i>\n <span class=\"notification-badge\" *ngIf=\"unreadNotificationCount > 0\">\n {{ unreadNotificationCount > 99 ? '99+' : unreadNotificationCount }}\n </span>\n </button>\n\n <!-- Nav Bar Apps: Left of User Menu -->\n <div class=\"nav-bar-apps left-of-user-menu\" *ngIf=\"leftOfUserMenuApps.length > 0\">\n <button *ngFor=\"let app of leftOfUserMenuApps\"\n class=\"nav-bar-app-btn\"\n [class.active]=\"app.ID === activeApp?.ID\"\n [title]=\"app.Name\"\n [style.--app-color]=\"app.GetColor()\"\n (click)=\"onNavBarAppClick(app, $event)\"\n (dblclick)=\"onNavBarAppDblClick(app, $event)\">\n <i [class]=\"app.Icon\"></i>\n </button>\n </div>\n\n <div class=\"user-menu\">\n <button class=\"avatar-btn\" (click)=\"toggleUserMenu($event)\">\n <ng-container *ngIf=\"userImageURL; else iconAvatar\">\n <img [src]=\"userImageURL\" alt=\"User avatar\" class=\"avatar-img\" />\n </ng-container>\n <ng-template #iconAvatar>\n <div class=\"icon-fallback\">\n <i [class]=\"userIconClass || 'fa-solid fa-user'\"></i>\n </div>\n </ng-template>\n </button>\n <!-- User Context Menu -->\n <div class=\"user-context-menu\" *ngIf=\"userMenuVisible\">\n <div class=\"user-menu-header\" *ngIf=\"userName\">\n <span class=\"user-name\">{{ userName }}</span>\n </div>\n <div class=\"user-menu-divider\" *ngIf=\"userName\"></div>\n <div class=\"user-menu-item\" (click)=\"onSettings()\">\n <i class=\"fa-solid fa-gear\"></i>\n <span>Settings</span>\n </div>\n <div class=\"user-menu-divider\"></div>\n <div class=\"user-menu-item\" (click)=\"onLogLayout()\">\n <i class=\"fa-solid fa-code\"></i>\n <span>Log Layout (Debug)</span>\n </div>\n <div class=\"user-menu-divider\"></div>\n <div class=\"user-menu-item danger\" (click)=\"onResetLayout()\">\n <i class=\"fa-solid fa-rotate-left\"></i>\n <span>Reset Layout</span>\n </div>\n <div class=\"user-menu-divider\"></div>\n <div class=\"user-menu-item\" (click)=\"onLogout()\">\n <i class=\"fa-solid fa-sign-out-alt\"></i>\n <span>Logout</span>\n </div>\n </div>\n </div>\n </div>\n </header>\n\n <!-- Search Popup -->\n <div class=\"search-popup-overlay\" *ngIf=\"isSearchOpen\" (click)=\"closeSearch()\"></div>\n <div class=\"search-popup\" [class.open]=\"isSearchOpen\">\n <div class=\"search-popup-content\" (click)=\"$event.stopPropagation()\">\n <kendo-dropdownlist\n [data]=\"searchableEntities\"\n textField=\"Name\"\n valueField=\"ID\"\n class=\"search-entity-dropdown\"\n [(ngModel)]=\"selectedEntity\">\n </kendo-dropdownlist>\n <input\n type=\"text\"\n #searchInput\n placeholder=\"Search...\"\n kendoTextBox\n class=\"search-input\"\n (keydown.enter)=\"onSearch($event)\"\n />\n <button class=\"search-submit-btn\" (click)=\"onSearch($event)\" title=\"Search\">\n <i class=\"fa-solid fa-search\"></i>\n </button>\n </div>\n </div>\n\n <!-- Mobile Navigation Drawer -->\n <div class=\"mobile-nav-overlay\" *ngIf=\"mobileNavOpen\" (click)=\"closeMobileNav()\"></div>\n <div class=\"mobile-nav-drawer\" [class.open]=\"mobileNavOpen\">\n <div class=\"mobile-nav-header\">\n <span>Navigation</span>\n <button class=\"close-btn\" (click)=\"closeMobileNav()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n <div class=\"mobile-nav-content\" *ngIf=\"activeApp\">\n <div class=\"mobile-nav-section-title\">{{ activeApp.Name }}</div>\n <mj-app-nav\n [app]=\"activeApp\"\n (navItemClick)=\"onNavItemClick($event)\">\n </mj-app-nav>\n </div>\n <div class=\"mobile-nav-footer\">\n <button class=\"mobile-nav-action\" title=\"Search\" (click)=\"toggleSearch(); closeMobileNav()\">\n <i class=\"fa-solid fa-search\"></i>\n <span>Search</span>\n </button>\n <button class=\"mobile-nav-action\" title=\"Notifications\" (click)=\"showNotifications(); closeMobileNav()\">\n <i class=\"fa-solid fa-bell\"></i>\n <span>Notifications</span>\n <span class=\"notification-badge-mobile\" *ngIf=\"unreadNotificationCount > 0\">\n {{ unreadNotificationCount > 99 ? '99+' : unreadNotificationCount }}\n </span>\n </button>\n </div>\n </div>\n\n <!-- Tab Container - with dynamic tab bar visibility -->\n <mj-tab-container [class.hide-tab-bar]=\"!tabBarVisible\"></mj-tab-container>\n</div>\n\n<!-- Loading State -->\n<div class=\"shell-loading\" *ngIf=\"loading\">\n <mj-loading text=\"Loading workspace...\" size=\"large\"></mj-loading>\n</div>\n", styles: [":host {\n display: block;\n height: 100vh;\n width: 100%;\n overflow: hidden;\n}\n\n/* MJ Logo - inline SVG as data URI from MJ-Mark-Only-Transparent.svg */\n.mj-logo {\n width: 32px;\n height: 18px;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='230' height='128' viewBox='0 0 230 128'%3E%3Cpath d='M0 0 C1.197 0.668 2.394 1.336 3.592 2.004 C12.234 6.837 20.792 11.805 29.327 16.824 C37.26 21.476 45.269 25.98 53.312 30.438 C53.91 30.769 54.507 31.1 55.122 31.441 C61.234 34.87 61.234 34.87 67.438 38.125 C69.709 37.16 69.709 37.16 72.258 35.652 C73.255 35.09 74.253 34.527 75.281 33.948 C76.364 33.325 77.447 32.703 78.562 32.062 C79.685 31.426 80.808 30.789 81.965 30.133 C90.435 25.322 98.84 20.401 107.239 15.469 C118.242 9.027 129.394 2.857 140.566 -3.286 C142.41 -4.306 144.248 -5.338 146.079 -6.382 C146.869 -6.832 147.659 -7.282 148.473 -7.746 C149.148 -8.136 149.824 -8.526 150.52 -8.927 C156.448 -11.856 163.036 -11.676 169.188 -9.625 C175.638 -6.152 178.915 -2.712 181.438 4.125 C181.951 7.259 181.946 10.308 181.892 13.479 C181.892 14.377 181.893 15.276 181.893 16.201 C181.891 19.145 181.86 22.088 181.828 25.031 C181.821 27.082 181.815 29.134 181.811 31.185 C181.796 36.564 181.757 41.943 181.712 47.322 C181.671 52.819 181.653 58.316 181.633 63.812 C181.59 74.584 181.522 85.354 181.438 96.125 C178.573 94.739 175.729 93.326 172.901 91.867 C170.644 90.732 168.349 89.671 166.018 88.7 C162.628 87.127 160.12 85.736 157.438 83.125 C155.741 78.082 155.893 73.244 156.047 68.004 C156.047 66.534 156.041 65.064 156.031 63.595 C156.018 59.745 156.076 55.899 156.15 52.049 C156.213 48.114 156.207 44.18 156.207 40.244 C156.217 32.536 156.303 24.832 156.438 17.125 C152.485 19.335 148.534 21.546 144.582 23.758 C143.476 24.376 142.37 24.995 141.231 25.632 C131.895 30.857 122.601 36.151 113.321 41.472 C107.737 44.673 102.15 47.868 96.562 51.062 C95.965 51.404 95.367 51.746 94.751 52.098 C86.826 56.629 78.889 61.14 70.938 65.625 C62.527 70.37 54.133 75.144 45.75 79.938 C45.166 80.271 44.581 80.605 43.979 80.95 C37.987 84.375 31.996 87.803 26.011 91.241 C14.366 97.93 2.707 104.594 -9.062 111.062 C-9.97 111.565 -10.878 112.067 -11.814 112.585 C-12.649 113.04 -13.484 113.496 -14.344 113.965 C-15.066 114.36 -15.789 114.756 -16.533 115.164 C-22.269 117.881 -28.602 117.949 -34.625 116.125 C-39.398 114.15 -42.881 110.491 -45.562 106.125 C-45.562 104.805 -45.562 103.485 -45.562 102.125 C-45.022 101.835 -44.481 101.545 -43.924 101.246 C-32.122 94.897 -20.456 88.363 -8.907 81.566 C-0.017 76.35 8.975 71.333 18.003 66.362 C24.427 62.82 30.777 59.186 37.065 55.408 C39.438 54.125 39.438 54.125 41.438 54.125 C41.438 53.465 41.438 52.805 41.438 52.125 C40.704 51.843 39.971 51.561 39.216 51.271 C36.702 50.234 34.368 49.093 31.98 47.797 C30.7 47.102 30.7 47.102 29.395 46.394 C28.481 45.892 27.567 45.391 26.625 44.875 C25.666 44.351 24.707 43.826 23.719 43.286 C14.477 38.202 5.37 32.897 -3.719 27.547 C-8.103 24.968 -12.509 22.431 -16.928 19.911 C-17.89 19.362 -17.89 19.362 -18.871 18.802 C-20.435 17.909 -21.999 17.017 -23.562 16.125 C-23.525 16.942 -23.487 17.759 -23.448 18.601 C-23.106 26.338 -22.848 34.071 -22.682 41.814 C-22.593 45.794 -22.474 49.768 -22.28 53.745 C-21.06 79.461 -21.06 79.461 -25.205 85.53 C-29.148 89.11 -33.517 90.996 -38.581 92.49 C-41.159 93.316 -43.282 94.688 -45.562 96.125 C-46.222 96.125 -46.882 96.125 -47.562 96.125 C-47.655 84.546 -47.726 72.967 -47.77 61.388 C-47.791 56.01 -47.819 50.633 -47.864 45.256 C-47.908 40.062 -47.932 34.869 -47.942 29.675 C-47.949 27.698 -47.964 25.721 -47.985 23.744 C-48.015 20.965 -48.018 18.187 -48.017 15.408 C-48.031 14.599 -48.045 13.79 -48.06 12.956 C-48.013 6.348 -46.391 0.196 -41.823 -4.764 C-27.895 -17.466 -13.817 -7.747 0 0 Z' fill='%23264FAF' transform='translate(47.5625,10.875)'/%3E%3Cpath d='M0 0 C2.051 0.961 2.051 0.961 4.098 2.16 C5.278 2.843 5.278 2.843 6.481 3.541 C7.333 4.043 8.185 4.545 9.062 5.062 C10.954 6.16 12.846 7.258 14.738 8.355 C16.255 9.24 16.255 9.24 17.803 10.142 C22.848 13.074 27.913 15.969 32.979 18.863 C34.753 19.877 36.525 20.892 38.297 21.907 C44.243 25.311 50.205 28.681 56.203 31.992 C57.347 32.625 58.491 33.258 59.669 33.911 C61.837 35.108 64.008 36.299 66.183 37.484 C67.154 38.02 68.125 38.557 69.125 39.109 C69.973 39.573 70.821 40.037 71.695 40.515 C74.149 42.096 76.015 43.87 78 46 C74.984 51.808 72.395 55.457 66.25 58.25 C54.159 61.04 44.857 55.778 34.625 49.75 C32.781 48.681 30.938 47.612 29.094 46.543 C28.114 45.972 27.134 45.402 26.125 44.814 C21.068 41.878 15.989 38.98 10.91 36.082 C9.13 35.065 7.35 34.048 5.57 33.03 C-5.598 26.648 -16.794 20.315 -28 14 C-28 13.34 -28 12.68 -28 12 C-24.284 9.789 -20.551 7.61 -16.812 5.438 C-15.757 4.809 -14.702 4.181 -13.615 3.533 C-12.083 2.649 -12.083 2.649 -10.52 1.746 C-9.582 1.196 -8.645 0.646 -7.679 0.08 C-4.518 -1.194 -3.196 -1.069 0 0 Z' fill='%23264FAF' transform='translate(150,69)'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n flex-shrink: 0;\n}\n\n.shell-container {\n display: flex;\n flex-direction: column;\n height: 100vh;\n width: 100%;\n overflow: hidden;\n}\n\nmj-tab-container {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n transition: all 0.2s ease-in-out;\n}\n\n/* Hide Golden Layout tab headers when only one tab */\nmj-tab-container.hide-tab-bar ::ng-deep .lm_header {\n display: none;\n}\n\n/* Show tab headers when multiple tabs */\nmj-tab-container:not(.hide-tab-bar) ::ng-deep .lm_header {\n opacity: 1;\n max-height: 40px;\n transition: opacity 0.2s ease-in-out, max-height 0.2s ease-in-out;\n}\n\n/* Adjust content area height when tabs hidden */\nmj-tab-container.hide-tab-bar ::ng-deep .lm_content {\n height: 100% !important;\n}\n\n/* Ensure smooth transitions */\nmj-tab-container ::ng-deep .lm_stack {\n transition: all 0.2s ease-in-out;\n}\n\n.shell-header {\n height: 60px;\n background: white;\n border-bottom: 1px solid #e0e0e0;\n display: flex;\n align-items: center;\n padding: 0 16px;\n gap: 16px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n flex-shrink: 0;\n}\n\n/* Nav Bar Apps - permanent app icons in the header */\n.nav-bar-apps {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.nav-bar-apps.left-of-switcher {\n /* No extra margin - header gap handles spacing */\n /* This prevents the app switcher from shifting when icons are hidden */\n}\n\n.nav-bar-apps.left-of-user-menu {\n margin-right: 8px;\n}\n\n.nav-bar-app-btn {\n --app-color: #757575;\n width: 40px;\n height: 40px;\n border-radius: 10px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #616161;\n font-size: 18px;\n transition: all 0.15s ease;\n position: relative;\n}\n\n.nav-bar-app-btn:hover {\n background: color-mix(in srgb, var(--app-color) 15%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active {\n background: color-mix(in srgb, var(--app-color) 20%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active::after {\n content: '';\n position: absolute;\n bottom: 6px;\n left: 50%;\n transform: translateX(-50%);\n width: 16px;\n height: 3px;\n background: var(--app-color);\n border-radius: 2px;\n}\n\n.nav-bar-app-btn i {\n transition: transform 0.15s ease;\n margin-top: 2px; /* Align with app switcher icon */\n}\n\n.nav-bar-app-btn:hover i {\n transform: scale(1.1);\n}\n\n.spacer {\n flex: 1;\n}\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.icon-btn {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #757575;\n font-size: 18px;\n transition: background 0.15s;\n}\n\n.icon-btn:hover {\n background: #f5f5f5;\n}\n\n/* Notification button with badge */\n.notification-btn {\n position: relative;\n}\n\n.notification-badge {\n position: absolute;\n top: 4px;\n right: 4px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: #e53935;\n color: white;\n font-size: 10px;\n font-weight: 600;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n.user-menu {\n position: relative;\n}\n\n.user-menu .avatar-btn {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: box-shadow 0.15s, transform 0.15s;\n padding: 0;\n overflow: hidden;\n}\n\n.user-menu .avatar-btn:hover {\n transform: scale(1.05);\n}\n\n/* Icon fallback styling - shows gray circle with icon */\n.user-menu .avatar-btn .icon-fallback {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 2px solid #e0e0e0;\n background: #f5f5f5;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: border-color 0.15s;\n}\n\n.user-menu .avatar-btn:hover .icon-fallback {\n border-color: #1976d2;\n}\n\n.user-menu .avatar-btn .icon-fallback i {\n color: #757575;\n font-size: 16px;\n}\n\n/* Avatar image - replaces the gray circle entirely */\n.user-menu .avatar-btn .avatar-img {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: cover;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);\n}\n\n.user-menu .avatar-btn:hover .avatar-img {\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);\n}\n\n/* User Menu Header */\n.user-menu-header {\n padding: 12px 16px;\n background: #fafafa;\n}\n\n.user-menu-header .user-name {\n font-weight: 600;\n font-size: 14px;\n color: #424242;\n}\n\n/* User Context Menu */\n.user-context-menu {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 8px;\n background: white;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);\n min-width: 180px;\n z-index: 10000;\n overflow: hidden;\n}\n\n.user-menu-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n cursor: pointer;\n font-size: 14px;\n color: #424242;\n transition: background 0.15s;\n}\n\n.user-menu-item i {\n width: 18px;\n text-align: center;\n color: #757575;\n font-size: 14px;\n}\n\n.user-menu-item:hover {\n background: #f5f5f5;\n}\n\n.user-menu-item.danger {\n color: #c62828;\n}\n\n.user-menu-item.danger i {\n color: #c62828;\n}\n\n.user-menu-item.danger:hover {\n background: #ffebee;\n}\n\n.user-menu-divider {\n height: 1px;\n background: #e0e0e0;\n margin: 4px 0;\n}\n\n.shell-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100vh;\n background: #fafafa;\n}\n\n/* Hamburger button - hidden on desktop */\n.hamburger-btn {\n display: none;\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: none;\n cursor: pointer;\n align-items: center;\n justify-content: center;\n color: #616161;\n font-size: 20px;\n transition: background 0.15s;\n}\n.hamburger-btn:hover {\n background: #f5f5f5;\n}\n\n/* Mobile Navigation Overlay */\n.mobile-nav-overlay {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 9998;\n}\n\n/* Mobile Navigation Drawer */\n.mobile-nav-drawer {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n width: 280px;\n max-width: 85vw;\n background: white;\n box-shadow: 2px 0 12px rgba(0, 0, 0, 0.15);\n z-index: 9999;\n flex-direction: column;\n transform: translateX(-100%);\n transition: transform 0.3s ease;\n}\n.mobile-nav-drawer.open {\n transform: translateX(0);\n}\n\n.mobile-nav-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid #e0e0e0;\n background: #fafafa;\n}\n.mobile-nav-header span {\n font-weight: 600;\n font-size: 16px;\n color: #424242;\n}\n.mobile-nav-header .close-btn {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #757575;\n font-size: 18px;\n transition: background 0.15s;\n}\n.mobile-nav-header .close-btn:hover {\n background: #e0e0e0;\n}\n\n.mobile-nav-content {\n flex: 1;\n overflow-y: auto;\n padding: 16px 0;\n}\n\n.mobile-nav-section-title {\n padding: 8px 20px;\n font-size: 12px;\n font-weight: 600;\n color: #9e9e9e;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.mobile-nav-footer {\n border-top: 1px solid #e0e0e0;\n padding: 12px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.mobile-nav-action {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n border: none;\n background: none;\n cursor: pointer;\n border-radius: 8px;\n color: #616161;\n font-size: 14px;\n font-weight: 500;\n transition: background 0.15s;\n width: 100%;\n text-align: left;\n}\n.mobile-nav-action:hover {\n background: #f5f5f5;\n}\n.mobile-nav-action i {\n font-size: 16px;\n width: 20px;\n text-align: center;\n}\n\n/* Mobile Responsive Styles */\n@media (max-width: 768px) {\n .hamburger-btn {\n display: flex;\n }\n\n .desktop-nav {\n display: none !important;\n }\n\n .desktop-only {\n display: none !important;\n }\n\n .mobile-nav-overlay {\n display: block;\n }\n\n .mobile-nav-drawer {\n display: flex;\n }\n\n .shell-header {\n padding: 0 12px;\n gap: 8px;\n }\n}\n\n/* Settings Full-Screen Window Styles */\n::ng-deep .settings-fullscreen-window {\n /* Remove window chrome for full-screen feel */\n box-shadow: none !important;\n border: none !important;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar {\n background: #ffffff;\n border-bottom: 1px solid #e0e0e0;\n padding: 12px 16px;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-title {\n font-size: 18px;\n font-weight: 600;\n color: #212121;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-actions {\n gap: 4px;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action:hover {\n background: #f5f5f5;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-content {\n padding: 0;\n overflow: auto;\n background: #fafafa;\n}\n\n/* Hide minimize/maximize buttons - only show close */\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action[title=\"Minimize\"],\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action[title=\"Maximize\"],\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window-minimize,\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window-maximize,\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window {\n display: none !important;\n}\n\n/* ========================================\n SEARCH POPUP\n ======================================== */\n\n.search-popup-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 9999;\n animation: fadeIn 0.15s ease;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.search-popup {\n position: fixed;\n top: 60px; /* Below header */\n right: 16px;\n width: 480px;\n max-width: calc(100vw - 32px);\n background: white;\n border-radius: 12px;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);\n z-index: 10000;\n opacity: 0;\n transform: translateY(-10px);\n pointer-events: none;\n transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.search-popup.open {\n opacity: 1;\n transform: translateY(0);\n pointer-events: all;\n}\n\n.search-popup-content {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n}\n\n.search-entity-dropdown {\n min-width: 140px;\n max-width: 180px;\n flex-shrink: 0;\n}\n\n.search-input {\n flex: 1;\n min-width: 0;\n height: 40px;\n padding: 8px 12px;\n font-size: 14px;\n border: 1px solid #d4d4d4;\n border-radius: 4px;\n outline: none;\n display: block !important;\n box-sizing: border-box;\n}\n\n.search-input:focus {\n border-color: #1976d2;\n box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.1);\n}\n\n.search-submit-btn {\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: #1976d2;\n color: white;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n transition: background 0.15s;\n flex-shrink: 0;\n}\n\n.search-submit-btn:hover {\n background: #1565c0;\n}\n\n.search-submit-btn:active {\n background: #0d47a1;\n}\n\n/* Mobile notification badge */\n.notification-badge-mobile {\n position: absolute;\n top: 8px;\n right: 8px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: #e53935;\n color: white;\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n/* Mobile-specific search popup adjustments */\n@media (max-width: 768px) {\n .search-popup {\n top: 60px;\n left: 16px;\n right: 16px;\n width: auto;\n max-width: none;\n }\n\n .search-popup-content {\n flex-wrap: wrap;\n }\n\n .search-entity-dropdown {\n width: 100%;\n }\n\n .search-input {\n flex: 1;\n min-width: 0;\n }\n}"] }]
1849
+ args: [{ selector: 'mj-shell', template: "<div class=\"shell-container\" [class.hidden]=\"loading\" [class.tabs-visible]=\"tabBarVisible\" kendoDialogContainer>\n <!-- Header -->\n <header class=\"shell-header\">\n <!-- MJ Logo -->\n <div class=\"mj-logo\" title=\"MemberJunction\"></div>\n\n <!-- Mobile Hamburger Button -->\n <button class=\"hamburger-btn\" (click)=\"toggleMobileNav()\" title=\"Menu\">\n <i class=\"fa-solid fa-bars\"></i>\n </button>\n\n <!-- Nav Bar Apps: Left of App Switcher -->\n <div class=\"nav-bar-apps left-of-switcher\" *ngIf=\"leftOfSwitcherApps.length > 0\">\n <button *ngFor=\"let app of leftOfSwitcherApps\"\n class=\"nav-bar-app-btn\"\n [class.active]=\"app.ID === activeApp?.ID\"\n [title]=\"app.Name\"\n [style.--app-color]=\"app.GetColor()\"\n (click)=\"onNavBarAppClick(app, $event)\"\n (dblclick)=\"onNavBarAppDblClick(app, $event)\">\n <i [class]=\"app.Icon\"></i>\n </button>\n </div>\n\n <!-- App Switcher -->\n <mj-app-switcher\n [activeApp]=\"activeApp\"\n [isViewingSystemTab]=\"isViewingSystemTab\"\n [loadingAppId]=\"loadingAppId\"\n (appSelected)=\"onAppSwitch($event)\">\n </mj-app-switcher>\n\n <!-- App Navigation (desktop only) -->\n <mj-app-nav\n *ngIf=\"activeApp\"\n class=\"desktop-nav\"\n [app]=\"activeApp\"\n (navItemClick)=\"onNavItemClick($event)\">\n </mj-app-nav>\n\n <!-- Spacer -->\n <div class=\"spacer\"></div>\n\n <!-- Actions (search, notifications, user menu) -->\n <div class=\"header-actions\">\n <button class=\"icon-btn desktop-only search-toggle-btn\" title=\"Search\" (click)=\"toggleSearch()\">\n <i class=\"fa-solid fa-search\"></i>\n </button>\n <button class=\"icon-btn desktop-only notification-btn\" title=\"Notifications\" (click)=\"showNotifications()\">\n <i class=\"fa-solid fa-bell\"></i>\n <span class=\"notification-badge\" *ngIf=\"unreadNotificationCount > 0\">\n {{ unreadNotificationCount > 99 ? '99+' : unreadNotificationCount }}\n </span>\n </button>\n\n <!-- Nav Bar Apps: Left of User Menu -->\n <div class=\"nav-bar-apps left-of-user-menu\" *ngIf=\"leftOfUserMenuApps.length > 0\">\n <button *ngFor=\"let app of leftOfUserMenuApps\"\n class=\"nav-bar-app-btn\"\n [class.active]=\"app.ID === activeApp?.ID\"\n [title]=\"app.Name\"\n [style.--app-color]=\"app.GetColor()\"\n (click)=\"onNavBarAppClick(app, $event)\"\n (dblclick)=\"onNavBarAppDblClick(app, $event)\">\n <i [class]=\"app.Icon\"></i>\n </button>\n </div>\n\n <div class=\"user-menu\">\n <button class=\"avatar-btn\" (click)=\"toggleUserMenu($event)\">\n <ng-container *ngIf=\"userImageURL; else iconAvatar\">\n <img [src]=\"userImageURL\" alt=\"User avatar\" class=\"avatar-img\" />\n </ng-container>\n <ng-template #iconAvatar>\n <div class=\"icon-fallback\">\n <i [class]=\"userIconClass || 'fa-solid fa-user'\"></i>\n </div>\n </ng-template>\n </button>\n <!-- User Context Menu -->\n <div class=\"user-context-menu\" *ngIf=\"userMenuVisible\">\n <div class=\"user-menu-header\" *ngIf=\"userName\">\n <span class=\"user-name\">{{ userName }}</span>\n </div>\n <div class=\"user-menu-divider\" *ngIf=\"userName\"></div>\n <div class=\"user-menu-item\" (click)=\"onSettings()\">\n <i class=\"fa-solid fa-gear\"></i>\n <span>Settings</span>\n </div>\n <div class=\"user-menu-divider\"></div>\n <div class=\"user-menu-item\" (click)=\"onLogLayout()\">\n <i class=\"fa-solid fa-code\"></i>\n <span>Log Layout (Debug)</span>\n </div>\n <div class=\"user-menu-divider\"></div>\n <div class=\"user-menu-item danger\" (click)=\"onResetLayout()\">\n <i class=\"fa-solid fa-rotate-left\"></i>\n <span>Reset Layout</span>\n </div>\n <div class=\"user-menu-divider\"></div>\n <div class=\"user-menu-item\" (click)=\"onLogout()\">\n <i class=\"fa-solid fa-sign-out-alt\"></i>\n <span>Logout</span>\n </div>\n </div>\n </div>\n </div>\n </header>\n\n <!-- Search Popup -->\n <div class=\"search-popup-overlay\" *ngIf=\"isSearchOpen\" (click)=\"closeSearch()\"></div>\n <div class=\"search-popup\" [class.open]=\"isSearchOpen\">\n <div class=\"search-popup-content\" (click)=\"$event.stopPropagation()\">\n <kendo-dropdownlist\n [data]=\"searchableEntities\"\n textField=\"Name\"\n valueField=\"ID\"\n class=\"search-entity-dropdown\"\n [(ngModel)]=\"selectedEntity\">\n </kendo-dropdownlist>\n <input\n type=\"text\"\n #searchInput\n placeholder=\"Search...\"\n kendoTextBox\n class=\"search-input\"\n (keydown.enter)=\"onSearch($event)\"\n />\n <button class=\"search-submit-btn\" (click)=\"onSearch($event)\" title=\"Search\">\n <i class=\"fa-solid fa-search\"></i>\n </button>\n </div>\n </div>\n\n <!-- Mobile Navigation Drawer -->\n <div class=\"mobile-nav-overlay\" *ngIf=\"mobileNavOpen\" (click)=\"closeMobileNav()\"></div>\n <div class=\"mobile-nav-drawer\" [class.open]=\"mobileNavOpen\">\n <div class=\"mobile-nav-header\">\n <span>Navigation</span>\n <button class=\"close-btn\" (click)=\"closeMobileNav()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n <div class=\"mobile-nav-content\" *ngIf=\"activeApp\">\n <div class=\"mobile-nav-section-title\">{{ activeApp.Name }}</div>\n <mj-app-nav\n [app]=\"activeApp\"\n (navItemClick)=\"onNavItemClick($event)\">\n </mj-app-nav>\n </div>\n <div class=\"mobile-nav-footer\">\n <button class=\"mobile-nav-action\" title=\"Search\" (click)=\"toggleSearch(); closeMobileNav()\">\n <i class=\"fa-solid fa-search\"></i>\n <span>Search</span>\n </button>\n <button class=\"mobile-nav-action\" title=\"Notifications\" (click)=\"showNotifications(); closeMobileNav()\">\n <i class=\"fa-solid fa-bell\"></i>\n <span>Notifications</span>\n <span class=\"notification-badge-mobile\" *ngIf=\"unreadNotificationCount > 0\">\n {{ unreadNotificationCount > 99 ? '99+' : unreadNotificationCount }}\n </span>\n </button>\n </div>\n </div>\n\n <!-- Tab Container - with dynamic tab bar visibility -->\n <mj-tab-container\n [class.hide-tab-bar]=\"!tabBarVisible\"\n (firstResourceLoadComplete)=\"onFirstResourceLoadComplete()\"\n (layoutInitError)=\"handleLayoutError()\">\n </mj-tab-container>\n</div>\n\n<!-- Loading State -->\n<div class=\"shell-loading\" *ngIf=\"loading\">\n <mj-loading\n [text]=\"currentLoadingText\"\n [textColor]=\"currentLoadingTextColor\"\n [logoColor]=\"currentLoadingColor\"\n [logoGradient]=\"currentLoadingGradient\"\n [animation]=\"currentLoadingAnimation\"\n size=\"large\">\n </mj-loading>\n</div>\n\n<!-- App Access Error Dialog -->\n<mj-app-access-dialog\n #appAccessDialog\n (result)=\"onAppAccessDialogResult($event)\">\n</mj-app-access-dialog>\n", styles: [":host {\n display: block;\n height: 100vh;\n width: 100%;\n overflow: hidden;\n}\n\n/* MJ Logo - inline SVG as data URI from MJ-Mark-Only-Transparent.svg */\n.mj-logo {\n width: 32px;\n height: 18px;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='230' height='128' viewBox='0 0 230 128'%3E%3Cpath d='M0 0 C1.197 0.668 2.394 1.336 3.592 2.004 C12.234 6.837 20.792 11.805 29.327 16.824 C37.26 21.476 45.269 25.98 53.312 30.438 C53.91 30.769 54.507 31.1 55.122 31.441 C61.234 34.87 61.234 34.87 67.438 38.125 C69.709 37.16 69.709 37.16 72.258 35.652 C73.255 35.09 74.253 34.527 75.281 33.948 C76.364 33.325 77.447 32.703 78.562 32.062 C79.685 31.426 80.808 30.789 81.965 30.133 C90.435 25.322 98.84 20.401 107.239 15.469 C118.242 9.027 129.394 2.857 140.566 -3.286 C142.41 -4.306 144.248 -5.338 146.079 -6.382 C146.869 -6.832 147.659 -7.282 148.473 -7.746 C149.148 -8.136 149.824 -8.526 150.52 -8.927 C156.448 -11.856 163.036 -11.676 169.188 -9.625 C175.638 -6.152 178.915 -2.712 181.438 4.125 C181.951 7.259 181.946 10.308 181.892 13.479 C181.892 14.377 181.893 15.276 181.893 16.201 C181.891 19.145 181.86 22.088 181.828 25.031 C181.821 27.082 181.815 29.134 181.811 31.185 C181.796 36.564 181.757 41.943 181.712 47.322 C181.671 52.819 181.653 58.316 181.633 63.812 C181.59 74.584 181.522 85.354 181.438 96.125 C178.573 94.739 175.729 93.326 172.901 91.867 C170.644 90.732 168.349 89.671 166.018 88.7 C162.628 87.127 160.12 85.736 157.438 83.125 C155.741 78.082 155.893 73.244 156.047 68.004 C156.047 66.534 156.041 65.064 156.031 63.595 C156.018 59.745 156.076 55.899 156.15 52.049 C156.213 48.114 156.207 44.18 156.207 40.244 C156.217 32.536 156.303 24.832 156.438 17.125 C152.485 19.335 148.534 21.546 144.582 23.758 C143.476 24.376 142.37 24.995 141.231 25.632 C131.895 30.857 122.601 36.151 113.321 41.472 C107.737 44.673 102.15 47.868 96.562 51.062 C95.965 51.404 95.367 51.746 94.751 52.098 C86.826 56.629 78.889 61.14 70.938 65.625 C62.527 70.37 54.133 75.144 45.75 79.938 C45.166 80.271 44.581 80.605 43.979 80.95 C37.987 84.375 31.996 87.803 26.011 91.241 C14.366 97.93 2.707 104.594 -9.062 111.062 C-9.97 111.565 -10.878 112.067 -11.814 112.585 C-12.649 113.04 -13.484 113.496 -14.344 113.965 C-15.066 114.36 -15.789 114.756 -16.533 115.164 C-22.269 117.881 -28.602 117.949 -34.625 116.125 C-39.398 114.15 -42.881 110.491 -45.562 106.125 C-45.562 104.805 -45.562 103.485 -45.562 102.125 C-45.022 101.835 -44.481 101.545 -43.924 101.246 C-32.122 94.897 -20.456 88.363 -8.907 81.566 C-0.017 76.35 8.975 71.333 18.003 66.362 C24.427 62.82 30.777 59.186 37.065 55.408 C39.438 54.125 39.438 54.125 41.438 54.125 C41.438 53.465 41.438 52.805 41.438 52.125 C40.704 51.843 39.971 51.561 39.216 51.271 C36.702 50.234 34.368 49.093 31.98 47.797 C30.7 47.102 30.7 47.102 29.395 46.394 C28.481 45.892 27.567 45.391 26.625 44.875 C25.666 44.351 24.707 43.826 23.719 43.286 C14.477 38.202 5.37 32.897 -3.719 27.547 C-8.103 24.968 -12.509 22.431 -16.928 19.911 C-17.89 19.362 -17.89 19.362 -18.871 18.802 C-20.435 17.909 -21.999 17.017 -23.562 16.125 C-23.525 16.942 -23.487 17.759 -23.448 18.601 C-23.106 26.338 -22.848 34.071 -22.682 41.814 C-22.593 45.794 -22.474 49.768 -22.28 53.745 C-21.06 79.461 -21.06 79.461 -25.205 85.53 C-29.148 89.11 -33.517 90.996 -38.581 92.49 C-41.159 93.316 -43.282 94.688 -45.562 96.125 C-46.222 96.125 -46.882 96.125 -47.562 96.125 C-47.655 84.546 -47.726 72.967 -47.77 61.388 C-47.791 56.01 -47.819 50.633 -47.864 45.256 C-47.908 40.062 -47.932 34.869 -47.942 29.675 C-47.949 27.698 -47.964 25.721 -47.985 23.744 C-48.015 20.965 -48.018 18.187 -48.017 15.408 C-48.031 14.599 -48.045 13.79 -48.06 12.956 C-48.013 6.348 -46.391 0.196 -41.823 -4.764 C-27.895 -17.466 -13.817 -7.747 0 0 Z' fill='%23264FAF' transform='translate(47.5625,10.875)'/%3E%3Cpath d='M0 0 C2.051 0.961 2.051 0.961 4.098 2.16 C5.278 2.843 5.278 2.843 6.481 3.541 C7.333 4.043 8.185 4.545 9.062 5.062 C10.954 6.16 12.846 7.258 14.738 8.355 C16.255 9.24 16.255 9.24 17.803 10.142 C22.848 13.074 27.913 15.969 32.979 18.863 C34.753 19.877 36.525 20.892 38.297 21.907 C44.243 25.311 50.205 28.681 56.203 31.992 C57.347 32.625 58.491 33.258 59.669 33.911 C61.837 35.108 64.008 36.299 66.183 37.484 C67.154 38.02 68.125 38.557 69.125 39.109 C69.973 39.573 70.821 40.037 71.695 40.515 C74.149 42.096 76.015 43.87 78 46 C74.984 51.808 72.395 55.457 66.25 58.25 C54.159 61.04 44.857 55.778 34.625 49.75 C32.781 48.681 30.938 47.612 29.094 46.543 C28.114 45.972 27.134 45.402 26.125 44.814 C21.068 41.878 15.989 38.98 10.91 36.082 C9.13 35.065 7.35 34.048 5.57 33.03 C-5.598 26.648 -16.794 20.315 -28 14 C-28 13.34 -28 12.68 -28 12 C-24.284 9.789 -20.551 7.61 -16.812 5.438 C-15.757 4.809 -14.702 4.181 -13.615 3.533 C-12.083 2.649 -12.083 2.649 -10.52 1.746 C-9.582 1.196 -8.645 0.646 -7.679 0.08 C-4.518 -1.194 -3.196 -1.069 0 0 Z' fill='%23264FAF' transform='translate(150,69)'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n flex-shrink: 0;\n}\n\n.shell-container {\n display: flex;\n flex-direction: column;\n height: 100vh;\n width: 100%;\n overflow: hidden;\n}\n\n/* Hide shell container while loading - allows tab container to render and load\n first resource in background while shell loading indicator is visible */\n.shell-container.hidden {\n visibility: hidden;\n position: absolute;\n pointer-events: none;\n}\n\nmj-tab-container {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n transition: all 0.2s ease-in-out;\n}\n\n/* Hide Golden Layout tab headers when only one tab */\nmj-tab-container.hide-tab-bar ::ng-deep .lm_header {\n display: none;\n}\n\n/* Show tab headers when multiple tabs */\nmj-tab-container:not(.hide-tab-bar) ::ng-deep .lm_header {\n opacity: 1;\n max-height: 40px;\n transition: opacity 0.2s ease-in-out, max-height 0.2s ease-in-out;\n}\n\n/* Adjust content area height when tabs hidden */\nmj-tab-container.hide-tab-bar ::ng-deep .lm_content {\n height: 100% !important;\n}\n\n/* Ensure smooth transitions */\nmj-tab-container ::ng-deep .lm_stack {\n transition: all 0.2s ease-in-out;\n}\n\n.shell-header {\n height: 60px;\n background: white;\n border-bottom: 1px solid #e0e0e0;\n display: flex;\n align-items: center;\n padding: 0 16px;\n gap: 16px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n flex-shrink: 0;\n}\n\n/* Nav Bar Apps - permanent app icons in the header */\n.nav-bar-apps {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.nav-bar-apps.left-of-switcher {\n /* No extra margin - header gap handles spacing */\n /* This prevents the app switcher from shifting when icons are hidden */\n}\n\n.nav-bar-apps.left-of-user-menu {\n margin-right: 8px;\n}\n\n.nav-bar-app-btn {\n --app-color: #757575;\n width: 40px;\n height: 40px;\n border-radius: 10px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #616161;\n font-size: 18px;\n transition: all 0.15s ease;\n position: relative;\n}\n\n.nav-bar-app-btn:hover {\n background: color-mix(in srgb, var(--app-color) 15%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active {\n background: color-mix(in srgb, var(--app-color) 20%, transparent);\n color: var(--app-color);\n}\n\n.nav-bar-app-btn.active::after {\n content: '';\n position: absolute;\n bottom: 6px;\n left: 50%;\n transform: translateX(-50%);\n width: 16px;\n height: 3px;\n background: var(--app-color);\n border-radius: 2px;\n}\n\n.nav-bar-app-btn i {\n transition: transform 0.15s ease;\n margin-top: 2px; /* Align with app switcher icon */\n}\n\n.nav-bar-app-btn:hover i {\n transform: scale(1.1);\n}\n\n.spacer {\n flex: 1;\n}\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.icon-btn {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #757575;\n font-size: 18px;\n transition: background 0.15s;\n}\n\n.icon-btn:hover {\n background: #f5f5f5;\n}\n\n/* Notification button with badge */\n.notification-btn {\n position: relative;\n}\n\n.notification-badge {\n position: absolute;\n top: 4px;\n right: 4px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: #e53935;\n color: white;\n font-size: 10px;\n font-weight: 600;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n.user-menu {\n position: relative;\n}\n\n.user-menu .avatar-btn {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: box-shadow 0.15s, transform 0.15s;\n padding: 0;\n overflow: hidden;\n}\n\n.user-menu .avatar-btn:hover {\n transform: scale(1.05);\n}\n\n/* Icon fallback styling - shows gray circle with icon */\n.user-menu .avatar-btn .icon-fallback {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 2px solid #e0e0e0;\n background: #f5f5f5;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: border-color 0.15s;\n}\n\n.user-menu .avatar-btn:hover .icon-fallback {\n border-color: #1976d2;\n}\n\n.user-menu .avatar-btn .icon-fallback i {\n color: #757575;\n font-size: 16px;\n}\n\n/* Avatar image - replaces the gray circle entirely */\n.user-menu .avatar-btn .avatar-img {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: cover;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);\n}\n\n.user-menu .avatar-btn:hover .avatar-img {\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);\n}\n\n/* User Menu Header */\n.user-menu-header {\n padding: 12px 16px;\n background: #fafafa;\n}\n\n.user-menu-header .user-name {\n font-weight: 600;\n font-size: 14px;\n color: #424242;\n}\n\n/* User Context Menu */\n.user-context-menu {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 8px;\n background: white;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);\n min-width: 180px;\n z-index: 10000;\n overflow: hidden;\n}\n\n.user-menu-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n cursor: pointer;\n font-size: 14px;\n color: #424242;\n transition: background 0.15s;\n}\n\n.user-menu-item i {\n width: 18px;\n text-align: center;\n color: #757575;\n font-size: 14px;\n}\n\n.user-menu-item:hover {\n background: #f5f5f5;\n}\n\n.user-menu-item.danger {\n color: #c62828;\n}\n\n.user-menu-item.danger i {\n color: #c62828;\n}\n\n.user-menu-item.danger:hover {\n background: #ffebee;\n}\n\n.user-menu-divider {\n height: 1px;\n background: #e0e0e0;\n margin: 4px 0;\n}\n\n.shell-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100vh;\n background: #fafafa;\n}\n\n/* Hamburger button - hidden on desktop */\n.hamburger-btn {\n display: none;\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: none;\n cursor: pointer;\n align-items: center;\n justify-content: center;\n color: #616161;\n font-size: 20px;\n transition: background 0.15s;\n}\n.hamburger-btn:hover {\n background: #f5f5f5;\n}\n\n/* Mobile Navigation Overlay */\n.mobile-nav-overlay {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 9998;\n}\n\n/* Mobile Navigation Drawer */\n.mobile-nav-drawer {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n width: 280px;\n max-width: 85vw;\n background: white;\n box-shadow: 2px 0 12px rgba(0, 0, 0, 0.15);\n z-index: 9999;\n flex-direction: column;\n transform: translateX(-100%);\n transition: transform 0.3s ease;\n}\n.mobile-nav-drawer.open {\n transform: translateX(0);\n}\n\n.mobile-nav-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid #e0e0e0;\n background: #fafafa;\n}\n.mobile-nav-header span {\n font-weight: 600;\n font-size: 16px;\n color: #424242;\n}\n.mobile-nav-header .close-btn {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #757575;\n font-size: 18px;\n transition: background 0.15s;\n}\n.mobile-nav-header .close-btn:hover {\n background: #e0e0e0;\n}\n\n.mobile-nav-content {\n flex: 1;\n overflow-y: auto;\n padding: 16px 0;\n}\n\n.mobile-nav-section-title {\n padding: 8px 20px;\n font-size: 12px;\n font-weight: 600;\n color: #9e9e9e;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.mobile-nav-footer {\n border-top: 1px solid #e0e0e0;\n padding: 12px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.mobile-nav-action {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n border: none;\n background: none;\n cursor: pointer;\n border-radius: 8px;\n color: #616161;\n font-size: 14px;\n font-weight: 500;\n transition: background 0.15s;\n width: 100%;\n text-align: left;\n}\n.mobile-nav-action:hover {\n background: #f5f5f5;\n}\n.mobile-nav-action i {\n font-size: 16px;\n width: 20px;\n text-align: center;\n}\n\n/* Mobile Responsive Styles */\n@media (max-width: 768px) {\n .hamburger-btn {\n display: flex;\n }\n\n .desktop-nav {\n display: none !important;\n }\n\n .desktop-only {\n display: none !important;\n }\n\n .mobile-nav-overlay {\n display: block;\n }\n\n .mobile-nav-drawer {\n display: flex;\n }\n\n .shell-header {\n padding: 0 12px;\n gap: 8px;\n }\n}\n\n/* Settings Full-Screen Window Styles */\n::ng-deep .settings-fullscreen-window {\n /* Remove window chrome for full-screen feel */\n box-shadow: none !important;\n border: none !important;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar {\n background: #ffffff;\n border-bottom: 1px solid #e0e0e0;\n padding: 12px 16px;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-title {\n font-size: 18px;\n font-weight: 600;\n color: #212121;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-actions {\n gap: 4px;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action:hover {\n background: #f5f5f5;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-content {\n padding: 0;\n overflow: auto;\n background: #fafafa;\n}\n\n/* Hide minimize/maximize buttons - only show close */\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action[title=\"Minimize\"],\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action[title=\"Maximize\"],\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window-minimize,\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window-maximize,\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window {\n display: none !important;\n}\n\n/* ========================================\n SEARCH POPUP\n ======================================== */\n\n.search-popup-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 9999;\n animation: fadeIn 0.15s ease;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.search-popup {\n position: fixed;\n top: 60px; /* Below header */\n right: 16px;\n width: 480px;\n max-width: calc(100vw - 32px);\n background: white;\n border-radius: 12px;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);\n z-index: 10000;\n opacity: 0;\n transform: translateY(-10px);\n pointer-events: none;\n transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.search-popup.open {\n opacity: 1;\n transform: translateY(0);\n pointer-events: all;\n}\n\n.search-popup-content {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n}\n\n.search-entity-dropdown {\n min-width: 140px;\n max-width: 180px;\n flex-shrink: 0;\n}\n\n.search-input {\n flex: 1;\n min-width: 0;\n height: 40px;\n padding: 8px 12px;\n font-size: 14px;\n border: 1px solid #d4d4d4;\n border-radius: 4px;\n outline: none;\n display: block !important;\n box-sizing: border-box;\n}\n\n.search-input:focus {\n border-color: #1976d2;\n box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.1);\n}\n\n.search-submit-btn {\n width: 40px;\n height: 40px;\n border-radius: 8px;\n border: none;\n background: #1976d2;\n color: white;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n transition: background 0.15s;\n flex-shrink: 0;\n}\n\n.search-submit-btn:hover {\n background: #1565c0;\n}\n\n.search-submit-btn:active {\n background: #0d47a1;\n}\n\n/* Mobile notification badge */\n.notification-badge-mobile {\n position: absolute;\n top: 8px;\n right: 8px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: #e53935;\n color: white;\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n/* Mobile-specific search popup adjustments */\n@media (max-width: 768px) {\n .search-popup {\n top: 60px;\n left: 16px;\n right: 16px;\n width: auto;\n max-width: none;\n }\n\n .search-popup-content {\n flex-wrap: wrap;\n }\n\n .search-entity-dropdown {\n width: 100%;\n }\n\n .search-input {\n flex: 1;\n min-width: 0;\n }\n}"] }]
1335
1850
  }], () => [{ type: i1.ApplicationManager }, { type: i1.WorkspaceStateManager }, { type: i1.GoldenLayoutManager }, { type: i1.TabService }, { type: i2.NavigationService }, { type: i3.ActivatedRoute }, { type: i3.Router }, { type: i4.MJAuthBase }, { type: i0.ChangeDetectorRef }, { type: i5.UserAvatarService }, { type: i6.SettingsDialogService }, { type: i0.ViewContainerRef }, { type: i2.TitleService }], { searchInput: [{
1336
1851
  type: ViewChild,
1337
1852
  args: ['searchInput']
1853
+ }], appAccessDialog: [{
1854
+ type: ViewChild,
1855
+ args: ['appAccessDialog']
1338
1856
  }] }); })();
1339
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ShellComponent, { className: "ShellComponent", filePath: "src/lib/shell/shell.component.ts", lineNumber: 36 }); })();
1857
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ShellComponent, { className: "ShellComponent", filePath: "src/lib/shell/shell.component.ts", lineNumber: 40 }); })();
1340
1858
  //# sourceMappingURL=shell.component.js.map