@flusys/ng-shared 1.0.0-beta → 1.1.0-beta

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
@@ -110,6 +110,77 @@ interface IDropDown {
110
110
  }
111
111
  ```
112
112
 
113
+ #### User Select Interfaces
114
+
115
+ ```typescript
116
+ interface IUserSelectFilter {
117
+ page: number;
118
+ pageSize: number;
119
+ search: string;
120
+ [key: string]: unknown;
121
+ }
122
+
123
+ type LoadUsersFn = (filter: IUserSelectFilter) => Observable<IListResponse<IUserBasicInfo>>;
124
+ ```
125
+
126
+ #### File Select Interfaces
127
+
128
+ ```typescript
129
+ interface IFileBasicInfo {
130
+ id: string;
131
+ name: string;
132
+ contentType: string;
133
+ size: string;
134
+ url: string | null;
135
+ }
136
+
137
+ interface IFileUploadOptions {
138
+ storageConfigId?: string;
139
+ folderPath?: string;
140
+ maxWidth?: number;
141
+ maxHeight?: number;
142
+ quality?: number;
143
+ compress?: boolean;
144
+ }
145
+
146
+ interface IUploadedFile {
147
+ name: string;
148
+ key: string;
149
+ size: number;
150
+ contentType: string;
151
+ }
152
+
153
+ interface IFileSelectFilter {
154
+ page: number;
155
+ pageSize: number;
156
+ search: string;
157
+ contentTypes?: string[];
158
+ folderId?: string;
159
+ [key: string]: unknown;
160
+ }
161
+
162
+ type LoadFilesFn = (filter: IFileSelectFilter) => Observable<IListResponse<IFileBasicInfo>>;
163
+ type UploadFileFn = (file: File, options?: IFileUploadOptions) => Observable<ISingleResponse<IUploadedFile>>;
164
+ type GetFileUrlsFn = (fileIds: string[]) => Observable<ISingleResponse<IFileBasicInfo[]>>;
165
+ ```
166
+
167
+ **File Type Filters (Constants):**
168
+
169
+ ```typescript
170
+ import { FILE_TYPE_FILTERS, getAcceptString, isFileTypeAllowed, getFileIconClass, formatFileSize } from '@flusys/ng-shared';
171
+
172
+ FILE_TYPE_FILTERS.IMAGES // ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml']
173
+ FILE_TYPE_FILTERS.DOCUMENTS // ['application/pdf', 'application/msword', ...]
174
+ FILE_TYPE_FILTERS.VIDEOS // ['video/mp4', 'video/webm', ...]
175
+ FILE_TYPE_FILTERS.AUDIO // ['audio/mpeg', 'audio/wav', ...]
176
+ FILE_TYPE_FILTERS.ALL // [] (allows all)
177
+
178
+ getAcceptString(['image/*']) // 'image/*'
179
+ isFileTypeAllowed(file, ['image/*']) // true/false
180
+ getFileIconClass('image/png') // 'pi pi-image'
181
+ formatFileSize('1024') // '1 KB'
182
+ ```
183
+
113
184
  ### Response Interfaces
114
185
 
115
186
  Type-safe interfaces matching FLUSYS_NEST backend response DTOs.
@@ -539,6 +610,176 @@ export class MyComponent {
539
610
 
540
611
  **Computed signals:** `selectedValueDisplay` (display text), `isSelectAll` (all items selected)
541
612
 
613
+ ### UserSelectComponent
614
+
615
+ Single user selection with lazy loading. Uses `USER_PROVIDER` internally or accepts custom `loadUsers` function.
616
+
617
+ - **Selector:** `lib-user-select`
618
+ - **Supports:** Template-driven, reactive forms, signal forms
619
+
620
+ ```typescript
621
+ @Component({
622
+ imports: [UserSelectComponent],
623
+ template: `
624
+ <!-- Simple usage - uses USER_PROVIDER internally -->
625
+ <lib-user-select
626
+ [(value)]="selectedUserId"
627
+ [isEditMode]="true"
628
+ />
629
+
630
+ <!-- With custom loadUsers function -->
631
+ <lib-user-select
632
+ [(value)]="selectedUserId"
633
+ [isEditMode]="true"
634
+ [loadUsers]="customLoadUsers"
635
+ />
636
+ `,
637
+ })
638
+ export class MyComponent {
639
+ readonly selectedUserId = signal<string | null>(null);
640
+ }
641
+ ```
642
+
643
+ **Inputs:**
644
+
645
+ | Input | Type | Default | Description |
646
+ | ----- | ---- | ------- | ----------- |
647
+ | `isEditMode` | `boolean` | required | Enable/disable editing |
648
+ | `placeHolder` | `string` | `'Select User'` | Placeholder text |
649
+ | `filterActive` | `boolean` | `true` | Filter active users only |
650
+ | `additionalFilters` | `Record<string, unknown>` | `{}` | Extra filter params |
651
+ | `pageSize` | `number` | `20` | Page size for pagination |
652
+ | `loadUsers` | `LoadUsersFn` | - | Custom user loading function |
653
+
654
+ **Model:** `value` - Two-way bound selected user ID (`string | null`)
655
+
656
+ **Outputs:** `userSelected` (IUserBasicInfo | null), `onError` (Error)
657
+
658
+ ### UserMultiSelectComponent
659
+
660
+ Multiple user selection with lazy loading. Uses `USER_PROVIDER` internally or accepts custom `loadUsers` function.
661
+
662
+ - **Selector:** `lib-user-multi-select`
663
+ - **Supports:** Template-driven, reactive forms, signal forms
664
+
665
+ ```typescript
666
+ @Component({
667
+ imports: [UserMultiSelectComponent],
668
+ template: `
669
+ <lib-user-multi-select
670
+ [(value)]="selectedUserIds"
671
+ [isEditMode]="true"
672
+ />
673
+ `,
674
+ })
675
+ export class MyComponent {
676
+ readonly selectedUserIds = signal<string[] | null>(null);
677
+ }
678
+ ```
679
+
680
+ **Inputs:** Same as `UserSelectComponent`.
681
+
682
+ **Model:** `value` - Two-way bound selected user IDs (`string[] | null`)
683
+
684
+ **Outputs:** `usersSelected` (IUserBasicInfo[]), `onError` (Error)
685
+
686
+ ### FileUploaderComponent
687
+
688
+ Drag & drop file upload with type filtering. Pass your own `uploadFile` function.
689
+
690
+ - **Selector:** `lib-file-uploader`
691
+
692
+ ```typescript
693
+ @Component({
694
+ imports: [FileUploaderComponent],
695
+ template: `
696
+ <!-- Single image upload -->
697
+ <lib-file-uploader
698
+ [uploadFile]="uploadFile"
699
+ [acceptTypes]="['image/*']"
700
+ [multiple]="false"
701
+ (fileUploaded)="onFileUploaded($event)"
702
+ />
703
+
704
+ <!-- Multiple document upload -->
705
+ <lib-file-uploader
706
+ [uploadFile]="uploadFile"
707
+ [acceptTypes]="FILE_TYPE_FILTERS.DOCUMENTS"
708
+ [multiple]="true"
709
+ [maxFiles]="5"
710
+ (filesUploaded)="onFilesUploaded($event)"
711
+ />
712
+ `,
713
+ })
714
+ export class MyComponent {
715
+ readonly uploadService = inject(UploadService);
716
+
717
+ readonly uploadFile: UploadFileFn = (file, options) =>
718
+ this.uploadService.uploadSingleFile(file, options);
719
+ }
720
+ ```
721
+
722
+ **Inputs:**
723
+
724
+ | Input | Type | Default | Description |
725
+ | ----- | ---- | ------- | ----------- |
726
+ | `uploadFile` | `UploadFileFn` | required | Upload function |
727
+ | `acceptTypes` | `string[]` | `[]` | Allowed MIME types |
728
+ | `multiple` | `boolean` | `false` | Allow multiple files |
729
+ | `maxFiles` | `number` | `10` | Max files for multiple |
730
+ | `maxSizeMb` | `number` | `10` | Max file size in MB |
731
+ | `uploadOptions` | `IFileUploadOptions` | `{}` | Upload options |
732
+ | `disabled` | `boolean` | `false` | Disable uploader |
733
+ | `showPreview` | `boolean` | `true` | Show selected files preview |
734
+ | `autoUpload` | `boolean` | `true` | Upload immediately on selection |
735
+
736
+ **Outputs:** `fileUploaded` (IUploadedFile), `filesUploaded` (IUploadedFile[]), `onError` (Error), `fileSelected` (File[])
737
+
738
+ ### FileSelectorDialogComponent
739
+
740
+ Dialog to browse and select existing files with filtering.
741
+
742
+ - **Selector:** `lib-file-selector-dialog`
743
+
744
+ ```typescript
745
+ @Component({
746
+ imports: [FileSelectorDialogComponent],
747
+ template: `
748
+ <lib-file-selector-dialog
749
+ [(visible)]="showFileSelector"
750
+ [loadFiles]="loadFiles"
751
+ [acceptTypes]="['image/*']"
752
+ [multiple]="false"
753
+ (fileSelected)="onFileSelected($event)"
754
+ />
755
+ `,
756
+ })
757
+ export class MyComponent {
758
+ readonly showFileSelector = signal(false);
759
+ readonly fileService = inject(FileManagerApiService);
760
+
761
+ readonly loadFiles: LoadFilesFn = (filter) =>
762
+ this.fileService.getAll(filter.search, {
763
+ pagination: { currentPage: filter.page, pageSize: filter.pageSize },
764
+ });
765
+ }
766
+ ```
767
+
768
+ **Inputs:**
769
+
770
+ | Input | Type | Default | Description |
771
+ | ----- | ---- | ------- | ----------- |
772
+ | `loadFiles` | `LoadFilesFn` | required | File loading function |
773
+ | `header` | `string` | `'Select File'` | Dialog header |
774
+ | `acceptTypes` | `string[]` | `[]` | Allowed MIME types |
775
+ | `multiple` | `boolean` | `false` | Allow multiple selection |
776
+ | `maxSelection` | `number` | `10` | Max files for multiple |
777
+ | `pageSize` | `number` | `20` | Page size for pagination |
778
+
779
+ **Model:** `visible` - Two-way bound dialog visibility (`boolean`)
780
+
781
+ **Outputs:** `fileSelected` (IFileBasicInfo), `filesSelected` (IFileBasicInfo[]), `closed` (void), `onError` (Error)
782
+
542
783
  ---
543
784
 
544
785
  ## 5. Directives
@@ -805,6 +1046,58 @@ interface IUserPermissionProvider {
805
1046
  }
806
1047
  ```
