hazo_auth 3.0.4 → 4.1.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.
Files changed (82) hide show
  1. package/README.md +228 -8
  2. package/SETUP_CHECKLIST.md +370 -0
  3. package/dist/app/api/hazo_auth/me/route.d.ts +3 -0
  4. package/dist/app/api/hazo_auth/me/route.d.ts.map +1 -1
  5. package/dist/app/api/hazo_auth/me/route.js +9 -1
  6. package/dist/components/layouts/my_settings/components/profile_picture_library_tab.d.ts.map +1 -1
  7. package/dist/components/layouts/my_settings/components/profile_picture_library_tab.js +2 -2
  8. package/dist/components/layouts/profile_stamp_test/index.d.ts +10 -0
  9. package/dist/components/layouts/profile_stamp_test/index.d.ts.map +1 -0
  10. package/dist/components/layouts/profile_stamp_test/index.js +51 -0
  11. package/dist/components/layouts/rbac_test/index.d.ts +15 -0
  12. package/dist/components/layouts/rbac_test/index.d.ts.map +1 -0
  13. package/dist/components/layouts/rbac_test/index.js +378 -0
  14. package/dist/components/layouts/shared/components/password_field.js +1 -1
  15. package/dist/components/layouts/shared/components/profile_stamp.d.ts +58 -0
  16. package/dist/components/layouts/shared/components/profile_stamp.d.ts.map +1 -0
  17. package/dist/components/layouts/shared/components/profile_stamp.js +72 -0
  18. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
  19. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +2 -2
  20. package/dist/components/layouts/shared/components/two_column_auth_layout.js +1 -1
  21. package/dist/components/layouts/shared/hooks/use_auth_status.d.ts +3 -0
  22. package/dist/components/layouts/shared/hooks/use_auth_status.d.ts.map +1 -1
  23. package/dist/components/layouts/shared/hooks/use_auth_status.js +4 -0
  24. package/dist/components/layouts/shared/index.d.ts +2 -0
  25. package/dist/components/layouts/shared/index.d.ts.map +1 -1
  26. package/dist/components/layouts/shared/index.js +1 -0
  27. package/dist/components/layouts/user_management/components/roles_matrix.d.ts +2 -3
  28. package/dist/components/layouts/user_management/components/roles_matrix.d.ts.map +1 -1
  29. package/dist/components/layouts/user_management/components/roles_matrix.js +133 -8
  30. package/dist/components/layouts/user_management/components/scope_hierarchy_tab.d.ts +12 -0
  31. package/dist/components/layouts/user_management/components/scope_hierarchy_tab.d.ts.map +1 -0
  32. package/dist/components/layouts/user_management/components/scope_hierarchy_tab.js +291 -0
  33. package/dist/components/layouts/user_management/components/scope_labels_tab.d.ts +13 -0
  34. package/dist/components/layouts/user_management/components/scope_labels_tab.d.ts.map +1 -0
  35. package/dist/components/layouts/user_management/components/scope_labels_tab.js +158 -0
  36. package/dist/components/layouts/user_management/components/user_scopes_tab.d.ts +11 -0
  37. package/dist/components/layouts/user_management/components/user_scopes_tab.d.ts.map +1 -0
  38. package/dist/components/layouts/user_management/components/user_scopes_tab.js +267 -0
  39. package/dist/components/layouts/user_management/index.d.ts +9 -2
  40. package/dist/components/layouts/user_management/index.d.ts.map +1 -1
  41. package/dist/components/layouts/user_management/index.js +22 -6
  42. package/dist/components/ui/hover-card.d.ts +7 -0
  43. package/dist/components/ui/hover-card.d.ts.map +1 -0
  44. package/dist/components/ui/hover-card.js +29 -0
  45. package/dist/components/ui/index.d.ts +1 -0
  46. package/dist/components/ui/index.d.ts.map +1 -1
  47. package/dist/components/ui/index.js +1 -0
  48. package/dist/components/ui/select.d.ts +14 -0
  49. package/dist/components/ui/select.d.ts.map +1 -0
  50. package/dist/components/ui/select.js +59 -0
  51. package/dist/components/ui/tree-view.d.ts +108 -0
  52. package/dist/components/ui/tree-view.d.ts.map +1 -0
  53. package/dist/components/ui/tree-view.js +194 -0
  54. package/dist/lib/auth/auth_types.d.ts +45 -0
  55. package/dist/lib/auth/auth_types.d.ts.map +1 -1
  56. package/dist/lib/auth/auth_types.js +13 -0
  57. package/dist/lib/auth/hazo_get_auth.server.d.ts +4 -2
  58. package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -1
  59. package/dist/lib/auth/hazo_get_auth.server.js +107 -3
  60. package/dist/lib/auth/scope_cache.d.ts +92 -0
  61. package/dist/lib/auth/scope_cache.d.ts.map +1 -0
  62. package/dist/lib/auth/scope_cache.js +171 -0
  63. package/dist/lib/scope_hierarchy_config.server.d.ts +39 -0
  64. package/dist/lib/scope_hierarchy_config.server.d.ts.map +1 -0
  65. package/dist/lib/scope_hierarchy_config.server.js +96 -0
  66. package/dist/lib/services/email_service.d.ts.map +1 -1
  67. package/dist/lib/services/email_service.js +7 -2
  68. package/dist/lib/services/profile_picture_service.d.ts +1 -7
  69. package/dist/lib/services/profile_picture_service.d.ts.map +1 -1
  70. package/dist/lib/services/profile_picture_service.js +77 -32
  71. package/dist/lib/services/registration_service.js +1 -1
  72. package/dist/lib/services/scope_labels_service.d.ts +48 -0
  73. package/dist/lib/services/scope_labels_service.d.ts.map +1 -0
  74. package/dist/lib/services/scope_labels_service.js +277 -0
  75. package/dist/lib/services/scope_service.d.ts +114 -0
  76. package/dist/lib/services/scope_service.d.ts.map +1 -0
  77. package/dist/lib/services/scope_service.js +582 -0
  78. package/dist/lib/services/user_scope_service.d.ts +74 -0
  79. package/dist/lib/services/user_scope_service.d.ts.map +1 -0
  80. package/dist/lib/services/user_scope_service.js +415 -0
  81. package/hazo_auth_config.example.ini +1 -1
  82. package/package.json +4 -1
