@flusys/ng-shared 3.0.1 → 4.0.0-rc
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 +161 -23
- package/fesm2022/flusys-ng-shared.mjs +1540 -387
- package/fesm2022/flusys-ng-shared.mjs.map +1 -1
- package/package.json +2 -2
- package/types/flusys-ng-shared.d.ts +231 -128
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, PLATFORM_ID, Injectable, DOCUMENT, REQUEST, signal, computed, ElementRef, input, effect, Directive, TemplateRef, ViewContainerRef, output,
|
|
2
|
+
import { inject, PLATFORM_ID, Injectable, DOCUMENT, REQUEST, signal, computed, ElementRef, input, effect, Directive, TemplateRef, ViewContainerRef, output, Pipe, Injector, isDevMode, NgModule, runInInjectionContext, resource, model, untracked, forwardRef, Component, ApplicationRef, viewChild, afterNextRender, ViewEncapsulation, DestroyRef, InjectionToken } from '@angular/core';
|
|
3
3
|
import { isPlatformServer, CommonModule, NgOptimizedImage, NgComponentOutlet, DatePipe, DOCUMENT as DOCUMENT$1 } from '@angular/common';
|
|
4
4
|
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
|
5
|
-
import { APP_CONFIG, getServiceUrl } from '@flusys/ng-core';
|
|
5
|
+
import { APP_CONFIG, getServiceUrl, TRANSLATE_ADAPTER, FALLBACK_MESSAGES_REGISTRY } from '@flusys/ng-core';
|
|
6
6
|
import { of, firstValueFrom, map as map$1 } from 'rxjs';
|
|
7
7
|
import { map, tap, catchError } from 'rxjs/operators';
|
|
8
8
|
import * as i1$1 from '@angular/forms';
|
|
@@ -17,12 +17,14 @@ import * as i1 from 'primeng/checkbox';
|
|
|
17
17
|
import { CheckboxModule } from 'primeng/checkbox';
|
|
18
18
|
import { ConfirmDialogModule } from 'primeng/confirmdialog';
|
|
19
19
|
import { DatePickerModule } from 'primeng/datepicker';
|
|
20
|
-
import * as
|
|
20
|
+
import * as i5 from 'primeng/dialog';
|
|
21
21
|
import { DialogModule } from 'primeng/dialog';
|
|
22
22
|
import { DividerModule } from 'primeng/divider';
|
|
23
23
|
import { FileUploadModule } from 'primeng/fileupload';
|
|
24
|
+
import * as i6 from 'primeng/iconfield';
|
|
24
25
|
import { IconFieldModule } from 'primeng/iconfield';
|
|
25
26
|
import { ImageModule } from 'primeng/image';
|
|
27
|
+
import * as i7 from 'primeng/inputicon';
|
|
26
28
|
import { InputIconModule } from 'primeng/inputicon';
|
|
27
29
|
import { InputNumberModule } from 'primeng/inputnumber';
|
|
28
30
|
import * as i2 from 'primeng/inputtext';
|
|
@@ -54,6 +56,7 @@ import { TooltipModule } from 'primeng/tooltip';
|
|
|
54
56
|
import { TreeTableModule } from 'primeng/treetable';
|
|
55
57
|
import { ProgressSpinnerModule } from 'primeng/progressspinner';
|
|
56
58
|
import { ColorPickerModule } from 'primeng/colorpicker';
|
|
59
|
+
import * as i3$1 from 'primeng/api';
|
|
57
60
|
import { MessageService, ConfirmationService } from 'primeng/api';
|
|
58
61
|
import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
59
62
|
|
|
@@ -157,6 +160,24 @@ const NOTIFICATION_PERMISSIONS = {
|
|
|
157
160
|
UPDATE: 'notification.update',
|
|
158
161
|
DELETE: 'notification.delete',
|
|
159
162
|
};
|
|
163
|
+
const LANGUAGE_PERMISSIONS = {
|
|
164
|
+
CREATE: 'language.create',
|
|
165
|
+
READ: 'language.read',
|
|
166
|
+
UPDATE: 'language.update',
|
|
167
|
+
DELETE: 'language.delete',
|
|
168
|
+
};
|
|
169
|
+
const TRANSLATION_KEY_PERMISSIONS = {
|
|
170
|
+
CREATE: 'translation-key.create',
|
|
171
|
+
READ: 'translation-key.read',
|
|
172
|
+
UPDATE: 'translation-key.update',
|
|
173
|
+
DELETE: 'translation-key.delete',
|
|
174
|
+
};
|
|
175
|
+
const TRANSLATION_PERMISSIONS = {
|
|
176
|
+
CREATE: 'translation.create',
|
|
177
|
+
READ: 'translation.read',
|
|
178
|
+
UPDATE: 'translation.update',
|
|
179
|
+
DELETE: 'translation.delete',
|
|
180
|
+
};
|
|
160
181
|
const PERMISSIONS = {
|
|
161
182
|
USER: USER_PERMISSIONS,
|
|
162
183
|
COMPANY: COMPANY_PERMISSIONS,
|
|
@@ -176,11 +197,383 @@ const PERMISSIONS = {
|
|
|
176
197
|
EVENT: EVENT_PERMISSIONS,
|
|
177
198
|
EVENT_PARTICIPANT: EVENT_PARTICIPANT_PERMISSIONS,
|
|
178
199
|
NOTIFICATION: NOTIFICATION_PERMISSIONS,
|
|
200
|
+
LANGUAGE: LANGUAGE_PERMISSIONS,
|
|
201
|
+
TRANSLATION_KEY: TRANSLATION_KEY_PERMISSIONS,
|
|
202
|
+
TRANSLATION: TRANSLATION_PERMISSIONS,
|
|
179
203
|
};
|
|
180
204
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
205
|
+
const SHARED_MESSAGES = {
|
|
206
|
+
// Common actions
|
|
207
|
+
'shared.save': 'Save',
|
|
208
|
+
'shared.cancel': 'Cancel',
|
|
209
|
+
'shared.delete': 'Delete',
|
|
210
|
+
'shared.edit': 'Edit',
|
|
211
|
+
'shared.create': 'Create',
|
|
212
|
+
'shared.update': 'Update',
|
|
213
|
+
'shared.add': 'Add',
|
|
214
|
+
'shared.remove': 'Remove',
|
|
215
|
+
'shared.close': 'Close',
|
|
216
|
+
'shared.confirm': 'Confirm',
|
|
217
|
+
'shared.back': 'Back',
|
|
218
|
+
'shared.next': 'Next',
|
|
219
|
+
'shared.previous': 'Previous',
|
|
220
|
+
'shared.submit': 'Submit',
|
|
221
|
+
'shared.reset': 'Reset',
|
|
222
|
+
'shared.clear': 'Clear',
|
|
223
|
+
'shared.search': 'Search',
|
|
224
|
+
'shared.filter': 'Filter',
|
|
225
|
+
'shared.refresh': 'Refresh',
|
|
226
|
+
'shared.export': 'Export',
|
|
227
|
+
'shared.import': 'Import',
|
|
228
|
+
'shared.download': 'Download',
|
|
229
|
+
'shared.upload': 'Upload',
|
|
230
|
+
'shared.view': 'View',
|
|
231
|
+
'shared.details': 'Details',
|
|
232
|
+
'shared.actions': 'Actions',
|
|
233
|
+
'shared.options': 'Options',
|
|
234
|
+
'shared.settings': 'Settings',
|
|
235
|
+
'shared.yes': 'Yes',
|
|
236
|
+
'shared.no': 'No',
|
|
237
|
+
'shared.continue': 'Continue',
|
|
238
|
+
'shared.view.details': 'View Details',
|
|
239
|
+
// Common labels
|
|
240
|
+
'shared.name': 'Name',
|
|
241
|
+
'shared.description': 'Description',
|
|
242
|
+
'shared.status': 'Status',
|
|
243
|
+
'shared.active': 'Active',
|
|
244
|
+
'shared.inactive': 'Inactive',
|
|
245
|
+
'shared.enabled': 'Enabled',
|
|
246
|
+
'shared.disabled': 'Disabled',
|
|
247
|
+
'shared.verified': 'Verified',
|
|
248
|
+
'shared.unverified': 'Unverified',
|
|
249
|
+
'shared.read.only': 'Read Only',
|
|
250
|
+
'shared.assigned': 'Assigned',
|
|
251
|
+
'shared.not.assigned': 'Not Assigned',
|
|
252
|
+
'shared.unknown': 'Unknown',
|
|
253
|
+
'shared.na': 'N/A',
|
|
254
|
+
'shared.no.company': 'No Company',
|
|
255
|
+
'shared.company': 'Company',
|
|
256
|
+
'shared.no.branch': 'No Branch',
|
|
257
|
+
'shared.display.order': 'Display Order',
|
|
258
|
+
'shared.display.order.placeholder': 'Enter display order',
|
|
259
|
+
'shared.created.at': 'Created At',
|
|
260
|
+
'shared.updated.at': 'Updated At',
|
|
261
|
+
'shared.created.by': 'Created By',
|
|
262
|
+
'shared.updated.by': 'Updated By',
|
|
263
|
+
'shared.date': 'Date',
|
|
264
|
+
'shared.time': 'Time',
|
|
265
|
+
'shared.email': 'Email',
|
|
266
|
+
'shared.phone': 'Phone',
|
|
267
|
+
'shared.address': 'Address',
|
|
268
|
+
'shared.type': 'Type',
|
|
269
|
+
'shared.category': 'Category',
|
|
270
|
+
'shared.code': 'Code',
|
|
271
|
+
'shared.serial': 'Serial',
|
|
272
|
+
'shared.order': 'Order',
|
|
273
|
+
'shared.priority': 'Priority',
|
|
274
|
+
'shared.notes': 'Notes',
|
|
275
|
+
'shared.comments': 'Comments',
|
|
276
|
+
// Toast summaries
|
|
277
|
+
'shared.info': 'Info',
|
|
278
|
+
'shared.warning': 'Warning',
|
|
279
|
+
'shared.confirm.delete.header': 'Confirm Delete',
|
|
280
|
+
// Status messages
|
|
281
|
+
'shared.loading': 'Loading...',
|
|
282
|
+
'shared.saving': 'Saving...',
|
|
283
|
+
'shared.deleting': 'Deleting...',
|
|
284
|
+
'shared.processing': 'Processing...',
|
|
285
|
+
'shared.please.wait': 'Please wait...',
|
|
286
|
+
// Success messages
|
|
287
|
+
'shared.success': 'Success',
|
|
288
|
+
'shared.operation.success': 'Operation completed successfully',
|
|
289
|
+
'shared.save.success': 'Saved successfully',
|
|
290
|
+
'shared.delete.success': 'Deleted successfully',
|
|
291
|
+
'shared.update.success': 'Updated successfully',
|
|
292
|
+
'shared.create.success': 'Created successfully',
|
|
293
|
+
// Error messages
|
|
294
|
+
'shared.error': 'Error',
|
|
295
|
+
'shared.operation.failed': 'Operation failed',
|
|
296
|
+
'shared.save.failed': 'Failed to save',
|
|
297
|
+
'shared.delete.failed': 'Failed to delete',
|
|
298
|
+
'shared.update.failed': 'Failed to update',
|
|
299
|
+
'shared.create.failed': 'Failed to create',
|
|
300
|
+
'shared.load.failed': 'Failed to load data',
|
|
301
|
+
'shared.unexpected.error': 'An unexpected error occurred',
|
|
302
|
+
'shared.network.error': 'Network error. Please check your connection.',
|
|
303
|
+
'shared.server.error': 'Server error. Please try again later.',
|
|
304
|
+
// Validation messages
|
|
305
|
+
'shared.required': 'This field is required',
|
|
306
|
+
'shared.invalid.email': 'Please enter a valid email address',
|
|
307
|
+
'shared.invalid.phone': 'Please enter a valid phone number',
|
|
308
|
+
'shared.min.length': 'Minimum {{min}} characters required',
|
|
309
|
+
'shared.max.length': 'Maximum {{max}} characters allowed',
|
|
310
|
+
'shared.min.value': 'Minimum value is {{min}}',
|
|
311
|
+
'shared.max.value': 'Maximum value is {{max}}',
|
|
312
|
+
'shared.invalid.format': 'Invalid format',
|
|
313
|
+
'shared.password.mismatch': 'Passwords do not match',
|
|
314
|
+
// Confirmation messages
|
|
315
|
+
'shared.confirm.delete': 'Are you sure you want to delete this item?',
|
|
316
|
+
'shared.confirm.delete.item': 'Are you sure you want to delete "{{name}}"?',
|
|
317
|
+
'shared.confirm.delete.multiple': 'Are you sure you want to delete {{count}} items?',
|
|
318
|
+
'shared.confirm.cancel': 'Are you sure you want to cancel? Unsaved changes will be lost.',
|
|
319
|
+
'shared.confirm.action': 'Are you sure you want to proceed?',
|
|
320
|
+
'shared.unsaved.changes': 'You have unsaved changes.',
|
|
321
|
+
// Empty states
|
|
322
|
+
'shared.no.data': 'No data available',
|
|
323
|
+
'shared.no.results': 'No results found',
|
|
324
|
+
'shared.empty.list': 'The list is empty',
|
|
325
|
+
'shared.no.items.selected': 'No items selected',
|
|
326
|
+
// Pagination
|
|
327
|
+
'shared.showing': 'Showing',
|
|
328
|
+
'shared.of': 'of',
|
|
329
|
+
'shared.items': 'items',
|
|
330
|
+
'shared.page': 'Page',
|
|
331
|
+
'shared.rows.per.page': 'Rows per page',
|
|
332
|
+
'shared.first': 'First',
|
|
333
|
+
'shared.last': 'Last',
|
|
334
|
+
// CRUD operation messages (used by createApiController)
|
|
335
|
+
'item.create.success': 'Item created successfully',
|
|
336
|
+
'item.create.many.success': '{{count}} items created successfully',
|
|
337
|
+
'item.get.success': 'Item retrieved successfully',
|
|
338
|
+
'item.get.all.success': 'Items retrieved successfully',
|
|
339
|
+
'item.update.success': 'Item updated successfully',
|
|
340
|
+
'item.update.many.success': '{{count}} items updated successfully',
|
|
341
|
+
'item.delete.success': '{{count}} item(s) deleted successfully',
|
|
342
|
+
'item.restore.success': '{{count}} item(s) restored successfully',
|
|
343
|
+
// HTTP error messages (for error interceptor)
|
|
344
|
+
'shared.error.bad.request': 'Bad Request',
|
|
345
|
+
'shared.error.not.found': 'Not Found',
|
|
346
|
+
'shared.error.conflict': 'Conflict',
|
|
347
|
+
'shared.error.validation.error': 'Validation Error',
|
|
348
|
+
'shared.error.server.error': 'Server Error',
|
|
349
|
+
'shared.error.service.unavailable': 'Service Unavailable',
|
|
350
|
+
// Validation
|
|
351
|
+
'shared.validation.error': 'Validation Error',
|
|
352
|
+
'shared.fill.all.fields': 'Please fill in all required fields correctly.',
|
|
353
|
+
'shared.fill.required.fields': 'Please fill in all required fields',
|
|
354
|
+
'shared.name.required': 'Name is required',
|
|
355
|
+
'shared.email.required': 'Email is required',
|
|
356
|
+
'shared.select.all': 'Select All',
|
|
357
|
+
'shared.deselect.all': 'Deselect All',
|
|
358
|
+
'shared.save.changes': 'Save Changes',
|
|
359
|
+
'shared.validation.required': '{{field}} is required',
|
|
360
|
+
'shared.validation.email': 'Please enter a valid email address',
|
|
361
|
+
'shared.validation.min.length': '{{field}} must be at least {{min}} characters',
|
|
362
|
+
'shared.validation.max.length': '{{field}} must be at most {{max}} characters',
|
|
363
|
+
'shared.validation.min': '{{field}} must be at least {{min}}',
|
|
364
|
+
'shared.validation.max': '{{field}} must be at most {{max}}',
|
|
365
|
+
'shared.validation.pattern': '{{field}} format is invalid',
|
|
366
|
+
'shared.password.required': 'Password is required',
|
|
367
|
+
'shared.confirm.password.required': 'Please confirm your password',
|
|
368
|
+
'shared.min.characters': 'Min. {{count}} characters',
|
|
369
|
+
'shared.select': 'Select...',
|
|
370
|
+
'shared.select.option': 'Select an option',
|
|
371
|
+
'shared.placeholder.current.password': 'Enter current password',
|
|
372
|
+
'shared.placeholder.new.password': 'Enter new password',
|
|
373
|
+
'shared.placeholder.confirm.password': 'Confirm new password',
|
|
374
|
+
// File uploader
|
|
375
|
+
'shared.upload.drop.multiple': 'Drop files here or click to upload',
|
|
376
|
+
'shared.upload.drop.single': 'Drop file here or click to upload',
|
|
377
|
+
'shared.upload.allowed.types': 'Allowed:',
|
|
378
|
+
'shared.upload.all.types.allowed': 'All file types allowed',
|
|
379
|
+
'shared.upload.uploading': 'Uploading {{fileName}}...',
|
|
380
|
+
'shared.upload.max.size': '(Max {{size}}MB)',
|
|
381
|
+
'shared.upload.invalid.type': 'Invalid File Type',
|
|
382
|
+
'shared.upload.file.too.large': 'File Too Large',
|
|
383
|
+
'shared.upload.complete': 'Upload Complete',
|
|
384
|
+
'shared.upload.files': 'files',
|
|
385
|
+
'shared.upload.files.uploaded': '{{count}} file(s) uploaded successfully',
|
|
386
|
+
'shared.upload.failed': 'Upload failed',
|
|
387
|
+
'shared.upload.provider.not.configured': 'File upload not configured. Add {{provider}} to your app config.',
|
|
388
|
+
// File type categories
|
|
389
|
+
'shared.file.type.images': 'Images',
|
|
390
|
+
'shared.file.type.documents': 'Documents',
|
|
391
|
+
'shared.file.type.videos': 'Videos',
|
|
392
|
+
'shared.file.type.audio': 'Audio',
|
|
393
|
+
// Size units
|
|
394
|
+
'shared.units.kb': 'KB',
|
|
395
|
+
'shared.units.mb': 'MB',
|
|
396
|
+
'shared.units.gb': 'GB',
|
|
397
|
+
'shared.units.tb': 'TB',
|
|
398
|
+
'shared.units.bytes': 'Bytes',
|
|
399
|
+
// File selector
|
|
400
|
+
'shared.file.selector.search.placeholder': 'Search files...',
|
|
401
|
+
'shared.file.selector.no.files': 'No files found',
|
|
402
|
+
'shared.file.selector.selected': '{{count}} selected',
|
|
403
|
+
'shared.file.selector.select.multiple': 'Select ({{count}})',
|
|
404
|
+
'shared.file.selector.select': 'Select',
|
|
405
|
+
'shared.file.selector.default.header': 'Select File',
|
|
406
|
+
'shared.file.selector.select.file': 'Select File',
|
|
407
|
+
'shared.file.selector.select.files': 'Select Files',
|
|
408
|
+
'shared.file.selector.all.folders': 'All Folders',
|
|
409
|
+
'shared.file.selector.all.storage': 'All Storage',
|
|
410
|
+
'shared.file.selector.provider.not.configured': 'File selection not configured.',
|
|
411
|
+
'shared.file.selector.add.provider': 'Add',
|
|
412
|
+
'shared.default': 'Default',
|
|
413
|
+
// User/option select
|
|
414
|
+
'shared.user.select.placeholder': 'Select User',
|
|
415
|
+
'shared.select.placeholder': 'Select Option',
|
|
416
|
+
'shared.multi.select.placeholder': 'Select Options',
|
|
417
|
+
'shared.multi.select.items.selected': '{{count}} Items Selected',
|
|
418
|
+
'shared.select.deselect.all': 'Select/Deselect All',
|
|
419
|
+
'shared.loading.actions': 'Loading actions...',
|
|
420
|
+
'shared.loading.roles': 'Loading roles...',
|
|
421
|
+
'shared.pending.changes': 'Pending Changes',
|
|
422
|
+
'shared.to.add': 'To Add',
|
|
423
|
+
'shared.to.remove': 'To Remove',
|
|
424
|
+
'shared.to.assign': 'To Assign',
|
|
425
|
+
'shared.to.whitelist': 'To Whitelist',
|
|
426
|
+
'shared.description.placeholder': 'Enter description',
|
|
427
|
+
// Backend error keys (used by exception filters)
|
|
428
|
+
'error.generic': 'An error occurred',
|
|
429
|
+
'error.not.found': 'Resource not found',
|
|
430
|
+
'error.validation': 'Validation failed',
|
|
431
|
+
'error.unauthorized': 'Unauthorized access',
|
|
432
|
+
'error.forbidden': 'Access forbidden',
|
|
433
|
+
'error.conflict': 'Resource conflict',
|
|
434
|
+
'error.internal': 'Internal server error',
|
|
435
|
+
'error.service.unavailable': 'Service temporarily unavailable',
|
|
436
|
+
'error.http': 'HTTP error',
|
|
437
|
+
'error.unknown': 'Unknown error occurred',
|
|
438
|
+
'error.permission.system.unavailable': 'Permission system temporarily unavailable. Please try again later.',
|
|
439
|
+
'error.insufficient.permissions': 'Missing required permissions: {{permissions}}',
|
|
440
|
+
'error.insufficient.permissions.or': 'Requires at least one of: {{permissions}}',
|
|
441
|
+
'error.no.permissions.found': 'No permissions found. Please contact administrator.',
|
|
442
|
+
// Backend system keys (infrastructure errors)
|
|
443
|
+
'system.repository.not.available': '{{entity}} repository not available',
|
|
444
|
+
'system.datasource.not.available': 'Data source not available',
|
|
445
|
+
'system.database.config.not.available': 'Database configuration not available',
|
|
446
|
+
'system.service.not.available': 'Service "{{provider}}" not available. Available: {{available}}',
|
|
447
|
+
'system.config.required': 'Configuration required',
|
|
448
|
+
'system.internal.error': 'Failed to initialize "{{provider}}": {{error}}',
|
|
449
|
+
'system.not.found': 'System resource not found',
|
|
450
|
+
'system.duplicate.request': 'Duplicate request detected',
|
|
451
|
+
'system.invalid.tenant.id': 'Invalid tenant ID',
|
|
452
|
+
'system.tenant.not.found': 'Tenant "{{tenantId}}" not found',
|
|
453
|
+
'system.tenant.header.required': 'Tenant not found. Ensure "{{header}}" header is set.',
|
|
454
|
+
'system.missing.parameter': 'Missing required parameter: {{key}}',
|
|
455
|
+
'system.sdk.not.installed': 'Required SDK "{{sdk}}" not installed. Run: npm install {{sdk}}',
|
|
456
|
+
'system.path.traversal.detected': 'Path traversal detected',
|
|
457
|
+
'system.invalid.file.key': 'Invalid file key',
|
|
458
|
+
// Aliases for commonly used keys (dot-separated)
|
|
459
|
+
'shared.all': 'All',
|
|
460
|
+
// PrimeNG component messages (synced to PrimeNGConfig)
|
|
461
|
+
'primeng.empty.message': 'No results found',
|
|
462
|
+
'primeng.empty.filter.message': 'No results found',
|
|
463
|
+
'primeng.empty.search.message': 'No results found',
|
|
464
|
+
'primeng.selection.message': '{0} items selected',
|
|
465
|
+
'primeng.empty.selection.message': 'No selected item',
|
|
466
|
+
'primeng.choose': 'Choose',
|
|
467
|
+
'primeng.upload': 'Upload',
|
|
468
|
+
'primeng.cancel': 'Cancel',
|
|
469
|
+
'primeng.pending': 'Pending',
|
|
470
|
+
'primeng.choose.date': 'Choose Date',
|
|
471
|
+
'primeng.today': 'Today',
|
|
472
|
+
'primeng.clear': 'Clear',
|
|
473
|
+
'primeng.week.header': 'Wk',
|
|
474
|
+
'primeng.first.day.of.week': '0',
|
|
475
|
+
'primeng.accept': 'Yes',
|
|
476
|
+
'primeng.reject': 'No',
|
|
477
|
+
'primeng.lt': 'Less than',
|
|
478
|
+
'primeng.lte': 'Less than or equal to',
|
|
479
|
+
'primeng.gt': 'Greater than',
|
|
480
|
+
'primeng.gte': 'Greater than or equal to',
|
|
481
|
+
'primeng.date.is': 'Date is',
|
|
482
|
+
'primeng.date.is.not': 'Date is not',
|
|
483
|
+
'primeng.date.before': 'Date is before',
|
|
484
|
+
'primeng.date.after': 'Date is after',
|
|
485
|
+
'primeng.contains': 'Contains',
|
|
486
|
+
'primeng.not.contains': 'Not contains',
|
|
487
|
+
'primeng.starts.with': 'Starts with',
|
|
488
|
+
'primeng.ends.with': 'Ends with',
|
|
489
|
+
'primeng.equals': 'Equals',
|
|
490
|
+
'primeng.not.equals': 'Not equals',
|
|
491
|
+
'primeng.no.filter': 'No Filter',
|
|
492
|
+
'primeng.match.all': 'Match All',
|
|
493
|
+
'primeng.match.any': 'Match Any',
|
|
494
|
+
'primeng.add.rule': 'Add Rule',
|
|
495
|
+
'primeng.remove.rule': 'Remove Rule',
|
|
496
|
+
'primeng.apply': 'Apply',
|
|
497
|
+
'primeng.aria.true.label': 'True',
|
|
498
|
+
'primeng.aria.false.label': 'False',
|
|
499
|
+
'primeng.aria.null.label': 'Not Selected',
|
|
500
|
+
'primeng.aria.star': '1 star',
|
|
501
|
+
'primeng.aria.stars': '{star} stars',
|
|
502
|
+
'primeng.aria.select.all': 'All items selected',
|
|
503
|
+
'primeng.aria.unselect.all': 'All items unselected',
|
|
504
|
+
'primeng.aria.close': 'Close',
|
|
505
|
+
'primeng.aria.previous': 'Previous',
|
|
506
|
+
'primeng.aria.next': 'Next',
|
|
507
|
+
'primeng.aria.navigation': 'Navigation',
|
|
508
|
+
'primeng.aria.scroll.top': 'Scroll Top',
|
|
509
|
+
'primeng.aria.move.top': 'Move Top',
|
|
510
|
+
'primeng.aria.move.up': 'Move Up',
|
|
511
|
+
'primeng.aria.move.down': 'Move Down',
|
|
512
|
+
'primeng.aria.move.bottom': 'Move Bottom',
|
|
513
|
+
'primeng.aria.move.to.target': 'Move to Target',
|
|
514
|
+
'primeng.aria.move.to.source': 'Move to Source',
|
|
515
|
+
'primeng.aria.move.all.to.target': 'Move All to Target',
|
|
516
|
+
'primeng.aria.move.all.to.source': 'Move All to Source',
|
|
517
|
+
'primeng.aria.page.label': 'Page {page}',
|
|
518
|
+
'primeng.aria.first.page.label': 'First Page',
|
|
519
|
+
'primeng.aria.last.page.label': 'Last Page',
|
|
520
|
+
'primeng.aria.next.page.label': 'Next Page',
|
|
521
|
+
'primeng.aria.prev.page.label': 'Previous Page',
|
|
522
|
+
'primeng.aria.rows.per.page.label': 'Rows per page',
|
|
523
|
+
'primeng.aria.jump.to.page.dropdown.label': 'Jump to Page Dropdown',
|
|
524
|
+
'primeng.aria.jump.to.page.input.label': 'Jump to Page Input',
|
|
525
|
+
'primeng.aria.select.row': 'Row Selected',
|
|
526
|
+
'primeng.aria.unselect.row': 'Row Unselected',
|
|
527
|
+
'primeng.aria.expand.row': 'Row Expanded',
|
|
528
|
+
'primeng.aria.collapse.row': 'Row Collapsed',
|
|
529
|
+
'primeng.aria.show.filter.menu': 'Show Filter Menu',
|
|
530
|
+
'primeng.aria.hide.filter.menu': 'Hide Filter Menu',
|
|
531
|
+
'primeng.aria.filter.operator': 'Filter Operator',
|
|
532
|
+
'primeng.aria.filter.constraint': 'Filter Constraint',
|
|
533
|
+
'primeng.aria.edit.row': 'Edit Row',
|
|
534
|
+
'primeng.aria.save.edit': 'Save Edit',
|
|
535
|
+
'primeng.aria.cancel.edit': 'Cancel Edit',
|
|
536
|
+
'primeng.aria.list.view': 'List View',
|
|
537
|
+
'primeng.aria.grid.view': 'Grid View',
|
|
538
|
+
'primeng.aria.slide': 'Slide',
|
|
539
|
+
'primeng.aria.slide.number': '{slideNumber}',
|
|
540
|
+
'primeng.aria.zoom.image': 'Zoom Image',
|
|
541
|
+
'primeng.aria.zoom.in': 'Zoom In',
|
|
542
|
+
'primeng.aria.zoom.out': 'Zoom Out',
|
|
543
|
+
'primeng.aria.rotate.right': 'Rotate Right',
|
|
544
|
+
'primeng.aria.rotate.left': 'Rotate Left',
|
|
545
|
+
// Common aliases (backward compatibility for modules using common.* prefix)
|
|
546
|
+
'common.save': 'Save',
|
|
547
|
+
'common.cancel': 'Cancel',
|
|
548
|
+
'common.delete': 'Delete',
|
|
549
|
+
'common.edit': 'Edit',
|
|
550
|
+
'common.create': 'Create',
|
|
551
|
+
'common.update': 'Update',
|
|
552
|
+
'common.add': 'Add',
|
|
553
|
+
'common.remove': 'Remove',
|
|
554
|
+
'common.close': 'Close',
|
|
555
|
+
'common.confirm': 'Confirm',
|
|
556
|
+
'common.test': 'Test',
|
|
557
|
+
'common.name': 'Name',
|
|
558
|
+
'common.description': 'Description',
|
|
559
|
+
'common.status': 'Status',
|
|
560
|
+
'common.active': 'Active',
|
|
561
|
+
'common.inactive': 'Inactive',
|
|
562
|
+
'common.default': 'Default',
|
|
563
|
+
'common.type': 'Type',
|
|
564
|
+
'common.created': 'Created',
|
|
565
|
+
'common.updated': 'Updated',
|
|
566
|
+
'common.actions': 'Actions',
|
|
567
|
+
'common.company': 'Company',
|
|
568
|
+
'common.success': 'Success',
|
|
569
|
+
'common.error': 'Error',
|
|
570
|
+
'common.validation': 'Validation',
|
|
571
|
+
'common.fill.required.fields': 'Please fill in all required fields',
|
|
572
|
+
// File uploader
|
|
573
|
+
'shared.file.uploader.no.upload.function': 'No upload function available. Configure FILE_PROVIDER or provide uploadFile input.',
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
184
577
|
const FILE_TYPE_FILTERS = {
|
|
185
578
|
IMAGES: ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml'],
|
|
186
579
|
DOCUMENTS: [
|
|
@@ -194,30 +587,15 @@ const FILE_TYPE_FILTERS = {
|
|
|
194
587
|
AUDIO: ['audio/mpeg', 'audio/wav', 'audio/ogg', 'audio/webm'],
|
|
195
588
|
ALL: [],
|
|
196
589
|
};
|
|
197
|
-
|
|
198
|
-
* Get accept string for file input from content types
|
|
199
|
-
*/
|
|
590
|
+
// ─── Utility Functions ────────────────────────────────────────────────────────
|
|
200
591
|
function getAcceptString(contentTypes) {
|
|
201
|
-
|
|
202
|
-
return '*/*';
|
|
203
|
-
return contentTypes.join(',');
|
|
592
|
+
return contentTypes.length ? contentTypes.join(',') : '*/*';
|
|
204
593
|
}
|
|
205
|
-
/**
|
|
206
|
-
* Check if file matches allowed content types
|
|
207
|
-
*/
|
|
208
594
|
function isFileTypeAllowed(file, allowedTypes) {
|
|
209
595
|
if (!allowedTypes.length)
|
|
210
596
|
return true;
|
|
211
|
-
return allowedTypes.some((type) =>
|
|
212
|
-
if (type.endsWith('/*')) {
|
|
213
|
-
return file.type.startsWith(type.replace('/*', '/'));
|
|
214
|
-
}
|
|
215
|
-
return file.type === type;
|
|
216
|
-
});
|
|
597
|
+
return allowedTypes.some((type) => type.endsWith('/*') ? file.type.startsWith(type.replace('/*', '/')) : file.type === type);
|
|
217
598
|
}
|
|
218
|
-
/**
|
|
219
|
-
* Get file icon class based on content type
|
|
220
|
-
*/
|
|
221
599
|
function getFileIconClass(contentType) {
|
|
222
600
|
if (contentType.startsWith('image/'))
|
|
223
601
|
return 'pi pi-image';
|
|
@@ -233,9 +611,6 @@ function getFileIconClass(contentType) {
|
|
|
233
611
|
return 'pi pi-file-excel';
|
|
234
612
|
return 'pi pi-file';
|
|
235
613
|
}
|
|
236
|
-
/**
|
|
237
|
-
* Format file size for display
|
|
238
|
-
*/
|
|
239
614
|
function formatFileSize(sizeInKb) {
|
|
240
615
|
const kb = typeof sizeInKb === 'string' ? parseFloat(sizeInKb) : sizeInKb;
|
|
241
616
|
if (kb < 1024)
|
|
@@ -243,8 +618,7 @@ function formatFileSize(sizeInKb) {
|
|
|
243
618
|
const mb = kb / 1024;
|
|
244
619
|
if (mb < 1024)
|
|
245
620
|
return `${mb.toFixed(1)} MB`;
|
|
246
|
-
|
|
247
|
-
return `${gb.toFixed(2)} GB`;
|
|
621
|
+
return `${(mb / 1024).toFixed(2)} GB`;
|
|
248
622
|
}
|
|
249
623
|
|
|
250
624
|
var ContactTypeEnum;
|
|
@@ -719,6 +1093,156 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
719
1093
|
}]
|
|
720
1094
|
}], propDecorators: { eventType: [{ type: i0.Input, args: [{ isSignal: true, alias: "eventType", required: false }] }], preventKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "preventKey", required: false }] }], action: [{ type: i0.Output, args: ["action"] }] } });
|
|
721
1095
|
|
|
1096
|
+
class TranslatePipe {
|
|
1097
|
+
translateAdapter = inject(TRANSLATE_ADAPTER, { optional: true });
|
|
1098
|
+
fallbackMessages = inject(FALLBACK_MESSAGES_REGISTRY, { optional: true });
|
|
1099
|
+
transform(key, params) {
|
|
1100
|
+
if (!this.translateAdapter) {
|
|
1101
|
+
return this.getFromFallback(key, params);
|
|
1102
|
+
}
|
|
1103
|
+
// Read languageCode signal to create reactive dependency for zoneless mode
|
|
1104
|
+
// This ensures the pipe re-evaluates when language changes
|
|
1105
|
+
this.translateAdapter.languageCode();
|
|
1106
|
+
return this.translateAdapter.translate(key, params);
|
|
1107
|
+
}
|
|
1108
|
+
getFromFallback(template, params) {
|
|
1109
|
+
// Try to get from fallback messages registry first
|
|
1110
|
+
if (this.fallbackMessages) {
|
|
1111
|
+
const value = this.fallbackMessages[template];
|
|
1112
|
+
if (value) {
|
|
1113
|
+
return this.interpolate(value, params);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
// Fall back to interpolating the key itself
|
|
1117
|
+
return this.interpolate(template, params);
|
|
1118
|
+
}
|
|
1119
|
+
interpolate(template, params) {
|
|
1120
|
+
if (!params)
|
|
1121
|
+
return template;
|
|
1122
|
+
return template.replace(/\{\{(\w+)\}\}/g, (match, paramKey) => {
|
|
1123
|
+
const value = params[paramKey];
|
|
1124
|
+
return value !== undefined ? String(value) : match;
|
|
1125
|
+
});
|
|
1126
|
+
}
|
|
1127
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: TranslatePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1128
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.5", ngImport: i0, type: TranslatePipe, isStandalone: true, name: "translate", pure: false });
|
|
1129
|
+
}
|
|
1130
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: TranslatePipe, decorators: [{
|
|
1131
|
+
type: Pipe,
|
|
1132
|
+
args: [{
|
|
1133
|
+
name: 'translate',
|
|
1134
|
+
pure: false,
|
|
1135
|
+
}]
|
|
1136
|
+
}] });
|
|
1137
|
+
|
|
1138
|
+
async function tryLoadLocalizationServices(injector) {
|
|
1139
|
+
try {
|
|
1140
|
+
// @ts-ignore - ng-localization is optional and loaded dynamically at runtime
|
|
1141
|
+
const locModule = await import('@flusys/ng-localization');
|
|
1142
|
+
const config = injector.get(locModule.LOCALIZATION_CONFIG, null);
|
|
1143
|
+
if (!config)
|
|
1144
|
+
return null;
|
|
1145
|
+
return {
|
|
1146
|
+
stateService: injector.get(locModule.LocalizationStateService),
|
|
1147
|
+
apiService: injector.get(locModule.LocalizationApiService),
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
catch {
|
|
1151
|
+
return null;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
function resolveTranslationModule(config) {
|
|
1155
|
+
return async () => {
|
|
1156
|
+
const injector = inject(Injector);
|
|
1157
|
+
const { modules, fallbackMessages } = config;
|
|
1158
|
+
// Try to load localization services if available
|
|
1159
|
+
const locServices = await tryLoadLocalizationServices(injector);
|
|
1160
|
+
// Register fallback messages
|
|
1161
|
+
if (fallbackMessages) {
|
|
1162
|
+
if (locServices) {
|
|
1163
|
+
modules.forEach((module) => {
|
|
1164
|
+
if (!locServices.stateService.hasModuleFallbacks(module)) {
|
|
1165
|
+
locServices.stateService.registerModuleFallbacks(module, fallbackMessages);
|
|
1166
|
+
}
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
else {
|
|
1170
|
+
const registry = injector.get(FALLBACK_MESSAGES_REGISTRY, null);
|
|
1171
|
+
if (registry) {
|
|
1172
|
+
Object.assign(registry, fallbackMessages);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
if (!locServices)
|
|
1177
|
+
return true;
|
|
1178
|
+
// Load translations from API
|
|
1179
|
+
const languageCode = locServices.stateService.currentLanguageCode();
|
|
1180
|
+
const modulesToLoad = modules.filter((m) => !locServices.stateService.isModuleLoaded(m));
|
|
1181
|
+
if (modulesToLoad.length === 0)
|
|
1182
|
+
return true;
|
|
1183
|
+
try {
|
|
1184
|
+
const response = (await firstValueFrom(locServices.apiService.getTranslationsByLanguage(languageCode, modulesToLoad)));
|
|
1185
|
+
if (response?.success && response?.data) {
|
|
1186
|
+
locServices.stateService.mergeTranslations(response.data);
|
|
1187
|
+
modulesToLoad.forEach((m) => locServices.stateService.markModuleLoaded(m));
|
|
1188
|
+
}
|
|
1189
|
+
else if (modulesToLoad.length > 0 && isDevMode()) {
|
|
1190
|
+
console.warn(`No translation data received for modules: ${modulesToLoad.join(', ')}`);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
catch (error) {
|
|
1194
|
+
if (isDevMode()) {
|
|
1195
|
+
console.error(`Failed to load translations for modules: ${modules.join(', ')}`, error);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
return true;
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
/** Fallback translate adapter for when localization provider is not used */
|
|
1203
|
+
const createFallbackTranslateAdapter = (fallbackRegistry) => ({
|
|
1204
|
+
languageCode: signal('en'),
|
|
1205
|
+
translate: (key, params) => {
|
|
1206
|
+
// Check fallback messages registry first
|
|
1207
|
+
const value = fallbackRegistry[key];
|
|
1208
|
+
if (value) {
|
|
1209
|
+
// Simple parameter interpolation
|
|
1210
|
+
if (params) {
|
|
1211
|
+
return value.replace(/\{\{(\w+)\}\}/g, (match, paramKey) => {
|
|
1212
|
+
const paramValue = params[paramKey];
|
|
1213
|
+
return paramValue !== undefined ? String(paramValue) : match;
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
return value;
|
|
1217
|
+
}
|
|
1218
|
+
// Fall back to returning the key
|
|
1219
|
+
return key;
|
|
1220
|
+
},
|
|
1221
|
+
});
|
|
1222
|
+
/**
|
|
1223
|
+
* Provide fallback localization when @flusys/ng-localization is not used.
|
|
1224
|
+
* Uses hardcoded fallback messages registered by route resolvers.
|
|
1225
|
+
*
|
|
1226
|
+
* @example
|
|
1227
|
+
* ```typescript
|
|
1228
|
+
* providers: [
|
|
1229
|
+
* ...provideFallbackLocalization(),
|
|
1230
|
+
* ]
|
|
1231
|
+
* ```
|
|
1232
|
+
*/
|
|
1233
|
+
function provideFallbackLocalization() {
|
|
1234
|
+
return [
|
|
1235
|
+
// Fallback messages registry (populated by route resolvers)
|
|
1236
|
+
{ provide: FALLBACK_MESSAGES_REGISTRY, useValue: {} },
|
|
1237
|
+
// Fallback translate adapter (reads from registry)
|
|
1238
|
+
{
|
|
1239
|
+
provide: TRANSLATE_ADAPTER,
|
|
1240
|
+
useFactory: createFallbackTranslateAdapter,
|
|
1241
|
+
deps: [FALLBACK_MESSAGES_REGISTRY],
|
|
1242
|
+
},
|
|
1243
|
+
];
|
|
1244
|
+
}
|
|
1245
|
+
|
|
722
1246
|
class AngularModule {
|
|
723
1247
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AngularModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
724
1248
|
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.5", ngImport: i0, type: AngularModule, imports: [CommonModule,
|
|
@@ -1218,14 +1742,13 @@ class IconComponent {
|
|
|
1218
1742
|
<i class="pi pi-question"></i>
|
|
1219
1743
|
}
|
|
1220
1744
|
}
|
|
1221
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: IsEmptyImageDirective, selector: "img", inputs: ["src"] }]
|
|
1745
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: IsEmptyImageDirective, selector: "img", inputs: ["src"] }] });
|
|
1222
1746
|
}
|
|
1223
1747
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: IconComponent, decorators: [{
|
|
1224
1748
|
type: Component,
|
|
1225
1749
|
args: [{
|
|
1226
1750
|
selector: 'lib-icon',
|
|
1227
1751
|
imports: [AngularModule],
|
|
1228
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1229
1752
|
template: `
|
|
1230
1753
|
@if (icon()) {
|
|
1231
1754
|
@if (iconType() === IconTypeEnum.PRIMENG_ICON) {
|
|
@@ -1285,6 +1808,7 @@ function checkScrollPagination(event, config) {
|
|
|
1285
1808
|
class LazyMultiSelectComponent extends BaseFormControl {
|
|
1286
1809
|
document = inject(DOCUMENT$1);
|
|
1287
1810
|
appRef = inject(ApplicationRef);
|
|
1811
|
+
translateAdapter = inject(TRANSLATE_ADAPTER, { optional: true });
|
|
1288
1812
|
onDocumentClickBound = this.handleDocumentClick.bind(this);
|
|
1289
1813
|
// View references
|
|
1290
1814
|
pSelectRef = viewChild.required('pSelect');
|
|
@@ -1292,7 +1816,14 @@ class LazyMultiSelectComponent extends BaseFormControl {
|
|
|
1292
1816
|
// Portal state
|
|
1293
1817
|
overlayViewRef = null;
|
|
1294
1818
|
// Inputs
|
|
1295
|
-
placeHolder = input('
|
|
1819
|
+
placeHolder = input('', ...(ngDevMode ? [{ debugName: "placeHolder" }] : []));
|
|
1820
|
+
// Computed placeholder with translation fallback
|
|
1821
|
+
displayPlaceholder = computed(() => {
|
|
1822
|
+
const customPlaceholder = this.placeHolder();
|
|
1823
|
+
if (customPlaceholder)
|
|
1824
|
+
return customPlaceholder;
|
|
1825
|
+
return this.t('shared.multi.select.placeholder');
|
|
1826
|
+
}, ...(ngDevMode ? [{ debugName: "displayPlaceholder" }] : []));
|
|
1296
1827
|
isEditMode = input.required(...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
|
|
1297
1828
|
isLoading = input.required(...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
1298
1829
|
total = input.required(...(ngDevMode ? [{ debugName: "total" }] : []));
|
|
@@ -1312,7 +1843,7 @@ class LazyMultiSelectComponent extends BaseFormControl {
|
|
|
1312
1843
|
if (selectedValues.length === 0)
|
|
1313
1844
|
return '';
|
|
1314
1845
|
if (selectedValues.length > 3) {
|
|
1315
|
-
return
|
|
1846
|
+
return this.t('shared.multi.select.items.selected', { count: selectedValues.length });
|
|
1316
1847
|
}
|
|
1317
1848
|
return this.selectDataList()
|
|
1318
1849
|
.filter((item) => selectedValues.includes(item.value))
|
|
@@ -1450,12 +1981,18 @@ class LazyMultiSelectComponent extends BaseFormControl {
|
|
|
1450
1981
|
event.stopPropagation();
|
|
1451
1982
|
this.value.set([]);
|
|
1452
1983
|
}
|
|
1984
|
+
t(key, variables) {
|
|
1985
|
+
if (this.translateAdapter) {
|
|
1986
|
+
return this.translateAdapter.translate(key, variables);
|
|
1987
|
+
}
|
|
1988
|
+
return key;
|
|
1989
|
+
}
|
|
1453
1990
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: LazyMultiSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1454
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: LazyMultiSelectComponent, isStandalone: true, selector: "lib-lazy-multi-select", inputs: { placeHolder: { classPropertyName: "placeHolder", publicName: "placeHolder", isSignal: true, isRequired: false, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: true, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: true, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: true, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: true, transformFunction: null }, selectDataList: { classPropertyName: "selectDataList", publicName: "selectDataList", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onSearch: "onSearch", onPagination: "onPagination" }, providers: [provideValueAccessor(LazyMultiSelectComponent)], viewQueries: [{ propertyName: "pSelectRef", first: true, predicate: ["pSelect"], descendants: true, isSignal: true }, { propertyName: "overlayTemplate", first: true, predicate: ["overlayTpl"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div\n class=\"p-select w-full\"\n #pSelect\n (click)=\"onSelectClick()\"\n [class.p-disabled]=\"disabled()\"\n [class.edit-mode-element-css]=\"!isEditMode()\"\n [class.overflow-hidden]=\"!isEditMode()\"\n>\n @if (selectedValueDisplay()) {\n <span class=\"p-select-label\" [class.edit-mode-element-css]=\"!isEditMode()\">\n {{ selectedValueDisplay() }}\n </span>\n } @else {\n <span class=\"p-select-label p-placeholder\">{{
|
|
1991
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: LazyMultiSelectComponent, isStandalone: true, selector: "lib-lazy-multi-select", inputs: { placeHolder: { classPropertyName: "placeHolder", publicName: "placeHolder", isSignal: true, isRequired: false, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: true, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: true, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: true, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: true, transformFunction: null }, selectDataList: { classPropertyName: "selectDataList", publicName: "selectDataList", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onSearch: "onSearch", onPagination: "onPagination" }, providers: [provideValueAccessor(LazyMultiSelectComponent)], viewQueries: [{ propertyName: "pSelectRef", first: true, predicate: ["pSelect"], descendants: true, isSignal: true }, { propertyName: "overlayTemplate", first: true, predicate: ["overlayTpl"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div\n class=\"p-select w-full\"\n #pSelect\n (click)=\"onSelectClick()\"\n [class.p-disabled]=\"disabled()\"\n [class.edit-mode-element-css]=\"!isEditMode()\"\n [class.overflow-hidden]=\"!isEditMode()\"\n>\n @if (selectedValueDisplay()) {\n <span class=\"p-select-label\" [class.edit-mode-element-css]=\"!isEditMode()\">\n {{ selectedValueDisplay() }}\n </span>\n } @else {\n <span class=\"p-select-label p-placeholder\">{{ displayPlaceholder() }}</span>\n }\n\n @if (isEditMode()) {\n <span class=\"p-select-clear-icon\" (click)=\"clear($event)\">\n <i class=\"pi pi-times\"></i>\n </span>\n\n <div class=\"p-select-dropdown\">\n <span class=\"p-select-dropdown-icon flex items-center\">\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"p-multiselect-dropdown-icon p-icon\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M7.01744 10.398C6.91269 10.3985 6.8089 10.378 6.71215 10.3379C6.61541 10.2977 6.52766 10.2386 6.45405 10.1641L1.13907 4.84913C1.03306 4.69404 0.985221 4.5065 1.00399 4.31958C1.02276 4.13266 1.10693 3.95838 1.24166 3.82747C1.37639 3.69655 1.55301 3.61742 1.74039 3.60402C1.92777 3.59062 2.11386 3.64382 2.26584 3.75424L7.01744 8.47394L11.769 3.75424C11.9189 3.65709 12.097 3.61306 12.2748 3.62921C12.4527 3.64535 12.6199 3.72073 12.7498 3.84328C12.8797 3.96582 12.9647 4.12842 12.9912 4.30502C13.0177 4.48162 12.9841 4.662 12.8958 4.81724L7.58083 10.1322C7.50996 10.2125 7.42344 10.2775 7.32656 10.3232C7.22968 10.3689 7.12449 10.3944 7.01744 10.398Z\"\n fill=\"currentColor\"\n />\n </svg>\n </span>\n </div>\n }\n</div>\n\n<ng-template #overlayTpl>\n <div class=\"p-select-overlay\" (click)=\"onOverlayClick($event)\">\n <div class=\"p-select-header flex flex-row gap-2 items-center\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"isSelectAll()\"\n [disabled]=\"disabled()\"\n (onChange)=\"changeSelectAll($event)\"\n />\n <input\n type=\"text\"\n pInputText\n class=\"w-full\"\n [placeholder]=\"'shared.search' | translate\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"searchTerm.set($event)\"\n />\n </div>\n <div class=\"p-select-list-container\" (scroll)=\"onScroll($event)\">\n <ul class=\"p-select-list\">\n @for (data of selectDataList(); track data.value) {\n <li\n class=\"p-select-option flex flex-row gap-2 items-center\"\n [class.p-select-option-selected]=\"isSelected(data)\"\n >\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"isSelected(data)\"\n [disabled]=\"disabled()\"\n (onChange)=\"selectValue($event, data)\"\n />\n <span>{{ data.label }}</span>\n </li>\n }\n </ul>\n </div>\n </div>\n</ng-template>\n", styles: [".p-select-overlay{display:flex;flex-direction:column;max-height:250px;overflow:hidden}.p-select-header{padding:.75rem;border-bottom:1px solid var(--p-surface-border);background:var(--p-content-hover-background);flex-shrink:0;width:100%;box-sizing:border-box}.p-select-header input{background:var(--p-form-field-background);border-color:var(--p-form-field-border-color);color:var(--p-text-color)}.p-select-header input::placeholder{color:var(--p-text-muted-color)}.p-select-list-container{flex:1;overflow-y:auto;min-height:0;width:100%}.p-select-list{margin:0;padding:.25rem 0;list-style:none;background:var(--p-surface-overlay);color:var(--p-text-color);width:100%}.p-select-option{padding:.5rem .75rem;cursor:pointer;transition:background-color .2s ease;color:var(--p-text-color)}.p-select-option:hover{background:var(--p-content-hover-background)}.p-select-option.p-select-option-selected{background:var(--p-highlight-background);color:var(--p-highlight-color)}.p-select-option.p-select-option-selected:hover{background:var(--p-highlight-focus-background);color:var(--p-highlight-focus-color)}.p-select-clear-icon{display:flex;align-items:center;padding:0 .5rem;color:var(--p-text-muted-color);cursor:pointer;transition:color .2s ease}.p-select-clear-icon:hover{color:var(--p-text-color)}\n"], dependencies: [{ kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i1.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None });
|
|
1455
1992
|
}
|
|
1456
1993
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: LazyMultiSelectComponent, decorators: [{
|
|
1457
1994
|
type: Component,
|
|
1458
|
-
args: [{ selector: 'lib-lazy-multi-select', imports: [PrimeModule, AngularModule
|
|
1995
|
+
args: [{ selector: 'lib-lazy-multi-select', imports: [PrimeModule, AngularModule, TranslatePipe], encapsulation: ViewEncapsulation.None, providers: [provideValueAccessor(LazyMultiSelectComponent)], template: "<div\n class=\"p-select w-full\"\n #pSelect\n (click)=\"onSelectClick()\"\n [class.p-disabled]=\"disabled()\"\n [class.edit-mode-element-css]=\"!isEditMode()\"\n [class.overflow-hidden]=\"!isEditMode()\"\n>\n @if (selectedValueDisplay()) {\n <span class=\"p-select-label\" [class.edit-mode-element-css]=\"!isEditMode()\">\n {{ selectedValueDisplay() }}\n </span>\n } @else {\n <span class=\"p-select-label p-placeholder\">{{ displayPlaceholder() }}</span>\n }\n\n @if (isEditMode()) {\n <span class=\"p-select-clear-icon\" (click)=\"clear($event)\">\n <i class=\"pi pi-times\"></i>\n </span>\n\n <div class=\"p-select-dropdown\">\n <span class=\"p-select-dropdown-icon flex items-center\">\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"p-multiselect-dropdown-icon p-icon\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M7.01744 10.398C6.91269 10.3985 6.8089 10.378 6.71215 10.3379C6.61541 10.2977 6.52766 10.2386 6.45405 10.1641L1.13907 4.84913C1.03306 4.69404 0.985221 4.5065 1.00399 4.31958C1.02276 4.13266 1.10693 3.95838 1.24166 3.82747C1.37639 3.69655 1.55301 3.61742 1.74039 3.60402C1.92777 3.59062 2.11386 3.64382 2.26584 3.75424L7.01744 8.47394L11.769 3.75424C11.9189 3.65709 12.097 3.61306 12.2748 3.62921C12.4527 3.64535 12.6199 3.72073 12.7498 3.84328C12.8797 3.96582 12.9647 4.12842 12.9912 4.30502C13.0177 4.48162 12.9841 4.662 12.8958 4.81724L7.58083 10.1322C7.50996 10.2125 7.42344 10.2775 7.32656 10.3232C7.22968 10.3689 7.12449 10.3944 7.01744 10.398Z\"\n fill=\"currentColor\"\n />\n </svg>\n </span>\n </div>\n }\n</div>\n\n<ng-template #overlayTpl>\n <div class=\"p-select-overlay\" (click)=\"onOverlayClick($event)\">\n <div class=\"p-select-header flex flex-row gap-2 items-center\">\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"isSelectAll()\"\n [disabled]=\"disabled()\"\n (onChange)=\"changeSelectAll($event)\"\n />\n <input\n type=\"text\"\n pInputText\n class=\"w-full\"\n [placeholder]=\"'shared.search' | translate\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"searchTerm.set($event)\"\n />\n </div>\n <div class=\"p-select-list-container\" (scroll)=\"onScroll($event)\">\n <ul class=\"p-select-list\">\n @for (data of selectDataList(); track data.value) {\n <li\n class=\"p-select-option flex flex-row gap-2 items-center\"\n [class.p-select-option-selected]=\"isSelected(data)\"\n >\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"isSelected(data)\"\n [disabled]=\"disabled()\"\n (onChange)=\"selectValue($event, data)\"\n />\n <span>{{ data.label }}</span>\n </li>\n }\n </ul>\n </div>\n </div>\n</ng-template>\n", styles: [".p-select-overlay{display:flex;flex-direction:column;max-height:250px;overflow:hidden}.p-select-header{padding:.75rem;border-bottom:1px solid var(--p-surface-border);background:var(--p-content-hover-background);flex-shrink:0;width:100%;box-sizing:border-box}.p-select-header input{background:var(--p-form-field-background);border-color:var(--p-form-field-border-color);color:var(--p-text-color)}.p-select-header input::placeholder{color:var(--p-text-muted-color)}.p-select-list-container{flex:1;overflow-y:auto;min-height:0;width:100%}.p-select-list{margin:0;padding:.25rem 0;list-style:none;background:var(--p-surface-overlay);color:var(--p-text-color);width:100%}.p-select-option{padding:.5rem .75rem;cursor:pointer;transition:background-color .2s ease;color:var(--p-text-color)}.p-select-option:hover{background:var(--p-content-hover-background)}.p-select-option.p-select-option-selected{background:var(--p-highlight-background);color:var(--p-highlight-color)}.p-select-option.p-select-option-selected:hover{background:var(--p-highlight-focus-background);color:var(--p-highlight-focus-color)}.p-select-clear-icon{display:flex;align-items:center;padding:0 .5rem;color:var(--p-text-muted-color);cursor:pointer;transition:color .2s ease}.p-select-clear-icon:hover{color:var(--p-text-color)}\n"] }]
|
|
1459
1996
|
}], ctorParameters: () => [], propDecorators: { pSelectRef: [{ type: i0.ViewChild, args: ['pSelect', { isSignal: true }] }], overlayTemplate: [{ type: i0.ViewChild, args: ['overlayTpl', { isSignal: true }] }], placeHolder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeHolder", required: false }] }], isEditMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEditMode", required: true }] }], isLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLoading", required: true }] }], total: [{ type: i0.Input, args: [{ isSignal: true, alias: "total", required: true }] }], pagination: [{ type: i0.Input, args: [{ isSignal: true, alias: "pagination", required: true }] }], selectDataList: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectDataList", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], onSearch: [{ type: i0.Output, args: ["onSearch"] }], onPagination: [{ type: i0.Output, args: ["onPagination"] }] } });
|
|
1460
1997
|
|
|
1461
1998
|
/**
|
|
@@ -1468,13 +2005,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
1468
2005
|
*/
|
|
1469
2006
|
class LazySelectComponent extends BaseFormControl {
|
|
1470
2007
|
destroyRef = inject(DestroyRef);
|
|
2008
|
+
translateAdapter = inject(TRANSLATE_ADAPTER, { optional: true });
|
|
1471
2009
|
onScrollBound = this.onScroll.bind(this);
|
|
1472
2010
|
scrollTargetEl = null;
|
|
1473
2011
|
isDestroyed = false;
|
|
1474
2012
|
// View references
|
|
1475
2013
|
scrollContainer = viewChild.required('scrollContainer');
|
|
1476
2014
|
// Inputs
|
|
1477
|
-
placeHolder = input('
|
|
2015
|
+
placeHolder = input('', ...(ngDevMode ? [{ debugName: "placeHolder" }] : []));
|
|
2016
|
+
// Computed placeholder with translation fallback
|
|
2017
|
+
displayPlaceholder = computed(() => {
|
|
2018
|
+
const customPlaceholder = this.placeHolder();
|
|
2019
|
+
if (customPlaceholder)
|
|
2020
|
+
return customPlaceholder;
|
|
2021
|
+
return this.t('shared.select.placeholder');
|
|
2022
|
+
}, ...(ngDevMode ? [{ debugName: "displayPlaceholder" }] : []));
|
|
1478
2023
|
optionLabel = input.required(...(ngDevMode ? [{ debugName: "optionLabel" }] : []));
|
|
1479
2024
|
optionValue = input.required(...(ngDevMode ? [{ debugName: "optionValue" }] : []));
|
|
1480
2025
|
isEditMode = input.required(...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
|
|
@@ -1557,12 +2102,18 @@ class LazySelectComponent extends BaseFormControl {
|
|
|
1557
2102
|
onBlur() {
|
|
1558
2103
|
this.markAsTouched();
|
|
1559
2104
|
}
|
|
2105
|
+
t(key, variables) {
|
|
2106
|
+
if (this.translateAdapter) {
|
|
2107
|
+
return this.translateAdapter.translate(key, variables);
|
|
2108
|
+
}
|
|
2109
|
+
return key;
|
|
2110
|
+
}
|
|
1560
2111
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: LazySelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1561
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.5", type: LazySelectComponent, isStandalone: true, selector: "lib-lazy-select", inputs: { placeHolder: { classPropertyName: "placeHolder", publicName: "placeHolder", isSignal: true, isRequired: false, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: true, transformFunction: null }, optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: true, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: true, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: true, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: true, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: true, transformFunction: null }, selectDataList: { classPropertyName: "selectDataList", publicName: "selectDataList", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onSearch: "onSearch", onPagination: "onPagination" }, providers: [provideValueAccessor(LazySelectComponent)], viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div #scrollContainer class=\"lib-scroll-container\">\n <p-select\n class=\"w-full\"\n [options]=\"selectDataList()\"\n [optionLabel]=\"optionLabel()\"\n [optionValue]=\"optionValue()\"\n [filter]=\"true\"\n [showClear]=\"true\"\n [placeholder]=\"
|
|
2112
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.5", type: LazySelectComponent, isStandalone: true, selector: "lib-lazy-select", inputs: { placeHolder: { classPropertyName: "placeHolder", publicName: "placeHolder", isSignal: true, isRequired: false, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: true, transformFunction: null }, optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: true, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: true, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: true, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: true, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: true, transformFunction: null }, selectDataList: { classPropertyName: "selectDataList", publicName: "selectDataList", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onSearch: "onSearch", onPagination: "onPagination" }, providers: [provideValueAccessor(LazySelectComponent)], viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div #scrollContainer class=\"lib-scroll-container\">\n <p-select\n class=\"w-full\"\n [options]=\"selectDataList()\"\n [optionLabel]=\"optionLabel()\"\n [optionValue]=\"optionValue()\"\n [filter]=\"true\"\n [showClear]=\"true\"\n [placeholder]=\"displayPlaceholder()\"\n [disabled]=\"disabled()\"\n [(ngModel)]=\"value\"\n appEditModeElementChanger\n [isEditMode]=\"isEditMode()\"\n (click)=\"showPanel()\"\n (onBlur)=\"onBlur()\"\n >\n <ng-template #filter let-filter>\n <input\n pInputText\n class=\"w-full\"\n [ngModel]=\"searchTerm()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"searchTerm.set($event)\"\n />\n </ng-template>\n <ng-template #selectedItem let-selectedOption>\n {{ selectedOption[optionLabel()] }}\n </ng-template>\n <ng-template #item let-item>\n {{ item[optionLabel()] }}\n </ng-template>\n </p-select>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: i3.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "directive", type: EditModeElementChangerDirective, selector: "[appEditModeElementChanger]", inputs: ["isEditMode"] }] });
|
|
1562
2113
|
}
|
|
1563
2114
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: LazySelectComponent, decorators: [{
|
|
1564
2115
|
type: Component,
|
|
1565
|
-
args: [{ selector: 'lib-lazy-select', imports: [AngularModule, PrimeModule, EditModeElementChangerDirective],
|
|
2116
|
+
args: [{ selector: 'lib-lazy-select', imports: [AngularModule, PrimeModule, EditModeElementChangerDirective], providers: [provideValueAccessor(LazySelectComponent)], template: "<div #scrollContainer class=\"lib-scroll-container\">\n <p-select\n class=\"w-full\"\n [options]=\"selectDataList()\"\n [optionLabel]=\"optionLabel()\"\n [optionValue]=\"optionValue()\"\n [filter]=\"true\"\n [showClear]=\"true\"\n [placeholder]=\"displayPlaceholder()\"\n [disabled]=\"disabled()\"\n [(ngModel)]=\"value\"\n appEditModeElementChanger\n [isEditMode]=\"isEditMode()\"\n (click)=\"showPanel()\"\n (onBlur)=\"onBlur()\"\n >\n <ng-template #filter let-filter>\n <input\n pInputText\n class=\"w-full\"\n [ngModel]=\"searchTerm()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"searchTerm.set($event)\"\n />\n </ng-template>\n <ng-template #selectedItem let-selectedOption>\n {{ selectedOption[optionLabel()] }}\n </ng-template>\n <ng-template #item let-item>\n {{ item[optionLabel()] }}\n </ng-template>\n </p-select>\n</div>\n" }]
|
|
1566
2117
|
}], ctorParameters: () => [], propDecorators: { scrollContainer: [{ type: i0.ViewChild, args: ['scrollContainer', { isSignal: true }] }], placeHolder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeHolder", required: false }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: true }] }], optionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionValue", required: true }] }], isEditMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEditMode", required: true }] }], isLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLoading", required: true }] }], total: [{ type: i0.Input, args: [{ isSignal: true, alias: "total", required: true }] }], pagination: [{ type: i0.Input, args: [{ isSignal: true, alias: "pagination", required: true }] }], selectDataList: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectDataList", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], onSearch: [{ type: i0.Output, args: ["onSearch"] }], onPagination: [{ type: i0.Output, args: ["onPagination"] }] } });
|
|
1567
2118
|
|
|
1568
2119
|
/**
|
|
@@ -1638,14 +2189,6 @@ const AUTH_STATE_PROVIDER = new InjectionToken('AUTH_STATE_PROVIDER', {
|
|
|
1638
2189
|
* Use with `inject(PROFILE_PERMISSION_PROVIDER, { optional: true })`.
|
|
1639
2190
|
*/
|
|
1640
2191
|
const PROFILE_PERMISSION_PROVIDER = new InjectionToken('PROFILE_PERMISSION_PROVIDER');
|
|
1641
|
-
/**
|
|
1642
|
-
* Profile Upload Provider Token
|
|
1643
|
-
*
|
|
1644
|
-
* Provides file upload functionality for profile pictures.
|
|
1645
|
-
* Optional - if not configured or storage not enabled, upload section is hidden.
|
|
1646
|
-
* Use with `inject(PROFILE_UPLOAD_PROVIDER, { optional: true })`.
|
|
1647
|
-
*/
|
|
1648
|
-
const PROFILE_UPLOAD_PROVIDER = new InjectionToken('PROFILE_UPLOAD_PROVIDER');
|
|
1649
2192
|
/**
|
|
1650
2193
|
* User List Provider Token
|
|
1651
2194
|
*
|
|
@@ -1660,6 +2203,20 @@ const PROFILE_UPLOAD_PROVIDER = new InjectionToken('PROFILE_UPLOAD_PROVIDER');
|
|
|
1660
2203
|
* ]
|
|
1661
2204
|
*/
|
|
1662
2205
|
const USER_LIST_PROVIDER = new InjectionToken('USER_LIST_PROVIDER');
|
|
2206
|
+
/**
|
|
2207
|
+
* File Provider Token
|
|
2208
|
+
*
|
|
2209
|
+
* Provides file loading and upload functionality for file selectors.
|
|
2210
|
+
* Optional - if not configured, file selector requires loadFiles/uploadFile inputs.
|
|
2211
|
+
* Use with `inject(FILE_PROVIDER, { optional: true })`.
|
|
2212
|
+
*
|
|
2213
|
+
* @example
|
|
2214
|
+
* // In app.config.ts
|
|
2215
|
+
* providers: [
|
|
2216
|
+
* { provide: FILE_PROVIDER, useClass: StorageFileProvider },
|
|
2217
|
+
* ]
|
|
2218
|
+
*/
|
|
2219
|
+
const FILE_PROVIDER = new InjectionToken('FILE_PROVIDER');
|
|
1663
2220
|
|
|
1664
2221
|
const DEFAULT_PAGE_SIZE$1 = 20;
|
|
1665
2222
|
/**
|
|
@@ -1673,10 +2230,11 @@ class BaseUserSelectComponent {
|
|
|
1673
2230
|
destroyRef = inject(DestroyRef);
|
|
1674
2231
|
injector = inject(Injector);
|
|
1675
2232
|
userProvider = inject(USER_PROVIDER);
|
|
2233
|
+
translateAdapter = inject(TRANSLATE_ADAPTER, { optional: true });
|
|
1676
2234
|
abortController = null;
|
|
1677
2235
|
// Inputs
|
|
1678
2236
|
loadUsers = input(...(ngDevMode ? [undefined, { debugName: "loadUsers" }] : []));
|
|
1679
|
-
placeHolder = input('
|
|
2237
|
+
placeHolder = input('', ...(ngDevMode ? [{ debugName: "placeHolder" }] : []));
|
|
1680
2238
|
isEditMode = input.required(...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
|
|
1681
2239
|
filterActive = input(true, ...(ngDevMode ? [{ debugName: "filterActive" }] : []));
|
|
1682
2240
|
additionalFilters = input({}, ...(ngDevMode ? [{ debugName: "additionalFilters" }] : []));
|
|
@@ -1694,6 +2252,13 @@ class BaseUserSelectComponent {
|
|
|
1694
2252
|
label: user.name || user.email,
|
|
1695
2253
|
value: user.id,
|
|
1696
2254
|
})), ...(ngDevMode ? [{ debugName: "dropdownUsers" }] : []));
|
|
2255
|
+
// Computed placeholder with translation fallback
|
|
2256
|
+
displayPlaceholder = computed(() => {
|
|
2257
|
+
const customPlaceholder = this.placeHolder();
|
|
2258
|
+
if (customPlaceholder)
|
|
2259
|
+
return customPlaceholder;
|
|
2260
|
+
return this.t('shared.user.select.placeholder');
|
|
2261
|
+
}, ...(ngDevMode ? [{ debugName: "displayPlaceholder" }] : []));
|
|
1697
2262
|
constructor() {
|
|
1698
2263
|
// Cleanup on destroy
|
|
1699
2264
|
this.destroyRef.onDestroy(() => {
|
|
@@ -1786,6 +2351,12 @@ class BaseUserSelectComponent {
|
|
|
1786
2351
|
})),
|
|
1787
2352
|
})));
|
|
1788
2353
|
}
|
|
2354
|
+
t(key, variables) {
|
|
2355
|
+
if (this.translateAdapter) {
|
|
2356
|
+
return this.translateAdapter.translate(key, variables);
|
|
2357
|
+
}
|
|
2358
|
+
return key;
|
|
2359
|
+
}
|
|
1789
2360
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: BaseUserSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1790
2361
|
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.5", type: BaseUserSelectComponent, isStandalone: true, inputs: { loadUsers: { classPropertyName: "loadUsers", publicName: "loadUsers", isSignal: true, isRequired: false, transformFunction: null }, placeHolder: { classPropertyName: "placeHolder", publicName: "placeHolder", isSignal: true, isRequired: false, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: true, transformFunction: null }, filterActive: { classPropertyName: "filterActive", publicName: "filterActive", isSignal: true, isRequired: false, transformFunction: null }, additionalFilters: { classPropertyName: "additionalFilters", publicName: "additionalFilters", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onError: "onError" }, ngImport: i0 });
|
|
1791
2362
|
}
|
|
@@ -1845,7 +2416,7 @@ class UserSelectComponent extends BaseUserSelectComponent {
|
|
|
1845
2416
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.5", type: UserSelectComponent, isStandalone: true, selector: "lib-user-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", userSelected: "userSelected" }, usesInheritance: true, ngImport: i0, template: `
|
|
1846
2417
|
<lib-lazy-select
|
|
1847
2418
|
[(value)]="value"
|
|
1848
|
-
[placeHolder]="
|
|
2419
|
+
[placeHolder]="displayPlaceholder()"
|
|
1849
2420
|
[optionLabel]="'label'"
|
|
1850
2421
|
[optionValue]="'value'"
|
|
1851
2422
|
[isEditMode]="isEditMode()"
|
|
@@ -1856,7 +2427,7 @@ class UserSelectComponent extends BaseUserSelectComponent {
|
|
|
1856
2427
|
(onSearch)="handleSearch($event)"
|
|
1857
2428
|
(onPagination)="handlePagination($event)"
|
|
1858
2429
|
/>
|
|
1859
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: LazySelectComponent, selector: "lib-lazy-select", inputs: ["placeHolder", "optionLabel", "optionValue", "isEditMode", "isLoading", "total", "pagination", "selectDataList", "value"], outputs: ["valueChange", "onSearch", "onPagination"] }]
|
|
2430
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: LazySelectComponent, selector: "lib-lazy-select", inputs: ["placeHolder", "optionLabel", "optionValue", "isEditMode", "isLoading", "total", "pagination", "selectDataList", "value"], outputs: ["valueChange", "onSearch", "onPagination"] }] });
|
|
1860
2431
|
}
|
|
1861
2432
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserSelectComponent, decorators: [{
|
|
1862
2433
|
type: Component,
|
|
@@ -1866,7 +2437,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
1866
2437
|
template: `
|
|
1867
2438
|
<lib-lazy-select
|
|
1868
2439
|
[(value)]="value"
|
|
1869
|
-
[placeHolder]="
|
|
2440
|
+
[placeHolder]="displayPlaceholder()"
|
|
1870
2441
|
[optionLabel]="'label'"
|
|
1871
2442
|
[optionValue]="'value'"
|
|
1872
2443
|
[isEditMode]="isEditMode()"
|
|
@@ -1878,7 +2449,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
1878
2449
|
(onPagination)="handlePagination($event)"
|
|
1879
2450
|
/>
|
|
1880
2451
|
`,
|
|
1881
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1882
2452
|
}]
|
|
1883
2453
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], userSelected: [{ type: i0.Output, args: ["userSelected"] }] } });
|
|
1884
2454
|
|
|
@@ -1930,7 +2500,7 @@ class UserMultiSelectComponent extends BaseUserSelectComponent {
|
|
|
1930
2500
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.5", type: UserMultiSelectComponent, isStandalone: true, selector: "lib-user-multi-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", usersSelected: "usersSelected" }, usesInheritance: true, ngImport: i0, template: `
|
|
1931
2501
|
<lib-lazy-multi-select
|
|
1932
2502
|
[(value)]="value"
|
|
1933
|
-
[placeHolder]="
|
|
2503
|
+
[placeHolder]="displayPlaceholder()"
|
|
1934
2504
|
[isEditMode]="isEditMode()"
|
|
1935
2505
|
[isLoading]="isLoading()"
|
|
1936
2506
|
[total]="total()"
|
|
@@ -1939,7 +2509,7 @@ class UserMultiSelectComponent extends BaseUserSelectComponent {
|
|
|
1939
2509
|
(onSearch)="handleSearch($event)"
|
|
1940
2510
|
(onPagination)="handlePagination($event)"
|
|
1941
2511
|
/>
|
|
1942
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: LazyMultiSelectComponent, selector: "lib-lazy-multi-select", inputs: ["placeHolder", "isEditMode", "isLoading", "total", "pagination", "selectDataList", "value"], outputs: ["valueChange", "onSearch", "onPagination"] }]
|
|
2512
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: LazyMultiSelectComponent, selector: "lib-lazy-multi-select", inputs: ["placeHolder", "isEditMode", "isLoading", "total", "pagination", "selectDataList", "value"], outputs: ["valueChange", "onSearch", "onPagination"] }] });
|
|
1943
2513
|
}
|
|
1944
2514
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserMultiSelectComponent, decorators: [{
|
|
1945
2515
|
type: Component,
|
|
@@ -1949,7 +2519,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
1949
2519
|
template: `
|
|
1950
2520
|
<lib-lazy-multi-select
|
|
1951
2521
|
[(value)]="value"
|
|
1952
|
-
[placeHolder]="
|
|
2522
|
+
[placeHolder]="displayPlaceholder()"
|
|
1953
2523
|
[isEditMode]="isEditMode()"
|
|
1954
2524
|
[isLoading]="isLoading()"
|
|
1955
2525
|
[total]="total()"
|
|
@@ -1959,19 +2529,59 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
1959
2529
|
(onPagination)="handlePagination($event)"
|
|
1960
2530
|
/>
|
|
1961
2531
|
`,
|
|
1962
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1963
2532
|
}]
|
|
1964
2533
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], usersSelected: [{ type: i0.Output, args: ["usersSelected"] }] } });
|
|
1965
2534
|
|
|
1966
2535
|
/**
|
|
1967
2536
|
* File Uploader Component - Drag & drop file upload with type filtering.
|
|
1968
2537
|
*
|
|
1969
|
-
*
|
|
2538
|
+
* Uses FILE_PROVIDER when available (no inputs needed).
|
|
2539
|
+
* Optionally pass `uploadFile` to override the provider.
|
|
2540
|
+
*
|
|
2541
|
+
* @example
|
|
2542
|
+
* ```html
|
|
2543
|
+
* <!-- Using FILE_PROVIDER (recommended) -->
|
|
2544
|
+
* <lib-file-uploader
|
|
2545
|
+
* [acceptTypes]="['image/*']"
|
|
2546
|
+
* (fileUploaded)="onFileUploaded($event)"
|
|
2547
|
+
* />
|
|
2548
|
+
*
|
|
2549
|
+
* <!-- Custom upload function -->
|
|
2550
|
+
* <lib-file-uploader
|
|
2551
|
+
* [uploadFile]="customUploadFn"
|
|
2552
|
+
* (fileUploaded)="onFileUploaded($event)"
|
|
2553
|
+
* />
|
|
2554
|
+
* ```
|
|
1970
2555
|
*/
|
|
1971
2556
|
class FileUploaderComponent {
|
|
1972
2557
|
messageService = inject(MessageService);
|
|
1973
|
-
|
|
1974
|
-
|
|
2558
|
+
translateAdapter = inject(TRANSLATE_ADAPTER, { optional: true });
|
|
2559
|
+
fileProvider = inject(FILE_PROVIDER, { optional: true });
|
|
2560
|
+
// Optional: custom upload function (overrides FILE_PROVIDER)
|
|
2561
|
+
uploadFile = input(...(ngDevMode ? [undefined, { debugName: "uploadFile" }] : []));
|
|
2562
|
+
// Optional: function to upload multiple files at once (more efficient)
|
|
2563
|
+
uploadMultipleFiles = input(...(ngDevMode ? [undefined, { debugName: "uploadMultipleFiles" }] : []));
|
|
2564
|
+
// Check if upload capability is available
|
|
2565
|
+
hasUploadCapability = computed(() => !!this.uploadFile() || !!this.fileProvider, ...(ngDevMode ? [{ debugName: "hasUploadCapability" }] : []));
|
|
2566
|
+
// Get effective upload function (input or provider)
|
|
2567
|
+
getUploadFn() {
|
|
2568
|
+
const inputFn = this.uploadFile();
|
|
2569
|
+
if (inputFn)
|
|
2570
|
+
return inputFn;
|
|
2571
|
+
if (this.fileProvider)
|
|
2572
|
+
return (file, opts) => this.fileProvider.uploadFile(file, opts);
|
|
2573
|
+
throw new Error('shared.file.uploader.no.upload.function');
|
|
2574
|
+
}
|
|
2575
|
+
// Get effective multiple upload function
|
|
2576
|
+
getUploadMultipleFn() {
|
|
2577
|
+
const inputFn = this.uploadMultipleFiles();
|
|
2578
|
+
if (inputFn)
|
|
2579
|
+
return inputFn;
|
|
2580
|
+
if (this.fileProvider?.uploadMultipleFiles) {
|
|
2581
|
+
return (files, opts) => this.fileProvider.uploadMultipleFiles(files, opts);
|
|
2582
|
+
}
|
|
2583
|
+
return undefined;
|
|
2584
|
+
}
|
|
1975
2585
|
// Inputs
|
|
1976
2586
|
acceptTypes = input([], ...(ngDevMode ? [{ debugName: "acceptTypes" }] : []));
|
|
1977
2587
|
multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : []));
|
|
@@ -2001,14 +2611,14 @@ class FileUploaderComponent {
|
|
|
2001
2611
|
// Check if types match predefined filters
|
|
2002
2612
|
const typesStr = JSON.stringify(types);
|
|
2003
2613
|
if (typesStr === JSON.stringify(FILE_TYPE_FILTERS.IMAGES))
|
|
2004
|
-
return '
|
|
2614
|
+
return this.t('shared.file.type.images');
|
|
2005
2615
|
if (typesStr === JSON.stringify(FILE_TYPE_FILTERS.DOCUMENTS))
|
|
2006
|
-
return '
|
|
2616
|
+
return this.t('shared.file.type.documents');
|
|
2007
2617
|
if (typesStr === JSON.stringify(FILE_TYPE_FILTERS.VIDEOS))
|
|
2008
|
-
return '
|
|
2618
|
+
return this.t('shared.file.type.videos');
|
|
2009
2619
|
if (typesStr === JSON.stringify(FILE_TYPE_FILTERS.AUDIO))
|
|
2010
|
-
return '
|
|
2011
|
-
return types.map(t => t.split('/')[1] || t).join(', ');
|
|
2620
|
+
return this.t('shared.file.type.audio');
|
|
2621
|
+
return types.map((t) => t.split('/')[1] || t).join(', ');
|
|
2012
2622
|
}, ...(ngDevMode ? [{ debugName: "acceptTypesDisplay" }] : []));
|
|
2013
2623
|
onDragOver(event) {
|
|
2014
2624
|
event.preventDefault();
|
|
@@ -2045,12 +2655,12 @@ class FileUploaderComponent {
|
|
|
2045
2655
|
handleFiles(files) {
|
|
2046
2656
|
// Filter by type
|
|
2047
2657
|
const allowedTypes = this.acceptTypes();
|
|
2048
|
-
const validFiles = files.filter(file => {
|
|
2658
|
+
const validFiles = files.filter((file) => {
|
|
2049
2659
|
if (!isFileTypeAllowed(file, allowedTypes)) {
|
|
2050
2660
|
this.messageService.add({
|
|
2051
2661
|
severity: 'warn',
|
|
2052
|
-
summary: '
|
|
2053
|
-
detail:
|
|
2662
|
+
summary: this.t('shared.upload.invalid.type'),
|
|
2663
|
+
detail: `${file.name}`,
|
|
2054
2664
|
});
|
|
2055
2665
|
return false;
|
|
2056
2666
|
}
|
|
@@ -2058,12 +2668,12 @@ class FileUploaderComponent {
|
|
|
2058
2668
|
});
|
|
2059
2669
|
// Filter by size
|
|
2060
2670
|
const maxSize = this.maxSizeMb() * 1024 * 1024;
|
|
2061
|
-
const sizeValidFiles = validFiles.filter(file => {
|
|
2671
|
+
const sizeValidFiles = validFiles.filter((file) => {
|
|
2062
2672
|
if (file.size > maxSize) {
|
|
2063
2673
|
this.messageService.add({
|
|
2064
2674
|
severity: 'warn',
|
|
2065
|
-
summary: '
|
|
2066
|
-
detail: `${file.name}
|
|
2675
|
+
summary: this.t('shared.upload.file.too.large'),
|
|
2676
|
+
detail: `${file.name} (${this.maxSizeMb()}${this.t('shared.units.mb')})`,
|
|
2067
2677
|
});
|
|
2068
2678
|
return false;
|
|
2069
2679
|
}
|
|
@@ -2082,37 +2692,24 @@ class FileUploaderComponent {
|
|
|
2082
2692
|
}
|
|
2083
2693
|
}
|
|
2084
2694
|
removeFile(file) {
|
|
2085
|
-
this.selectedFiles.update(files => files.filter(f => f !== file));
|
|
2695
|
+
this.selectedFiles.update((files) => files.filter((f) => f !== file));
|
|
2086
2696
|
}
|
|
2087
2697
|
async uploadFiles(files) {
|
|
2088
2698
|
const filesToUpload = files ?? this.selectedFiles();
|
|
2089
2699
|
if (!filesToUpload.length || this.isUploading())
|
|
2090
2700
|
return;
|
|
2091
2701
|
this.isUploading.set(true);
|
|
2092
|
-
const uploadedFiles = [];
|
|
2093
2702
|
try {
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
}
|
|
2102
|
-
else {
|
|
2103
|
-
throw new Error(response.message || 'Upload failed');
|
|
2104
|
-
}
|
|
2703
|
+
const batchUploadFn = this.getUploadMultipleFn();
|
|
2704
|
+
// Use batch upload if available and multiple files
|
|
2705
|
+
if (batchUploadFn && filesToUpload.length > 1) {
|
|
2706
|
+
await this.uploadBatch(filesToUpload, batchUploadFn);
|
|
2707
|
+
}
|
|
2708
|
+
else {
|
|
2709
|
+
await this.uploadSequential(filesToUpload);
|
|
2105
2710
|
}
|
|
2106
|
-
this.filesUploaded.emit(uploadedFiles);
|
|
2107
|
-
this.selectedFiles.set([]);
|
|
2108
|
-
this.messageService.add({
|
|
2109
|
-
severity: 'success',
|
|
2110
|
-
summary: 'Upload Complete',
|
|
2111
|
-
detail: `${uploadedFiles.length} file(s) uploaded successfully`,
|
|
2112
|
-
});
|
|
2113
2711
|
}
|
|
2114
2712
|
catch (error) {
|
|
2115
|
-
// Error toast handled by global interceptor
|
|
2116
2713
|
this.onError.emit(error);
|
|
2117
2714
|
}
|
|
2118
2715
|
finally {
|
|
@@ -2121,54 +2718,113 @@ class FileUploaderComponent {
|
|
|
2121
2718
|
this.uploadProgress.set(0);
|
|
2122
2719
|
}
|
|
2123
2720
|
}
|
|
2721
|
+
async uploadBatch(files, uploadFn) {
|
|
2722
|
+
this.uploadingFileName.set(`${files.length} ${this.t('shared.upload.files')}`);
|
|
2723
|
+
this.uploadProgress.set(0);
|
|
2724
|
+
const response = await firstValueFrom(uploadFn(files, this.uploadOptions()));
|
|
2725
|
+
if (response.success && response.data) {
|
|
2726
|
+
response.data.forEach((file) => this.fileUploaded.emit(file));
|
|
2727
|
+
this.filesUploaded.emit(response.data);
|
|
2728
|
+
this.selectedFiles.set([]);
|
|
2729
|
+
this.messageService.add({
|
|
2730
|
+
severity: 'success',
|
|
2731
|
+
summary: this.t('shared.upload.complete'),
|
|
2732
|
+
detail: this.t('shared.upload.files.uploaded', { count: response.data.length }),
|
|
2733
|
+
});
|
|
2734
|
+
}
|
|
2735
|
+
else {
|
|
2736
|
+
throw new Error(response.message || this.t('shared.upload.failed'));
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
async uploadSequential(files) {
|
|
2740
|
+
const uploadedFiles = [];
|
|
2741
|
+
const uploadFn = this.getUploadFn();
|
|
2742
|
+
for (const file of files) {
|
|
2743
|
+
this.uploadingFileName.set(file.name);
|
|
2744
|
+
this.uploadProgress.set(0);
|
|
2745
|
+
const response = await firstValueFrom(uploadFn(file, this.uploadOptions()));
|
|
2746
|
+
if (response.success && response.data) {
|
|
2747
|
+
uploadedFiles.push(response.data);
|
|
2748
|
+
this.fileUploaded.emit(response.data);
|
|
2749
|
+
}
|
|
2750
|
+
else {
|
|
2751
|
+
throw new Error(response.message || this.t('shared.upload.failed'));
|
|
2752
|
+
}
|
|
2753
|
+
}
|
|
2754
|
+
this.filesUploaded.emit(uploadedFiles);
|
|
2755
|
+
this.selectedFiles.set([]);
|
|
2756
|
+
this.messageService.add({
|
|
2757
|
+
severity: 'success',
|
|
2758
|
+
summary: this.t('shared.upload.complete'),
|
|
2759
|
+
detail: this.t('shared.upload.files.uploaded', { count: uploadedFiles.length }),
|
|
2760
|
+
});
|
|
2761
|
+
}
|
|
2124
2762
|
getFileIcon(file) {
|
|
2125
2763
|
return getFileIconClass(file.type);
|
|
2126
2764
|
}
|
|
2127
2765
|
formatSize(bytes) {
|
|
2128
2766
|
const kb = bytes / 1024;
|
|
2129
2767
|
if (kb < 1024)
|
|
2130
|
-
return `${kb.toFixed(1)}
|
|
2768
|
+
return `${kb.toFixed(1)} ${this.t('shared.units.kb')}`;
|
|
2131
2769
|
const mb = kb / 1024;
|
|
2132
|
-
return `${mb.toFixed(1)}
|
|
2770
|
+
return `${mb.toFixed(1)} ${this.t('shared.units.mb')}`;
|
|
2771
|
+
}
|
|
2772
|
+
t(key, variables) {
|
|
2773
|
+
if (this.translateAdapter) {
|
|
2774
|
+
return this.translateAdapter.translate(key, variables);
|
|
2775
|
+
}
|
|
2776
|
+
return key;
|
|
2133
2777
|
}
|
|
2134
2778
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FileUploaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2135
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: FileUploaderComponent, isStandalone: true, selector: "lib-file-uploader", inputs: { uploadFile: { classPropertyName: "uploadFile", publicName: "uploadFile", isSignal: true, isRequired: true, transformFunction: null }, acceptTypes: { classPropertyName: "acceptTypes", publicName: "acceptTypes", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, maxFiles: { classPropertyName: "maxFiles", publicName: "maxFiles", isSignal: true, isRequired: false, transformFunction: null }, maxSizeMb: { classPropertyName: "maxSizeMb", publicName: "maxSizeMb", isSignal: true, isRequired: false, transformFunction: null }, uploadOptions: { classPropertyName: "uploadOptions", publicName: "uploadOptions", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showPreview: { classPropertyName: "showPreview", publicName: "showPreview", isSignal: true, isRequired: false, transformFunction: null }, autoUpload: { classPropertyName: "autoUpload", publicName: "autoUpload", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fileUploaded: "fileUploaded", filesUploaded: "filesUploaded", onError: "onError", fileSelected: "fileSelected" }, ngImport: i0, template: `
|
|
2136
|
-
|
|
2137
|
-
class="
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2779
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: FileUploaderComponent, isStandalone: true, selector: "lib-file-uploader", inputs: { uploadFile: { classPropertyName: "uploadFile", publicName: "uploadFile", isSignal: true, isRequired: false, transformFunction: null }, uploadMultipleFiles: { classPropertyName: "uploadMultipleFiles", publicName: "uploadMultipleFiles", isSignal: true, isRequired: false, transformFunction: null }, acceptTypes: { classPropertyName: "acceptTypes", publicName: "acceptTypes", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, maxFiles: { classPropertyName: "maxFiles", publicName: "maxFiles", isSignal: true, isRequired: false, transformFunction: null }, maxSizeMb: { classPropertyName: "maxSizeMb", publicName: "maxSizeMb", isSignal: true, isRequired: false, transformFunction: null }, uploadOptions: { classPropertyName: "uploadOptions", publicName: "uploadOptions", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showPreview: { classPropertyName: "showPreview", publicName: "showPreview", isSignal: true, isRequired: false, transformFunction: null }, autoUpload: { classPropertyName: "autoUpload", publicName: "autoUpload", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fileUploaded: "fileUploaded", filesUploaded: "filesUploaded", onError: "onError", fileSelected: "fileSelected" }, ngImport: i0, template: `
|
|
2780
|
+
@if (!hasUploadCapability()) {
|
|
2781
|
+
<div class="p-4 border border-dashed border-orange-300 bg-orange-50 dark:bg-orange-900/20 rounded-lg text-center">
|
|
2782
|
+
<i class="pi pi-exclamation-triangle text-2xl text-orange-500 mb-2"></i>
|
|
2783
|
+
<p class="text-sm text-orange-700 dark:text-orange-300">
|
|
2784
|
+
{{ 'shared.upload.provider.not.configured' | translate: { provider: 'provideStorageProviders()' } }}
|
|
2785
|
+
</p>
|
|
2786
|
+
</div>
|
|
2787
|
+
} @else {
|
|
2144
2788
|
<div
|
|
2145
|
-
class="
|
|
2146
|
-
[class.
|
|
2147
|
-
|
|
2148
|
-
(
|
|
2789
|
+
class="w-full"
|
|
2790
|
+
[class.opacity-60]="disabled()"
|
|
2791
|
+
(dragover)="onDragOver($event)"
|
|
2792
|
+
(dragleave)="onDragLeave($event)"
|
|
2793
|
+
(drop)="onDrop($event)"
|
|
2149
2794
|
>
|
|
2150
|
-
|
|
2795
|
+
<!-- Upload Area - Responsive padding -->
|
|
2796
|
+
<div
|
|
2797
|
+
class="upload-zone border-2 border-dashed rounded-lg p-4 sm:p-6 md:p-8 cursor-pointer transition-all duration-200 text-center"
|
|
2798
|
+
[class.drag-over]="isDragOver()"
|
|
2799
|
+
[class.cursor-not-allowed]="disabled()"
|
|
2800
|
+
(click)="fileInput.click()"
|
|
2801
|
+
>
|
|
2802
|
+
@if (isUploading()) {
|
|
2151
2803
|
<div class="flex flex-col items-center">
|
|
2152
2804
|
<i class="pi pi-spin pi-spinner text-3xl sm:text-4xl text-primary"></i>
|
|
2153
|
-
<p class="mt-2 text-sm sm:text-base break-all px-2">
|
|
2805
|
+
<p class="mt-2 text-sm sm:text-base break-all px-2">{{ 'shared.upload.uploading' | translate: { fileName: uploadingFileName() } }}</p>
|
|
2154
2806
|
@if (uploadProgress() > 0) {
|
|
2155
|
-
<p-progressBar
|
|
2807
|
+
<p-progressBar
|
|
2808
|
+
[value]="uploadProgress()"
|
|
2809
|
+
[showValue]="true"
|
|
2810
|
+
class="w-full mt-2 max-w-xs"
|
|
2811
|
+
/>
|
|
2156
2812
|
}
|
|
2157
2813
|
</div>
|
|
2158
2814
|
} @else {
|
|
2159
2815
|
<div class="flex flex-col items-center">
|
|
2160
2816
|
<i class="pi pi-cloud-upload text-3xl sm:text-4xl text-primary"></i>
|
|
2161
2817
|
<p class="mt-2 mb-1 font-semibold text-sm sm:text-base">
|
|
2162
|
-
{{ multiple() ? '
|
|
2818
|
+
{{ multiple() ? ('shared.upload.drop.multiple' | translate) : ('shared.upload.drop.single' | translate) }}
|
|
2163
2819
|
</p>
|
|
2164
2820
|
<p class="text-xs sm:text-sm text-color-secondary px-2">
|
|
2165
2821
|
@if (acceptTypesDisplay()) {
|
|
2166
|
-
|
|
2822
|
+
{{ 'shared.upload.allowed.types' | translate }} {{ acceptTypesDisplay() }}
|
|
2167
2823
|
} @else {
|
|
2168
|
-
|
|
2824
|
+
{{ 'shared.upload.all.types.allowed' | translate }}
|
|
2169
2825
|
}
|
|
2170
2826
|
@if (maxSizeMb()) {
|
|
2171
|
-
<span class="whitespace-nowrap">
|
|
2827
|
+
<span class="whitespace-nowrap">{{ 'shared.upload.max.size' | translate: { size: maxSizeMb() } }}</span>
|
|
2172
2828
|
}
|
|
2173
2829
|
</p>
|
|
2174
2830
|
</div>
|
|
@@ -2190,10 +2846,20 @@ class FileUploaderComponent {
|
|
|
2190
2846
|
@if (selectedFiles().length > 0 && showPreview()) {
|
|
2191
2847
|
<div class="mt-3 space-y-2">
|
|
2192
2848
|
@for (file of selectedFiles(); track file.name) {
|
|
2193
|
-
<div
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
<
|
|
2849
|
+
<div
|
|
2850
|
+
class="file-preview-item flex items-center gap-2 p-2 sm:p-3 rounded-lg"
|
|
2851
|
+
>
|
|
2852
|
+
<i
|
|
2853
|
+
[class]="getFileIcon(file)"
|
|
2854
|
+
class="text-lg sm:text-xl flex-shrink-0"
|
|
2855
|
+
></i>
|
|
2856
|
+
<span class="flex-1 truncate text-sm sm:text-base min-w-0">{{
|
|
2857
|
+
file.name
|
|
2858
|
+
}}</span>
|
|
2859
|
+
<span
|
|
2860
|
+
class="text-xs sm:text-sm text-color-secondary whitespace-nowrap"
|
|
2861
|
+
>{{ formatSize(file.size) }}</span
|
|
2862
|
+
>
|
|
2197
2863
|
<p-button
|
|
2198
2864
|
icon="pi pi-times"
|
|
2199
2865
|
[text]="true"
|
|
@@ -2207,48 +2873,61 @@ class FileUploaderComponent {
|
|
|
2207
2873
|
}
|
|
2208
2874
|
</div>
|
|
2209
2875
|
}
|
|
2210
|
-
|
|
2211
|
-
|
|
2876
|
+
</div>
|
|
2877
|
+
}
|
|
2878
|
+
`, isInline: true, styles: [".upload-zone{border-color:var(--p-surface-300);background:var(--p-surface-50)}.upload-zone:hover:not(.cursor-not-allowed){border-color:var(--p-primary-color);background:var(--p-surface-100)}.upload-zone.drag-over{border-color:var(--p-primary-color);background:var(--p-primary-50)}:host-context(.p-dark) .upload-zone,.dark .upload-zone{border-color:var(--p-surface-600);background:var(--p-surface-800)}:host-context(.p-dark) .upload-zone:hover:not(.cursor-not-allowed),.dark .upload-zone:hover:not(.cursor-not-allowed){border-color:var(--p-primary-color);background:var(--p-surface-700)}:host-context(.p-dark) .upload-zone.drag-over,.dark .upload-zone.drag-over{border-color:var(--p-primary-color);background:var(--p-primary-900)}.file-preview-item{border:1px solid var(--p-surface-200);background:var(--p-surface-0)}:host-context(.p-dark) .file-preview-item,.dark .file-preview-item{border-color:var(--p-surface-600);background:var(--p-surface-800)}\n"], dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i2$1.ProgressBar, selector: "p-progressBar, p-progressbar, p-progress-bar", inputs: ["value", "showValue", "styleClass", "valueStyleClass", "unit", "mode", "color"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
2212
2879
|
}
|
|
2213
2880
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FileUploaderComponent, decorators: [{
|
|
2214
2881
|
type: Component,
|
|
2215
|
-
args: [{ selector: 'lib-file-uploader', imports: [AngularModule, PrimeModule], template: `
|
|
2216
|
-
|
|
2217
|
-
class="
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2882
|
+
args: [{ selector: 'lib-file-uploader', imports: [AngularModule, PrimeModule, TranslatePipe], template: `
|
|
2883
|
+
@if (!hasUploadCapability()) {
|
|
2884
|
+
<div class="p-4 border border-dashed border-orange-300 bg-orange-50 dark:bg-orange-900/20 rounded-lg text-center">
|
|
2885
|
+
<i class="pi pi-exclamation-triangle text-2xl text-orange-500 mb-2"></i>
|
|
2886
|
+
<p class="text-sm text-orange-700 dark:text-orange-300">
|
|
2887
|
+
{{ 'shared.upload.provider.not.configured' | translate: { provider: 'provideStorageProviders()' } }}
|
|
2888
|
+
</p>
|
|
2889
|
+
</div>
|
|
2890
|
+
} @else {
|
|
2224
2891
|
<div
|
|
2225
|
-
class="
|
|
2226
|
-
[class.
|
|
2227
|
-
|
|
2228
|
-
(
|
|
2892
|
+
class="w-full"
|
|
2893
|
+
[class.opacity-60]="disabled()"
|
|
2894
|
+
(dragover)="onDragOver($event)"
|
|
2895
|
+
(dragleave)="onDragLeave($event)"
|
|
2896
|
+
(drop)="onDrop($event)"
|
|
2229
2897
|
>
|
|
2230
|
-
|
|
2898
|
+
<!-- Upload Area - Responsive padding -->
|
|
2899
|
+
<div
|
|
2900
|
+
class="upload-zone border-2 border-dashed rounded-lg p-4 sm:p-6 md:p-8 cursor-pointer transition-all duration-200 text-center"
|
|
2901
|
+
[class.drag-over]="isDragOver()"
|
|
2902
|
+
[class.cursor-not-allowed]="disabled()"
|
|
2903
|
+
(click)="fileInput.click()"
|
|
2904
|
+
>
|
|
2905
|
+
@if (isUploading()) {
|
|
2231
2906
|
<div class="flex flex-col items-center">
|
|
2232
2907
|
<i class="pi pi-spin pi-spinner text-3xl sm:text-4xl text-primary"></i>
|
|
2233
|
-
<p class="mt-2 text-sm sm:text-base break-all px-2">
|
|
2908
|
+
<p class="mt-2 text-sm sm:text-base break-all px-2">{{ 'shared.upload.uploading' | translate: { fileName: uploadingFileName() } }}</p>
|
|
2234
2909
|
@if (uploadProgress() > 0) {
|
|
2235
|
-
<p-progressBar
|
|
2910
|
+
<p-progressBar
|
|
2911
|
+
[value]="uploadProgress()"
|
|
2912
|
+
[showValue]="true"
|
|
2913
|
+
class="w-full mt-2 max-w-xs"
|
|
2914
|
+
/>
|
|
2236
2915
|
}
|
|
2237
2916
|
</div>
|
|
2238
2917
|
} @else {
|
|
2239
2918
|
<div class="flex flex-col items-center">
|
|
2240
2919
|
<i class="pi pi-cloud-upload text-3xl sm:text-4xl text-primary"></i>
|
|
2241
2920
|
<p class="mt-2 mb-1 font-semibold text-sm sm:text-base">
|
|
2242
|
-
{{ multiple() ? '
|
|
2921
|
+
{{ multiple() ? ('shared.upload.drop.multiple' | translate) : ('shared.upload.drop.single' | translate) }}
|
|
2243
2922
|
</p>
|
|
2244
2923
|
<p class="text-xs sm:text-sm text-color-secondary px-2">
|
|
2245
2924
|
@if (acceptTypesDisplay()) {
|
|
2246
|
-
|
|
2925
|
+
{{ 'shared.upload.allowed.types' | translate }} {{ acceptTypesDisplay() }}
|
|
2247
2926
|
} @else {
|
|
2248
|
-
|
|
2927
|
+
{{ 'shared.upload.all.types.allowed' | translate }}
|
|
2249
2928
|
}
|
|
2250
2929
|
@if (maxSizeMb()) {
|
|
2251
|
-
<span class="whitespace-nowrap">
|
|
2930
|
+
<span class="whitespace-nowrap">{{ 'shared.upload.max.size' | translate: { size: maxSizeMb() } }}</span>
|
|
2252
2931
|
}
|
|
2253
2932
|
</p>
|
|
2254
2933
|
</div>
|
|
@@ -2270,10 +2949,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
2270
2949
|
@if (selectedFiles().length > 0 && showPreview()) {
|
|
2271
2950
|
<div class="mt-3 space-y-2">
|
|
2272
2951
|
@for (file of selectedFiles(); track file.name) {
|
|
2273
|
-
<div
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
<
|
|
2952
|
+
<div
|
|
2953
|
+
class="file-preview-item flex items-center gap-2 p-2 sm:p-3 rounded-lg"
|
|
2954
|
+
>
|
|
2955
|
+
<i
|
|
2956
|
+
[class]="getFileIcon(file)"
|
|
2957
|
+
class="text-lg sm:text-xl flex-shrink-0"
|
|
2958
|
+
></i>
|
|
2959
|
+
<span class="flex-1 truncate text-sm sm:text-base min-w-0">{{
|
|
2960
|
+
file.name
|
|
2961
|
+
}}</span>
|
|
2962
|
+
<span
|
|
2963
|
+
class="text-xs sm:text-sm text-color-secondary whitespace-nowrap"
|
|
2964
|
+
>{{ formatSize(file.size) }}</span
|
|
2965
|
+
>
|
|
2277
2966
|
<p-button
|
|
2278
2967
|
icon="pi pi-times"
|
|
2279
2968
|
[text]="true"
|
|
@@ -2287,71 +2976,63 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
2287
2976
|
}
|
|
2288
2977
|
</div>
|
|
2289
2978
|
}
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2979
|
+
</div>
|
|
2980
|
+
}
|
|
2981
|
+
`, styles: [".upload-zone{border-color:var(--p-surface-300);background:var(--p-surface-50)}.upload-zone:hover:not(.cursor-not-allowed){border-color:var(--p-primary-color);background:var(--p-surface-100)}.upload-zone.drag-over{border-color:var(--p-primary-color);background:var(--p-primary-50)}:host-context(.p-dark) .upload-zone,.dark .upload-zone{border-color:var(--p-surface-600);background:var(--p-surface-800)}:host-context(.p-dark) .upload-zone:hover:not(.cursor-not-allowed),.dark .upload-zone:hover:not(.cursor-not-allowed){border-color:var(--p-primary-color);background:var(--p-surface-700)}:host-context(.p-dark) .upload-zone.drag-over,.dark .upload-zone.drag-over{border-color:var(--p-primary-color);background:var(--p-primary-900)}.file-preview-item{border:1px solid var(--p-surface-200);background:var(--p-surface-0)}:host-context(.p-dark) .file-preview-item,.dark .file-preview-item{border-color:var(--p-surface-600);background:var(--p-surface-800)}\n"] }]
|
|
2982
|
+
}], propDecorators: { uploadFile: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadFile", required: false }] }], uploadMultipleFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadMultipleFiles", required: false }] }], acceptTypes: [{ type: i0.Input, args: [{ isSignal: true, alias: "acceptTypes", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], maxFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFiles", required: false }] }], maxSizeMb: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSizeMb", required: false }] }], uploadOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadOptions", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], showPreview: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPreview", required: false }] }], autoUpload: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoUpload", required: false }] }], fileUploaded: [{ type: i0.Output, args: ["fileUploaded"] }], filesUploaded: [{ type: i0.Output, args: ["filesUploaded"] }], onError: [{ type: i0.Output, args: ["onError"] }], fileSelected: [{ type: i0.Output, args: ["fileSelected"] }] } });
|
|
2293
2983
|
|
|
2294
2984
|
const DEFAULT_PAGE_SIZE = 20;
|
|
2985
|
+
const DEFAULT_SELECTOR_PAGE_SIZE = 50;
|
|
2295
2986
|
/**
|
|
2296
|
-
* File Selector Dialog -
|
|
2987
|
+
* File Selector Dialog - Self-contained file browser with upload support.
|
|
2297
2988
|
*
|
|
2298
|
-
*
|
|
2989
|
+
* Uses FILE_PROVIDER internally - no external functions needed.
|
|
2990
|
+
* Just configure with inputs and handle selection events.
|
|
2299
2991
|
*
|
|
2300
2992
|
* Features:
|
|
2301
2993
|
* - Search with debouncing
|
|
2302
|
-
* - File type filtering
|
|
2994
|
+
* - File type filtering (acceptTypes)
|
|
2995
|
+
* - Folder filtering
|
|
2303
2996
|
* - Infinite scroll pagination
|
|
2304
2997
|
* - Single or multiple selection
|
|
2998
|
+
* - Built-in file upload (withUploader)
|
|
2305
2999
|
* - File preview with icons
|
|
2306
3000
|
*
|
|
2307
3001
|
* @example
|
|
2308
|
-
* ```typescript
|
|
2309
|
-
* // In component
|
|
2310
|
-
* readonly fileService = inject(FileManagerApiService);
|
|
2311
|
-
*
|
|
2312
|
-
* readonly loadFiles: LoadFilesFn = (filter) =>
|
|
2313
|
-
* this.fileService.getAll(filter.search, {
|
|
2314
|
-
* pagination: { currentPage: filter.page, pageSize: filter.pageSize },
|
|
2315
|
-
* filter: { contentTypes: filter.contentTypes },
|
|
2316
|
-
* }).pipe(
|
|
2317
|
-
* map(res => ({
|
|
2318
|
-
* ...res,
|
|
2319
|
-
* data: res.data?.map(f => ({
|
|
2320
|
-
* id: f.id,
|
|
2321
|
-
* name: f.name,
|
|
2322
|
-
* contentType: f.contentType,
|
|
2323
|
-
* size: f.size,
|
|
2324
|
-
* url: f.url
|
|
2325
|
-
* }))
|
|
2326
|
-
* }))
|
|
2327
|
-
* );
|
|
2328
|
-
* ```
|
|
2329
|
-
*
|
|
2330
3002
|
* ```html
|
|
2331
3003
|
* <lib-file-selector-dialog
|
|
2332
|
-
* [(visible)]="
|
|
2333
|
-
* [loadFiles]="loadFiles"
|
|
3004
|
+
* [(visible)]="showSelector"
|
|
2334
3005
|
* [acceptTypes]="['image/*']"
|
|
2335
|
-
* [multiple]="
|
|
2336
|
-
*
|
|
3006
|
+
* [multiple]="true"
|
|
3007
|
+
* [withUploader]="true"
|
|
3008
|
+
* (filesSelected)="onFilesSelected($event)"
|
|
2337
3009
|
* />
|
|
2338
3010
|
* ```
|
|
2339
3011
|
*/
|
|
2340
3012
|
class FileSelectorDialogComponent {
|
|
2341
3013
|
destroyRef = inject(DestroyRef);
|
|
3014
|
+
translateAdapter = inject(TRANSLATE_ADAPTER, { optional: true });
|
|
3015
|
+
fileProvider = inject(FILE_PROVIDER, { optional: true });
|
|
2342
3016
|
abortController = null;
|
|
2343
3017
|
searchDebounceTimer = null;
|
|
2344
|
-
//
|
|
2345
|
-
|
|
2346
|
-
// Inputs
|
|
2347
|
-
header = input('Select File', ...(ngDevMode ? [{ debugName: "header" }] : []));
|
|
3018
|
+
// Configuration inputs
|
|
3019
|
+
header = input(...(ngDevMode ? [undefined, { debugName: "header" }] : []));
|
|
2348
3020
|
acceptTypes = input([], ...(ngDevMode ? [{ debugName: "acceptTypes" }] : []));
|
|
2349
3021
|
multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : []));
|
|
3022
|
+
// Computed header - shows "Select Files" for multiple, allows custom override
|
|
3023
|
+
dialogHeader = computed(() => {
|
|
3024
|
+
const customHeader = this.header();
|
|
3025
|
+
if (customHeader)
|
|
3026
|
+
return customHeader;
|
|
3027
|
+
return this.t(this.multiple() ? 'shared.file.selector.select.files' : 'shared.file.selector.select.file');
|
|
3028
|
+
}, ...(ngDevMode ? [{ debugName: "dialogHeader" }] : []));
|
|
2350
3029
|
maxSelection = input(10, ...(ngDevMode ? [{ debugName: "maxSelection" }] : []));
|
|
2351
3030
|
pageSize = input(DEFAULT_PAGE_SIZE, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
|
|
3031
|
+
folderId = input(...(ngDevMode ? [undefined, { debugName: "folderId" }] : [])); // Filter by folder
|
|
3032
|
+
withUploader = input(false, ...(ngDevMode ? [{ debugName: "withUploader" }] : []));
|
|
2352
3033
|
// Two-way visibility binding
|
|
2353
3034
|
visible = model(false, ...(ngDevMode ? [{ debugName: "visible" }] : []));
|
|
2354
|
-
// Outputs
|
|
3035
|
+
// Outputs - return file IDs
|
|
2355
3036
|
fileSelected = output();
|
|
2356
3037
|
filesSelected = output();
|
|
2357
3038
|
closed = output();
|
|
@@ -2361,10 +3042,48 @@ class FileSelectorDialogComponent {
|
|
|
2361
3042
|
files = signal([], ...(ngDevMode ? [{ debugName: "files" }] : []));
|
|
2362
3043
|
selectedFiles = signal([], ...(ngDevMode ? [{ debugName: "selectedFiles" }] : []));
|
|
2363
3044
|
total = signal(undefined, ...(ngDevMode ? [{ debugName: "total" }] : []));
|
|
2364
|
-
pagination = signal({
|
|
3045
|
+
pagination = signal({
|
|
3046
|
+
pageSize: DEFAULT_PAGE_SIZE,
|
|
3047
|
+
currentPage: 0,
|
|
3048
|
+
}, ...(ngDevMode ? [{ debugName: "pagination" }] : []));
|
|
2365
3049
|
searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
|
|
2366
|
-
//
|
|
2367
|
-
|
|
3050
|
+
// Folder selector state
|
|
3051
|
+
folders = signal([], ...(ngDevMode ? [{ debugName: "folders" }] : []));
|
|
3052
|
+
selectedFolderId = signal(null, ...(ngDevMode ? [{ debugName: "selectedFolderId" }] : []));
|
|
3053
|
+
foldersLoading = signal(false, ...(ngDevMode ? [{ debugName: "foldersLoading" }] : []));
|
|
3054
|
+
foldersPagination = signal({
|
|
3055
|
+
pageSize: DEFAULT_SELECTOR_PAGE_SIZE,
|
|
3056
|
+
currentPage: 0,
|
|
3057
|
+
}, ...(ngDevMode ? [{ debugName: "foldersPagination" }] : []));
|
|
3058
|
+
foldersTotal = signal(undefined, ...(ngDevMode ? [{ debugName: "foldersTotal" }] : []));
|
|
3059
|
+
// Storage config selector state
|
|
3060
|
+
storageConfigs = signal([], ...(ngDevMode ? [{ debugName: "storageConfigs" }] : []));
|
|
3061
|
+
selectedStorageConfigId = signal(null, ...(ngDevMode ? [{ debugName: "selectedStorageConfigId" }] : []));
|
|
3062
|
+
storageConfigsLoading = signal(false, ...(ngDevMode ? [{ debugName: "storageConfigsLoading" }] : []));
|
|
3063
|
+
storageConfigsPagination = signal({
|
|
3064
|
+
pageSize: DEFAULT_SELECTOR_PAGE_SIZE,
|
|
3065
|
+
currentPage: 0,
|
|
3066
|
+
}, ...(ngDevMode ? [{ debugName: "storageConfigsPagination" }] : []));
|
|
3067
|
+
storageConfigsTotal = signal(undefined, ...(ngDevMode ? [{ debugName: "storageConfigsTotal" }] : []));
|
|
3068
|
+
// Get effective storage config ID (selected or default)
|
|
3069
|
+
effectiveStorageConfigId = computed(() => {
|
|
3070
|
+
const selected = this.selectedStorageConfigId();
|
|
3071
|
+
if (selected)
|
|
3072
|
+
return selected;
|
|
3073
|
+
// Find default config
|
|
3074
|
+
const defaultConfig = this.storageConfigs().find((c) => c.isDefault);
|
|
3075
|
+
return defaultConfig?.id;
|
|
3076
|
+
}, ...(ngDevMode ? [{ debugName: "effectiveStorageConfigId" }] : []));
|
|
3077
|
+
// Upload function bound to provider
|
|
3078
|
+
uploadFileFn = (file, options) => {
|
|
3079
|
+
if (!this.fileProvider)
|
|
3080
|
+
throw new Error('shared.file.selector.provider.not.configured');
|
|
3081
|
+
return this.fileProvider.uploadFile(file, options);
|
|
3082
|
+
};
|
|
3083
|
+
// Multiple upload function bound to provider (optional)
|
|
3084
|
+
uploadMultipleFilesFn = this.fileProvider?.uploadMultipleFiles
|
|
3085
|
+
? (files, options) => this.fileProvider.uploadMultipleFiles(files, options)
|
|
3086
|
+
: undefined;
|
|
2368
3087
|
constructor() {
|
|
2369
3088
|
this.destroyRef.onDestroy(() => {
|
|
2370
3089
|
this.abortController?.abort();
|
|
@@ -2372,13 +3091,17 @@ class FileSelectorDialogComponent {
|
|
|
2372
3091
|
clearTimeout(this.searchDebounceTimer);
|
|
2373
3092
|
}
|
|
2374
3093
|
});
|
|
2375
|
-
// Load files when dialog becomes visible
|
|
3094
|
+
// Load files and storage configs when dialog becomes visible
|
|
2376
3095
|
effect(() => {
|
|
2377
3096
|
const isVisible = this.visible();
|
|
2378
3097
|
if (isVisible) {
|
|
2379
3098
|
untracked(() => {
|
|
2380
3099
|
this.resetState();
|
|
2381
3100
|
this.fetchFiles();
|
|
3101
|
+
// Preload storage configs for upload default
|
|
3102
|
+
if (this.fileProvider?.loadStorageConfigs) {
|
|
3103
|
+
this.loadStorageConfigs();
|
|
3104
|
+
}
|
|
2382
3105
|
});
|
|
2383
3106
|
}
|
|
2384
3107
|
});
|
|
@@ -2391,7 +3114,6 @@ class FileSelectorDialogComponent {
|
|
|
2391
3114
|
});
|
|
2392
3115
|
}
|
|
2393
3116
|
onSearchChange(value) {
|
|
2394
|
-
// Debounce search
|
|
2395
3117
|
if (this.searchDebounceTimer) {
|
|
2396
3118
|
clearTimeout(this.searchDebounceTimer);
|
|
2397
3119
|
}
|
|
@@ -2471,15 +3193,131 @@ class FileSelectorDialogComponent {
|
|
|
2471
3193
|
onDialogHide() {
|
|
2472
3194
|
this.closed.emit();
|
|
2473
3195
|
}
|
|
3196
|
+
// Folder selector methods
|
|
3197
|
+
onFolderChange(folderId) {
|
|
3198
|
+
this.selectedFolderId.set(folderId);
|
|
3199
|
+
this.pagination.update((p) => ({ ...p, currentPage: 0 }));
|
|
3200
|
+
this.files.set([]);
|
|
3201
|
+
this.fetchFiles();
|
|
3202
|
+
}
|
|
3203
|
+
onFolderSearch(event) {
|
|
3204
|
+
this.foldersPagination.update((p) => ({ ...p, currentPage: 0 }));
|
|
3205
|
+
this.loadFolders(event.filter);
|
|
3206
|
+
}
|
|
3207
|
+
async loadFolders(search = '') {
|
|
3208
|
+
if (!this.fileProvider?.loadFolders || this.foldersLoading())
|
|
3209
|
+
return;
|
|
3210
|
+
this.foldersLoading.set(true);
|
|
3211
|
+
try {
|
|
3212
|
+
const pag = this.foldersPagination();
|
|
3213
|
+
const filter = {
|
|
3214
|
+
page: pag.currentPage,
|
|
3215
|
+
pageSize: pag.pageSize,
|
|
3216
|
+
search,
|
|
3217
|
+
};
|
|
3218
|
+
const response = await firstValueFrom(this.fileProvider.loadFolders(filter));
|
|
3219
|
+
if (response.success && response.data) {
|
|
3220
|
+
this.folders.set(response.data);
|
|
3221
|
+
this.foldersTotal.set(response.meta?.total);
|
|
3222
|
+
}
|
|
3223
|
+
}
|
|
3224
|
+
catch (error) {
|
|
3225
|
+
this.onError.emit(error);
|
|
3226
|
+
}
|
|
3227
|
+
finally {
|
|
3228
|
+
this.foldersLoading.set(false);
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
// Storage config selector methods
|
|
3232
|
+
onStorageConfigChange(configId) {
|
|
3233
|
+
this.selectedStorageConfigId.set(configId);
|
|
3234
|
+
this.pagination.update((p) => ({ ...p, currentPage: 0 }));
|
|
3235
|
+
this.files.set([]);
|
|
3236
|
+
this.fetchFiles();
|
|
3237
|
+
}
|
|
3238
|
+
onStorageConfigSearch(event) {
|
|
3239
|
+
this.storageConfigsPagination.update((p) => ({ ...p, currentPage: 0 }));
|
|
3240
|
+
this.loadStorageConfigs(event.filter);
|
|
3241
|
+
}
|
|
3242
|
+
async loadStorageConfigs(search = '') {
|
|
3243
|
+
if (!this.fileProvider?.loadStorageConfigs || this.storageConfigsLoading())
|
|
3244
|
+
return;
|
|
3245
|
+
this.storageConfigsLoading.set(true);
|
|
3246
|
+
try {
|
|
3247
|
+
const pag = this.storageConfigsPagination();
|
|
3248
|
+
const filter = {
|
|
3249
|
+
page: pag.currentPage,
|
|
3250
|
+
pageSize: pag.pageSize,
|
|
3251
|
+
search,
|
|
3252
|
+
};
|
|
3253
|
+
const response = await firstValueFrom(this.fileProvider.loadStorageConfigs(filter));
|
|
3254
|
+
if (response.success && response.data) {
|
|
3255
|
+
this.storageConfigs.set(response.data);
|
|
3256
|
+
this.storageConfigsTotal.set(response.meta?.total);
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
catch (error) {
|
|
3260
|
+
this.onError.emit(error);
|
|
3261
|
+
}
|
|
3262
|
+
finally {
|
|
3263
|
+
this.storageConfigsLoading.set(false);
|
|
3264
|
+
}
|
|
3265
|
+
}
|
|
3266
|
+
onFileUploaded(uploadedFile) {
|
|
3267
|
+
if (!uploadedFile.id)
|
|
3268
|
+
return;
|
|
3269
|
+
// Convert uploaded file to IFileBasicInfo
|
|
3270
|
+
const fileInfo = {
|
|
3271
|
+
id: uploadedFile.id,
|
|
3272
|
+
name: uploadedFile.name,
|
|
3273
|
+
contentType: uploadedFile.contentType,
|
|
3274
|
+
size: String(uploadedFile.size / 1024),
|
|
3275
|
+
url: null,
|
|
3276
|
+
};
|
|
3277
|
+
// Add to the beginning of files list
|
|
3278
|
+
this.files.update((current) => [fileInfo, ...current]);
|
|
3279
|
+
// Auto-select the uploaded file
|
|
3280
|
+
if (this.multiple()) {
|
|
3281
|
+
const selected = this.selectedFiles();
|
|
3282
|
+
if (selected.length < this.maxSelection()) {
|
|
3283
|
+
this.selectedFiles.update((files) => [...files, fileInfo]);
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3286
|
+
else {
|
|
3287
|
+
this.selectedFiles.set([fileInfo]);
|
|
3288
|
+
}
|
|
3289
|
+
// Refresh files to get proper URLs
|
|
3290
|
+
this.fetchFiles();
|
|
3291
|
+
}
|
|
2474
3292
|
resetState() {
|
|
3293
|
+
// Cancel any pending request and reset loading state
|
|
3294
|
+
this.abortController?.abort();
|
|
3295
|
+
this.abortController = null;
|
|
3296
|
+
this.isLoading.set(false);
|
|
2475
3297
|
this.files.set([]);
|
|
2476
3298
|
this.selectedFiles.set([]);
|
|
2477
3299
|
this.searchTerm.set('');
|
|
2478
3300
|
this.pagination.set({ pageSize: this.pageSize(), currentPage: 0 });
|
|
2479
3301
|
this.total.set(undefined);
|
|
3302
|
+
// Reset folder selector
|
|
3303
|
+
this.selectedFolderId.set(null);
|
|
3304
|
+
this.folders.set([]);
|
|
3305
|
+
this.foldersPagination.set({
|
|
3306
|
+
pageSize: DEFAULT_SELECTOR_PAGE_SIZE,
|
|
3307
|
+
currentPage: 0,
|
|
3308
|
+
});
|
|
3309
|
+
this.foldersTotal.set(undefined);
|
|
3310
|
+
// Reset storage config selector
|
|
3311
|
+
this.selectedStorageConfigId.set(null);
|
|
3312
|
+
this.storageConfigs.set([]);
|
|
3313
|
+
this.storageConfigsPagination.set({
|
|
3314
|
+
pageSize: DEFAULT_SELECTOR_PAGE_SIZE,
|
|
3315
|
+
currentPage: 0,
|
|
3316
|
+
});
|
|
3317
|
+
this.storageConfigsTotal.set(undefined);
|
|
2480
3318
|
}
|
|
2481
3319
|
async fetchFiles(append = false) {
|
|
2482
|
-
if (this.isLoading())
|
|
3320
|
+
if (!this.fileProvider || this.isLoading())
|
|
2483
3321
|
return;
|
|
2484
3322
|
this.abortController?.abort();
|
|
2485
3323
|
this.abortController = new AbortController();
|
|
@@ -2490,15 +3328,33 @@ class FileSelectorDialogComponent {
|
|
|
2490
3328
|
page: pag.currentPage,
|
|
2491
3329
|
pageSize: pag.pageSize,
|
|
2492
3330
|
search: this.searchTerm(),
|
|
2493
|
-
contentTypes: this.acceptTypes().length
|
|
3331
|
+
contentTypes: this.acceptTypes().length
|
|
3332
|
+
? this.acceptTypes()
|
|
3333
|
+
: undefined,
|
|
3334
|
+
folderId: this.selectedFolderId() || this.folderId(),
|
|
3335
|
+
storageConfigId: this.selectedStorageConfigId() || undefined,
|
|
2494
3336
|
};
|
|
2495
|
-
const response = await firstValueFrom(this.loadFiles(
|
|
3337
|
+
const response = await firstValueFrom(this.fileProvider.loadFiles(filter));
|
|
2496
3338
|
if (response.success && response.data) {
|
|
3339
|
+
let files = response.data;
|
|
3340
|
+
// Always fetch URLs for all files to get fresh presigned URLs
|
|
3341
|
+
if (this.fileProvider.getFileUrls && files.length > 0) {
|
|
3342
|
+
const fileIds = files.map((f) => f.id);
|
|
3343
|
+
const urlResponse = await firstValueFrom(this.fileProvider.getFileUrls(fileIds));
|
|
3344
|
+
if (urlResponse.success && urlResponse.data) {
|
|
3345
|
+
// Merge URLs into files
|
|
3346
|
+
const urlMap = new Map(urlResponse.data.map((f) => [f.id, f.url]));
|
|
3347
|
+
files = files.map((f) => ({
|
|
3348
|
+
...f,
|
|
3349
|
+
url: urlMap.get(f.id) ?? f.url,
|
|
3350
|
+
}));
|
|
3351
|
+
}
|
|
3352
|
+
}
|
|
2497
3353
|
if (append) {
|
|
2498
|
-
this.files.update((current) => [...current, ...
|
|
3354
|
+
this.files.update((current) => [...current, ...files]);
|
|
2499
3355
|
}
|
|
2500
3356
|
else {
|
|
2501
|
-
this.files.set(
|
|
3357
|
+
this.files.set(files);
|
|
2502
3358
|
}
|
|
2503
3359
|
this.total.set(response.meta?.total);
|
|
2504
3360
|
}
|
|
@@ -2512,10 +3368,16 @@ class FileSelectorDialogComponent {
|
|
|
2512
3368
|
this.isLoading.set(false);
|
|
2513
3369
|
}
|
|
2514
3370
|
}
|
|
3371
|
+
t(key, variables) {
|
|
3372
|
+
if (this.translateAdapter) {
|
|
3373
|
+
return this.translateAdapter.translate(key, variables);
|
|
3374
|
+
}
|
|
3375
|
+
return key;
|
|
3376
|
+
}
|
|
2515
3377
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FileSelectorDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2516
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: FileSelectorDialogComponent, isStandalone: true, selector: "lib-file-selector-dialog", inputs: {
|
|
3378
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: FileSelectorDialogComponent, isStandalone: true, selector: "lib-file-selector-dialog", inputs: { header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, acceptTypes: { classPropertyName: "acceptTypes", publicName: "acceptTypes", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, maxSelection: { classPropertyName: "maxSelection", publicName: "maxSelection", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, folderId: { classPropertyName: "folderId", publicName: "folderId", isSignal: true, isRequired: false, transformFunction: null }, withUploader: { classPropertyName: "withUploader", publicName: "withUploader", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { visible: "visibleChange", fileSelected: "fileSelected", filesSelected: "filesSelected", closed: "closed", onError: "onError" }, ngImport: i0, template: `
|
|
2517
3379
|
<p-dialog
|
|
2518
|
-
[header]="
|
|
3380
|
+
[header]="dialogHeader()"
|
|
2519
3381
|
[(visible)]="visible"
|
|
2520
3382
|
[modal]="true"
|
|
2521
3383
|
[closable]="true"
|
|
@@ -2526,107 +3388,246 @@ class FileSelectorDialogComponent {
|
|
|
2526
3388
|
styleClass="file-selector-dialog"
|
|
2527
3389
|
(onHide)="onDialogHide()"
|
|
2528
3390
|
>
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
class="
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
3391
|
+
@if (!fileProvider) {
|
|
3392
|
+
<div class="p-6 text-center">
|
|
3393
|
+
<i
|
|
3394
|
+
class="pi pi-exclamation-triangle text-4xl text-orange-500 mb-3"
|
|
3395
|
+
></i>
|
|
3396
|
+
<p class="text-lg font-medium text-color mb-2">
|
|
3397
|
+
{{ 'shared.file.selector.provider.not.configured' | translate }}
|
|
3398
|
+
</p>
|
|
3399
|
+
<p class="text-sm text-color-secondary mb-4">
|
|
3400
|
+
{{ 'shared.file.selector.add.provider' | translate }}
|
|
3401
|
+
<code class="inline-block bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 px-2 py-1 rounded font-mono text-xs">provideStorageProviders()</code>
|
|
3402
|
+
</p>
|
|
3403
|
+
<button
|
|
3404
|
+
pButton
|
|
3405
|
+
[label]="'shared.close' | translate"
|
|
3406
|
+
class="p-button-text"
|
|
3407
|
+
(click)="onCancel()"
|
|
3408
|
+
></button>
|
|
3409
|
+
</div>
|
|
3410
|
+
} @else {
|
|
3411
|
+
<!-- Upload Section (when withUploader is enabled) -->
|
|
3412
|
+
@if (withUploader()) {
|
|
3413
|
+
<div class="mb-4">
|
|
3414
|
+
<lib-file-uploader
|
|
3415
|
+
[uploadFile]="uploadFileFn"
|
|
3416
|
+
[uploadMultipleFiles]="uploadMultipleFilesFn"
|
|
3417
|
+
[uploadOptions]="{ storageConfigId: effectiveStorageConfigId() }"
|
|
3418
|
+
[acceptTypes]="acceptTypes()"
|
|
3419
|
+
[multiple]="multiple()"
|
|
3420
|
+
[maxFiles]="maxSelection()"
|
|
3421
|
+
[maxSizeMb]="10"
|
|
3422
|
+
[showPreview]="false"
|
|
3423
|
+
(fileUploaded)="onFileUploaded($event)"
|
|
3424
|
+
/>
|
|
3425
|
+
</div>
|
|
2546
3426
|
}
|
|
2547
|
-
</div>
|
|
2548
3427
|
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
[
|
|
2570
|
-
|
|
3428
|
+
<!-- Filters Row - All on same line on desktop -->
|
|
3429
|
+
<div
|
|
3430
|
+
class="flex flex-col sm:flex-row gap-2 mb-3 items-stretch sm:items-center"
|
|
3431
|
+
>
|
|
3432
|
+
<!-- Search -->
|
|
3433
|
+
<p-iconfield class="flex-1">
|
|
3434
|
+
<p-inputicon class="pi pi-search" />
|
|
3435
|
+
<input
|
|
3436
|
+
pInputText
|
|
3437
|
+
type="text"
|
|
3438
|
+
[ngModel]="searchTerm()"
|
|
3439
|
+
(ngModelChange)="onSearchChange($event)"
|
|
3440
|
+
[placeholder]="'shared.file.selector.search.placeholder' | translate"
|
|
3441
|
+
class="w-full"
|
|
3442
|
+
/>
|
|
3443
|
+
</p-iconfield>
|
|
3444
|
+
|
|
3445
|
+
<!-- Folder Selector -->
|
|
3446
|
+
@if (fileProvider.loadFolders) {
|
|
3447
|
+
<p-select
|
|
3448
|
+
[options]="folders()"
|
|
3449
|
+
[ngModel]="selectedFolderId()"
|
|
3450
|
+
(ngModelChange)="onFolderChange($event)"
|
|
3451
|
+
optionLabel="name"
|
|
3452
|
+
optionValue="id"
|
|
3453
|
+
[placeholder]="'shared.file.selector.all.folders' | translate"
|
|
3454
|
+
[showClear]="true"
|
|
3455
|
+
[filter]="true"
|
|
3456
|
+
filterBy="name"
|
|
3457
|
+
(onFilter)="onFolderSearch($event)"
|
|
3458
|
+
[loading]="foldersLoading()"
|
|
3459
|
+
class="w-full sm:w-40"
|
|
3460
|
+
(onShow)="loadFolders()"
|
|
2571
3461
|
>
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
<
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
<
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
3462
|
+
<ng-template pTemplate="selectedItem" let-folder>
|
|
3463
|
+
<div class="flex items-center gap-2">
|
|
3464
|
+
<i class="pi pi-folder text-color-secondary"></i>
|
|
3465
|
+
<span>{{ folder?.name }}</span>
|
|
3466
|
+
</div>
|
|
3467
|
+
</ng-template>
|
|
3468
|
+
<ng-template pTemplate="item" let-folder>
|
|
3469
|
+
<div class="flex items-center gap-2">
|
|
3470
|
+
<i class="pi pi-folder text-color-secondary"></i>
|
|
3471
|
+
<span>{{ folder.name }}</span>
|
|
3472
|
+
</div>
|
|
3473
|
+
</ng-template>
|
|
3474
|
+
</p-select>
|
|
3475
|
+
}
|
|
2585
3476
|
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
3477
|
+
<!-- Storage Config Selector -->
|
|
3478
|
+
@if (fileProvider.loadStorageConfigs) {
|
|
3479
|
+
<p-select
|
|
3480
|
+
[options]="storageConfigs()"
|
|
3481
|
+
[ngModel]="selectedStorageConfigId()"
|
|
3482
|
+
(ngModelChange)="onStorageConfigChange($event)"
|
|
3483
|
+
optionLabel="name"
|
|
3484
|
+
optionValue="id"
|
|
3485
|
+
[placeholder]="'shared.file.selector.all.storage' | translate"
|
|
3486
|
+
[showClear]="true"
|
|
3487
|
+
[filter]="true"
|
|
3488
|
+
filterBy="name"
|
|
3489
|
+
(onFilter)="onStorageConfigSearch($event)"
|
|
3490
|
+
[loading]="storageConfigsLoading()"
|
|
3491
|
+
class="w-full sm:w-40"
|
|
3492
|
+
(onShow)="loadStorageConfigs()"
|
|
3493
|
+
>
|
|
3494
|
+
<ng-template pTemplate="selectedItem" let-config>
|
|
3495
|
+
<div class="flex items-center gap-2">
|
|
3496
|
+
<i class="pi pi-database text-color-secondary"></i>
|
|
3497
|
+
<span>{{ config?.name }}</span>
|
|
3498
|
+
@if (config?.isDefault) {
|
|
3499
|
+
<span
|
|
3500
|
+
class="text-xs bg-primary text-primary-contrast px-1 rounded"
|
|
3501
|
+
>{{ 'shared.default' | translate }}</span
|
|
3502
|
+
>
|
|
3503
|
+
}
|
|
3504
|
+
</div>
|
|
3505
|
+
</ng-template>
|
|
3506
|
+
<ng-template pTemplate="item" let-config>
|
|
3507
|
+
<div class="flex items-center gap-2">
|
|
3508
|
+
<i class="pi pi-database text-color-secondary"></i>
|
|
3509
|
+
<span>{{ config.name }}</span>
|
|
3510
|
+
@if (config.isDefault) {
|
|
3511
|
+
<span
|
|
3512
|
+
class="text-xs bg-primary text-primary-contrast px-1 rounded"
|
|
3513
|
+
>{{ 'shared.default' | translate }}</span
|
|
3514
|
+
>
|
|
3515
|
+
}
|
|
3516
|
+
</div>
|
|
3517
|
+
</ng-template>
|
|
3518
|
+
</p-select>
|
|
2594
3519
|
}
|
|
2595
3520
|
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
3521
|
+
<!-- Selected count -->
|
|
3522
|
+
@if (multiple()) {
|
|
3523
|
+
<span
|
|
3524
|
+
class="text-sm text-color-secondary self-center whitespace-nowrap"
|
|
3525
|
+
>
|
|
3526
|
+
{{ 'shared.file.selector.selected' | translate: { count: selectedFiles().length } }}
|
|
3527
|
+
</span>
|
|
2600
3528
|
}
|
|
2601
|
-
|
|
2602
|
-
</div>
|
|
3529
|
+
</div>
|
|
2603
3530
|
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
(
|
|
2619
|
-
|
|
3531
|
+
<!-- File Grid - Responsive columns -->
|
|
3532
|
+
<div class="file-grid" #scrollContainer (scroll)="onScroll($event)">
|
|
3533
|
+
@if (isLoading() && files().length === 0) {
|
|
3534
|
+
<div class="col-span-full flex justify-center p-4">
|
|
3535
|
+
<i
|
|
3536
|
+
class="pi pi-spin pi-spinner text-4xl text-color-secondary"
|
|
3537
|
+
></i>
|
|
3538
|
+
</div>
|
|
3539
|
+
} @else if (files().length === 0) {
|
|
3540
|
+
<div class="col-span-full text-center p-4 text-color-secondary">
|
|
3541
|
+
<i class="pi pi-inbox text-4xl mb-2 block"></i>
|
|
3542
|
+
<p>{{ 'shared.file.selector.no.files' | translate }}</p>
|
|
3543
|
+
</div>
|
|
3544
|
+
} @else {
|
|
3545
|
+
@for (file of files(); track file.id) {
|
|
3546
|
+
<div
|
|
3547
|
+
class="file-card"
|
|
3548
|
+
[class.selected]="isSelected(file)"
|
|
3549
|
+
[class.disabled]="!isFileAllowed(file)"
|
|
3550
|
+
(click)="toggleSelection(file)"
|
|
3551
|
+
>
|
|
3552
|
+
<!-- File Preview -->
|
|
3553
|
+
<div class="file-preview">
|
|
3554
|
+
@if (isImage(file) && file.url) {
|
|
3555
|
+
<img
|
|
3556
|
+
[src]="file.url"
|
|
3557
|
+
[alt]="file.name"
|
|
3558
|
+
class="w-full h-full object-cover"
|
|
3559
|
+
/>
|
|
3560
|
+
} @else {
|
|
3561
|
+
<i
|
|
3562
|
+
[class]="getFileIcon(file)"
|
|
3563
|
+
class="text-4xl sm:text-5xl text-color-secondary"
|
|
3564
|
+
></i>
|
|
3565
|
+
}
|
|
3566
|
+
@if (isSelected(file)) {
|
|
3567
|
+
<div class="selected-overlay">
|
|
3568
|
+
<i class="pi pi-check text-xl sm:text-2xl"></i>
|
|
3569
|
+
</div>
|
|
3570
|
+
}
|
|
3571
|
+
</div>
|
|
3572
|
+
|
|
3573
|
+
<!-- File Info -->
|
|
3574
|
+
<div class="p-2 text-center bg-surface-0 dark:bg-surface-900">
|
|
3575
|
+
<span
|
|
3576
|
+
class="block text-xs sm:text-sm whitespace-nowrap overflow-hidden text-ellipsis"
|
|
3577
|
+
[title]="file.name"
|
|
3578
|
+
>
|
|
3579
|
+
{{ file.name }}
|
|
3580
|
+
</span>
|
|
3581
|
+
<span class="block text-xs text-color-secondary">{{
|
|
3582
|
+
formatSize(file.size)
|
|
3583
|
+
}}</span>
|
|
3584
|
+
</div>
|
|
3585
|
+
</div>
|
|
3586
|
+
}
|
|
3587
|
+
|
|
3588
|
+
@if (isLoading()) {
|
|
3589
|
+
<div class="col-span-full flex justify-center p-2">
|
|
3590
|
+
<i class="pi pi-spin pi-spinner text-color-secondary"></i>
|
|
3591
|
+
</div>
|
|
3592
|
+
}
|
|
3593
|
+
}
|
|
2620
3594
|
</div>
|
|
2621
|
-
|
|
3595
|
+
|
|
3596
|
+
<!-- Footer -->
|
|
3597
|
+
<ng-template pTemplate="footer">
|
|
3598
|
+
<div
|
|
3599
|
+
class="flex flex-col-reverse sm:flex-row gap-2 w-full sm:w-auto sm:justify-end"
|
|
3600
|
+
>
|
|
3601
|
+
<button
|
|
3602
|
+
pButton
|
|
3603
|
+
type="button"
|
|
3604
|
+
[label]="'shared.cancel' | translate"
|
|
3605
|
+
class="p-button-text w-full sm:w-auto"
|
|
3606
|
+
(click)="onCancel()"
|
|
3607
|
+
></button>
|
|
3608
|
+
<button
|
|
3609
|
+
pButton
|
|
3610
|
+
type="button"
|
|
3611
|
+
[label]="
|
|
3612
|
+
multiple()
|
|
3613
|
+
? ('shared.file.selector.select.multiple' | translate: { count: selectedFiles().length })
|
|
3614
|
+
: ('shared.file.selector.select' | translate)
|
|
3615
|
+
"
|
|
3616
|
+
[disabled]="selectedFiles().length === 0"
|
|
3617
|
+
class="w-full sm:w-auto"
|
|
3618
|
+
(click)="onConfirm()"
|
|
3619
|
+
></button>
|
|
3620
|
+
</div>
|
|
3621
|
+
</ng-template>
|
|
3622
|
+
}
|
|
2622
3623
|
</p-dialog>
|
|
2623
|
-
`, isInline: true, styles: [".file-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:.75rem;max-height:300px;overflow-y:auto;padding:.5rem}@media(min-width:480px){.file-grid{grid-template-columns:repeat(3,1fr);max-height:350px}}@media(min-width:640px){.file-grid{grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:1rem;max-height:400px}}.file-card{border:2px solid var(--p-surface-300);border-radius:var(--p-border-radius);cursor:pointer;transition:all .2s ease;overflow:hidden;background:var(--p-surface-0)}:host-context(.p-dark) .file-card,.dark .file-card{border-color:var(--p-surface-600);background:var(--p-surface-800)}.file-card:hover:not(.disabled){border-color:var(--p-primary-color);transform:translateY(-2px);box-shadow:var(--p-overlay-shadow)}.file-card.selected{border-color:var(--p-primary-color);background:var(--p-primary-50)}:host-context(.p-dark) .file-card.selected,.dark .file-card.selected{background:var(--p-primary-900)}.file-card.disabled{opacity:.5;cursor:not-allowed}.file-preview{position:relative;height:80px;display:flex;align-items:center;justify-content:center;background:var(--p-surface-100)}@media(min-width:640px){.file-preview{height:100px}}:host-context(.p-dark) .file-preview,.dark .file-preview{background:var(--p-surface-700)}.selected-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(var(--p-primary-500-rgb, 59, 130, 246),.3)}.selected-overlay i{color:var(--p-primary-color);background:var(--p-surface-0);border-radius:50%;padding:.5rem}:host-context(.p-dark) .selected-overlay i,.dark .selected-overlay i{background:var(--p-surface-900)}\n"], dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: IsEmptyImageDirective, selector: "img", inputs: ["src"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "directive", type: i1$2.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "pButtonPT", "pButtonUnstyled", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "component", type:
|
|
3624
|
+
`, isInline: true, styles: [".file-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:.75rem;max-height:300px;overflow-y:auto;padding:.5rem}@media(min-width:480px){.file-grid{grid-template-columns:repeat(3,1fr);max-height:350px}}@media(min-width:640px){.file-grid{grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:1rem;max-height:400px}}.file-card{border:2px solid var(--p-surface-300);border-radius:var(--p-border-radius);cursor:pointer;transition:all .2s ease;overflow:hidden;background:var(--p-surface-0)}:host-context(.p-dark) .file-card,.dark .file-card{border-color:var(--p-surface-600);background:var(--p-surface-800)}.file-card:hover:not(.disabled){border-color:var(--p-primary-color);transform:translateY(-2px);box-shadow:var(--p-overlay-shadow)}.file-card.selected{border-color:var(--p-primary-color);background:var(--p-primary-50)}:host-context(.p-dark) .file-card.selected,.dark .file-card.selected{background:var(--p-primary-900)}.file-card.disabled{opacity:.5;cursor:not-allowed}.file-preview{position:relative;height:80px;display:flex;align-items:center;justify-content:center;background:var(--p-surface-100)}@media(min-width:640px){.file-preview{height:100px}}:host-context(.p-dark) .file-preview,.dark .file-preview{background:var(--p-surface-700)}.selected-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(var(--p-primary-500-rgb, 59, 130, 246),.3)}.selected-overlay i{color:var(--p-primary-color);background:var(--p-surface-0);border-radius:50%;padding:.5rem}:host-context(.p-dark) .selected-overlay i,.dark .selected-overlay i{background:var(--p-surface-900)}\n"], dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: IsEmptyImageDirective, selector: "img", inputs: ["src"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "directive", type: i3$1.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i1$2.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "pButtonPT", "pButtonUnstyled", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "component", type: i5.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "component", type: i6.IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["hostName", "iconPosition", "styleClass"] }, { kind: "component", type: i7.InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["hostName", "styleClass"] }, { kind: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: i3.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: FileUploaderComponent, selector: "lib-file-uploader", inputs: ["uploadFile", "uploadMultipleFiles", "acceptTypes", "multiple", "maxFiles", "maxSizeMb", "uploadOptions", "disabled", "showPreview", "autoUpload"], outputs: ["fileUploaded", "filesUploaded", "onError", "fileSelected"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
2624
3625
|
}
|
|
2625
3626
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FileSelectorDialogComponent, decorators: [{
|
|
2626
3627
|
type: Component,
|
|
2627
|
-
args: [{ selector: 'lib-file-selector-dialog', imports: [AngularModule, PrimeModule], template: `
|
|
3628
|
+
args: [{ selector: 'lib-file-selector-dialog', imports: [AngularModule, PrimeModule, FileUploaderComponent, TranslatePipe], template: `
|
|
2628
3629
|
<p-dialog
|
|
2629
|
-
[header]="
|
|
3630
|
+
[header]="dialogHeader()"
|
|
2630
3631
|
[(visible)]="visible"
|
|
2631
3632
|
[modal]="true"
|
|
2632
3633
|
[closable]="true"
|
|
@@ -2637,102 +3638,241 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
2637
3638
|
styleClass="file-selector-dialog"
|
|
2638
3639
|
(onHide)="onDialogHide()"
|
|
2639
3640
|
>
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
class="
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
3641
|
+
@if (!fileProvider) {
|
|
3642
|
+
<div class="p-6 text-center">
|
|
3643
|
+
<i
|
|
3644
|
+
class="pi pi-exclamation-triangle text-4xl text-orange-500 mb-3"
|
|
3645
|
+
></i>
|
|
3646
|
+
<p class="text-lg font-medium text-color mb-2">
|
|
3647
|
+
{{ 'shared.file.selector.provider.not.configured' | translate }}
|
|
3648
|
+
</p>
|
|
3649
|
+
<p class="text-sm text-color-secondary mb-4">
|
|
3650
|
+
{{ 'shared.file.selector.add.provider' | translate }}
|
|
3651
|
+
<code class="inline-block bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 px-2 py-1 rounded font-mono text-xs">provideStorageProviders()</code>
|
|
3652
|
+
</p>
|
|
3653
|
+
<button
|
|
3654
|
+
pButton
|
|
3655
|
+
[label]="'shared.close' | translate"
|
|
3656
|
+
class="p-button-text"
|
|
3657
|
+
(click)="onCancel()"
|
|
3658
|
+
></button>
|
|
3659
|
+
</div>
|
|
3660
|
+
} @else {
|
|
3661
|
+
<!-- Upload Section (when withUploader is enabled) -->
|
|
3662
|
+
@if (withUploader()) {
|
|
3663
|
+
<div class="mb-4">
|
|
3664
|
+
<lib-file-uploader
|
|
3665
|
+
[uploadFile]="uploadFileFn"
|
|
3666
|
+
[uploadMultipleFiles]="uploadMultipleFilesFn"
|
|
3667
|
+
[uploadOptions]="{ storageConfigId: effectiveStorageConfigId() }"
|
|
3668
|
+
[acceptTypes]="acceptTypes()"
|
|
3669
|
+
[multiple]="multiple()"
|
|
3670
|
+
[maxFiles]="maxSelection()"
|
|
3671
|
+
[maxSizeMb]="10"
|
|
3672
|
+
[showPreview]="false"
|
|
3673
|
+
(fileUploaded)="onFileUploaded($event)"
|
|
3674
|
+
/>
|
|
3675
|
+
</div>
|
|
2657
3676
|
}
|
|
2658
|
-
</div>
|
|
2659
3677
|
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
[
|
|
2681
|
-
|
|
3678
|
+
<!-- Filters Row - All on same line on desktop -->
|
|
3679
|
+
<div
|
|
3680
|
+
class="flex flex-col sm:flex-row gap-2 mb-3 items-stretch sm:items-center"
|
|
3681
|
+
>
|
|
3682
|
+
<!-- Search -->
|
|
3683
|
+
<p-iconfield class="flex-1">
|
|
3684
|
+
<p-inputicon class="pi pi-search" />
|
|
3685
|
+
<input
|
|
3686
|
+
pInputText
|
|
3687
|
+
type="text"
|
|
3688
|
+
[ngModel]="searchTerm()"
|
|
3689
|
+
(ngModelChange)="onSearchChange($event)"
|
|
3690
|
+
[placeholder]="'shared.file.selector.search.placeholder' | translate"
|
|
3691
|
+
class="w-full"
|
|
3692
|
+
/>
|
|
3693
|
+
</p-iconfield>
|
|
3694
|
+
|
|
3695
|
+
<!-- Folder Selector -->
|
|
3696
|
+
@if (fileProvider.loadFolders) {
|
|
3697
|
+
<p-select
|
|
3698
|
+
[options]="folders()"
|
|
3699
|
+
[ngModel]="selectedFolderId()"
|
|
3700
|
+
(ngModelChange)="onFolderChange($event)"
|
|
3701
|
+
optionLabel="name"
|
|
3702
|
+
optionValue="id"
|
|
3703
|
+
[placeholder]="'shared.file.selector.all.folders' | translate"
|
|
3704
|
+
[showClear]="true"
|
|
3705
|
+
[filter]="true"
|
|
3706
|
+
filterBy="name"
|
|
3707
|
+
(onFilter)="onFolderSearch($event)"
|
|
3708
|
+
[loading]="foldersLoading()"
|
|
3709
|
+
class="w-full sm:w-40"
|
|
3710
|
+
(onShow)="loadFolders()"
|
|
2682
3711
|
>
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
<
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
<
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
3712
|
+
<ng-template pTemplate="selectedItem" let-folder>
|
|
3713
|
+
<div class="flex items-center gap-2">
|
|
3714
|
+
<i class="pi pi-folder text-color-secondary"></i>
|
|
3715
|
+
<span>{{ folder?.name }}</span>
|
|
3716
|
+
</div>
|
|
3717
|
+
</ng-template>
|
|
3718
|
+
<ng-template pTemplate="item" let-folder>
|
|
3719
|
+
<div class="flex items-center gap-2">
|
|
3720
|
+
<i class="pi pi-folder text-color-secondary"></i>
|
|
3721
|
+
<span>{{ folder.name }}</span>
|
|
3722
|
+
</div>
|
|
3723
|
+
</ng-template>
|
|
3724
|
+
</p-select>
|
|
3725
|
+
}
|
|
2696
3726
|
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
3727
|
+
<!-- Storage Config Selector -->
|
|
3728
|
+
@if (fileProvider.loadStorageConfigs) {
|
|
3729
|
+
<p-select
|
|
3730
|
+
[options]="storageConfigs()"
|
|
3731
|
+
[ngModel]="selectedStorageConfigId()"
|
|
3732
|
+
(ngModelChange)="onStorageConfigChange($event)"
|
|
3733
|
+
optionLabel="name"
|
|
3734
|
+
optionValue="id"
|
|
3735
|
+
[placeholder]="'shared.file.selector.all.storage' | translate"
|
|
3736
|
+
[showClear]="true"
|
|
3737
|
+
[filter]="true"
|
|
3738
|
+
filterBy="name"
|
|
3739
|
+
(onFilter)="onStorageConfigSearch($event)"
|
|
3740
|
+
[loading]="storageConfigsLoading()"
|
|
3741
|
+
class="w-full sm:w-40"
|
|
3742
|
+
(onShow)="loadStorageConfigs()"
|
|
3743
|
+
>
|
|
3744
|
+
<ng-template pTemplate="selectedItem" let-config>
|
|
3745
|
+
<div class="flex items-center gap-2">
|
|
3746
|
+
<i class="pi pi-database text-color-secondary"></i>
|
|
3747
|
+
<span>{{ config?.name }}</span>
|
|
3748
|
+
@if (config?.isDefault) {
|
|
3749
|
+
<span
|
|
3750
|
+
class="text-xs bg-primary text-primary-contrast px-1 rounded"
|
|
3751
|
+
>{{ 'shared.default' | translate }}</span
|
|
3752
|
+
>
|
|
3753
|
+
}
|
|
3754
|
+
</div>
|
|
3755
|
+
</ng-template>
|
|
3756
|
+
<ng-template pTemplate="item" let-config>
|
|
3757
|
+
<div class="flex items-center gap-2">
|
|
3758
|
+
<i class="pi pi-database text-color-secondary"></i>
|
|
3759
|
+
<span>{{ config.name }}</span>
|
|
3760
|
+
@if (config.isDefault) {
|
|
3761
|
+
<span
|
|
3762
|
+
class="text-xs bg-primary text-primary-contrast px-1 rounded"
|
|
3763
|
+
>{{ 'shared.default' | translate }}</span
|
|
3764
|
+
>
|
|
3765
|
+
}
|
|
3766
|
+
</div>
|
|
3767
|
+
</ng-template>
|
|
3768
|
+
</p-select>
|
|
2705
3769
|
}
|
|
2706
3770
|
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
3771
|
+
<!-- Selected count -->
|
|
3772
|
+
@if (multiple()) {
|
|
3773
|
+
<span
|
|
3774
|
+
class="text-sm text-color-secondary self-center whitespace-nowrap"
|
|
3775
|
+
>
|
|
3776
|
+
{{ 'shared.file.selector.selected' | translate: { count: selectedFiles().length } }}
|
|
3777
|
+
</span>
|
|
2711
3778
|
}
|
|
2712
|
-
|
|
2713
|
-
</div>
|
|
3779
|
+
</div>
|
|
2714
3780
|
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
(
|
|
2730
|
-
|
|
3781
|
+
<!-- File Grid - Responsive columns -->
|
|
3782
|
+
<div class="file-grid" #scrollContainer (scroll)="onScroll($event)">
|
|
3783
|
+
@if (isLoading() && files().length === 0) {
|
|
3784
|
+
<div class="col-span-full flex justify-center p-4">
|
|
3785
|
+
<i
|
|
3786
|
+
class="pi pi-spin pi-spinner text-4xl text-color-secondary"
|
|
3787
|
+
></i>
|
|
3788
|
+
</div>
|
|
3789
|
+
} @else if (files().length === 0) {
|
|
3790
|
+
<div class="col-span-full text-center p-4 text-color-secondary">
|
|
3791
|
+
<i class="pi pi-inbox text-4xl mb-2 block"></i>
|
|
3792
|
+
<p>{{ 'shared.file.selector.no.files' | translate }}</p>
|
|
3793
|
+
</div>
|
|
3794
|
+
} @else {
|
|
3795
|
+
@for (file of files(); track file.id) {
|
|
3796
|
+
<div
|
|
3797
|
+
class="file-card"
|
|
3798
|
+
[class.selected]="isSelected(file)"
|
|
3799
|
+
[class.disabled]="!isFileAllowed(file)"
|
|
3800
|
+
(click)="toggleSelection(file)"
|
|
3801
|
+
>
|
|
3802
|
+
<!-- File Preview -->
|
|
3803
|
+
<div class="file-preview">
|
|
3804
|
+
@if (isImage(file) && file.url) {
|
|
3805
|
+
<img
|
|
3806
|
+
[src]="file.url"
|
|
3807
|
+
[alt]="file.name"
|
|
3808
|
+
class="w-full h-full object-cover"
|
|
3809
|
+
/>
|
|
3810
|
+
} @else {
|
|
3811
|
+
<i
|
|
3812
|
+
[class]="getFileIcon(file)"
|
|
3813
|
+
class="text-4xl sm:text-5xl text-color-secondary"
|
|
3814
|
+
></i>
|
|
3815
|
+
}
|
|
3816
|
+
@if (isSelected(file)) {
|
|
3817
|
+
<div class="selected-overlay">
|
|
3818
|
+
<i class="pi pi-check text-xl sm:text-2xl"></i>
|
|
3819
|
+
</div>
|
|
3820
|
+
}
|
|
3821
|
+
</div>
|
|
3822
|
+
|
|
3823
|
+
<!-- File Info -->
|
|
3824
|
+
<div class="p-2 text-center bg-surface-0 dark:bg-surface-900">
|
|
3825
|
+
<span
|
|
3826
|
+
class="block text-xs sm:text-sm whitespace-nowrap overflow-hidden text-ellipsis"
|
|
3827
|
+
[title]="file.name"
|
|
3828
|
+
>
|
|
3829
|
+
{{ file.name }}
|
|
3830
|
+
</span>
|
|
3831
|
+
<span class="block text-xs text-color-secondary">{{
|
|
3832
|
+
formatSize(file.size)
|
|
3833
|
+
}}</span>
|
|
3834
|
+
</div>
|
|
3835
|
+
</div>
|
|
3836
|
+
}
|
|
3837
|
+
|
|
3838
|
+
@if (isLoading()) {
|
|
3839
|
+
<div class="col-span-full flex justify-center p-2">
|
|
3840
|
+
<i class="pi pi-spin pi-spinner text-color-secondary"></i>
|
|
3841
|
+
</div>
|
|
3842
|
+
}
|
|
3843
|
+
}
|
|
2731
3844
|
</div>
|
|
2732
|
-
|
|
3845
|
+
|
|
3846
|
+
<!-- Footer -->
|
|
3847
|
+
<ng-template pTemplate="footer">
|
|
3848
|
+
<div
|
|
3849
|
+
class="flex flex-col-reverse sm:flex-row gap-2 w-full sm:w-auto sm:justify-end"
|
|
3850
|
+
>
|
|
3851
|
+
<button
|
|
3852
|
+
pButton
|
|
3853
|
+
type="button"
|
|
3854
|
+
[label]="'shared.cancel' | translate"
|
|
3855
|
+
class="p-button-text w-full sm:w-auto"
|
|
3856
|
+
(click)="onCancel()"
|
|
3857
|
+
></button>
|
|
3858
|
+
<button
|
|
3859
|
+
pButton
|
|
3860
|
+
type="button"
|
|
3861
|
+
[label]="
|
|
3862
|
+
multiple()
|
|
3863
|
+
? ('shared.file.selector.select.multiple' | translate: { count: selectedFiles().length })
|
|
3864
|
+
: ('shared.file.selector.select' | translate)
|
|
3865
|
+
"
|
|
3866
|
+
[disabled]="selectedFiles().length === 0"
|
|
3867
|
+
class="w-full sm:w-auto"
|
|
3868
|
+
(click)="onConfirm()"
|
|
3869
|
+
></button>
|
|
3870
|
+
</div>
|
|
3871
|
+
</ng-template>
|
|
3872
|
+
}
|
|
2733
3873
|
</p-dialog>
|
|
2734
|
-
`,
|
|
2735
|
-
}], ctorParameters: () => [], propDecorators: {
|
|
3874
|
+
`, styles: [".file-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:.75rem;max-height:300px;overflow-y:auto;padding:.5rem}@media(min-width:480px){.file-grid{grid-template-columns:repeat(3,1fr);max-height:350px}}@media(min-width:640px){.file-grid{grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:1rem;max-height:400px}}.file-card{border:2px solid var(--p-surface-300);border-radius:var(--p-border-radius);cursor:pointer;transition:all .2s ease;overflow:hidden;background:var(--p-surface-0)}:host-context(.p-dark) .file-card,.dark .file-card{border-color:var(--p-surface-600);background:var(--p-surface-800)}.file-card:hover:not(.disabled){border-color:var(--p-primary-color);transform:translateY(-2px);box-shadow:var(--p-overlay-shadow)}.file-card.selected{border-color:var(--p-primary-color);background:var(--p-primary-50)}:host-context(.p-dark) .file-card.selected,.dark .file-card.selected{background:var(--p-primary-900)}.file-card.disabled{opacity:.5;cursor:not-allowed}.file-preview{position:relative;height:80px;display:flex;align-items:center;justify-content:center;background:var(--p-surface-100)}@media(min-width:640px){.file-preview{height:100px}}:host-context(.p-dark) .file-preview,.dark .file-preview{background:var(--p-surface-700)}.selected-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(var(--p-primary-500-rgb, 59, 130, 246),.3)}.selected-overlay i{color:var(--p-primary-color);background:var(--p-surface-0);border-radius:50%;padding:.5rem}:host-context(.p-dark) .selected-overlay i,.dark .selected-overlay i{background:var(--p-surface-900)}\n"] }]
|
|
3875
|
+
}], ctorParameters: () => [], propDecorators: { header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], acceptTypes: [{ type: i0.Input, args: [{ isSignal: true, alias: "acceptTypes", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], maxSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSelection", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], folderId: [{ type: i0.Input, args: [{ isSignal: true, alias: "folderId", required: false }] }], withUploader: [{ type: i0.Input, args: [{ isSignal: true, alias: "withUploader", required: false }] }], visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }, { type: i0.Output, args: ["visibleChange"] }], fileSelected: [{ type: i0.Output, args: ["fileSelected"] }], filesSelected: [{ type: i0.Output, args: ["filesSelected"] }], closed: [{ type: i0.Output, args: ["closed"] }], onError: [{ type: i0.Output, args: ["onError"] }] } });
|
|
2736
3876
|
|
|
2737
3877
|
function createGuard(guardName, redirectTo, evaluate, getDenialMessage) {
|
|
2738
3878
|
return () => {
|
|
@@ -2828,8 +3968,7 @@ function allPermissionsGuard(permissions, redirectTo = '/') {
|
|
|
2828
3968
|
* @Component({
|
|
2829
3969
|
* selector: 'app-product-form',
|
|
2830
3970
|
* standalone: true,
|
|
2831
|
-
*
|
|
2832
|
-
* template: `...`
|
|
3971
|
+
* * template: `...`
|
|
2833
3972
|
* })
|
|
2834
3973
|
* export class ProductFormComponent extends BaseFormPage<IProduct, IProductFormModel> {
|
|
2835
3974
|
* private readonly productService = inject(ProductApiService);
|
|
@@ -2896,6 +4035,7 @@ class BaseFormPage {
|
|
|
2896
4035
|
route = inject(ActivatedRoute);
|
|
2897
4036
|
messageService = inject(MessageService);
|
|
2898
4037
|
destroyRef = inject(DestroyRef);
|
|
4038
|
+
translateAdapter = inject(TRANSLATE_ADAPTER, { optional: true });
|
|
2899
4039
|
routeParams = toSignal(this.route.paramMap);
|
|
2900
4040
|
initialized = false;
|
|
2901
4041
|
/** Loading state for async operations */
|
|
@@ -2933,8 +4073,8 @@ class BaseFormPage {
|
|
|
2933
4073
|
: this.createItem(model);
|
|
2934
4074
|
operation$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
|
2935
4075
|
next: () => {
|
|
2936
|
-
const
|
|
2937
|
-
this.showSuccess(
|
|
4076
|
+
const messageKey = this.isEditMode() ? 'shared.update.success' : 'shared.create.success';
|
|
4077
|
+
this.showSuccess(this.t(messageKey));
|
|
2938
4078
|
this.router.navigate([this.getResourceRoute()]);
|
|
2939
4079
|
},
|
|
2940
4080
|
error: () => {
|
|
@@ -2959,8 +4099,8 @@ class BaseFormPage {
|
|
|
2959
4099
|
showValidationError() {
|
|
2960
4100
|
this.messageService.add({
|
|
2961
4101
|
severity: 'error',
|
|
2962
|
-
summary: '
|
|
2963
|
-
detail: '
|
|
4102
|
+
summary: this.t('shared.validation.error'),
|
|
4103
|
+
detail: this.t('shared.fill.all.fields'),
|
|
2964
4104
|
});
|
|
2965
4105
|
}
|
|
2966
4106
|
/**
|
|
@@ -2970,7 +4110,7 @@ class BaseFormPage {
|
|
|
2970
4110
|
showSuccess(detail) {
|
|
2971
4111
|
this.messageService.add({
|
|
2972
4112
|
severity: 'success',
|
|
2973
|
-
summary: '
|
|
4113
|
+
summary: this.t('shared.success'),
|
|
2974
4114
|
detail,
|
|
2975
4115
|
});
|
|
2976
4116
|
}
|
|
@@ -2981,10 +4121,16 @@ class BaseFormPage {
|
|
|
2981
4121
|
showError(detail) {
|
|
2982
4122
|
this.messageService.add({
|
|
2983
4123
|
severity: 'error',
|
|
2984
|
-
summary: '
|
|
4124
|
+
summary: this.t('shared.error'),
|
|
2985
4125
|
detail,
|
|
2986
4126
|
});
|
|
2987
4127
|
}
|
|
4128
|
+
/**
|
|
4129
|
+
* Translate a key using the adapter, fallback to key if not available.
|
|
4130
|
+
*/
|
|
4131
|
+
t(key, variables) {
|
|
4132
|
+
return this.translateAdapter?.translate(key, variables) ?? key;
|
|
4133
|
+
}
|
|
2988
4134
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: BaseFormPage, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2989
4135
|
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.5", type: BaseFormPage, isStandalone: true, ngImport: i0 });
|
|
2990
4136
|
}
|
|
@@ -3021,6 +4167,7 @@ class BaseListPage {
|
|
|
3021
4167
|
appConfig = inject(APP_CONFIG);
|
|
3022
4168
|
confirmationService = inject(ConfirmationService);
|
|
3023
4169
|
destroyRef = inject(DestroyRef);
|
|
4170
|
+
translateAdapter = inject(TRANSLATE_ADAPTER, { optional: true });
|
|
3024
4171
|
/** Items list */
|
|
3025
4172
|
items = signal([], ...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
3026
4173
|
/** Loading state */
|
|
@@ -3069,26 +4216,32 @@ class BaseListPage {
|
|
|
3069
4216
|
/**
|
|
3070
4217
|
* Show success toast message
|
|
3071
4218
|
*/
|
|
3072
|
-
showSuccess(detail, summary
|
|
3073
|
-
this.messageService.add({ severity: 'success', summary, detail });
|
|
4219
|
+
showSuccess(detail, summary) {
|
|
4220
|
+
this.messageService.add({ severity: 'success', summary: summary ?? this.t('shared.success'), detail });
|
|
3074
4221
|
}
|
|
3075
4222
|
/**
|
|
3076
4223
|
* Show error toast message
|
|
3077
4224
|
*/
|
|
3078
|
-
showError(detail, summary
|
|
3079
|
-
this.messageService.add({ severity: 'error', summary, detail });
|
|
4225
|
+
showError(detail, summary) {
|
|
4226
|
+
this.messageService.add({ severity: 'error', summary: summary ?? this.t('shared.error'), detail });
|
|
3080
4227
|
}
|
|
3081
4228
|
/**
|
|
3082
4229
|
* Show info toast message
|
|
3083
4230
|
*/
|
|
3084
|
-
showInfo(detail, summary
|
|
3085
|
-
this.messageService.add({ severity: 'info', summary, detail });
|
|
4231
|
+
showInfo(detail, summary) {
|
|
4232
|
+
this.messageService.add({ severity: 'info', summary: summary ?? this.t('shared.info'), detail });
|
|
3086
4233
|
}
|
|
3087
4234
|
/**
|
|
3088
4235
|
* Show warning toast message
|
|
3089
4236
|
*/
|
|
3090
|
-
showWarn(detail, summary
|
|
3091
|
-
this.messageService.add({ severity: 'warn', summary, detail });
|
|
4237
|
+
showWarn(detail, summary) {
|
|
4238
|
+
this.messageService.add({ severity: 'warn', summary: summary ?? this.t('shared.warning'), detail });
|
|
4239
|
+
}
|
|
4240
|
+
/**
|
|
4241
|
+
* Translate a key using the adapter, fallback to key if not available.
|
|
4242
|
+
*/
|
|
4243
|
+
t(key, variables) {
|
|
4244
|
+
return this.translateAdapter?.translate(key, variables) ?? key;
|
|
3092
4245
|
}
|
|
3093
4246
|
/**
|
|
3094
4247
|
* Delete an item with confirmation dialog
|
|
@@ -3100,7 +4253,7 @@ class BaseListPage {
|
|
|
3100
4253
|
onDelete(item, idGetter, deleteApiCall, options) {
|
|
3101
4254
|
this.confirmationService.confirm({
|
|
3102
4255
|
message: this.getDeleteConfirmMessage(item),
|
|
3103
|
-
header: options?.header ?? '
|
|
4256
|
+
header: options?.header ?? this.t('shared.confirm.delete.header'),
|
|
3104
4257
|
icon: 'pi pi-exclamation-triangle',
|
|
3105
4258
|
acceptButtonStyleClass: 'p-button-danger',
|
|
3106
4259
|
accept: () => {
|
|
@@ -3108,11 +4261,11 @@ class BaseListPage {
|
|
|
3108
4261
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
3109
4262
|
.subscribe({
|
|
3110
4263
|
next: () => {
|
|
3111
|
-
this.showSuccess(options?.successMessage ?? '
|
|
4264
|
+
this.showSuccess(options?.successMessage ?? this.t('shared.delete.success'));
|
|
3112
4265
|
this.loadData();
|
|
3113
4266
|
},
|
|
3114
4267
|
error: () => {
|
|
3115
|
-
this.showError(options?.errorMessage ?? '
|
|
4268
|
+
this.showError(options?.errorMessage ?? this.t('shared.delete.failed'));
|
|
3116
4269
|
},
|
|
3117
4270
|
});
|
|
3118
4271
|
},
|
|
@@ -3128,17 +4281,17 @@ class BaseListPage {
|
|
|
3128
4281
|
async onDeleteAsync(item, idGetter, deleteApiCall, options) {
|
|
3129
4282
|
this.confirmationService.confirm({
|
|
3130
4283
|
message: this.getDeleteConfirmMessage(item),
|
|
3131
|
-
header: options?.header ?? '
|
|
4284
|
+
header: options?.header ?? this.t('shared.confirm.delete.header'),
|
|
3132
4285
|
icon: 'pi pi-exclamation-triangle',
|
|
3133
4286
|
acceptButtonStyleClass: 'p-button-danger',
|
|
3134
4287
|
accept: async () => {
|
|
3135
4288
|
try {
|
|
3136
4289
|
await deleteApiCall(idGetter(item));
|
|
3137
|
-
this.showSuccess(options?.successMessage ?? '
|
|
4290
|
+
this.showSuccess(options?.successMessage ?? this.t('shared.delete.success'));
|
|
3138
4291
|
await this.loadData();
|
|
3139
4292
|
}
|
|
3140
4293
|
catch {
|
|
3141
|
-
this.showError(options?.errorMessage ?? '
|
|
4294
|
+
this.showError(options?.errorMessage ?? this.t('shared.delete.failed'));
|
|
3142
4295
|
}
|
|
3143
4296
|
},
|
|
3144
4297
|
});
|
|
@@ -3162,5 +4315,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
3162
4315
|
* Generated bundle index. Do not edit.
|
|
3163
4316
|
*/
|
|
3164
4317
|
|
|
3165
|
-
export { ACTION_PERMISSIONS, AUTH_STATE_PROVIDER, AngularModule, ApiResourceService, ApiResourceService as ApiService, BRANCH_PERMISSIONS, BaseFormControl, BaseFormPage, BaseListPage, BaseUserSelectComponent, COMPANY_ACTION_PERMISSIONS, COMPANY_API_PROVIDER, COMPANY_PERMISSIONS, ContactTypeEnum, CookieService, EMAIL_CONFIG_PERMISSIONS, EMAIL_TEMPLATE_PERMISSIONS, EVENT_PARTICIPANT_PERMISSIONS, EVENT_PERMISSIONS, EditModeElementChangerDirective, FILE_PERMISSIONS, FILE_TYPE_FILTERS, FOLDER_PERMISSIONS, FORM_PERMISSIONS, FileSelectorDialogComponent, FileUploaderComponent, FileUrlService, HasPermissionDirective, IconComponent, IconTypeEnum, IsEmptyImageDirective, LazyMultiSelectComponent, LazySelectComponent, NOTIFICATION_PERMISSIONS, PERMISSIONS, PROFILE_PERMISSION_PROVIDER,
|
|
4318
|
+
export { ACTION_PERMISSIONS, AUTH_STATE_PROVIDER, AngularModule, ApiResourceService, ApiResourceService as ApiService, BRANCH_PERMISSIONS, BaseFormControl, BaseFormPage, BaseListPage, BaseUserSelectComponent, COMPANY_ACTION_PERMISSIONS, COMPANY_API_PROVIDER, COMPANY_PERMISSIONS, ContactTypeEnum, CookieService, EMAIL_CONFIG_PERMISSIONS, EMAIL_TEMPLATE_PERMISSIONS, EVENT_PARTICIPANT_PERMISSIONS, EVENT_PERMISSIONS, EditModeElementChangerDirective, FILE_PERMISSIONS, FILE_PROVIDER, FILE_TYPE_FILTERS, FOLDER_PERMISSIONS, FORM_PERMISSIONS, FileSelectorDialogComponent, FileUploaderComponent, FileUrlService, HasPermissionDirective, IconComponent, IconTypeEnum, IsEmptyImageDirective, LANGUAGE_PERMISSIONS, LazyMultiSelectComponent, LazySelectComponent, NOTIFICATION_PERMISSIONS, PERMISSIONS, PROFILE_PERMISSION_PROVIDER, PermissionValidatorService, PlatformService, PreventDefaultDirective, PrimeModule, ROLE_ACTION_PERMISSIONS, ROLE_PERMISSIONS, SHARED_MESSAGES, STORAGE_CONFIG_PERMISSIONS, TRANSLATION_KEY_PERMISSIONS, TRANSLATION_PERMISSIONS, TranslatePipe, USER_ACTION_PERMISSIONS, USER_LIST_PROVIDER, USER_PERMISSIONS, USER_PERMISSION_PROVIDER, USER_PROVIDER, USER_ROLE_PERMISSIONS, UserMultiSelectComponent, UserSelectComponent, allPermissionsGuard, anyPermissionGuard, checkScrollPagination, evaluateLogicNode, evaluatePermission, formatFileSize, getAcceptString, getFileIconClass, hasAllPermissions, hasAnyPermission, hasPermission, isFileTypeAllowed, permissionGuard, provideFallbackLocalization, provideValueAccessor, resolveTranslationModule };
|
|
3166
4319
|
//# sourceMappingURL=flusys-ng-shared.mjs.map
|