807
1048
 
1049
+ #### IProfileUploadProvider / `PROFILE_UPLOAD_PROVIDER`
1050
+
1051
+ Profile picture upload for ng-auth profile page. Implemented by ng-storage.
1052
+
1053
+ ```typescript
1054
+ interface IProfileUploadResult {
1055
+ id: string; // File manager ID (UUID)
1056
+ name: string; // Original file name
1057
+ key: string; // Storage key/path
1058
+ size: number; // File size in bytes
1059
+ contentType: string; // MIME type
1060
+ }
1061
+
1062
+ interface IProfileUploadOptions {
1063
+ folderPath?: string;
1064
+ compress?: boolean;
1065
+ maxWidth?: number;
1066
+ maxHeight?: number;
1067
+ }
1068
+
1069
+ interface IProfileUploadProvider {
1070
+ uploadProfilePicture(
1071
+ file: File,
1072
+ options?: IProfileUploadOptions
1073
+ ): Observable<ISingleResponse<IProfileUploadResult>>;
1074
+ }
1075
+ ```
1076
+
1077
+ #### IProfilePermissionProvider / `PROFILE_PERMISSION_PROVIDER`
1078
+
1079
+ User permission queries for ng-auth profile page. Implemented by ng-iam.
1080
+
1081
+ ```typescript
1082
+ interface IProfileRoleInfo {
1083
+ id: string;
1084
+ name: string;
1085
+ description?: string | null;
1086
+ }
1087
+
1088
+ interface IProfileActionInfo {
1089
+ id: string;
1090
+ code: string;
1091
+ name: string;
1092
+ description?: string | null;
1093
+ }
1094
+
1095
+ interface IProfilePermissionProvider {
1096
+ getUserRoles(userId: string, branchId?: string): Observable<ISingleResponse<IProfileRoleInfo[]>>;
1097
+ getUserActions(userId: string, branchId?: string): Observable<ISingleResponse<IProfileActionInfo[]>>;
1098
+ }
1099
+ ```
1100
+
808
1101
  ### Usage in Consuming Packages
