@flusys/ng-shared 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/flusys-ng-shared.mjs +1543 -0
- package/fesm2022/flusys-ng-shared.mjs.map +1 -0
- package/package.json +26 -0
- package/types/flusys-ng-shared.d.ts +1107 -0
|
@@ -0,0 +1,1107 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import * as _angular_core from '@angular/core';
|
|
3
|
+
import { AfterViewInit, ResourceRef, Injector, model, ElementRef, InjectionToken } from '@angular/core';
|
|
4
|
+
import * as i1 from '@angular/common';
|
|
5
|
+
import * as i2 from '@angular/router';
|
|
6
|
+
import { CanActivateFn } from '@angular/router';
|
|
7
|
+
import * as i5 from '@angular/forms';
|
|
8
|
+
import { ControlValueAccessor } from '@angular/forms';
|
|
9
|
+
import * as i1$1 from 'primeng/inputtext';
|
|
10
|
+
import * as i2$1 from 'primeng/tag';
|
|
11
|
+
import * as i3 from 'primeng/selectbutton';
|
|
12
|
+
import * as i4 from 'primeng/password';
|
|
13
|
+
import * as i5$1 from 'primeng/button';
|
|
14
|
+
import * as i6 from 'primeng/tooltip';
|
|
15
|
+
import * as i7 from 'primeng/checkbox';
|
|
16
|
+
import { CheckboxChangeEvent } from 'primeng/checkbox';
|
|
17
|
+
import * as i8 from 'primeng/steps';
|
|
18
|
+
import * as i9 from 'primeng/ripple';
|
|
19
|
+
import * as i10 from 'primeng/panel';
|
|
20
|
+
import * as i11 from 'primeng/paginator';
|
|
21
|
+
import * as i12 from 'primeng/table';
|
|
22
|
+
import * as i13 from 'primeng/inputnumber';
|
|
23
|
+
import * as i14 from 'primeng/textarea';
|
|
24
|
+
import * as i15 from 'primeng/progressbar';
|
|
25
|
+
import * as i16 from 'primeng/fileupload';
|
|
26
|
+
import * as i17 from 'primeng/card';
|
|
27
|
+
import * as i18 from 'primeng/select';
|
|
28
|
+
import * as i19 from 'primeng/inputicon';
|
|
29
|
+
import * as i20 from 'primeng/iconfield';
|
|
30
|
+
import * as i21 from 'primeng/popover';
|
|
31
|
+
import * as i22 from 'primeng/listbox';
|
|
32
|
+
import * as i23 from 'primeng/radiobutton';
|
|
33
|
+
import * as i24 from 'primeng/toggleswitch';
|
|
34
|
+
import * as i25 from 'primeng/image';
|
|
35
|
+
import * as i26 from 'primeng/datepicker';
|
|
36
|
+
import * as i27 from 'primeng/splitbutton';
|
|
37
|
+
import * as i28 from 'primeng/divider';
|
|
38
|
+
import * as i29 from 'primeng/multiselect';
|
|
39
|
+
import * as i30 from 'primeng/autocomplete';
|
|
40
|
+
import * as i31 from 'primeng/tabs';
|
|
41
|
+
import * as i32 from 'primeng/dialog';
|
|
42
|
+
import * as i33 from 'primeng/treetable';
|
|
43
|
+
import * as _flusys_ng_shared from '@flusys/ng-shared';
|
|
44
|
+
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
|
|
45
|
+
import { ApiLoaderService } from '@flusys/ng-core';
|
|
46
|
+
import { FormValueControl } from '@angular/forms/signals';
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Base entity interface - matches backend Identity entity
|
|
50
|
+
*/
|
|
51
|
+
interface IBaseEntity {
|
|
52
|
+
id: string;
|
|
53
|
+
createdAt: Date;
|
|
54
|
+
updatedAt: Date;
|
|
55
|
+
deletedAt?: Date | null;
|
|
56
|
+
createdById?: string | null;
|
|
57
|
+
updatedById?: string | null;
|
|
58
|
+
deletedById?: string | null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Soft deletable entity mixin
|
|
62
|
+
*/
|
|
63
|
+
interface ISoftDeletable {
|
|
64
|
+
deletedAt?: Date | null;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Timestampable entity mixin
|
|
68
|
+
*/
|
|
69
|
+
interface ITimestampable {
|
|
70
|
+
createdAt: Date;
|
|
71
|
+
updatedAt: Date;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Entity with active status
|
|
75
|
+
*/
|
|
76
|
+
interface IActivatable {
|
|
77
|
+
isActive: boolean;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Entity with ordering/serial
|
|
81
|
+
*/
|
|
82
|
+
interface IOrderable {
|
|
83
|
+
serial?: number | null;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Entity with metadata JSON field
|
|
87
|
+
*/
|
|
88
|
+
interface IMetadata {
|
|
89
|
+
metadata?: Record<string, unknown> | null;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Logged-in user info - matches backend ILoggedUserInfo
|
|
93
|
+
*/
|
|
94
|
+
interface ILoggedUserInfo {
|
|
95
|
+
id: string;
|
|
96
|
+
email: string;
|
|
97
|
+
name?: string;
|
|
98
|
+
phone?: string;
|
|
99
|
+
profilePictureId?: string;
|
|
100
|
+
companyId?: string;
|
|
101
|
+
branchId?: string;
|
|
102
|
+
companyLogoId?: string;
|
|
103
|
+
branchLogoId?: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Request metadata added by backend ResponseMetaInterceptor
|
|
108
|
+
*/
|
|
109
|
+
interface IRequestMeta {
|
|
110
|
+
requestId?: string;
|
|
111
|
+
timestamp?: string;
|
|
112
|
+
responseTime?: number;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Pagination metadata for list responses
|
|
116
|
+
*/
|
|
117
|
+
interface IPaginationMeta {
|
|
118
|
+
total: number;
|
|
119
|
+
page: number;
|
|
120
|
+
pageSize: number;
|
|
121
|
+
count: number;
|
|
122
|
+
hasMore?: boolean;
|
|
123
|
+
totalPages?: number;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Bulk operation metadata
|
|
127
|
+
*/
|
|
128
|
+
interface IBulkMeta {
|
|
129
|
+
count: number;
|
|
130
|
+
failed?: number;
|
|
131
|
+
total?: number;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Validation error detail
|
|
135
|
+
*/
|
|
136
|
+
interface IValidationError {
|
|
137
|
+
field: string;
|
|
138
|
+
message: string;
|
|
139
|
+
constraint?: string;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Single item response (insert, update, get-by-id)
|
|
143
|
+
*/
|
|
144
|
+
interface ISingleResponse<T> {
|
|
145
|
+
success: boolean;
|
|
146
|
+
message: string;
|
|
147
|
+
data?: T;
|
|
148
|
+
_meta?: IRequestMeta;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* List response with pagination (get-all)
|
|
152
|
+
*/
|
|
153
|
+
interface IListResponse<T> {
|
|
154
|
+
success: boolean;
|
|
155
|
+
message: string;
|
|
156
|
+
data?: T[];
|
|
157
|
+
meta: IPaginationMeta;
|
|
158
|
+
_meta?: IRequestMeta;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Bulk operation response (insert-many, update-many)
|
|
162
|
+
*/
|
|
163
|
+
interface IBulkResponse<T> {
|
|
164
|
+
success: boolean;
|
|
165
|
+
message: string;
|
|
166
|
+
data?: T[];
|
|
167
|
+
meta: IBulkMeta;
|
|
168
|
+
_meta?: IRequestMeta;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Message-only response (delete, logout, status updates)
|
|
172
|
+
*/
|
|
173
|
+
interface IMessageResponse {
|
|
174
|
+
success: boolean;
|
|
175
|
+
message: string;
|
|
176
|
+
_meta?: IRequestMeta;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Error response
|
|
180
|
+
*/
|
|
181
|
+
interface IErrorResponse {
|
|
182
|
+
success: false;
|
|
183
|
+
message: string;
|
|
184
|
+
code?: string;
|
|
185
|
+
errors?: IValidationError[];
|
|
186
|
+
_meta?: IRequestMeta;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Union type for all API responses
|
|
190
|
+
*/
|
|
191
|
+
type ApiResponse<T> = ISingleResponse<T> | IListResponse<T> | IBulkResponse<T> | IMessageResponse | IErrorResponse;
|
|
192
|
+
interface IUserCompanyPayload {
|
|
193
|
+
id: string;
|
|
194
|
+
name: string;
|
|
195
|
+
slug: string;
|
|
196
|
+
logoId?: string;
|
|
197
|
+
}
|
|
198
|
+
interface IUserBranchPayload {
|
|
199
|
+
id: string;
|
|
200
|
+
name: string;
|
|
201
|
+
slug: string;
|
|
202
|
+
logoId?: string;
|
|
203
|
+
}
|
|
204
|
+
interface ILoginUserData {
|
|
205
|
+
id: string;
|
|
206
|
+
name: string;
|
|
207
|
+
email: string;
|
|
208
|
+
phone?: string;
|
|
209
|
+
profilePictureId?: string | null;
|
|
210
|
+
companyId?: string;
|
|
211
|
+
branchId?: string;
|
|
212
|
+
company?: IUserCompanyPayload;
|
|
213
|
+
branch?: IUserBranchPayload;
|
|
214
|
+
}
|
|
215
|
+
interface ILoginResponse {
|
|
216
|
+
success: boolean;
|
|
217
|
+
message: string;
|
|
218
|
+
data: {
|
|
219
|
+
accessToken: string;
|
|
220
|
+
refreshToken: string;
|
|
221
|
+
user: ILoginUserData;
|
|
222
|
+
};
|
|
223
|
+
_meta?: IRequestMeta;
|
|
224
|
+
}
|
|
225
|
+
interface IRefreshTokenResponse {
|
|
226
|
+
success: boolean;
|
|
227
|
+
message: string;
|
|
228
|
+
data: {
|
|
229
|
+
accessToken: string;
|
|
230
|
+
refreshToken?: string;
|
|
231
|
+
};
|
|
232
|
+
_meta?: IRequestMeta;
|
|
233
|
+
}
|
|
234
|
+
interface IFileData {
|
|
235
|
+
id: string;
|
|
236
|
+
name: string;
|
|
237
|
+
originalName: string;
|
|
238
|
+
contentType: string;
|
|
239
|
+
size: number;
|
|
240
|
+
key: string;
|
|
241
|
+
url?: string;
|
|
242
|
+
thumbnailUrl?: string;
|
|
243
|
+
createdAt: Date;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Company basic info for dropdowns
|
|
248
|
+
*/
|
|
249
|
+
interface ICompanyBasicInfo {
|
|
250
|
+
id: string;
|
|
251
|
+
name: string;
|
|
252
|
+
slug?: string;
|
|
253
|
+
}
|
|
254
|
+
interface ICompanyApiProvider {
|
|
255
|
+
/**
|
|
256
|
+
* Get list of companies with pagination
|
|
257
|
+
*/
|
|
258
|
+
getCompanies(filter?: {
|
|
259
|
+
page?: number;
|
|
260
|
+
pageSize?: number;
|
|
261
|
+
search?: string;
|
|
262
|
+
[key: string]: any;
|
|
263
|
+
}): Observable<IListResponse<ICompanyBasicInfo>>;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Delete operation types
|
|
268
|
+
* - 'delete': Soft delete (sets deletedAt timestamp)
|
|
269
|
+
* - 'restore': Restore soft-deleted item (clears deletedAt)
|
|
270
|
+
* - 'permanent': Permanently delete from database
|
|
271
|
+
*/
|
|
272
|
+
type DeleteType = 'delete' | 'restore' | 'permanent';
|
|
273
|
+
/**
|
|
274
|
+
* Delete request payload - matches backend DeleteDto
|
|
275
|
+
*/
|
|
276
|
+
interface IDeleteData {
|
|
277
|
+
/** Single ID or array of IDs to delete */
|
|
278
|
+
id: string | string[];
|
|
279
|
+
/** Type of delete operation */
|
|
280
|
+
type: DeleteType;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
interface IDropDown {
|
|
284
|
+
label: string;
|
|
285
|
+
value: string;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
interface IPagination {
|
|
289
|
+
pageSize: number;
|
|
290
|
+
currentPage: number;
|
|
291
|
+
}
|
|
292
|
+
interface ISort {
|
|
293
|
+
[key: string]: 'ASC' | 'DESC';
|
|
294
|
+
}
|
|
295
|
+
interface IFilter {
|
|
296
|
+
[key: string]: any;
|
|
297
|
+
}
|
|
298
|
+
interface IFilterData {
|
|
299
|
+
filter?: IFilter;
|
|
300
|
+
pagination?: IPagination;
|
|
301
|
+
select?: string[];
|
|
302
|
+
sort?: ISort;
|
|
303
|
+
withDeleted?: boolean;
|
|
304
|
+
extraKey?: string[];
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** Action node - checks a single permission */
|
|
308
|
+
interface IActionNode {
|
|
309
|
+
type: 'action';
|
|
310
|
+
actionId: string;
|
|
311
|
+
}
|
|
312
|
+
/** Group node - combines children with AND/OR logic */
|
|
313
|
+
interface IGroupNode {
|
|
314
|
+
type: 'group';
|
|
315
|
+
operator: 'AND' | 'OR';
|
|
316
|
+
children: ILogicNode[];
|
|
317
|
+
}
|
|
318
|
+
/** Permission logic tree (discriminated union of action/group) */
|
|
319
|
+
type ILogicNode = IActionNode | IGroupNode;
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* User Permission Provider Interface
|
|
323
|
+
*
|
|
324
|
+
* Abstracts user permission data access operations.
|
|
325
|
+
* Implemented by auth package, used by IAM for user permission queries.
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* // In IAM component
|
|
329
|
+
* class UserActionSelectorComponent {
|
|
330
|
+
* private readonly userPermissionProvider = inject(USER_PERMISSION_PROVIDER);
|
|
331
|
+
*
|
|
332
|
+
* async loadUserBranches(userId: string) {
|
|
333
|
+
* const response = await this.userPermissionProvider
|
|
334
|
+
* .getUserBranchPermissions(userId, '')
|
|
335
|
+
* .toPromise();
|
|
336
|
+
* this.branches.set(response?.data ?? []);
|
|
337
|
+
* }
|
|
338
|
+
* }
|
|
339
|
+
*/
|
|
340
|
+
interface IUserPermissionProvider {
|
|
341
|
+
/**
|
|
342
|
+
* Get user's branch permissions
|
|
343
|
+
*/
|
|
344
|
+
getUserBranchPermissions(userId: string): Observable<ISingleResponse<any>>;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* User data for dropdowns and selectors
|
|
349
|
+
*/
|
|
350
|
+
interface IUserBasicInfo {
|
|
351
|
+
id: string;
|
|
352
|
+
name: string;
|
|
353
|
+
email: string;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* User Provider Interface
|
|
357
|
+
*
|
|
358
|
+
* Abstracts user data access for IAM and other feature packages.
|
|
359
|
+
* Implemented by auth package, used by IAM for user selection in permission assignment.
|
|
360
|
+
*
|
|
361
|
+
* @example
|
|
362
|
+
* // In IAM component
|
|
363
|
+
* class UserActionSelectorComponent {
|
|
364
|
+
* private readonly userProvider = inject(USER_PROVIDER);
|
|
365
|
+
*
|
|
366
|
+
* loadUsers() {
|
|
367
|
+
* this.userProvider.getUsers({ page: 0, pageSize: 50 }).subscribe(users => {
|
|
368
|
+
* this.users.set(users.data);
|
|
369
|
+
* });
|
|
370
|
+
* }
|
|
371
|
+
* }
|
|
372
|
+
*/
|
|
373
|
+
interface IUserProvider {
|
|
374
|
+
/**
|
|
375
|
+
* Get list of users with pagination
|
|
376
|
+
* @param filter Optional filter (page, pageSize, search, etc.)
|
|
377
|
+
*/
|
|
378
|
+
getUsers(filter?: {
|
|
379
|
+
page?: number;
|
|
380
|
+
pageSize?: number;
|
|
381
|
+
search?: string;
|
|
382
|
+
companyId?: string;
|
|
383
|
+
branchId?: string;
|
|
384
|
+
[key: string]: any;
|
|
385
|
+
}): Observable<IListResponse<IUserBasicInfo>>;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
declare enum ContactTypeEnum {
|
|
389
|
+
PHONE = 1,
|
|
390
|
+
EMAIL = 2
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
declare enum IconTypeEnum {
|
|
394
|
+
PRIMENG_ICON = 1,
|
|
395
|
+
IMAGE_FILE_LINK = 2,
|
|
396
|
+
DIRECT_TAG_SVG = 3
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
declare class CookieService {
|
|
400
|
+
private doc;
|
|
401
|
+
private platformService;
|
|
402
|
+
private readonly request;
|
|
403
|
+
get(): string;
|
|
404
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<CookieService, never>;
|
|
405
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<CookieService>;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Request DTO for fetching file URLs
|
|
410
|
+
*/
|
|
411
|
+
interface GetFilesRequestDto {
|
|
412
|
+
id: string;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Response DTO with file information including URL
|
|
416
|
+
*/
|
|
417
|
+
interface FilesResponseDto {
|
|
418
|
+
id: string;
|
|
419
|
+
name: string;
|
|
420
|
+
contentType: string;
|
|
421
|
+
url: string;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Service to fetch file URLs from the backend.
|
|
425
|
+
* Uses POST /file-manager/get-files endpoint which:
|
|
426
|
+
* - Handles presigned URLs for cloud storage (AWS S3, Azure)
|
|
427
|
+
* - Auto-refreshes expired URLs
|
|
428
|
+
* - Validates file access permissions
|
|
429
|
+
* - Works with all storage providers (Local, S3, Azure, SFTP)
|
|
430
|
+
*/
|
|
431
|
+
declare class FileUrlService {
|
|
432
|
+
private readonly http;
|
|
433
|
+
private readonly appConfig;
|
|
434
|
+
/** Cache of file URLs by file ID */
|
|
435
|
+
private readonly urlCache;
|
|
436
|
+
/**
|
|
437
|
+
* Get file URL by ID from cache (reactive signal)
|
|
438
|
+
*/
|
|
439
|
+
getFileUrl(fileId: string | null | undefined): string | null;
|
|
440
|
+
/**
|
|
441
|
+
* Get file URL signal (computed from cache)
|
|
442
|
+
*/
|
|
443
|
+
fileUrlSignal(fileId: string | null | undefined): _angular_core.Signal<string | null>;
|
|
444
|
+
/**
|
|
445
|
+
* Fetch file URLs from backend and update cache.
|
|
446
|
+
* Returns Observable of fetched files.
|
|
447
|
+
*/
|
|
448
|
+
fetchFileUrls(fileIds: string[]): Observable<FilesResponseDto[]>;
|
|
449
|
+
/**
|
|
450
|
+
* Fetch a single file URL.
|
|
451
|
+
* Returns Observable of file info or null if not found.
|
|
452
|
+
*/
|
|
453
|
+
fetchSingleFileUrl(fileId: string): Observable<FilesResponseDto | null>;
|
|
454
|
+
/**
|
|
455
|
+
* Clear the URL cache.
|
|
456
|
+
* Useful on logout or when switching contexts.
|
|
457
|
+
*/
|
|
458
|
+
clearCache(): void;
|
|
459
|
+
/**
|
|
460
|
+
* Remove specific file from cache.
|
|
461
|
+
*/
|
|
462
|
+
removeFromCache(fileId: string): void;
|
|
463
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FileUrlService, never>;
|
|
464
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<FileUrlService>;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Permission Validator Service
|
|
469
|
+
*
|
|
470
|
+
* Centralized service for permission validation across all packages.
|
|
471
|
+
* Provides signal-based state management and reactive permission checking.
|
|
472
|
+
*
|
|
473
|
+
* Features:
|
|
474
|
+
* - Signal-based permission storage
|
|
475
|
+
* - Individual permission checks
|
|
476
|
+
* - Permission change detection
|
|
477
|
+
* - Reactive permission state updates
|
|
478
|
+
*
|
|
479
|
+
* Usage:
|
|
480
|
+
* ```typescript
|
|
481
|
+
* // In component
|
|
482
|
+
* readonly permissionValidator = inject(PermissionValidatorService);
|
|
483
|
+
*
|
|
484
|
+
* // Set permissions (typically from auth/IAM)
|
|
485
|
+
* this.permissionValidator.setPermissions(['user.view', 'user.create']);
|
|
486
|
+
*
|
|
487
|
+
* // Check individual permission
|
|
488
|
+
* if (this.permissionValidator.hasPermission('user.view')) {
|
|
489
|
+
* // Show UI element
|
|
490
|
+
* }
|
|
491
|
+
*
|
|
492
|
+
* // Access current permissions reactively
|
|
493
|
+
* const permissions = this.permissionValidator.permissions();
|
|
494
|
+
* ```
|
|
495
|
+
*
|
|
496
|
+
* @packageDocumentation
|
|
497
|
+
*/
|
|
498
|
+
declare class PermissionValidatorService {
|
|
499
|
+
/**
|
|
500
|
+
* Private writable signal for permissions
|
|
501
|
+
*/
|
|
502
|
+
private readonly _permissions;
|
|
503
|
+
/**
|
|
504
|
+
* Readonly permission signal for external consumers
|
|
505
|
+
*/
|
|
506
|
+
readonly permissions: _angular_core.Signal<string[]>;
|
|
507
|
+
/**
|
|
508
|
+
* Private writable signal for loaded state
|
|
509
|
+
*/
|
|
510
|
+
private readonly _isLoaded;
|
|
511
|
+
/**
|
|
512
|
+
* Set permissions (replaces existing permissions)
|
|
513
|
+
* @param permissions - Array of permission codes
|
|
514
|
+
*/
|
|
515
|
+
setPermissions(permissions: string[]): void;
|
|
516
|
+
/**
|
|
517
|
+
* Clear all permissions
|
|
518
|
+
*/
|
|
519
|
+
clearPermissions(): void;
|
|
520
|
+
/**
|
|
521
|
+
* Check if user has a specific permission
|
|
522
|
+
* @param permissionCode - Required permission code
|
|
523
|
+
* @returns True if user has permission
|
|
524
|
+
*/
|
|
525
|
+
hasPermission(permissionCode: string): boolean;
|
|
526
|
+
/**
|
|
527
|
+
* Check if permissions are loaded
|
|
528
|
+
* @returns True if permissions have been loaded
|
|
529
|
+
*/
|
|
530
|
+
isPermissionsLoaded(): boolean;
|
|
531
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<PermissionValidatorService, never>;
|
|
532
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<PermissionValidatorService>;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
declare class PlatformService {
|
|
536
|
+
private readonly platformId;
|
|
537
|
+
get isServer(): boolean;
|
|
538
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<PlatformService, never>;
|
|
539
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<PlatformService>;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
declare class EditModeElementChangerDirective implements AfterViewInit {
|
|
543
|
+
private el;
|
|
544
|
+
private ngControl;
|
|
545
|
+
readonly isEditMode: _angular_core.InputSignal<boolean>;
|
|
546
|
+
constructor();
|
|
547
|
+
ngAfterViewInit(): void;
|
|
548
|
+
private updateControl;
|
|
549
|
+
private updateElement;
|
|
550
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<EditModeElementChangerDirective, never>;
|
|
551
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<EditModeElementChangerDirective, "[appEditModeElementChanger]", never, { "isEditMode": { "alias": "isEditMode"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* HasPermission Directive
|
|
556
|
+
*
|
|
557
|
+
* Structural directive for permission-based rendering.
|
|
558
|
+
* Shows/hides elements based on permission logic evaluation.
|
|
559
|
+
*
|
|
560
|
+
* Supports:
|
|
561
|
+
* - Simple permission check (string)
|
|
562
|
+
* - Complex permission logic (ILogicNode with AND/OR operators)
|
|
563
|
+
*
|
|
564
|
+
* Usage:
|
|
565
|
+
* ```html
|
|
566
|
+
* <!-- Simple permission check -->
|
|
567
|
+
* <button *hasPermission="'user.create'">Create User</button>
|
|
568
|
+
*
|
|
569
|
+
* <!-- Complex permission logic -->
|
|
570
|
+
* <button *hasPermission="userManageLogic">Manage Users</button>
|
|
571
|
+
*
|
|
572
|
+
* <!-- Where userManageLogic is: -->
|
|
573
|
+
* <!-- (user.view OR user.create) AND department.manage -->
|
|
574
|
+
* ```
|
|
575
|
+
*
|
|
576
|
+
* The directive automatically reacts to permission changes through signals.
|
|
577
|
+
*
|
|
578
|
+
* @example
|
|
579
|
+
* // In component
|
|
580
|
+
* readonly userManageLogic: ILogicNode = {
|
|
581
|
+
* id: 'root',
|
|
582
|
+
* type: 'group',
|
|
583
|
+
* operator: 'AND',
|
|
584
|
+
* children: [
|
|
585
|
+
* {
|
|
586
|
+
* id: '1',
|
|
587
|
+
* type: 'group',
|
|
588
|
+
* operator: 'OR',
|
|
589
|
+
* children: [
|
|
590
|
+
* { id: '2', type: 'action', actionId: 'user.view' },
|
|
591
|
+
* { id: '3', type: 'action', actionId: 'user.create' }
|
|
592
|
+
* ]
|
|
593
|
+
* },
|
|
594
|
+
* { id: '4', type: 'action', actionId: 'department.manage' }
|
|
595
|
+
* ]
|
|
596
|
+
* };
|
|
597
|
+
*
|
|
598
|
+
* // In template
|
|
599
|
+
* <div *hasPermission="userManageLogic">
|
|
600
|
+
* User management content
|
|
601
|
+
* </div>
|
|
602
|
+
*/
|
|
603
|
+
declare class HasPermissionDirective {
|
|
604
|
+
private readonly templateRef;
|
|
605
|
+
private readonly viewContainer;
|
|
606
|
+
private readonly permissionValidator;
|
|
607
|
+
/**
|
|
608
|
+
* Permission logic input signal
|
|
609
|
+
* Accepts either:
|
|
610
|
+
* - string: Single permission code to check
|
|
611
|
+
* - ILogicNode: Complex permission logic tree
|
|
612
|
+
*/
|
|
613
|
+
readonly hasPermission: _angular_core.InputSignal<string | ILogicNode | null>;
|
|
614
|
+
/**
|
|
615
|
+
* View created state
|
|
616
|
+
*/
|
|
617
|
+
private viewCreated;
|
|
618
|
+
constructor();
|
|
619
|
+
/**
|
|
620
|
+
* Update view based on permission evaluation
|
|
621
|
+
*/
|
|
622
|
+
private updateView;
|
|
623
|
+
/**
|
|
624
|
+
* Clear the view container
|
|
625
|
+
*/
|
|
626
|
+
private clearView;
|
|
627
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<HasPermissionDirective, never>;
|
|
628
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<HasPermissionDirective, "[hasPermission]", never, { "hasPermission": { "alias": "hasPermission"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
declare class IsEmptyImageDirective {
|
|
632
|
+
readonly src: _angular_core.InputSignal<string>;
|
|
633
|
+
private readonly hasError;
|
|
634
|
+
private readonly defaultImg;
|
|
635
|
+
readonly imageSrc: _angular_core.Signal<string>;
|
|
636
|
+
onError(): void;
|
|
637
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<IsEmptyImageDirective, never>;
|
|
638
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<IsEmptyImageDirective, "img", never, { "src": { "alias": "src"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
declare class PreventDefaultDirective {
|
|
642
|
+
eventType: _angular_core.InputSignal<"click" | "keydown" | "keyup">;
|
|
643
|
+
preventKey: _angular_core.InputSignal<string | undefined>;
|
|
644
|
+
action: _angular_core.OutputEmitterRef<Event>;
|
|
645
|
+
onClick(event: MouseEvent): void;
|
|
646
|
+
onKeydown(event: KeyboardEvent): void;
|
|
647
|
+
onKeyup(event: KeyboardEvent): void;
|
|
648
|
+
private processEvent;
|
|
649
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<PreventDefaultDirective, never>;
|
|
650
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<PreventDefaultDirective, "[appPreventDefault]", never, { "eventType": { "alias": "eventType"; "required": false; "isSignal": true; }; "preventKey": { "alias": "preventKey"; "required": false; "isSignal": true; }; }, { "action": "action"; }, never, never, true, never>;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
declare class AngularModule {
|
|
654
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AngularModule, never>;
|
|
655
|
+
static ɵmod: _angular_core.ɵɵNgModuleDeclaration<AngularModule, never, [typeof i1.CommonModule, typeof i2.RouterOutlet, typeof i2.RouterLink, typeof IsEmptyImageDirective, typeof i1.NgOptimizedImage, typeof i1.NgComponentOutlet, typeof PreventDefaultDirective], [typeof i1.CommonModule, typeof i5.ReactiveFormsModule, typeof i5.FormsModule, typeof i2.RouterOutlet, typeof i2.RouterLink, typeof IsEmptyImageDirective, typeof i1.NgOptimizedImage, typeof i1.NgComponentOutlet, typeof PreventDefaultDirective]>;
|
|
656
|
+
static ɵinj: _angular_core.ɵɵInjectorDeclaration<AngularModule>;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
declare class PrimeModule {
|
|
660
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<PrimeModule, never>;
|
|
661
|
+
static ɵmod: _angular_core.ɵɵNgModuleDeclaration<PrimeModule, never, never, [typeof i1$1.InputTextModule, typeof i2$1.TagModule, typeof i3.SelectButtonModule, typeof i4.PasswordModule, typeof i5$1.ButtonModule, typeof i6.TooltipModule, typeof i7.CheckboxModule, typeof i8.StepsModule, typeof i9.RippleModule, typeof i10.PanelModule, typeof i11.PaginatorModule, typeof i12.TableModule, typeof i13.InputNumberModule, typeof i14.TextareaModule, typeof i15.ProgressBarModule, typeof i16.FileUploadModule, typeof i17.CardModule, typeof i18.SelectModule, typeof i19.InputIconModule, typeof i20.IconFieldModule, typeof i21.PopoverModule, typeof i22.ListboxModule, typeof i23.RadioButtonModule, typeof i24.ToggleSwitchModule, typeof i25.ImageModule, typeof i26.DatePickerModule, typeof i27.SplitButtonModule, typeof i28.DividerModule, typeof i29.MultiSelectModule, typeof i30.AutoCompleteModule, typeof i31.TabsModule, typeof i32.DialogModule, typeof i33.TreeTableModule]>;
|
|
662
|
+
static ɵinj: _angular_core.ɵɵInjectorDeclaration<PrimeModule>;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Service interface for CRUD operations.
|
|
667
|
+
* Matches NestJS shared API controller endpoints:
|
|
668
|
+
*
|
|
669
|
+
* | Angular Method | HTTP | NestJS Endpoint | Response Type |
|
|
670
|
+
* |------------------|--------|------------------------|------------------------|
|
|
671
|
+
* | insert() | POST | /{resource}/insert | ISingleResponse<T> |
|
|
672
|
+
* | insertMany() | POST | /{resource}/insert-many| IBulkResponse<T> |
|
|
673
|
+
* | findById() | POST | /{resource}/get/:id | ISingleResponse<T> |
|
|
674
|
+
* | getAll() | POST | /{resource}/get-all | IListResponse<T> |
|
|
675
|
+
* | update() | POST | /{resource}/update | ISingleResponse<T> |
|
|
676
|
+
* | updateMany() | POST | /{resource}/update-many| IBulkResponse<T> |
|
|
677
|
+
* | delete() | POST | /{resource}/delete | IMessageResponse |
|
|
678
|
+
*/
|
|
679
|
+
interface IApiService<DtoT, InterfaceT> {
|
|
680
|
+
insert(dto: DtoT): Observable<ISingleResponse<InterfaceT>>;
|
|
681
|
+
insertMany(dtos: DtoT[]): Observable<IBulkResponse<InterfaceT>>;
|
|
682
|
+
findById(id: string, select?: string[]): Observable<ISingleResponse<InterfaceT>>;
|
|
683
|
+
getAll(search: string, filter: IFilterData): Observable<IListResponse<InterfaceT>>;
|
|
684
|
+
update(dto: DtoT): Observable<ISingleResponse<InterfaceT>>;
|
|
685
|
+
updateMany(dtos: DtoT[]): Observable<IBulkResponse<InterfaceT>>;
|
|
686
|
+
delete(deleteDto: IDeleteData): Observable<IMessageResponse>;
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Abstract base class for API services using Angular 21 resource() API.
|
|
690
|
+
* Provides signal-based reactive data fetching with automatic loading states.
|
|
691
|
+
* Response types match FLUSYS_NEST backend DTOs.
|
|
692
|
+
*
|
|
693
|
+
* ## Endpoint Mapping
|
|
694
|
+
*
|
|
695
|
+
* All endpoints use POST method (RPC-style API):
|
|
696
|
+
* - `POST /{resource}/insert` - Create single item
|
|
697
|
+
* - `POST /{resource}/insert-many` - Create multiple items
|
|
698
|
+
* - `POST /{resource}/get/:id` - Get single item by ID
|
|
699
|
+
* - `POST /{resource}/get-all?q=` - List with pagination/filter
|
|
700
|
+
* - `POST /{resource}/update` - Update single item
|
|
701
|
+
* - `POST /{resource}/update-many` - Update multiple items
|
|
702
|
+
* - `POST /{resource}/delete` - Delete/restore/permanent delete
|
|
703
|
+
*
|
|
704
|
+
* @example
|
|
705
|
+
* ```typescript
|
|
706
|
+
* // Define service
|
|
707
|
+
* @Injectable({ providedIn: 'root' })
|
|
708
|
+
* export class UserService extends ApiResourceService<UserDto, User> {
|
|
709
|
+
* constructor(http: HttpClient) {
|
|
710
|
+
* super('users', http);
|
|
711
|
+
* }
|
|
712
|
+
* }
|
|
713
|
+
*
|
|
714
|
+
* // In component - use signals
|
|
715
|
+
* userService = inject(UserService);
|
|
716
|
+
* users = this.userService.data; // Signal<User[]>
|
|
717
|
+
* isLoading = this.userService.isLoading; // Signal<boolean>
|
|
718
|
+
* total = this.userService.total; // Signal<number>
|
|
719
|
+
*
|
|
720
|
+
* // Trigger fetch
|
|
721
|
+
* this.userService.fetchList('search', { pagination: { currentPage: 0, pageSize: 10 } });
|
|
722
|
+
*
|
|
723
|
+
* // CRUD operations
|
|
724
|
+
* await this.userService.insertAsync({ name: 'John', email: 'john@example.com' });
|
|
725
|
+
* await this.userService.updateAsync({ id: '123', name: 'John Updated' });
|
|
726
|
+
* await this.userService.deleteAsync({ id: '123', type: 'delete' });
|
|
727
|
+
* ```
|
|
728
|
+
*/
|
|
729
|
+
declare abstract class ApiResourceService<DtoT, InterfaceT> implements IApiService<DtoT, InterfaceT> {
|
|
730
|
+
protected readonly baseUrl: string;
|
|
731
|
+
protected readonly loaderService: ApiLoaderService;
|
|
732
|
+
protected readonly http: HttpClient;
|
|
733
|
+
protected readonly moduleApiName: string;
|
|
734
|
+
/** Current search term */
|
|
735
|
+
readonly searchTerm: _angular_core.WritableSignal<string>;
|
|
736
|
+
/** Current filter and pagination state */
|
|
737
|
+
readonly filterData: _angular_core.WritableSignal<IFilterData>;
|
|
738
|
+
/** Resource for list data - uses IListResponse matching backend */
|
|
739
|
+
readonly listResource: ResourceRef<IListResponse<InterfaceT> | undefined>;
|
|
740
|
+
/** Whether data is currently loading */
|
|
741
|
+
readonly isLoading: _angular_core.Signal<boolean>;
|
|
742
|
+
/** List data array */
|
|
743
|
+
readonly data: _angular_core.Signal<InterfaceT[]>;
|
|
744
|
+
/** Total count of items */
|
|
745
|
+
readonly total: _angular_core.Signal<number>;
|
|
746
|
+
/** Pagination metadata */
|
|
747
|
+
readonly pageInfo: _angular_core.Signal<_flusys_ng_shared.IPaginationMeta | undefined>;
|
|
748
|
+
/** Whether there are more pages */
|
|
749
|
+
readonly hasMore: _angular_core.Signal<boolean>;
|
|
750
|
+
constructor(moduleApiName: string, http: HttpClient);
|
|
751
|
+
protected getHttpOptions(endpoint: string, params?: HttpParams): {
|
|
752
|
+
params?: HttpParams | undefined;
|
|
753
|
+
headers: HttpHeaders;
|
|
754
|
+
};
|
|
755
|
+
/**
|
|
756
|
+
* Fetch list data (triggers resource reload)
|
|
757
|
+
*/
|
|
758
|
+
fetchList(search?: string, filter?: Partial<IFilterData>): void;
|
|
759
|
+
/**
|
|
760
|
+
* Update pagination
|
|
761
|
+
*/
|
|
762
|
+
setPagination(pagination: IPagination): void;
|
|
763
|
+
/**
|
|
764
|
+
* Go to next page
|
|
765
|
+
*/
|
|
766
|
+
nextPage(): void;
|
|
767
|
+
/**
|
|
768
|
+
* Reset to first page
|
|
769
|
+
*/
|
|
770
|
+
resetPagination(): void;
|
|
771
|
+
/**
|
|
772
|
+
* Reload current data
|
|
773
|
+
*/
|
|
774
|
+
reload(): void;
|
|
775
|
+
/**
|
|
776
|
+
* Insert single item (Observable)
|
|
777
|
+
* POST /{resource}/insert
|
|
778
|
+
*/
|
|
779
|
+
insert(dto: DtoT): Observable<ISingleResponse<InterfaceT>>;
|
|
780
|
+
/**
|
|
781
|
+
* Insert multiple items (Observable)
|
|
782
|
+
* POST /{resource}/insert-many
|
|
783
|
+
*/
|
|
784
|
+
insertMany(dtos: DtoT[]): Observable<IBulkResponse<InterfaceT>>;
|
|
785
|
+
/**
|
|
786
|
+
* Find single item by ID (Observable)
|
|
787
|
+
* POST /{resource}/get/:id
|
|
788
|
+
*/
|
|
789
|
+
findById(id: string, select?: string[]): Observable<ISingleResponse<InterfaceT>>;
|
|
790
|
+
/**
|
|
791
|
+
* Get all items with pagination (Observable)
|
|
792
|
+
* POST /{resource}/get-all?q=search
|
|
793
|
+
*/
|
|
794
|
+
getAll(search: string, filter: IFilterData): Observable<IListResponse<InterfaceT>>;
|
|
795
|
+
/**
|
|
796
|
+
* Update single item (Observable)
|
|
797
|
+
* POST /{resource}/update
|
|
798
|
+
*/
|
|
799
|
+
update(dto: DtoT): Observable<ISingleResponse<InterfaceT>>;
|
|
800
|
+
/**
|
|
801
|
+
* Update multiple items (Observable)
|
|
802
|
+
* POST /{resource}/update-many
|
|
803
|
+
*/
|
|
804
|
+
updateMany(dtos: DtoT[]): Observable<IBulkResponse<InterfaceT>>;
|
|
805
|
+
/**
|
|
806
|
+
* Delete items (Observable)
|
|
807
|
+
* POST /{resource}/delete
|
|
808
|
+
* @param deleteDto - { id: string | string[], type: 'delete' | 'restore' | 'permanent' }
|
|
809
|
+
*/
|
|
810
|
+
delete(deleteDto: IDeleteData): Observable<IMessageResponse>;
|
|
811
|
+
/**
|
|
812
|
+
* Fetch paginated list (async)
|
|
813
|
+
*/
|
|
814
|
+
protected fetchAllAsync(search: string, filter: IFilterData): Promise<IListResponse<InterfaceT>>;
|
|
815
|
+
/**
|
|
816
|
+
* Find single item by ID (async)
|
|
817
|
+
*/
|
|
818
|
+
findByIdAsync(id: string, select?: string[]): Promise<ISingleResponse<InterfaceT>>;
|
|
819
|
+
/**
|
|
820
|
+
* Insert single item (async)
|
|
821
|
+
*/
|
|
822
|
+
insertAsync(dto: DtoT): Promise<ISingleResponse<InterfaceT>>;
|
|
823
|
+
/**
|
|
824
|
+
* Insert multiple items (async)
|
|
825
|
+
*/
|
|
826
|
+
insertManyAsync(dtos: DtoT[]): Promise<IBulkResponse<InterfaceT>>;
|
|
827
|
+
/**
|
|
828
|
+
* Update single item (async)
|
|
829
|
+
*/
|
|
830
|
+
updateAsync(dto: DtoT): Promise<ISingleResponse<InterfaceT>>;
|
|
831
|
+
/**
|
|
832
|
+
* Update multiple items (async)
|
|
833
|
+
*/
|
|
834
|
+
updateManyAsync(dtos: DtoT[]): Promise<IBulkResponse<InterfaceT>>;
|
|
835
|
+
/**
|
|
836
|
+
* Delete items (async)
|
|
837
|
+
*/
|
|
838
|
+
deleteAsync(deleteDto: IDeleteData): Promise<IMessageResponse>;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
declare class IconComponent {
|
|
842
|
+
icon: _angular_core.InputSignal<string>;
|
|
843
|
+
iconType: _angular_core.InputSignal<IconTypeEnum | undefined>;
|
|
844
|
+
protected readonly IconTypeEnum: typeof IconTypeEnum;
|
|
845
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<IconComponent, never>;
|
|
846
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<IconComponent, "lib-icon", never, { "icon": { "alias": "icon"; "required": true; "isSignal": true; }; "iconType": { "alias": "iconType"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* Base class for form controls that support ALL Angular form patterns:
|
|
851
|
+
*
|
|
852
|
+
* 1. **Template-driven forms:** `[(value)]="mySignal"` or `[(ngModel)]="myValue"`
|
|
853
|
+
* 2. **Reactive forms:** `[formControl]="ctrl"` or `formControlName="field"`
|
|
854
|
+
* 3. **Signal forms (Angular 21+):** `[formField]="formTree.field"`
|
|
855
|
+
*
|
|
856
|
+
* Implements both `ControlValueAccessor` (reactive forms) and `FormValueControl` (signal forms).
|
|
857
|
+
*
|
|
858
|
+
* @example
|
|
859
|
+
* ```typescript
|
|
860
|
+
* @Component({
|
|
861
|
+
* providers: [provideValueAccessor(MySelectComponent)]
|
|
862
|
+
* })
|
|
863
|
+
* export class MySelectComponent extends BaseFormControl<string | null> {
|
|
864
|
+
* override readonly value = model<string | null>(null);
|
|
865
|
+
*
|
|
866
|
+
* constructor() {
|
|
867
|
+
* super();
|
|
868
|
+
* this.initializeFormControl();
|
|
869
|
+
* }
|
|
870
|
+
* }
|
|
871
|
+
*
|
|
872
|
+
* // Usage:
|
|
873
|
+
* // Template-driven: <my-select [(value)]="selectedId" />
|
|
874
|
+
* // Reactive forms: <my-select [formControl]="myControl" />
|
|
875
|
+
* // Signal forms: <my-select [formField]="formTree.myField" />
|
|
876
|
+
* ```
|
|
877
|
+
*/
|
|
878
|
+
declare abstract class BaseFormControl<T> implements ControlValueAccessor, FormValueControl<T> {
|
|
879
|
+
protected readonly injector: Injector;
|
|
880
|
+
/**
|
|
881
|
+
* The value model - must be overridden in subclass with model<T>().
|
|
882
|
+
* This property satisfies both:
|
|
883
|
+
* - FormValueControl interface (signal forms)
|
|
884
|
+
* - Internal state for ControlValueAccessor (reactive forms)
|
|
885
|
+
*/
|
|
886
|
+
abstract readonly value: ReturnType<typeof model<T>>;
|
|
887
|
+
/**
|
|
888
|
+
* Disabled state model - bound to form control disabled state.
|
|
889
|
+
* Using model() to satisfy FormValueControl interface requirements.
|
|
890
|
+
*/
|
|
891
|
+
readonly disabled: _angular_core.ModelSignal<boolean>;
|
|
892
|
+
/**
|
|
893
|
+
* Touched state model - for validation styling.
|
|
894
|
+
* Using model() to satisfy FormValueControl interface requirements.
|
|
895
|
+
*/
|
|
896
|
+
readonly touched: _angular_core.ModelSignal<boolean>;
|
|
897
|
+
private onChange;
|
|
898
|
+
private onTouched;
|
|
899
|
+
private isWritingValue;
|
|
900
|
+
/**
|
|
901
|
+
* Initialize the form control synchronization for ControlValueAccessor.
|
|
902
|
+
* Must be called in the subclass constructor after super().
|
|
903
|
+
*
|
|
904
|
+
* Note: For signal forms ([formField]), this is not needed as
|
|
905
|
+
* the FormField directive binds directly to the value model.
|
|
906
|
+
*/
|
|
907
|
+
protected initializeFormControl(): void;
|
|
908
|
+
/** ControlValueAccessor: Write value from form control to signal */
|
|
909
|
+
writeValue(value: T): void;
|
|
910
|
+
/** ControlValueAccessor: Register change callback */
|
|
911
|
+
registerOnChange(fn: (value: T) => void): void;
|
|
912
|
+
/** ControlValueAccessor: Register touched callback */
|
|
913
|
+
registerOnTouched(fn: () => void): void;
|
|
914
|
+
/** ControlValueAccessor: Set disabled state from form control */
|
|
915
|
+
setDisabledState(isDisabled: boolean): void;
|
|
916
|
+
/** Mark the control as touched (call on blur or panel close) */
|
|
917
|
+
protected markAsTouched(): void;
|
|
918
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<BaseFormControl<any>, never>;
|
|
919
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<BaseFormControl<any>, never, never, { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; }, { "disabled": "disabledChange"; "touched": "touchedChange"; }, never, never, true, never>;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
/**
|
|
923
|
+
* Lazy-loading multi-select component with search, pagination, and select-all.
|
|
924
|
+
*
|
|
925
|
+
* Supports ALL Angular form patterns:
|
|
926
|
+
* - Template-driven: `[(value)]="selectedIds"`
|
|
927
|
+
* - Reactive forms: `[formControl]="ctrl"` or `formControlName="field"`
|
|
928
|
+
* - Signal forms: `[formField]="formTree.field"`
|
|
929
|
+
*/
|
|
930
|
+
declare class LazyMultiSelectComponent extends BaseFormControl<string[] | null> {
|
|
931
|
+
readonly placeHolder: _angular_core.InputSignal<string>;
|
|
932
|
+
readonly isEditMode: _angular_core.InputSignal<boolean>;
|
|
933
|
+
readonly isLoading: _angular_core.InputSignal<boolean>;
|
|
934
|
+
readonly total: _angular_core.InputSignal<number | undefined>;
|
|
935
|
+
readonly pagination: _angular_core.InputSignal<IPagination>;
|
|
936
|
+
readonly selectDataList: _angular_core.InputSignal<IDropDown[]>;
|
|
937
|
+
/** Two-way bound value using model() for signal forms compatibility */
|
|
938
|
+
readonly value: _angular_core.ModelSignal<string[] | null>;
|
|
939
|
+
readonly onSearch: _angular_core.OutputEmitterRef<string>;
|
|
940
|
+
readonly onPagination: _angular_core.OutputEmitterRef<IPagination>;
|
|
941
|
+
readonly searchTerm: _angular_core.WritableSignal<string>;
|
|
942
|
+
/** Computed: Display text for selected values (replaces getSelectedValue method) */
|
|
943
|
+
readonly selectedValueDisplay: _angular_core.Signal<string>;
|
|
944
|
+
/** Computed: Whether all items are selected (replaces isSelectAll signal) */
|
|
945
|
+
readonly isSelectAll: _angular_core.Signal<boolean>;
|
|
946
|
+
constructor();
|
|
947
|
+
scrollTargetEl: HTMLElement | null;
|
|
948
|
+
private readonly onScrollBound;
|
|
949
|
+
readonly multiScrollContainer: _angular_core.Signal<ElementRef<HTMLDivElement>>;
|
|
950
|
+
onScroll(event: Event): void;
|
|
951
|
+
readonly pSelectRef: _angular_core.Signal<ElementRef<HTMLDivElement>>;
|
|
952
|
+
openOptions: _angular_core.WritableSignal<boolean>;
|
|
953
|
+
onSelectClick(event: Event): void;
|
|
954
|
+
onOverlayClick(event: Event): void;
|
|
955
|
+
handleDocumentClick(event: MouseEvent): void;
|
|
956
|
+
isSelected(data: IDropDown): boolean | undefined;
|
|
957
|
+
key(option: IDropDown): string;
|
|
958
|
+
selectValue(event: CheckboxChangeEvent, option: IDropDown): void;
|
|
959
|
+
changeSelectAll(event: CheckboxChangeEvent): void;
|
|
960
|
+
clear(event: Event): void;
|
|
961
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LazyMultiSelectComponent, never>;
|
|
962
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LazyMultiSelectComponent, "lib-lazy-multi-select", never, { "placeHolder": { "alias": "placeHolder"; "required": false; "isSignal": true; }; "isEditMode": { "alias": "isEditMode"; "required": true; "isSignal": true; }; "isLoading": { "alias": "isLoading"; "required": true; "isSignal": true; }; "total": { "alias": "total"; "required": true; "isSignal": true; }; "pagination": { "alias": "pagination"; "required": true; "isSignal": true; }; "selectDataList": { "alias": "selectDataList"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "onSearch": "onSearch"; "onPagination": "onPagination"; }, never, never, true, never>;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
/**
|
|
966
|
+
* Lazy-loading single select component with search and pagination.
|
|
967
|
+
*
|
|
968
|
+
* Supports ALL Angular form patterns:
|
|
969
|
+
* - Template-driven: `[(value)]="selectedId"`
|
|
970
|
+
* - Reactive forms: `[formControl]="ctrl"` or `formControlName="field"`
|
|
971
|
+
* - Signal forms: `[formField]="formTree.field"`
|
|
972
|
+
*/
|
|
973
|
+
declare class LazySelectComponent extends BaseFormControl<string | null> {
|
|
974
|
+
readonly placeHolder: _angular_core.InputSignal<string>;
|
|
975
|
+
readonly optionLabel: _angular_core.InputSignal<string>;
|
|
976
|
+
readonly optionValue: _angular_core.InputSignal<string>;
|
|
977
|
+
readonly isEditMode: _angular_core.InputSignal<boolean>;
|
|
978
|
+
readonly isLoading: _angular_core.InputSignal<boolean>;
|
|
979
|
+
readonly total: _angular_core.InputSignal<number | undefined>;
|
|
980
|
+
readonly pagination: _angular_core.InputSignal<IPagination>;
|
|
981
|
+
readonly selectDataList: _angular_core.InputSignal<IDropDown[]>;
|
|
982
|
+
/** Two-way bound value using model() for signal forms compatibility */
|
|
983
|
+
readonly value: _angular_core.ModelSignal<string | null>;
|
|
984
|
+
readonly onSearch: _angular_core.OutputEmitterRef<string>;
|
|
985
|
+
readonly onPagination: _angular_core.OutputEmitterRef<IPagination>;
|
|
986
|
+
readonly searchTerm: _angular_core.WritableSignal<string>;
|
|
987
|
+
constructor();
|
|
988
|
+
isPanelShow: _angular_core.WritableSignal<boolean>;
|
|
989
|
+
scrollTargetEl: HTMLElement | null;
|
|
990
|
+
private readonly onScrollBound;
|
|
991
|
+
readonly scrollContainer: _angular_core.Signal<ElementRef<HTMLDivElement>>;
|
|
992
|
+
onScroll(event: Event): void;
|
|
993
|
+
showPanel(): void;
|
|
994
|
+
onBlur(): void;
|
|
995
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LazySelectComponent, never>;
|
|
996
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LazySelectComponent, "lib-lazy-select", never, { "placeHolder": { "alias": "placeHolder"; "required": false; "isSignal": true; }; "optionLabel": { "alias": "optionLabel"; "required": true; "isSignal": true; }; "optionValue": { "alias": "optionValue"; "required": true; "isSignal": true; }; "isEditMode": { "alias": "isEditMode"; "required": true; "isSignal": true; }; "isLoading": { "alias": "isLoading"; "required": true; "isSignal": true; }; "total": { "alias": "total"; "required": true; "isSignal": true; }; "pagination": { "alias": "pagination"; "required": true; "isSignal": true; }; "selectDataList": { "alias": "selectDataList"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "onSearch": "onSearch"; "onPagination": "onPagination"; }, never, never, true, never>;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
/**
|
|
1000
|
+
* Injection Tokens for Provider Interfaces
|
|
1001
|
+
*
|
|
1002
|
+
* These tokens enable dependency injection of provider implementations
|
|
1003
|
+
* without creating direct package dependencies.
|
|
1004
|
+
*
|
|
1005
|
+
* Pattern:
|
|
1006
|
+
* 1. ng-shared defines interfaces and tokens (no implementation)
|
|
1007
|
+
* 2. ng-auth provides implementations
|
|
1008
|
+
* 3. ng-iam and ng-storage inject via tokens
|
|
1009
|
+
* 4. app.config.ts wires everything together
|
|
1010
|
+
*
|
|
1011
|
+
* @example
|
|
1012
|
+
* // In IAM component
|
|
1013
|
+
* private readonly userProvider = inject(USER_PROVIDER);
|
|
1014
|
+
*
|
|
1015
|
+
* // In app.config.ts
|
|
1016
|
+
* providers: [
|
|
1017
|
+
* { provide: USER_PROVIDER, useClass: AuthUserProvider },
|
|
1018
|
+
* ]
|
|
1019
|
+
*/
|
|
1020
|
+
/**
|
|
1021
|
+
* User Provider Token
|
|
1022
|
+
*
|
|
1023
|
+
* Provides user data access for IAM user selection.
|
|
1024
|
+
*/
|
|
1025
|
+
declare const USER_PROVIDER: InjectionToken<IUserProvider>;
|
|
1026
|
+
/**
|
|
1027
|
+
* Company API Provider Token
|
|
1028
|
+
*
|
|
1029
|
+
* Provides company data access for IAM company selection.
|
|
1030
|
+
*/
|
|
1031
|
+
declare const COMPANY_API_PROVIDER: InjectionToken<ICompanyApiProvider>;
|
|
1032
|
+
/**
|
|
1033
|
+
* User Permission Provider Token
|
|
1034
|
+
*
|
|
1035
|
+
* Provides user permission assignment operations for IAM.
|
|
1036
|
+
*/
|
|
1037
|
+
declare const USER_PERMISSION_PROVIDER: InjectionToken<IUserPermissionProvider>;
|
|
1038
|
+
|
|
1039
|
+
/**
|
|
1040
|
+
* Permission Guard
|
|
1041
|
+
*
|
|
1042
|
+
* Route-level guard for permission-based access control.
|
|
1043
|
+
* Validates permissions before allowing navigation.
|
|
1044
|
+
*
|
|
1045
|
+
* Features:
|
|
1046
|
+
* - Single permission check
|
|
1047
|
+
* - Complex ILogicNode logic trees
|
|
1048
|
+
* - Configurable redirect URL
|
|
1049
|
+
* - Debug logging for denied access
|
|
1050
|
+
*
|
|
1051
|
+
* @example
|
|
1052
|
+
* ```typescript
|
|
1053
|
+
* // Simple permission check
|
|
1054
|
+
* { path: 'users', canActivate: [permissionGuard('user.view')] }
|
|
1055
|
+
*
|
|
1056
|
+
* // Complex logic
|
|
1057
|
+
* { path: 'admin', canActivate: [permissionGuard({
|
|
1058
|
+
* id: 'root',
|
|
1059
|
+
* type: 'group',
|
|
1060
|
+
* operator: 'AND',
|
|
1061
|
+
* children: [
|
|
1062
|
+
* { id: '1', type: 'action', actionId: 'admin.view' },
|
|
1063
|
+
* { id: '2', type: 'action', actionId: 'admin.manage' }
|
|
1064
|
+
* ]
|
|
1065
|
+
* })] }
|
|
1066
|
+
*
|
|
1067
|
+
* // With custom redirect
|
|
1068
|
+
* { path: 'users', canActivate: [permissionGuard('user.view', '/access-denied')] }
|
|
1069
|
+
* ```
|
|
1070
|
+
*/
|
|
1071
|
+
declare function permissionGuard(permission: string | ILogicNode, redirectTo?: string): CanActivateFn;
|
|
1072
|
+
/**
|
|
1073
|
+
* Any Permission Guard (OR logic)
|
|
1074
|
+
*
|
|
1075
|
+
* Allows access if user has ANY of the specified permissions.
|
|
1076
|
+
*
|
|
1077
|
+
* @example
|
|
1078
|
+
* ```typescript
|
|
1079
|
+
* // Allow if user has view OR create permission
|
|
1080
|
+
* { path: 'users', canActivate: [anyPermissionGuard(['user.view', 'user.create'])] }
|
|
1081
|
+
* ```
|
|
1082
|
+
*/
|
|
1083
|
+
declare function anyPermissionGuard(permissions: string[], redirectTo?: string): CanActivateFn;
|
|
1084
|
+
/**
|
|
1085
|
+
* All Permissions Guard (AND logic)
|
|
1086
|
+
*
|
|
1087
|
+
* Allows access only if user has ALL of the specified permissions.
|
|
1088
|
+
*
|
|
1089
|
+
* @example
|
|
1090
|
+
* ```typescript
|
|
1091
|
+
* // Allow only if user has BOTH view AND create permissions
|
|
1092
|
+
* { path: 'admin', canActivate: [allPermissionsGuard(['admin.view', 'admin.manage'])] }
|
|
1093
|
+
* ```
|
|
1094
|
+
*/
|
|
1095
|
+
declare function allPermissionsGuard(permissions: string[], redirectTo?: string): CanActivateFn;
|
|
1096
|
+
|
|
1097
|
+
/** Evaluate permission logic (string or ILogicNode) against user permissions */
|
|
1098
|
+
declare function evaluatePermission(logic: string | ILogicNode | null | undefined, permissions: string[]): boolean;
|
|
1099
|
+
/** Recursively evaluate an ILogicNode tree */
|
|
1100
|
+
declare function evaluateLogicNode(node: ILogicNode, permissions: string[]): boolean;
|
|
1101
|
+
/** Check if user has ANY of the specified permissions (OR logic) */
|
|
1102
|
+
declare function hasAnyPermission(permissionCodes: string[], permissions: string[]): boolean;
|
|
1103
|
+
/** Check if user has ALL of the specified permissions (AND logic) */
|
|
1104
|
+
declare function hasAllPermissions(permissionCodes: string[], permissions: string[]): boolean;
|
|
1105
|
+
|
|
1106
|
+
export { AngularModule, ApiResourceService, ApiResourceService as ApiService, COMPANY_API_PROVIDER, ContactTypeEnum, CookieService, EditModeElementChangerDirective, FileUrlService, HasPermissionDirective, IconComponent, IconTypeEnum, IsEmptyImageDirective, LazyMultiSelectComponent, LazySelectComponent, PermissionValidatorService, PlatformService, PreventDefaultDirective, PrimeModule, USER_PERMISSION_PROVIDER, USER_PROVIDER, allPermissionsGuard, anyPermissionGuard, evaluateLogicNode, evaluatePermission, hasAllPermissions, hasAnyPermission, permissionGuard };
|
|
1107
|
+
export type { ApiResponse, DeleteType, FilesResponseDto, GetFilesRequestDto, IActionNode, IActivatable, IApiService, IBaseEntity, IBulkMeta, IBulkResponse, ICompanyApiProvider, ICompanyBasicInfo, IDeleteData, IDropDown, IErrorResponse, IFileData, IFilter, IFilterData, IGroupNode, IListResponse, ILoggedUserInfo, ILogicNode, ILoginResponse, ILoginUserData, IMessageResponse, IMetadata, IOrderable, IPagination, IPaginationMeta, IRefreshTokenResponse, IRequestMeta, ISingleResponse, ISoftDeletable, ISort, ITimestampable, IUserBasicInfo, IUserBranchPayload, IUserCompanyPayload, IUserPermissionProvider, IUserProvider, IValidationError };
|