@flusys/ng-shared 1.0.0-rc → 1.0.0
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 +1 -1
- package/fesm2022/flusys-ng-shared.mjs +299 -511
- package/fesm2022/flusys-ng-shared.mjs.map +1 -1
- package/package.json +9 -9
- package/types/flusys-ng-shared.d.ts +249 -524
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, PLATFORM_ID, Injectable, DOCUMENT, REQUEST, signal, computed, ElementRef, input, effect, Directive, TemplateRef, ViewContainerRef, output, NgModule, Injector, runInInjectionContext, resource, model, untracked, forwardRef, ChangeDetectionStrategy, Component, DestroyRef, viewChild, afterNextRender, InjectionToken, isDevMode } from '@angular/core';
|
|
3
|
-
import * as
|
|
3
|
+
import * as i3 from '@angular/common';
|
|
4
4
|
import { isPlatformServer, CommonModule, NgOptimizedImage, NgComponentOutlet, DatePipe } from '@angular/common';
|
|
5
5
|
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
|
6
|
-
import { APP_CONFIG, getServiceUrl
|
|
6
|
+
import { APP_CONFIG, getServiceUrl } from '@flusys/ng-core';
|
|
7
7
|
import { of, firstValueFrom, map as map$1 } from 'rxjs';
|
|
8
8
|
import { map, tap, catchError } from 'rxjs/operators';
|
|
9
|
-
import * as i1$
|
|
9
|
+
import * as i1$1 from '@angular/forms';
|
|
10
10
|
import { NgControl, FormsModule, ReactiveFormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
11
11
|
import { RouterOutlet, RouterLink, RouterLinkActive, Router, ActivatedRoute } from '@angular/router';
|
|
12
12
|
import { AutoCompleteModule } from 'primeng/autocomplete';
|
|
13
13
|
import { AvatarModule } from 'primeng/avatar';
|
|
14
|
-
import * as i1$
|
|
14
|
+
import * as i1$2 from 'primeng/button';
|
|
15
15
|
import { ButtonModule } from 'primeng/button';
|
|
16
16
|
import { CardModule } from 'primeng/card';
|
|
17
|
-
import * as i1
|
|
17
|
+
import * as i1 from 'primeng/checkbox';
|
|
18
18
|
import { CheckboxModule } from 'primeng/checkbox';
|
|
19
19
|
import { ConfirmDialogModule } from 'primeng/confirmdialog';
|
|
20
20
|
import { DatePickerModule } from 'primeng/datepicker';
|
|
@@ -38,7 +38,7 @@ import * as i2$1 from 'primeng/progressbar';
|
|
|
38
38
|
import { ProgressBarModule } from 'primeng/progressbar';
|
|
39
39
|
import { RadioButtonModule } from 'primeng/radiobutton';
|
|
40
40
|
import { RippleModule } from 'primeng/ripple';
|
|
41
|
-
import * as i3 from 'primeng/select';
|
|
41
|
+
import * as i3$1 from 'primeng/select';
|
|
42
42
|
import { SelectModule } from 'primeng/select';
|
|
43
43
|
import { SelectButtonModule } from 'primeng/selectbutton';
|
|
44
44
|
import { SkeletonModule } from 'primeng/skeleton';
|
|
@@ -293,96 +293,69 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
293
293
|
|
|
294
294
|
/**
|
|
295
295
|
* Service to fetch file URLs from the backend.
|
|
296
|
-
*
|
|
297
|
-
* - Handles presigned URLs for cloud storage (AWS S3, Azure)
|
|
298
|
-
* - Auto-refreshes expired URLs
|
|
299
|
-
* - Validates file access permissions
|
|
300
|
-
* - Works with all storage providers (Local, S3, Azure, SFTP)
|
|
296
|
+
* Handles presigned URLs for cloud storage, auto-refresh, and caching.
|
|
301
297
|
*/
|
|
302
298
|
class FileUrlService {
|
|
303
299
|
http = inject(HttpClient);
|
|
304
300
|
appConfig = inject(APP_CONFIG);
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Get file URL by ID from cache (reactive signal)
|
|
309
|
-
*/
|
|
301
|
+
_cache = signal(new Map(), ...(ngDevMode ? [{ debugName: "_cache" }] : []));
|
|
302
|
+
cache = this._cache.asReadonly();
|
|
303
|
+
/** Get file URL by ID from cache (synchronous) */
|
|
310
304
|
getFileUrl(fileId) {
|
|
311
305
|
if (!fileId)
|
|
312
306
|
return null;
|
|
313
|
-
return this.
|
|
307
|
+
return this._cache().get(fileId)?.url ?? null;
|
|
314
308
|
}
|
|
315
|
-
/**
|
|
316
|
-
* Get file URL signal (computed from cache)
|
|
317
|
-
*/
|
|
309
|
+
/** Get file URL as computed signal */
|
|
318
310
|
fileUrlSignal(fileId) {
|
|
319
311
|
return computed(() => this.getFileUrl(fileId));
|
|
320
312
|
}
|
|
321
|
-
/**
|
|
322
|
-
* Fetch file URLs from backend and update cache.
|
|
323
|
-
* Skips IDs already in cache to prevent duplicate calls.
|
|
324
|
-
* Returns Observable of fetched files (including cached ones).
|
|
325
|
-
*/
|
|
313
|
+
/** Fetch file URLs from backend and update cache */
|
|
326
314
|
fetchFileUrls(fileIds, forceRefresh = false) {
|
|
327
315
|
if (!fileIds.length)
|
|
328
316
|
return of([]);
|
|
329
|
-
const cache = this.
|
|
330
|
-
// Filter out IDs already in cache (unless force refresh)
|
|
317
|
+
const cache = this._cache();
|
|
331
318
|
const missingIds = forceRefresh
|
|
332
319
|
? fileIds
|
|
333
320
|
: fileIds.filter((id) => !cache.has(id));
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
const cachedFiles = fileIds
|
|
337
|
-
.map((id) => cache.get(id))
|
|
338
|
-
.filter((f) => !!f);
|
|
339
|
-
return of(cachedFiles);
|
|
321
|
+
if (!missingIds.length) {
|
|
322
|
+
return of(this.getFromCache(fileIds));
|
|
340
323
|
}
|
|
341
324
|
const requestDto = missingIds.map((id) => ({ id }));
|
|
342
325
|
return this.http
|
|
343
326
|
.post(`${getServiceUrl(this.appConfig, 'storage')}/file-manager/get-files`, requestDto)
|
|
344
|
-
.pipe(map((response) => response.data ?? []), tap((files) =>
|
|
345
|
-
// Update cache with new files
|
|
346
|
-
const newCache = new Map(this.urlCache());
|
|
347
|
-
files.forEach((file) => newCache.set(file.id, file));
|
|
348
|
-
this.urlCache.set(newCache);
|
|
349
|
-
}), map(() => {
|
|
350
|
-
// Return all requested files (cached + newly fetched)
|
|
351
|
-
const allCache = this.urlCache();
|
|
352
|
-
return fileIds
|
|
353
|
-
.map((id) => allCache.get(id))
|
|
354
|
-
.filter((f) => !!f);
|
|
355
|
-
}), catchError(() => of([])));
|
|
327
|
+
.pipe(map((response) => response.data ?? []), tap((files) => this.addToCache(files)), map(() => this.getFromCache(fileIds)), catchError(() => of([])));
|
|
356
328
|
}
|
|
357
|
-
/**
|
|
358
|
-
* Fetch a single file URL.
|
|
359
|
-
* Uses cache if available to prevent duplicate calls.
|
|
360
|
-
* Returns Observable of file info or null if not found.
|
|
361
|
-
*/
|
|
329
|
+
/** Fetch single file URL (delegates to fetchFileUrls) */
|
|
362
330
|
fetchSingleFileUrl(fileId, forceRefresh = false) {
|
|
363
|
-
// Return from cache immediately if available
|
|
364
|
-
if (!forceRefresh) {
|
|
365
|
-
const cached = this.urlCache().get(fileId);
|
|
366
|
-
if (cached) {
|
|
367
|
-
return of(cached);
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
331
|
return this.fetchFileUrls([fileId], forceRefresh).pipe(map((files) => files[0] ?? null));
|
|
371
332
|
}
|
|
372
|
-
/**
|
|
373
|
-
* Clear the URL cache.
|
|
374
|
-
* Useful on logout or when switching contexts.
|
|
375
|
-
*/
|
|
333
|
+
/** Clear entire cache */
|
|
376
334
|
clearCache() {
|
|
377
|
-
this.
|
|
335
|
+
this._cache.set(new Map());
|
|
378
336
|
}
|
|
379
|
-
/**
|
|
380
|
-
* Remove specific file from cache.
|
|
381
|
-
*/
|
|
337
|
+
/** Remove specific file from cache */
|
|
382
338
|
removeFromCache(fileId) {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
339
|
+
this._cache.update((cache) => {
|
|
340
|
+
const next = new Map(cache);
|
|
341
|
+
next.delete(fileId);
|
|
342
|
+
return next;
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
addToCache(files) {
|
|
346
|
+
this._cache.update((cache) => {
|
|
347
|
+
const next = new Map(cache);
|
|
348
|
+
for (const file of files) {
|
|
349
|
+
next.set(file.id, file);
|
|
350
|
+
}
|
|
351
|
+
return next;
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
getFromCache(fileIds) {
|
|
355
|
+
const cache = this._cache();
|
|
356
|
+
return fileIds
|
|
357
|
+
.map((id) => cache.get(id))
|
|
358
|
+
.filter((f) => f !== undefined);
|
|
386
359
|
}
|
|
387
360
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: FileUrlService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
388
361
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: FileUrlService, providedIn: 'root' });
|
|
@@ -393,82 +366,89 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
393
366
|
}] });
|
|
394
367
|
|
|
395
368
|
/**
|
|
396
|
-
*
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
369
|
+
* Check if user has a specific permission using wildcard matching.
|
|
370
|
+
* Supports:
|
|
371
|
+
* - Exact match: 'user.create' matches 'user.create'
|
|
372
|
+
* - Full wildcard: '*' matches everything
|
|
373
|
+
* - Module wildcard: 'user.*' matches 'user.create', 'user.read', etc.
|
|
374
|
+
*/
|
|
375
|
+
function hasPermission(requiredPermission, userPermissions) {
|
|
376
|
+
// Exact match
|
|
377
|
+
if (userPermissions.includes(requiredPermission))
|
|
378
|
+
return true;
|
|
379
|
+
// Wildcard matching
|
|
380
|
+
for (const permission of userPermissions) {
|
|
381
|
+
// Full wildcard - grants all permissions
|
|
382
|
+
if (permission === '*')
|
|
383
|
+
return true;
|
|
384
|
+
// Module wildcard (e.g., 'user.*' matches 'user.create')
|
|
385
|
+
if (permission.endsWith('.*') &&
|
|
386
|
+
requiredPermission.startsWith(permission.slice(0, -1))) {
|
|
387
|
+
return true;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
/** Evaluate permission logic (string or ILogicNode) against user permissions */
|
|
393
|
+
function evaluatePermission(logic, permissions) {
|
|
394
|
+
if (!logic)
|
|
395
|
+
return false;
|
|
396
|
+
if (typeof logic === 'string')
|
|
397
|
+
return hasPermission(logic, permissions);
|
|
398
|
+
return evaluateLogicNode(logic, permissions);
|
|
399
|
+
}
|
|
400
|
+
/** Recursively evaluate an ILogicNode tree */
|
|
401
|
+
function evaluateLogicNode(node, permissions) {
|
|
402
|
+
switch (node.type) {
|
|
403
|
+
case 'action':
|
|
404
|
+
return node.actionId ? hasPermission(node.actionId, permissions) : false;
|
|
405
|
+
case 'group':
|
|
406
|
+
if (!node.children || node.children.length === 0)
|
|
407
|
+
return false;
|
|
408
|
+
return node.operator === 'AND'
|
|
409
|
+
? node.children.every((child) => evaluateLogicNode(child, permissions))
|
|
410
|
+
: node.children.some((child) => evaluateLogicNode(child, permissions));
|
|
411
|
+
default:
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
/** Check if user has ANY of the specified permissions (OR logic) */
|
|
416
|
+
function hasAnyPermission(permissionCodes, permissions) {
|
|
417
|
+
if (!permissionCodes?.length)
|
|
418
|
+
return false;
|
|
419
|
+
return permissionCodes.some((code) => hasPermission(code, permissions));
|
|
420
|
+
}
|
|
421
|
+
/** Check if user has ALL of the specified permissions (AND logic) */
|
|
422
|
+
function hasAllPermissions(permissionCodes, permissions) {
|
|
423
|
+
if (!permissionCodes?.length)
|
|
424
|
+
return false;
|
|
425
|
+
return permissionCodes.every((code) => hasPermission(code, permissions));
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Permission state management service.
|
|
430
|
+
* Provides signal-based storage and permission checking with wildcard support.
|
|
428
431
|
*/
|
|
429
432
|
class PermissionValidatorService {
|
|
430
|
-
// ==================== SIGNALS ====================
|
|
431
|
-
/**
|
|
432
|
-
* Private writable signal for permissions
|
|
433
|
-
*/
|
|
434
433
|
_permissions = signal([], ...(ngDevMode ? [{ debugName: "_permissions" }] : []));
|
|
435
|
-
/**
|
|
436
|
-
* Readonly permission signal for external consumers
|
|
437
|
-
*/
|
|
438
434
|
permissions = this._permissions.asReadonly();
|
|
439
|
-
/**
|
|
440
|
-
* Private writable signal for loaded state
|
|
441
|
-
*/
|
|
442
435
|
_isLoaded = signal(false, ...(ngDevMode ? [{ debugName: "_isLoaded" }] : []));
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
* @param permissions - Array of permission codes
|
|
446
|
-
*/
|
|
436
|
+
isLoaded = this._isLoaded.asReadonly();
|
|
437
|
+
/** Set permissions (replaces existing) */
|
|
447
438
|
setPermissions(permissions) {
|
|
448
439
|
this._permissions.set(permissions);
|
|
449
440
|
this._isLoaded.set(true);
|
|
450
441
|
}
|
|
451
|
-
/**
|
|
452
|
-
* Clear all permissions
|
|
453
|
-
*/
|
|
442
|
+
/** Clear all permissions */
|
|
454
443
|
clearPermissions() {
|
|
455
444
|
this._permissions.set([]);
|
|
456
445
|
this._isLoaded.set(false);
|
|
457
446
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
* @param permissionCode - Required permission code
|
|
462
|
-
* @returns True if user has permission
|
|
463
|
-
*/
|
|
464
|
-
hasPermission(permissionCode) {
|
|
465
|
-
return this.permissions().includes(permissionCode);
|
|
447
|
+
/** Check if user has permission (supports wildcards: '*', 'module.*') */
|
|
448
|
+
hasPermission(code) {
|
|
449
|
+
return hasPermission(code, this._permissions());
|
|
466
450
|
}
|
|
467
|
-
|
|
468
|
-
/**
|
|
469
|
-
* Check if permissions are loaded
|
|
470
|
-
* @returns True if permissions have been loaded
|
|
471
|
-
*/
|
|
451
|
+
/** @deprecated Use `isLoaded()` signal instead */
|
|
472
452
|
isPermissionsLoaded() {
|
|
473
453
|
return this._isLoaded();
|
|
474
454
|
}
|
|
@@ -477,9 +457,7 @@ class PermissionValidatorService {
|
|
|
477
457
|
}
|
|
478
458
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: PermissionValidatorService, decorators: [{
|
|
479
459
|
type: Injectable,
|
|
480
|
-
args: [{
|
|
481
|
-
providedIn: 'root',
|
|
482
|
-
}]
|
|
460
|
+
args: [{ providedIn: 'root' }]
|
|
483
461
|
}] });
|
|
484
462
|
|
|
485
463
|
class EditModeElementChangerDirective {
|
|
@@ -542,70 +520,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
542
520
|
type: Directive,
|
|
543
521
|
args: [{
|
|
544
522
|
selector: '[appEditModeElementChanger]',
|
|
545
|
-
standalone: true,
|
|
546
523
|
}]
|
|
547
524
|
}], ctorParameters: () => [], propDecorators: { isEditMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEditMode", required: true }] }] } });
|
|
548
525
|
|
|
549
|
-
/**
|
|
550
|
-
* Check if user has a specific permission using wildcard matching.
|
|
551
|
-
* Supports:
|
|
552
|
-
* - Exact match: 'user.create' matches 'user.create'
|
|
553
|
-
* - Full wildcard: '*' matches everything
|
|
554
|
-
* - Module wildcard: 'user.*' matches 'user.create', 'user.read', etc.
|
|
555
|
-
*/
|
|
556
|
-
function hasPermission(requiredPermission, userPermissions) {
|
|
557
|
-
// Exact match
|
|
558
|
-
if (userPermissions.includes(requiredPermission))
|
|
559
|
-
return true;
|
|
560
|
-
// Wildcard matching
|
|
561
|
-
for (const permission of userPermissions) {
|
|
562
|
-
// Full wildcard - grants all permissions
|
|
563
|
-
if (permission === '*')
|
|
564
|
-
return true;
|
|
565
|
-
// Module wildcard (e.g., 'user.*' matches 'user.create')
|
|
566
|
-
if (permission.endsWith('.*') &&
|
|
567
|
-
requiredPermission.startsWith(permission.slice(0, -1))) {
|
|
568
|
-
return true;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
return false;
|
|
572
|
-
}
|
|
573
|
-
/** Evaluate permission logic (string or ILogicNode) against user permissions */
|
|
574
|
-
function evaluatePermission(logic, permissions) {
|
|
575
|
-
if (!logic)
|
|
576
|
-
return false;
|
|
577
|
-
if (typeof logic === 'string')
|
|
578
|
-
return hasPermission(logic, permissions);
|
|
579
|
-
return evaluateLogicNode(logic, permissions);
|
|
580
|
-
}
|
|
581
|
-
/** Recursively evaluate an ILogicNode tree */
|
|
582
|
-
function evaluateLogicNode(node, permissions) {
|
|
583
|
-
switch (node.type) {
|
|
584
|
-
case 'action':
|
|
585
|
-
return node.actionId ? hasPermission(node.actionId, permissions) : false;
|
|
586
|
-
case 'group':
|
|
587
|
-
if (!node.children || node.children.length === 0)
|
|
588
|
-
return false;
|
|
589
|
-
return node.operator === 'AND'
|
|
590
|
-
? node.children.every((child) => evaluateLogicNode(child, permissions))
|
|
591
|
-
: node.children.some((child) => evaluateLogicNode(child, permissions));
|
|
592
|
-
default:
|
|
593
|
-
return false;
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
/** Check if user has ANY of the specified permissions (OR logic) */
|
|
597
|
-
function hasAnyPermission(permissionCodes, permissions) {
|
|
598
|
-
if (!permissionCodes?.length)
|
|
599
|
-
return false;
|
|
600
|
-
return permissionCodes.some((code) => hasPermission(code, permissions));
|
|
601
|
-
}
|
|
602
|
-
/** Check if user has ALL of the specified permissions (AND logic) */
|
|
603
|
-
function hasAllPermissions(permissionCodes, permissions) {
|
|
604
|
-
if (!permissionCodes?.length)
|
|
605
|
-
return false;
|
|
606
|
-
return permissionCodes.every((code) => hasPermission(code, permissions));
|
|
607
|
-
}
|
|
608
|
-
|
|
609
526
|
/**
|
|
610
527
|
* HasPermission Directive
|
|
611
528
|
*
|
|
@@ -726,7 +643,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
726
643
|
type: Directive,
|
|
727
644
|
args: [{
|
|
728
645
|
selector: '[hasPermission]',
|
|
729
|
-
standalone: true,
|
|
730
646
|
}]
|
|
731
647
|
}], ctorParameters: () => [], propDecorators: { hasPermission: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasPermission", required: false }] }] } });
|
|
732
648
|
|
|
@@ -755,7 +671,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
755
671
|
'[src]': 'imageSrc()',
|
|
756
672
|
'(error)': 'onError()',
|
|
757
673
|
},
|
|
758
|
-
standalone: true,
|
|
759
674
|
}]
|
|
760
675
|
}], propDecorators: { src: [{ type: i0.Input, args: [{ isSignal: true, alias: "src", required: false }] }] } });
|
|
761
676
|
|
|
@@ -793,7 +708,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
793
708
|
type: Directive,
|
|
794
709
|
args: [{
|
|
795
710
|
selector: '[appPreventDefault]',
|
|
796
|
-
standalone: true,
|
|
797
711
|
host: {
|
|
798
712
|
'(click)': 'onClick($event)',
|
|
799
713
|
'(keydown)': 'onKeydown($event)',
|
|
@@ -1028,7 +942,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
1028
942
|
*/
|
|
1029
943
|
class ApiResourceService {
|
|
1030
944
|
baseUrl;
|
|
1031
|
-
loaderService = inject(ApiLoaderService);
|
|
1032
945
|
injector = inject(Injector);
|
|
1033
946
|
http;
|
|
1034
947
|
moduleApiName;
|
|
@@ -1432,26 +1345,25 @@ class IconComponent {
|
|
|
1432
1345
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: IconComponent, isStandalone: true, selector: "lib-icon", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: true, transformFunction: null }, iconType: { classPropertyName: "iconType", publicName: "iconType", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
1433
1346
|
@if (icon()) {
|
|
1434
1347
|
@if (iconType() === IconTypeEnum.PRIMENG_ICON) {
|
|
1435
|
-
<i [
|
|
1348
|
+
<i [class]="icon()"></i>
|
|
1436
1349
|
} @else if (iconType() === IconTypeEnum.IMAGE_FILE_LINK) {
|
|
1437
1350
|
<img [alt]="icon()" [src]="icon()" />
|
|
1438
1351
|
} @else {
|
|
1439
1352
|
<i class="pi pi-question"></i>
|
|
1440
1353
|
}
|
|
1441
1354
|
}
|
|
1442
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type:
|
|
1355
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: IsEmptyImageDirective, selector: "img", inputs: ["src"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1443
1356
|
}
|
|
1444
1357
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: IconComponent, decorators: [{
|
|
1445
1358
|
type: Component,
|
|
1446
1359
|
args: [{
|
|
1447
1360
|
selector: 'lib-icon',
|
|
1448
|
-
standalone: true,
|
|
1449
1361
|
imports: [AngularModule],
|
|
1450
1362
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1451
1363
|
template: `
|
|
1452
1364
|
@if (icon()) {
|
|
1453
1365
|
@if (iconType() === IconTypeEnum.PRIMENG_ICON) {
|
|
1454
|
-
<i [
|
|
1366
|
+
<i [class]="icon()"></i>
|
|
1455
1367
|
} @else if (iconType() === IconTypeEnum.IMAGE_FILE_LINK) {
|
|
1456
1368
|
<img [alt]="icon()" [src]="icon()" />
|
|
1457
1369
|
} @else {
|
|
@@ -1462,6 +1374,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
1462
1374
|
}]
|
|
1463
1375
|
}], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: true }] }], iconType: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconType", required: false }] }] } });
|
|
1464
1376
|
|
|
1377
|
+
/**
|
|
1378
|
+
* Check if scroll has reached near bottom and calculate next page if available.
|
|
1379
|
+
* Returns next pagination if should load more, null otherwise.
|
|
1380
|
+
*
|
|
1381
|
+
* @example
|
|
1382
|
+
* ```typescript
|
|
1383
|
+
* onScroll(event: Event): void {
|
|
1384
|
+
* const nextPagination = checkScrollPagination(event, {
|
|
1385
|
+
* pagination: this.pagination(),
|
|
1386
|
+
* total: this.total(),
|
|
1387
|
+
* isLoading: this.isLoading(),
|
|
1388
|
+
* });
|
|
1389
|
+
* if (nextPagination) {
|
|
1390
|
+
* this.onPagination.emit(nextPagination);
|
|
1391
|
+
* }
|
|
1392
|
+
* }
|
|
1393
|
+
* ```
|
|
1394
|
+
*/
|
|
1395
|
+
function checkScrollPagination(event, config) {
|
|
1396
|
+
const el = event.target;
|
|
1397
|
+
if (!(el instanceof HTMLElement))
|
|
1398
|
+
return null;
|
|
1399
|
+
const threshold = config.threshold ?? 50;
|
|
1400
|
+
const nearBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - threshold;
|
|
1401
|
+
if (!nearBottom || config.isLoading)
|
|
1402
|
+
return null;
|
|
1403
|
+
const { pagination, total } = config;
|
|
1404
|
+
const nextPage = pagination.currentPage + 1;
|
|
1405
|
+
const hasMore = nextPage * pagination.pageSize < (total ?? 0);
|
|
1406
|
+
if (!hasMore)
|
|
1407
|
+
return null;
|
|
1408
|
+
return { ...pagination, currentPage: nextPage };
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1465
1411
|
/**
|
|
1466
1412
|
* Lazy-loading multi-select component with search, pagination, and select-all.
|
|
1467
1413
|
*
|
|
@@ -1543,17 +1489,13 @@ class LazyMultiSelectComponent extends BaseFormControl {
|
|
|
1543
1489
|
});
|
|
1544
1490
|
}
|
|
1545
1491
|
onScroll(event) {
|
|
1546
|
-
const
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
const hasMore = nextPage * pag.pageSize < (this.total() ?? 0);
|
|
1554
|
-
if (hasMore) {
|
|
1555
|
-
this.onPagination.emit({ ...pag, currentPage: nextPage });
|
|
1556
|
-
}
|
|
1492
|
+
const nextPagination = checkScrollPagination(event, {
|
|
1493
|
+
pagination: this.pagination(),
|
|
1494
|
+
total: this.total(),
|
|
1495
|
+
isLoading: this.isLoading(),
|
|
1496
|
+
});
|
|
1497
|
+
if (nextPagination) {
|
|
1498
|
+
this.onPagination.emit(nextPagination);
|
|
1557
1499
|
}
|
|
1558
1500
|
}
|
|
1559
1501
|
onSelectClick(event) {
|
|
@@ -1603,11 +1545,11 @@ class LazyMultiSelectComponent extends BaseFormControl {
|
|
|
1603
1545
|
this.value.set([]);
|
|
1604
1546
|
}
|
|
1605
1547
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: LazyMultiSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1606
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", 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 }], usesInheritance: true, ngImport: i0, template: "<div class=\"p-select w-full\" #pSelect (click)=\"onSelectClick($event)\" [class.p-disabled]=\"disabled()\">\n @if (selectedValueDisplay()) {\n <span class=\"p-select-label\">{{ selectedValueDisplay() }}</span>\n } @else {\n <span class=\"p-select-label p-placeholder\">{{ placeHolder() }}</span>\n }\n\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 width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"\n class=\"p-multiselect-dropdown-icon p-icon\" aria-hidden=\"true\">\n <path 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\" fill=\"currentColor\" />\n </svg>\n </span>\n </div>\n\n @if (openOptions()) {\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=\"Search...\"\n [ngModel]=\"searchTerm()\"\n [ngModelOptions]=\"{ standalone: true }\"\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 key(data)) {\n <li class=\"p-select-option flex flex-row gap-2 items-center\"\n [ngClass]=\"{ 'p-select-option-selected': isSelected(data) }\">\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 }\n</div>", styles: [".p-select-overlay{position:absolute;top:100%;left:0;right:0;z-index:var(--p-overlay-select-zindex, 1004);margin-top:var(--p-select-overlay-offset, 2px);background:var(--p-select-overlay-background, var(--p-surface-0));border:1px solid var(--p-select-overlay-border-color, var(--p-surface-200));border-radius:var(--p-select-overlay-border-radius, var(--p-border-radius));box-shadow:var(--p-select-overlay-shadow, var(--p-overlay-shadow))}.p-select-header{padding:.75rem;border-bottom:1px solid var(--p-surface-200);background:var(--p-surface-50)}:host-context(.p-dark) .p-select-header,.dark .p-select-header{border-color:var(--p-surface-700);background:var(--p-surface-800)}.p-select-list-container{max-height:10rem;overflow-y:auto}@media(min-width:640px){.p-select-list-container{max-height:12.5rem}}.p-select-list{margin:0;padding:.25rem 0;list-style:none}.p-select-option{padding:.5rem .75rem;cursor:pointer;transition:background-color .2s ease}.p-select-option:hover{background:var(--p-select-option-focus-background, var(--p-surface-100));color:var(--p-select-option-focus-color, var(--p-text-color))}:host-context(.p-dark) .p-select-option:hover,.dark .p-select-option:hover{background:var(--p-surface-700)}.p-select-option.p-select-option-selected{background:var(--p-select-option-selected-background, var(--p-primary-50));color:var(--p-select-option-selected-color, var(--p-primary-color))}:host-context(.p-dark) .p-select-option.p-select-option-selected,.dark .p-select-option.p-select-option-selected{background:var(--p-primary-900)}.p-select-option.p-select-option-selected:hover{background:var(--p-select-option-selected-focus-background, var(--p-primary-100));color:var(--p-select-option-selected-focus-color, var(--p-primary-color))}:host-context(.p-dark) .p-select-option.p-select-option-selected:hover,.dark .p-select-option.p-select-option-selected:hover{background:var(--p-primary-800)}.p-select-clear-icon{display:flex;align-items:center;padding:0 .5rem;color:var(--p-text-color-secondary);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
|
|
1548
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", 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 }], usesInheritance: true, ngImport: i0, template: "<div class=\"p-select w-full\" #pSelect (click)=\"onSelectClick($event)\" [class.p-disabled]=\"disabled()\">\n @if (selectedValueDisplay()) {\n <span class=\"p-select-label\">{{ selectedValueDisplay() }}</span>\n } @else {\n <span class=\"p-select-label p-placeholder\">{{ placeHolder() }}</span>\n }\n\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 width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"\n class=\"p-multiselect-dropdown-icon p-icon\" aria-hidden=\"true\">\n <path 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\" fill=\"currentColor\" />\n </svg>\n </span>\n </div>\n\n @if (openOptions()) {\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=\"Search...\"\n [ngModel]=\"searchTerm()\"\n [ngModelOptions]=\"{ standalone: true }\"\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 key(data)) {\n <li class=\"p-select-option flex flex-row gap-2 items-center\"\n [ngClass]=\"{ 'p-select-option-selected': isSelected(data) }\">\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 }\n</div>", styles: [".p-select-overlay{position:absolute;top:100%;left:0;right:0;z-index:var(--p-overlay-select-zindex, 1004);margin-top:var(--p-select-overlay-offset, 2px);background:var(--p-select-overlay-background, var(--p-surface-0));border:1px solid var(--p-select-overlay-border-color, var(--p-surface-200));border-radius:var(--p-select-overlay-border-radius, var(--p-border-radius));box-shadow:var(--p-select-overlay-shadow, var(--p-overlay-shadow))}.p-select-header{padding:.75rem;border-bottom:1px solid var(--p-surface-200);background:var(--p-surface-50)}:host-context(.p-dark) .p-select-header,.dark .p-select-header{border-color:var(--p-surface-700);background:var(--p-surface-800)}.p-select-list-container{max-height:10rem;overflow-y:auto}@media(min-width:640px){.p-select-list-container{max-height:12.5rem}}.p-select-list{margin:0;padding:.25rem 0;list-style:none}.p-select-option{padding:.5rem .75rem;cursor:pointer;transition:background-color .2s ease}.p-select-option:hover{background:var(--p-select-option-focus-background, var(--p-surface-100));color:var(--p-select-option-focus-color, var(--p-text-color))}:host-context(.p-dark) .p-select-option:hover,.dark .p-select-option:hover{background:var(--p-surface-700)}.p-select-option.p-select-option-selected{background:var(--p-select-option-selected-background, var(--p-primary-50));color:var(--p-select-option-selected-color, var(--p-primary-color))}:host-context(.p-dark) .p-select-option.p-select-option-selected,.dark .p-select-option.p-select-option-selected{background:var(--p-primary-900)}.p-select-option.p-select-option-selected:hover{background:var(--p-select-option-selected-focus-background, var(--p-primary-100));color:var(--p-select-option-selected-focus-color, var(--p-primary-color))}:host-context(.p-dark) .p-select-option.p-select-option-selected:hover,.dark .p-select-option.p-select-option-selected:hover{background:var(--p-primary-800)}.p-select-clear-icon{display:flex;align-items:center;padding:0 .5rem;color:var(--p-text-color-secondary);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: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1607
1549
|
}
|
|
1608
1550
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: LazyMultiSelectComponent, decorators: [{
|
|
1609
1551
|
type: Component,
|
|
1610
|
-
args: [{ selector: 'lib-lazy-multi-select',
|
|
1552
|
+
args: [{ selector: 'lib-lazy-multi-select', imports: [PrimeModule, AngularModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [provideValueAccessor(LazyMultiSelectComponent)], template: "<div class=\"p-select w-full\" #pSelect (click)=\"onSelectClick($event)\" [class.p-disabled]=\"disabled()\">\n @if (selectedValueDisplay()) {\n <span class=\"p-select-label\">{{ selectedValueDisplay() }}</span>\n } @else {\n <span class=\"p-select-label p-placeholder\">{{ placeHolder() }}</span>\n }\n\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 width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"\n class=\"p-multiselect-dropdown-icon p-icon\" aria-hidden=\"true\">\n <path 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\" fill=\"currentColor\" />\n </svg>\n </span>\n </div>\n\n @if (openOptions()) {\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=\"Search...\"\n [ngModel]=\"searchTerm()\"\n [ngModelOptions]=\"{ standalone: true }\"\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 key(data)) {\n <li class=\"p-select-option flex flex-row gap-2 items-center\"\n [ngClass]=\"{ 'p-select-option-selected': isSelected(data) }\">\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 }\n</div>", styles: [".p-select-overlay{position:absolute;top:100%;left:0;right:0;z-index:var(--p-overlay-select-zindex, 1004);margin-top:var(--p-select-overlay-offset, 2px);background:var(--p-select-overlay-background, var(--p-surface-0));border:1px solid var(--p-select-overlay-border-color, var(--p-surface-200));border-radius:var(--p-select-overlay-border-radius, var(--p-border-radius));box-shadow:var(--p-select-overlay-shadow, var(--p-overlay-shadow))}.p-select-header{padding:.75rem;border-bottom:1px solid var(--p-surface-200);background:var(--p-surface-50)}:host-context(.p-dark) .p-select-header,.dark .p-select-header{border-color:var(--p-surface-700);background:var(--p-surface-800)}.p-select-list-container{max-height:10rem;overflow-y:auto}@media(min-width:640px){.p-select-list-container{max-height:12.5rem}}.p-select-list{margin:0;padding:.25rem 0;list-style:none}.p-select-option{padding:.5rem .75rem;cursor:pointer;transition:background-color .2s ease}.p-select-option:hover{background:var(--p-select-option-focus-background, var(--p-surface-100));color:var(--p-select-option-focus-color, var(--p-text-color))}:host-context(.p-dark) .p-select-option:hover,.dark .p-select-option:hover{background:var(--p-surface-700)}.p-select-option.p-select-option-selected{background:var(--p-select-option-selected-background, var(--p-primary-50));color:var(--p-select-option-selected-color, var(--p-primary-color))}:host-context(.p-dark) .p-select-option.p-select-option-selected,.dark .p-select-option.p-select-option-selected{background:var(--p-primary-900)}.p-select-option.p-select-option-selected:hover{background:var(--p-select-option-selected-focus-background, var(--p-primary-100));color:var(--p-select-option-selected-focus-color, var(--p-primary-color))}:host-context(.p-dark) .p-select-option.p-select-option-selected:hover,.dark .p-select-option.p-select-option-selected:hover{background:var(--p-primary-800)}.p-select-clear-icon{display:flex;align-items:center;padding:0 .5rem;color:var(--p-text-color-secondary);cursor:pointer;transition:color .2s ease}.p-select-clear-icon:hover{color:var(--p-text-color)}\n"] }]
|
|
1611
1553
|
}], ctorParameters: () => [], propDecorators: { pSelectRef: [{ type: i0.ViewChild, args: ['pSelect', { 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"] }] } });
|
|
1612
1554
|
|
|
1613
1555
|
/**
|
|
@@ -1673,17 +1615,13 @@ class LazySelectComponent extends BaseFormControl {
|
|
|
1673
1615
|
});
|
|
1674
1616
|
}
|
|
1675
1617
|
onScroll(event) {
|
|
1676
|
-
const
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
const hasMore = nextPage * pag.pageSize < (this.total() ?? 0);
|
|
1684
|
-
if (hasMore) {
|
|
1685
|
-
this.onPagination.emit({ ...pag, currentPage: nextPage });
|
|
1686
|
-
}
|
|
1618
|
+
const nextPagination = checkScrollPagination(event, {
|
|
1619
|
+
pagination: this.pagination(),
|
|
1620
|
+
total: this.total(),
|
|
1621
|
+
isLoading: this.isLoading(),
|
|
1622
|
+
});
|
|
1623
|
+
if (nextPagination) {
|
|
1624
|
+
this.onPagination.emit(nextPagination);
|
|
1687
1625
|
}
|
|
1688
1626
|
}
|
|
1689
1627
|
showPanel() {
|
|
@@ -1710,11 +1648,11 @@ class LazySelectComponent extends BaseFormControl {
|
|
|
1710
1648
|
this.markAsTouched();
|
|
1711
1649
|
}
|
|
1712
1650
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: LazySelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1713
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.3", 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]=\"placeHolder()\"\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$
|
|
1651
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.3", 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]=\"placeHolder()\"\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$1.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1714
1652
|
}
|
|
1715
1653
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: LazySelectComponent, decorators: [{
|
|
1716
1654
|
type: Component,
|
|
1717
|
-
args: [{ selector: 'lib-lazy-select',
|
|
1655
|
+
args: [{ selector: 'lib-lazy-select', imports: [AngularModule, PrimeModule, EditModeElementChangerDirective], changeDetection: ChangeDetectionStrategy.OnPush, 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]=\"placeHolder()\"\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" }]
|
|
1718
1656
|
}], 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"] }] } });
|
|
1719
1657
|
|
|
1720
1658
|
/**
|
|
@@ -1813,56 +1751,33 @@ const PROFILE_UPLOAD_PROVIDER = new InjectionToken('PROFILE_UPLOAD_PROVIDER');
|
|
|
1813
1751
|
*/
|
|
1814
1752
|
const USER_LIST_PROVIDER = new InjectionToken('USER_LIST_PROVIDER');
|
|
1815
1753
|
|
|
1816
|
-
const DEFAULT_PAGE_SIZE$
|
|
1754
|
+
const DEFAULT_PAGE_SIZE$1 = 20;
|
|
1817
1755
|
/**
|
|
1818
|
-
*
|
|
1819
|
-
*
|
|
1820
|
-
* Uses USER_PROVIDER internally by default, or accepts custom `loadUsers` function.
|
|
1821
|
-
*
|
|
1822
|
-
* Features:
|
|
1823
|
-
* - Search with debouncing (handled by lazy-select)
|
|
1824
|
-
* - Infinite scroll pagination
|
|
1825
|
-
* - Filter active users by default (configurable)
|
|
1826
|
-
* - Supports additional filters via `additionalFilters` input
|
|
1827
|
-
*
|
|
1828
|
-
* @example
|
|
1829
|
-
* ```html
|
|
1830
|
-
* <!-- Simple usage - uses USER_PROVIDER internally -->
|
|
1831
|
-
* <lib-user-select
|
|
1832
|
-
* [(value)]="selectedUserId"
|
|
1833
|
-
* [isEditMode]="true"
|
|
1834
|
-
* />
|
|
1756
|
+
* Base class for user selection components.
|
|
1757
|
+
* Provides shared user loading, pagination, and search functionality.
|
|
1835
1758
|
*
|
|
1836
|
-
*
|
|
1837
|
-
*
|
|
1838
|
-
* [(value)]="selectedUserId"
|
|
1839
|
-
* [isEditMode]="true"
|
|
1840
|
-
* [loadUsers]="customLoadUsers"
|
|
1841
|
-
* />
|
|
1842
|
-
* ```
|
|
1759
|
+
* Subclasses must implement:
|
|
1760
|
+
* - `setupValueEffect()` to track value changes and emit selection events
|
|
1843
1761
|
*/
|
|
1844
|
-
class
|
|
1762
|
+
class BaseUserSelectComponent {
|
|
1845
1763
|
destroyRef = inject(DestroyRef);
|
|
1764
|
+
injector = inject(Injector);
|
|
1846
1765
|
userProvider = inject(USER_PROVIDER);
|
|
1847
1766
|
abortController = null;
|
|
1848
|
-
// Optional: custom function to load users (uses USER_PROVIDER if not provided)
|
|
1849
|
-
loadUsers = input(...(ngDevMode ? [undefined, { debugName: "loadUsers" }] : []));
|
|
1850
1767
|
// Inputs
|
|
1768
|
+
loadUsers = input(...(ngDevMode ? [undefined, { debugName: "loadUsers" }] : []));
|
|
1851
1769
|
placeHolder = input('Select User', ...(ngDevMode ? [{ debugName: "placeHolder" }] : []));
|
|
1852
1770
|
isEditMode = input.required(...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
|
|
1853
1771
|
filterActive = input(true, ...(ngDevMode ? [{ debugName: "filterActive" }] : []));
|
|
1854
1772
|
additionalFilters = input({}, ...(ngDevMode ? [{ debugName: "additionalFilters" }] : []));
|
|
1855
|
-
pageSize = input(DEFAULT_PAGE_SIZE$
|
|
1856
|
-
// Two-way bound value
|
|
1857
|
-
value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
1773
|
+
pageSize = input(DEFAULT_PAGE_SIZE$1, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
|
|
1858
1774
|
// Outputs
|
|
1859
|
-
userSelected = output();
|
|
1860
1775
|
onError = output();
|
|
1861
1776
|
// Internal state
|
|
1862
1777
|
isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
1863
1778
|
users = signal([], ...(ngDevMode ? [{ debugName: "users" }] : []));
|
|
1864
1779
|
total = signal(undefined, ...(ngDevMode ? [{ debugName: "total" }] : []));
|
|
1865
|
-
pagination = signal({ pageSize: DEFAULT_PAGE_SIZE$
|
|
1780
|
+
pagination = signal({ pageSize: DEFAULT_PAGE_SIZE$1, currentPage: 0 }, ...(ngDevMode ? [{ debugName: "pagination" }] : []));
|
|
1866
1781
|
searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
|
|
1867
1782
|
// Computed dropdown data
|
|
1868
1783
|
dropdownUsers = computed(() => this.users().map((user) => ({
|
|
@@ -1885,20 +1800,8 @@ class UserSelectComponent {
|
|
|
1885
1800
|
afterNextRender(() => {
|
|
1886
1801
|
this.fetchUsers();
|
|
1887
1802
|
});
|
|
1888
|
-
//
|
|
1889
|
-
|
|
1890
|
-
const selectedId = this.value();
|
|
1891
|
-
const users = this.users();
|
|
1892
|
-
untracked(() => {
|
|
1893
|
-
if (selectedId) {
|
|
1894
|
-
const user = users.find((u) => u.id === selectedId);
|
|
1895
|
-
this.userSelected.emit(user ?? null);
|
|
1896
|
-
}
|
|
1897
|
-
else {
|
|
1898
|
-
this.userSelected.emit(null);
|
|
1899
|
-
}
|
|
1900
|
-
});
|
|
1901
|
-
});
|
|
1803
|
+
// Setup value change tracking (implemented by subclass)
|
|
1804
|
+
this.setupValueEffect();
|
|
1902
1805
|
}
|
|
1903
1806
|
handleSearch(search) {
|
|
1904
1807
|
this.searchTerm.set(search);
|
|
@@ -1910,6 +1813,12 @@ class UserSelectComponent {
|
|
|
1910
1813
|
this.pagination.set(pagination);
|
|
1911
1814
|
this.fetchUsers(true);
|
|
1912
1815
|
}
|
|
1816
|
+
/** Reload users (useful when filters change externally) */
|
|
1817
|
+
reload() {
|
|
1818
|
+
this.pagination.update((p) => ({ ...p, currentPage: 0 }));
|
|
1819
|
+
this.users.set([]);
|
|
1820
|
+
this.fetchUsers();
|
|
1821
|
+
}
|
|
1913
1822
|
async fetchUsers(append = false) {
|
|
1914
1823
|
if (this.isLoading())
|
|
1915
1824
|
return;
|
|
@@ -1967,14 +1876,63 @@ class UserSelectComponent {
|
|
|
1967
1876
|
})),
|
|
1968
1877
|
})));
|
|
1969
1878
|
}
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1879
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BaseUserSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1880
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.3", 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 });
|
|
1881
|
+
}
|
|
1882
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BaseUserSelectComponent, decorators: [{
|
|
1883
|
+
type: Directive
|
|
1884
|
+
}], ctorParameters: () => [], propDecorators: { loadUsers: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadUsers", required: false }] }], placeHolder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeHolder", required: false }] }], isEditMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEditMode", required: true }] }], filterActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterActive", required: false }] }], additionalFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "additionalFilters", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], onError: [{ type: i0.Output, args: ["onError"] }] } });
|
|
1885
|
+
|
|
1886
|
+
/**
|
|
1887
|
+
* User Select Component - Single user selection with lazy loading.
|
|
1888
|
+
*
|
|
1889
|
+
* Uses USER_PROVIDER internally by default, or accepts custom `loadUsers` function.
|
|
1890
|
+
*
|
|
1891
|
+
* Features:
|
|
1892
|
+
* - Search with debouncing (handled by lazy-select)
|
|
1893
|
+
* - Infinite scroll pagination
|
|
1894
|
+
* - Filter active users by default (configurable)
|
|
1895
|
+
* - Supports additional filters via `additionalFilters` input
|
|
1896
|
+
*
|
|
1897
|
+
* @example
|
|
1898
|
+
* ```html
|
|
1899
|
+
* <!-- Simple usage - uses USER_PROVIDER internally -->
|
|
1900
|
+
* <lib-user-select
|
|
1901
|
+
* [(value)]="selectedUserId"
|
|
1902
|
+
* [isEditMode]="true"
|
|
1903
|
+
* />
|
|
1904
|
+
*
|
|
1905
|
+
* <!-- With custom loadUsers function -->
|
|
1906
|
+
* <lib-user-select
|
|
1907
|
+
* [(value)]="selectedUserId"
|
|
1908
|
+
* [isEditMode]="true"
|
|
1909
|
+
* [loadUsers]="customLoadUsers"
|
|
1910
|
+
* />
|
|
1911
|
+
* ```
|
|
1912
|
+
*/
|
|
1913
|
+
class UserSelectComponent extends BaseUserSelectComponent {
|
|
1914
|
+
// Two-way bound value
|
|
1915
|
+
value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
1916
|
+
// Outputs
|
|
1917
|
+
userSelected = output();
|
|
1918
|
+
setupValueEffect() {
|
|
1919
|
+
// Emit selected user when value changes
|
|
1920
|
+
effect(() => {
|
|
1921
|
+
const selectedId = this.value();
|
|
1922
|
+
const users = this.users();
|
|
1923
|
+
untracked(() => {
|
|
1924
|
+
if (selectedId) {
|
|
1925
|
+
const user = users.find((u) => u.id === selectedId);
|
|
1926
|
+
this.userSelected.emit(user ?? null);
|
|
1927
|
+
}
|
|
1928
|
+
else {
|
|
1929
|
+
this.userSelected.emit(null);
|
|
1930
|
+
}
|
|
1931
|
+
});
|
|
1932
|
+
});
|
|
1975
1933
|
}
|
|
1976
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserSelectComponent, deps:
|
|
1977
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.3", type: UserSelectComponent, isStandalone: true, selector: "lib-user-select", inputs: {
|
|
1934
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserSelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
1935
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.3", 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: `
|
|
1978
1936
|
<lib-lazy-select
|
|
1979
1937
|
[(value)]="value"
|
|
1980
1938
|
[placeHolder]="placeHolder()"
|
|
@@ -1994,7 +1952,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
1994
1952
|
type: Component,
|
|
1995
1953
|
args: [{
|
|
1996
1954
|
selector: 'lib-user-select',
|
|
1997
|
-
standalone: true,
|
|
1998
1955
|
imports: [AngularModule, PrimeModule, LazySelectComponent],
|
|
1999
1956
|
template: `
|
|
2000
1957
|
<lib-lazy-select
|
|
@@ -2013,9 +1970,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
2013
1970
|
`,
|
|
2014
1971
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
2015
1972
|
}]
|
|
2016
|
-
}],
|
|
1973
|
+
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], userSelected: [{ type: i0.Output, args: ["userSelected"] }] } });
|
|
2017
1974
|
|
|
2018
|
-
const DEFAULT_PAGE_SIZE$1 = 20;
|
|
2019
1975
|
/**
|
|
2020
1976
|
* User Multi-Select Component - Multiple user selection with lazy loading.
|
|
2021
1977
|
*
|
|
@@ -2044,50 +2000,12 @@ const DEFAULT_PAGE_SIZE$1 = 20;
|
|
|
2044
2000
|
* />
|
|
2045
2001
|
* ```
|
|
2046
2002
|
*/
|
|
2047
|
-
class UserMultiSelectComponent {
|
|
2048
|
-
destroyRef = inject(DestroyRef);
|
|
2049
|
-
userProvider = inject(USER_PROVIDER);
|
|
2050
|
-
abortController = null;
|
|
2051
|
-
// Optional: custom function to load users (uses USER_PROVIDER if not provided)
|
|
2052
|
-
loadUsers = input(...(ngDevMode ? [undefined, { debugName: "loadUsers" }] : []));
|
|
2053
|
-
// Inputs
|
|
2054
|
-
placeHolder = input('Select Users', ...(ngDevMode ? [{ debugName: "placeHolder" }] : []));
|
|
2055
|
-
isEditMode = input.required(...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
|
|
2056
|
-
filterActive = input(true, ...(ngDevMode ? [{ debugName: "filterActive" }] : []));
|
|
2057
|
-
additionalFilters = input({}, ...(ngDevMode ? [{ debugName: "additionalFilters" }] : []));
|
|
2058
|
-
pageSize = input(DEFAULT_PAGE_SIZE$1, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
|
|
2003
|
+
class UserMultiSelectComponent extends BaseUserSelectComponent {
|
|
2059
2004
|
// Two-way bound value
|
|
2060
2005
|
value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
2061
2006
|
// Outputs
|
|
2062
2007
|
usersSelected = output();
|
|
2063
|
-
|
|
2064
|
-
// Internal state
|
|
2065
|
-
isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
2066
|
-
users = signal([], ...(ngDevMode ? [{ debugName: "users" }] : []));
|
|
2067
|
-
total = signal(undefined, ...(ngDevMode ? [{ debugName: "total" }] : []));
|
|
2068
|
-
pagination = signal({ pageSize: DEFAULT_PAGE_SIZE$1, currentPage: 0 }, ...(ngDevMode ? [{ debugName: "pagination" }] : []));
|
|
2069
|
-
searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
|
|
2070
|
-
// Computed dropdown data
|
|
2071
|
-
dropdownUsers = computed(() => this.users().map((user) => ({
|
|
2072
|
-
label: user.name || user.email,
|
|
2073
|
-
value: user.id,
|
|
2074
|
-
})), ...(ngDevMode ? [{ debugName: "dropdownUsers" }] : []));
|
|
2075
|
-
constructor() {
|
|
2076
|
-
// Cleanup on destroy
|
|
2077
|
-
this.destroyRef.onDestroy(() => {
|
|
2078
|
-
this.abortController?.abort();
|
|
2079
|
-
});
|
|
2080
|
-
// Update page size from input
|
|
2081
|
-
effect(() => {
|
|
2082
|
-
const size = this.pageSize();
|
|
2083
|
-
untracked(() => {
|
|
2084
|
-
this.pagination.update((p) => ({ ...p, pageSize: size }));
|
|
2085
|
-
});
|
|
2086
|
-
});
|
|
2087
|
-
// Load initial users after render
|
|
2088
|
-
afterNextRender(() => {
|
|
2089
|
-
this.fetchUsers();
|
|
2090
|
-
});
|
|
2008
|
+
setupValueEffect() {
|
|
2091
2009
|
// Emit selected users when value changes
|
|
2092
2010
|
effect(() => {
|
|
2093
2011
|
const selectedIds = this.value() ?? [];
|
|
@@ -2098,81 +2016,8 @@ class UserMultiSelectComponent {
|
|
|
2098
2016
|
});
|
|
2099
2017
|
});
|
|
2100
2018
|
}
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
this.pagination.update((p) => ({ ...p, currentPage: 0 }));
|
|
2104
|
-
this.users.set([]);
|
|
2105
|
-
this.fetchUsers();
|
|
2106
|
-
}
|
|
2107
|
-
handlePagination(pagination) {
|
|
2108
|
-
this.pagination.set(pagination);
|
|
2109
|
-
this.fetchUsers(true);
|
|
2110
|
-
}
|
|
2111
|
-
async fetchUsers(append = false) {
|
|
2112
|
-
if (this.isLoading())
|
|
2113
|
-
return;
|
|
2114
|
-
// Cancel previous request
|
|
2115
|
-
this.abortController?.abort();
|
|
2116
|
-
this.abortController = new AbortController();
|
|
2117
|
-
this.isLoading.set(true);
|
|
2118
|
-
try {
|
|
2119
|
-
const pag = this.pagination();
|
|
2120
|
-
const filter = {
|
|
2121
|
-
page: pag.currentPage,
|
|
2122
|
-
pageSize: pag.pageSize,
|
|
2123
|
-
search: this.searchTerm(),
|
|
2124
|
-
...this.additionalFilters(),
|
|
2125
|
-
};
|
|
2126
|
-
// Use custom loadUsers if provided, otherwise use USER_PROVIDER
|
|
2127
|
-
const customLoadUsers = this.loadUsers();
|
|
2128
|
-
const response = await firstValueFrom(customLoadUsers
|
|
2129
|
-
? customLoadUsers(filter)
|
|
2130
|
-
: this.loadUsersFromProvider(filter));
|
|
2131
|
-
if (response.success && response.data) {
|
|
2132
|
-
if (append) {
|
|
2133
|
-
this.users.update((current) => [...current, ...response.data]);
|
|
2134
|
-
}
|
|
2135
|
-
else {
|
|
2136
|
-
this.users.set(response.data);
|
|
2137
|
-
}
|
|
2138
|
-
this.total.set(response.meta?.total);
|
|
2139
|
-
}
|
|
2140
|
-
}
|
|
2141
|
-
catch (error) {
|
|
2142
|
-
if (error.name !== 'AbortError') {
|
|
2143
|
-
this.onError.emit(error);
|
|
2144
|
-
}
|
|
2145
|
-
}
|
|
2146
|
-
finally {
|
|
2147
|
-
this.isLoading.set(false);
|
|
2148
|
-
}
|
|
2149
|
-
}
|
|
2150
|
-
/** Load users from USER_PROVIDER with active filter */
|
|
2151
|
-
loadUsersFromProvider(filter) {
|
|
2152
|
-
return this.userProvider
|
|
2153
|
-
.getUsers({
|
|
2154
|
-
page: filter.page,
|
|
2155
|
-
pageSize: filter.pageSize,
|
|
2156
|
-
search: filter.search,
|
|
2157
|
-
isActive: this.filterActive() ? true : undefined,
|
|
2158
|
-
})
|
|
2159
|
-
.pipe(map$1((res) => ({
|
|
2160
|
-
...res,
|
|
2161
|
-
data: res.data?.map((u) => ({
|
|
2162
|
-
id: u.id,
|
|
2163
|
-
name: u.name,
|
|
2164
|
-
email: u.email,
|
|
2165
|
-
})),
|
|
2166
|
-
})));
|
|
2167
|
-
}
|
|
2168
|
-
/** Reload users (useful when filters change externally) */
|
|
2169
|
-
reload() {
|
|
2170
|
-
this.pagination.update((p) => ({ ...p, currentPage: 0 }));
|
|
2171
|
-
this.users.set([]);
|
|
2172
|
-
this.fetchUsers();
|
|
2173
|
-
}
|
|
2174
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserMultiSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2175
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.3", type: UserMultiSelectComponent, isStandalone: true, selector: "lib-user-multi-select", 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 }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", usersSelected: "usersSelected", onError: "onError" }, ngImport: i0, template: `
|
|
2019
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserMultiSelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
2020
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.3", 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: `
|
|
2176
2021
|
<lib-lazy-multi-select
|
|
2177
2022
|
[(value)]="value"
|
|
2178
2023
|
[placeHolder]="placeHolder()"
|
|
@@ -2190,7 +2035,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
2190
2035
|
type: Component,
|
|
2191
2036
|
args: [{
|
|
2192
2037
|
selector: 'lib-user-multi-select',
|
|
2193
|
-
standalone: true,
|
|
2194
2038
|
imports: [AngularModule, PrimeModule, LazyMultiSelectComponent],
|
|
2195
2039
|
template: `
|
|
2196
2040
|
<lib-lazy-multi-select
|
|
@@ -2207,7 +2051,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
2207
2051
|
`,
|
|
2208
2052
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
2209
2053
|
}]
|
|
2210
|
-
}],
|
|
2054
|
+
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], usersSelected: [{ type: i0.Output, args: ["usersSelected"] }] } });
|
|
2211
2055
|
|
|
2212
2056
|
/**
|
|
2213
2057
|
* File Uploader Component - Drag & drop file upload with type filtering.
|
|
@@ -2454,11 +2298,11 @@ class FileUploaderComponent {
|
|
|
2454
2298
|
</div>
|
|
2455
2299
|
}
|
|
2456
2300
|
</div>
|
|
2457
|
-
`, 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$
|
|
2301
|
+
`, 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2458
2302
|
}
|
|
2459
2303
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: FileUploaderComponent, decorators: [{
|
|
2460
2304
|
type: Component,
|
|
2461
|
-
args: [{ selector: 'lib-file-uploader',
|
|
2305
|
+
args: [{ selector: 'lib-file-uploader', imports: [AngularModule, PrimeModule], template: `
|
|
2462
2306
|
<div
|
|
2463
2307
|
class="w-full"
|
|
2464
2308
|
[class.opacity-60]="disabled()"
|
|
@@ -2649,16 +2493,14 @@ class FileSelectorDialogComponent {
|
|
|
2649
2493
|
}, 500);
|
|
2650
2494
|
}
|
|
2651
2495
|
onScroll(event) {
|
|
2652
|
-
const
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
this.fetchFiles(true);
|
|
2661
|
-
}
|
|
2496
|
+
const nextPagination = checkScrollPagination(event, {
|
|
2497
|
+
pagination: this.pagination(),
|
|
2498
|
+
total: this.total(),
|
|
2499
|
+
isLoading: this.isLoading(),
|
|
2500
|
+
});
|
|
2501
|
+
if (nextPagination) {
|
|
2502
|
+
this.pagination.set(nextPagination);
|
|
2503
|
+
this.fetchFiles(true);
|
|
2662
2504
|
}
|
|
2663
2505
|
}
|
|
2664
2506
|
toggleSelection(file) {
|
|
@@ -2868,11 +2710,11 @@ class FileSelectorDialogComponent {
|
|
|
2868
2710
|
</div>
|
|
2869
2711
|
</ng-template>
|
|
2870
2712
|
</p-dialog>
|
|
2871
|
-
`, 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$
|
|
2713
|
+
`, 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: i4.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: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2872
2714
|
}
|
|
2873
2715
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: FileSelectorDialogComponent, decorators: [{
|
|
2874
2716
|
type: Component,
|
|
2875
|
-
args: [{ selector: 'lib-file-selector-dialog',
|
|
2717
|
+
args: [{ selector: 'lib-file-selector-dialog', imports: [AngularModule, PrimeModule], template: `
|
|
2876
2718
|
<p-dialog
|
|
2877
2719
|
[header]="header()"
|
|
2878
2720
|
[(visible)]="visible"
|
|
@@ -2982,129 +2824,75 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
2982
2824
|
`, changeDetection: ChangeDetectionStrategy.OnPush, 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"] }]
|
|
2983
2825
|
}], ctorParameters: () => [], propDecorators: { loadFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadFiles", required: true }] }], 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 }] }], 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"] }] } });
|
|
2984
2826
|
|
|
2985
|
-
|
|
2986
|
-
const devLog = (message) => {
|
|
2987
|
-
if (isDevMode())
|
|
2988
|
-
console.log(message);
|
|
2989
|
-
};
|
|
2990
|
-
/**
|
|
2991
|
-
* Permission Guard
|
|
2992
|
-
*
|
|
2993
|
-
* Route-level guard for permission-based access control.
|
|
2994
|
-
* Validates permissions before allowing navigation.
|
|
2995
|
-
*
|
|
2996
|
-
* Features:
|
|
2997
|
-
* - Single permission check
|
|
2998
|
-
* - Complex ILogicNode logic trees
|
|
2999
|
-
* - Configurable redirect URL
|
|
3000
|
-
* - Debug logging for denied access
|
|
3001
|
-
*
|
|
3002
|
-
* @example
|
|
3003
|
-
* ```typescript
|
|
3004
|
-
* // Simple permission check
|
|
3005
|
-
* { path: 'users', canActivate: [permissionGuard('user.view')] }
|
|
3006
|
-
*
|
|
3007
|
-
* // Complex logic
|
|
3008
|
-
* { path: 'admin', canActivate: [permissionGuard({
|
|
3009
|
-
* id: 'root',
|
|
3010
|
-
* type: 'group',
|
|
3011
|
-
* operator: 'AND',
|
|
3012
|
-
* children: [
|
|
3013
|
-
* { id: '1', type: 'action', actionId: 'admin.view' },
|
|
3014
|
-
* { id: '2', type: 'action', actionId: 'admin.manage' }
|
|
3015
|
-
* ]
|
|
3016
|
-
* })] }
|
|
3017
|
-
*
|
|
3018
|
-
* // With custom redirect
|
|
3019
|
-
* { path: 'users', canActivate: [permissionGuard('user.view', '/access-denied')] }
|
|
3020
|
-
* ```
|
|
3021
|
-
*/
|
|
3022
|
-
function permissionGuard(permission, redirectTo = '/') {
|
|
2827
|
+
function createGuard(guardName, redirectTo, evaluate, getDenialMessage) {
|
|
3023
2828
|
return () => {
|
|
3024
2829
|
const permissionValidator = inject(PermissionValidatorService);
|
|
3025
2830
|
const router = inject(Router);
|
|
3026
|
-
// Check if permissions are loaded
|
|
3027
2831
|
if (!permissionValidator.isPermissionsLoaded()) {
|
|
3028
|
-
|
|
2832
|
+
if (isDevMode()) {
|
|
2833
|
+
console.log(`[${guardName}] Permissions not loaded, denying access`);
|
|
2834
|
+
}
|
|
3029
2835
|
return router.createUrlTree([redirectTo]);
|
|
3030
2836
|
}
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
devLog(`[permissionGuard] Access denied - missing permission: ${permissionCode}`);
|
|
2837
|
+
if (!evaluate(permissionValidator.permissions())) {
|
|
2838
|
+
if (isDevMode()) {
|
|
2839
|
+
console.log(`[${guardName}] ${getDenialMessage()}`);
|
|
2840
|
+
}
|
|
3036
2841
|
return router.createUrlTree([redirectTo]);
|
|
3037
2842
|
}
|
|
3038
2843
|
return true;
|
|
3039
2844
|
};
|
|
3040
2845
|
}
|
|
3041
2846
|
/**
|
|
3042
|
-
*
|
|
2847
|
+
* Permission Guard - Single permission or ILogicNode check.
|
|
3043
2848
|
*
|
|
3044
|
-
*
|
|
2849
|
+
* @example
|
|
2850
|
+
* ```typescript
|
|
2851
|
+
* { path: 'users', canActivate: [permissionGuard('user.view')] }
|
|
2852
|
+
* { path: 'admin', canActivate: [permissionGuard(logicNode, '/access-denied')] }
|
|
2853
|
+
* ```
|
|
2854
|
+
*/
|
|
2855
|
+
function permissionGuard(permission, redirectTo = '/') {
|
|
2856
|
+
const code = typeof permission === 'string' ? permission : 'complex-logic';
|
|
2857
|
+
return createGuard('permissionGuard', redirectTo, (perms) => evaluatePermission(permission, perms), () => `Access denied - missing: ${code}`);
|
|
2858
|
+
}
|
|
2859
|
+
/**
|
|
2860
|
+
* Any Permission Guard (OR logic) - Access if user has ANY permission.
|
|
3045
2861
|
*
|
|
3046
2862
|
* @example
|
|
3047
2863
|
* ```typescript
|
|
3048
|
-
* // Allow if user has view OR create permission
|
|
3049
2864
|
* { path: 'users', canActivate: [anyPermissionGuard(['user.view', 'user.create'])] }
|
|
3050
2865
|
* ```
|
|
3051
2866
|
*/
|
|
3052
2867
|
function anyPermissionGuard(permissions, redirectTo = '/') {
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
if (!permissionValidator.isPermissionsLoaded()) {
|
|
3063
|
-
devLog('[anyPermissionGuard] Permissions not loaded, denying access to route');
|
|
3064
|
-
return router.createUrlTree([redirectTo]);
|
|
3065
|
-
}
|
|
3066
|
-
const userPermissions = permissionValidator.permissions();
|
|
3067
|
-
const hasPermission = hasAnyPermission(permissions, userPermissions);
|
|
3068
|
-
if (!hasPermission) {
|
|
3069
|
-
devLog(`[anyPermissionGuard] Access denied - missing any of: ${permissions.join(', ')}`);
|
|
3070
|
-
return router.createUrlTree([redirectTo]);
|
|
3071
|
-
}
|
|
3072
|
-
return true;
|
|
3073
|
-
};
|
|
2868
|
+
if (!permissions?.length) {
|
|
2869
|
+
return () => {
|
|
2870
|
+
if (isDevMode()) {
|
|
2871
|
+
console.log('[anyPermissionGuard] Empty permissions array, denying');
|
|
2872
|
+
}
|
|
2873
|
+
return inject(Router).createUrlTree([redirectTo]);
|
|
2874
|
+
};
|
|
2875
|
+
}
|
|
2876
|
+
return createGuard('anyPermissionGuard', redirectTo, (perms) => hasAnyPermission(permissions, perms), () => `Access denied - missing any of: ${permissions.join(', ')}`);
|
|
3074
2877
|
}
|
|
3075
2878
|
/**
|
|
3076
|
-
* All Permissions Guard (AND logic)
|
|
3077
|
-
*
|
|
3078
|
-
* Allows access only if user has ALL of the specified permissions.
|
|
2879
|
+
* All Permissions Guard (AND logic) - Access only if user has ALL permissions.
|
|
3079
2880
|
*
|
|
3080
2881
|
* @example
|
|
3081
2882
|
* ```typescript
|
|
3082
|
-
* // Allow only if user has BOTH view AND create permissions
|
|
3083
2883
|
* { path: 'admin', canActivate: [allPermissionsGuard(['admin.view', 'admin.manage'])] }
|
|
3084
2884
|
* ```
|
|
3085
2885
|
*/
|
|
3086
2886
|
function allPermissionsGuard(permissions, redirectTo = '/') {
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
if (!permissionValidator.isPermissionsLoaded()) {
|
|
3097
|
-
devLog('[allPermissionsGuard] Permissions not loaded, denying access to route');
|
|
3098
|
-
return router.createUrlTree([redirectTo]);
|
|
3099
|
-
}
|
|
3100
|
-
const userPermissions = permissionValidator.permissions();
|
|
3101
|
-
const hasPermission = hasAllPermissions(permissions, userPermissions);
|
|
3102
|
-
if (!hasPermission) {
|
|
3103
|
-
devLog(`[allPermissionsGuard] Access denied - missing all of: ${permissions.join(', ')}`);
|
|
3104
|
-
return router.createUrlTree([redirectTo]);
|
|
3105
|
-
}
|
|
3106
|
-
return true;
|
|
3107
|
-
};
|
|
2887
|
+
if (!permissions?.length) {
|
|
2888
|
+
return () => {
|
|
2889
|
+
if (isDevMode()) {
|
|
2890
|
+
console.log('[allPermissionsGuard] Empty permissions array, denying');
|
|
2891
|
+
}
|
|
2892
|
+
return inject(Router).createUrlTree([redirectTo]);
|
|
2893
|
+
};
|
|
2894
|
+
}
|
|
2895
|
+
return createGuard('allPermissionsGuard', redirectTo, (perms) => hasAllPermissions(permissions, perms), () => `Access denied - missing all of: ${permissions.join(', ')}`);
|
|
3108
2896
|
}
|
|
3109
2897
|
|
|
3110
2898
|
/**
|
|
@@ -3464,5 +3252,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
3464
3252
|
* Generated bundle index. Do not edit.
|
|
3465
3253
|
*/
|
|
3466
3254
|
|
|
3467
|
-
export { ACTION_PERMISSIONS, AUTH_STATE_PROVIDER, AngularModule, ApiResourceService, ApiResourceService as ApiService, BRANCH_PERMISSIONS, BaseFormControl, BaseFormPage, BaseListPage, COMPANY_ACTION_PERMISSIONS, COMPANY_API_PROVIDER, COMPANY_PERMISSIONS, ContactTypeEnum, CookieService, EMAIL_CONFIG_PERMISSIONS, EMAIL_TEMPLATE_PERMISSIONS, EditModeElementChangerDirective, FILE_PERMISSIONS, FILE_TYPE_FILTERS, FOLDER_PERMISSIONS, FORM_PERMISSIONS, FileSelectorDialogComponent, FileUploaderComponent, FileUrlService, HasPermissionDirective, IconComponent, IconTypeEnum, IsEmptyImageDirective, LazyMultiSelectComponent, LazySelectComponent, PERMISSIONS, PROFILE_PERMISSION_PROVIDER, PROFILE_UPLOAD_PROVIDER, PermissionValidatorService, PlatformService, PreventDefaultDirective, PrimeModule, ROLE_ACTION_PERMISSIONS, ROLE_PERMISSIONS, STORAGE_CONFIG_PERMISSIONS, USER_ACTION_PERMISSIONS, USER_LIST_PROVIDER, USER_PERMISSIONS, USER_PERMISSION_PROVIDER, USER_PROVIDER, USER_ROLE_PERMISSIONS, UserMultiSelectComponent, UserSelectComponent, allPermissionsGuard, anyPermissionGuard, evaluateLogicNode, evaluatePermission, formatFileSize, getAcceptString, getFileIconClass, hasAllPermissions, hasAnyPermission, hasPermission, isFileTypeAllowed, permissionGuard, provideValueAccessor };
|
|
3255
|
+
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, EditModeElementChangerDirective, FILE_PERMISSIONS, FILE_TYPE_FILTERS, FOLDER_PERMISSIONS, FORM_PERMISSIONS, FileSelectorDialogComponent, FileUploaderComponent, FileUrlService, HasPermissionDirective, IconComponent, IconTypeEnum, IsEmptyImageDirective, LazyMultiSelectComponent, LazySelectComponent, PERMISSIONS, PROFILE_PERMISSION_PROVIDER, PROFILE_UPLOAD_PROVIDER, PermissionValidatorService, PlatformService, PreventDefaultDirective, PrimeModule, ROLE_ACTION_PERMISSIONS, ROLE_PERMISSIONS, STORAGE_CONFIG_PERMISSIONS, 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, provideValueAccessor };
|
|
3468
3256
|
//# sourceMappingURL=flusys-ng-shared.mjs.map
|