809
1102
 
810
1103
  ```typescript
@@ -931,6 +1224,10 @@ export const appConfig: ApplicationConfig = {
931
1224
  | `IconComponent` | `lib-icon` | Flexible icon renderer |
932
1225
  | `LazySelectComponent` | `lib-lazy-select` | Lazy-loading dropdown |
933
1226
  | `LazyMultiSelectComponent` | `lib-lazy-multi-select`| Lazy-loading multi-select |
1227
+ | `UserSelectComponent` | `lib-user-select` | Single user selector |
1228
+ | `UserMultiSelectComponent` | `lib-user-multi-select`| Multiple user selector |
1229
+ | `FileUploaderComponent` | `lib-file-uploader` | Drag & drop file upload |
1230
+ | `FileSelectorDialogComponent` | `lib-file-selector-dialog` | File browser dialog |
934
1231
 
935
1232
  ### Directives
936
1233
 
@@ -964,6 +1261,14 @@ export const appConfig: ApplicationConfig = {
964
1261
  | `IMessageResponse` | Message-only response |
965
1262
  | `IErrorResponse` | Error with validation details |
966
1263
  | `ILogicNode` | Permission logic tree (AND/OR nodes) |
1264
+ | `IUserSelectFilter` | User select filter params |
1265
+ | `LoadUsersFn` | User loading function type |
1266
+ | `IFileBasicInfo` | Basic file info for selectors |
1267
+ | `IFileUploadOptions`| Upload options (compression, etc.) |
1268
+ | `IUploadedFile` | Uploaded file response |
1269
+ | `IFileSelectFilter` | File select filter params |
1270
+ | `LoadFilesFn` | File loading function type |
1271
+ | `UploadFileFn` | File upload function type |
967
1272
 
968
1273
  ### Injection Tokens
969
1274
 
@@ -972,6 +1277,8 @@ export const appConfig: ApplicationConfig = {
972
1277
  | `USER_PROVIDER` | `IUserProvider` | User list for IAM |
973
1278
  | `COMPANY_API_PROVIDER` | `ICompanyApiProvider` | Company list for IAM |
974
1279
  | `USER_PERMISSION_PROVIDER` | `IUserPermissionProvider` | User permission queries |
1280
+ | `PROFILE_UPLOAD_PROVIDER` | `IProfileUploadProvider` | Profile picture upload (ng-storage) |
1281
+ | `PROFILE_PERMISSION_PROVIDER` | `IProfilePermissionProvider` | User permissions for profile (ng-iam) |
975
1282
 
976
1283
  ## See Also
977
1284
 
@@ -982,5 +1289,5 @@ export const appConfig: ApplicationConfig = {
982
1289
 
983
1290
  ---
984
1291
 
985
- **Last Updated:** 2026-02-15
1292
+ **Last Updated:** 2026-02-16
986
1293
  **Angular Version:** 21