@@ -0,0 +1,267 @@
1
+ // file_description: User Scopes tab component for assigning scopes to users in HRBAC
2
+ // section: client_directive
3
+ "use client";
4
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
5
+ // section: imports
6
+ import { useState, useEffect, useCallback, useMemo } from "react";
7
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "../../../ui/table";
8
+ import { Button } from "../../../ui/button";
9
+ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "../../../ui/dialog";
10
+ import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "../../../ui/alert-dialog";
11
+ import { Input } from "../../../ui/input";
12
+ import { Label } from "../../../ui/label";
13
+ import { Avatar, AvatarFallback, AvatarImage } from "../../../ui/avatar";
14
+ import { TreeView } from "../../../ui/tree-view";
15
+ import { Loader2, Plus, Trash2, Search, CircleCheck, CircleX, ChevronRight, Building2, FolderTree, } from "lucide-react";
16
+ import { toast } from "sonner";
17
+ import { useHazoAuthConfig } from "../../../../contexts/hazo_auth_provider";
18
+ const SCOPE_LEVEL_LABELS = {
19
+ hazo_scopes_l1: "Level 1",
20
+ hazo_scopes_l2: "Level 2",
21
+ hazo_scopes_l3: "Level 3",
22
+ hazo_scopes_l4: "Level 4",
23
+ hazo_scopes_l5: "Level 5",
24
+ hazo_scopes_l6: "Level 6",
25
+ hazo_scopes_l7: "Level 7",
26
+ };
27
+ // Convert ScopeTreeNode to TreeDataItem format for selection
28
+ function convertToTreeData(nodes) {
29
+ return nodes.map((node) => {
30
+ const hasChildren = node.children && node.children.length > 0;
31
+ const item = {
32
+ id: node.id,
33
+ name: `${node.name} (${node.seq})`,
34
+ icon: Building2,
35
+ scopeData: node,
36
+ };
37
+ if (hasChildren) {
38
+ item.children = convertToTreeData(node.children);
39
+ }
40
+ return item;
41
+ });
42
+ }
43
+ // section: component
44
+ /**
45
+ * User Scopes tab component for assigning scopes to users
46
+ * Two-panel layout: Users list | Scope assignments
47
+ * @param props - Component props
48
+ * @returns User Scopes tab component
49
+ */
50
+ export function UserScopesTab({ className }) {
51
+ const { apiBasePath } = useHazoAuthConfig();
52
+ // Users state
53
+ const [users, setUsers] = useState([]);
54
+ const [usersLoading, setUsersLoading] = useState(true);
55
+ const [userSearch, setUserSearch] = useState("");
56
+ const [selectedUser, setSelectedUser] = useState(null);
57
+ // User scopes state
58
+ const [userScopes, setUserScopes] = useState([]);
59
+ const [scopesLoading, setScopesLoading] = useState(false);
60
+ const [inheritedLevels, setInheritedLevels] = useState([]);
61
+ // Add scope dialog state
62
+ const [addDialogOpen, setAddDialogOpen] = useState(false);
63
+ const [scopeTree, setScopeTree] = useState([]);
64
+ const [treeLoading, setTreeLoading] = useState(false);
65
+ const [selectedTreeItem, setSelectedTreeItem] = useState();
66
+ const [actionLoading, setActionLoading] = useState(false);
67
+ // Delete scope dialog state
68
+ const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
69
+ const [scopeToDelete, setScopeToDelete] = useState(null);
70
+ // Load users
71
+ useEffect(() => {
72
+ const loadUsers = async () => {
73
+ setUsersLoading(true);
74
+ try {
75
+ const response = await fetch(`${apiBasePath}/user_management/users`);
76
+ const data = await response.json();
77
+ if (data.success) {
78
+ setUsers(data.users || []);
79
+ }
80
+ else {
81
+ toast.error(data.error || "Failed to load users");
82
+ }
83
+ }
84
+ catch (error) {
85
+ toast.error("Failed to load users");
86
+ }
87
+ finally {
88
+ setUsersLoading(false);
89
+ }
90
+ };
91
+ void loadUsers();
92
+ }, [apiBasePath]);
93
+ // Load user scopes when user selected
94
+ const loadUserScopes = useCallback(async () => {
95
+ if (!selectedUser) {
96
+ setUserScopes([]);
97
+ setInheritedLevels([]);
98
+ return;
99
+ }
100
+ setScopesLoading(true);
101
+ try {
102
+ const params = new URLSearchParams({
103
+ user_id: selectedUser.id,
104
+ include_effective: "true",
105
+ });
106
+ const response = await fetch(`${apiBasePath}/user_management/users/scopes?${params}`);
107
+ const data = await response.json();
108
+ if (data.success) {
109
+ setUserScopes(data.direct_scopes || []);
110
+ setInheritedLevels(data.inherited_scope_types || []);
111
+ }
112
+ else {
113
+ toast.error(data.error || "Failed to load user scopes");
114
+ }
115
+ }
116
+ catch (error) {
117
+ toast.error("Failed to load user scopes");
118
+ }
119
+ finally {
120
+ setScopesLoading(false);
121
+ }
122
+ }, [apiBasePath, selectedUser]);
123
+ useEffect(() => {
124
+ void loadUserScopes();
125
+ }, [loadUserScopes]);
126
+ // Load scope tree for add dialog (all scopes across all orgs)
127
+ const loadScopeTree = useCallback(async () => {
128
+ setTreeLoading(true);
129
+ try {
130
+ const params = new URLSearchParams({ action: "tree_all" });
131
+ const response = await fetch(`${apiBasePath}/scope_management/scopes?${params}`);
132
+ const data = await response.json();
133
+ if (data.success) {
134
+ setScopeTree(data.trees || []);
135
+ }
136
+ else {
137
+ setScopeTree([]);
138
+ }
139
+ }
140
+ catch (error) {
141
+ setScopeTree([]);
142
+ }
143
+ finally {
144
+ setTreeLoading(false);
145
+ }
146
+ }, [apiBasePath]);
147
+ useEffect(() => {
148
+ if (addDialogOpen) {
149
+ void loadScopeTree();
150
+ }
151
+ }, [addDialogOpen, loadScopeTree]);
152
+ // Filter users by search
153
+ const filteredUsers = users.filter((user) => {
154
+ var _a;
155
+ const search = userSearch.toLowerCase();
156
+ return ((((_a = user.name) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(search)) || false) ||
157
+ user.email_address.toLowerCase().includes(search));
158
+ });
159
+ // Get user initials
160
+ const getUserInitials = (user) => {
161
+ var _a, _b;
162
+ if (user.name) {
163
+ const parts = user.name.trim().split(" ");
164
+ if (parts.length >= 2) {
165
+ return `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase();
166
+ }
167
+ return ((_a = user.name[0]) === null || _a === void 0 ? void 0 : _a.toUpperCase()) || "";
168
+ }
169
+ return ((_b = user.email_address[0]) === null || _b === void 0 ? void 0 : _b.toUpperCase()) || "?";
170
+ };
171
+ // Convert tree to TreeDataItem format
172
+ const treeData = useMemo(() => {
173
+ return convertToTreeData(scopeTree);
174
+ }, [scopeTree]);
175
+ // Handle tree item selection
176
+ const handleTreeSelectChange = (item) => {
177
+ setSelectedTreeItem(item);
178
+ };
179
+ // Handle add scope
180
+ const handleAddScope = async () => {
181
+ if (!selectedUser || !(selectedTreeItem === null || selectedTreeItem === void 0 ? void 0 : selectedTreeItem.scopeData)) {
182
+ toast.error("Please select a scope from the tree");
183
+ return;
184
+ }
185
+ const scope = selectedTreeItem.scopeData;
186
+ setActionLoading(true);
187
+ try {
188
+ const response = await fetch(`${apiBasePath}/user_management/users/scopes`, {
189
+ method: "POST",
190
+ headers: { "Content-Type": "application/json" },
191
+ body: JSON.stringify({
192
+ user_id: selectedUser.id,
193
+ scope_type: scope.level,
194
+ scope_id: scope.id,
195
+ scope_seq: scope.seq,
196
+ }),
197
+ });
198
+ const data = await response.json();
199
+ if (data.success) {
200
+ toast.success("Scope assigned successfully");
201
+ setAddDialogOpen(false);
202
+ setSelectedTreeItem(undefined);
203
+ await loadUserScopes();
204
+ }
205
+ else {
206
+ toast.error(data.error || "Failed to assign scope");
207
+ }
208
+ }
209
+ catch (error) {
210
+ toast.error("Failed to assign scope");
211
+ }
212
+ finally {
213
+ setActionLoading(false);
214
+ }
215
+ };
216
+ // Handle remove scope
217
+ const handleRemoveScope = async () => {
218
+ if (!selectedUser || !scopeToDelete)
219
+ return;
220
+ setActionLoading(true);
221
+ try {
222
+ const params = new URLSearchParams({
223
+ user_id: selectedUser.id,
224
+ scope_type: scopeToDelete.scope_type,
225
+ scope_id: scopeToDelete.scope_id,
226
+ });
227
+ const response = await fetch(`${apiBasePath}/user_management/users/scopes?${params}`, {
228
+ method: "DELETE",
229
+ });
230
+ const data = await response.json();
231
+ if (data.success) {
232
+ toast.success("Scope removed successfully");
233
+ setDeleteDialogOpen(false);
234
+ setScopeToDelete(null);
235
+ await loadUserScopes();
236
+ }
237
+ else {
238
+ toast.error(data.error || "Failed to remove scope");
239
+ }
240
+ }
241
+ catch (error) {
242
+ toast.error("Failed to remove scope");
243
+ }
244
+ finally {
245
+ setActionLoading(false);
246
+ }
247
+ };
248
+ // Get level label
249
+ const getLevelLabel = (level) => {
250
+ return SCOPE_LEVEL_LABELS[level] || level;
251
+ };
252
+ return (_jsxs("div", { className: `cls_user_scopes_tab flex flex-col lg:flex-row gap-4 w-full min-h-[500px] ${className || ""}`, children: [_jsxs("div", { className: "cls_user_scopes_users_panel w-full lg:w-1/3 flex flex-col border rounded-lg", children: [_jsxs("div", { className: "cls_user_scopes_users_header p-4 border-b bg-muted/30", children: [_jsx("h3", { className: "font-semibold mb-2", children: "Select User" }), _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" }), _jsx(Input, { value: userSearch, onChange: (e) => setUserSearch(e.target.value), placeholder: "Search users...", className: "pl-8" })] })] }), _jsx("div", { className: "cls_user_scopes_users_list flex-1 overflow-auto", children: usersLoading ? (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-slate-400" }) })) : filteredUsers.length === 0 ? (_jsx("div", { className: "text-center text-muted-foreground p-8", children: "No users found." })) : (_jsx("div", { className: "divide-y", children: filteredUsers.map((user) => (_jsxs("div", { className: `cls_user_scopes_user_item flex items-center gap-3 p-3 cursor-pointer hover:bg-muted/50 transition-colors ${(selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.id) === user.id ? "bg-muted" : ""}`, onClick: () => setSelectedUser(user), children: [_jsxs(Avatar, { className: "h-8 w-8", children: [_jsx(AvatarImage, { src: user.profile_picture_url || undefined }), _jsx(AvatarFallback, { className: "bg-slate-200 text-slate-600 text-xs", children: getUserInitials(user) })] }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("p", { className: "text-sm font-medium truncate", children: user.name || user.email_address }), user.name && (_jsx("p", { className: "text-xs text-muted-foreground truncate", children: user.email_address }))] }), (selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.id) === user.id && (_jsx(ChevronRight, { className: "h-4 w-4 text-muted-foreground" }))] }, user.id))) })) })] }), _jsxs("div", { className: "cls_user_scopes_assignments_panel w-full lg:w-2/3 flex flex-col border rounded-lg", children: [_jsxs("div", { className: "cls_user_scopes_assignments_header p-4 border-b bg-muted/30 flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("h3", { className: "font-semibold", children: selectedUser
253
+ ? `Scopes for ${selectedUser.name || selectedUser.email_address}`
254
+ : "Select a user to view scopes" }), selectedUser && inheritedLevels.length > 0 && (_jsxs("p", { className: "text-xs text-muted-foreground mt-1", children: ["Inherits access to: ", inheritedLevels.map(getLevelLabel).join(", ")] }))] }), selectedUser && (_jsxs(Button, { onClick: () => {
255
+ setSelectedTreeItem(undefined);
256
+ setAddDialogOpen(true);
257
+ }, variant: "default", size: "sm", children: [_jsx(Plus, { className: "h-4 w-4 mr-2" }), "Add Scope"] }))] }), _jsx("div", { className: "cls_user_scopes_assignments_content flex-1 overflow-auto", children: !selectedUser ? (_jsx("div", { className: "flex items-center justify-center h-full text-muted-foreground", children: "Select a user from the left panel to manage their scope assignments." })) : scopesLoading ? (_jsx("div", { className: "flex items-center justify-center h-full", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-slate-400" }) })) : userScopes.length === 0 ? (_jsxs("div", { className: "flex flex-col items-center justify-center h-full gap-4 text-muted-foreground", children: [_jsx("p", { children: "No scopes assigned to this user." }), _jsxs(Button, { onClick: () => {
258
+ setSelectedTreeItem(undefined);
259
+ setAddDialogOpen(true);
260
+ }, variant: "outline", size: "sm", children: [_jsx(Plus, { className: "h-4 w-4 mr-2" }), "Assign First Scope"] })] })) : (_jsxs(Table, { className: "w-full", children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Level" }), _jsx(TableHead, { children: "Scope Seq" }), _jsx(TableHead, { children: "Scope ID" }), _jsx(TableHead, { children: "Assigned" }), _jsx(TableHead, { className: "text-right w-[80px]", children: "Actions" })] }) }), _jsx(TableBody, { children: userScopes.map((scope) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "font-medium", children: getLevelLabel(scope.scope_type) }), _jsx(TableCell, { className: "font-mono text-sm", children: scope.scope_seq }), _jsxs(TableCell, { className: "font-mono text-xs text-muted-foreground", children: [scope.scope_id.substring(0, 8), "..."] }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: new Date(scope.created_at).toLocaleDateString() }), _jsx(TableCell, { className: "text-right", children: _jsx(Button, { onClick: () => {
261
+ setScopeToDelete(scope);
262
+ setDeleteDialogOpen(true);
263
+ }, variant: "outline", size: "sm", className: "text-destructive", children: _jsx(Trash2, { className: "h-4 w-4" }) }) })] }, `${scope.scope_type}-${scope.scope_id}`))) })] })) })] }), _jsx(Dialog, { open: addDialogOpen, onOpenChange: setAddDialogOpen, children: _jsxs(DialogContent, { className: "cls_user_scopes_add_dialog sm:max-w-[500px]", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Add Scope Assignment" }), _jsxs(DialogDescription, { children: ["Select a scope from the tree to assign to", " ", (selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.name) || (selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.email_address), "."] })] }), _jsxs("div", { className: "flex flex-col gap-4 py-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Select Scope" }), treeLoading ? (_jsx("div", { className: "flex items-center justify-center p-8 border rounded-lg", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-slate-400" }) })) : scopeTree.length === 0 ? (_jsxs("div", { className: "flex flex-col items-center justify-center p-6 border rounded-lg border-dashed", children: [_jsx(FolderTree, { className: "h-8 w-8 text-muted-foreground mb-2" }), _jsx("p", { className: "text-sm text-muted-foreground text-center", children: "No scopes available. Create scopes in the Scope Hierarchy tab first." })] })) : (_jsx("div", { className: "border rounded-lg max-h-[300px] overflow-auto", children: _jsx(TreeView, { data: treeData, expandAll: true, defaultNodeIcon: Building2, defaultLeafIcon: Building2, onSelectChange: handleTreeSelectChange, initialSelectedItemId: selectedTreeItem === null || selectedTreeItem === void 0 ? void 0 : selectedTreeItem.id, className: "w-full" }) }))] }), (selectedTreeItem === null || selectedTreeItem === void 0 ? void 0 : selectedTreeItem.scopeData) && (_jsxs("div", { className: "p-3 border rounded-lg bg-muted/50", children: [_jsxs("p", { className: "text-sm", children: [_jsx("span", { className: "font-medium", children: "Selected:" }), " ", selectedTreeItem.scopeData.name] }), _jsxs("p", { className: "text-xs text-muted-foreground", children: [SCOPE_LEVEL_LABELS[selectedTreeItem.scopeData.level], " -", " ", selectedTreeItem.scopeData.seq, " (", selectedTreeItem.scopeData.org, ")"] })] }))] }), _jsxs(DialogFooter, { children: [_jsx(Button, { onClick: handleAddScope, disabled: actionLoading || !(selectedTreeItem === null || selectedTreeItem === void 0 ? void 0 : selectedTreeItem.scopeData), variant: "default", children: actionLoading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "h-4 w-4 mr-2 animate-spin" }), "Assigning..."] })) : (_jsxs(_Fragment, { children: [_jsx(CircleCheck, { className: "h-4 w-4 mr-2" }), "Assign Scope"] })) }), _jsxs(Button, { onClick: () => setAddDialogOpen(false), variant: "outline", children: [_jsx(CircleX, { className: "h-4 w-4 mr-2" }), "Cancel"] })] })] }) }), _jsx(AlertDialog, { open: deleteDialogOpen, onOpenChange: setDeleteDialogOpen, children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Remove Scope Assignment" }), _jsxs(AlertDialogDescription, { children: ["Are you sure you want to remove the scope \"", scopeToDelete === null || scopeToDelete === void 0 ? void 0 : scopeToDelete.scope_seq, "\" from", " ", (selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.name) || (selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.email_address), "? This will also revoke access to any inherited scopes."] })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogAction, { onClick: handleRemoveScope, disabled: actionLoading, children: actionLoading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "h-4 w-4 mr-2 animate-spin" }), "Removing..."] })) : ("Remove") }), _jsx(AlertDialogCancel, { onClick: () => {
264
+ setDeleteDialogOpen(false);
265
+ setScopeToDelete(null);
266
+ }, children: "Cancel" })] })] }) })] }));
267
+ }
@@ -1,13 +1,20 @@
1
1
  export type UserManagementLayoutProps = {
2
2
  className?: string;
3
+ /** Whether HRBAC is enabled (passed from server) */
4
+ hrbacEnabled?: boolean;
5
+ /** Default organization for HRBAC scopes */
6
+ defaultOrg?: string;
3
7
  };
4
8
  /**
5
- * User Management layout component with three tabs
9
+ * User Management layout component with tabs for managing users, roles, permissions, and HRBAC scopes
6
10
  * Tab 1: Manage Users - data table with user details and actions
7
11
  * Tab 2: Roles - roles-permissions matrix
8
12
  * Tab 3: Permissions - manage permissions from DB and config
13
+ * Tab 4: Scope Labels - customize scope level labels (if HRBAC enabled)
14
+ * Tab 5: Scope Hierarchy - manage HRBAC scopes (if HRBAC enabled)
15
+ * Tab 6: User Scopes - assign scopes to users (if HRBAC enabled)
9
16
  * @param props - Component props
10
17
  * @returns User Management layout component
11
18
  */
12
- export declare function UserManagementLayout({ className }: UserManagementLayoutProps): import("react/jsx-runtime").JSX.Element;
19
+ export declare function UserManagementLayout({ className, hrbacEnabled, defaultOrg }: UserManagementLayoutProps): import("react/jsx-runtime").JSX.Element;
13
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/user_management/index.tsx"],"names":[],"mappings":"AA6CA,MAAM,MAAM,yBAAyB,GAAG;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAsBF;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,SAAS,EAAE,EAAE,yBAAyB,2CAmsC5E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/user_management/index.tsx"],"names":[],"mappings":"AAgDA,MAAM,MAAM,yBAAyB,GAAG;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAsBF;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,SAAS,EAAE,YAAoB,EAAE,UAAe,EAAE,EAAE,yBAAyB,2CAivCnH"}
@@ -1,4 +1,4 @@
1
- // file_description: User Management layout component with three tabs for managing users, roles, and permissions
1
+ // file_description: User Management layout component with tabs for managing users, roles, permissions, and HRBAC scopes
2
2
  // section: client_directive
3
3
  "use client";
4
4
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
@@ -14,20 +14,26 @@ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, D
14
14
  import { Input } from "../../ui/input";
15
15
  import { Label } from "../../ui/label";
16
16
  import { RolesMatrix } from "./components/roles_matrix";
17
+ import { ScopeHierarchyTab } from "./components/scope_hierarchy_tab";
18
+ import { ScopeLabelsTab } from "./components/scope_labels_tab";
19
+ import { UserScopesTab } from "./components/user_scopes_tab";
17
20
  import { UserX, KeyRound, Edit, Trash2, Loader2, CircleCheck, CircleX, Plus, UserPlus } from "lucide-react";
18
21
  import { toast } from "sonner";
19
22
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../../ui/tooltip";
20
23
  import { useHazoAuthConfig } from "../../../contexts/hazo_auth_provider";
21
24
  // section: component
22
25
  /**
23
- * User Management layout component with three tabs
26
+ * User Management layout component with tabs for managing users, roles, permissions, and HRBAC scopes
24
27
  * Tab 1: Manage Users - data table with user details and actions
25
28
  * Tab 2: Roles - roles-permissions matrix
26
29
  * Tab 3: Permissions - manage permissions from DB and config
30
+ * Tab 4: Scope Labels - customize scope level labels (if HRBAC enabled)
31
+ * Tab 5: Scope Hierarchy - manage HRBAC scopes (if HRBAC enabled)
32
+ * Tab 6: User Scopes - assign scopes to users (if HRBAC enabled)
27
33
  * @param props - Component props
28
34
  * @returns User Management layout component
29
35
  */
30
- export function UserManagementLayout({ className }) {
36
+ export function UserManagementLayout({ className, hrbacEnabled = false, defaultOrg = "" }) {
31
37
  const { apiBasePath } = useHazoAuthConfig();
32
38
  // Permission checks
33
39
  const authResult = use_hazo_auth();
@@ -37,11 +43,18 @@ export function UserManagementLayout({ className }) {
37
43
  authResult.permissions.includes("admin_role_management");
38
44
  const hasPermissionManagementPermission = authResult.authenticated &&
39
45
  authResult.permissions.includes("admin_permission_management");
46
+ const hasScopeHierarchyPermission = authResult.authenticated &&
47
+ authResult.permissions.includes("admin_scope_hierarchy_management");
48
+ const hasUserScopeAssignmentPermission = authResult.authenticated &&
49
+ authResult.permissions.includes("admin_user_scope_assignment");
40
50
  // Determine which tabs to show
41
51
  const showUsersTab = hasUserManagementPermission;
42
52
  const showRolesTab = hasRoleManagementPermission;
43
53
  const showPermissionsTab = hasPermissionManagementPermission;
44
- const hasAnyPermission = showUsersTab || showRolesTab || showPermissionsTab;
54
+ const showScopeHierarchyTab = hrbacEnabled && hasScopeHierarchyPermission;
55
+ const showScopeLabelsTab = hrbacEnabled && hasScopeHierarchyPermission;
56
+ const showUserScopesTab = hrbacEnabled && hasUserScopeAssignmentPermission;
57
+ const hasAnyPermission = showUsersTab || showRolesTab || showPermissionsTab || showScopeHierarchyTab || showScopeLabelsTab || showUserScopesTab;
45
58
  // Tab 1: Users state
46
59
  const [users, setUsers] = useState([]);
47
60
  const [usersLoading, setUsersLoading] = useState(true);
@@ -420,7 +433,10 @@ export function UserManagementLayout({ className }) {
420
433
  };
421
434
  return (_jsxs("div", { className: `cls_user_management_layout flex flex-col gap-4 w-full ${className || ""}`, children: [authResult.loading ? (_jsx("div", { className: "cls_user_management_permissions_loading flex items-center justify-center p-8", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-slate-400" }) })) : !hasAnyPermission ? (_jsxs("div", { className: "cls_user_management_no_permissions flex flex-col items-center justify-center p-8 gap-4", children: [_jsx("p", { className: "text-lg font-semibold text-slate-700", children: "Access Denied" }), _jsx("p", { className: "text-sm text-muted-foreground text-center", children: "You don't have permission to access User Management. Please contact your administrator." })] })) : (_jsxs(Tabs, { defaultValue: showUsersTab ? "users" :
422
435
  showRolesTab ? "roles" :
423
- showPermissionsTab ? "permissions" : "users", className: "cls_user_management_tabs w-full", children: [_jsxs(TabsList, { className: "cls_user_management_tabs_list flex w-full", children: [showUsersTab && (_jsx(TabsTrigger, { value: "users", className: "cls_user_management_tabs_trigger flex-1", children: "Manage Users" })), showRolesTab && (_jsx(TabsTrigger, { value: "roles", className: "cls_user_management_tabs_trigger flex-1", children: "Roles" })), showPermissionsTab && (_jsx(TabsTrigger, { value: "permissions", className: "cls_user_management_tabs_trigger flex-1", children: "Permissions" }))] }), showUsersTab && (_jsx(TabsContent, { value: "users", className: "cls_user_management_tab_users w-full", children: usersLoading ? (_jsx("div", { className: "cls_user_management_users_loading flex items-center justify-center p-8", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-slate-400" }) })) : (_jsx("div", { className: "cls_user_management_users_table_container border rounded-lg overflow-auto w-full", children: _jsxs(Table, { className: "cls_user_management_users_table w-full", children: [_jsx(TableHeader, { className: "cls_user_management_users_table_header", children: _jsxs(TableRow, { className: "cls_user_management_users_table_header_row", children: [_jsx(TableHead, { className: "cls_user_management_users_table_header_profile_pic w-16", children: "Photo" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_id", children: "ID" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_name", children: "Name" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_email", children: "Email" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_email_verified", children: "Email Verified" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_is_active", children: "Active" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_last_logon", children: "Last Logon" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_created_at", children: "Created At" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_actions text-right", children: "Actions" })] }) }), _jsx(TableBody, { className: "cls_user_management_users_table_body", children: users.length === 0 ? (_jsx(TableRow, { className: "cls_user_management_users_table_row_empty", children: _jsx(TableCell, { colSpan: 9, className: "text-center text-muted-foreground py-8", children: "No users found." }) })) : (users.map((user) => (_jsxs(TableRow, { className: "cls_user_management_users_table_row cursor-pointer hover:bg-muted/50", onClick: () => {
436
+ showPermissionsTab ? "permissions" :
437
+ showScopeLabelsTab ? "scope_labels" :
438
+ showScopeHierarchyTab ? "scope_hierarchy" :
439
+ showUserScopesTab ? "user_scopes" : "users", className: "cls_user_management_tabs w-full", children: [_jsxs(TabsList, { className: "cls_user_management_tabs_list flex w-full flex-wrap", children: [showUsersTab && (_jsx(TabsTrigger, { value: "users", className: "cls_user_management_tabs_trigger flex-1", children: "Manage Users" })), showRolesTab && (_jsx(TabsTrigger, { value: "roles", className: "cls_user_management_tabs_trigger flex-1", children: "Roles" })), showPermissionsTab && (_jsx(TabsTrigger, { value: "permissions", className: "cls_user_management_tabs_trigger flex-1", children: "Permissions" })), showScopeLabelsTab && (_jsx(TabsTrigger, { value: "scope_labels", className: "cls_user_management_tabs_trigger flex-1", children: "Scope Labels" })), showScopeHierarchyTab && (_jsx(TabsTrigger, { value: "scope_hierarchy", className: "cls_user_management_tabs_trigger flex-1", children: "Scope Hierarchy" })), showUserScopesTab && (_jsx(TabsTrigger, { value: "user_scopes", className: "cls_user_management_tabs_trigger flex-1", children: "User Scopes" }))] }), showUsersTab && (_jsx(TabsContent, { value: "users", className: "cls_user_management_tab_users w-full", children: usersLoading ? (_jsx("div", { className: "cls_user_management_users_loading flex items-center justify-center p-8", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-slate-400" }) })) : (_jsx("div", { className: "cls_user_management_users_table_container border rounded-lg overflow-auto w-full", children: _jsxs(Table, { className: "cls_user_management_users_table w-full", children: [_jsx(TableHeader, { className: "cls_user_management_users_table_header", children: _jsxs(TableRow, { className: "cls_user_management_users_table_header_row", children: [_jsx(TableHead, { className: "cls_user_management_users_table_header_profile_pic w-16", children: "Photo" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_id", children: "ID" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_name", children: "Name" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_email", children: "Email" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_email_verified", children: "Email Verified" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_is_active", children: "Active" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_last_logon", children: "Last Logon" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_created_at", children: "Created At" }), _jsx(TableHead, { className: "cls_user_management_users_table_header_actions text-right", children: "Actions" })] }) }), _jsx(TableBody, { className: "cls_user_management_users_table_body", children: users.length === 0 ? (_jsx(TableRow, { className: "cls_user_management_users_table_row_empty", children: _jsx(TableCell, { colSpan: 9, className: "text-center text-muted-foreground py-8", children: "No users found." }) })) : (users.map((user) => (_jsxs(TableRow, { className: "cls_user_management_users_table_row cursor-pointer hover:bg-muted/50", onClick: () => {
424
440
  setSelectedUser(user);
425
441
  setUserDetailDialogOpen(true);
426
442
  }, children: [_jsx(TableCell, { className: "cls_user_management_users_table_cell_profile_pic", children: _jsxs(Avatar, { className: "cls_user_management_users_table_avatar h-8 w-8", children: [_jsx(AvatarImage, { src: user.profile_picture_url || undefined, alt: user.name ? `Profile picture of ${user.name}` : "Profile picture", className: "cls_user_management_users_table_avatar_image" }), _jsx(AvatarFallback, { className: "cls_user_management_users_table_avatar_fallback bg-slate-200 text-slate-600 text-xs", children: getUserInitials(user) })] }) }), _jsxs(TableCell, { className: "cls_user_management_users_table_cell_id font-mono text-xs", children: [user.id.substring(0, 8), "..."] }), _jsx(TableCell, { className: "cls_user_management_users_table_cell_name", children: user.name || "-" }), _jsx(TableCell, { className: "cls_user_management_users_table_cell_email", children: user.email_address }), _jsx(TableCell, { className: "cls_user_management_users_table_cell_email_verified", children: user.email_verified ? (_jsx("span", { className: "text-green-600", children: "Yes" })) : (_jsx("span", { className: "text-red-600", children: "No" })) }), _jsx(TableCell, { className: "cls_user_management_users_table_cell_is_active", children: user.is_active ? (_jsx("span", { className: "text-green-600", children: "Active" })) : (_jsx("span", { className: "text-red-600", children: "Inactive" })) }), _jsx(TableCell, { className: "cls_user_management_users_table_cell_last_logon", children: user.last_logon
@@ -445,7 +461,7 @@ export function UserManagementLayout({ className }) {
445
461
  setEditingPermission(permission);
446
462
  setEditDescription(permission.description);
447
463
  setEditPermissionDialogOpen(true);
448
- }, variant: "outline", size: "sm", className: "cls_user_management_permissions_table_action_edit", children: [_jsx(Edit, { className: "h-4 w-4 mr-1" }), "Edit"] }), _jsxs(Button, { onClick: () => handleDeletePermission(permission), disabled: permissionsActionLoading, variant: "outline", size: "sm", className: "cls_user_management_permissions_table_action_delete text-destructive", children: [_jsx(Trash2, { className: "h-4 w-4 mr-1" }), "Delete"] })] })) }) })] }, `${permission.source}-${permission.id}-${permission.permission_name}`)))) })] }) }))] }) }))] })), _jsx(AlertDialog, { open: deactivateDialogOpen, onOpenChange: setDeactivateDialogOpen, children: _jsxs(AlertDialogContent, { className: "cls_user_management_deactivate_dialog", children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Deactivate User" }), _jsxs(AlertDialogDescription, { children: ["Are you sure you want to deactivate ", (selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.name) || (selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.email_address), "? They will not be able to log in until reactivated."] })] }), _jsxs(AlertDialogFooter, { className: "cls_user_management_deactivate_dialog_footer", children: [_jsx(AlertDialogAction, { onClick: handleDeactivateUser, disabled: usersActionLoading, className: "cls_user_management_deactivate_dialog_confirm", children: usersActionLoading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "h-4 w-4 mr-2 animate-spin" }), "Deactivating..."] })) : ("Deactivate") }), _jsx(AlertDialogCancel, { onClick: () => {
464
+ }, variant: "outline", size: "sm", className: "cls_user_management_permissions_table_action_edit", children: [_jsx(Edit, { className: "h-4 w-4 mr-1" }), "Edit"] }), _jsxs(Button, { onClick: () => handleDeletePermission(permission), disabled: permissionsActionLoading, variant: "outline", size: "sm", className: "cls_user_management_permissions_table_action_delete text-destructive", children: [_jsx(Trash2, { className: "h-4 w-4 mr-1" }), "Delete"] })] })) }) })] }, `${permission.source}-${permission.id}-${permission.permission_name}`)))) })] }) }))] }) })), showScopeLabelsTab && (_jsx(TabsContent, { value: "scope_labels", className: "cls_user_management_tab_scope_labels w-full", children: _jsx(ScopeLabelsTab, { defaultOrg: defaultOrg }) })), showScopeHierarchyTab && (_jsx(TabsContent, { value: "scope_hierarchy", className: "cls_user_management_tab_scope_hierarchy w-full", children: _jsx(ScopeHierarchyTab, { defaultOrg: defaultOrg }) })), showUserScopesTab && (_jsx(TabsContent, { value: "user_scopes", className: "cls_user_management_tab_user_scopes w-full", children: _jsx(UserScopesTab, {}) }))] })), _jsx(AlertDialog, { open: deactivateDialogOpen, onOpenChange: setDeactivateDialogOpen, children: _jsxs(AlertDialogContent, { className: "cls_user_management_deactivate_dialog", children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Deactivate User" }), _jsxs(AlertDialogDescription, { children: ["Are you sure you want to deactivate ", (selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.name) || (selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.email_address), "? They will not be able to log in until reactivated."] })] }), _jsxs(AlertDialogFooter, { className: "cls_user_management_deactivate_dialog_footer", children: [_jsx(AlertDialogAction, { onClick: handleDeactivateUser, disabled: usersActionLoading, className: "cls_user_management_deactivate_dialog_confirm", children: usersActionLoading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "h-4 w-4 mr-2 animate-spin" }), "Deactivating..."] })) : ("Deactivate") }), _jsx(AlertDialogCancel, { onClick: () => {
449
465
  setDeactivateDialogOpen(false);
450
466
  setSelectedUser(null);
451
467
  }, className: "cls_user_management_deactivate_dialog_cancel", children: "Cancel" })] })] }) }), _jsx(AlertDialog, { open: resetPasswordDialogOpen, onOpenChange: setResetPasswordDialogOpen, children: _jsxs(AlertDialogContent, { className: "cls_user_management_reset_password_dialog", children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Reset Password" }), _jsxs(AlertDialogDescription, { children: ["Send a password reset email to ", selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.email_address, "? They will receive a link to reset their password."] })] }), _jsxs(AlertDialogFooter, { className: "cls_user_management_reset_password_dialog_footer", children: [_jsx(AlertDialogAction, { onClick: handleResetPassword, disabled: usersActionLoading, className: "cls_user_management_reset_password_dialog_confirm", children: usersActionLoading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "h-4 w-4 mr-2 animate-spin" }), "Sending..."] })) : ("Send Reset Email") }), _jsx(AlertDialogCancel, { onClick: () => {
@@ -0,0 +1,7 @@
1
+ import * as React from "react";
2
+ import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
3
+ declare const HoverCard: React.FC<HoverCardPrimitive.HoverCardProps>;
4
+ declare const HoverCardTrigger: React.ForwardRefExoticComponent<HoverCardPrimitive.HoverCardTriggerProps & React.RefAttributes<HTMLAnchorElement>>;
5
+ declare const HoverCardContent: React.ForwardRefExoticComponent<Omit<HoverCardPrimitive.HoverCardContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
6
+ export { HoverCard, HoverCardTrigger, HoverCardContent };
7
+ //# sourceMappingURL=hover-card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hover-card.d.ts","sourceRoot":"","sources":["../../../src/components/ui/hover-card.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,kBAAkB,MAAM,4BAA4B,CAAA;AAKhE,QAAA,MAAM,SAAS,6CAA0B,CAAA;AAEzC,QAAA,MAAM,gBAAgB,oHAA6B,CAAA;AAEnD,QAAA,MAAM,gBAAgB,oKAcpB,CAAA;AAIF,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,CAAA"}
@@ -0,0 +1,29 @@
1
+ // file_description: HoverCard component from shadcn/ui using Radix UI
2
+ // section: client_directive
3
+ "use client";
4
+ var __rest = (this && this.__rest) || function (s, e) {
5
+ var t = {};
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
7
+ t[p] = s[p];
8
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
9
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
10
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
11
+ t[p[i]] = s[p[i]];
12
+ }
13
+ return t;
14
+ };
15
+ import { jsx as _jsx } from "react/jsx-runtime";
16
+ // section: imports
17
+ import * as React from "react";
18
+ import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
19
+ import { cn } from "../../lib/utils";
20
+ // section: components
21
+ const HoverCard = HoverCardPrimitive.Root;
22
+ const HoverCardTrigger = HoverCardPrimitive.Trigger;
23
+ const HoverCardContent = React.forwardRef((_a, ref) => {
24
+ var { className, align = "center", sideOffset = 4 } = _a, props = __rest(_a, ["className", "align", "sideOffset"]);
25
+ return (_jsx(HoverCardPrimitive.Content, Object.assign({ ref: ref, align: align, sideOffset: sideOffset, className: cn("z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-hover-card-content-transform-origin]", className) }, props)));
26
+ });
27
+ HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
28
+ // section: exports
29
+ export { HoverCard, HoverCardTrigger, HoverCardContent };
@@ -5,6 +5,7 @@ export * from "./checkbox";
5
5
  export * from "./dialog";
6
6
  export * from "./dropdown-menu";
7
7
  export * from "./hazo_ui_tooltip";
8
+ export * from "./hover-card";
8
9
  export * from "./input";
9
10
  export * from "./label";
10
11
  export * from "./separator";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ui/index.ts"],"names":[],"mappings":"AAEA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ui/index.ts"],"names":[],"mappings":"AAEA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC"}
@@ -7,6 +7,7 @@ export * from "./checkbox";
7
7
  export * from "./dialog";
8
8
  export * from "./dropdown-menu";
9
9
  export * from "./hazo_ui_tooltip";
10
+ export * from "./hover-card";
10
11
  export * from "./input";
11
12
  export * from "./label";
12
13
  export * from "./separator";
@@ -0,0 +1,14 @@
1
+ import * as React from "react";
2
+ import * as SelectPrimitive from "@radix-ui/react-select";
3
+ declare const Select: React.FC<SelectPrimitive.SelectProps>;
4
+ declare const SelectGroup: React.ForwardRefExoticComponent<SelectPrimitive.SelectGroupProps & React.RefAttributes<HTMLDivElement>>;
5
+ declare const SelectValue: React.ForwardRefExoticComponent<SelectPrimitive.SelectValueProps & React.RefAttributes<HTMLSpanElement>>;
6
+ declare const SelectTrigger: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectTriggerProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
7
+ declare const SelectScrollUpButton: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectScrollUpButtonProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
8
+ declare const SelectScrollDownButton: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectScrollDownButtonProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
9
+ declare const SelectContent: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
10
+ declare const SelectLabel: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectLabelProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
11
+ declare const SelectItem: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectItemProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
12
+ declare const SelectSeparator: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectSeparatorProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
13
+ export { Select, SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectLabel, SelectItem, SelectSeparator, SelectScrollUpButton, SelectScrollDownButton, };
14
+ //# sourceMappingURL=select.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../../src/components/ui/select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAA;AAKzD,QAAA,MAAM,MAAM,uCAAuB,CAAA;AAEnC,QAAA,MAAM,WAAW,yGAAwB,CAAA;AAEzC,QAAA,MAAM,WAAW,0GAAwB,CAAA;AAEzC,QAAA,MAAM,aAAa,oKAiBjB,CAAA;AAGF,QAAA,MAAM,oBAAoB,qKAcxB,CAAA;AAGF,QAAA,MAAM,sBAAsB,uKAc1B,CAAA;AAIF,QAAA,MAAM,aAAa,8JA6BjB,CAAA;AAGF,QAAA,MAAM,WAAW,4JASf,CAAA;AAGF,QAAA,MAAM,UAAU,2JAoBd,CAAA;AAGF,QAAA,MAAM,eAAe,gKASnB,CAAA;AAGF,OAAO,EACL,MAAM,EACN,WAAW,EACX,WAAW,EACX,aAAa,EACb,aAAa,EACb,WAAW,EACX,UAAU,EACV,eAAe,EACf,oBAAoB,EACpB,sBAAsB,GACvB,CAAA"}
@@ -0,0 +1,59 @@
1
+ "use client";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
+ import * as React from "react";
15
+ import * as SelectPrimitive from "@radix-ui/react-select";
16
+ import { Check, ChevronDown, ChevronUp } from "lucide-react";
17
+ import { cn } from "../../lib/utils";
18
+ const Select = SelectPrimitive.Root;
19
+ const SelectGroup = SelectPrimitive.Group;
20
+ const SelectValue = SelectPrimitive.Value;
21
+ const SelectTrigger = React.forwardRef((_a, ref) => {
22
+ var { className, children } = _a, props = __rest(_a, ["className", "children"]);
23
+ return (_jsxs(SelectPrimitive.Trigger, Object.assign({ ref: ref, className: cn("flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1", className) }, props, { children: [children, _jsx(SelectPrimitive.Icon, { asChild: true, children: _jsx(ChevronDown, { className: "h-4 w-4 opacity-50" }) })] })));
24
+ });
25
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
26
+ const SelectScrollUpButton = React.forwardRef((_a, ref) => {
27
+ var { className } = _a, props = __rest(_a, ["className"]);
28
+ return (_jsx(SelectPrimitive.ScrollUpButton, Object.assign({ ref: ref, className: cn("flex cursor-default items-center justify-center py-1", className) }, props, { children: _jsx(ChevronUp, { className: "h-4 w-4" }) })));
29
+ });
30
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
31
+ const SelectScrollDownButton = React.forwardRef((_a, ref) => {
32
+ var { className } = _a, props = __rest(_a, ["className"]);
33
+ return (_jsx(SelectPrimitive.ScrollDownButton, Object.assign({ ref: ref, className: cn("flex cursor-default items-center justify-center py-1", className) }, props, { children: _jsx(ChevronDown, { className: "h-4 w-4" }) })));
34
+ });
35
+ SelectScrollDownButton.displayName =
36
+ SelectPrimitive.ScrollDownButton.displayName;
37
+ const SelectContent = React.forwardRef((_a, ref) => {
38
+ var { className, children, position = "popper" } = _a, props = __rest(_a, ["className", "children", "position"]);
39
+ return (_jsx(SelectPrimitive.Portal, { children: _jsxs(SelectPrimitive.Content, Object.assign({ ref: ref, className: cn("relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", position === "popper" &&
40
+ "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", className), position: position }, props, { children: [_jsx(SelectScrollUpButton, {}), _jsx(SelectPrimitive.Viewport, { className: cn("p-1", position === "popper" &&
41
+ "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"), children: children }), _jsx(SelectScrollDownButton, {})] })) }));
42
+ });
43
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
44
+ const SelectLabel = React.forwardRef((_a, ref) => {
45
+ var { className } = _a, props = __rest(_a, ["className"]);
46
+ return (_jsx(SelectPrimitive.Label, Object.assign({ ref: ref, className: cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className) }, props)));
47
+ });
48
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
49
+ const SelectItem = React.forwardRef((_a, ref) => {
50
+ var { className, children } = _a, props = __rest(_a, ["className", "children"]);
51
+ return (_jsxs(SelectPrimitive.Item, Object.assign({ ref: ref, className: cn("relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className) }, props, { children: [_jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(SelectPrimitive.ItemIndicator, { children: _jsx(Check, { className: "h-4 w-4" }) }) }), _jsx(SelectPrimitive.ItemText, { children: children })] })));
52
+ });
53
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
54
+ const SelectSeparator = React.forwardRef((_a, ref) => {
55
+ var { className } = _a, props = __rest(_a, ["className"]);
56
+ return (_jsx(SelectPrimitive.Separator, Object.assign({ ref: ref, className: cn("-mx-1 my-1 h-px bg-muted", className) }, props)));
57
+ });
58
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
59
+ export { Select, SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectLabel, SelectItem, SelectSeparator, SelectScrollUpButton, SelectScrollDownButton, };