@flusys/ng-shared 3.0.0 → 3.0.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/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  ## Package Information
10
10
 
11
11
  - **Package:** `@flusys/ng-shared`
12
- - **Version:** 3.0.0
12
+ - **Version:** 3.0.1
13
13
  - **Dependencies:** ng-core
14
14
  - **Dependents:** ng-layout, ng-auth, ng-iam, ng-storage, flusysng
15
15
  - **Build Command:** `npm run build:ng-shared`
@@ -38,13 +38,13 @@ interface IBaseEntity {
38
38
 
39
39
  **Entity Mixins:**
40
40
 
41
- | Interface | Fields | Purpose |
42
- | --------------- | ---------------------------------- | ---------------------- |
43
- | `ISoftDeletable`| `deletedAt?: Date \| null` | Soft delete support |
44
- | `ITimestampable`| `createdAt, updatedAt` | Timestamp tracking |
45
- | `IActivatable` | `isActive: boolean` | Active status toggle |
46
- | `IOrderable` | `serial?: number \| null` | Ordering/sorting |
47
- | `IMetadata` | `metadata?: Record<string, unknown>` | JSON metadata field |
41
+ | Interface | Fields | Purpose |
42
+ | ---------------- | ------------------------------------ | -------------------- |
43
+ | `ISoftDeletable` | `deletedAt?: Date \| null` | Soft delete support |
44
+ | `ITimestampable` | `createdAt, updatedAt` | Timestamp tracking |
45
+ | `IActivatable` | `isActive: boolean` | Active status toggle |
46
+ | `IOrderable` | `serial?: number \| null` | Ordering/sorting |
47
+ | `IMetadata` | `metadata?: Record<string, unknown>` | JSON metadata field |
48
48
 
49
49
  #### ILoggedUserInfo
50
50
 
@@ -74,7 +74,9 @@ interface IPagination {
74
74
  currentPage: number;
75
75
  }
76
76
 
77
- interface ISort { [key: string]: 'ASC' | 'DESC' }
77
+ interface ISort {
78
+ [key: string]: "ASC" | "DESC";
79
+ }
78
80
 
79
81
  // Filter supports primitives and arrays for multi-value filtering
80
82
  interface IFilter {
@@ -98,10 +100,10 @@ interface IFilterData {
98
100
  Delete request payload matching backend DeleteDto.
99
101
 
100
102
  ```typescript
101
- type DeleteType = 'delete' | 'restore' | 'permanent';
103
+ type DeleteType = "delete" | "restore" | "permanent";
102
104
 
103
105
  interface IDeleteData {
104
- id: string | string[]; // Single or batch delete
106
+ id: string | string[]; // Single or batch delete
105
107
  type: DeleteType;
106
108
  }
107
109
  ```
@@ -124,7 +126,6 @@ interface IUserSelectFilter {
124
126
  page: number;
125
127
  pageSize: number;
126
128
  search: string;
127
- [key: string]: unknown;
128
129
  }
129
130
 
130
131
  type LoadUsersFn = (filter: IUserSelectFilter) => Observable<IListResponse<IUserBasicInfo>>;
@@ -151,7 +152,7 @@ interface IFileUploadOptions {
151
152
  }
152
153
 
153
154
  interface IUploadedFile {
154
- id?: string; // File manager ID (UUID) - available when registered
155
+ id?: string; // File manager ID (UUID) - available when registered
155
156
  name: string;
156
157
  key: string;
157
158
  size: number;
@@ -164,7 +165,6 @@ interface IFileSelectFilter {
164
165
  search: string;
165
166
  contentTypes?: string[];
166
167
  folderId?: string;
167
- [key: string]: unknown;
168
168
  }
169
169
 
170
170
  type LoadFilesFn = (filter: IFileSelectFilter) => Observable<IListResponse<IFileBasicInfo>>;
@@ -175,18 +175,18 @@ type GetFileUrlsFn = (fileIds: string[]) => Observable<ISingleResponse<IFileBasi
175
175
  **File Type Filters (Constants):**
176
176
 
177
177
  ```typescript
178
- import { FILE_TYPE_FILTERS, getAcceptString, isFileTypeAllowed, getFileIconClass, formatFileSize } from '@flusys/ng-shared';
179
-
180
- FILE_TYPE_FILTERS.IMAGES // ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml']
181
- FILE_TYPE_FILTERS.DOCUMENTS // ['application/pdf', 'application/msword', ...]
182
- FILE_TYPE_FILTERS.VIDEOS // ['video/mp4', 'video/webm', ...]
183
- FILE_TYPE_FILTERS.AUDIO // ['audio/mpeg', 'audio/wav', ...]
184
- FILE_TYPE_FILTERS.ALL // [] (allows all)
185
-
186
- getAcceptString(['image/*']) // 'image/*'
187
- isFileTypeAllowed(file, ['image/*']) // true/false
188
- getFileIconClass('image/png') // 'pi pi-image'
189
- formatFileSize(1024) // '1 KB'
178
+ import { FILE_TYPE_FILTERS, getAcceptString, isFileTypeAllowed, getFileIconClass, formatFileSize } from "@flusys/ng-shared";
179
+
180
+ FILE_TYPE_FILTERS.IMAGES; // ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml']
181
+ FILE_TYPE_FILTERS.DOCUMENTS; // ['application/pdf', 'application/msword', ...]
182
+ FILE_TYPE_FILTERS.VIDEOS; // ['video/mp4', 'video/webm', ...]
183
+ FILE_TYPE_FILTERS.AUDIO; // ['audio/mpeg', 'audio/wav', ...]
184
+ FILE_TYPE_FILTERS.ALL; // [] (allows all)
185
+
186
+ getAcceptString(["image/*"]); // 'image/*'
187
+ isFileTypeAllowed(file, ["image/*"]); // true/false
188
+ getFileIconClass("image/png"); // 'pi pi-image'
189
+ formatFileSize(1024); // '1 KB'
190
190
  ```
191
191
 
192
192
  ### Response Interfaces
@@ -242,12 +242,12 @@ type ApiResponse<T> = ISingleResponse<T> | IListResponse<T> | IBulkResponse<T> |
242
242
 
243
243
  **Metadata types:**
244
244
 
245
- | Interface | Fields |
246
- | ------------------ | -------------------------------------------- |
247
- | `IRequestMeta` | `requestId?, timestamp?, responseTime?` |
245
+ | Interface | Fields |
246
+ | ------------------ | ----------------------------------------------------- |
247
+ | `IRequestMeta` | `requestId?, timestamp?, responseTime?` |
248
248
  | `IPaginationMeta` | `total, page, pageSize, count, hasMore?, totalPages?` |
249
- | `IBulkMeta` | `count, failed?, total?` |
250
- | `IValidationError` | `field, message, constraint?` |
249
+ | `IBulkMeta` | `count, failed?, total?` |
250
+ | `IValidationError` | `field, message, constraint?` |
251
251
 
252
252
  ### Auth & Storage Response Types
253
253
 
@@ -292,14 +292,14 @@ Discriminated union for building complex permission logic trees.
292
292
  ```typescript
293
293
  // Single permission check
294
294
  interface IActionNode {
295
- type: 'action';
295
+ type: "action";
296
296
  actionId: string;
297
297
  }
298
298
 
299
299
  // Group with AND/OR logic
300
300
  interface IGroupNode {
301
- type: 'group';
302
- operator: 'AND' | 'OR';
301
+ type: "group";
302
+ operator: "AND" | "OR";
303
303
  children: ILogicNode[];
304
304
  }
305
305
 
@@ -374,25 +374,25 @@ Signal-based CRUD service using Angular 21 `resource()` API with **lazy initiali
374
374
  **ServiceName Type:**
375
375
 
376
376
  ```typescript
377
- type ServiceName = 'auth' | 'administration' | 'iam' | 'storage' | 'formBuilder' | 'email';
377
+ type ServiceName = "auth" | "administration" | "iam" | "storage" | "formBuilder" | "email";
378
378
  ```
379
379
 
380
380
  **Define a service:**
381
381
 
382
382
  ```typescript
383
- import { Injectable } from '@angular/core';
384
- import { HttpClient } from '@angular/common/http';
385
- import { ApiResourceService } from '@flusys/ng-shared';
383
+ import { Injectable } from "@angular/core";
384
+ import { HttpClient } from "@angular/common/http";
385
+ import { ApiResourceService } from "@flusys/ng-shared";
386
386
 
387
- @Injectable({ providedIn: 'root' })
387
+ @Injectable({ providedIn: "root" })
388
388
  export class UserService extends ApiResourceService<UserDto, IUser> {
389
389
  constructor(http: HttpClient) {
390
390
  // Option 1: Use global apiBaseUrl (default)
391
- super('users', http);
391
+ super("users", http);
392
392
  // Base URL: APP_CONFIG.apiBaseUrl + '/users'
393
393
 
394
394
  // Option 2: Use feature-specific service URL (recommended)
395
- super('users', http, 'administration');
395
+ super("users", http, "administration");
396
396
  // Base URL: APP_CONFIG.services.administration.baseUrl + '/users'
397
397
  }
398
398
  }
@@ -400,13 +400,14 @@ export class UserService extends ApiResourceService<UserDto, IUser> {
400
400
 
401
401
  **Constructor Parameters:**
402
402
 
403
- | Parameter | Type | Required | Description |
404
- |-----------|------|----------|-------------|
405
- | `moduleApiName` | `string` | Yes | API path segment (e.g., 'users', 'file-manager') |
406
- | `http` | `HttpClient` | Yes | Angular HttpClient instance |
407
- | `serviceName` | `ServiceName` | No | Feature service name for URL resolution |
403
+ | Parameter | Type | Required | Description |
404
+ | --------------- | ------------- | -------- | ------------------------------------------------ |
405
+ | `moduleApiName` | `string` | Yes | API path segment (e.g., 'users', 'file-manager') |
406
+ | `http` | `HttpClient` | Yes | Angular HttpClient instance |
407
+ | `serviceName` | `ServiceName` | No | Feature service name for URL resolution |
408
408
 
409
409
  **Service URL Resolution:**
410
+
410
411
  - If `serviceName` is provided, uses `getServiceUrl(config, serviceName)` to resolve the base URL
411
412
  - Falls back to `APP_CONFIG.apiBaseUrl` if service not found or `serviceName` not provided
412
413
 
@@ -416,7 +417,7 @@ The list resource is **lazy-initialized** to avoid unnecessary HTTP requests on
416
417
 
417
418
  ```typescript
418
419
  // Resource is NOT created until one of these is called:
419
- userService.fetchList('', { pagination: { currentPage: 0, pageSize: 10 } });
420
+ userService.fetchList("", { pagination: { currentPage: 0, pageSize: 10 } });
420
421
  // OR
421
422
  userService.initListResource(); // Explicit initialization
422
423
  ```
@@ -439,35 +440,35 @@ initListResource(): void {
439
440
 
440
441
  **Endpoint mapping:**
441
442
 
442
- | Method | HTTP | Endpoint | Response |
443
- | -------------- | ---- | ------------------------- | ------------------------ |
444
- | `insert(dto)` | POST | `/{resource}/insert` | `ISingleResponse<T>` |
445
- | `insertMany(dtos)` | POST | `/{resource}/insert-many` | `IBulkResponse<T>` |
446
- | `findById(id, select?)` | POST | `/{resource}/get/:id` | `ISingleResponse<T>` |
447
- | `getAll(search, filter)` | POST | `/{resource}/get-all?q=` | `IListResponse<T>` |
448
- | `update(dto)` | POST | `/{resource}/update` | `ISingleResponse<T>` |
449
- | `updateMany(dtos)` | POST | `/{resource}/update-many` | `IBulkResponse<T>` |
450
- | `delete(deleteDto)` | POST | `/{resource}/delete` | `IMessageResponse` |
443
+ | Method | HTTP | Endpoint | Response |
444
+ | ------------------------ | ---- | ------------------------- | -------------------- |
445
+ | `insert(dto)` | POST | `/{resource}/insert` | `ISingleResponse<T>` |
446
+ | `insertMany(dtos)` | POST | `/{resource}/insert-many` | `IBulkResponse<T>` |
447
+ | `findById(id, select?)` | POST | `/{resource}/get/:id` | `ISingleResponse<T>` |
448
+ | `getAll(search, filter)` | POST | `/{resource}/get-all?q=` | `IListResponse<T>` |
449
+ | `update(dto)` | POST | `/{resource}/update` | `ISingleResponse<T>` |
450
+ | `updateMany(dtos)` | POST | `/{resource}/update-many` | `IBulkResponse<T>` |
451
+ | `delete(deleteDto)` | POST | `/{resource}/delete` | `IMessageResponse` |
451
452
 
452
453
  All methods above return `Observable`. Async (Promise) variants are also available: `insertAsync`, `insertManyAsync`, `findByIdAsync`, `updateAsync`, `updateManyAsync`, `deleteAsync`.
453
454
 
454
455
  **Reactive signals:**
455
456
 
456
- | Signal | Type | Description |
457
- | ------------ | ------------------------- | ------------------------ |
458
- | `isLoading` | `Signal<boolean>` | Whether data is loading |
459
- | `data` | `Signal<T[]>` | Current list data |
460
- | `total` | `Signal<number>` | Total item count |
461
- | `pageInfo` | `Signal<IPaginationMeta>` | Pagination metadata |
462
- | `hasMore` | `Signal<boolean>` | More pages available |
463
- | `searchTerm` | `WritableSignal<string>` | Current search term |
457
+ | Signal | Type | Description |
458
+ | ------------ | ----------------------------- | ----------------------- |
459
+ | `isLoading` | `Signal<boolean>` | Whether data is loading |
460
+ | `data` | `Signal<T[]>` | Current list data |
461
+ | `total` | `Signal<number>` | Total item count |
462
+ | `pageInfo` | `Signal<IPaginationMeta>` | Pagination metadata |
463
+ | `hasMore` | `Signal<boolean>` | More pages available |
464
+ | `searchTerm` | `WritableSignal<string>` | Current search term |
464
465
  | `filterData` | `WritableSignal<IFilterData>` | Filter/pagination state |
465
466
 
466
467
  **List management:**
467
468
 
468
469
  ```typescript
469
470
  // Trigger data fetch (updates searchTerm and filterData signals, resource auto-reloads)
470
- userService.fetchList('search term', { pagination: { currentPage: 0, pageSize: 10 } });
471
+ userService.fetchList("search term", { pagination: { currentPage: 0, pageSize: 10 } });
471
472
 
472
473
  // Pagination helpers
473
474
  userService.setPagination({ currentPage: 1, pageSize: 20 });
@@ -530,14 +531,14 @@ export class ProductComponent {
530
531
 
531
532
  **Methods:**
532
533
 
533
- | Method | Returns | Description |
534
- | ----------------------------- | ----------------------------------- | ---------------------------------- |
535
- | `getFileUrl(fileId)` | `string \| null` | Get cached URL (synchronous) |
536
- | `fileUrlSignal(fileId)` | `Signal<string \| null>` | Computed signal from cache |
537
- | `fetchFileUrls(fileIds[])` | `Observable<FilesResponseDto[]>` | Fetch from backend, updates cache |
538
- | `fetchSingleFileUrl(fileId)` | `Observable<FilesResponseDto \| null>` | Fetch single file |
539
- | `clearCache()` | `void` | Clear all cached URLs |
540
- | `removeFromCache(fileId)` | `void` | Remove specific entry from cache |
534
+ | Method | Returns | Description |
535
+ | ---------------------------- | -------------------------------------- | --------------------------------- |
536
+ | `getFileUrl(fileId)` | `string \| null` | Get cached URL (synchronous) |
537
+ | `fileUrlSignal(fileId)` | `Signal<string \| null>` | Computed signal from cache |
538
+ | `fetchFileUrls(fileIds[])` | `Observable<FilesResponseDto[]>` | Fetch from backend, updates cache |
539
+ | `fetchSingleFileUrl(fileId)` | `Observable<FilesResponseDto \| null>` | Fetch single file |
540
+ | `clearCache()` | `void` | Clear all cached URLs |
541
+ | `removeFromCache(fileId)` | `void` | Remove specific entry from cache |
541
542
 
542
543
  ### PermissionValidatorService
543
544
 
@@ -569,18 +570,18 @@ export class MyComponent {
569
570
 
570
571
  **Methods:**
571
572
 
572
- | Method | Returns | Description |
573
- | ---------------------------- | --------- | ---------------------------------- |
574
- | `setPermissions(codes[])` | `void` | Replace all permissions |
575
- | `clearPermissions()` | `void` | Clear all permissions |
576
- | `hasPermission(code)` | `boolean` | Check single permission (supports wildcards) |
577
- | `isPermissionsLoaded()` | `boolean` | **Deprecated** - Use `isLoaded()` signal |
573
+ | Method | Returns | Description |
574
+ | ------------------------- | --------- | -------------------------------------------- |
575
+ | `setPermissions(codes[])` | `void` | Replace all permissions |
576
+ | `clearPermissions()` | `void` | Clear all permissions |
577
+ | `hasPermission(code)` | `boolean` | Check single permission (supports wildcards) |
578
+ | `isPermissionsLoaded()` | `boolean` | **Deprecated** - Use `isLoaded()` signal |
578
579
 
579
580
  **Signals:**
580
581
 
581
- | Signal | Type | Description |
582
- | ------------- | ------------------ | ------------------------------ |
583
- | `permissions` | `Signal<string[]>` | Readonly current permissions |
582
+ | Signal | Type | Description |
583
+ | ------------- | ------------------ | --------------------------------- |
584
+ | `permissions` | `Signal<string[]>` | Readonly current permissions |
584
585
  | `isLoaded` | `Signal<boolean>` | Whether permissions have been set |
585
586
 
586
587
  **Wildcard Support:**
@@ -589,13 +590,13 @@ The `hasPermission()` method uses the permission evaluator utility which support
589
590
 
590
591
  ```typescript
591
592
  // Exact match
592
- hasPermission('user.read') // true if permissions include 'user.read'
593
+ hasPermission("user.read"); // true if permissions include 'user.read'
593
594
 
594
595
  // Global wildcard
595
- hasPermission('user.read') // true if permissions include '*'
596
+ hasPermission("user.read"); // true if permissions include '*'
596
597
 
597
598
  // Module wildcard
598
- hasPermission('user.read') // true if permissions include 'user.*'
599
+ hasPermission("user.read"); // true if permissions include 'user.*'
599
600
  ```
600
601
 
601
602
  ### CookieService
@@ -603,7 +604,7 @@ hasPermission('user.read') // true if permissions include 'user.*'
603
604
  SSR-aware cookie reading service.
604
605
 
605
606
  ```typescript
606
- import { CookieService } from '@flusys/ng-shared';
607
+ import { CookieService } from "@flusys/ng-shared";
607
608
 
608
609
  const cookies = inject(CookieService).get(); // Returns document.cookie (browser) or request header cookie (server)
609
610
  ```
@@ -613,7 +614,7 @@ const cookies = inject(CookieService).get(); // Returns document.cookie (browser
613
614
  SSR environment detection service.
614
615
 
615
616
  ```typescript
616
- import { PlatformService } from '@flusys/ng-shared';
617
+ import { PlatformService } from "@flusys/ng-shared";
617
618
 
618
619
  const platform = inject(PlatformService);
619
620
  if (!platform.isServer) {
@@ -654,21 +655,7 @@ Single-select dropdown with lazy loading, search, and scroll pagination.
654
655
  ```typescript
655
656
  @Component({
656
657
  imports: [LazySelectComponent],
657
- template: `
658
- <lib-lazy-select
659
- [(value)]="selectedId"
660
- [selectDataList]="items()"
661
- [optionLabel]="'label'"
662
- [optionValue]="'value'"
663
- [isEditMode]="true"
664
- [isLoading]="loading()"
665
- [total]="total()"
666
- [pagination]="pagination()"
667
- [placeHolder]="'Select item'"
668
- (onSearch)="handleSearch($event)"
669
- (onPagination)="handlePagination($event)"
670
- />
671
- `,
658
+ template: ` <lib-lazy-select [(value)]="selectedId" [selectDataList]="items()" [optionLabel]="'label'" [optionValue]="'value'" [isEditMode]="true" [isLoading]="loading()" [total]="total()" [pagination]="pagination()" [placeHolder]="'Select item'" (onSearch)="handleSearch($event)" (onPagination)="handlePagination($event)" /> `,
672
659
  })
673
660
  export class MyComponent {
674
661
  readonly selectedId = signal<string | null>(null);
@@ -681,16 +668,16 @@ export class MyComponent {
681
668
 
682
669
  **Inputs:**
683
670
 
684
- | Input | Type | Description |
685
- | ---------------- | ----------------- | -------------------------------- |
686
- | `selectDataList` | `Array<IDropDown>` | Dropdown options (required) |
687
- | `optionLabel` | `string` | Label field name (required) |
688
- | `optionValue` | `string` | Value field name (required) |
689
- | `isEditMode` | `boolean` | Enable/disable editing (required)|
690
- | `isLoading` | `boolean` | Loading state (required) |
691
- | `total` | `number \| undefined` | Total items for pagination |
692
- | `pagination` | `IPagination` | Current pagination state |
693
- | `placeHolder` | `string` | Placeholder text (default: `'Select Option'`) |
671
+ | Input | Type | Description |
672
+ | ---------------- | --------------------- | --------------------------------------------- |
673
+ | `selectDataList` | `Array<IDropDown>` | Dropdown options (required) |
674
+ | `optionLabel` | `string` | Label field name (required) |
675
+ | `optionValue` | `string` | Value field name (required) |
676
+ | `isEditMode` | `boolean` | Enable/disable editing (required) |
677
+ | `isLoading` | `boolean` | Loading state (required) |
678
+ | `total` | `number \| undefined` | Total items for pagination |
679
+ | `pagination` | `IPagination` | Current pagination state |
680
+ | `placeHolder` | `string` | Placeholder text (default: `'Select Option'`) |
694
681
 
695
682
  **Model:** `value` - Two-way bound selected value (`string | null`)
696
683
 
@@ -707,19 +694,7 @@ Multi-select dropdown with lazy loading, search, select-all, and scroll paginati
707
694
  ```typescript
708
695
  @Component({
709
696
  imports: [LazyMultiSelectComponent],
710
- template: `
711
- <lib-lazy-multi-select
712
- [(value)]="selectedIds"
713
- [selectDataList]="items()"
714
- [isEditMode]="true"
715
- [isLoading]="loading()"
716
- [total]="total()"
717
- [pagination]="pagination()"
718
- [placeHolder]="'Select items'"
719
- (onSearch)="handleSearch($event)"
720
- (onPagination)="handlePagination($event)"
721
- />
722
- `,
697
+ template: ` <lib-lazy-multi-select [(value)]="selectedIds" [selectDataList]="items()" [isEditMode]="true" [isLoading]="loading()" [total]="total()" [pagination]="pagination()" [placeHolder]="'Select items'" (onSearch)="handleSearch($event)" (onPagination)="handlePagination($event)" /> `,
723
698
  })
724
699
  export class MyComponent {
725
700
  readonly selectedIds = signal<string[] | null>(null);
@@ -744,17 +719,10 @@ Single user selection with lazy loading. Uses `USER_PROVIDER` internally or acce
744
719
  imports: [UserSelectComponent],
745
720
  template: `
746
721
  <!-- Simple usage - uses USER_PROVIDER internally -->
747
- <lib-user-select
748
- [(value)]="selectedUserId"
749
- [isEditMode]="true"
750
- />
722
+ <lib-user-select [(value)]="selectedUserId" [isEditMode]="true" />
751
723
 
752
724
  <!-- With custom loadUsers function -->
753
- <lib-user-select
754
- [(value)]="selectedUserId"
755
- [isEditMode]="true"
756
- [loadUsers]="customLoadUsers"
757
- />
725
+ <lib-user-select [(value)]="selectedUserId" [isEditMode]="true" [loadUsers]="customLoadUsers" />
758
726
  `,
759
727
  })
760
728
  export class MyComponent {
@@ -764,14 +732,14 @@ export class MyComponent {
764
732
 
765
733
  **Inputs:**
766
734
 
767
- | Input | Type | Default | Description |
768
- | ----- | ---- | ------- | ----------- |
769
- | `isEditMode` | `boolean` | required | Enable/disable editing |
770
- | `placeHolder` | `string` | `'Select User'` | Placeholder text |
771
- | `filterActive` | `boolean` | `true` | Filter active users only |
772
- | `additionalFilters` | `Record<string, unknown>` | `{}` | Extra filter params |
773
- | `pageSize` | `number` | `20` | Page size for pagination |
774
- | `loadUsers` | `LoadUsersFn` | - | Custom user loading function |
735
+ | Input | Type | Default | Description |
736
+ | ------------------- | ------------------------- | --------------- | ---------------------------- |
737
+ | `isEditMode` | `boolean` | required | Enable/disable editing |
738
+ | `placeHolder` | `string` | `'Select User'` | Placeholder text |
739
+ | `filterActive` | `boolean` | `true` | Filter active users only |
740
+ | `additionalFilters` | `Record<string, unknown>` | `{}` | Extra filter params |
741
+ | `pageSize` | `number` | `20` | Page size for pagination |
742
+ | `loadUsers` | `LoadUsersFn` | - | Custom user loading function |
775
743
 
776
744
  **Model:** `value` - Two-way bound selected user ID (`string | null`)
777
745
 
@@ -787,12 +755,7 @@ Multiple user selection with lazy loading. Uses `USER_PROVIDER` internally or ac
787
755
  ```typescript
788
756
  @Component({
789
757
  imports: [UserMultiSelectComponent],
790
- template: `
791
- <lib-user-multi-select
792
- [(value)]="selectedUserIds"
793
- [isEditMode]="true"
794
- />
795
- `,
758
+ template: ` <lib-user-multi-select [(value)]="selectedUserIds" [isEditMode]="true" /> `,
796
759
  })
797
760
  export class MyComponent {
798
761
  readonly selectedUserIds = signal<string[] | null>(null);
@@ -816,44 +779,32 @@ Drag & drop file upload with type filtering. Pass your own `uploadFile` function
816
779
  imports: [FileUploaderComponent],
817
780
  template: `
818
781
  <!-- Single image upload -->
819
- <lib-file-uploader
820
- [uploadFile]="uploadFile"
821
- [acceptTypes]="['image/*']"
822
- [multiple]="false"
823
- (fileUploaded)="onFileUploaded($event)"
824
- />
782
+ <lib-file-uploader [uploadFile]="uploadFile" [acceptTypes]="['image/*']" [multiple]="false" (fileUploaded)="onFileUploaded($event)" />
825
783
 
826
784
  <!-- Multiple document upload -->
827
- <lib-file-uploader
828
- [uploadFile]="uploadFile"
829
- [acceptTypes]="FILE_TYPE_FILTERS.DOCUMENTS"
830
- [multiple]="true"
831
- [maxFiles]="5"
832
- (filesUploaded)="onFilesUploaded($event)"
833
- />
785
+ <lib-file-uploader [uploadFile]="uploadFile" [acceptTypes]="FILE_TYPE_FILTERS.DOCUMENTS" [multiple]="true" [maxFiles]="5" (filesUploaded)="onFilesUploaded($event)" />
834
786
  `,
835
787
  })
836
788
  export class MyComponent {
837
789
  readonly uploadService = inject(UploadService);
838
790
 
839
- readonly uploadFile: UploadFileFn = (file, options) =>
840
- this.uploadService.uploadSingleFile(file, options);
791
+ readonly uploadFile: UploadFileFn = (file, options) => this.uploadService.uploadSingleFile(file, options);
841
792
  }
842
793
  ```
843
794
 
844
795
  **Inputs:**
845
796
 
846
- | Input | Type | Default | Description |
847
- | ----- | ---- | ------- | ----------- |
848
- | `uploadFile` | `UploadFileFn` | required | Upload function |
849
- | `acceptTypes` | `string[]` | `[]` | Allowed MIME types |
850
- | `multiple` | `boolean` | `false` | Allow multiple files |
851
- | `maxFiles` | `number` | `10` | Max files for multiple |
852
- | `maxSizeMb` | `number` | `10` | Max file size in MB |
853
- | `uploadOptions` | `IFileUploadOptions` | `{}` | Upload options |
854
- | `disabled` | `boolean` | `false` | Disable uploader |
855
- | `showPreview` | `boolean` | `true` | Show selected files preview |
856
- | `autoUpload` | `boolean` | `true` | Upload immediately on selection |
797
+ | Input | Type | Default | Description |
798
+ | --------------- | -------------------- | -------- | ------------------------------- |
799
+ | `uploadFile` | `UploadFileFn` | required | Upload function |
800
+ | `acceptTypes` | `string[]` | `[]` | Allowed MIME types |
801
+ | `multiple` | `boolean` | `false` | Allow multiple files |
802
+ | `maxFiles` | `number` | `10` | Max files for multiple |
803
+ | `maxSizeMb` | `number` | `10` | Max file size in MB |
804
+ | `uploadOptions` | `IFileUploadOptions` | `{}` | Upload options |
805
+ | `disabled` | `boolean` | `false` | Disable uploader |
806
+ | `showPreview` | `boolean` | `true` | Show selected files preview |
807
+ | `autoUpload` | `boolean` | `true` | Upload immediately on selection |
857
808
 
858
809
  **Outputs:** `fileUploaded` (IUploadedFile), `filesUploaded` (IUploadedFile[]), `onError` (Error), `fileSelected` (File[])
859
810
 
@@ -866,15 +817,7 @@ Dialog to browse and select existing files with filtering.
866
817
  ```typescript
867
818
  @Component({
868
819
  imports: [FileSelectorDialogComponent],
869
- template: `
870
- <lib-file-selector-dialog
871
- [(visible)]="showFileSelector"
872
- [loadFiles]="loadFiles"
873
- [acceptTypes]="['image/*']"
874
- [multiple]="false"
875
- (fileSelected)="onFileSelected($event)"
876
- />
877
- `,
820
+ template: ` <lib-file-selector-dialog [(visible)]="showFileSelector" [loadFiles]="loadFiles" [acceptTypes]="['image/*']" [multiple]="false" (fileSelected)="onFileSelected($event)" /> `,
878
821
  })
879
822
  export class MyComponent {
880
823
  readonly showFileSelector = signal(false);
@@ -889,14 +832,14 @@ export class MyComponent {
889
832
 
890
833
  **Inputs:**
891
834
 
892
- | Input | Type | Default | Description |
893
- | ----- | ---- | ------- | ----------- |
894
- | `loadFiles` | `LoadFilesFn` | required | File loading function |
895
- | `header` | `string` | `'Select File'` | Dialog header |
896
- | `acceptTypes` | `string[]` | `[]` | Allowed MIME types |
897
- | `multiple` | `boolean` | `false` | Allow multiple selection |
898
- | `maxSelection` | `number` | `10` | Max files for multiple |
899
- | `pageSize` | `number` | `20` | Page size for pagination |
835
+ | Input | Type | Default | Description |
836
+ | -------------- | ------------- | --------------- | ------------------------ |
837
+ | `loadFiles` | `LoadFilesFn` | required | File loading function |
838
+ | `header` | `string` | `'Select File'` | Dialog header |
839
+ | `acceptTypes` | `string[]` | `[]` | Allowed MIME types |
840
+ | `multiple` | `boolean` | `false` | Allow multiple selection |
841
+ | `maxSelection` | `number` | `10` | Max files for multiple |
842
+ | `pageSize` | `number` | `20` | Page size for pagination |
900
843
 
901
844
  **Model:** `visible` - Two-way bound dialog visibility (`boolean`)
902
845
 
@@ -914,7 +857,7 @@ Structural directive for permission-based rendering. Fail-closed: hides content
914
857
  - **Input:** `hasPermission` - `string | ILogicNode | null`
915
858
 
916
859
  ```typescript
917
- import { HasPermissionDirective, ILogicNode } from '@flusys/ng-shared';
860
+ import { HasPermissionDirective, ILogicNode } from "@flusys/ng-shared";
918
861
 
919
862
  @Component({
920
863
  imports: [HasPermissionDirective],
@@ -928,11 +871,11 @@ import { HasPermissionDirective, ILogicNode } from '@flusys/ng-shared';
928
871
  })
929
872
  export class MyComponent {
930
873
  readonly editLogic: ILogicNode = {
931
- type: 'group',
932
- operator: 'AND',
874
+ type: "group",
875
+ operator: "AND",
933
876
  children: [
934
- { type: 'action', actionId: 'user.view' },
935
- { type: 'action', actionId: 'user.update' },
877
+ { type: "action", actionId: "user.view" },
878
+ { type: "action", actionId: "user.update" },
936
879
  ],
937
880
  };
938
881
  }
@@ -946,8 +889,7 @@ Toggles readonly/disabled state for form controls based on edit mode. Supports `
946
889
  - **Input:** `isEditMode` (required boolean)
947
890
 
948
891
  ```html
949
- <input [appEditModeElementChanger] [isEditMode]="isEditing()" />
950
- <p-select [appEditModeElementChanger] [isEditMode]="isEditing()" />
892
+ <input [appEditModeElementChanger] [isEditMode]="isEditing()" /> <p-select [appEditModeElementChanger] [isEditMode]="isEditing()" />
951
893
  ```
952
894
 
953
895
  ### IsEmptyImageDirective
@@ -972,8 +914,7 @@ Prevents default browser behavior on specified events and emits the event.
972
914
  - **Output:** `action` - Emits the prevented event
973
915
 
974
916
  ```html
975
- <a href="#" appPreventDefault (action)="handleClick($event)">Click me</a>
976
- <input appPreventDefault eventType="keydown" preventKey="Enter" (action)="onEnter($event)" />
917
+ <a href="#" appPreventDefault (action)="handleClick($event)">Click me</a> <input appPreventDefault eventType="keydown" preventKey="Enter" (action)="onEnter($event)" />
977
918
  ```
978
919
 
979
920
  ---
@@ -987,24 +928,29 @@ Route-level guards for permission-based access control. All guards deny access w
987
928
  Single permission or complex logic check.
988
929
 
989
930
  ```typescript
990
- import { permissionGuard } from '@flusys/ng-shared';
931
+ import { permissionGuard } from "@flusys/ng-shared";
991
932
 
992
933
  const routes: Routes = [
993
934
  // Simple permission
994
- { path: 'users', canActivate: [permissionGuard('user.view')] },
935
+ { path: "users", canActivate: [permissionGuard("user.view")] },
995
936
 
996
937
  // Complex logic (ILogicNode)
997
- { path: 'admin', canActivate: [permissionGuard({
998
- type: 'group',
999
- operator: 'AND',
1000
- children: [
1001
- { type: 'action', actionId: 'admin.view' },
1002
- { type: 'action', actionId: 'admin.manage' },
938
+ {
939
+ path: "admin",
940
+ canActivate: [
941
+ permissionGuard({
942
+ type: "group",
943
+ operator: "AND",
944
+ children: [
945
+ { type: "action", actionId: "admin.view" },
946
+ { type: "action", actionId: "admin.manage" },
947
+ ],
948
+ }),
1003
949
  ],
1004
- })] },
950
+ },
1005
951
 
1006
952
  // Custom redirect on deny
1007
- { path: 'settings', canActivate: [permissionGuard('settings.view', '/access-denied')] },
953
+ { path: "settings", canActivate: [permissionGuard("settings.view", "/access-denied")] },
1008
954
  ];
1009
955
  ```
1010
956
 
@@ -1033,34 +979,34 @@ AND logic - allows access only if user has ALL specified permissions.
1033
979
  Pure functions for permission logic evaluation. Used internally by `HasPermissionDirective` and guards. **Supports wildcard permissions.**
1034
980
 
1035
981
  ```typescript
1036
- import { evaluatePermission, evaluateLogicNode, hasAnyPermission, hasAllPermissions, hasPermission } from '@flusys/ng-shared';
982
+ import { evaluatePermission, evaluateLogicNode, hasAnyPermission, hasAllPermissions, hasPermission } from "@flusys/ng-shared";
1037
983
 
1038
- const userPermissions = ['user.view', 'user.create', 'admin.*'];
984
+ const userPermissions = ["user.view", "user.create", "admin.*"];
1039
985
 
1040
986
  // Low-level hasPermission check with wildcard support
1041
- hasPermission('user.view', userPermissions); // true (exact match)
1042
- hasPermission('admin.manage', userPermissions); // true (matches 'admin.*')
1043
- hasPermission('settings.view', ['*']); // true (global wildcard)
987
+ hasPermission("user.view", userPermissions); // true (exact match)
988
+ hasPermission("admin.manage", userPermissions); // true (matches 'admin.*')
989
+ hasPermission("settings.view", ["*"]); // true (global wildcard)
1044
990
 
1045
991
  // Evaluate string or ILogicNode
1046
- evaluatePermission('user.view', userPermissions); // true
1047
- evaluatePermission(null, userPermissions); // false
992
+ evaluatePermission("user.view", userPermissions); // true
993
+ evaluatePermission(null, userPermissions); // false
1048
994
 
1049
995
  // Evaluate ILogicNode tree recursively
1050
996
  evaluateLogicNode(logicNode, userPermissions);
1051
997
 
1052
998
  // Simple OR/AND checks (also support wildcards)
1053
- hasAnyPermission(['user.view', 'user.delete'], userPermissions); // true (has user.view)
1054
- hasAllPermissions(['user.view', 'user.delete'], userPermissions); // false (missing user.delete)
999
+ hasAnyPermission(["user.view", "user.delete"], userPermissions); // true (has user.view)
1000
+ hasAllPermissions(["user.view", "user.delete"], userPermissions); // false (missing user.delete)
1055
1001
  ```
1056
1002
 
1057
1003
  **Wildcard Rules:**
1058
1004
 
1059
- | Pattern | Matches |
1060
- |---------|---------|
1061
- | `*` | All permissions (global wildcard) |
1062
- | `module.*` | All permissions starting with `module.` |
1063
- | `user.read` | Exact match only |
1005
+ | Pattern | Matches |
1006
+ | ----------- | --------------------------------------- |
1007
+ | `*` | All permissions (global wildcard) |
1008
+ | `module.*` | All permissions starting with `module.` |
1009
+ | `user.read` | Exact match only |
1064
1010
 
1065
1011
  **Implementation Details:**
1066
1012
 
@@ -1072,10 +1018,10 @@ export function hasPermission(requiredPermission: string, userPermissions: strin
1072
1018
  // Wildcard matching
1073
1019
  for (const permission of userPermissions) {
1074
1020
  // Global wildcard
1075
- if (permission === '*') return true;
1021
+ if (permission === "*") return true;
1076
1022
 
1077
1023
  // Module wildcard (e.g., 'user.*' matches 'user.read')
1078
- if (permission.endsWith('.*')) {
1024
+ if (permission.endsWith(".*")) {
1079
1025
  const prefix = permission.slice(0, -1); // 'user.'
1080
1026
  if (requiredPermission.startsWith(prefix)) return true;
1081
1027
  }
@@ -1119,10 +1065,10 @@ onScroll(event: Event): void {
1119
1065
  Abstract base class for custom form controls. Implements both `ControlValueAccessor` (reactive forms) and `FormValueControl` (signal forms).
1120
1066
 
1121
1067
  ```typescript
1122
- import { BaseFormControl, provideValueAccessor } from '@flusys/ng-shared';
1068
+ import { BaseFormControl, provideValueAccessor } from "@flusys/ng-shared";
1123
1069
 
1124
1070
  @Component({
1125
- selector: 'my-select',
1071
+ selector: "my-select",
1126
1072
  providers: [provideValueAccessor(MySelectComponent)],
1127
1073
  })
1128
1074
  export class MySelectComponent extends BaseFormControl<string | null> {
@@ -1226,7 +1172,7 @@ export class UserListComponent extends BaseListPage<IUser> {
1226
1172
  Re-exports common Angular modules for convenience.
1227
1173
 
1228
1174
  ```typescript
1229
- import { AngularModule } from '@flusys/ng-shared';
1175
+ import { AngularModule } from "@flusys/ng-shared";
1230
1176
  // Includes: CommonModule, FormsModule, ReactiveFormsModule, RouterLink, RouterOutlet,
1231
1177
  // RouterLinkActive, NgOptimizedImage, NgComponentOutlet, + directives (IsEmptyImageDirective, PreventDefaultDirective)
1232
1178
  // Providers: DatePipe
@@ -1237,7 +1183,7 @@ import { AngularModule } from '@flusys/ng-shared';
1237
1183
  Re-exports PrimeNG component modules for convenience.
1238
1184
 
1239
1185
  ```typescript
1240
- import { PrimeModule } from '@flusys/ng-shared';
1186
+ import { PrimeModule } from "@flusys/ng-shared";
1241
1187
  // Includes 30 modules:
1242
1188
  // - Layout: AccordionModule, CardModule, DividerModule, PanelModule, SplitterModule, TabsModule, ToolbarModule
1243
1189
  // - Form: AutoCompleteModule, CheckboxModule, DatePickerModule, InputTextModule, InputTextareaModule,
@@ -1273,13 +1219,14 @@ ng-iam/ng-storage (consume interfaces via DI)
1273
1219
  User list access for IAM user selection.
1274
1220
 
1275
1221
  ```typescript
1276
- interface IUserBasicInfo { id: string; name: string; email: string }
1222
+ interface IUserBasicInfo {
1223
+ id: string;
1224
+ name: string;
1225
+ email: string;
1226
+ }
1277
1227
 
1278
1228
  interface IUserProvider {
1279
- getUsers(filter?: {
1280
- page?: number; pageSize?: number; search?: string;
1281
- companyId?: string; branchId?: string;
1282
- }): Observable<IListResponse<IUserBasicInfo>>;
1229
+ getUsers(filter?: { page?: number; pageSize?: number; search?: string; companyId?: string; branchId?: string }): Observable<IListResponse<IUserBasicInfo>>;
1283
1230
  }
1284
1231
  ```
1285
1232
 
@@ -1290,12 +1237,14 @@ interface IUserProvider {
1290
1237
  Company list access for IAM company selection.
1291
1238
 
1292
1239
  ```typescript
1293
- interface ICompanyBasicInfo { id: string; name: string; slug?: string }
1240
+ interface ICompanyBasicInfo {
1241
+ id: string;
1242
+ name: string;
1243
+ slug?: string;
1244
+ }
1294
1245
 
1295
1246
  interface ICompanyApiProvider {
1296
- getCompanies(filter?: {
1297
- page?: number; pageSize?: number; search?: string;
1298
- }): Observable<IListResponse<ICompanyBasicInfo>>;
1247
+ getCompanies(filter?: { page?: number; pageSize?: number; search?: string }): Observable<IListResponse<ICompanyBasicInfo>>;
1299
1248
  }
1300
1249
  ```
1301
1250
 
@@ -1325,10 +1274,10 @@ Profile picture upload for ng-auth profile page. Implemented by ng-storage. **Op
1325
1274
 
1326
1275
  ```typescript
1327
1276
  interface IProfileUploadResult {
1328
- id: string; // File manager ID (UUID)
1329
- name: string; // Original file name
1330
- key: string; // Storage key/path
1331
- size: number; // File size in bytes
1277
+ id: string; // File manager ID (UUID)
1278
+ name: string; // Original file name
1279
+ key: string; // Storage key/path
1280
+ size: number; // File size in bytes
1332
1281
  contentType: string; // MIME type
1333
1282
  }
1334
1283
 
@@ -1340,10 +1289,7 @@ interface IProfileUploadOptions {
1340
1289
  }
1341
1290
 
1342
1291
  interface IProfileUploadProvider {
1343
- uploadProfilePicture(
1344
- file: File,
1345
- options?: IProfileUploadOptions
1346
- ): Observable<ISingleResponse<IProfileUploadResult>>;
1292
+ uploadProfilePicture(file: File, options?: IProfileUploadOptions): Observable<ISingleResponse<IProfileUploadResult>>;
1347
1293
  }
1348
1294
  ```
1349
1295
 
@@ -1417,14 +1363,13 @@ interface IUserListItem {
1417
1363
  email: string;
1418
1364
  phone?: string;
1419
1365
  isActive?: boolean;
1420
- [key: string]: unknown;
1421
1366
  }
1422
1367
 
1423
1368
  interface IUserListAction<T = IUserListItem> {
1424
1369
  id: string;
1425
1370
  label: string;
1426
1371
  icon?: string;
1427
- severity?: 'primary' | 'secondary' | 'success' | 'info' | 'warn' | 'danger';
1372
+ severity?: "primary" | "secondary" | "success" | "info" | "warn" | "danger";
1428
1373
  permission?: string;
1429
1374
  tooltip?: string;
1430
1375
  disabled?: boolean | ((user: T) => boolean);
@@ -1436,7 +1381,7 @@ interface IUserListColumn {
1436
1381
  header: string;
1437
1382
  width?: string;
1438
1383
  sortable?: boolean;
1439
- templateType?: 'text' | 'badge' | 'date' | 'boolean' | 'custom';
1384
+ templateType?: "text" | "badge" | "date" | "boolean" | "custom";
1440
1385
  }
1441
1386
 
1442
1387
  interface IUserListFilter {
@@ -1446,7 +1391,6 @@ interface IUserListFilter {
1446
1391
  isActive?: boolean;
1447
1392
  companyId?: string;
1448
1393
  branchId?: string;
1449
- [key: string]: unknown;
1450
1394
  }
1451
1395
 
1452
1396
  interface IUserListProvider<T extends IUserListItem = IUserListItem> {
@@ -1463,17 +1407,13 @@ interface IUserListProvider<T extends IUserListItem = IUserListItem> {
1463
1407
 
1464
1408
  ```typescript
1465
1409
  // In app.config.ts
1466
- providers: [
1467
- { provide: USER_LIST_PROVIDER, useClass: MyUserListProvider },
1468
- ]
1410
+ providers: [{ provide: USER_LIST_PROVIDER, useClass: MyUserListProvider }];
1469
1411
 
1470
1412
  // Implementation
1471
- @Injectable({ providedIn: 'root' })
1413
+ @Injectable({ providedIn: "root" })
1472
1414
  export class MyUserListProvider implements IUserListProvider {
1473
1415
  getExtraRowActions() {
1474
- return [
1475
- { id: 'assign-role', label: 'Assign Role', icon: 'pi pi-users' },
1476
- ];
1416
+ return [{ id: "assign-role", label: "Assign Role", icon: "pi pi-users" }];
1477
1417
  }
1478
1418
  }
1479
1419
  ```
@@ -1481,13 +1421,13 @@ export class MyUserListProvider implements IUserListProvider {
1481
1421
  ### Usage in Consuming Packages
1482
1422
 
1483
1423
  ```typescript
1484
- import { USER_PROVIDER } from '@flusys/ng-shared';
1424
+ import { USER_PROVIDER } from "@flusys/ng-shared";
1485
1425
 
1486
1426
  export class UserSelectorComponent {
1487
1427
  private readonly userProvider = inject(USER_PROVIDER);
1488
1428
 
1489
1429
  loadUsers() {
1490
- this.userProvider.getUsers({ page: 0, pageSize: 50 }).subscribe(response => {
1430
+ this.userProvider.getUsers({ page: 0, pageSize: 50 }).subscribe((response) => {
1491
1431
  this.users.set(response.data ?? []);
1492
1432
  });
1493
1433
  }
@@ -1498,7 +1438,7 @@ export class UserSelectorComponent {
1498
1438
 
1499
1439
  ```typescript
1500
1440
  // app.config.ts
1501
- import { provideAuthProviders } from '@flusys/ng-auth';
1441
+ import { provideAuthProviders } from "@flusys/ng-auth";
1502
1442
 
1503
1443
  export const appConfig: ApplicationConfig = {
1504
1444
  providers: [
@@ -1598,12 +1538,10 @@ providers: [
1598
1538
  { provide: COMPANY_API_PROVIDER, useClass: AuthCompanyApiProvider },
1599
1539
  { provide: USER_PERMISSION_PROVIDER, useClass: AuthUserPermissionProvider },
1600
1540
  { provide: AUTH_STATE_PROVIDER, useClass: AuthStateProviderAdapter },
1601
- ]
1541
+ ];
1602
1542
 
1603
1543
  // OR use the convenience function
1604
- providers: [
1605
- ...provideAuthProviders(),
1606
- ]
1544
+ providers: [...provideAuthProviders()];
1607
1545
  ```
1608
1546
 
1609
1547
  ### Permissions Not Working
@@ -1622,107 +1560,107 @@ providers: [
1622
1560
 
1623
1561
  ### Services
1624
1562
 
1625
- | Service | Description |
1626
- | ------------------------------ | ------------------------------------- |
1627
- | `ApiResourceService<DTO, T>` | Signal-based CRUD with resource() API (lazy-initialized, accepts optional `serviceName`) |
1628
- | `FileUrlService` | Cloud storage URL fetching |
1629
- | `PermissionValidatorService` | Permission state management with wildcards |
1630
- | `CookieService` | SSR-aware cookie reading |
1631
- | `PlatformService` | SSR environment detection |
1563
+ | Service | Description |
1564
+ | ---------------------------- | ---------------------------------------------------------------------------------------- |
1565
+ | `ApiResourceService<DTO, T>` | Signal-based CRUD with resource() API (lazy-initialized, accepts optional `serviceName`) |
1566
+ | `FileUrlService` | Cloud storage URL fetching |
1567
+ | `PermissionValidatorService` | Permission state management with wildcards |
1568
+ | `CookieService` | SSR-aware cookie reading |
1569
+ | `PlatformService` | SSR environment detection |
1632
1570
 
1633
1571
  ### Classes
1634
1572
 
1635
- | Class | Description |
1636
- | ------------------------ | -------------------------------------------- |
1637
- | `ApiResourceService` | Signal-based CRUD base class (alias: `ApiService`) |
1638
- | `BaseFormControl` | Abstract base for custom form controls |
1639
- | `BaseFormPage` | Abstract directive for create/edit pages |
1640
- | `BaseListPage` | Abstract directive for list pages |
1573
+ | Class | Description |
1574
+ | -------------------- | -------------------------------------------------- |
1575
+ | `ApiResourceService` | Signal-based CRUD base class (alias: `ApiService`) |
1576
+ | `BaseFormControl` | Abstract base for custom form controls |
1577
+ | `BaseFormPage` | Abstract directive for create/edit pages |
1578
+ | `BaseListPage` | Abstract directive for list pages |
1641
1579
 
1642
1580
  ### Constants
1643
1581
 
1644
- | Constant | Description |
1645
- | -------------- | --------------------------------------------- |
1646
- | `PERMISSIONS` | Aggregated permission codes by module |
1647
- | `USER_PERMISSIONS` | `{ CREATE, READ, UPDATE, DELETE }` for users |
1648
- | `ROLE_PERMISSIONS` | `{ CREATE, READ, UPDATE, DELETE }` for roles |
1649
- | `FILE_PERMISSIONS` | `{ CREATE, READ, UPDATE, DELETE }` for files |
1582
+ | Constant | Description |
1583
+ | ------------------- | ----------------------------------------------------- |
1584
+ | `PERMISSIONS` | Aggregated permission codes by module |
1585
+ | `USER_PERMISSIONS` | `{ CREATE, READ, UPDATE, DELETE }` for users |
1586
+ | `ROLE_PERMISSIONS` | `{ CREATE, READ, UPDATE, DELETE }` for roles |
1587
+ | `FILE_PERMISSIONS` | `{ CREATE, READ, UPDATE, DELETE }` for files |
1650
1588
  | `FILE_TYPE_FILTERS` | Predefined MIME type arrays (IMAGES, DOCUMENTS, etc.) |
1651
1589
 
1652
1590
  ### Components
1653
1591
 
1654
- | Component | Selector | Description |
1655
- | -------------------------- | ---------------------- | ------------------------- |
1656
- | `IconComponent` | `lib-icon` | Flexible icon renderer |
1657
- | `LazySelectComponent` | `lib-lazy-select` | Lazy-loading dropdown |
1658
- | `LazyMultiSelectComponent` | `lib-lazy-multi-select`| Lazy-loading multi-select |
1659
- | `UserSelectComponent` | `lib-user-select` | Single user selector |
1660
- | `UserMultiSelectComponent` | `lib-user-multi-select`| Multiple user selector |
1661
- | `FileUploaderComponent` | `lib-file-uploader` | Drag & drop file upload |
1662
- | `FileSelectorDialogComponent` | `lib-file-selector-dialog` | File browser dialog |
1592
+ | Component | Selector | Description |
1593
+ | ----------------------------- | -------------------------- | ------------------------- |
1594
+ | `IconComponent` | `lib-icon` | Flexible icon renderer |
1595
+ | `LazySelectComponent` | `lib-lazy-select` | Lazy-loading dropdown |
1596
+ | `LazyMultiSelectComponent` | `lib-lazy-multi-select` | Lazy-loading multi-select |
1597
+ | `UserSelectComponent` | `lib-user-select` | Single user selector |
1598
+ | `UserMultiSelectComponent` | `lib-user-multi-select` | Multiple user selector |
1599
+ | `FileUploaderComponent` | `lib-file-uploader` | Drag & drop file upload |
1600
+ | `FileSelectorDialogComponent` | `lib-file-selector-dialog` | File browser dialog |
1663
1601
 
1664
1602
  ### Directives
1665
1603
 
1666
- | Directive | Selector | Description |
1667
- | --------------------------------- | --------------------------- | ----------------------------------- |
1668
- | `HasPermissionDirective` | `[hasPermission]` | Permission-based rendering |
1604
+ | Directive | Selector | Description |
1605
+ | --------------------------------- | ----------------------------- | --------------------------------- |
1606
+ | `HasPermissionDirective` | `[hasPermission]` | Permission-based rendering |
1669
1607
  | `EditModeElementChangerDirective` | `[appEditModeElementChanger]` | Toggle edit mode on form controls |
1670
- | `IsEmptyImageDirective` | `img` | Image fallback on error/empty |
1671
- | `PreventDefaultDirective` | `[appPreventDefault]` | Prevent default event behavior |
1608
+ | `IsEmptyImageDirective` | `img` | Image fallback on error/empty |
1609
+ | `PreventDefaultDirective` | `[appPreventDefault]` | Prevent default event behavior |
1672
1610
 
1673
1611
  ### Guards
1674
1612
 
1675
- | Guard | Description |
1676
- | ---------------------- | -------------------------------------- |
1677
- | `permissionGuard` | Single permission or ILogicNode check |
1678
- | `anyPermissionGuard` | OR logic (any of listed permissions) |
1679
- | `allPermissionsGuard` | AND logic (all of listed permissions) |
1613
+ | Guard | Description |
1614
+ | --------------------- | ------------------------------------- |
1615
+ | `permissionGuard` | Single permission or ILogicNode check |
1616
+ | `anyPermissionGuard` | OR logic (any of listed permissions) |
1617
+ | `allPermissionsGuard` | AND logic (all of listed permissions) |
1680
1618
 
1681
1619
  ### Interfaces
1682
1620
 
1683
- | Interface | Description |
1684
- | -------------------- | ------------------------------------ |
1685
- | `IBaseEntity` | Base entity with ID and timestamps |
1686
- | `ILoggedUserInfo` | Current user info with company ctx |
1687
- | `IFilterData` | Filter, pagination, sort payload |
1688
- | `IFilter` | Filter object (supports arrays) |
1689
- | `IDeleteData` | Delete request payload |
1690
- | `IDropDown` | Simple label/value pair |
1691
- | `ISingleResponse<T>` | Single item response |
1692
- | `IListResponse<T>` | List with pagination |
1693
- | `IBulkResponse<T>` | Bulk operation response |
1694
- | `IMessageResponse` | Message-only response |
1695
- | `IErrorResponse` | Error with validation details |
1696
- | `ILogicNode` | Permission logic tree (AND/OR nodes) |
1697
- | `IUserSelectFilter` | User select filter params |
1698
- | `LoadUsersFn` | User loading function type |
1699
- | `IFileBasicInfo` | Basic file info for selectors |
1700
- | `IFileUploadOptions`| Upload options (compression, etc.) |
1701
- | `IUploadedFile` | Uploaded file response |
1702
- | `IFileSelectFilter` | File select filter params |
1703
- | `LoadFilesFn` | File loading function type |
1704
- | `UploadFileFn` | File upload function type |
1705
- | `FilesResponseDto` | File URL service response |
1706
- | `IAuthStateProvider`| Auth state provider interface |
1707
- | `IUserListProvider` | User list extensions provider |
1708
- | `IUserListItem` | Base user for list operations |
1709
- | `IUserListAction` | User list action definition |
1710
- | `IUserListColumn` | Extra column for user list |
1711
- | `IUserListFilter` | User list filter parameters |
1712
- | `IUserBranchPermission` | User permissions per branch |
1713
- | `ServiceName` | `'auth' \| 'administration' \| 'iam' \| 'storage' \| 'formBuilder' \| 'email'` |
1621
+ | Interface | Description |
1622
+ | ----------------------- | ------------------------------------------------------------------------------ |
1623
+ | `IBaseEntity` | Base entity with ID and timestamps |
1624
+ | `ILoggedUserInfo` | Current user info with company ctx |
1625
+ | `IFilterData` | Filter, pagination, sort payload |
1626
+ | `IFilter` | Filter object (supports arrays) |
1627
+ | `IDeleteData` | Delete request payload |
1628
+ | `IDropDown` | Simple label/value pair |
1629
+ | `ISingleResponse<T>` | Single item response |
1630
+ | `IListResponse<T>` | List with pagination |
1631
+ | `IBulkResponse<T>` | Bulk operation response |
1632
+ | `IMessageResponse` | Message-only response |
1633
+ | `IErrorResponse` | Error with validation details |
1634
+ | `ILogicNode` | Permission logic tree (AND/OR nodes) |
1635
+ | `IUserSelectFilter` | User select filter params |
1636
+ | `LoadUsersFn` | User loading function type |
1637
+ | `IFileBasicInfo` | Basic file info for selectors |
1638
+ | `IFileUploadOptions` | Upload options (compression, etc.) |
1639
+ | `IUploadedFile` | Uploaded file response |
1640
+ | `IFileSelectFilter` | File select filter params |
1641
+ | `LoadFilesFn` | File loading function type |
1642
+ | `UploadFileFn` | File upload function type |
1643
+ | `FilesResponseDto` | File URL service response |
1644
+ | `IAuthStateProvider` | Auth state provider interface |
1645
+ | `IUserListProvider` | User list extensions provider |
1646
+ | `IUserListItem` | Base user for list operations |
1647
+ | `IUserListAction` | User list action definition |
1648
+ | `IUserListColumn` | Extra column for user list |
1649
+ | `IUserListFilter` | User list filter parameters |
1650
+ | `IUserBranchPermission` | User permissions per branch |
1651
+ | `ServiceName` | `'auth' \| 'administration' \| 'iam' \| 'storage' \| 'formBuilder' \| 'email'` |
1714
1652
 
1715
1653
  ### Injection Tokens
1716
1654
 
1717
- | Token | Interface | Optional | Description |
1718
- | -------------------------- | ------------------------- | -------- | ---------------------------- |
1719
- | `USER_PROVIDER` | `IUserProvider` | No | User list for IAM |
1720
- | `COMPANY_API_PROVIDER` | `ICompanyApiProvider` | No | Company list for IAM |
1721
- | `USER_PERMISSION_PROVIDER` | `IUserPermissionProvider` | No | User permission queries |
1722
- | `AUTH_STATE_PROVIDER` | `IAuthStateProvider` | No | Auth state for feature packages |
1723
- | `PROFILE_UPLOAD_PROVIDER` | `IProfileUploadProvider` | Yes | Profile picture upload (ng-storage) |
1724
- | `PROFILE_PERMISSION_PROVIDER` | `IProfilePermissionProvider` | Yes | User permissions for profile (ng-iam) |
1725
- | `USER_LIST_PROVIDER` | `IUserListProvider` | Yes | User list extensions |
1655
+ | Token | Interface | Optional | Description |
1656
+ | ----------------------------- | ---------------------------- | -------- | ------------------------------------- |
1657
+ | `USER_PROVIDER` | `IUserProvider` | No | User list for IAM |
1658
+ | `COMPANY_API_PROVIDER` | `ICompanyApiProvider` | No | Company list for IAM |
1659
+ | `USER_PERMISSION_PROVIDER` | `IUserPermissionProvider` | No | User permission queries |
1660
+ | `AUTH_STATE_PROVIDER` | `IAuthStateProvider` | No | Auth state for feature packages |
1661
+ | `PROFILE_UPLOAD_PROVIDER` | `IProfileUploadProvider` | Yes | Profile picture upload (ng-storage) |
1662
+ | `PROFILE_PERMISSION_PROVIDER` | `IProfilePermissionProvider` | Yes | User permissions for profile (ng-iam) |
1663
+ | `USER_LIST_PROVIDER` | `IUserListProvider` | Yes | User list extensions |
1726
1664
 
1727
1665
  ## See Also
1728
1666
 
@@ -1734,5 +1672,5 @@ providers: [
1734
1672
  ---
1735
1673
 
1736
1674
  **Last Updated:** 2026-02-25
1737
- **Version:** 3.0.0
1675
+ **Version:** 3.0.1
1738
1676
  **Angular Version:** 21