rbac-manager 0.0.0-stage → 1.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/.github/workflows/publish.yml +29 -0
- package/README.md +317 -2
- package/package.json +45 -4
- package/scripts/postbuild.js +17 -0
- package/src/config/rbac.config.ts +206 -0
- package/src/constants/actions.constants.ts +21 -0
- package/src/constants/apiKeys.constants.ts +25 -0
- package/src/constants/auth.constants.ts +39 -0
- package/src/constants/endpoints.constants.ts +66 -0
- package/src/constants/i18n.constants.ts +82 -0
- package/src/constants/index.ts +70 -0
- package/src/constants/masters.constants.ts +68 -0
- package/src/constants/permissions/index.ts +44 -0
- package/src/constants/permissions/masterPermissions.constants.ts +44 -0
- package/src/constants/permissions/rolePermissions.constants.ts +18 -0
- package/src/constants/permissions.constants.ts +34 -0
- package/src/constants/roles.constants.ts +34 -0
- package/src/core/adapters/authAdapter.ts +89 -0
- package/src/core/adapters/index.ts +17 -0
- package/src/core/adapters/mastersAdapter.ts +132 -0
- package/src/core/adapters/permissionsAdapter.ts +90 -0
- package/src/core/adapters/rolesAdapter.ts +115 -0
- package/src/core/api/httpClient.ts +296 -0
- package/src/core/context/PermissionContext.tsx +232 -0
- package/src/core/context/RBACConfigContext.tsx +52 -0
- package/src/core/guards/Can.tsx +98 -0
- package/src/core/guards/RouteGuard.tsx +42 -0
- package/src/core/hooks/useMaster.ts +99 -0
- package/src/core/hooks/usePermissions.ts +114 -0
- package/src/core/hooks/useRoles.ts +120 -0
- package/src/core/types/adapter.types.ts +54 -0
- package/src/core/types/auth.types.ts +44 -0
- package/src/core/types/index.ts +7 -0
- package/src/core/types/masters.types.ts +63 -0
- package/src/core/types/pagination.types.ts +37 -0
- package/src/core/types/rbac.types.ts +69 -0
- package/src/core/types/router.types.ts +43 -0
- package/src/core/types/style.types.ts +53 -0
- package/src/core/utils/permissionResolver.ts +44 -0
- package/src/index.ts +44 -0
- package/src/modules/masters/DepartmentMasterView.tsx +126 -0
- package/src/modules/masters/DesignationMasterView.tsx +97 -0
- package/src/modules/masters/EmployeeMasterView.tsx +107 -0
- package/src/modules/masters/EntityMasterView.tsx +102 -0
- package/src/modules/masters/ModuleMasterView.tsx +104 -0
- package/src/modules/masters/SubModuleMasterView.tsx +106 -0
- package/src/modules/masters/components/MasterDataTable.tsx +684 -0
- package/src/modules/masters/index.ts +7 -0
- package/src/modules/roles-and-permissions/components/PermissionMatrix.tsx +289 -0
- package/src/modules/roles-and-permissions/components/PermissionRegistry.tsx +108 -0
- package/src/modules/roles-and-permissions/components/RoleListTable.tsx +568 -0
- package/src/modules/roles-and-permissions/components/RoleModal.tsx +213 -0
- package/src/modules/roles-and-permissions/index.ts +4 -0
- package/src/shared/components/Badge.tsx +24 -0
- package/src/shared/components/Button.tsx +75 -0
- package/src/shared/components/DynamicSidebar.tsx +181 -0
- package/src/shared/components/Input.tsx +48 -0
- package/src/shared/components/Modal.tsx +70 -0
- package/src/shared/components/Table.tsx +345 -0
- package/src/styles/standalone.css +51 -0
- package/src/theme/ThemeContext.tsx +74 -0
- package/src/theme/defaultTheme.ts +81 -0
- package/src/theme/index.ts +3 -0
- package/src/theme/theme.types.ts +106 -0
- package/tsconfig.cjs.json +10 -0
- package/tsconfig.esm.json +10 -0
- package/tsconfig.json +28 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { useState, useCallback } from 'react';
|
|
2
|
+
import { useRBACConfig } from '../context/RBACConfigContext';
|
|
3
|
+
import { StandardRole, PaginatedResult, RoleFormData } from '../types';
|
|
4
|
+
import { buildPaginationQueryParams } from '../types/pagination.types';
|
|
5
|
+
|
|
6
|
+
export function useRoles() {
|
|
7
|
+
const { config, http } = useRBACConfig();
|
|
8
|
+
const [roles, setRoles] = useState<StandardRole[]>([]);
|
|
9
|
+
const [total, setTotal] = useState<number>(0);
|
|
10
|
+
const [page, setPage] = useState<number>(1);
|
|
11
|
+
const [limit, setLimit] = useState<number>(10);
|
|
12
|
+
const [isLoading, setIsLoading] = useState<boolean>(false);
|
|
13
|
+
const [error, setError] = useState<Error | null>(null);
|
|
14
|
+
|
|
15
|
+
const fetchRoles = useCallback(
|
|
16
|
+
async (params?: { page?: number; limit?: number; search?: string; sortBy?: string; sortOrder?: 'asc' | 'desc'; [key: string]: any }) => {
|
|
17
|
+
setIsLoading(true);
|
|
18
|
+
setError(null);
|
|
19
|
+
try {
|
|
20
|
+
const targetPage = params?.page ?? page;
|
|
21
|
+
const targetLimit = params?.limit ?? limit;
|
|
22
|
+
|
|
23
|
+
const pagParams = buildPaginationQueryParams(targetPage, targetLimit, config.pagination);
|
|
24
|
+
const queryParams = {
|
|
25
|
+
...pagParams,
|
|
26
|
+
...(params || {}),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const raw = await http.get(config.endpoints.ROLES_LIST, queryParams);
|
|
30
|
+
const result: PaginatedResult<StandardRole> = config.adapters.roles.transformRoleListResponse(raw);
|
|
31
|
+
|
|
32
|
+
setRoles(result.items);
|
|
33
|
+
setTotal(result.total);
|
|
34
|
+
setPage(result.page);
|
|
35
|
+
setLimit(result.limit);
|
|
36
|
+
return result;
|
|
37
|
+
} catch (err: any) {
|
|
38
|
+
setError(err);
|
|
39
|
+
throw err;
|
|
40
|
+
} finally {
|
|
41
|
+
setIsLoading(false);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
[config.adapters.roles, config.endpoints.ROLES_LIST, config.pagination, http, limit, page]
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const fetchRoleDetails = useCallback(
|
|
48
|
+
async (id: string | number) => {
|
|
49
|
+
const endpoint = config.endpoints.ROLES_DETAILS.replace(':id', String(id));
|
|
50
|
+
const raw = await http.get(endpoint);
|
|
51
|
+
return config.adapters.roles.transformRoleDetailsResponse(raw);
|
|
52
|
+
},
|
|
53
|
+
[config.adapters.roles, config.endpoints.ROLES_DETAILS, http]
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const createRole = useCallback(
|
|
57
|
+
async (formData: RoleFormData) => {
|
|
58
|
+
const payload = config.adapters.roles.transformCreateRolePayload(formData);
|
|
59
|
+
const raw = await http.post(config.endpoints.ROLES_CREATE, payload);
|
|
60
|
+
await fetchRoles();
|
|
61
|
+
return raw;
|
|
62
|
+
},
|
|
63
|
+
[config.adapters.roles, config.endpoints.ROLES_CREATE, fetchRoles, http]
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const editRole = useCallback(
|
|
67
|
+
async (id: string | number, formData: Partial<RoleFormData>) => {
|
|
68
|
+
const endpoint = config.endpoints.ROLES_EDIT.replace(':id', String(id));
|
|
69
|
+
const payload = config.adapters.roles.transformEditRolePayload(formData);
|
|
70
|
+
const raw = await http.patch(endpoint, payload);
|
|
71
|
+
await fetchRoles();
|
|
72
|
+
return raw;
|
|
73
|
+
},
|
|
74
|
+
[config.adapters.roles, config.endpoints.ROLES_EDIT, fetchRoles, http]
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const deleteRole = useCallback(
|
|
78
|
+
async (id: string | number) => {
|
|
79
|
+
const endpoint = config.endpoints.ROLES_DELETE.replace(':id', String(id));
|
|
80
|
+
const raw = await http.delete(endpoint);
|
|
81
|
+
await fetchRoles();
|
|
82
|
+
return raw;
|
|
83
|
+
},
|
|
84
|
+
[config.endpoints.ROLES_DELETE, fetchRoles, http]
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const fetchRolePermissions = useCallback(
|
|
88
|
+
async (roleId: string | number): Promise<(string | number)[]> => {
|
|
89
|
+
const endpoint = config.endpoints.ROLES_GET_PERMISSIONS.replace(':id', String(roleId));
|
|
90
|
+
const raw = await http.get(endpoint);
|
|
91
|
+
return config.adapters.roles.transformRolePermissionsResponse(raw);
|
|
92
|
+
},
|
|
93
|
+
[config.adapters.roles, config.endpoints.ROLES_GET_PERMISSIONS, http]
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const assignPermissions = useCallback(
|
|
97
|
+
async (roleId: string | number, permissionActionIds: (string | number)[]) => {
|
|
98
|
+
const endpoint = config.endpoints.ROLES_ASSIGN_PERMISSIONS.replace(':id', String(roleId));
|
|
99
|
+
const payload = config.adapters.roles.transformAssignPermissionsPayload(roleId, permissionActionIds);
|
|
100
|
+
return http.post(endpoint, payload);
|
|
101
|
+
},
|
|
102
|
+
[config.adapters.roles, config.endpoints.ROLES_ASSIGN_PERMISSIONS, http]
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
roles,
|
|
107
|
+
total,
|
|
108
|
+
page,
|
|
109
|
+
limit,
|
|
110
|
+
isLoading,
|
|
111
|
+
error,
|
|
112
|
+
fetchRoles,
|
|
113
|
+
fetchRoleDetails,
|
|
114
|
+
createRole,
|
|
115
|
+
editRole,
|
|
116
|
+
deleteRole,
|
|
117
|
+
fetchRolePermissions,
|
|
118
|
+
assignPermissions,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { StandardAuthMeData, StandardUser, LoginCredentials } from './auth.types';
|
|
2
|
+
import { StandardRole, StandardModuleWithActions, StandardAction, RoleFormData } from './rbac.types';
|
|
3
|
+
import {
|
|
4
|
+
StandardEntityMaster,
|
|
5
|
+
StandardDepartmentMaster,
|
|
6
|
+
StandardDesignationMaster,
|
|
7
|
+
StandardEmployeeMaster,
|
|
8
|
+
StandardModuleMasterItem,
|
|
9
|
+
} from './masters.types';
|
|
10
|
+
|
|
11
|
+
export interface PaginatedResult<T> {
|
|
12
|
+
items: T[];
|
|
13
|
+
total: number;
|
|
14
|
+
page: number;
|
|
15
|
+
limit: number;
|
|
16
|
+
totalPages?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface AuthAdapter {
|
|
20
|
+
transformLoginPayload: (credentials: LoginCredentials) => Record<string, any>;
|
|
21
|
+
transformLoginResponse: (raw: any) => { success: boolean; user?: Partial<StandardUser>; token?: string; message?: string };
|
|
22
|
+
transformAuthMeResponse: (raw: any) => StandardAuthMeData;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface RolesAdapter {
|
|
26
|
+
transformRoleListResponse: (raw: any) => PaginatedResult<StandardRole>;
|
|
27
|
+
transformRoleDetailsResponse: (raw: any) => StandardRole;
|
|
28
|
+
transformCreateRolePayload: (data: RoleFormData) => Record<string, any>;
|
|
29
|
+
transformEditRolePayload: (data: Partial<RoleFormData>) => Record<string, any>;
|
|
30
|
+
transformRolePermissionsResponse: (raw: any) => (string | number)[];
|
|
31
|
+
transformAssignPermissionsPayload: (roleId: string | number, permissionActionIds: (string | number)[]) => Record<string, any>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface PermissionsAdapter {
|
|
35
|
+
transformActionsListResponse: (raw: any) => StandardAction[];
|
|
36
|
+
transformRegistryResponse: (raw: any) => PaginatedResult<StandardModuleWithActions>;
|
|
37
|
+
transformModuleParentsResponse: (raw: any) => PaginatedResult<StandardModuleWithActions>;
|
|
38
|
+
transformModuleSubmodulesResponse: (raw: any) => PaginatedResult<StandardModuleWithActions>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface MastersAdapter {
|
|
42
|
+
transformEntityListResponse: (raw: any) => PaginatedResult<StandardEntityMaster>;
|
|
43
|
+
transformDepartmentListResponse: (raw: any) => PaginatedResult<StandardDepartmentMaster>;
|
|
44
|
+
transformDesignationListResponse: (raw: any) => PaginatedResult<StandardDesignationMaster>;
|
|
45
|
+
transformEmployeeListResponse: (raw: any) => PaginatedResult<StandardEmployeeMaster>;
|
|
46
|
+
transformModuleMasterListResponse: (raw: any) => PaginatedResult<StandardModuleMasterItem>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface RBACAdapters {
|
|
50
|
+
auth: AuthAdapter;
|
|
51
|
+
roles: RolesAdapter;
|
|
52
|
+
permissions: PermissionsAdapter;
|
|
53
|
+
masters: MastersAdapter;
|
|
54
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface StandardUser {
|
|
2
|
+
id: string | number;
|
|
3
|
+
email: string;
|
|
4
|
+
firstName?: string;
|
|
5
|
+
lastName?: string;
|
|
6
|
+
fullName: string;
|
|
7
|
+
mobileNumber?: string;
|
|
8
|
+
entityId?: string | number | null;
|
|
9
|
+
departmentId?: string | number | null;
|
|
10
|
+
role: {
|
|
11
|
+
id: string | number;
|
|
12
|
+
name: string;
|
|
13
|
+
key: string;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface StandardPermissionItem {
|
|
18
|
+
permissionKey: string;
|
|
19
|
+
routePath?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface StandardNavigationItem {
|
|
23
|
+
id: string | number;
|
|
24
|
+
name: string;
|
|
25
|
+
slug: string;
|
|
26
|
+
routePath?: string;
|
|
27
|
+
sortOrder: number;
|
|
28
|
+
parentId: string | number;
|
|
29
|
+
children: StandardNavigationItem[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface StandardAuthMeData {
|
|
33
|
+
user: StandardUser;
|
|
34
|
+
permissions: StandardPermissionItem[];
|
|
35
|
+
navigation: StandardNavigationItem[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface LoginCredentials {
|
|
39
|
+
email: string;
|
|
40
|
+
password?: string;
|
|
41
|
+
mobileNumber?: string;
|
|
42
|
+
otp?: string;
|
|
43
|
+
[key: string]: any;
|
|
44
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export interface StandardEntityMaster {
|
|
2
|
+
id: string | number;
|
|
3
|
+
name: string;
|
|
4
|
+
code?: string;
|
|
5
|
+
state?: string;
|
|
6
|
+
city?: string;
|
|
7
|
+
pincode?: string;
|
|
8
|
+
isActive: boolean;
|
|
9
|
+
createdAt?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface StandardDepartmentMaster {
|
|
13
|
+
id: string | number;
|
|
14
|
+
name: string;
|
|
15
|
+
code?: string;
|
|
16
|
+
entityId?: string | number | null;
|
|
17
|
+
entityName?: string | null;
|
|
18
|
+
isActive: boolean;
|
|
19
|
+
createdAt?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface StandardDesignationMaster {
|
|
23
|
+
id: string | number;
|
|
24
|
+
name: string;
|
|
25
|
+
code?: string;
|
|
26
|
+
departmentId?: string | number | null;
|
|
27
|
+
departmentName?: string | null;
|
|
28
|
+
isActive: boolean;
|
|
29
|
+
createdAt?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface StandardEmployeeMaster {
|
|
33
|
+
id: string | number;
|
|
34
|
+
employeeCode?: string;
|
|
35
|
+
firstName: string;
|
|
36
|
+
lastName: string;
|
|
37
|
+
fullName: string;
|
|
38
|
+
email: string;
|
|
39
|
+
mobileNumber?: string;
|
|
40
|
+
entityId?: string | number | null;
|
|
41
|
+
entityName?: string | null;
|
|
42
|
+
departmentId?: string | number | null;
|
|
43
|
+
departmentName?: string | null;
|
|
44
|
+
designationId?: string | number | null;
|
|
45
|
+
designationName?: string | null;
|
|
46
|
+
reportingManagerId?: string | number | null;
|
|
47
|
+
roleId?: string | number | null;
|
|
48
|
+
roleName?: string | null;
|
|
49
|
+
isActive: boolean;
|
|
50
|
+
createdAt?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface StandardModuleMasterItem {
|
|
54
|
+
id: string | number;
|
|
55
|
+
name: string;
|
|
56
|
+
slug: string;
|
|
57
|
+
routePath?: string | null;
|
|
58
|
+
sortOrder: number;
|
|
59
|
+
parentId: string | number;
|
|
60
|
+
parentName?: string | null;
|
|
61
|
+
isActive: boolean;
|
|
62
|
+
createdAt?: string;
|
|
63
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface PaginationConfig {
|
|
2
|
+
pageIndexOffset?: 0 | 1; // 1 for 1-based (default), 0 for 0-based (Spring Boot, etc.)
|
|
3
|
+
pageParamName?: string; // e.g. 'page' or 'pageNumber' or 'pageIndex'
|
|
4
|
+
limitParamName?: string; // e.g. 'limit' or 'size' or 'pageSize'
|
|
5
|
+
useOffsetLimit?: boolean;// If true, sends offset and limit instead of page and limit
|
|
6
|
+
offsetParamName?: string;// e.g. 'offset' or 'skip'
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const defaultPaginationConfig: Required<PaginationConfig> = {
|
|
10
|
+
pageIndexOffset: 1,
|
|
11
|
+
pageParamName: 'page',
|
|
12
|
+
limitParamName: 'limit',
|
|
13
|
+
useOffsetLimit: false,
|
|
14
|
+
offsetParamName: 'offset',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function buildPaginationQueryParams(
|
|
18
|
+
page: number,
|
|
19
|
+
limit: number,
|
|
20
|
+
config?: PaginationConfig
|
|
21
|
+
): Record<string, number> {
|
|
22
|
+
const cfg = { ...defaultPaginationConfig, ...(config || {}) };
|
|
23
|
+
|
|
24
|
+
if (cfg.useOffsetLimit) {
|
|
25
|
+
const offset = Math.max(0, (page - 1) * limit);
|
|
26
|
+
return {
|
|
27
|
+
[cfg.offsetParamName]: offset,
|
|
28
|
+
[cfg.limitParamName]: limit,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const backendPage = cfg.pageIndexOffset === 0 ? Math.max(0, page - 1) : page;
|
|
33
|
+
return {
|
|
34
|
+
[cfg.pageParamName]: backendPage,
|
|
35
|
+
[cfg.limitParamName]: limit,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export interface StandardAction {
|
|
2
|
+
id: string | number;
|
|
3
|
+
name: string;
|
|
4
|
+
key: string;
|
|
5
|
+
isActive: boolean;
|
|
6
|
+
sortOrder?: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface StandardRole {
|
|
10
|
+
id: string | number;
|
|
11
|
+
name: string;
|
|
12
|
+
key: string;
|
|
13
|
+
description?: string | null;
|
|
14
|
+
isActive: boolean;
|
|
15
|
+
entityId?: string | number | null;
|
|
16
|
+
entityName?: string | null;
|
|
17
|
+
departmentId?: string | number | null;
|
|
18
|
+
departmentName?: string | null;
|
|
19
|
+
createdAt?: string;
|
|
20
|
+
updatedAt?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface StandardPermissionActionMapping {
|
|
24
|
+
permissionActionId: string | number;
|
|
25
|
+
moduleId: string | number;
|
|
26
|
+
actionId: string | number;
|
|
27
|
+
permissionKey: string;
|
|
28
|
+
routePath?: string | null;
|
|
29
|
+
description?: string | null;
|
|
30
|
+
sortOrder?: number;
|
|
31
|
+
actionDetails: StandardAction;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface StandardModuleWithActions {
|
|
35
|
+
id: string | number;
|
|
36
|
+
name: string;
|
|
37
|
+
slug: string;
|
|
38
|
+
routePath?: string | null;
|
|
39
|
+
sortOrder: number;
|
|
40
|
+
parentId: string | number;
|
|
41
|
+
isActive: boolean;
|
|
42
|
+
actions: StandardPermissionActionMapping[];
|
|
43
|
+
children?: StandardModuleWithActions[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface RolePermissionMatrixRow {
|
|
47
|
+
moduleId: string | number;
|
|
48
|
+
moduleName: string;
|
|
49
|
+
slug: string;
|
|
50
|
+
parentId: string | number;
|
|
51
|
+
level: number;
|
|
52
|
+
actions: {
|
|
53
|
+
actionKey: string;
|
|
54
|
+
actionName: string;
|
|
55
|
+
actionId: string | number;
|
|
56
|
+
permissionActionId: string | number;
|
|
57
|
+
permissionKey: string;
|
|
58
|
+
isAssigned: boolean;
|
|
59
|
+
}[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface RoleFormData {
|
|
63
|
+
role_name: string;
|
|
64
|
+
role_key: string;
|
|
65
|
+
description?: string;
|
|
66
|
+
entityId?: string | number | null;
|
|
67
|
+
departmentId?: string | number | null;
|
|
68
|
+
is_active?: boolean;
|
|
69
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
export interface RouterAdapter {
|
|
4
|
+
navigate: (path: string) => void;
|
|
5
|
+
renderLink?: (props: { href: string; className?: string; children: React.ReactNode }) => React.ReactNode;
|
|
6
|
+
currentPath?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates a router adapter for Next.js App Router or Pages Router
|
|
11
|
+
* Usage:
|
|
12
|
+
* createNextRouterAdapter(useRouter(), Link)
|
|
13
|
+
*/
|
|
14
|
+
export function createNextRouterAdapter(
|
|
15
|
+
router: { push: (url: string) => void },
|
|
16
|
+
LinkComponent?: React.ComponentType<any>
|
|
17
|
+
): RouterAdapter {
|
|
18
|
+
return {
|
|
19
|
+
navigate: (path: string) => router.push(path),
|
|
20
|
+
renderLink: LinkComponent
|
|
21
|
+
? ({ href, className, children }) =>
|
|
22
|
+
React.createElement(LinkComponent, { href, className }, children)
|
|
23
|
+
: undefined,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Creates a router adapter for React Router (v5/v6)
|
|
29
|
+
* Usage:
|
|
30
|
+
* createReactRouterAdapter(useNavigate(), Link)
|
|
31
|
+
*/
|
|
32
|
+
export function createReactRouterAdapter(
|
|
33
|
+
navigateFn: (path: string) => void,
|
|
34
|
+
LinkComponent?: React.ComponentType<any>
|
|
35
|
+
): RouterAdapter {
|
|
36
|
+
return {
|
|
37
|
+
navigate: (path: string) => navigateFn(path),
|
|
38
|
+
renderLink: LinkComponent
|
|
39
|
+
? ({ href, className, children }) =>
|
|
40
|
+
React.createElement(LinkComponent, { to: href, className }, children)
|
|
41
|
+
: undefined,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export interface TableClassNames {
|
|
2
|
+
container?: string;
|
|
3
|
+
table?: string;
|
|
4
|
+
thead?: string;
|
|
5
|
+
th?: string;
|
|
6
|
+
tbody?: string;
|
|
7
|
+
tr?: string;
|
|
8
|
+
td?: string;
|
|
9
|
+
empty?: string;
|
|
10
|
+
pagination?: {
|
|
11
|
+
container?: string;
|
|
12
|
+
info?: string;
|
|
13
|
+
buttons?: string;
|
|
14
|
+
pageText?: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface MasterDataTableClassNames {
|
|
19
|
+
root?: string;
|
|
20
|
+
header?: {
|
|
21
|
+
container?: string;
|
|
22
|
+
title?: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
addButton?: string;
|
|
25
|
+
};
|
|
26
|
+
search?: {
|
|
27
|
+
container?: string;
|
|
28
|
+
input?: string;
|
|
29
|
+
};
|
|
30
|
+
table?: TableClassNames;
|
|
31
|
+
modal?: {
|
|
32
|
+
backdrop?: string;
|
|
33
|
+
container?: string;
|
|
34
|
+
header?: string;
|
|
35
|
+
body?: string;
|
|
36
|
+
footer?: string;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface RoleListTableClassNames {
|
|
41
|
+
root?: string;
|
|
42
|
+
header?: {
|
|
43
|
+
container?: string;
|
|
44
|
+
title?: string;
|
|
45
|
+
description?: string;
|
|
46
|
+
createButton?: string;
|
|
47
|
+
};
|
|
48
|
+
search?: {
|
|
49
|
+
container?: string;
|
|
50
|
+
input?: string;
|
|
51
|
+
};
|
|
52
|
+
table?: TableClassNames;
|
|
53
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { PERMISSION_KEYS } from '../../constants/permissions';
|
|
2
|
+
|
|
3
|
+
export type PermissionKeyResolverFn = (moduleKey: string, actionKey: string) => string;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Default resolver produces: `<module>.<action>` (e.g. "roles.add", "department_master.view")
|
|
7
|
+
*/
|
|
8
|
+
export const defaultPermissionResolver: PermissionKeyResolverFn = (moduleKey: string, actionKey: string): string => {
|
|
9
|
+
// Check if defined in PERMISSION_KEYS container
|
|
10
|
+
if (moduleKey === 'roles') {
|
|
11
|
+
const act = actionKey.toUpperCase() as keyof typeof PERMISSION_KEYS.roles;
|
|
12
|
+
if (PERMISSION_KEYS.roles[act]) return PERMISSION_KEYS.roles[act];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const masterModule = PERMISSION_KEYS.masters[moduleKey as keyof typeof PERMISSION_KEYS.masters];
|
|
16
|
+
if (masterModule) {
|
|
17
|
+
const act = actionKey.toUpperCase() as keyof typeof masterModule;
|
|
18
|
+
if (masterModule[act]) return masterModule[act];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return `${moduleKey}.${actionKey}`;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Resolves a permission string, checking alias maps if present
|
|
26
|
+
*/
|
|
27
|
+
export function resolvePermission(
|
|
28
|
+
input: { permissionKey?: string; module?: string; action?: string },
|
|
29
|
+
resolver: PermissionKeyResolverFn = defaultPermissionResolver,
|
|
30
|
+
aliasMap: Record<string, string> = {}
|
|
31
|
+
): string {
|
|
32
|
+
let resolved = input.permissionKey || '';
|
|
33
|
+
|
|
34
|
+
if (!resolved && input.module && input.action) {
|
|
35
|
+
resolved = resolver(input.module, input.action);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Check alias override if configured
|
|
39
|
+
if (resolved && aliasMap[resolved]) {
|
|
40
|
+
return aliasMap[resolved];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return resolved;
|
|
44
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Central Constants & Customization
|
|
2
|
+
export * from './constants';
|
|
3
|
+
export * from './constants/permissions';
|
|
4
|
+
|
|
5
|
+
// Configuration
|
|
6
|
+
export * from './config/rbac.config';
|
|
7
|
+
|
|
8
|
+
// Theming & UI Styling Customization
|
|
9
|
+
export * from './theme';
|
|
10
|
+
|
|
11
|
+
// Core Types
|
|
12
|
+
export * from './core/types';
|
|
13
|
+
|
|
14
|
+
// API Adapters & Transformers
|
|
15
|
+
export * from './core/adapters';
|
|
16
|
+
export * from './core/api/httpClient';
|
|
17
|
+
|
|
18
|
+
// Contexts & State
|
|
19
|
+
export * from './core/context/RBACConfigContext';
|
|
20
|
+
export * from './core/context/PermissionContext';
|
|
21
|
+
|
|
22
|
+
// Access Control Guards & Resolvers
|
|
23
|
+
export * from './core/guards/Can';
|
|
24
|
+
export * from './core/guards/RouteGuard';
|
|
25
|
+
export * from './core/utils/permissionResolver';
|
|
26
|
+
|
|
27
|
+
// Hooks
|
|
28
|
+
export * from './core/hooks/useRoles';
|
|
29
|
+
export * from './core/hooks/usePermissions';
|
|
30
|
+
export * from './core/hooks/useMaster';
|
|
31
|
+
|
|
32
|
+
// Shared UI Components
|
|
33
|
+
export * from './shared/components/Button';
|
|
34
|
+
export * from './shared/components/Input';
|
|
35
|
+
export * from './shared/components/Modal';
|
|
36
|
+
export * from './shared/components/Badge';
|
|
37
|
+
export * from './shared/components/Table';
|
|
38
|
+
export * from './shared/components/DynamicSidebar';
|
|
39
|
+
|
|
40
|
+
// Roles & Permissions Module
|
|
41
|
+
export * from './modules/roles-and-permissions';
|
|
42
|
+
|
|
43
|
+
// Masters Module
|
|
44
|
+
export * from './modules/masters';
|