1+ < div class ="container mx-auto p-4 ">
2+ <!-- Header -->
3+ < div class ="max-w-6xl mx-auto mb-6 bg-primary text-white rounded-lg shadow-sm overflow-hidden transition-all duration-300 ">
4+ < div class ="p-6 flex justify-between items-center ">
5+ < h1 class ="text-2xl font-bold "> Role Permission Mapping</ h1 >
6+ </ div >
7+ </ div >
8+
9+ <!-- Role Selection Card -->
10+ < div class ="max-w-6xl mx-auto mb-6 bg-surface-container-highest rounded-lg shadow-sm overflow-hidden transition-all duration-300 ">
11+ < div class ="p-6 ">
12+ < h2 class ="text-xl font-medium mb-4 "> Select Role</ h2 >
13+
14+ < div class ="flex flex-col md:flex-row items-center gap-4 ">
15+ < mat-form-field appearance ="outline " class ="w-full md:w-1/2 ">
16+ < mat-label > Role</ mat-label >
17+ < select matNativeControl [value] ="selectedRoleId() " (change) ="onRoleChange($event) ">
18+ < option > Please select a Role</ option >
19+ @for (role of roles(); track role.id) {
20+ < option [value] ="role.id "> {{ role.name }}</ option >
21+ }
22+ </ select >
23+ </ mat-form-field >
24+
25+ < div class ="flex-grow "> </ div >
26+
27+ < button mat-raised-button color ="primary " (click) ="saveMapping() " [disabled] ="loading() || saving() || !mapping() ">
28+ < div class ="flex items-center gap-2 ">
29+ @if (saving()) {
30+ < mat-spinner [diameter] ="20 "> </ mat-spinner >
31+ }
32+ < mat-icon > save</ mat-icon >
33+ < span > Save Permissions</ span >
34+ </ div >
35+ </ button >
36+ </ div >
37+ </ div >
38+ </ div >
39+
40+ <!-- Loading State -->
41+ @if (loading()) {
42+ < div class ="max-w-6xl mx-auto mt-8 text-center ">
43+ < mat-spinner diameter ="40 " class ="mx-auto "> </ mat-spinner >
44+ < p class ="mt-4 text-on-surface-variant "> Loading role permissions...</ p >
45+ </ div >
46+ }
47+
48+ <!-- Page-Operation Matrix -->
49+ @if (mapping() && !loading()) {
50+ < div class ="max-w-6xl mx-auto ">
51+ < h2 class ="text-xl font-medium mb-4 "> Configure Permissions for {{ mapping()?.roleName }}</ h2 >
52+
53+ < div class ="bg-surface-container-highest rounded-lg shadow-sm overflow-hidden transition-all duration-300 mb-6 ">
54+ < div class ="p-4 ">
55+ < mat-card appearance ="outlined " class ="mb-4 ">
56+ < mat-card-header >
57+ < mat-card-title > Instructions</ mat-card-title >
58+ </ mat-card-header >
59+ < mat-card-content >
60+ < p > Select the operations each page should have access to. Click on a page row to expand and view all available operations.</ p >
61+ < ul class ="mt-2 list-disc pl-6 ">
62+ < li > Use the checkboxes to grant or revoke specific permissions</ li >
63+ < li > Click the page name to toggle all operations for that page</ li >
64+ < li > Click "Save Permissions" when you're done making changes</ li >
65+ </ ul >
66+ </ mat-card-content >
67+ </ mat-card >
68+
69+ <!-- Table of Permission Mappings -->
70+ < table class ="w-full border-collapse ">
71+ < thead >
72+ < tr class ="bg-surface-container ">
73+ < th class ="px-4 py-3 text-left "> Page</ th >
74+ < th class ="px-4 py-3 text-left "> Permissions</ th >
75+ </ tr >
76+ </ thead >
77+ < tbody >
78+ @for (page of mapping()?.pages; track page.pageId) {
79+ < tr class ="border-b border-outline-variant hover:bg-surface-container transition-colors cursor-pointer ">
80+ < td class ="px-4 py-4 w-1/4 ">
81+ <!-- Page Name with Expand/Collapse Icon -->
82+ < div class ="flex items-center " (click) ="togglePanel(page.pageId) ">
83+ < mat-icon > {{ isPanelExpanded(page.pageId) ? 'expand_less' : 'expand_more' }}</ mat-icon >
84+ < span class ="ml-2 font-medium "> {{ page.pageName }}</ span >
85+ </ div >
86+ </ td >
87+ < td class ="px-4 py-4 ">
88+ <!-- All Operations Toggle -->
89+ < div class ="flex items-center ">
90+ < mat-checkbox
91+ [checked] ="areAllOperationsSelected(page) "
92+ [indeterminate] ="areSomeOperationsSelected(page) "
93+ (change) ="toggleAllOperations(page, $event.checked) ">
94+ {{ areAllOperationsSelected(page) ? 'All operations' : areSomeOperationsSelected(page) ? 'Some operations' : 'No operations' }}
95+ </ mat-checkbox >
96+ </ div >
97+
98+ <!-- Expanded Operations List -->
99+ @if (isPanelExpanded(page.pageId)) {
100+ < div class ="mt-3 pl-8 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3 ">
101+ @for (operation of page.operations; track operation.operationId) {
102+ < mat-checkbox
103+ [checked] ="operation.isSelected "
104+ (change) ="toggleOperation(page, operation.operationId) ">
105+ {{ operation.operationName }}
106+ </ mat-checkbox >
107+ }
108+ </ div >
109+ }
110+ </ td >
111+ </ tr >
112+ }
113+ </ tbody >
114+ </ table >
115+ </ div >
116+ </ div >
117+
118+ <!-- Save Button (Bottom) -->
119+ < div class ="flex justify-end mb-8 ">
120+ < button mat-raised-button color ="primary " (click) ="saveMapping() " [disabled] ="saving() ">
121+ < div class ="flex items-center gap-2 ">
122+ @if (saving()) {
123+ < mat-spinner [diameter] ="20 "> </ mat-spinner >
124+ }
125+ < mat-icon > save</ mat-icon >
126+ < span > Save Permissions</ span >
127+ </ div >
128+ </ button >
129+ </ div >
130+ </ div >
131+ }
132+
133+ <!-- No Data State -->
134+ @if (!mapping() && !loading()) {
135+ < div class ="max-w-6xl mx-auto my-8 p-6 bg-surface-container-highest rounded-lg text-center ">
136+ < mat-icon class ="text-6xl text-on-surface-variant mb-4 "> find_in_page</ mat-icon >
137+ < p class ="text-xl text-on-surface-variant "> No roles available or permission data could not be loaded.</ p >
138+ < button mat-raised-button color ="primary " class ="mt-4 " (click) ="loadRoles() ">
139+ < mat-icon > refresh</ mat-icon >
140+ Retry
141+ </ button >
142+ </ div >
143+ }
144+ </ div >
0 commit comments