hazo_auth 3.0.4 → 4.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 +146 -0
- package/SETUP_CHECKLIST.md +369 -0
- package/dist/components/layouts/my_settings/components/profile_picture_library_tab.d.ts.map +1 -1
- package/dist/components/layouts/my_settings/components/profile_picture_library_tab.js +2 -2
- package/dist/components/layouts/rbac_test/index.d.ts +15 -0
- package/dist/components/layouts/rbac_test/index.d.ts.map +1 -0
- package/dist/components/layouts/rbac_test/index.js +378 -0
- package/dist/components/layouts/shared/components/password_field.js +1 -1
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +2 -2
- package/dist/components/layouts/shared/components/two_column_auth_layout.js +1 -1
- package/dist/components/layouts/user_management/components/roles_matrix.d.ts +2 -3
- package/dist/components/layouts/user_management/components/roles_matrix.d.ts.map +1 -1
- package/dist/components/layouts/user_management/components/roles_matrix.js +133 -8
- package/dist/components/layouts/user_management/components/scope_hierarchy_tab.d.ts +12 -0
- package/dist/components/layouts/user_management/components/scope_hierarchy_tab.d.ts.map +1 -0
- package/dist/components/layouts/user_management/components/scope_hierarchy_tab.js +291 -0
- package/dist/components/layouts/user_management/components/scope_labels_tab.d.ts +13 -0
- package/dist/components/layouts/user_management/components/scope_labels_tab.d.ts.map +1 -0
- package/dist/components/layouts/user_management/components/scope_labels_tab.js +158 -0
- package/dist/components/layouts/user_management/components/user_scopes_tab.d.ts +11 -0
- package/dist/components/layouts/user_management/components/user_scopes_tab.d.ts.map +1 -0
- package/dist/components/layouts/user_management/components/user_scopes_tab.js +267 -0
- package/dist/components/layouts/user_management/index.d.ts +9 -2
- package/dist/components/layouts/user_management/index.d.ts.map +1 -1
- package/dist/components/layouts/user_management/index.js +22 -6
- package/dist/components/ui/select.d.ts +14 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/select.js +59 -0
- package/dist/components/ui/tree-view.d.ts +108 -0
- package/dist/components/ui/tree-view.d.ts.map +1 -0
- package/dist/components/ui/tree-view.js +194 -0
- package/dist/lib/auth/auth_types.d.ts +45 -0
- package/dist/lib/auth/auth_types.d.ts.map +1 -1
- package/dist/lib/auth/auth_types.js +13 -0
- package/dist/lib/auth/hazo_get_auth.server.d.ts +4 -2
- package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -1
- package/dist/lib/auth/hazo_get_auth.server.js +107 -3
- package/dist/lib/auth/scope_cache.d.ts +92 -0
- package/dist/lib/auth/scope_cache.d.ts.map +1 -0
- package/dist/lib/auth/scope_cache.js +171 -0
- package/dist/lib/scope_hierarchy_config.server.d.ts +39 -0
- package/dist/lib/scope_hierarchy_config.server.d.ts.map +1 -0
- package/dist/lib/scope_hierarchy_config.server.js +96 -0
- package/dist/lib/services/email_service.d.ts.map +1 -1
- package/dist/lib/services/email_service.js +7 -2
- package/dist/lib/services/profile_picture_service.d.ts +1 -7
- package/dist/lib/services/profile_picture_service.d.ts.map +1 -1
- package/dist/lib/services/profile_picture_service.js +77 -32
- package/dist/lib/services/registration_service.js +1 -1
- package/dist/lib/services/scope_labels_service.d.ts +48 -0
- package/dist/lib/services/scope_labels_service.d.ts.map +1 -0
- package/dist/lib/services/scope_labels_service.js +277 -0
- package/dist/lib/services/scope_service.d.ts +114 -0
- package/dist/lib/services/scope_service.d.ts.map +1 -0
- package/dist/lib/services/scope_service.js +582 -0
- package/dist/lib/services/user_scope_service.d.ts +74 -0
- package/dist/lib/services/user_scope_service.d.ts.map +1 -0
- package/dist/lib/services/user_scope_service.js +415 -0
- package/hazo_auth_config.example.ini +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -706,6 +706,7 @@ import { ResetPasswordLayout } from "hazo_auth/components/layouts/reset_password
|
|
|
706
706
|
import { EmailVerificationLayout } from "hazo_auth/components/layouts/email_verification";
|
|
707
707
|
import { MySettingsLayout } from "hazo_auth/components/layouts/my_settings";
|
|
708
708
|
import { UserManagementLayout } from "hazo_auth/components/layouts/user_management";
|
|
709
|
+
import { RbacTestLayout } from "hazo_auth/components/layouts/rbac_test";
|
|
709
710
|
|
|
710
711
|
// Shared layout components and hooks (barrel import - recommended)
|
|
711
712
|
import {
|
|
@@ -762,6 +763,7 @@ export default async function LoginPage() {
|
|
|
762
763
|
- `EmailVerificationLayout` - Verify email address
|
|
763
764
|
- `MySettingsLayout` - User profile and settings
|
|
764
765
|
- `UserManagementLayout` - Admin user/role management (requires user_management API routes)
|
|
766
|
+
- `RbacTestLayout` - RBAC/HRBAC permission and scope testing tool (requires admin_test_access permission)
|
|
765
767
|
|
|
766
768
|
### User Management Component
|
|
767
769
|
|
|
@@ -793,6 +795,7 @@ export { GET, POST, PUT } from "hazo_auth/server/routes";
|
|
|
793
795
|
- **Users:** List users, deactivate users, send password reset emails
|
|
794
796
|
- **Permissions:** List permissions (from DB and config), migrate config permissions to DB, create/update/delete permissions
|
|
795
797
|
- **Roles:** List roles with permissions, create roles, update role-permission assignments
|
|
798
|
+
- **UI Enhancement**: The Roles tab uses a tag-based UI for better readability. Each role displays permissions as inline tags/chips (showing up to 4, with "+N more" to expand). Edit permissions via an interactive dialog with Select All/Unselect All buttons.
|
|
796
799
|
- **User Roles:** Get user roles, assign roles to users, bulk update user role assignments
|
|
797
800
|
|
|
798
801
|
**Example Usage:**
|
|
@@ -1229,6 +1232,149 @@ enable_friendly_error_messages = true
|
|
|
1229
1232
|
|
|
1230
1233
|
---
|
|
1231
1234
|
|
|
1235
|
+
## Hierarchical Role-Based Access Control (HRBAC)
|
|
1236
|
+
|
|
1237
|
+
hazo_auth supports optional Hierarchical Role-Based Access Control (HRBAC) with 7 scope levels (L1-L7). HRBAC extends standard RBAC by allowing users to be assigned to scopes in a hierarchy, with automatic inheritance of access to child scopes.
|
|
1238
|
+
|
|
1239
|
+
### Enabling HRBAC
|
|
1240
|
+
|
|
1241
|
+
Add the following to your `hazo_auth_config.ini`:
|
|
1242
|
+
|
|
1243
|
+
```ini
|
|
1244
|
+
[hazo_auth__scope_hierarchy]
|
|
1245
|
+
enable_hrbac = true
|
|
1246
|
+
default_org = my_organization # Optional: default organization for single-tenant apps
|
|
1247
|
+
scope_cache_ttl_minutes = 15
|
|
1248
|
+
scope_cache_max_entries = 5000
|
|
1249
|
+
|
|
1250
|
+
# Optional: customize default labels for each scope level
|
|
1251
|
+
default_label_l1 = Company
|
|
1252
|
+
default_label_l2 = Division
|
|
1253
|
+
default_label_l3 = Department
|
|
1254
|
+
default_label_l4 = Team
|
|
1255
|
+
default_label_l5 = Project
|
|
1256
|
+
default_label_l6 = Sub-project
|
|
1257
|
+
default_label_l7 = Task
|
|
1258
|
+
```
|
|
1259
|
+
|
|
1260
|
+
### Database Setup
|
|
1261
|
+
|
|
1262
|
+
HRBAC requires additional database tables. See `SETUP_CHECKLIST.md` for full PostgreSQL and SQLite scripts, including:
|
|
1263
|
+
- `hazo_scopes_l1` through `hazo_scopes_l7` - Scope tables with parent_scope_id references
|
|
1264
|
+
- `hazo_user_scopes` - User-scope assignments
|
|
1265
|
+
- `hazo_scope_labels` - Custom labels per organization
|
|
1266
|
+
- `hazo_enum_scope_types` - Enum type for scope validation
|
|
1267
|
+
|
|
1268
|
+
### Using hazo_get_auth with Scope Options
|
|
1269
|
+
|
|
1270
|
+
When HRBAC is enabled, you can check scope access alongside permissions:
|
|
1271
|
+
|
|
1272
|
+
```typescript
|
|
1273
|
+
import { hazo_get_auth } from "hazo_auth/lib/auth/hazo_get_auth.server";
|
|
1274
|
+
import { ScopeAccessError } from "hazo_auth/lib/auth/auth_types";
|
|
1275
|
+
|
|
1276
|
+
export async function GET(request: NextRequest) {
|
|
1277
|
+
try {
|
|
1278
|
+
const authResult = await hazo_get_auth(request, {
|
|
1279
|
+
required_permissions: ["view_reports"],
|
|
1280
|
+
scope_type: "hazo_scopes_l3", // Check access to Level 3 scope
|
|
1281
|
+
scope_seq: "L3_001", // Scope identifier (or use scope_id for UUID)
|
|
1282
|
+
strict: true, // Throws ScopeAccessError if denied
|
|
1283
|
+
});
|
|
1284
|
+
|
|
1285
|
+
if (!authResult.authenticated) {
|
|
1286
|
+
return NextResponse.json({ error: "Authentication required" }, { status: 401 });
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
// Both permission_ok and scope_ok must be true for full access
|
|
1290
|
+
if (authResult.scope_ok) {
|
|
1291
|
+
// Access granted - scope_access_via shows how access was granted
|
|
1292
|
+
console.log("Access via:", authResult.scope_access_via);
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
return NextResponse.json({ message: "Access granted" });
|
|
1296
|
+
} catch (error) {
|
|
1297
|
+
if (error instanceof ScopeAccessError) {
|
|
1298
|
+
return NextResponse.json(
|
|
1299
|
+
{ error: "Scope access denied", scope: error.scope_identifier },
|
|
1300
|
+
{ status: 403 }
|
|
1301
|
+
);
|
|
1302
|
+
}
|
|
1303
|
+
throw error;
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
```
|
|
1307
|
+
|
|
1308
|
+
### Scope Access Inheritance
|
|
1309
|
+
|
|
1310
|
+
Users assigned to a higher-level scope automatically have access to all descendant scopes:
|
|
1311
|
+
- User with L2 scope access can access all L3, L4, L5, L6, L7 scopes under that L2 scope
|
|
1312
|
+
- Direct assignments take precedence over inherited access
|
|
1313
|
+
- The `scope_access_via` field in the result shows which scope granted access
|
|
1314
|
+
|
|
1315
|
+
### Required Permissions for Management
|
|
1316
|
+
|
|
1317
|
+
- `admin_scope_hierarchy_management` - Manage scopes and scope labels
|
|
1318
|
+
- `admin_user_scope_assignment` - Assign scopes to users
|
|
1319
|
+
- `admin_test_access` - Access the RBAC/HRBAC test tool
|
|
1320
|
+
|
|
1321
|
+
Add these to your `application_permission_list_defaults` in `hazo_auth_config.ini`:
|
|
1322
|
+
|
|
1323
|
+
```ini
|
|
1324
|
+
[hazo_auth__user_management]
|
|
1325
|
+
application_permission_list_defaults = admin_user_management,admin_role_management,admin_permission_management,admin_scope_hierarchy_management,admin_user_scope_assignment,admin_test_access
|
|
1326
|
+
```
|
|
1327
|
+
|
|
1328
|
+
### User Management UI
|
|
1329
|
+
|
|
1330
|
+
When HRBAC is enabled and the user has appropriate permissions, three new tabs appear in the User Management layout:
|
|
1331
|
+
- **Scope Hierarchy** - Create, edit, and delete scopes at each level
|
|
1332
|
+
- **Scope Labels** - Customize labels for scope levels per organization
|
|
1333
|
+
- **User Scopes** - Assign and remove scope assignments for users
|
|
1334
|
+
|
|
1335
|
+
### RBAC/HRBAC Test Tool
|
|
1336
|
+
|
|
1337
|
+
The `RbacTestLayout` component provides a comprehensive testing interface for administrators to test RBAC permissions and HRBAC scope access for any user in the system.
|
|
1338
|
+
|
|
1339
|
+
**Features:**
|
|
1340
|
+
- **User Selection**: Dropdown to select any user in the system
|
|
1341
|
+
- **User Info Display**: Shows selected user's current permissions and assigned scopes
|
|
1342
|
+
- **RBAC Test Tab**: Select permissions to test if the user has them
|
|
1343
|
+
- **HRBAC Test Tab**: Select a scope from a tree view and test if the user has access
|
|
1344
|
+
- **Results Display**: Clear pass/fail indicators with missing permissions and scope access details
|
|
1345
|
+
|
|
1346
|
+
**Required Permission:** `admin_test_access`
|
|
1347
|
+
|
|
1348
|
+
**Usage in Your App:**
|
|
1349
|
+
|
|
1350
|
+
```typescript
|
|
1351
|
+
// app/admin/rbac-test/page.tsx
|
|
1352
|
+
import { RbacTestLayout } from "hazo_auth/components/layouts/rbac_test";
|
|
1353
|
+
import { is_hrbac_enabled, get_default_org } from "hazo_auth/lib/scope_hierarchy_config.server";
|
|
1354
|
+
|
|
1355
|
+
export default function RbacTestPage() {
|
|
1356
|
+
const hrbacEnabled = is_hrbac_enabled();
|
|
1357
|
+
const defaultOrg = get_default_org();
|
|
1358
|
+
|
|
1359
|
+
return (
|
|
1360
|
+
<RbacTestLayout
|
|
1361
|
+
hrbacEnabled={hrbacEnabled}
|
|
1362
|
+
defaultOrg={defaultOrg}
|
|
1363
|
+
/>
|
|
1364
|
+
);
|
|
1365
|
+
}
|
|
1366
|
+
```
|
|
1367
|
+
|
|
1368
|
+
**API Route Required:**
|
|
1369
|
+
The test tool uses the `/api/hazo_auth/rbac_test` endpoint which is included in the package. This route:
|
|
1370
|
+
- Accepts `test_user_id` parameter to test any user
|
|
1371
|
+
- Checks permissions and scope access for the specified user
|
|
1372
|
+
- Requires `admin_test_access` permission to call
|
|
1373
|
+
|
|
1374
|
+
**Demo Page:** A test page is available at `/hazo_auth/rbac_test` in the demo app.
|
|
1375
|
+
|
|
1376
|
+
---
|
|
1377
|
+
|
|
1232
1378
|
## Profile Picture Menu Widget
|
|
1233
1379
|
|
|
1234
1380
|
The Profile Picture Menu is a versatile component for navbar or sidebar that automatically displays:
|
package/SETUP_CHECKLIST.md
CHANGED
|
@@ -957,6 +957,375 @@ Visit each page and verify it loads:
|
|
|
957
957
|
|
|
958
958
|
---
|
|
959
959
|
|
|
960
|
+
## Phase 7: HRBAC Setup (Optional)
|
|
961
|
+
|
|
962
|
+
Hierarchical Role-Based Access Control (HRBAC) extends the standard RBAC with 7 hierarchical scope levels. This phase is optional - only complete it if you need scope-based access control.
|
|
963
|
+
|
|
964
|
+
### Step 7.1: Enable HRBAC in Configuration
|
|
965
|
+
|
|
966
|
+
Add to your `hazo_auth_config.ini`:
|
|
967
|
+
|
|
968
|
+
```ini
|
|
969
|
+
[hazo_auth__scope_hierarchy]
|
|
970
|
+
enable_hrbac = true
|
|
971
|
+
default_org = my_organization
|
|
972
|
+
scope_cache_ttl_minutes = 15
|
|
973
|
+
scope_cache_max_entries = 5000
|
|
974
|
+
|
|
975
|
+
# Optional: customize default labels for each scope level
|
|
976
|
+
default_label_l1 = Company
|
|
977
|
+
default_label_l2 = Division
|
|
978
|
+
default_label_l3 = Department
|
|
979
|
+
default_label_l4 = Team
|
|
980
|
+
default_label_l5 = Project
|
|
981
|
+
default_label_l6 = Sub-project
|
|
982
|
+
default_label_l7 = Task
|
|
983
|
+
```
|
|
984
|
+
|
|
985
|
+
### Step 7.2: Add HRBAC Permissions
|
|
986
|
+
|
|
987
|
+
Add the HRBAC management permissions to your `application_permission_list_defaults`:
|
|
988
|
+
|
|
989
|
+
```ini
|
|
990
|
+
[hazo_auth__user_management]
|
|
991
|
+
application_permission_list_defaults = admin_user_management,admin_role_management,admin_permission_management,admin_scope_hierarchy_management,admin_user_scope_assignment
|
|
992
|
+
```
|
|
993
|
+
|
|
994
|
+
### Step 7.3: Create HRBAC Database Tables
|
|
995
|
+
|
|
996
|
+
#### PostgreSQL
|
|
997
|
+
|
|
998
|
+
```sql
|
|
999
|
+
-- =============================================
|
|
1000
|
+
-- HRBAC Database Setup Script (PostgreSQL)
|
|
1001
|
+
-- =============================================
|
|
1002
|
+
|
|
1003
|
+
-- 1. Create scope types enum
|
|
1004
|
+
CREATE TYPE hazo_enum_scope_types AS ENUM (
|
|
1005
|
+
'hazo_scopes_l1',
|
|
1006
|
+
'hazo_scopes_l2',
|
|
1007
|
+
'hazo_scopes_l3',
|
|
1008
|
+
'hazo_scopes_l4',
|
|
1009
|
+
'hazo_scopes_l5',
|
|
1010
|
+
'hazo_scopes_l6',
|
|
1011
|
+
'hazo_scopes_l7'
|
|
1012
|
+
);
|
|
1013
|
+
|
|
1014
|
+
-- 2. Create sequence generator function for scope IDs
|
|
1015
|
+
CREATE OR REPLACE FUNCTION hazo_scope_id_generator(table_name TEXT)
|
|
1016
|
+
RETURNS TEXT AS $$
|
|
1017
|
+
DECLARE
|
|
1018
|
+
prefix TEXT;
|
|
1019
|
+
next_num INTEGER;
|
|
1020
|
+
result TEXT;
|
|
1021
|
+
BEGIN
|
|
1022
|
+
-- Extract level number from table name (e.g., 'hazo_scopes_l3' -> '3')
|
|
1023
|
+
prefix := 'L' || SUBSTRING(table_name FROM 'hazo_scopes_l([0-9]+)');
|
|
1024
|
+
|
|
1025
|
+
-- Get the next sequence number
|
|
1026
|
+
EXECUTE format(
|
|
1027
|
+
'SELECT COALESCE(MAX(CAST(SUBSTRING(seq FROM ''L[0-9]+_([0-9]+)'') AS INTEGER)), 0) + 1 FROM %I',
|
|
1028
|
+
table_name
|
|
1029
|
+
) INTO next_num;
|
|
1030
|
+
|
|
1031
|
+
-- Format as L{level}_{padded_number}
|
|
1032
|
+
result := prefix || '_' || LPAD(next_num::TEXT, 3, '0');
|
|
1033
|
+
|
|
1034
|
+
RETURN result;
|
|
1035
|
+
END;
|
|
1036
|
+
$$ LANGUAGE plpgsql;
|
|
1037
|
+
|
|
1038
|
+
-- 3. Create scope tables (L1 through L7)
|
|
1039
|
+
|
|
1040
|
+
-- Level 1 (top level - no parent)
|
|
1041
|
+
CREATE TABLE hazo_scopes_l1 (
|
|
1042
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
1043
|
+
seq TEXT NOT NULL DEFAULT hazo_scope_id_generator('hazo_scopes_l1'),
|
|
1044
|
+
org TEXT NOT NULL,
|
|
1045
|
+
name TEXT NOT NULL,
|
|
1046
|
+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
1047
|
+
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
1048
|
+
);
|
|
1049
|
+
CREATE INDEX idx_hazo_scopes_l1_org ON hazo_scopes_l1(org);
|
|
1050
|
+
CREATE INDEX idx_hazo_scopes_l1_seq ON hazo_scopes_l1(seq);
|
|
1051
|
+
|
|
1052
|
+
-- Level 2 (parent: L1)
|
|
1053
|
+
CREATE TABLE hazo_scopes_l2 (
|
|
1054
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
1055
|
+
seq TEXT NOT NULL DEFAULT hazo_scope_id_generator('hazo_scopes_l2'),
|
|
1056
|
+
org TEXT NOT NULL,
|
|
1057
|
+
name TEXT NOT NULL,
|
|
1058
|
+
parent_scope_id UUID REFERENCES hazo_scopes_l1(id) ON DELETE CASCADE,
|
|
1059
|
+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
1060
|
+
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
1061
|
+
);
|
|
1062
|
+
CREATE INDEX idx_hazo_scopes_l2_org ON hazo_scopes_l2(org);
|
|
1063
|
+
CREATE INDEX idx_hazo_scopes_l2_seq ON hazo_scopes_l2(seq);
|
|
1064
|
+
CREATE INDEX idx_hazo_scopes_l2_parent ON hazo_scopes_l2(parent_scope_id);
|
|
1065
|
+
|
|
1066
|
+
-- Level 3 (parent: L2)
|
|
1067
|
+
CREATE TABLE hazo_scopes_l3 (
|
|
1068
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
1069
|
+
seq TEXT NOT NULL DEFAULT hazo_scope_id_generator('hazo_scopes_l3'),
|
|
1070
|
+
org TEXT NOT NULL,
|
|
1071
|
+
name TEXT NOT NULL,
|
|
1072
|
+
parent_scope_id UUID REFERENCES hazo_scopes_l2(id) ON DELETE CASCADE,
|
|
1073
|
+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
1074
|
+
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
1075
|
+
);
|
|
1076
|
+
CREATE INDEX idx_hazo_scopes_l3_org ON hazo_scopes_l3(org);
|
|
1077
|
+
CREATE INDEX idx_hazo_scopes_l3_seq ON hazo_scopes_l3(seq);
|
|
1078
|
+
CREATE INDEX idx_hazo_scopes_l3_parent ON hazo_scopes_l3(parent_scope_id);
|
|
1079
|
+
|
|
1080
|
+
-- Level 4 (parent: L3)
|
|
1081
|
+
CREATE TABLE hazo_scopes_l4 (
|
|
1082
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
1083
|
+
seq TEXT NOT NULL DEFAULT hazo_scope_id_generator('hazo_scopes_l4'),
|
|
1084
|
+
org TEXT NOT NULL,
|
|
1085
|
+
name TEXT NOT NULL,
|
|
1086
|
+
parent_scope_id UUID REFERENCES hazo_scopes_l3(id) ON DELETE CASCADE,
|
|
1087
|
+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
1088
|
+
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
1089
|
+
);
|
|
1090
|
+
CREATE INDEX idx_hazo_scopes_l4_org ON hazo_scopes_l4(org);
|
|
1091
|
+
CREATE INDEX idx_hazo_scopes_l4_seq ON hazo_scopes_l4(seq);
|
|
1092
|
+
CREATE INDEX idx_hazo_scopes_l4_parent ON hazo_scopes_l4(parent_scope_id);
|
|
1093
|
+
|
|
1094
|
+
-- Level 5 (parent: L4)
|
|
1095
|
+
CREATE TABLE hazo_scopes_l5 (
|
|
1096
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
1097
|
+
seq TEXT NOT NULL DEFAULT hazo_scope_id_generator('hazo_scopes_l5'),
|
|
1098
|
+
org TEXT NOT NULL,
|
|
1099
|
+
name TEXT NOT NULL,
|
|
1100
|
+
parent_scope_id UUID REFERENCES hazo_scopes_l4(id) ON DELETE CASCADE,
|
|
1101
|
+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
1102
|
+
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
1103
|
+
);
|
|
1104
|
+
CREATE INDEX idx_hazo_scopes_l5_org ON hazo_scopes_l5(org);
|
|
1105
|
+
CREATE INDEX idx_hazo_scopes_l5_seq ON hazo_scopes_l5(seq);
|
|
1106
|
+
CREATE INDEX idx_hazo_scopes_l5_parent ON hazo_scopes_l5(parent_scope_id);
|
|
1107
|
+
|
|
1108
|
+
-- Level 6 (parent: L5)
|
|
1109
|
+
CREATE TABLE hazo_scopes_l6 (
|
|
1110
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
1111
|
+
seq TEXT NOT NULL DEFAULT hazo_scope_id_generator('hazo_scopes_l6'),
|
|
1112
|
+
org TEXT NOT NULL,
|
|
1113
|
+
name TEXT NOT NULL,
|
|
1114
|
+
parent_scope_id UUID REFERENCES hazo_scopes_l5(id) ON DELETE CASCADE,
|
|
1115
|
+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
1116
|
+
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
1117
|
+
);
|
|
1118
|
+
CREATE INDEX idx_hazo_scopes_l6_org ON hazo_scopes_l6(org);
|
|
1119
|
+
CREATE INDEX idx_hazo_scopes_l6_seq ON hazo_scopes_l6(seq);
|
|
1120
|
+
CREATE INDEX idx_hazo_scopes_l6_parent ON hazo_scopes_l6(parent_scope_id);
|
|
1121
|
+
|
|
1122
|
+
-- Level 7 (parent: L6)
|
|
1123
|
+
CREATE TABLE hazo_scopes_l7 (
|
|
1124
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
1125
|
+
seq TEXT NOT NULL DEFAULT hazo_scope_id_generator('hazo_scopes_l7'),
|
|
1126
|
+
org TEXT NOT NULL,
|
|
1127
|
+
name TEXT NOT NULL,
|
|
1128
|
+
parent_scope_id UUID REFERENCES hazo_scopes_l6(id) ON DELETE CASCADE,
|
|
1129
|
+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
1130
|
+
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
|
|
1131
|
+
);
|
|
1132
|
+
CREATE INDEX idx_hazo_scopes_l7_org ON hazo_scopes_l7(org);
|
|
1133
|
+
CREATE INDEX idx_hazo_scopes_l7_seq ON hazo_scopes_l7(seq);
|
|
1134
|
+
CREATE INDEX idx_hazo_scopes_l7_parent ON hazo_scopes_l7(parent_scope_id);
|
|
1135
|
+
|
|
1136
|
+
-- 4. Create user scopes junction table
|
|
1137
|
+
CREATE TABLE hazo_user_scopes (
|
|
1138
|
+
user_id UUID NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
|
|
1139
|
+
scope_id UUID NOT NULL,
|
|
1140
|
+
scope_seq TEXT NOT NULL,
|
|
1141
|
+
scope_type hazo_enum_scope_types NOT NULL,
|
|
1142
|
+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
1143
|
+
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
1144
|
+
PRIMARY KEY (user_id, scope_type, scope_id)
|
|
1145
|
+
);
|
|
1146
|
+
CREATE INDEX idx_hazo_user_scopes_user_id ON hazo_user_scopes(user_id);
|
|
1147
|
+
CREATE INDEX idx_hazo_user_scopes_scope_id ON hazo_user_scopes(scope_id);
|
|
1148
|
+
CREATE INDEX idx_hazo_user_scopes_scope_type ON hazo_user_scopes(scope_type);
|
|
1149
|
+
|
|
1150
|
+
-- 5. Create scope labels table
|
|
1151
|
+
CREATE TABLE hazo_scope_labels (
|
|
1152
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
1153
|
+
org TEXT NOT NULL,
|
|
1154
|
+
scope_type hazo_enum_scope_types NOT NULL,
|
|
1155
|
+
label TEXT NOT NULL,
|
|
1156
|
+
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
1157
|
+
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
|
1158
|
+
UNIQUE(org, scope_type)
|
|
1159
|
+
);
|
|
1160
|
+
CREATE INDEX idx_hazo_scope_labels_org ON hazo_scope_labels(org);
|
|
1161
|
+
```
|
|
1162
|
+
|
|
1163
|
+
#### PostgreSQL Grant Scripts
|
|
1164
|
+
|
|
1165
|
+
After creating the tables, grant appropriate permissions:
|
|
1166
|
+
|
|
1167
|
+
```sql
|
|
1168
|
+
-- Grant to your admin user (replace 'your_admin_user' with actual username)
|
|
1169
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes_l1 TO your_admin_user;
|
|
1170
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes_l2 TO your_admin_user;
|
|
1171
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes_l3 TO your_admin_user;
|
|
1172
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes_l4 TO your_admin_user;
|
|
1173
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes_l5 TO your_admin_user;
|
|
1174
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes_l6 TO your_admin_user;
|
|
1175
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes_l7 TO your_admin_user;
|
|
1176
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_user_scopes TO your_admin_user;
|
|
1177
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scope_labels TO your_admin_user;
|
|
1178
|
+
GRANT USAGE ON TYPE hazo_enum_scope_types TO your_admin_user;
|
|
1179
|
+
GRANT EXECUTE ON FUNCTION hazo_scope_id_generator(TEXT) TO your_admin_user;
|
|
1180
|
+
|
|
1181
|
+
-- For PostgREST authenticated role
|
|
1182
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes_l1 TO authenticated;
|
|
1183
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes_l2 TO authenticated;
|
|
1184
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes_l3 TO authenticated;
|
|
1185
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes_l4 TO authenticated;
|
|
1186
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes_l5 TO authenticated;
|
|
1187
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes_l6 TO authenticated;
|
|
1188
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scopes_l7 TO authenticated;
|
|
1189
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_user_scopes TO authenticated;
|
|
1190
|
+
GRANT ALL PRIVILEGES ON TABLE hazo_scope_labels TO authenticated;
|
|
1191
|
+
GRANT USAGE ON TYPE hazo_enum_scope_types TO authenticated;
|
|
1192
|
+
GRANT EXECUTE ON FUNCTION hazo_scope_id_generator(TEXT) TO authenticated;
|
|
1193
|
+
```
|
|
1194
|
+
|
|
1195
|
+
#### SQLite
|
|
1196
|
+
|
|
1197
|
+
```sql
|
|
1198
|
+
-- =============================================
|
|
1199
|
+
-- HRBAC Database Setup Script (SQLite)
|
|
1200
|
+
-- =============================================
|
|
1201
|
+
|
|
1202
|
+
-- Scope tables (L1 through L7)
|
|
1203
|
+
|
|
1204
|
+
CREATE TABLE IF NOT EXISTS hazo_scopes_l1 (
|
|
1205
|
+
id TEXT PRIMARY KEY,
|
|
1206
|
+
seq TEXT NOT NULL,
|
|
1207
|
+
org TEXT NOT NULL,
|
|
1208
|
+
name TEXT NOT NULL,
|
|
1209
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1210
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1211
|
+
);
|
|
1212
|
+
|
|
1213
|
+
CREATE TABLE IF NOT EXISTS hazo_scopes_l2 (
|
|
1214
|
+
id TEXT PRIMARY KEY,
|
|
1215
|
+
seq TEXT NOT NULL,
|
|
1216
|
+
org TEXT NOT NULL,
|
|
1217
|
+
name TEXT NOT NULL,
|
|
1218
|
+
parent_scope_id TEXT REFERENCES hazo_scopes_l1(id) ON DELETE CASCADE,
|
|
1219
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1220
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1221
|
+
);
|
|
1222
|
+
|
|
1223
|
+
CREATE TABLE IF NOT EXISTS hazo_scopes_l3 (
|
|
1224
|
+
id TEXT PRIMARY KEY,
|
|
1225
|
+
seq TEXT NOT NULL,
|
|
1226
|
+
org TEXT NOT NULL,
|
|
1227
|
+
name TEXT NOT NULL,
|
|
1228
|
+
parent_scope_id TEXT REFERENCES hazo_scopes_l2(id) ON DELETE CASCADE,
|
|
1229
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1230
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1231
|
+
);
|
|
1232
|
+
|
|
1233
|
+
CREATE TABLE IF NOT EXISTS hazo_scopes_l4 (
|
|
1234
|
+
id TEXT PRIMARY KEY,
|
|
1235
|
+
seq TEXT NOT NULL,
|
|
1236
|
+
org TEXT NOT NULL,
|
|
1237
|
+
name TEXT NOT NULL,
|
|
1238
|
+
parent_scope_id TEXT REFERENCES hazo_scopes_l3(id) ON DELETE CASCADE,
|
|
1239
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1240
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1241
|
+
);
|
|
1242
|
+
|
|
1243
|
+
CREATE TABLE IF NOT EXISTS hazo_scopes_l5 (
|
|
1244
|
+
id TEXT PRIMARY KEY,
|
|
1245
|
+
seq TEXT NOT NULL,
|
|
1246
|
+
org TEXT NOT NULL,
|
|
1247
|
+
name TEXT NOT NULL,
|
|
1248
|
+
parent_scope_id TEXT REFERENCES hazo_scopes_l4(id) ON DELETE CASCADE,
|
|
1249
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1250
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1251
|
+
);
|
|
1252
|
+
|
|
1253
|
+
CREATE TABLE IF NOT EXISTS hazo_scopes_l6 (
|
|
1254
|
+
id TEXT PRIMARY KEY,
|
|
1255
|
+
seq TEXT NOT NULL,
|
|
1256
|
+
org TEXT NOT NULL,
|
|
1257
|
+
name TEXT NOT NULL,
|
|
1258
|
+
parent_scope_id TEXT REFERENCES hazo_scopes_l5(id) ON DELETE CASCADE,
|
|
1259
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1260
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1261
|
+
);
|
|
1262
|
+
|
|
1263
|
+
CREATE TABLE IF NOT EXISTS hazo_scopes_l7 (
|
|
1264
|
+
id TEXT PRIMARY KEY,
|
|
1265
|
+
seq TEXT NOT NULL,
|
|
1266
|
+
org TEXT NOT NULL,
|
|
1267
|
+
name TEXT NOT NULL,
|
|
1268
|
+
parent_scope_id TEXT REFERENCES hazo_scopes_l6(id) ON DELETE CASCADE,
|
|
1269
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1270
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1271
|
+
);
|
|
1272
|
+
|
|
1273
|
+
-- User scopes junction table
|
|
1274
|
+
CREATE TABLE IF NOT EXISTS hazo_user_scopes (
|
|
1275
|
+
user_id TEXT NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
|
|
1276
|
+
scope_id TEXT NOT NULL,
|
|
1277
|
+
scope_seq TEXT NOT NULL,
|
|
1278
|
+
scope_type TEXT NOT NULL CHECK(scope_type IN ('hazo_scopes_l1','hazo_scopes_l2','hazo_scopes_l3','hazo_scopes_l4','hazo_scopes_l5','hazo_scopes_l6','hazo_scopes_l7')),
|
|
1279
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1280
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1281
|
+
PRIMARY KEY (user_id, scope_type, scope_id)
|
|
1282
|
+
);
|
|
1283
|
+
|
|
1284
|
+
-- Scope labels table
|
|
1285
|
+
CREATE TABLE IF NOT EXISTS hazo_scope_labels (
|
|
1286
|
+
id TEXT PRIMARY KEY,
|
|
1287
|
+
org TEXT NOT NULL,
|
|
1288
|
+
scope_type TEXT NOT NULL CHECK(scope_type IN ('hazo_scopes_l1','hazo_scopes_l2','hazo_scopes_l3','hazo_scopes_l4','hazo_scopes_l5','hazo_scopes_l6','hazo_scopes_l7')),
|
|
1289
|
+
label TEXT NOT NULL,
|
|
1290
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1291
|
+
changed_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1292
|
+
UNIQUE(org, scope_type)
|
|
1293
|
+
);
|
|
1294
|
+
```
|
|
1295
|
+
|
|
1296
|
+
### Step 7.4: Verify HRBAC Tables
|
|
1297
|
+
|
|
1298
|
+
#### PostgreSQL
|
|
1299
|
+
```sql
|
|
1300
|
+
SELECT table_name FROM information_schema.tables
|
|
1301
|
+
WHERE table_name LIKE 'hazo_scopes_%'
|
|
1302
|
+
OR table_name IN ('hazo_user_scopes', 'hazo_scope_labels');
|
|
1303
|
+
-- Expected: 9 tables (7 scope tables + user_scopes + scope_labels)
|
|
1304
|
+
```
|
|
1305
|
+
|
|
1306
|
+
#### SQLite
|
|
1307
|
+
```bash
|
|
1308
|
+
sqlite3 data/hazo_auth.sqlite ".tables" | grep -E "hazo_scopes|hazo_user_scopes|hazo_scope_labels"
|
|
1309
|
+
```
|
|
1310
|
+
|
|
1311
|
+
### Step 7.5: Test HRBAC
|
|
1312
|
+
|
|
1313
|
+
1. Start your dev server: `npm run dev`
|
|
1314
|
+
2. Log in with a user that has `admin_scope_hierarchy_management` permission
|
|
1315
|
+
3. Visit `/hazo_auth/user_management`
|
|
1316
|
+
4. Verify the "Scope Hierarchy", "Scope Labels", and "User Scopes" tabs appear
|
|
1317
|
+
5. Visit `/hazo_auth/scope_test` to test scope access checking
|
|
1318
|
+
|
|
1319
|
+
**HRBAC Checklist:**
|
|
1320
|
+
- [ ] `enable_hrbac = true` in config
|
|
1321
|
+
- [ ] HRBAC permissions added to defaults
|
|
1322
|
+
- [ ] All 9 HRBAC tables created
|
|
1323
|
+
- [ ] Grants applied (PostgreSQL)
|
|
1324
|
+
- [ ] HRBAC tabs visible in User Management
|
|
1325
|
+
- [ ] Scope test page works
|
|
1326
|
+
|
|
1327
|
+
---
|
|
1328
|
+
|
|
960
1329
|
## Troubleshooting
|
|
961
1330
|
|
|
962
1331
|
### Issue: Email not sending
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile_picture_library_tab.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/my_settings/components/profile_picture_library_tab.tsx"],"names":[],"mappings":"AAeA,MAAM,MAAM,6BAA6B,GAAG;IAC1C,UAAU,EAAE,OAAO,CAAC;IACpB,kBAAkB,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,uBAAuB,EAAE,MAAM,CAAC;IAChC,uBAAuB,EAAE,MAAM,CAAC;CACjC,CAAC;AAGF;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,QAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,GACxB,EAAE,6BAA6B,
|
|
1
|
+
{"version":3,"file":"profile_picture_library_tab.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/my_settings/components/profile_picture_library_tab.tsx"],"names":[],"mappings":"AAeA,MAAM,MAAM,6BAA6B,GAAG;IAC1C,UAAU,EAAE,OAAO,CAAC;IACpB,kBAAkB,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,uBAAuB,EAAE,MAAM,CAAC;IAChC,uBAAuB,EAAE,MAAM,CAAC;CACjC,CAAC;AAGF;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,QAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,GACxB,EAAE,6BAA6B,2CAyQ/B"}
|
|
@@ -128,9 +128,9 @@ export function ProfilePictureLibraryTab({ useLibrary, onUseLibraryChange, onPho
|
|
|
128
128
|
};
|
|
129
129
|
return (_jsxs("div", { className: "cls_profile_picture_library_tab flex flex-col gap-4", children: [_jsxs("div", { className: "cls_profile_picture_library_tab_switch flex items-center gap-3", children: [_jsx(Switch, { id: "use-library", checked: useLibrary, onCheckedChange: onUseLibraryChange, disabled: disabled, className: "cls_profile_picture_library_tab_switch_input", "aria-label": "Use library photo" }), _jsxs(Label, { htmlFor: "use-library", className: "cls_profile_picture_library_tab_switch_label text-sm font-medium text-[var(--hazo-text-secondary)] cursor-pointer", children: ["Use library photo", _jsx(HazoUITooltip, { message: libraryTooltipMessage, iconSize: tooltipIconSizeSmall, side: "top" })] })] }), _jsxs("div", { className: "cls_profile_picture_library_tab_content grid grid-cols-12 gap-4", children: [_jsxs("div", { className: "cls_profile_picture_library_tab_categories_container flex flex-col gap-2 col-span-3", children: [_jsx(Label, { className: "cls_profile_picture_library_tab_categories_label text-sm font-medium text-[var(--hazo-text-secondary)]", children: "Categories" }), loadingCategories ? (_jsx("div", { className: "cls_profile_picture_library_tab_loading flex items-center justify-center p-8 border border-[var(--hazo-border)] rounded-lg bg-[var(--hazo-bg-subtle)] min-h-[400px]", children: _jsx(Loader2, { className: "h-6 w-6 text-[var(--hazo-text-subtle)] animate-spin", "aria-hidden": "true" }) })) : categories.length > 0 ? (_jsx(VerticalTabs, { value: selectedCategory || categories[0], onValueChange: setSelectedCategory, className: "cls_profile_picture_library_tab_vertical_tabs", children: _jsx(VerticalTabsList, { className: "cls_profile_picture_library_tab_vertical_tabs_list w-full", children: categories.map((category) => (_jsx(VerticalTabsTrigger, { value: category, className: "cls_profile_picture_library_tab_vertical_tabs_trigger w-full justify-start", children: category }, category))) }) })) : (_jsx("div", { className: "cls_profile_picture_library_tab_no_categories flex items-center justify-center p-8 border border-[var(--hazo-border)] rounded-lg bg-[var(--hazo-bg-subtle)] min-h-[400px]", children: _jsx("p", { className: "cls_profile_picture_library_tab_no_categories_text text-sm text-[var(--hazo-text-muted)]", children: "No categories available" }) }))] }), _jsxs("div", { className: "cls_profile_picture_library_tab_photos_container flex flex-col gap-2 col-span-6", children: [_jsx(Label, { className: "cls_profile_picture_library_tab_photos_label text-sm font-medium text-[var(--hazo-text-secondary)]", children: "Photos" }), loadingPhotos ? (_jsx("div", { className: "cls_profile_picture_library_tab_photos_loading flex items-center justify-center p-8 border border-[var(--hazo-border)] rounded-lg bg-[var(--hazo-bg-subtle)] min-h-[400px]", children: _jsx(Loader2, { className: "h-6 w-6 text-[var(--hazo-text-subtle)] animate-spin", "aria-hidden": "true" }) })) : photos.length > 0 ? (_jsx("div", { className: `cls_profile_picture_library_tab_photos_grid grid ${getGridColumnsClass(libraryPhotoGridColumns)} gap-3 overflow-y-auto p-4 border border-[var(--hazo-border)] rounded-lg bg-[var(--hazo-bg-subtle)] min-h-[400px] max-h-[400px]`, children: photos.map((photoUrl) => (_jsx("button", { type: "button", onClick: () => handlePhotoClick(photoUrl), className: `
|
|
130
130
|
cls_profile_picture_library_tab_photo_thumbnail
|
|
131
|
-
aspect-square rounded-lg overflow-hidden border-2 transition-colors cursor-pointer
|
|
131
|
+
w-full aspect-square rounded-lg overflow-hidden border-2 transition-colors cursor-pointer
|
|
132
132
|
${selectedPhoto === photoUrl ? "border-blue-500 ring-2 ring-blue-200" : "border-[var(--hazo-border)] hover:border-[var(--hazo-border-emphasis)]"}
|
|
133
|
-
`, "aria-label": `Select photo ${photoUrl.split('/').pop()}`, children: _jsx("img", { src: photoUrl, alt: `Library photo ${photoUrl.split('/').pop()}`, className: "cls_profile_picture_library_tab_photo_thumbnail_image w-full h-full object-cover", loading: "lazy", onError: (e) => {
|
|
133
|
+
`, style: { minHeight: '80px', minWidth: '80px' }, "aria-label": `Select photo ${photoUrl.split('/').pop()}`, children: _jsx("img", { src: photoUrl, alt: `Library photo ${photoUrl.split('/').pop()}`, className: "cls_profile_picture_library_tab_photo_thumbnail_image w-full h-full object-cover", loading: "lazy", onError: (e) => {
|
|
134
134
|
// Fallback if image fails to load
|
|
135
135
|
const target = e.target;
|
|
136
136
|
target.style.display = 'none';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type RbacTestLayoutProps = {
|
|
2
|
+
className?: string;
|
|
3
|
+
/** Whether HRBAC is enabled (passed from server) */
|
|
4
|
+
hrbacEnabled?: boolean;
|
|
5
|
+
/** Default organization for HRBAC scopes */
|
|
6
|
+
defaultOrg?: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* RBAC/HRBAC Test layout component
|
|
10
|
+
* Allows testing permissions and scope access for different users
|
|
11
|
+
* @param props - Component props
|
|
12
|
+
* @returns RBAC test layout component
|
|
13
|
+
*/
|
|
14
|
+
export declare function RbacTestLayout({ className, hrbacEnabled, defaultOrg, }: RbacTestLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/rbac_test/index.tsx"],"names":[],"mappings":"AA2CA,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AA+GF;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,YAAoB,EACpB,UAAe,GAChB,EAAE,mBAAmB,2CAw3BrB"}
|