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,319 @@
1
+ import { Injectable, inject } from '@angular/core';
2
+ import {
3
+ HttpClient,
4
+ HttpErrorResponse,
5
+ HttpEvent,
6
+ HttpRequest,
7
+ } from '@angular/common/http';
8
+ import { Observable, firstValueFrom, throwError } from 'rxjs';
9
+ import { GlobalService } from '../../../services/global.service';
10
+
11
+ import {
12
+ ItemInterface,
13
+ FieldInterface,
14
+ TransportInterface,
15
+ ManagmentInterface,
16
+ PaginationInterface,
17
+ GroupedDataArt,
18
+ } from '../../../interfaces/index';
19
+
20
+ import { catchError, retry, map } from 'rxjs/operators';
21
+
22
+ import * as pako from 'pako';
23
+
24
+ @Injectable()
25
+ export class ManagmentService {
26
+ private http = inject(HttpClient);
27
+ private globalService = inject(GlobalService);
28
+
29
+ private managmentsUrl: string =
30
+ this.globalService.restService() + 'managment';
31
+
32
+ private url(...segments: (string | number)[]): string {
33
+ return [this.managmentsUrl, ...segments].join('/');
34
+ }
35
+
36
+ /** Streams a GET request for a single record PDF/ZIP as a progress-tracked HttpEvent sequence. */
37
+ public downloadFile(
38
+ managment: ManagmentInterface,
39
+ fileType: string = 'pdf'
40
+ ): Observable<HttpEvent<Blob>> {
41
+ return this.http.request(
42
+ new HttpRequest(
43
+ 'GET',
44
+ this.url('GetData', managment.functionId, managment.appId, managment.year, managment.entId, managment.keys, managment.keyId),
45
+ null,
46
+ this.globalService.jwt(fileType)
47
+ )
48
+ );
49
+ }
50
+
51
+ /** Streams a GET request for a paginated batch of records as a ZIP progress-event sequence. */
52
+ public downloadFileAll(
53
+ managment: ManagmentInterface,
54
+ fileType: string = 'zip'
55
+ ): Observable<HttpEvent<Blob>> {
56
+ return this.http.request(
57
+ new HttpRequest(
58
+ 'GET',
59
+ this.url('GetItemsData', managment.appId, managment.year, managment.filterId, managment.page, managment.functionId, managment.entId),
60
+ null,
61
+ this.globalService.jwt(fileType)
62
+ )
63
+ );
64
+ }
65
+
66
+ /** Downloads a single record as a raw Blob PDF (no progress events). */
67
+ public downloadPDF(
68
+ managment: ManagmentInterface,
69
+ fileType: string = 'pdf'
70
+ ): Observable<Blob> {
71
+ return this.http
72
+ .get(
73
+ this.url('GetData', managment.functionId, managment.appId, managment.year, managment.entId, managment.keys, managment.keyId),
74
+ { ...this.globalService.jwt(fileType), responseType: 'blob' }
75
+ )
76
+ .pipe(retry(3), catchError(this.handleError));
77
+ }
78
+
79
+ /** Fetches grouped article data (GetGroupedDataArt) and resolves the full response. */
80
+ public async getGroupedDataArtPromise(
81
+ managment: ManagmentInterface
82
+ ): Promise<GroupedDataArt> {
83
+ return await firstValueFrom(
84
+ this.http
85
+ .get<GroupedDataArt>(
86
+ this.url('GetGroupedDataArt', managment.appId, managment.year, managment.codmag!, managment.codart!),
87
+ this.globalService.jwt()
88
+ )
89
+ .pipe(retry(3), catchError(this.handleError))
90
+ );
91
+ }
92
+
93
+ /** Returns an Observable of paginated search results (GetItemsData). */
94
+ public getItemsData(
95
+ managment: ManagmentInterface
96
+ ): Observable<PaginationInterface> {
97
+ return this.http
98
+ .get<PaginationInterface>(
99
+ this.url('GetItemsData', managment.appId, managment.year, managment.filterId, managment.page, managment.functionId, managment.entId),
100
+ this.globalService.jwt()
101
+ )
102
+ .pipe(retry(3), catchError(this.handleError));
103
+ }
104
+
105
+ /** Returns an Observable of all records across all pages (GetAllItemsData). */
106
+ public getAllItemsData(
107
+ managment: ManagmentInterface
108
+ ): Observable<PaginationInterface> {
109
+ return this.http
110
+ .get<PaginationInterface>(
111
+ this.url('GetAllItemsData', managment.appId, managment.year, managment.page),
112
+ this.globalService.jwt()
113
+ )
114
+ .pipe(retry(3), catchError(this.handleError));
115
+ }
116
+
117
+ /** Returns an Observable with the total record count for the given app/year pair. */
118
+ public getItemsCount(managment: ManagmentInterface): Observable<number> {
119
+ return this.http
120
+ .get<number>(
121
+ this.url('GetItemsCount', managment.appId, managment.year),
122
+ this.globalService.jwt()
123
+ )
124
+ .pipe(retry(3), catchError(this.handleError));
125
+ }
126
+
127
+ /** Sends a DELETE request for the record identified by appId/year/keyId. */
128
+ public deleteItem(managment: ManagmentInterface): Observable<boolean> {
129
+ return this.http
130
+ .delete<boolean>(
131
+ this.url('DeleteItem', managment.appId, managment.year, managment.keyId),
132
+ this.globalService.jwt()
133
+ )
134
+ .pipe(retry(3), catchError(this.handleError));
135
+ }
136
+
137
+ /** Returns entity state info (error/warning counts) for a given project record (Observable). */
138
+ public getItemsState(
139
+ managment: ManagmentInterface
140
+ ): Observable<ItemInterface[]> {
141
+ return this.http
142
+ .get<ItemInterface[]>(
143
+ this.url('GetItemsState', managment.appId, managment.year, managment.keyId),
144
+ this.globalService.jwt()
145
+ )
146
+ .pipe(retry(3), catchError(this.handleError));
147
+ }
148
+
149
+ /** Promise variant of getItemsState — resolves entity state info for a given record. */
150
+ public async getItemsSStatePromise(
151
+ managment: ManagmentInterface
152
+ ): Promise<ItemInterface[]> {
153
+ return await firstValueFrom(
154
+ this.http
155
+ .get<ItemInterface[]>(
156
+ this.url('GetItemsState', managment.appId, managment.year, managment.keyId),
157
+ this.globalService.jwt()
158
+ )
159
+ .pipe(retry(3), catchError(this.handleError))
160
+ );
161
+ }
162
+
163
+ /** Fetches a list of ItemInterface records by entity name/ids (Promise, GetItemsInfo). */
164
+ public async getItemsByNamePromise(
165
+ managment: ManagmentInterface
166
+ ): Promise<ItemInterface[]> {
167
+ return await firstValueFrom(
168
+ this.http
169
+ .get<ItemInterface[]>(
170
+ this.url('GetItemsInfo', managment.appId, String(managment.entIds), managment.year, managment.functionId, managment.keyId),
171
+ this.globalService.jwt()
172
+ )
173
+ .pipe(retry(3), catchError(this.handleError))
174
+ );
175
+ }
176
+
177
+ /** Observable variant of getItemsByNamePromise (GetItemsInfo). */
178
+ public getItemsByName(
179
+ managment: ManagmentInterface
180
+ ): Observable<ItemInterface[]> {
181
+ return this.http
182
+ .get<ItemInterface[]>(
183
+ this.url('GetItemsInfo', managment.appId, String(managment.entIds), managment.year, managment.functionId, managment.keyId),
184
+ this.globalService.jwt()
185
+ )
186
+ .pipe(retry(3), catchError(this.handleError));
187
+ }
188
+
189
+ /** Fetches the entity field schema (GetResource/{entId}.json) as an Observable. */
190
+ public getFields(
191
+ managment: ManagmentInterface
192
+ ): Observable<FieldInterface[]> {
193
+ return this.http
194
+ .get<FieldInterface[]>(
195
+ this.url('GetResource', managment.appId, managment.year, managment.entId + '.json'),
196
+ this.globalService.jwt()
197
+ )
198
+ .pipe(retry(3), catchError(this.handleError));
199
+ }
200
+
201
+ /** Promise variant of getFields — resolves the entity field schema JSON. */
202
+ public async getFieldsPromise(
203
+ managment: ManagmentInterface
204
+ ): Promise<FieldInterface[]> {
205
+ return await firstValueFrom(
206
+ this.http
207
+ .get<FieldInterface[]>(
208
+ this.url('GetResource', managment.appId, managment.year, managment.entId + '.json'),
209
+ this.globalService.jwt()
210
+ )
211
+ .pipe(retry(3), catchError(this.handleError))
212
+ );
213
+ }
214
+
215
+ /**
216
+ * Fetches entity data (Observable). The pako-compressed base64 response is
217
+ * decompressed by the `getDataFile` operator before emission.
218
+ */
219
+ public getData(
220
+ managment: ManagmentInterface
221
+ ): Observable<TransportInterface> {
222
+ return this.http
223
+ .get<TransportInterface>(
224
+ this.url('GetData', managment.functionId, managment.appId, managment.year, managment.entId, managment.keys, managment.keyId),
225
+ this.globalService.jwt()
226
+ )
227
+ .pipe(
228
+ retry(3),
229
+ catchError(this.handleError),
230
+ map(d => this.getDataFile(d))
231
+ );
232
+ }
233
+
234
+ /** Decodes the base64 dataFile, inflates it with pako, and returns the updated transport. */
235
+ private getDataFile(data: TransportInterface) {
236
+ const binary = atob(data.dataFile as string);
237
+ const bytes = new Uint8Array(binary.length);
238
+ for (let i = 0; i < binary.length; i++) {
239
+ bytes[i] = binary.charCodeAt(i);
240
+ }
241
+ data.dataFile = pako.inflate(bytes, { to: 'string' });
242
+ return data;
243
+ }
244
+
245
+ /** Promise variant of getData — resolves raw transport data (no decompression applied). */
246
+ public getDataPromise(
247
+ managment: ManagmentInterface
248
+ ): Promise<TransportInterface> {
249
+ return firstValueFrom(
250
+ this.http
251
+ .get<TransportInterface>(
252
+ this.url('GetData', managment.functionId, managment.appId, managment.year, managment.entId, managment.keys, managment.keyId),
253
+ this.globalService.jwt()
254
+ )
255
+ .pipe(retry(3), catchError(this.handleError))
256
+ );
257
+ }
258
+
259
+ /** Sends a POST request to insert a new managment record. */
260
+ public postData(
261
+ managment: ManagmentInterface
262
+ ): Observable<TransportInterface> {
263
+ return this.http
264
+ .post<TransportInterface>(
265
+ this.managmentsUrl,
266
+ JSON.stringify(managment),
267
+ this.globalService.jwt()
268
+ )
269
+ .pipe(retry(3), catchError(this.handleError));
270
+ }
271
+
272
+ /** Sends a PUT request to update an existing managment record (Observable). */
273
+ public putData(
274
+ managment: ManagmentInterface
275
+ ): Observable<TransportInterface> {
276
+ return this.http
277
+ .put<TransportInterface>(
278
+ this.managmentsUrl,
279
+ JSON.stringify(managment),
280
+ this.globalService.jwt()
281
+ )
282
+ .pipe(retry(3), catchError(this.handleError));
283
+ }
284
+
285
+ /** Promise variant of putData — awaits a PUT save and resolves the transport response. */
286
+ public putDataPromise(
287
+ managment: ManagmentInterface
288
+ ): Promise<TransportInterface> {
289
+ return firstValueFrom(
290
+ this.http
291
+ .put<TransportInterface>(
292
+ this.managmentsUrl,
293
+ JSON.stringify(managment),
294
+ this.globalService.jwt()
295
+ )
296
+ .pipe(retry(3), catchError(this.handleError))
297
+ );
298
+ }
299
+
300
+ /** Centralised error handler: maps client-side network errors and HTTP status codes to a typed Error. */
301
+ private handleError(error: HttpErrorResponse): Observable<never> {
302
+ let errorMessage = 'An error occurred';
303
+
304
+ if (error.error instanceof ErrorEvent) {
305
+ // Client-side or network error
306
+ errorMessage = `Client Error: ${error.error.message}`;
307
+ console.error('Client-side error:', error.error.message);
308
+ } else {
309
+ // Backend error
310
+ errorMessage = `Server Error (${error.status}): ${error.message}`;
311
+ console.error(
312
+ `Backend returned code ${error.status}, body:`,
313
+ error.error
314
+ );
315
+ }
316
+
317
+ return throwError(() => new Error(errorMessage));
318
+ }
319
+ }
@@ -0,0 +1 @@
1
+ export * from './modelsearch.component';
@@ -0,0 +1,124 @@
1
+ <!-- modelsearch.component -->
2
+ <modeltemplate>
3
+ <div class="fill d-flex flex-column">
4
+ <!-- ── Header ────────────────────────────────────────────────── -->
5
+ <div class="model-header">
6
+ <div
7
+ class="model-title truncate"
8
+ title="{{ msg?.getProjectDescription('description') }}">
9
+ {{ msg?.getProjectDescription('description') }}
10
+ </div>
11
+ </div>
12
+
13
+ <!-- ── Toolbar ───────────────────────────────────────────────── -->
14
+ <div class="mtb-bar">
15
+ <div class="mtb-group">
16
+ <a class="mtb-btn" (click)="click('exit')" [class.pe-none]="exitState">
17
+ <i
18
+ [class.icon-disabled]="exitState"
19
+ class="bi bi-box-arrow-left"
20
+ title="{{ msg?.get('app.exit') }}"></i>
21
+ </a>
22
+ </div>
23
+
24
+ <div class="mtb-divider"></div>
25
+
26
+ <!-- Search input -->
27
+ <div class="msearch-input-wrap">
28
+ <i class="bi bi-search msearch-input-icon"></i>
29
+ <input
30
+ id="bkgwhite"
31
+ [attr.data-state]="0"
32
+ type="text"
33
+ [attr.data-length]="30"
34
+ [attr.data-type]="0"
35
+ nvg
36
+ class="msearch-input"
37
+ [placeholder]="msg?.get('app.search')"
38
+ [title]="msg?.get('app.search')"
39
+ (input)="onEnter($event.target.value)"
40
+ (keyup)="onKeyUp($event)"
41
+ #inputfilter />
42
+ </div>
43
+
44
+ <div class="mtb-divider"></div>
45
+
46
+ <div class="mtb-group">
47
+ <a class="mtb-btn" (click)="click('plus')" [class.pe-none]="plusState">
48
+ <i
49
+ [class.icon-disabled]="plusState"
50
+ class="bi bi-plus-circle"
51
+ title="{{ msg?.get('app.plus') }}"></i>
52
+ </a>
53
+ </div>
54
+
55
+ <div class="mtb-divider"></div>
56
+
57
+ <div class="mtb-group">
58
+ <a
59
+ class="mtb-btn"
60
+ [class.pe-none]="firstState"
61
+ (click)="click('first')">
62
+ <i
63
+ [class.icon-disabled]="firstState"
64
+ class="bi bi-chevron-double-left"
65
+ title="{{ msg?.get('app.first') }}"></i>
66
+ </a>
67
+ <a
68
+ class="mtb-btn"
69
+ [class.pe-none]="previousState"
70
+ (click)="click('previous')">
71
+ <i
72
+ [class.icon-disabled]="previousState"
73
+ class="bi bi-chevron-left"
74
+ title="{{ msg?.get('app.previous') }}"></i>
75
+ </a>
76
+ <span class="msearch-page-badge">{{ currentPage }}</span>
77
+ <a class="mtb-btn" [class.pe-none]="nextState" (click)="click('next')">
78
+ <i
79
+ [class.icon-disabled]="nextState"
80
+ class="bi bi-chevron-right"
81
+ title="{{ msg?.get('app.next') }}"></i>
82
+ </a>
83
+ <a class="mtb-btn" [class.pe-none]="lastState" (click)="click('last')">
84
+ <i
85
+ [class.icon-disabled]="lastState"
86
+ class="bi bi-chevron-double-right"
87
+ title="{{ msg?.get('app.last') }}"></i>
88
+ </a>
89
+ </div>
90
+
91
+ <div class="mtb-divider"></div>
92
+
93
+ <div class="mtb-group">
94
+ <a
95
+ class="mtb-btn"
96
+ [class.pe-none]="printState"
97
+ (click)="click('print')">
98
+ <i
99
+ [class.icon-disabled]="printState"
100
+ class="bi bi-printer"
101
+ title="{{ msg?.get('app.print') }}"></i>
102
+ </a>
103
+ </div>
104
+ </div>
105
+
106
+ <!-- ── Cards grid ────────────────────────────────────────────── -->
107
+ <div class="msearch-body">
108
+ <div class="row g-2">
109
+ @for (item of items; track item.key_id) {
110
+ <div class="col-sm-6 col-md-4">
111
+ <card
112
+ [item]="item"
113
+ (activate)="activate($event)"
114
+ (print)="print($event)"
115
+ (delete)="delete($event)"
116
+ (flipflop)="flipflop($event)">
117
+ </card>
118
+ </div>
119
+ }
120
+ </div>
121
+ </div>
122
+ </div>
123
+ </modeltemplate>
124
+ <!-- fine modelsearch.component-->