newportsite 1.1.3

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 (131) hide show
  1. package/newportsite-1.1.3.tgz +0 -0
  2. package/ng-package.json +7 -0
  3. package/obfuscate.js +70 -0
  4. package/package.json +15 -0
  5. package/src/lib/app.component.ts +47 -0
  6. package/src/lib/app.routing.ts +38 -0
  7. package/src/lib/auth/alert.component.html +5 -0
  8. package/src/lib/auth/alert.component.ts +24 -0
  9. package/src/lib/auth/auth.component.html +1 -0
  10. package/src/lib/auth/auth.component.ts +10 -0
  11. package/src/lib/auth/auth.routes.ts +16 -0
  12. package/src/lib/auth/index.ts +4 -0
  13. package/src/lib/auth/login.component.html +87 -0
  14. package/src/lib/auth/login.component.ts +158 -0
  15. package/src/lib/auth/models/index.ts +1 -0
  16. package/src/lib/auth/models/user.ts +25 -0
  17. package/src/lib/auth/register.component.html +157 -0
  18. package/src/lib/auth/register.component.ts +219 -0
  19. package/src/lib/auth/services/alert.service.ts +47 -0
  20. package/src/lib/auth/services/auth.service.ts +28 -0
  21. package/src/lib/auth/services/index.ts +3 -0
  22. package/src/lib/auth/services/user.service.spec.ts +112 -0
  23. package/src/lib/auth/services/user.service.ts +47 -0
  24. package/src/lib/common/card.component.html +72 -0
  25. package/src/lib/common/card.component.ts +102 -0
  26. package/src/lib/common/commands.component.html +8 -0
  27. package/src/lib/common/commands.component.ts +42 -0
  28. package/src/lib/common/context.component.html +9 -0
  29. package/src/lib/common/context.component.ts +38 -0
  30. package/src/lib/common/grid.component.html +20 -0
  31. package/src/lib/common/grid.component.ts +747 -0
  32. package/src/lib/common/index.ts +9 -0
  33. package/src/lib/common/loader.component.html +5 -0
  34. package/src/lib/common/loader.component.ts +27 -0
  35. package/src/lib/common/lookup.component.html +29 -0
  36. package/src/lib/common/lookup.component.ts +115 -0
  37. package/src/lib/common/messagebox.component.html +39 -0
  38. package/src/lib/common/messagebox.component.ts +74 -0
  39. package/src/lib/common/theme-toggle.component.ts +139 -0
  40. package/src/lib/config.ts +62 -0
  41. package/src/lib/containers/default-layout/default-layout.component.html +191 -0
  42. package/src/lib/containers/default-layout/default-layout.component.ts +158 -0
  43. package/src/lib/containers/default-layout/index.ts +1 -0
  44. package/src/lib/containers/index.ts +1 -0
  45. package/src/lib/directives/component.draggable.ts +80 -0
  46. package/src/lib/directives/index.ts +2 -0
  47. package/src/lib/directives/input.directive.spec.ts +158 -0
  48. package/src/lib/directives/input.directive.ts +210 -0
  49. package/src/lib/home/dashboard/dashboard.component.html +38 -0
  50. package/src/lib/home/dashboard/dashboard.component.ts +50 -0
  51. package/src/lib/home/dashboard/index.ts +1 -0
  52. package/src/lib/home/index.component.html +1 -0
  53. package/src/lib/home/index.component.ts +10 -0
  54. package/src/lib/home/index.routes.ts +29 -0
  55. package/src/lib/home/index.ts +1 -0
  56. package/src/lib/home/info/index.ts +1 -0
  57. package/src/lib/home/info/info.component.css +476 -0
  58. package/src/lib/home/info/info.component.html +174 -0
  59. package/src/lib/home/info/info.component.ts +287 -0
  60. package/src/lib/home/model/article.component.html +10 -0
  61. package/src/lib/home/model/article.component.ts +50 -0
  62. package/src/lib/home/model/barchart.component.html +8 -0
  63. package/src/lib/home/model/barchart.component.ts +59 -0
  64. package/src/lib/home/model/index.ts +7 -0
  65. package/src/lib/home/model/itemdetail.component.html +25 -0
  66. package/src/lib/home/model/itemdetail.component.ts +93 -0
  67. package/src/lib/home/model/itemtab.component.html +25 -0
  68. package/src/lib/home/model/itemtab.component.ts +105 -0
  69. package/src/lib/home/model/model.component.html +121 -0
  70. package/src/lib/home/model/model.component.ts +510 -0
  71. package/src/lib/home/model/modeltoolbar.component.html +111 -0
  72. package/src/lib/home/model/modeltoolbar.component.ts +157 -0
  73. package/src/lib/home/model/navigation.component.html +86 -0
  74. package/src/lib/home/model/navigation.component.ts +247 -0
  75. package/src/lib/home/model/services/index.ts +1 -0
  76. package/src/lib/home/model/services/model.service.spec.ts +423 -0
  77. package/src/lib/home/model/services/model.service.ts +319 -0
  78. package/src/lib/home/modelsearch/index.ts +1 -0
  79. package/src/lib/home/modelsearch/modelsearch.component.html +124 -0
  80. package/src/lib/home/modelsearch/modelsearch.component.ts +453 -0
  81. package/src/lib/interfaces/data.interface.ts +131 -0
  82. package/src/lib/interfaces/index.ts +2 -0
  83. package/src/lib/interfaces/item.interface.ts +438 -0
  84. package/src/lib/players/lookup/lookup.directive.ts +6 -0
  85. package/src/lib/players/lookup/lookup.item.component.ts +37 -0
  86. package/src/lib/players/lookup/lookup.item.ts +9 -0
  87. package/src/lib/players/lookup/lookup.player.component.ts +59 -0
  88. package/src/lib/players/lookup/lookup.selector.component.ts +41 -0
  89. package/src/lib/players/model/model.directive.ts +6 -0
  90. package/src/lib/players/model/model.item.component.spec.ts +311 -0
  91. package/src/lib/players/model/model.item.component.ts +3457 -0
  92. package/src/lib/players/model/model.item.ts +9 -0
  93. package/src/lib/players/model/model.player.component.ts +109 -0
  94. package/src/lib/players/model/model.selector.component.ts +59 -0
  95. package/src/lib/scheduler/scheduler.component.html +13 -0
  96. package/src/lib/scheduler/scheduler.component.scss +6 -0
  97. package/src/lib/scheduler/scheduler.component.ts +296 -0
  98. package/src/lib/scheduler/scheduler.routes.ts +15 -0
  99. package/src/lib/scheduler/schedulerdialog.component.html +72 -0
  100. package/src/lib/scheduler/schedulerdialog.component.ts +208 -0
  101. package/src/lib/scheduler/services/scheduler.service.ts +133 -0
  102. package/src/lib/services/auth-state.service.ts +129 -0
  103. package/src/lib/services/auth.interceptor.spec.ts +144 -0
  104. package/src/lib/services/auth.interceptor.ts +44 -0
  105. package/src/lib/services/cache.service.spec.ts +143 -0
  106. package/src/lib/services/cache.service.ts +71 -0
  107. package/src/lib/services/global-error-handler.spec.ts +39 -0
  108. package/src/lib/services/global-error-handler.ts +28 -0
  109. package/src/lib/services/global.service.spec.ts +801 -0
  110. package/src/lib/services/global.service.ts +724 -0
  111. package/src/lib/services/message.service.ts +556 -0
  112. package/src/lib/services/theme.service.ts +96 -0
  113. package/src/lib/template/authtemplate.component.html +6 -0
  114. package/src/lib/template/authtemplate.component.ts +13 -0
  115. package/src/lib/template/basetemplate.component.html +7 -0
  116. package/src/lib/template/basetemplate.component.ts +13 -0
  117. package/src/lib/template/index.ts +3 -0
  118. package/src/lib/template/modeltemplate.component.html +7 -0
  119. package/src/lib/template/modeltemplate.component.ts +21 -0
  120. package/src/lib/utils/piva.spec.ts +56 -0
  121. package/src/lib/utils/piva.ts +29 -0
  122. package/src/lib/validators/email.validator.spec.ts +57 -0
  123. package/src/lib/validators/email.validator.ts +17 -0
  124. package/src/lib/validators/equalPasswords.validator.spec.ts +54 -0
  125. package/src/lib/validators/equalPasswords.validator.ts +17 -0
  126. package/src/lib/validators/index.ts +2 -0
  127. package/src/lib/version.ts +1 -0
  128. package/src/public-api.ts +64 -0
  129. package/src/typings.d.ts +2 -0
  130. package/tsconfig.lib.json +18 -0
  131. package/tsconfig.lib.prod.json +9 -0
