Skip to content

Commit c59db2f

Browse files
authored
Merge pull request #24689 from abpframework/issue-24684
Angular Aria Implementation for ABP Packages - Issue 24684
2 parents 0c01d07 + f6fdf98 commit c59db2f

File tree

10 files changed

+176
-117
lines changed

10 files changed

+176
-117
lines changed

npm/ng-packs/packages/feature-management/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
"@abp/ng.theme.shared": "~10.1.0-rc.2",
1111
"tslib": "^2.0.0"
1212
},
13+
"peerDependencies": {
14+
"@angular/aria": "~21.0.0"
15+
},
1316
"publishConfig": {
1417
"access": "public"
1518
}

npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.html

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,26 @@ <h3>
1212
<ng-template #abpBody>
1313
<div class="row">
1414
@if (groups.length) {
15-
<div class="col-md-4">
16-
<ul
17-
ngbNav
18-
#nav="ngbNav"
19-
[(activeId)]="selectedGroupDisplayName"
20-
class="nav-pills"
21-
orientation="vertical"
22-
>
15+
<div ngTabs orientation="vertical" class="row">
16+
<div class="col-md-4">
17+
<div ngTabList orientation="vertical" selectionMode="follow" [(selectedTab)]="selectedGroupDisplayName" class="nav nav-pills flex-column">
18+
@for (group of groups; track group.name) {
19+
<button ngTab #tab="ngTab" type="button" [value]="group.displayName" class="nav-link text-start" [class.active]="tab.selected()">
20+
{{ group.displayName }}
21+
</button>
22+
}
23+
</div>
24+
</div>
25+
<ng-template #descTmp let-description>
26+
@if (description) {
27+
<small class="d-block form-text text-muted">{{ description }}</small>
28+
}
29+
</ng-template>
30+
31+
<div class="col-md-8">
2332
@for (group of groups; track group.name) {
24-
<li [ngbNavItem]="group.displayName">
25-
<a ngbNavLink>{{ group.displayName }}</a>
26-
<ng-template ngbNavContent>
33+
<div ngTabPanel [value]="group.displayName">
34+
<ng-template ngTabContent>
2735
<h4>{{ selectedGroupDisplayName }}</h4>
2836
<hr class="mt-2 mb-3" />
2937

@@ -128,18 +136,10 @@ <h4>{{ selectedGroupDisplayName }}</h4>
128136
</div>
129137
}
130138
</ng-template>
131-
</li>
139+
</div>
132140
}
133-
</ul>
141+
</div>
134142
</div>
135-
136-
<ng-template #descTmp let-description>
137-
@if (description) {
138-
<small class="d-block form-text text-muted">{{ description }}</small>
139-
}
140-
</ng-template>
141-
142-
<div class="col-md-8"><div class="py-0" [ngbNavOutlet]="nav"></div></div>
143143
}
144144

145145
@if (!groups.length) {

npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Component, EventEmitter, Input, Output, inject, DOCUMENT } from '@angular/core';
2-
import { NgTemplateOutlet } from '@angular/common';
2+
import { NgTemplateOutlet, NgStyle } from '@angular/common';
33
import { FormsModule } from '@angular/forms';
44
import { ConfigStateService, LocalizationPipe, TrackByService } from '@abp/ng.core';
55
import {
@@ -17,7 +17,7 @@ import {
1717
ModalComponent,
1818
ToasterService,
1919
} from '@abp/ng.theme.shared';
20-
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
20+
import { Tabs, TabList, Tab, TabPanel, TabContent } from '@angular/aria/tabs';
2121
import { finalize } from 'rxjs/operators';
2222
import { FreeTextInputDirective } from '../../directives';
2323
import { FeatureManagement } from '../../models';
@@ -36,11 +36,16 @@ const DEFAULT_PROVIDER_NAME = 'D';
3636
exportAs: 'abpFeatureManagement',
3737
imports: [
3838
NgTemplateOutlet,
39+
NgStyle,
3940
ButtonComponent,
4041
ModalComponent,
4142
LocalizationPipe,
4243
FormsModule,
43-
NgbNavModule,
44+
Tabs,
45+
TabList,
46+
Tab,
47+
TabPanel,
48+
TabContent,
4449
FreeTextInputDirective,
4550
ModalCloseDirective,
4651
],

npm/ng-packs/packages/identity/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
"@abp/ng.theme.shared": "~10.1.0-rc.2",
1313
"tslib": "^2.0.0"
1414
},
15+
"peerDependencies": {
16+
"@angular/aria": "~21.0.0"
17+
},
1518
"publishConfig": {
1619
"access": "public"
1720
}

