@flusys/ng-auth 0.1.0-beta.3 → 1.0.0-rc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +360 -19
- package/fesm2022/flusys-ng-auth.mjs +2832 -880
- package/fesm2022/flusys-ng-auth.mjs.map +1 -1
- package/package.json +5 -5
- package/types/flusys-ng-auth.d.ts +351 -78
package/README.md
CHANGED
|
@@ -393,41 +393,106 @@ getCompanyBranches(companyId); // User's permitted branches
|
|
|
393
393
|
|
|
394
394
|
## Pages
|
|
395
395
|
|
|
396
|
+
All page components follow Angular 21 best practices:
|
|
397
|
+
- `ChangeDetectionStrategy.OnPush` for optimal performance
|
|
398
|
+
- Signal Forms (`@angular/forms/signals`) with validation
|
|
399
|
+
- 100% responsive design (mobile-first with Tailwind)
|
|
400
|
+
- Dark mode compatible (PrimeNG + Tailwind CSS variables)
|
|
401
|
+
- `inject()` for dependency injection
|
|
402
|
+
|
|
396
403
|
### Authentication Pages
|
|
397
404
|
|
|
398
405
|
**LoginPageComponent** (`/auth/login`)
|
|
399
406
|
- Multi-step login: Step 1 = credentials, Step 2 = company/branch selection (if needed)
|
|
400
|
-
- Visual step indicator
|
|
407
|
+
- Visual step indicator (when company feature enabled)
|
|
408
|
+
- Email verification step (when email not verified)
|
|
401
409
|
- Auto-selects if only one company/branch available
|
|
402
410
|
- Stores returnUrl for post-login redirect
|
|
411
|
+
- Responsive form layout with mobile padding
|
|
403
412
|
|
|
404
413
|
**RegisterPageComponent** (`/auth/register`)
|
|
405
414
|
- User registration with optional company creation
|
|
406
|
-
-
|
|
407
|
-
-
|
|
415
|
+
- Two-column responsive grid layout
|
|
416
|
+
- Email/password validation with signal forms
|
|
417
|
+
- Company details section (when company feature enabled)
|
|
418
|
+
|
|
419
|
+
**ForgotPasswordPageComponent** (`/auth/forgot-password`)
|
|
420
|
+
- Email input with validation
|
|
421
|
+
- Success state showing email sent confirmation
|
|
422
|
+
|
|
423
|
+
**ResetPasswordPageComponent** (`/auth/reset-password`)
|
|
424
|
+
- Password reset with token validation
|
|
425
|
+
- Password confirmation matching
|
|
426
|
+
- Success/invalid token states
|
|
427
|
+
|
|
428
|
+
**VerifyEmailPageComponent** (`/auth/verify-email`)
|
|
429
|
+
- Token verification with SSR support (TransferState)
|
|
430
|
+
- Resend verification option
|
|
431
|
+
- Success/failure states
|
|
432
|
+
|
|
433
|
+
### Profile Page
|
|
434
|
+
|
|
435
|
+
**ProfilePageComponent** (`/profile`)
|
|
436
|
+
- Page title with description
|
|
437
|
+
- Avatar section with initials fallback
|
|
438
|
+
- Update name and phone
|
|
439
|
+
- Upload profile picture (requires `PROFILE_UPLOAD_PROVIDER` from ng-storage)
|
|
440
|
+
- Change password section with strength indicator
|
|
441
|
+
- View company/branch info (if company feature enabled)
|
|
442
|
+
- View roles/actions (requires `PROFILE_PERMISSION_PROVIDER` from ng-iam)
|
|
443
|
+
- Responsive two-column layout on desktop
|
|
444
|
+
|
|
445
|
+
**Optional Provider Dependencies:**
|
|
446
|
+
|
|
447
|
+
| Provider | Source | Feature Enabled |
|
|
448
|
+
|----------|--------|-----------------|
|
|
449
|
+
| `PROFILE_UPLOAD_PROVIDER` | ng-storage via `provideStorageProviders()` | Profile picture upload |
|
|
450
|
+
| `PROFILE_PERMISSION_PROVIDER` | ng-iam via `provideIamProviders()` | Roles/actions display |
|
|
451
|
+
|
|
452
|
+
**Graceful Degradation:**
|
|
453
|
+
- If provider not registered, feature shows "not enabled" message
|
|
454
|
+
- If service disabled in config, section is hidden
|
|
455
|
+
- No errors thrown for missing optional providers
|
|
408
456
|
|
|
409
457
|
### Administration Pages
|
|
410
458
|
|
|
411
459
|
**AdministrationPageComponent** (`/administration`)
|
|
412
|
-
-
|
|
413
|
-
-
|
|
460
|
+
- Page title "Administration" with dynamic subtitle
|
|
461
|
+
- Horizontal scrolling tabs (hidden scrollbar on mobile)
|
|
462
|
+
- Tabs: Users, Companies, Branches
|
|
463
|
+
- Company/Branch tabs only visible when company feature enabled
|
|
414
464
|
|
|
415
465
|
**User Management:**
|
|
416
466
|
- `UserListComponent` - LazyLoad datatable with Edit, Delete, Permission actions
|
|
417
|
-
- `UserFormComponent` - Create/edit user
|
|
467
|
+
- `UserFormComponent` - Create/edit user with auto company/branch assignment
|
|
468
|
+
- Permission dialogs for company/branch assignments
|
|
418
469
|
|
|
419
470
|
**Company Management:**
|
|
420
|
-
- `CompanyListComponent` - Company CRUD
|
|
421
|
-
- `CompanyFormComponent` - Create/edit company
|
|
471
|
+
- `CompanyListComponent` - Company CRUD with View Branches action
|
|
472
|
+
- `CompanyFormComponent` - Create/edit company with auto slug generation
|
|
422
473
|
|
|
423
474
|
**Branch Management:**
|
|
424
|
-
- `BranchListComponent` - Branch CRUD filtered by company
|
|
425
|
-
- `BranchFormComponent` - Create/edit branch
|
|
475
|
+
- `BranchListComponent` - Branch CRUD filtered by company dropdown
|
|
476
|
+
- `BranchFormComponent` - Create/edit branch with company selection
|
|
477
|
+
|
|
478
|
+
**Table Features (all list components):**
|
|
479
|
+
- Responsive header (stacked on mobile)
|
|
480
|
+
- Horizontal scroll wrapper (`overflow-x-auto`)
|
|
481
|
+
- Conditional pagination (`[paginator]="total() > 0"`)
|
|
482
|
+
- Striped rows (`p-datatable-striped`)
|
|
483
|
+
- Lazy loading for performance
|
|
426
484
|
|
|
427
485
|
---
|
|
428
486
|
|
|
429
487
|
## Dialog Components
|
|
430
488
|
|
|
489
|
+
Both dialog components use Angular 21 patterns:
|
|
490
|
+
- `ChangeDetectionStrategy.OnPush`
|
|
491
|
+
- `input.required<T>()` for required inputs
|
|
492
|
+
- `output<void>()` for events
|
|
493
|
+
- `effect()` for reactive data loading
|
|
494
|
+
- Responsive breakpoints (`{ '960px': '90vw', '640px': '95vw' }`)
|
|
495
|
+
|
|
431
496
|
### UserCompanyPermissionDialogComponent
|
|
432
497
|
|
|
433
498
|
Manages user-to-company assignments with checkboxes.
|
|
@@ -447,11 +512,21 @@ import { UserCompanyPermissionDialogComponent } from '@flusys/ng-auth';
|
|
|
447
512
|
})
|
|
448
513
|
```
|
|
449
514
|
|
|
515
|
+
**Inputs/Outputs:**
|
|
516
|
+
```typescript
|
|
517
|
+
readonly visible = input.required<boolean>();
|
|
518
|
+
readonly user = input.required<IUser | null>();
|
|
519
|
+
readonly closed = output<void>();
|
|
520
|
+
readonly permissionsChanged = output<void>();
|
|
521
|
+
```
|
|
522
|
+
|
|
450
523
|
**Features:**
|
|
451
524
|
- Shows all companies with checkboxes
|
|
452
525
|
- Pre-checks assigned companies
|
|
453
526
|
- Immediate save on toggle (no Save button)
|
|
454
527
|
- Toast notifications for success/error
|
|
528
|
+
- Loading spinner during data fetch
|
|
529
|
+
- Disabled checkboxes while saving
|
|
455
530
|
|
|
456
531
|
### UserBranchPermissionDialogComponent
|
|
457
532
|
|
|
@@ -473,13 +548,14 @@ import { UserBranchPermissionDialogComponent } from '@flusys/ng-auth';
|
|
|
473
548
|
```
|
|
474
549
|
|
|
475
550
|
**Features:**
|
|
476
|
-
-
|
|
477
|
-
-
|
|
551
|
+
- Company dropdown shows only user's permitted companies
|
|
552
|
+
- Branch list loads on company selection
|
|
478
553
|
- Immediate save on toggle
|
|
554
|
+
- Contextual empty messages (no permissions vs no branches)
|
|
479
555
|
- Scoped to user's permitted companies
|
|
480
556
|
|
|
481
557
|
**Workflow:**
|
|
482
|
-
1. Dialog opens → Loads user's permitted companies
|
|
558
|
+
1. Dialog opens → Loads user's permitted companies via effect()
|
|
483
559
|
2. User selects company → Loads branches for that company
|
|
484
560
|
3. User toggles branch checkboxes → Immediately assigns/revokes
|
|
485
561
|
|
|
@@ -513,6 +589,21 @@ import { ADMINISTRATION_ROUTES } from '@flusys/ng-auth';
|
|
|
513
589
|
}
|
|
514
590
|
```
|
|
515
591
|
|
|
592
|
+
### PROFILE_ROUTES
|
|
593
|
+
|
|
594
|
+
User profile page routes.
|
|
595
|
+
|
|
596
|
+
```typescript
|
|
597
|
+
import { PROFILE_ROUTES } from '@flusys/ng-auth';
|
|
598
|
+
|
|
599
|
+
// Route: /profile
|
|
600
|
+
{
|
|
601
|
+
path: 'profile',
|
|
602
|
+
canActivate: [authGuard],
|
|
603
|
+
children: PROFILE_ROUTES
|
|
604
|
+
}
|
|
605
|
+
```
|
|
606
|
+
|
|
516
607
|
---
|
|
517
608
|
|
|
518
609
|
## Setup
|
|
@@ -529,6 +620,8 @@ import {
|
|
|
529
620
|
provideAuthLayoutIntegration,
|
|
530
621
|
provideAuthProviders
|
|
531
622
|
} from '@flusys/ng-auth';
|
|
623
|
+
import { provideIamProviders } from '@flusys/ng-iam';
|
|
624
|
+
import { provideStorageProviders } from '@flusys/ng-storage';
|
|
532
625
|
|
|
533
626
|
export const appConfig: ApplicationConfig = {
|
|
534
627
|
providers: [
|
|
@@ -542,7 +635,9 @@ export const appConfig: ApplicationConfig = {
|
|
|
542
635
|
),
|
|
543
636
|
{ provide: APP_CONFIG, useValue: DEFAULT_APP_CONFIG },
|
|
544
637
|
...provideAuthLayoutIntegration(),
|
|
545
|
-
...provideAuthProviders()
|
|
638
|
+
...provideAuthProviders(),
|
|
639
|
+
...provideIamProviders(), // Enables permissions display on profile page
|
|
640
|
+
...provideStorageProviders(), // Enables profile picture upload
|
|
546
641
|
]
|
|
547
642
|
};
|
|
548
643
|
```
|
|
@@ -551,7 +646,7 @@ export const appConfig: ApplicationConfig = {
|
|
|
551
646
|
|
|
552
647
|
```typescript
|
|
553
648
|
import { Routes } from '@angular/router';
|
|
554
|
-
import { authGuard, guestGuard, AUTH_ROUTES, ADMINISTRATION_ROUTES } from '@flusys/ng-auth';
|
|
649
|
+
import { authGuard, guestGuard, AUTH_ROUTES, ADMINISTRATION_ROUTES, PROFILE_ROUTES } from '@flusys/ng-auth';
|
|
555
650
|
|
|
556
651
|
export const routes: Routes = [
|
|
557
652
|
{ path: 'auth', children: AUTH_ROUTES },
|
|
@@ -560,7 +655,8 @@ export const routes: Routes = [
|
|
|
560
655
|
canActivate: [authGuard],
|
|
561
656
|
children: [
|
|
562
657
|
{ path: 'dashboard', loadComponent: () => import('./dashboard.component') },
|
|
563
|
-
{ path: 'administration', children: ADMINISTRATION_ROUTES }
|
|
658
|
+
{ path: 'administration', children: ADMINISTRATION_ROUTES },
|
|
659
|
+
{ path: 'profile', children: PROFILE_ROUTES }
|
|
564
660
|
]
|
|
565
661
|
}
|
|
566
662
|
];
|
|
@@ -665,6 +761,67 @@ interface IUserBranchPermission { id: string; userId: string; branchId: string;
|
|
|
665
761
|
|
|
666
762
|
## Best Practices
|
|
667
763
|
|
|
764
|
+
### Angular 21 Component Patterns
|
|
765
|
+
|
|
766
|
+
All components in ng-auth follow these patterns:
|
|
767
|
+
|
|
768
|
+
```typescript
|
|
769
|
+
@Component({
|
|
770
|
+
selector: 'lib-example',
|
|
771
|
+
standalone: true,
|
|
772
|
+
changeDetection: ChangeDetectionStrategy.OnPush, // Always OnPush
|
|
773
|
+
imports: [AngularModule, PrimeModule, FormField],
|
|
774
|
+
template: `...`
|
|
775
|
+
})
|
|
776
|
+
export class ExampleComponent {
|
|
777
|
+
// Dependency injection via inject()
|
|
778
|
+
private readonly service = inject(MyService);
|
|
779
|
+
|
|
780
|
+
// Signal-based state
|
|
781
|
+
readonly isLoading = signal(false);
|
|
782
|
+
readonly data = signal<IData | null>(null);
|
|
783
|
+
|
|
784
|
+
// Computed signals
|
|
785
|
+
readonly isValid = computed(() => this.data() !== null);
|
|
786
|
+
|
|
787
|
+
// Signal Forms
|
|
788
|
+
readonly formModel = signal<IFormModel>({ name: '', email: '' });
|
|
789
|
+
readonly formTree = form(this.formModel, (f) => {
|
|
790
|
+
required(f.name, { message: 'Name is required' });
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
// Error handling with proper typing
|
|
794
|
+
async onSubmit(): Promise<void> {
|
|
795
|
+
try {
|
|
796
|
+
// ...
|
|
797
|
+
} catch (error: unknown) {
|
|
798
|
+
const err = error as { error?: { message?: string } };
|
|
799
|
+
// Handle error
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
### Responsive Design Patterns
|
|
806
|
+
|
|
807
|
+
```html
|
|
808
|
+
<!-- Responsive container -->
|
|
809
|
+
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 p-4">
|
|
810
|
+
|
|
811
|
+
<!-- Two-column form grid -->
|
|
812
|
+
<form class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
813
|
+
|
|
814
|
+
<!-- Right-aligned buttons -->
|
|
815
|
+
<div class="flex justify-end gap-4 md:col-span-2 pt-4">
|
|
816
|
+
|
|
817
|
+
<!-- Horizontally scrollable tabs -->
|
|
818
|
+
<div class="scrollbar-hide flex gap-1 overflow-x-auto flex-nowrap">
|
|
819
|
+
|
|
820
|
+
<!-- Responsive table wrapper -->
|
|
821
|
+
<div class="overflow-x-auto">
|
|
822
|
+
<p-table [scrollable]="true" [paginator]="total() > 0">
|
|
823
|
+
```
|
|
824
|
+
|
|
668
825
|
### Component Organization
|
|
669
826
|
|
|
670
827
|
```
|
|
@@ -675,7 +832,14 @@ projects/ng-auth/
|
|
|
675
832
|
├── pages/ ← Route-specific pages
|
|
676
833
|
│ ├── login/
|
|
677
834
|
│ ├── register/
|
|
678
|
-
│
|
|
835
|
+
│ ├── forgot-password/
|
|
836
|
+
│ ├── reset-password/
|
|
837
|
+
│ ├── verify-email/
|
|
838
|
+
│ ├── profile/
|
|
839
|
+
│ ├── administration/
|
|
840
|
+
│ ├── users/
|
|
841
|
+
│ ├── company/
|
|
842
|
+
│ └── branch/
|
|
679
843
|
├── services/
|
|
680
844
|
├── guards/
|
|
681
845
|
├── interceptors/
|
|
@@ -704,6 +868,27 @@ const allCompanies = await companyApi.fetchList(); // Security risk
|
|
|
704
868
|
- TokenRefreshInterceptor handles automatic refresh
|
|
705
869
|
- Auto-persistence for company/branch selection
|
|
706
870
|
|
|
871
|
+
### Type Safety
|
|
872
|
+
|
|
873
|
+
Avoid `any` types - use explicit interfaces:
|
|
874
|
+
|
|
875
|
+
```typescript
|
|
876
|
+
// ✅ CORRECT - Explicit response type
|
|
877
|
+
.subscribe({
|
|
878
|
+
next: (result: { message?: string }) => {
|
|
879
|
+
this.messageService.add({
|
|
880
|
+
severity: 'success',
|
|
881
|
+
detail: result.message,
|
|
882
|
+
});
|
|
883
|
+
},
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
// ❌ WRONG - Using any
|
|
887
|
+
.subscribe({
|
|
888
|
+
next: (result: any) => { ... },
|
|
889
|
+
});
|
|
890
|
+
```
|
|
891
|
+
|
|
707
892
|
### Multi-Company Flow
|
|
708
893
|
|
|
709
894
|
1. Login → Check if `requiresSelection: true`
|
|
@@ -760,6 +945,143 @@ providers: [
|
|
|
760
945
|
|
|
761
946
|
---
|
|
762
947
|
|
|
948
|
+
## No-IAM Mode (Bypassing Permission Guards)
|
|
949
|
+
|
|
950
|
+
When you don't use the `@flusys/ng-iam` module but your routes use `permissionGuard`, the guard will fail because no permissions are loaded.
|
|
951
|
+
|
|
952
|
+
**Solution:** Set wildcard permissions in `PermissionValidatorService` after login.
|
|
953
|
+
|
|
954
|
+
### How Permission Guard Works
|
|
955
|
+
|
|
956
|
+
```
|
|
957
|
+
Route with permissionGuard('user.view')
|
|
958
|
+
↓
|
|
959
|
+
permissionGuard() → inject(PermissionValidatorService)
|
|
960
|
+
↓
|
|
961
|
+
permissionValidator.isPermissionsLoaded() → false
|
|
962
|
+
↓
|
|
963
|
+
Redirect to '/' ❌
|
|
964
|
+
```
|
|
965
|
+
|
|
966
|
+
### Fix: Set Wildcard Permissions After Login
|
|
967
|
+
|
|
968
|
+
#### Option 1: In Login Flow (Recommended)
|
|
969
|
+
|
|
970
|
+
Update your login handling to set permissions after successful authentication:
|
|
971
|
+
|
|
972
|
+
```typescript
|
|
973
|
+
// login.component.ts or auth.service.ts
|
|
974
|
+
import { PermissionValidatorService } from '@flusys/ng-shared';
|
|
975
|
+
|
|
976
|
+
@Component({ ... })
|
|
977
|
+
export class LoginComponent {
|
|
978
|
+
private readonly permissionValidator = inject(PermissionValidatorService);
|
|
979
|
+
private readonly authApi = inject(AuthApiService);
|
|
980
|
+
private readonly authState = inject(AuthStateService);
|
|
981
|
+
|
|
982
|
+
async onLogin(): Promise<void> {
|
|
983
|
+
const response = await firstValueFrom(this.authApi.login(credentials));
|
|
984
|
+
this.authState.setLoginState(response);
|
|
985
|
+
|
|
986
|
+
// When IAM is NOT used, grant all permissions via wildcard
|
|
987
|
+
this.permissionValidator.setPermissions(['*']);
|
|
988
|
+
|
|
989
|
+
// Navigate to dashboard
|
|
990
|
+
this.router.navigate(['/dashboard']);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
#### Option 2: In APP_INITIALIZER
|
|
996
|
+
|
|
997
|
+
Set permissions at app startup:
|
|
998
|
+
|
|
999
|
+
```typescript
|
|
1000
|
+
// app.config.ts
|
|
1001
|
+
import { APP_INITIALIZER } from '@angular/core';
|
|
1002
|
+
import { PermissionValidatorService } from '@flusys/ng-shared';
|
|
1003
|
+
|
|
1004
|
+
export const appConfig: ApplicationConfig = {
|
|
1005
|
+
providers: [
|
|
1006
|
+
{
|
|
1007
|
+
provide: APP_INITIALIZER,
|
|
1008
|
+
useFactory: (permissionValidator: PermissionValidatorService) => {
|
|
1009
|
+
return () => {
|
|
1010
|
+
// Set wildcard permissions when IAM is disabled
|
|
1011
|
+
permissionValidator.setPermissions(['*']);
|
|
1012
|
+
};
|
|
1013
|
+
},
|
|
1014
|
+
deps: [PermissionValidatorService],
|
|
1015
|
+
multi: true,
|
|
1016
|
+
},
|
|
1017
|
+
// ... other providers
|
|
1018
|
+
],
|
|
1019
|
+
};
|
|
1020
|
+
```
|
|
1021
|
+
|
|
1022
|
+
#### Option 3: In AuthInitService (After Session Restore)
|
|
1023
|
+
|
|
1024
|
+
If you restore sessions on page refresh, set permissions there:
|
|
1025
|
+
|
|
1026
|
+
```typescript
|
|
1027
|
+
// After successful /auth/me response
|
|
1028
|
+
authInit.initialize().subscribe({
|
|
1029
|
+
next: (user) => {
|
|
1030
|
+
// Session restored, set wildcard permissions
|
|
1031
|
+
permissionValidator.setPermissions(['*']);
|
|
1032
|
+
},
|
|
1033
|
+
});
|
|
1034
|
+
```
|
|
1035
|
+
|
|
1036
|
+
### Wildcard Permission Syntax
|
|
1037
|
+
|
|
1038
|
+
The `permissionGuard` utilities support these patterns:
|
|
1039
|
+
|
|
1040
|
+
| Pattern | Meaning |
|
|
1041
|
+
|---------|---------|
|
|
1042
|
+
| `*` | Full access to everything |
|
|
1043
|
+
| `user.*` | All user permissions |
|
|
1044
|
+
| `branch.*` | All branch permissions |
|
|
1045
|
+
|
|
1046
|
+
### For Jest Tests
|
|
1047
|
+
|
|
1048
|
+
Mock `PermissionValidatorService` in your test setup:
|
|
1049
|
+
|
|
1050
|
+
```typescript
|
|
1051
|
+
import { PermissionValidatorService } from '@flusys/ng-shared';
|
|
1052
|
+
|
|
1053
|
+
describe('MyComponent', () => {
|
|
1054
|
+
beforeEach(async () => {
|
|
1055
|
+
await TestBed.configureTestingModule({
|
|
1056
|
+
imports: [MyComponent],
|
|
1057
|
+
providers: [
|
|
1058
|
+
{
|
|
1059
|
+
provide: PermissionValidatorService,
|
|
1060
|
+
useValue: {
|
|
1061
|
+
permissions: () => ['*'],
|
|
1062
|
+
isPermissionsLoaded: () => true,
|
|
1063
|
+
hasPermission: () => true,
|
|
1064
|
+
setPermissions: jest.fn(),
|
|
1065
|
+
clearPermissions: jest.fn(),
|
|
1066
|
+
},
|
|
1067
|
+
},
|
|
1068
|
+
],
|
|
1069
|
+
}).compileComponents();
|
|
1070
|
+
});
|
|
1071
|
+
});
|
|
1072
|
+
```
|
|
1073
|
+
|
|
1074
|
+
### For Template Permission Checks
|
|
1075
|
+
|
|
1076
|
+
If using `*hasPermission` directive, it will also respect wildcard:
|
|
1077
|
+
|
|
1078
|
+
```html
|
|
1079
|
+
<!-- This will show when permissions include '*' -->
|
|
1080
|
+
<button *hasPermission="'user.delete'">Delete User</button>
|
|
1081
|
+
```
|
|
1082
|
+
|
|
1083
|
+
---
|
|
1084
|
+
|
|
763
1085
|
## See Also
|
|
764
1086
|
|
|
765
1087
|
- [CORE-GUIDE.md](./CORE-GUIDE.md) - APP_CONFIG configuration
|
|
@@ -770,6 +1092,25 @@ providers: [
|
|
|
770
1092
|
|
|
771
1093
|
---
|
|
772
1094
|
|
|
773
|
-
**Last Updated:** 2026-02-
|
|
774
|
-
**Package Version:** 1.0.1
|
|
1095
|
+
**Last Updated:** 2026-02-19
|
|
775
1096
|
**Angular Version:** 21
|
|
1097
|
+
|
|
1098
|
+
## Component Checklist
|
|
1099
|
+
|
|
1100
|
+
| Component | OnPush | Signal Forms | Responsive | Dark Mode |
|
|
1101
|
+
|-----------|--------|--------------|------------|-----------|
|
|
1102
|
+
| LoginPageComponent | ✅ | ✅ | ✅ | ✅ |
|
|
1103
|
+
| RegisterPageComponent | ✅ | ✅ | ✅ | ✅ |
|
|
1104
|
+
| ForgotPasswordPageComponent | ✅ | ✅ | ✅ | ✅ |
|
|
1105
|
+
| ResetPasswordPageComponent | ✅ | ✅ | ✅ | ✅ |
|
|
1106
|
+
| VerifyEmailPageComponent | ✅ | ✅ | ✅ | ✅ |
|
|
1107
|
+
| ProfilePageComponent | ✅ | ✅ | ✅ | ✅ |
|
|
1108
|
+
| AdministrationPageComponent | ✅ | N/A | ✅ | ✅ |
|
|
1109
|
+
| UserListComponent | ✅ | N/A | ✅ | ✅ |
|
|
1110
|
+
| UserFormComponent | ✅ | ✅ | ✅ | ✅ |
|
|
1111
|
+
| CompanyListComponent | ✅ | N/A | ✅ | ✅ |
|
|
1112
|
+
| CompanyFormComponent | ✅ | ✅ | ✅ | ✅ |
|
|
1113
|
+
| BranchListComponent | ✅ | N/A | ✅ | ✅ |
|
|
1114
|
+
| BranchFormComponent | ✅ | ✅ | ✅ | ✅ |
|
|
1115
|
+
| UserCompanyPermissionDialogComponent | ✅ | N/A | ✅ | ✅ |
|
|
1116
|
+
| UserBranchPermissionDialogComponent | ✅ | N/A | ✅ | ✅ |
|