@@ -0,0 +1,111 @@
1
+ <!-- modeltoolbar.component -->
2
+ <div class="mtb-bar-m2" [class.pe-none]="gsv?.getLoading()">
3
+ <div class="mtb-group">
4
+ <a class="mtb-btn" (click)="click('exit')">
5
+ <i
6
+ [class.icon-disabled]="exitState || gsv?.getLoading()"
7
+ [class.icon-exit]="!exitState && !gsv?.getLoading()"
8
+ class="bi bi-box-arrow-left"
9
+ title="{{ msg?.get('app.exit') }}"></i>
10
+ </a>
11
+ </div>
12
+
13
+ <div class="mtb-divider"></div>
14
+
15
+ <div class="mtb-group">
16
+ <a class="mtb-btn" (click)="click('plus')">
17
+ <i
18
+ [class.icon-disabled]="plusState || gsv?.getLoading()"
19
+ class="bi bi-plus-circle"
20
+ title="{{ msg?.get('app.plus') }}"></i>
21
+ </a>
22
+ <a class="mtb-btn" (click)="click('minus')">
23
+ <i
24
+ [class.icon-disabled]="minusState || gsv?.getLoading()"
25
+ class="bi bi-patch-minus"
26
+ title="{{ msg?.get('app.minus') }}"></i>
27
+ </a>
28
+ </div>
29
+
30
+ <div class="mtb-divider"></div>
31
+
32
+ <div class="mtb-group">
33
+ <a class="mtb-btn" (click)="click('detail')">
34
+ <i
35
+ [class.icon-disabled]="detailState || gsv?.getLoading()"
36
+ class="bi bi-card-text"
37
+ title="{{ msg?.get('app.detail') }}"></i>
38
+ </a>
39
+ <a class="mtb-btn" (click)="click('intodetail')">
40
+ <i
41
+ [class.icon-disabled]="intodetailState || gsv?.getLoading()"
42
+ class="bi bi-box-arrow-up-left"
43
+ title="{{ msg?.get('app.intodetail') }}"></i>
44
+ </a>
45
+ <a class="mtb-btn" (click)="click('table')">
46
+ <i
47
+ [class.icon-disabled]="tableState || gsv?.getLoading()"
48
+ class="bi bi-list"
49
+ title="{{ msg?.get('app.table') }}"></i>
50
+ </a>
51
+ <a class="mtb-btn" (click)="click('print')">
52
+ <i
53
+ [class.icon-disabled]="printState || gsv?.getLoading()"
54
+ class="bi bi-printer"
55
+ title="{{ msg?.get('app.print') }}"></i>
56
+ </a>
57
+ </div>
58
+
59
+ <div class="mtb-divider"></div>
60
+
61
+ <div class="mtb-group">
62
+ <a class="mtb-btn" [class.pe-none]="saveState" (click)="click('save')">
63
+ <i
64
+ [class.icon-disabled]="saveState"
65
+ class="bi bi-save"
66
+ title="{{ msg?.get('app.save') }}"></i>
67
+ </a>
68
+ <a class="mtb-btn d-none d-lg-flex" (click)="click('upload')">
69
+ <i
70
+ [class.icon-disabled]="uploadState || gsv?.getLoading()"
71
+ class="bi bi-upload"
72
+ title="{{ msg?.get('app.upload') }}"></i>
73
+ </a>
74
+ <a class="mtb-btn d-none d-lg-flex" (click)="click('download')">
75
+ <i
76
+ [class.icon-disabled]="downloadState || gsv?.getLoading()"
77
+ class="bi bi-download"
78
+ title="{{ msg?.get('app.download') }}"></i>
79
+ </a>
80
+ </div>
81
+
82
+ <div class="mtb-spacer"></div>
83
+
84
+ <div class="mtb-group">
85
+ <a class="mtb-btn d-none d-lg-flex" (click)="click('first')">
86
+ <i
87
+ [class.icon-disabled]="firstState || gsv?.getLoading()"
88
+ class="bi bi-chevron-double-left"
89
+ title="{{ msg?.get('app.first') }}"></i>
90
+ </a>
91
+ <a class="mtb-btn" (click)="click('previous')">
92
+ <i
93
+ [class.icon-disabled]="previousState || gsv?.getLoading()"
94
+ class="bi bi-chevron-left"
95
+ title="{{ msg?.get('app.previous') }}"></i>
96
+ </a>
97
+ <a class="mtb-btn" (click)="click('next')">
98
+ <i
99
+ [class.icon-disabled]="nextState || gsv?.getLoading()"
100
+ class="bi bi-chevron-right"
101
+ title="{{ msg?.get('app.next') }}"></i>
102
+ </a>
103
+ <a class="mtb-btn d-none d-lg-flex" (click)="click('last')">
104
+ <i
105
+ [class.icon-disabled]="lastState || gsv?.getLoading()"
106
+ class="bi bi-chevron-double-right"
107
+ title="{{ msg?.get('app.last') }}"></i>
108
+ </a>
109
+ </div>
110
+ </div>
111
+ <!-- fine modeltoolbar.component -->
@@ -0,0 +1,157 @@
1
+ import {
2
+ Component,
3
+ ChangeDetectionStrategy,
4
+ ChangeDetectorRef,
5
+ DestroyRef,
6
+ OnInit,
7
+ effect,
8
+ input,
9
+ output,
10
+ inject,
11
+ } from '@angular/core';
12
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
13
+
14
+ import { GlobalService } from '../../services/global.service';
15
+ import { AppMessageService } from '../../services/message.service';
16
+
17
+ import {
18
+ ItemCommandInterface,
19
+ ViewListInterface,
20
+ } from '../../interfaces/index';
21
+
22
+ @Component({
23
+ selector: 'modeltoolbar',
24
+ templateUrl: 'modeltoolbar.component.html',
25
+ changeDetection: ChangeDetectionStrategy.OnPush,
26
+ imports: [],
27
+ })
28
+ export class ModelToolbarComponent implements OnInit {
29
+ gsv = inject(GlobalService);
30
+ msg = inject(AppMessageService);
31
+ private destroyRef = inject(DestroyRef);
32
+ private cdr = inject(ChangeDetectorRef);
33
+
34
+ readonly commands = input<ItemCommandInterface[]>([]);
35
+ readonly disabled = input<boolean>();
36
+ readonly commandRaised = output<string>();
37
+ readonly viewChanged = output<ViewListInterface>();
38
+
39
+ private static readonly CMD_IDS = [
40
+ 'exit',
41
+ 'plus',
42
+ 'minus',
43
+ 'first',
44
+ 'previous',
45
+ 'next',
46
+ 'last',
47
+ 'upload',
48
+ 'download',
49
+ 'detail',
50
+ 'intodetail',
51
+ 'print',
52
+ 'table',
53
+ 'save',
54
+ 'insertmode',
55
+ ] as const;
56
+
57
+ /** All command states keyed by id — true = disabled. */
58
+ public state: Record<string, boolean> = {};
59
+ public hidenavigation = true;
60
+
61
+ // Template-compatible aliases (kept as getters so existing HTML bindings still work)
62
+ get exitState() {
63
+ return this.state['exit'];
64
+ }
65
+ get plusState() {
66
+ return this.state['plus'];
67
+ }
68
+ get minusState() {
69
+ return this.state['minus'];
70
+ }
71
+ get firstState() {
72
+ return this.state['first'];
73
+ }
74
+ get previousState() {
75
+ return this.state['previous'];
76
+ }
77
+ get nextState() {
78
+ return this.state['next'];
79
+ }
80
+ get lastState() {
81
+ return this.state['last'];
82
+ }
83
+ get uploadState() {
84
+ return this.state['upload'];
85
+ }
86
+ get downloadState() {
87
+ return this.state['download'];
88
+ }
89
+ get detailState() {
90
+ return this.state['detail'];
91
+ }
92
+ get intodetailState() {
93
+ return this.state['intodetail'];
94
+ }
95
+ get printState() {
96
+ return this.state['print'];
97
+ }
98
+ get tableState() {
99
+ return this.state['table'];
100
+ }
101
+ get saveState() {
102
+ return this.state['save'];
103
+ }
104
+ get insertModeState() {
105
+ return this.state['insertmode'];
106
+ }
107
+
108
+ constructor() {
109
+ this.resetCommand();
110
+ effect(() => {
111
+ if (this.disabled()) this.resetCommand();
112
+ });
113
+ }
114
+
115
+ /** Lifecycle: subscribes to the GlobalService command stream and applies state updates. */
116
+ public ngOnInit() {
117
+ this.gsv
118
+ .getItemCommands()
119
+ .pipe(takeUntilDestroyed(this.destroyRef))
120
+ .subscribe(commands => {
121
+ this.setState(commands);
122
+ });
123
+ }
124
+
125
+ /** Handles a toolbar button click: emits viewChanged for 'table', otherwise raises the command by id. */
126
+ public click(id: string) {
127
+ if (this.state[id]) return; // state true = disabled → skip
128
+ if (id === 'table') {
129
+ this.viewChanged.emit({ state: true });
130
+ this.resetCommand();
131
+ } else {
132
+ this.commandRaised.emit(id);
133
+ }
134
+ }
135
+
136
+ /** Sets all command states to disabled (true). */
137
+ private resetCommand() {
138
+ for (const id of ModelToolbarComponent.CMD_IDS) {
139
+ this.state[id] = true;
140
+ }
141
+ }
142
+
143
+ /** Applies incoming command states and recomputes the navigation-row visibility flag. */
144
+ private setState(commands: ItemCommandInterface[]) {
145
+ for (const cmd of commands) {
146
+ if (cmd.id in this.state) {
147
+ this.state[cmd.id] = cmd.state;
148
+ }
149
+ }
150
+ this.hidenavigation =
151
+ this.state['first'] &&
152
+ this.state['previous'] &&
153
+ this.state['next'] &&
154
+ this.state['last'];
155
+ this.cdr.markForCheck();
156
+ }
157
+ }
@@ -0,0 +1,86 @@
1
+ <!-- navigation.component -->
2
+ @if (!hide) {
3
+ <div
4
+ class="nav-panel h-100"
5
+ [class.nav-panel-compact]="collapsed()"
6
+ [class.pe-none]="gsv?.getLoading()">
7
+ <!-- HEADER: always visible -->
8
+ <div class="nav-header">
9
+ <div class="nav-header-top">
10
+ @if (!collapsed()) {
11
+ <span
12
+ class="nav-title truncate"
13
+ title="{{ msg?.getProjectDescription('description') }}">
14
+ {{ msg?.getProjectDescription('description') }}
15
+ </span>
16
+ }
17
+ <button
18
+ class="nav-toggle-btn"
19
+ (click)="toggleCollapse()"
20
+ [title]="
21
+ collapsed() ? msg?.get('app.expand') : msg?.get('app.collapse')
22
+ ">
23
+ <i
24
+ class="bi"
25
+ [class.bi-chevron-double-right]="collapsed()"
26
+ [class.bi-chevron-double-left]="!collapsed()"></i>
27
+ </button>
28
+ </div>
29
+ @if (!collapsed()) {
30
+ <div class="nav-filter-wrap">
31
+ <i class="bi bi-search nav-filter-icon"></i>
32
+ <input
33
+ id="filter"
34
+ #txt1
35
+ [title]="msg?.get('app.filter')"
36
+ type="text"
37
+ class="nav-filter-input"
38
+ [placeholder]="msg?.get('app.filter')"
39
+ (input)="filter(txt1.value)" />
40
+ </div>
41
+ }
42
+ </div>
43
+
44
+ <!-- ITEMS -->
45
+ <div class="navigation">
46
+ @if (collapsed()) {
47
+ @for (item of items; track item) {
48
+ <div
49
+ class="nav-entry nav-entry-compact"
50
+ [class.nav-active]="active === item">
51
+ <a
52
+ [title]="msg?.getItemInfo(item, 'title')"
53
+ (click)="click(item)"
54
+ [hidden]="!item.visible"
55
+ [class.disabled]="!item.enabled">
56
+ <span
57
+ class="nav-state-dot"
58
+ [ngClass]="getDesktopStateClass(item)"></span>
59
+ <span class="nav-item-id">{{ item.id }}</span>
60
+ </a>
61
+ </div>
62
+ }
63
+ } @else {
64
+ @for (item of items; track item) {
65
+ <div class="nav-entry" [class.nav-active]="active === item">
66
+ <a
67
+ [title]="msg?.getItemInfo(item, 'title')"
68
+ (click)="click(item)"
69
+ [hidden]="!item.visible"
70
+ [class.disabled]="!item.enabled">
71
+ <span
72
+ class="nav-state-dot"
73
+ [ngClass]="getDesktopStateClass(item)"></span>
74
+ <span
75
+ class="nav-item-text truncate"
76
+ [ngClass]="getItemTextClass(item)">
77
+ {{ msg?.getItemInfo(item, 'title') }}
78
+ </span>
79
+ </a>
80
+ </div>
81
+ }
82
+ }
83
+ </div>
84
+ </div>
85
+ }
86
+ <!-- fine navigation.component -->
@@ -0,0 +1,247 @@
1
+ import {
2
+ Component,
3
+ input,
4
+ output,
5
+ effect,
6
+ ChangeDetectionStrategy,
7
+ ChangeDetectorRef,
8
+ OnDestroy,
9
+ AfterViewInit,
10
+ DestroyRef,
11
+ inject,
12
+ } from '@angular/core';
13
+
14
+ import { GlobalService } from '../../services/global.service';
15
+
16
+ import { AppMessageService } from '../../services/message.service';
17
+
18
+ import {
19
+ ItemInterface,
20
+ ItemState,
21
+ ManagmentInterface,
22
+ ItemType,
23
+ } from '../../interfaces/index';
24
+ import { ManagmentService } from './services/index';
25
+ import { Subscription } from 'rxjs';
26
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
27
+ import { NgClass } from '@angular/common';
28
+
29
+ @Component({
30
+ selector: 'navigation',
31
+ templateUrl: 'navigation.component.html',
32
+ changeDetection: ChangeDetectionStrategy.OnPush,
33
+ imports: [NgClass],
34
+ })
35
+ export class NavigationComponent implements AfterViewInit, OnDestroy {
36
+ gsv = inject(GlobalService);
37
+ msg = inject(AppMessageService);
38
+ msv = inject(ManagmentService);
39
+ private destroyRef = inject(DestroyRef);
40
+ private cdr = inject(ChangeDetectorRef);
41
+
42
+ readonly modelChanged = output<ItemInterface>();
43
+ readonly hideNavigation = output<boolean>();
44
+ readonly collapsedChanged = output<boolean>();
45
+ readonly collapsed = input<boolean>(false);
46
+ public items!: ItemInterface[];
47
+ public itemState = ItemState;
48
+ public active: ItemInterface | null = null;
49
+ public projectId!: string;
50
+ public projectItems: ItemInterface[] | undefined;
51
+ public hide = false;
52
+ private managment: ManagmentInterface = {
53
+ functionId: '',
54
+ appId: '',
55
+ entId: '',
56
+ year: 0,
57
+ keys: '',
58
+ fields: [],
59
+ states: [],
60
+ entIds: [],
61
+ keyId: '1',
62
+ filterId: '',
63
+ page: 1,
64
+ data: '',
65
+ };
66
+ readonly model = input<ItemInterface>();
67
+ private subscriptionItemState!: Subscription;
68
+
69
+ constructor() {
70
+ // Re-render nav state dots whenever updateState() recalculates item states.
71
+ this.gsv
72
+ .getItemState()
73
+ .pipe(takeUntilDestroyed(this.destroyRef))
74
+ .subscribe(() => this.cdr.markForCheck());
75
+
76
+ effect(() => {
77
+ const m = this.model();
78
+ if (m && this.items?.length > 0) {
79
+ this.click(m);
80
+ }
81
+ });
82
+ }
83
+
84
+ /** Lifecycle: cleans up subscriptions and resets the active item state. */
85
+ public ngOnDestroy(): void {
86
+ this.subscriptionItemState?.unsubscribe();
87
+ this.items = [];
88
+ this.projectItems = [];
89
+ this.active = null;
90
+ }
91
+
92
+ /** Lifecycle: subscribes to projectChanged and loads the initial navigation item list. */
93
+ public ngAfterViewInit(): void {
94
+ this.gsv
95
+ .getProjectChanged()
96
+ .pipe(takeUntilDestroyed(this.destroyRef))
97
+ .subscribe(projectId => {
98
+ this.reinitializeForProject();
99
+ });
100
+
101
+ this.initializeProject();
102
+ }
103
+
104
+ /** Fetches project items from cache or API and calls setupProject to populate the list. */
105
+ private initializeProject(): void {
106
+ this.managment.appId = this.gsv.getProject().project;
107
+ this.managment.year = this.gsv.getYear();
108
+ this.managment.keyId = this.gsv.getKeyId();
109
+
110
+ this.projectId = this.managment.appId + '.' + this.managment.year;
111
+
112
+ this.projectItems = this.gsv.getProjectItems(this.projectId);
113
+
114
+ if (this.projectItems === undefined) {
115
+ this.subscriptionItemState = this.msv
116
+ .getItemsState(this.managment)
117
+ .subscribe({
118
+ next: (data: ItemInterface[]) => {
119
+ this.setupProject(data);
120
+ this.gsv.setProjectItems(this.projectId, data);
121
+ },
122
+ error: error => {
123
+ console.error('Error fetching project items:', error);
124
+ this.gsv.navigateToDefault();
125
+ },
126
+ });
127
+ } else {
128
+ this.setupProject(this.gsv.getProjectItems(this.projectId));
129
+ }
130
+ }
131
+
132
+ /** Clears state and re-runs initializeProject when the active project changes. */
133
+ private reinitializeForProject(): void {
134
+ if (this.subscriptionItemState) {
135
+ this.subscriptionItemState.unsubscribe();
136
+ }
137
+
138
+ this.items = [];
139
+ this.projectItems = undefined;
140
+ this.active = null;
141
+
142
+ this.initializeProject();
143
+ }
144
+
145
+ /**
146
+ * Filters the raw item array by project, resolves a `targetModel` from localStorage
147
+ * if present, selects the first/target item, and emits modelChanged.
148
+ */
149
+ public setupProject(data: ItemInterface[]): void {
150
+ if (data.length > 0) {
151
+ for (let i = 0; i < data.length; i++) {
152
+ data[i].ivisible = data[i].visible;
153
+ }
154
+ this.items = data.filter(
155
+ e =>
156
+ ((e.linkedItems ?? []).indexOf(e.name) === -1 ||
157
+ (e.linkedItems ?? []).indexOf(e.name) === 0) &&
158
+ e.enabled &&
159
+ e.visible &&
160
+ (e.groupName === '' || e.rootModel === true) &&
161
+ (e.type === ItemType.Multiple || e.type === ItemType.Single)
162
+ );
163
+ this.hide = this.items.length == 1;
164
+ this.hideNavigation.emit(this.hide);
165
+
166
+ const targetModel = localStorage.getItem('targetModel');
167
+ if (targetModel) {
168
+ const model = this.items.find(e => e.name === targetModel);
169
+ if (model) {
170
+ localStorage.removeItem('targetModel');
171
+ this.click(model);
172
+ } else {
173
+ localStorage.removeItem('targetModel');
174
+ this.click(this.items[0]);
175
+ }
176
+ } else {
177
+ this.click(this.items[0]);
178
+ }
179
+ }
180
+ }
181
+
182
+ /** Sets the active navigation item and emits the modelChanged event. */
183
+ public click(item: ItemInterface): void {
184
+ if (this.active !== item) {
185
+ this.active = item;
186
+ this.modelChanged.emit(item);
187
+ }
188
+ }
189
+
190
+ /** Shows/hides navigation items by matching the search string against title, name and groupName. */
191
+ public filter(value: string): void {
192
+ const needle = value.trim().toUpperCase();
193
+ this.items.forEach((model: ItemInterface) => {
194
+ if (
195
+ needle === '' ||
196
+ model.title.toUpperCase().includes(needle) ||
197
+ model.name.toUpperCase().includes(needle) ||
198
+ model.groupName.toUpperCase().includes(needle)
199
+ ) {
200
+ model.visible = model.ivisible;
201
+ } else {
202
+ model.visible = false;
203
+ }
204
+ });
205
+ }
206
+
207
+ /** Returns true if the given item is the currently selected navigation entry. */
208
+ isActiveItem(item: ItemInterface): boolean {
209
+ return this.active === item;
210
+ }
211
+
212
+ /** Returns the CSS class object for the navigation icon (highlights when item is active). */
213
+ getIconClass(item: ItemInterface) {
214
+ return { 'has-selected': this.active === item };
215
+ }
216
+
217
+ /** Returns the CSS class object for the desktop state indicator (error/warning/valid icons). */
218
+ getDesktopStateClass(item: ItemInterface) {
219
+ return {
220
+ active: this.active === item,
221
+ 'span-state': item.state === this.itemState.Valid,
222
+ 'span-state-rect':
223
+ item.state === this.itemState.Error ||
224
+ item.state === this.itemState.Warning,
225
+ 'dot-empty': item.state === this.itemState.Empty,
226
+ 'dot-success': item.state === this.itemState.Valid,
227
+ 'triangle-error': item.state === this.itemState.Error,
228
+ 'rectangle-warning': item.state === this.itemState.Warning,
229
+ 'font-weight-bold': this.active === item,
230
+ 'mx-1': item.state !== this.itemState.Error,
231
+ 'align-self-start': item.state !== this.itemState.Error,
232
+ };
233
+ }
234
+
235
+ /** Returns the CSS class object for the item label (bold when active). */
236
+ getItemTextClass(item: ItemInterface) {
237
+ return {
238
+ active: this.active === item,
239
+ 'font-weight-bold': this.active === item,
240
+ };
241
+ }
242
+
243
+ /** Emits the inverse of the current collapsed state to toggle the navigation panel. */
244
+ toggleCollapse(): void {
245
+ this.collapsedChanged.emit(!this.collapsed());
246
+ }
247
+ }
@@ -0,0 +1 @@
1
+ export * from './model.service';