@payez/next-mvp 3.5.0 → 3.6.1
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/dist/api-handlers/admin/index.d.ts +1 -0
- package/dist/api-handlers/admin/index.js +3 -1
- package/dist/api-handlers/admin/stats.d.ts +21 -0
- package/dist/api-handlers/admin/stats.js +240 -0
- package/dist/auth/utils/idp-client.js +1 -0
- package/dist/components/account/MobileNavDrawer.d.ts +32 -0
- package/dist/components/account/MobileNavDrawer.js +81 -0
- package/dist/components/account/UserAvatarMenu.js +5 -1
- package/dist/components/account/index.d.ts +2 -0
- package/dist/components/account/index.js +5 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -1
- package/dist/pages/admin-page-permissions/PagePermissionsAdminPage.d.ts +18 -0
- package/dist/pages/admin-page-permissions/PagePermissionsAdminPage.js +276 -0
- package/dist/pages/admin-page-permissions/index.d.ts +6 -0
- package/dist/pages/admin-page-permissions/index.js +13 -0
- package/dist/pages/admin-roles/RolesAdminPage.d.ts +12 -11
- package/dist/pages/admin-roles/RolesAdminPage.js +249 -66
- package/dist/routes/auth/session.d.ts +1 -30
- package/dist/routes/auth/session.js +3 -4
- package/package.json +6 -1
- package/src/api-handlers/admin/index.ts +5 -0
- package/src/api-handlers/admin/stats.ts +240 -0
- package/src/auth/utils/idp-client.ts +1 -0
- package/src/components/account/MobileNavDrawer.tsx +305 -0
- package/src/components/account/UserAvatarMenu.tsx +47 -17
- package/src/components/account/index.ts +5 -0
- package/src/index.ts +2 -2
- package/src/pages/admin-page-permissions/PagePermissionsAdminPage.tsx +527 -0
- package/src/pages/admin-page-permissions/index.ts +7 -0
- package/src/pages/admin-roles/RolesAdminPage.tsx +494 -318
- package/src/routes/auth/session.ts +3 -4
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Page Permissions Admin Page (/admin/page-permissions)
|
|
4
|
+
*
|
|
5
|
+
* Design: Aurum (DESIGN_SPEC.md)
|
|
6
|
+
* Control which roles can access which pages
|
|
7
|
+
*
|
|
8
|
+
* Three sections:
|
|
9
|
+
* 1. Search & Filters — Find pages by route or category
|
|
10
|
+
* 2. Pages & Role Requirements — Table showing pages and their role assignments
|
|
11
|
+
* 3. Change History — Audit log of permission changes
|
|
12
|
+
*
|
|
13
|
+
* Design Principles:
|
|
14
|
+
* - No shadows, gradients, or animation
|
|
15
|
+
* - One accent color (blue #0066cc)
|
|
16
|
+
* - Inline interactions (no modals)
|
|
17
|
+
* - Scan-friendly tables and lists
|
|
18
|
+
*/
|
|
19
|
+
'use client';
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.default = PagePermissionsAdminPage;
|
|
22
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
23
|
+
const react_1 = require("react");
|
|
24
|
+
// Mock data
|
|
25
|
+
const MOCK_PAGES = [
|
|
26
|
+
{
|
|
27
|
+
id: 1,
|
|
28
|
+
route: '/dashboard',
|
|
29
|
+
displayName: 'Dashboard',
|
|
30
|
+
requires2fa: false,
|
|
31
|
+
roles: [],
|
|
32
|
+
category: 'user',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 2,
|
|
36
|
+
route: '/admin',
|
|
37
|
+
displayName: 'Admin Dashboard',
|
|
38
|
+
requires2fa: true,
|
|
39
|
+
roles: ['SiteAdmin', 'ClientAdmin'],
|
|
40
|
+
category: 'admin',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 3,
|
|
44
|
+
route: '/admin/users',
|
|
45
|
+
displayName: 'User Management',
|
|
46
|
+
requires2fa: true,
|
|
47
|
+
roles: ['SiteAdmin'],
|
|
48
|
+
category: 'admin',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 4,
|
|
52
|
+
route: '/account/security',
|
|
53
|
+
displayName: 'Security Settings',
|
|
54
|
+
requires2fa: true,
|
|
55
|
+
roles: [],
|
|
56
|
+
category: 'account',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 5,
|
|
60
|
+
route: '/interview-practice',
|
|
61
|
+
displayName: 'Interview Practice',
|
|
62
|
+
requires2fa: false,
|
|
63
|
+
roles: ['ClientAdmin'],
|
|
64
|
+
category: 'user',
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
const MOCK_CHANGES = [
|
|
68
|
+
{
|
|
69
|
+
timestamp: '3/10/2026, 10:30 AM',
|
|
70
|
+
event: '/admin/users role requirement changed: Added ClientAdmin by Admin User',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
timestamp: '3/10/2026, 10:15 AM',
|
|
74
|
+
event: '/dashboard updated: 2FA requirement removed by Admin User',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
timestamp: '3/9/2026, 3:45 PM',
|
|
78
|
+
event: '/interview-practice role requirement changed: Added SiteAdmin by Admin User',
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
const CATEGORIES = ['All Pages', 'Admin Pages', 'Account Pages', 'User Pages'];
|
|
82
|
+
const categoryMap = {
|
|
83
|
+
'All Pages': '',
|
|
84
|
+
'Admin Pages': 'admin',
|
|
85
|
+
'Account Pages': 'account',
|
|
86
|
+
'User Pages': 'user',
|
|
87
|
+
};
|
|
88
|
+
function PagePermissionsAdminPage() {
|
|
89
|
+
const [pages, setPages] = (0, react_1.useState)(MOCK_PAGES);
|
|
90
|
+
const [searchQuery, setSearchQuery] = (0, react_1.useState)('');
|
|
91
|
+
const [activeFilter, setActiveFilter] = (0, react_1.useState)('All Pages');
|
|
92
|
+
const [message, setMessage] = (0, react_1.useState)(null);
|
|
93
|
+
const [editingPageId, setEditingPageId] = (0, react_1.useState)(null);
|
|
94
|
+
const [tempRoles, setTempRoles] = (0, react_1.useState)([]);
|
|
95
|
+
const filteredPages = pages.filter((page) => {
|
|
96
|
+
const matchesSearch = page.route.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
97
|
+
page.displayName.toLowerCase().includes(searchQuery.toLowerCase());
|
|
98
|
+
const categoryFilter = categoryMap[activeFilter];
|
|
99
|
+
const matchesCategory = !categoryFilter || page.category === categoryFilter;
|
|
100
|
+
return matchesSearch && matchesCategory;
|
|
101
|
+
});
|
|
102
|
+
const handleEditRoles = (pageId, currentRoles) => {
|
|
103
|
+
setEditingPageId(pageId);
|
|
104
|
+
setTempRoles([...currentRoles]);
|
|
105
|
+
};
|
|
106
|
+
const handleToggleRole = (role) => {
|
|
107
|
+
setTempRoles((prev) => prev.includes(role) ? prev.filter((r) => r !== role) : [...prev, role]);
|
|
108
|
+
};
|
|
109
|
+
const handleSaveRoles = (pageId) => {
|
|
110
|
+
setPages((prev) => prev.map((p) => (p.id === pageId ? { ...p, roles: tempRoles } : p)));
|
|
111
|
+
setMessage('Page updated');
|
|
112
|
+
setEditingPageId(null);
|
|
113
|
+
setTimeout(() => setMessage(null), 3000);
|
|
114
|
+
};
|
|
115
|
+
const handleRemoveRole = (pageId, role) => {
|
|
116
|
+
setPages((prev) => prev.map((p) => p.id === pageId ? { ...p, roles: p.roles.filter((r) => r !== role) } : p));
|
|
117
|
+
setMessage('Role removed');
|
|
118
|
+
setTimeout(() => setMessage(null), 3000);
|
|
119
|
+
};
|
|
120
|
+
return ((0, jsx_runtime_1.jsx)("div", { style: { background: '#f8f8f8', minHeight: '100vh', padding: '40px 20px' }, children: (0, jsx_runtime_1.jsxs)("div", { style: { maxWidth: '1200px', margin: '0 auto' }, children: [(0, jsx_runtime_1.jsxs)("div", { style: { marginBottom: '40px' }, children: [(0, jsx_runtime_1.jsx)("h1", { style: {
|
|
121
|
+
fontSize: '32px',
|
|
122
|
+
fontWeight: 400,
|
|
123
|
+
color: '#333',
|
|
124
|
+
marginBottom: '8px',
|
|
125
|
+
}, children: "Page Permissions" }), (0, jsx_runtime_1.jsx)("p", { style: { fontSize: '16px', color: '#666', fontWeight: 400 }, children: "Control which roles can access which pages" })] }), (0, jsx_runtime_1.jsx)("div", { style: { height: '1px', background: '#e0e0e0', margin: '24px 0' } }), (0, jsx_runtime_1.jsxs)("section", { style: { marginBottom: '40px' }, children: [(0, jsx_runtime_1.jsx)("div", { style: { marginBottom: '16px' }, children: (0, jsx_runtime_1.jsx)("input", { type: "text", placeholder: "Search pages...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), style: {
|
|
126
|
+
width: '100%',
|
|
127
|
+
padding: '10px 14px',
|
|
128
|
+
fontSize: '14px',
|
|
129
|
+
border: '1px solid #e0e0e0',
|
|
130
|
+
borderRadius: '4px',
|
|
131
|
+
background: 'white',
|
|
132
|
+
boxSizing: 'border-box',
|
|
133
|
+
} }) }), (0, jsx_runtime_1.jsx)("div", { style: { display: 'flex', gap: '8px', flexWrap: 'wrap' }, children: CATEGORIES.map((cat) => ((0, jsx_runtime_1.jsx)("button", { onClick: () => setActiveFilter(cat), style: {
|
|
134
|
+
padding: '8px 14px',
|
|
135
|
+
fontSize: '13px',
|
|
136
|
+
border: activeFilter === cat ? 'none' : '1px solid #e0e0e0',
|
|
137
|
+
borderRadius: '4px',
|
|
138
|
+
background: activeFilter === cat ? '#0066cc' : 'white',
|
|
139
|
+
color: activeFilter === cat ? 'white' : '#333',
|
|
140
|
+
cursor: 'pointer',
|
|
141
|
+
transition: 'all 0.2s',
|
|
142
|
+
}, onMouseEnter: (e) => {
|
|
143
|
+
if (activeFilter !== cat) {
|
|
144
|
+
e.currentTarget.style.background = '#f5f5f5';
|
|
145
|
+
}
|
|
146
|
+
}, onMouseLeave: (e) => {
|
|
147
|
+
if (activeFilter !== cat) {
|
|
148
|
+
e.currentTarget.style.background = 'white';
|
|
149
|
+
}
|
|
150
|
+
}, children: cat }, cat))) })] }), (0, jsx_runtime_1.jsx)("div", { style: { height: '1px', background: '#e0e0e0', margin: '24px 0' } }), message && ((0, jsx_runtime_1.jsxs)("div", { style: {
|
|
151
|
+
padding: '8px 12px',
|
|
152
|
+
background: '#e8f5e9',
|
|
153
|
+
color: '#2e7d32',
|
|
154
|
+
borderRadius: '4px',
|
|
155
|
+
marginBottom: '12px',
|
|
156
|
+
fontSize: '13px',
|
|
157
|
+
}, children: ["\u2713 ", message] })), (0, jsx_runtime_1.jsxs)("section", { style: { marginBottom: '60px' }, children: [(0, jsx_runtime_1.jsx)("h2", { style: {
|
|
158
|
+
fontSize: '18px',
|
|
159
|
+
fontWeight: 400,
|
|
160
|
+
color: '#666',
|
|
161
|
+
marginBottom: '24px',
|
|
162
|
+
textTransform: 'uppercase',
|
|
163
|
+
letterSpacing: '1px',
|
|
164
|
+
}, children: "Pages & Permissions" }), (0, jsx_runtime_1.jsxs)("table", { style: {
|
|
165
|
+
width: '100%',
|
|
166
|
+
borderCollapse: 'collapse',
|
|
167
|
+
background: 'white',
|
|
168
|
+
border: '1px solid #e0e0e0',
|
|
169
|
+
borderRadius: '4px',
|
|
170
|
+
overflow: 'hidden',
|
|
171
|
+
}, children: [(0, jsx_runtime_1.jsx)("thead", { children: (0, jsx_runtime_1.jsxs)("tr", { style: { background: '#f8f8f8', borderBottom: '1px solid #e0e0e0' }, children: [(0, jsx_runtime_1.jsx)("th", { style: {
|
|
172
|
+
padding: '16px',
|
|
173
|
+
textAlign: 'left',
|
|
174
|
+
fontSize: '12px',
|
|
175
|
+
color: '#999',
|
|
176
|
+
textTransform: 'uppercase',
|
|
177
|
+
letterSpacing: '0.5px',
|
|
178
|
+
fontWeight: 'normal',
|
|
179
|
+
}, children: "Route" }), (0, jsx_runtime_1.jsx)("th", { style: {
|
|
180
|
+
padding: '16px',
|
|
181
|
+
textAlign: 'left',
|
|
182
|
+
fontSize: '12px',
|
|
183
|
+
color: '#999',
|
|
184
|
+
textTransform: 'uppercase',
|
|
185
|
+
letterSpacing: '0.5px',
|
|
186
|
+
fontWeight: 'normal',
|
|
187
|
+
}, children: "Display Name" }), (0, jsx_runtime_1.jsx)("th", { style: {
|
|
188
|
+
padding: '16px',
|
|
189
|
+
textAlign: 'center',
|
|
190
|
+
fontSize: '12px',
|
|
191
|
+
color: '#999',
|
|
192
|
+
textTransform: 'uppercase',
|
|
193
|
+
letterSpacing: '0.5px',
|
|
194
|
+
fontWeight: 'normal',
|
|
195
|
+
}, children: "2FA" }), (0, jsx_runtime_1.jsx)("th", { style: {
|
|
196
|
+
padding: '16px',
|
|
197
|
+
textAlign: 'left',
|
|
198
|
+
fontSize: '12px',
|
|
199
|
+
color: '#999',
|
|
200
|
+
textTransform: 'uppercase',
|
|
201
|
+
letterSpacing: '0.5px',
|
|
202
|
+
fontWeight: 'normal',
|
|
203
|
+
}, children: "Roles" })] }) }), (0, jsx_runtime_1.jsx)("tbody", { children: filteredPages.map((page) => ((0, jsx_runtime_1.jsxs)("tr", { style: {
|
|
204
|
+
borderBottom: '1px solid #e0e0e0',
|
|
205
|
+
height: '48px',
|
|
206
|
+
}, onMouseEnter: (e) => (e.currentTarget.style.background = '#f5f5f5'), onMouseLeave: (e) => (e.currentTarget.style.background = 'white'), children: [(0, jsx_runtime_1.jsx)("td", { style: {
|
|
207
|
+
padding: '16px',
|
|
208
|
+
fontSize: '12px',
|
|
209
|
+
fontFamily: 'Courier New, monospace',
|
|
210
|
+
color: '#333',
|
|
211
|
+
}, title: "Click to copy", children: page.route }), (0, jsx_runtime_1.jsx)("td", { style: { padding: '16px', fontSize: '14px', color: '#333' }, children: page.displayName }), (0, jsx_runtime_1.jsx)("td", { style: { padding: '16px', textAlign: 'center', fontSize: '14px' }, children: page.requires2fa ? '✓' : '✕' }), (0, jsx_runtime_1.jsx)("td", { style: { padding: '16px', fontSize: '13px' }, children: editingPageId === page.id ? ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', gap: '12px', alignItems: 'center' }, children: [(0, jsx_runtime_1.jsx)("div", { style: { display: 'flex', gap: '12px' }, children: ['SiteAdmin', 'ClientAdmin'].map((role) => ((0, jsx_runtime_1.jsxs)("label", { style: {
|
|
212
|
+
display: 'flex',
|
|
213
|
+
alignItems: 'center',
|
|
214
|
+
gap: '6px',
|
|
215
|
+
cursor: 'pointer',
|
|
216
|
+
}, children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: tempRoles.includes(role), onChange: () => handleToggleRole(role), style: { cursor: 'pointer' } }), (0, jsx_runtime_1.jsx)("span", { style: { fontSize: '12px', color: '#333' }, children: role })] }, role))) }), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', gap: '6px' }, children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => handleSaveRoles(page.id), style: {
|
|
217
|
+
padding: '6px 10px',
|
|
218
|
+
background: '#0066cc',
|
|
219
|
+
color: 'white',
|
|
220
|
+
border: 'none',
|
|
221
|
+
borderRadius: '4px',
|
|
222
|
+
cursor: 'pointer',
|
|
223
|
+
fontSize: '11px',
|
|
224
|
+
}, onMouseEnter: (e) => (e.currentTarget.style.background = '#0052a3'), onMouseLeave: (e) => (e.currentTarget.style.background = '#0066cc'), children: "Save" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setEditingPageId(null), style: {
|
|
225
|
+
padding: '6px 10px',
|
|
226
|
+
background: 'white',
|
|
227
|
+
color: '#333',
|
|
228
|
+
border: '1px solid #e0e0e0',
|
|
229
|
+
borderRadius: '4px',
|
|
230
|
+
cursor: 'pointer',
|
|
231
|
+
fontSize: '11px',
|
|
232
|
+
}, onMouseEnter: (e) => (e.currentTarget.style.background = '#f5f5f5'), onMouseLeave: (e) => (e.currentTarget.style.background = 'white'), children: "Cancel" })] })] })) : ((0, jsx_runtime_1.jsx)("div", { style: { display: 'flex', gap: '6px', alignItems: 'center' }, children: page.roles.length > 0 ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [page.roles.map((role) => ((0, jsx_runtime_1.jsxs)("span", { style: {
|
|
233
|
+
background: '#e3f2fd',
|
|
234
|
+
color: '#0066cc',
|
|
235
|
+
padding: '4px 8px',
|
|
236
|
+
borderRadius: '3px',
|
|
237
|
+
fontSize: '12px',
|
|
238
|
+
display: 'inline-flex',
|
|
239
|
+
alignItems: 'center',
|
|
240
|
+
gap: '4px',
|
|
241
|
+
}, children: [role, (0, jsx_runtime_1.jsx)("button", { onClick: () => handleRemoveRole(page.id, role), style: {
|
|
242
|
+
background: 'none',
|
|
243
|
+
border: 'none',
|
|
244
|
+
color: '#0066cc',
|
|
245
|
+
cursor: 'pointer',
|
|
246
|
+
fontSize: '12px',
|
|
247
|
+
padding: '0',
|
|
248
|
+
lineHeight: '1',
|
|
249
|
+
}, children: "\u2715" })] }, role))), (0, jsx_runtime_1.jsx)("button", { onClick: () => handleEditRoles(page.id, page.roles), style: {
|
|
250
|
+
padding: '4px 8px',
|
|
251
|
+
background: 'white',
|
|
252
|
+
color: '#0066cc',
|
|
253
|
+
border: '1px solid #e0e0e0',
|
|
254
|
+
borderRadius: '3px',
|
|
255
|
+
cursor: 'pointer',
|
|
256
|
+
fontSize: '11px',
|
|
257
|
+
}, onMouseEnter: (e) => (e.currentTarget.style.background = '#f5f5f5'), onMouseLeave: (e) => (e.currentTarget.style.background = 'white'), children: "+" })] })) : ((0, jsx_runtime_1.jsx)("button", { onClick: () => handleEditRoles(page.id, []), style: {
|
|
258
|
+
padding: '4px 8px',
|
|
259
|
+
background: 'white',
|
|
260
|
+
color: '#0066cc',
|
|
261
|
+
border: '1px solid #e0e0e0',
|
|
262
|
+
borderRadius: '3px',
|
|
263
|
+
cursor: 'pointer',
|
|
264
|
+
fontSize: '11px',
|
|
265
|
+
}, onMouseEnter: (e) => (e.currentTarget.style.background = '#f5f5f5'), onMouseLeave: (e) => (e.currentTarget.style.background = 'white'), children: "+ Add Role" })) })) })] }, page.id))) })] }), (0, jsx_runtime_1.jsxs)("div", { style: { marginTop: '12px', fontSize: '12px', color: '#999' }, children: [filteredPages.length, " of ", pages.length, " pages shown"] })] }), (0, jsx_runtime_1.jsx)("div", { style: { height: '1px', background: '#e0e0e0', margin: '24px 0' } }), (0, jsx_runtime_1.jsxs)("section", { children: [(0, jsx_runtime_1.jsx)("h2", { style: {
|
|
266
|
+
fontSize: '18px',
|
|
267
|
+
fontWeight: 400,
|
|
268
|
+
color: '#666',
|
|
269
|
+
marginBottom: '24px',
|
|
270
|
+
textTransform: 'uppercase',
|
|
271
|
+
letterSpacing: '1px',
|
|
272
|
+
}, children: "Recent Changes" }), (0, jsx_runtime_1.jsx)("div", { style: { background: 'white', border: '1px solid #e0e0e0', borderRadius: '4px' }, children: MOCK_CHANGES.map((change, idx) => ((0, jsx_runtime_1.jsxs)("div", { style: {
|
|
273
|
+
padding: '16px',
|
|
274
|
+
borderBottom: idx < MOCK_CHANGES.length - 1 ? '1px solid #e0e0e0' : 'none',
|
|
275
|
+
}, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontSize: '12px', color: '#999', marginBottom: '4px' }, children: change.timestamp }), (0, jsx_runtime_1.jsx)("div", { style: { fontSize: '14px', color: '#333' }, children: change.event })] }, idx))) })] })] }) }));
|
|
276
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Page Permissions Admin exports
|
|
4
|
+
*
|
|
5
|
+
* - PagePermissionsAdminPage: Admin interface for managing page permissions (/admin/page-permissions)
|
|
6
|
+
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.PagePermissionsAdminPage = void 0;
|
|
12
|
+
var PagePermissionsAdminPage_1 = require("./PagePermissionsAdminPage");
|
|
13
|
+
Object.defineProperty(exports, "PagePermissionsAdminPage", { enumerable: true, get: function () { return __importDefault(PagePermissionsAdminPage_1).default; } });
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Role Management Admin Page (/admin/roles)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Design: Aurum (DESIGN_SPEC.md)
|
|
5
|
+
* Three sections:
|
|
6
|
+
* 1. Available Roles — Cards showing SiteAdmin, ClientAdmin
|
|
7
|
+
* 2. User Assignments — Table with inline role dropdowns
|
|
8
|
+
* 3. Change History — Audit log of role changes
|
|
7
9
|
*
|
|
8
|
-
*
|
|
10
|
+
* Design Principles:
|
|
11
|
+
* - No shadows, gradients, or animation
|
|
12
|
+
* - One accent color (blue #0066cc)
|
|
13
|
+
* - Inline interactions (no modals)
|
|
14
|
+
* - Scan-friendly tables and lists
|
|
9
15
|
*/
|
|
10
|
-
|
|
11
|
-
rolesEndpoint?: string;
|
|
12
|
-
matrixEndpoint?: string;
|
|
13
|
-
}
|
|
14
|
-
export default function RolesAdminPage({ rolesEndpoint, matrixEndpoint, }: RolesAdminPageProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
-
export {};
|
|
16
|
+
export default function RolesAdminPage(): import("react/jsx-runtime").JSX.Element;
|