create-lego-one 2.0.10 → 2.0.12
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/index.cjs +145 -0
- package/dist/index.cjs.map +1 -1
- package/package.json +5 -3
- package/template/host/e2e/auth.spec.ts +38 -0
- package/template/host/e2e/layout.spec.ts +38 -0
- package/template/host/modern.config.ts +19 -0
- package/template/host/package.json +71 -0
- package/template/host/playwright.config.ts +34 -0
- package/template/host/postcss.config.mjs +6 -0
- package/template/host/src/App.tsx +6 -0
- package/template/host/src/bootstrap.tsx +74 -0
- package/template/host/src/global.css +59 -0
- package/template/host/src/index.ts +2 -0
- package/template/host/src/kernel/__tests__/lib-utils.test.ts +32 -0
- package/template/host/src/kernel/__tests__/rbac-hooks.test.tsx +114 -0
- package/template/host/src/kernel/__tests__/rbac-utils.test.ts +108 -0
- package/template/host/src/kernel/auth/ProtectedRoute.tsx +41 -0
- package/template/host/src/kernel/auth/components/LoginForm.tsx +97 -0
- package/template/host/src/kernel/auth/components/LogoutButton.tsx +79 -0
- package/template/host/src/kernel/auth/hooks.ts +174 -0
- package/template/host/src/kernel/auth/index.ts +5 -0
- package/template/host/src/kernel/auth/schemas.ts +27 -0
- package/template/host/src/kernel/auth/service.ts +197 -0
- package/template/host/src/kernel/auth/types.ts +36 -0
- package/template/host/src/kernel/channels/ChannelBus.ts +181 -0
- package/template/host/src/kernel/channels/ChannelProvider.tsx +57 -0
- package/template/host/src/kernel/channels/events.ts +27 -0
- package/template/host/src/kernel/channels/hooks.ts +168 -0
- package/template/host/src/kernel/channels/index.ts +6 -0
- package/template/host/src/kernel/channels/integrations/ToastIntegration.tsx +60 -0
- package/template/host/src/kernel/channels/plugin-hooks.ts +72 -0
- package/template/host/src/kernel/channels/types.ts +112 -0
- package/template/host/src/kernel/components/__tests__/Badge.test.tsx +35 -0
- package/template/host/src/kernel/components/__tests__/Button.test.tsx +63 -0
- package/template/host/src/kernel/components/__tests__/Input.test.tsx +64 -0
- package/template/host/src/kernel/components/index.ts +32 -0
- package/template/host/src/kernel/components/ui/alert.tsx +58 -0
- package/template/host/src/kernel/components/ui/avatar.tsx +47 -0
- package/template/host/src/kernel/components/ui/badge.tsx +35 -0
- package/template/host/src/kernel/components/ui/button.tsx +50 -0
- package/template/host/src/kernel/components/ui/card.tsx +78 -0
- package/template/host/src/kernel/components/ui/dialog.tsx +116 -0
- package/template/host/src/kernel/components/ui/dropdown-menu.tsx +192 -0
- package/template/host/src/kernel/components/ui/index.ts +7 -0
- package/template/host/src/kernel/components/ui/input.tsx +24 -0
- package/template/host/src/kernel/components/ui/label.tsx +21 -0
- package/template/host/src/kernel/components/ui/popover.tsx +28 -0
- package/template/host/src/kernel/components/ui/progress.tsx +25 -0
- package/template/host/src/kernel/components/ui/scroll-area.tsx +45 -0
- package/template/host/src/kernel/components/ui/select.tsx +155 -0
- package/template/host/src/kernel/components/ui/separator.tsx +28 -0
- package/template/host/src/kernel/components/ui/skeleton.tsx +15 -0
- package/template/host/src/kernel/components/ui/switch.tsx +26 -0
- package/template/host/src/kernel/components/ui/table.tsx +116 -0
- package/template/host/src/kernel/components/ui/tabs.tsx +52 -0
- package/template/host/src/kernel/components/ui/toast.tsx +126 -0
- package/template/host/src/kernel/components/ui/toaster.tsx +34 -0
- package/template/host/src/kernel/components/ui/tooltip.tsx +27 -0
- package/template/host/src/kernel/components/ui/use-toast.ts +183 -0
- package/template/host/src/kernel/index.ts +48 -0
- package/template/host/src/kernel/lib/cn.ts +1 -0
- package/template/host/src/kernel/lib/utils.ts +36 -0
- package/template/host/src/kernel/plugins/Slot.tsx +41 -0
- package/template/host/src/kernel/plugins/SlotProvider.tsx +88 -0
- package/template/host/src/kernel/plugins/index.ts +23 -0
- package/template/host/src/kernel/plugins/loader.ts +122 -0
- package/template/host/src/kernel/plugins/schemas.ts +54 -0
- package/template/host/src/kernel/plugins/store.ts +185 -0
- package/template/host/src/kernel/plugins/types.ts +103 -0
- package/template/host/src/kernel/providers/PocketBaseProvider.tsx +70 -0
- package/template/host/src/kernel/providers/QueryProvider.tsx +28 -0
- package/template/host/src/kernel/providers/ThemeProvider.tsx +25 -0
- package/template/host/src/kernel/providers/index.ts +3 -0
- package/template/host/src/kernel/rbac/components/OrganizationSelector.tsx +69 -0
- package/template/host/src/kernel/rbac/components/PermissionGate.tsx +43 -0
- package/template/host/src/kernel/rbac/hooks.ts +379 -0
- package/template/host/src/kernel/rbac/index.ts +6 -0
- package/template/host/src/kernel/rbac/service.ts +504 -0
- package/template/host/src/kernel/rbac/types.ts +164 -0
- package/template/host/src/kernel/rbac/utils.ts +34 -0
- package/template/host/src/kernel/shared-state/bridge.ts +31 -0
- package/template/host/src/kernel/shared-state/index.ts +3 -0
- package/template/host/src/kernel/shared-state/store.ts +62 -0
- package/template/host/src/kernel/shared-state/types.ts +60 -0
- package/template/host/src/kernel/use-migrations.ts +72 -0
- package/template/host/src/layout/MobileMenu.tsx +61 -0
- package/template/host/src/layout/Shell.tsx +42 -0
- package/template/host/src/layout/Sidebar.tsx +178 -0
- package/template/host/src/layout/Topbar.tsx +50 -0
- package/template/host/src/layout/index.ts +4 -0
- package/template/host/src/lib/pocketbase/client.ts +38 -0
- package/template/host/src/lib/pocketbase/collections/audit_logs.ts +87 -0
- package/template/host/src/lib/pocketbase/collections/index.ts +19 -0
- package/template/host/src/lib/pocketbase/collections/organizations.ts +63 -0
- package/template/host/src/lib/pocketbase/collections/permissions.ts +57 -0
- package/template/host/src/lib/pocketbase/collections/roles.ts +55 -0
- package/template/host/src/lib/pocketbase/collections/todos.ts +74 -0
- package/template/host/src/lib/pocketbase/collections/user_roles.ts +57 -0
- package/template/host/src/lib/pocketbase/collections/users.ts +43 -0
- package/template/host/src/lib/pocketbase/index.ts +5 -0
- package/template/host/src/lib/pocketbase/migrations.ts +44 -0
- package/template/host/src/lib/pocketbase/seed/permissions.ts +8 -0
- package/template/host/src/lib/pocketbase/seed/roles.ts +22 -0
- package/template/host/src/lib/pocketbase/seed.ts +113 -0
- package/template/host/src/lib/pocketbase/types.ts +102 -0
- package/template/host/src/modern.runtime.ts +26 -0
- package/template/host/src/plugins.d.ts +9 -0
- package/template/host/src/providers/PocketBaseProvider.tsx +30 -0
- package/template/host/src/routes/_.tsx +6 -0
- package/template/host/src/routes/dashboard._.tsx +41 -0
- package/template/host/src/routes/index.tsx +93 -0
- package/template/host/src/routes/login.tsx +36 -0
- package/template/host/src/saas.config.ts +52 -0
- package/template/host/src/test/setup.ts +65 -0
- package/template/host/src/test/utils.tsx +69 -0
- package/template/host/src/test/vitest-globals.d.ts +19 -0
- package/template/host/src/vite-env.d.ts +16 -0
- package/template/host/tailwind.config.ts +77 -0
- package/template/host/tsconfig.json +19 -0
- package/template/host/vitest.config.ts +30 -0
- package/template/package.json +44 -0
- package/template/packages/plugins/@lego/plugin-dashboard/modern.config.ts +19 -0
- package/template/packages/plugins/@lego/plugin-dashboard/package.json +35 -0
- package/template/packages/plugins/@lego/plugin-dashboard/postcss.config.mjs +6 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/App.tsx +27 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/components/ActivityFeed.tsx +63 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/components/QuickActionSlot.tsx +11 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/components/QuickActions.tsx +68 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/components/SidebarWidget.tsx +35 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/components/StatCard.tsx +47 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/global.css +24 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/hooks/useChannelIntegration.ts +43 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/hooks/useDashboardStats.ts +65 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/hooks/usePocketBase.ts +47 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/hooks/useRecentActivity.ts +55 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/lib/utils.ts +6 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/pages/DashboardPage.tsx +105 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/plugin.config.ts +121 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/plugin.ts +18 -0
- package/template/packages/plugins/@lego/plugin-dashboard/src/vite-env.d.ts +32 -0
- package/template/packages/plugins/@lego/plugin-dashboard/tailwind.config.ts +35 -0
- package/template/packages/plugins/@lego/plugin-dashboard/tsconfig.json +18 -0
- package/template/packages/plugins/@lego/plugin-todo/modern.config.ts +18 -0
- package/template/packages/plugins/@lego/plugin-todo/package.json +41 -0
- package/template/packages/plugins/@lego/plugin-todo/postcss.config.mjs +6 -0
- package/template/packages/plugins/@lego/plugin-todo/src/App.tsx +12 -0
- package/template/packages/plugins/@lego/plugin-todo/src/components/SidebarWidget.tsx +16 -0
- package/template/packages/plugins/@lego/plugin-todo/src/components/TodoDialog.tsx +55 -0
- package/template/packages/plugins/@lego/plugin-todo/src/components/TodoFilters.tsx +79 -0
- package/template/packages/plugins/@lego/plugin-todo/src/components/TodoForm.tsx +94 -0
- package/template/packages/plugins/@lego/plugin-todo/src/components/TodoItem.tsx +121 -0
- package/template/packages/plugins/@lego/plugin-todo/src/components/TodoList.tsx +41 -0
- package/template/packages/plugins/@lego/plugin-todo/src/components/index.ts +6 -0
- package/template/packages/plugins/@lego/plugin-todo/src/global.css +59 -0
- package/template/packages/plugins/@lego/plugin-todo/src/hooks/useCreateTodo.ts +62 -0
- package/template/packages/plugins/@lego/plugin-todo/src/hooks/useDeleteTodo.ts +46 -0
- package/template/packages/plugins/@lego/plugin-todo/src/hooks/usePocketBase.ts +38 -0
- package/template/packages/plugins/@lego/plugin-todo/src/hooks/useTodos.ts +64 -0
- package/template/packages/plugins/@lego/plugin-todo/src/hooks/useUpdateTodo.ts +35 -0
- package/template/packages/plugins/@lego/plugin-todo/src/index.tsx +5 -0
- package/template/packages/plugins/@lego/plugin-todo/src/lib/utils.ts +20 -0
- package/template/packages/plugins/@lego/plugin-todo/src/pages/TodoPage.tsx +89 -0
- package/template/packages/plugins/@lego/plugin-todo/src/plugin.config.ts +104 -0
- package/template/packages/plugins/@lego/plugin-todo/src/plugin.ts +13 -0
- package/template/packages/plugins/@lego/plugin-todo/src/schemas.ts +37 -0
- package/template/packages/plugins/@lego/plugin-todo/src/types.ts +42 -0
- package/template/packages/plugins/@lego/plugin-todo/src/vite-env.d.ts +31 -0
- package/template/packages/plugins/@lego/plugin-todo/tailwind.config.ts +51 -0
- package/template/packages/plugins/@lego/plugin-todo/tsconfig.json +18 -0
- package/template/pnpm-workspace.yaml +4 -0
- package/template/tsconfig.json +8 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
3
|
+
import { usePocketBase } from '../providers';
|
|
4
|
+
import { RBACService } from './service';
|
|
5
|
+
import type {
|
|
6
|
+
Organization,
|
|
7
|
+
CreateOrganizationData,
|
|
8
|
+
UpdateOrganizationData,
|
|
9
|
+
Role,
|
|
10
|
+
CreateRoleData,
|
|
11
|
+
UpdateRoleData,
|
|
12
|
+
Permission,
|
|
13
|
+
UserRole,
|
|
14
|
+
AssignRoleData,
|
|
15
|
+
UserWithRoles,
|
|
16
|
+
CreateUserRequest,
|
|
17
|
+
UpdateUserRequest,
|
|
18
|
+
ResourceType,
|
|
19
|
+
ActionType,
|
|
20
|
+
} from './types';
|
|
21
|
+
import { useGlobalKernelState } from '../shared-state';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get RBAC service instance
|
|
25
|
+
*/
|
|
26
|
+
function useRBACService(): RBACService | null {
|
|
27
|
+
const pb = usePocketBase();
|
|
28
|
+
if (!pb) return null;
|
|
29
|
+
return new RBACService(pb);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Manage current organization
|
|
34
|
+
*/
|
|
35
|
+
export function useCurrentOrganization() {
|
|
36
|
+
const { organization, setOrganization } = useGlobalKernelState();
|
|
37
|
+
const queryClient = useQueryClient();
|
|
38
|
+
|
|
39
|
+
const setCurrentOrganization = useCallback((org: Organization | null) => {
|
|
40
|
+
setOrganization(org);
|
|
41
|
+
// Clear related queries when switching organizations
|
|
42
|
+
queryClient.clear();
|
|
43
|
+
}, [setOrganization, queryClient]);
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
organization,
|
|
47
|
+
setCurrentOrganization,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get user's organizations
|
|
53
|
+
*/
|
|
54
|
+
export function useOrganizations() {
|
|
55
|
+
const service = useRBACService();
|
|
56
|
+
|
|
57
|
+
return useQuery({
|
|
58
|
+
queryKey: ['organizations'],
|
|
59
|
+
queryFn: () => service?.getUserOrganizations() || [],
|
|
60
|
+
enabled: !!service,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get single organization
|
|
66
|
+
*/
|
|
67
|
+
export function useOrganization(id: string) {
|
|
68
|
+
const service = useRBACService();
|
|
69
|
+
|
|
70
|
+
return useQuery({
|
|
71
|
+
queryKey: ['organization', id],
|
|
72
|
+
queryFn: () => service?.getOrganization(id),
|
|
73
|
+
enabled: !!service && !!id,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Create organization
|
|
79
|
+
*/
|
|
80
|
+
export function useCreateOrganization() {
|
|
81
|
+
const service = useRBACService();
|
|
82
|
+
const queryClient = useQueryClient();
|
|
83
|
+
const { setCurrentOrganization } = useCurrentOrganization();
|
|
84
|
+
|
|
85
|
+
return useMutation({
|
|
86
|
+
mutationFn: (data: CreateOrganizationData) => {
|
|
87
|
+
if (!service) throw new Error('Service not available');
|
|
88
|
+
return service.createOrganization(data);
|
|
89
|
+
},
|
|
90
|
+
onSuccess: (org) => {
|
|
91
|
+
queryClient.invalidateQueries({ queryKey: ['organizations'] });
|
|
92
|
+
setCurrentOrganization(org);
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Update organization
|
|
99
|
+
*/
|
|
100
|
+
export function useUpdateOrganization() {
|
|
101
|
+
const service = useRBACService();
|
|
102
|
+
const queryClient = useQueryClient();
|
|
103
|
+
|
|
104
|
+
return useMutation({
|
|
105
|
+
mutationFn: ({ id, data }: { id: string; data: UpdateOrganizationData }) => {
|
|
106
|
+
if (!service) throw new Error('Service not available');
|
|
107
|
+
return service.updateOrganization(id, data);
|
|
108
|
+
},
|
|
109
|
+
onSuccess: (_, { id }) => {
|
|
110
|
+
queryClient.invalidateQueries({ queryKey: ['organization', id] });
|
|
111
|
+
queryClient.invalidateQueries({ queryKey: ['organizations'] });
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Get organization roles
|
|
118
|
+
*/
|
|
119
|
+
export function useOrganizationRoles(organizationId: string | null) {
|
|
120
|
+
const service = useRBACService();
|
|
121
|
+
|
|
122
|
+
return useQuery({
|
|
123
|
+
queryKey: ['roles', organizationId],
|
|
124
|
+
queryFn: () => {
|
|
125
|
+
if (!organizationId || !service) return [];
|
|
126
|
+
return service.getOrganizationRoles(organizationId);
|
|
127
|
+
},
|
|
128
|
+
enabled: !!service && !!organizationId,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Create custom role
|
|
134
|
+
*/
|
|
135
|
+
export function useCreateRole() {
|
|
136
|
+
const service = useRBACService();
|
|
137
|
+
const queryClient = useQueryClient();
|
|
138
|
+
|
|
139
|
+
return useMutation({
|
|
140
|
+
mutationFn: (data: CreateRoleData) => {
|
|
141
|
+
if (!service) throw new Error('Service not available');
|
|
142
|
+
return service.createRole(data);
|
|
143
|
+
},
|
|
144
|
+
onSuccess: (_, { organizationId }) => {
|
|
145
|
+
queryClient.invalidateQueries({ queryKey: ['roles', organizationId] });
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Update role
|
|
152
|
+
*/
|
|
153
|
+
export function useUpdateRole() {
|
|
154
|
+
const service = useRBACService();
|
|
155
|
+
const queryClient = useQueryClient();
|
|
156
|
+
|
|
157
|
+
return useMutation({
|
|
158
|
+
mutationFn: ({ id, data }: { id: string; data: UpdateRoleData }) => {
|
|
159
|
+
if (!service) throw new Error('Service not available');
|
|
160
|
+
return service.updateRole(id, data);
|
|
161
|
+
},
|
|
162
|
+
onSuccess: () => {
|
|
163
|
+
queryClient.invalidateQueries({ queryKey: ['roles'] });
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Delete role
|
|
170
|
+
*/
|
|
171
|
+
export function useDeleteRole() {
|
|
172
|
+
const service = useRBACService();
|
|
173
|
+
const queryClient = useQueryClient();
|
|
174
|
+
|
|
175
|
+
return useMutation({
|
|
176
|
+
mutationFn: (id: string) => {
|
|
177
|
+
if (!service) throw new Error('Service not available');
|
|
178
|
+
return service.deleteRole(id);
|
|
179
|
+
},
|
|
180
|
+
onSuccess: () => {
|
|
181
|
+
queryClient.invalidateQueries({ queryKey: ['roles'] });
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Get all permissions
|
|
188
|
+
*/
|
|
189
|
+
export function usePermissions() {
|
|
190
|
+
const service = useRBACService();
|
|
191
|
+
|
|
192
|
+
return useQuery({
|
|
193
|
+
queryKey: ['permissions'],
|
|
194
|
+
queryFn: () => service?.getAllPermissions() || [],
|
|
195
|
+
enabled: !!service,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Get organization users
|
|
201
|
+
*/
|
|
202
|
+
export function useOrganizationUsers(organizationId: string | null) {
|
|
203
|
+
const service = useRBACService();
|
|
204
|
+
|
|
205
|
+
return useQuery({
|
|
206
|
+
queryKey: ['users', organizationId],
|
|
207
|
+
queryFn: () => {
|
|
208
|
+
if (!organizationId || !service) return [];
|
|
209
|
+
return service.getOrganizationUsers(organizationId);
|
|
210
|
+
},
|
|
211
|
+
enabled: !!service && !!organizationId,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Assign role to user
|
|
217
|
+
*/
|
|
218
|
+
export function useAssignRole() {
|
|
219
|
+
const service = useRBACService();
|
|
220
|
+
const queryClient = useQueryClient();
|
|
221
|
+
|
|
222
|
+
return useMutation({
|
|
223
|
+
mutationFn: (data: AssignRoleData) => {
|
|
224
|
+
if (!service) throw new Error('Service not available');
|
|
225
|
+
return service.assignRole(data);
|
|
226
|
+
},
|
|
227
|
+
onSuccess: (_, { organizationId }) => {
|
|
228
|
+
queryClient.invalidateQueries({ queryKey: ['users', organizationId] });
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Remove role from user
|
|
235
|
+
*/
|
|
236
|
+
export function useRemoveRole() {
|
|
237
|
+
const service = useRBACService();
|
|
238
|
+
const queryClient = useQueryClient();
|
|
239
|
+
|
|
240
|
+
return useMutation({
|
|
241
|
+
mutationFn: ({ userRoleId, organizationId }: { userRoleId: string; organizationId: string }) => {
|
|
242
|
+
if (!service) throw new Error('Service not available');
|
|
243
|
+
return service.removeRole(userRoleId);
|
|
244
|
+
},
|
|
245
|
+
onSuccess: (_, { organizationId }) => {
|
|
246
|
+
queryClient.invalidateQueries({ queryKey: ['users', organizationId] });
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Create user
|
|
253
|
+
*/
|
|
254
|
+
export function useCreateUser() {
|
|
255
|
+
const service = useRBACService();
|
|
256
|
+
const queryClient = useQueryClient();
|
|
257
|
+
|
|
258
|
+
return useMutation({
|
|
259
|
+
mutationFn: (data: CreateUserRequest) => {
|
|
260
|
+
if (!service) throw new Error('Service not available');
|
|
261
|
+
return service.createUser(data);
|
|
262
|
+
},
|
|
263
|
+
onSuccess: (_, { organizationId }) => {
|
|
264
|
+
queryClient.invalidateQueries({ queryKey: ['users', organizationId] });
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Update user
|
|
271
|
+
*/
|
|
272
|
+
export function useUpdateUser() {
|
|
273
|
+
const service = useRBACService();
|
|
274
|
+
const queryClient = useQueryClient();
|
|
275
|
+
|
|
276
|
+
return useMutation({
|
|
277
|
+
mutationFn: ({ userId, data }: { userId: string; data: UpdateUserRequest }) => {
|
|
278
|
+
if (!service) throw new Error('Service not available');
|
|
279
|
+
return service.updateUser(userId, data);
|
|
280
|
+
},
|
|
281
|
+
onSuccess: (_, { userId }) => {
|
|
282
|
+
queryClient.invalidateQueries({ queryKey: ['users'] });
|
|
283
|
+
queryClient.invalidateQueries({ queryKey: ['auth', 'user'] });
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Delete user
|
|
290
|
+
*/
|
|
291
|
+
export function useDeleteUser() {
|
|
292
|
+
const service = useRBACService();
|
|
293
|
+
const queryClient = useQueryClient();
|
|
294
|
+
|
|
295
|
+
return useMutation({
|
|
296
|
+
mutationFn: ({ userId, organizationId }: { userId: string; organizationId: string }) => {
|
|
297
|
+
if (!service) throw new Error('Service not available');
|
|
298
|
+
return service.deleteUser(userId);
|
|
299
|
+
},
|
|
300
|
+
onSuccess: (_, { organizationId }) => {
|
|
301
|
+
queryClient.invalidateQueries({ queryKey: ['users', organizationId] });
|
|
302
|
+
},
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Check permissions
|
|
308
|
+
*/
|
|
309
|
+
export function useHasPermission() {
|
|
310
|
+
const service = useRBACService();
|
|
311
|
+
const { user, organization } = useGlobalKernelState();
|
|
312
|
+
|
|
313
|
+
return useCallback(
|
|
314
|
+
async (resource: ResourceType, action: ActionType): Promise<boolean> => {
|
|
315
|
+
if (!service || !user?.id || !organization?.id) return false;
|
|
316
|
+
const result = await service.hasPermission(user.id, organization.id, resource, action);
|
|
317
|
+
return result.allowed;
|
|
318
|
+
},
|
|
319
|
+
[service, user, organization]
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Get user permissions for current organization
|
|
325
|
+
*/
|
|
326
|
+
export function useUserPermissions() {
|
|
327
|
+
const service = useRBACService();
|
|
328
|
+
const { user, organization } = useGlobalKernelState();
|
|
329
|
+
|
|
330
|
+
return useQuery({
|
|
331
|
+
queryKey: ['permissions', 'user', user?.id, organization?.id],
|
|
332
|
+
queryFn: () => {
|
|
333
|
+
if (!service || !user?.id || !organization?.id) return [];
|
|
334
|
+
return service.getUserPermissions(user.id, organization.id);
|
|
335
|
+
},
|
|
336
|
+
enabled: !!service && !!user?.id && !!organization?.id,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Require permission - returns whether user has permission
|
|
342
|
+
*/
|
|
343
|
+
export function useRequirePermission(resource: ResourceType, action: ActionType) {
|
|
344
|
+
const permissions = useUserPermissions();
|
|
345
|
+
const [hasPermission, setHasPermission] = useState(false);
|
|
346
|
+
|
|
347
|
+
useEffect(() => {
|
|
348
|
+
const perms = permissions.data || [];
|
|
349
|
+
|
|
350
|
+
const allowed =
|
|
351
|
+
perms.some(p => p.resource === 'all' && p.action === 'all') ||
|
|
352
|
+
perms.some(p => p.resource === resource && p.action === 'all') ||
|
|
353
|
+
perms.some(p => p.resource === 'all' && p.action === action) ||
|
|
354
|
+
perms.some(p => p.resource === resource && p.action === action);
|
|
355
|
+
|
|
356
|
+
setHasPermission(allowed);
|
|
357
|
+
}, [permissions.data, resource, action]);
|
|
358
|
+
|
|
359
|
+
return {
|
|
360
|
+
hasPermission,
|
|
361
|
+
isLoading: permissions.isLoading,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Get audit logs
|
|
367
|
+
*/
|
|
368
|
+
export function useAuditLogs(organizationId: string | null, page = 1) {
|
|
369
|
+
const service = useRBACService();
|
|
370
|
+
|
|
371
|
+
return useQuery({
|
|
372
|
+
queryKey: ['audit-logs', organizationId, page],
|
|
373
|
+
queryFn: () => {
|
|
374
|
+
if (!organizationId || !service) return null;
|
|
375
|
+
return service.getAuditLogs(organizationId, page);
|
|
376
|
+
},
|
|
377
|
+
enabled: !!service && !!organizationId,
|
|
378
|
+
});
|
|
379
|
+
}
|