npm/ng-packs/packages/identity/src/lib/components/users/users.component.html

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,39 +28,47 @@ <h3>{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewUser') | abpLocali
2828
<ng-template #abpBody>
2929
@if (form) {
3030
<form [formGroup]="form" (ngSubmit)="save()">
31-
<ul ngbNav #nav="ngbNav" class="nav-tabs">
32-
<li ngbNavItem>
33-
<a ngbNavLink>{{ 'AbpIdentity::UserInformations' | abpLocalization }}</a>
34-
<ng-template ngbNavContent>
35-
<abp-extensible-form [selectedRecord]="selected"></abp-extensible-form>
36-
</ng-template>
37-
</li>
31+
<div ngTabs selectionMode="follow">
32+
<div ngTabList [(selectedTab)]="selectedTab" class="nav nav-tabs">
33+
<button ngTab #tabInfo="ngTab" [value]="'user-info'" class="nav-link" [class.active]="tabInfo.selected()" type="button">
34+
{{ 'AbpIdentity::UserInformations' | abpLocalization }}
35+
</button>
36+
<button ngTab #tabRoles="ngTab" [value]="'roles'" class="nav-link" [class.active]="tabRoles.selected()" type="button">
37+
{{ 'AbpIdentity::Roles' | abpLocalization }}
38+
</button>
39+
</div>
3840

39-
<li ngbNavItem>
40-
<a ngbNavLink>{{ 'AbpIdentity::Roles' | abpLocalization }}</a>
41-
<ng-template ngbNavContent>
42-
@for (roleGroup of roleGroups; track $index; let i = $index) {
43-
<div class="form-check mb-2">
44-
<abp-checkbox
45-
*abpReplaceableTemplate="{
46-
inputs: {
47-
checkboxId: 'roles-' + i,
48-
label: roles[i].name,
49-
formControl: roleGroup.controls[roles[i].name]
50-
},
51-
componentKey: inputKey
52-
}"
53-
[checkboxId]="'roles-' + i"
54-
[formControl]="roleGroup.controls[roles[i].name]"
55-
[label]="roles[i].name"
56-
>
57-
</abp-checkbox>
58-
</div>
59-
}
60-
</ng-template>
61-
</li>
62-
</ul>
63-
<div class="mt-2 fade-in-top" [ngbNavOutlet]="nav"></div>
41+
<div class="mt-2 fade-in-top">
42+
<div ngTabPanel [value]="'user-info'">
43+
<ng-template ngTabContent>
44+
<abp-extensible-form [selectedRecord]="selected"></abp-extensible-form>
45+
</ng-template>
46+
</div>
47+
48+
<div ngTabPanel [value]="'roles'">
49+
<ng-template ngTabContent>
50+
@for (roleGroup of roleGroups; track $index; let i = $index) {
51+
<div class="form-check mb-2">
52+
<abp-checkbox
53+
*abpReplaceableTemplate="{
54+
inputs: {
55+
checkboxId: 'roles-' + i,
56+
label: roles[i].name,
57+
formControl: roleGroup.controls[roles[i].name]
58+
},
59+
componentKey: inputKey
60+
}"
61+
[checkboxId]="'roles-' + i"
62+
[formControl]="roleGroup.controls[roles[i].name]"
63+
[label]="roles[i].name"
64+
>
65+
</abp-checkbox>
66+
</div>
67+
}
68+
</ng-template>
69+
</div>
70+
</div>
71+
</div>
6472
</form>
6573
} @else {
6674
<div class="text-center"><i class="fa fa-pulse fa-spinner" aria-hidden="true"></i></div>

npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ import {
5252
import { finalize, switchMap, tap } from 'rxjs/operators';
5353
import { eIdentityComponents } from '../../enums/components';
5454
import { PageComponent } from '@abp/ng.components/page';
55-
import { NgbDropdownModule, NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
55+
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
56+
import { Tabs, TabList, Tab, TabPanel, TabContent } from '@angular/aria/tabs';
5657
import { NgxValidateCoreModule } from '@ngx-validate/core';
5758

5859
@Component({
@@ -70,7 +71,11 @@ import { NgxValidateCoreModule } from '@ngx-validate/core';
7071
FormsModule,
7172
PermissionManagementComponent,
7273
PageComponent,
73-
NgbNavModule,
74+
Tabs,
75+
TabList,
76+
Tab,
77+
TabPanel,
78+
TabContent,
7479
NgbDropdownModule,
7580
NgxValidateCoreModule,
7681
LocalizationPipe,
@@ -101,6 +106,8 @@ export class UsersComponent implements OnInit {
101106

102107
selected?: IdentityUserDto;
103108

109+
selectedTab = 'user-info';
110+
104111
selectedUserRoles?: IdentityRoleDto[];
105112

106113
roles?: IdentityRoleDto[];
@@ -159,6 +166,7 @@ export class UsersComponent implements OnInit {
159166
}
160167

161168
openModal() {
169+
this.selectedTab = 'user-info';
162170
this.buildForm();
163171
this.isModalVisible = true;
164172
}

npm/ng-packs/packages/permission-management/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
"@abp/ng.theme.shared": "~10.1.0-rc.2",
1111
"tslib": "^2.0.0"
1212
},
13+
"peerDependencies": {
14+
"@angular/aria": "~21.0.0"
15+
},
1316
"publishConfig": {
1417
"access": "public"
1518
},

npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.html

Lines changed: 69 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -43,78 +43,93 @@ <h4>
4343
<legend class="px-1 h5 mb-0">
4444
{{ 'AbpPermissionManagement::PermissionGroup' | abpLocalization }}
4545
</legend>
46-
<div class="row">
46+
<div class="row" ngTabs orientation="vertical">
4747
<div class="col-md-4">
48-
<div class="overflow-auto lpx-scroll-pills-container scroll-in-modal">
49-
<ul class="nav nav-pills flex-column">
48+
<div
49+
class="overflow-auto lpx-scroll-pills-container scroll-in-modal"
50+
ngTabList
51+
orientation="vertical"
52+
selectionMode="follow"
53+
[selectedTab]="selectedGroup?.name"
54+
(selectedTabChange)="onTabChange($event)"
55+
>
56+
<div class="nav nav-pills flex-column">
5057
@for (group of permissionGroups(); track $index) {
51-
<li class="border nav-item">
58+
<div class="border nav-item">
5259
@if ({ assignedCount: getAssignedCount(group.name) }; as count) {
53-
<a
54-
class="nav-link pointer"
55-
[class.active]="selectedGroup?.name === group?.name"
56-
(click)="onChangeGroup(group)"
57-
(select)="setDisabled(group.permissions)"
60+
<button
61+
ngTab
62+
[value]="group.name"
63+
class="nav-link pointer text-start w-100"
64+
#tab="ngTab"
65+
[class.active]="tab.selected()"
66+
type="button"
5867
>
5968
<div [class.font-weight-bold]="count.assignedCount">
6069
{{ group?.displayName }}
6170
@if (count.assignedCount > 0) {
6271
<span>({{ count.assignedCount }})</span>
6372
}
6473
</div>
65-
</a>
74+
</button>
6675
}
67-
</li>
76+
</div>
6877
}
69-
</ul>
78+
</div>
7079
</div>
7180
</div>
7281

7382
<div class="col-md-8 scroll-in-modal">
74-
<div class="ps-1">
75-
@if (selectedGroupPermissions.length) {
76-
<div class="form-check mb-2">
77-
<input
78-
#selectAllInThisTabsRef
79-
type="checkbox"
80-
id="select-all-in-this-tabs"
81-
name="select-all-in-this-tabs"
82-
class="form-check-input"
83-
[(ngModel)]="selectThisTab"
84-
[disabled]="disableSelectAllTab"
85-
(click)="onClickSelectThisTab()"
86-
/>
87-
<label class="form-check-label" for="select-all-in-this-tabs">{{
88-
'AbpPermissionManagement::SelectAllInThisTab' | abpLocalization
89-
}}</label>
90-
</div>
91-
<hr class="my-2" />
92-
@for (permission of selectedGroupPermissions; track $index; let i = $index) {
93-
<div [ngStyle]="permission.style" class="form-check mb-2">
94-
<input
95-
#permissionCheckbox
96-
type="checkbox"
97-
[checked]="getChecked(permission.name)"
98-
[value]="getChecked(permission.name)"
99-
[attr.id]="permission.name"
100-
class="form-check-input"
101-
[disabled]="isGrantedByOtherProviderName(permission.grantedProviders)"
102-
(click)="onClickCheckbox(permission, permissionCheckbox.value)"
103-
/>
104-
<label class="form-check-label" [attr.for]="permission.name"
105-
>{{ permission.displayName }}
106-
@if (!hideBadges) {
107-
@for (provider of permission.grantedProviders; track $index) {
108-
<span class="badge bg-primary text-dark"
109-
>{{ provider.providerName }}: {{ provider.providerKey }}</span
110-
>
111-
}
83+
@for (group of permissionGroups(); track $index) {
84+
<div ngTabPanel [value]="group.name">
85+
<ng-template ngTabContent>
86+
<div class="ps-1">
87+
@if (selectedGroupPermissions.length) {
88+
<div class="form-check mb-2">
89+
<input
90+
#selectAllInThisTabsRef
91+
type="checkbox"
92+
id="select-all-in-this-tabs"
93+
name="select-all-in-this-tabs"
94+
class="form-check-input"
95+
[(ngModel)]="selectThisTab"
96+
[disabled]="disableSelectAllTab"
97+
(click)="onClickSelectThisTab()"
98+
/>
99+
<label class="form-check-label" for="select-all-in-this-tabs">{{
100+
'AbpPermissionManagement::SelectAllInThisTab' | abpLocalization
101+
}}</label>
102+
</div>
103+
<hr class="my-2" />
104+
@for (permission of selectedGroupPermissions; track $index; let i = $index) {
105+
<div [ngStyle]="permission.style" class="form-check mb-2">
106+
<input
107+
#permissionCheckbox
108+
type="checkbox"
109+
[checked]="getChecked(permission.name)"
110+
[value]="getChecked(permission.name)"
111+
[attr.id]="permission.name"
112+
class="form-check-input"
113+
[disabled]="isGrantedByOtherProviderName(permission.grantedProviders)"
114+
(click)="onClickCheckbox(permission, permissionCheckbox.value)"
115+
/>
116+
<label class="form-check-label" [attr.for]="permission.name"
117+
>{{ permission.displayName }}
118+
@if (!hideBadges) {
119+
@for (provider of permission.grantedProviders; track $index) {
120+
<span class="badge bg-primary text-dark"
121+
>{{ provider.providerName }}: {{ provider.providerKey }}</span
122+
>
123+
}
124+
}
125+
</label>
126+
</div>
112127
}
113-
</label>
128+
}
114129
</div>
115-
}
116-
}
117-
</div>
130+
</ng-template>
131+
</div>
132+
}
118133
</div>
119134
</div>
120135
</fieldset>

0 commit comments

Comments
 (0)