@omnibase/shadcn 0.5.1 → 0.5.3
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 +253 -1
- package/dist/index.d.cts +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +252 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -40,6 +40,7 @@ __export(index_exports, {
|
|
|
40
40
|
SwitchActiveTenant: () => SwitchActiveTenant,
|
|
41
41
|
TenantCreator: () => TenantCreator,
|
|
42
42
|
UserInvite: () => UserInvite,
|
|
43
|
+
UserViewer: () => UserViewer,
|
|
43
44
|
VerificationForm: () => VerificationForm,
|
|
44
45
|
filterInputNodes: () => filterInputNodes,
|
|
45
46
|
findAnchorNode: () => findAnchorNode,
|
|
@@ -146,7 +147,7 @@ var alertVariants = (0, import_class_variance_authority.cva)(
|
|
|
146
147
|
destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
|
|
147
148
|
warning: "border-yellow-500/50 text-yellow-700 bg-yellow-50 dark:border-yellow-500 dark:text-yellow-200 dark:bg-yellow-950/20 [&>svg]:text-yellow-600 dark:[&>svg]:text-yellow-200",
|
|
148
149
|
success: "border-green-500/50 text-green-700 bg-green-50 dark:border-green-500 dark:text-green-200 dark:bg-green-950/20 [&>svg]:text-green-600 dark:[&>svg]:text-green-200",
|
|
149
|
-
info: "border-blue-500/50 text-blue-
|
|
150
|
+
info: "border-blue-500/50 text-blue-900 bg-blue-50 dark:border-blue-500 dark:text-blue-200 dark:bg-blue-950/20 [&>svg]:text-blue-900 dark:[&>svg]:text-blue-200"
|
|
150
151
|
}
|
|
151
152
|
},
|
|
152
153
|
defaultVariants: {
|
|
@@ -2018,6 +2019,256 @@ function RoleCreator({
|
|
|
2018
2019
|
] })
|
|
2019
2020
|
] });
|
|
2020
2021
|
}
|
|
2022
|
+
|
|
2023
|
+
// src/user-viewer/index.tsx
|
|
2024
|
+
var import_react4 = require("react");
|
|
2025
|
+
|
|
2026
|
+
// src/components/ui/table.tsx
|
|
2027
|
+
var React16 = require("react");
|
|
2028
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
2029
|
+
function Table({ className, ...props }) {
|
|
2030
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2031
|
+
"div",
|
|
2032
|
+
{
|
|
2033
|
+
"data-slot": "table-container",
|
|
2034
|
+
className: "relative w-full overflow-x-auto",
|
|
2035
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2036
|
+
"table",
|
|
2037
|
+
{
|
|
2038
|
+
"data-slot": "table",
|
|
2039
|
+
className: cn("w-full caption-bottom text-sm", className),
|
|
2040
|
+
...props
|
|
2041
|
+
}
|
|
2042
|
+
)
|
|
2043
|
+
}
|
|
2044
|
+
);
|
|
2045
|
+
}
|
|
2046
|
+
function TableHeader({ className, ...props }) {
|
|
2047
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2048
|
+
"thead",
|
|
2049
|
+
{
|
|
2050
|
+
"data-slot": "table-header",
|
|
2051
|
+
className: cn("[&_tr]:border-b", className),
|
|
2052
|
+
...props
|
|
2053
|
+
}
|
|
2054
|
+
);
|
|
2055
|
+
}
|
|
2056
|
+
function TableBody({ className, ...props }) {
|
|
2057
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2058
|
+
"tbody",
|
|
2059
|
+
{
|
|
2060
|
+
"data-slot": "table-body",
|
|
2061
|
+
className: cn("[&_tr:last-child]:border-0", className),
|
|
2062
|
+
...props
|
|
2063
|
+
}
|
|
2064
|
+
);
|
|
2065
|
+
}
|
|
2066
|
+
function TableRow({ className, ...props }) {
|
|
2067
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2068
|
+
"tr",
|
|
2069
|
+
{
|
|
2070
|
+
"data-slot": "table-row",
|
|
2071
|
+
className: cn(
|
|
2072
|
+
"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
|
|
2073
|
+
className
|
|
2074
|
+
),
|
|
2075
|
+
...props
|
|
2076
|
+
}
|
|
2077
|
+
);
|
|
2078
|
+
}
|
|
2079
|
+
function TableHead({ className, ...props }) {
|
|
2080
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2081
|
+
"th",
|
|
2082
|
+
{
|
|
2083
|
+
"data-slot": "table-head",
|
|
2084
|
+
className: cn(
|
|
2085
|
+
"text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
|
2086
|
+
className
|
|
2087
|
+
),
|
|
2088
|
+
...props
|
|
2089
|
+
}
|
|
2090
|
+
);
|
|
2091
|
+
}
|
|
2092
|
+
function TableCell({ className, ...props }) {
|
|
2093
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2094
|
+
"td",
|
|
2095
|
+
{
|
|
2096
|
+
"data-slot": "table-cell",
|
|
2097
|
+
className: cn(
|
|
2098
|
+
"p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
|
2099
|
+
className
|
|
2100
|
+
),
|
|
2101
|
+
...props
|
|
2102
|
+
}
|
|
2103
|
+
);
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
// src/components/ui/avatar.tsx
|
|
2107
|
+
var React17 = require("react");
|
|
2108
|
+
var AvatarPrimitive = __toESM(require("@radix-ui/react-avatar"), 1);
|
|
2109
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
2110
|
+
function Avatar({
|
|
2111
|
+
className,
|
|
2112
|
+
...props
|
|
2113
|
+
}) {
|
|
2114
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2115
|
+
AvatarPrimitive.Root,
|
|
2116
|
+
{
|
|
2117
|
+
"data-slot": "avatar",
|
|
2118
|
+
className: cn(
|
|
2119
|
+
"relative flex size-8 shrink-0 overflow-hidden rounded-full",
|
|
2120
|
+
className
|
|
2121
|
+
),
|
|
2122
|
+
...props
|
|
2123
|
+
}
|
|
2124
|
+
);
|
|
2125
|
+
}
|
|
2126
|
+
function AvatarFallback({
|
|
2127
|
+
className,
|
|
2128
|
+
...props
|
|
2129
|
+
}) {
|
|
2130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2131
|
+
AvatarPrimitive.Fallback,
|
|
2132
|
+
{
|
|
2133
|
+
"data-slot": "avatar-fallback",
|
|
2134
|
+
className: cn(
|
|
2135
|
+
"bg-muted flex size-full items-center justify-center rounded-full",
|
|
2136
|
+
className
|
|
2137
|
+
),
|
|
2138
|
+
...props
|
|
2139
|
+
}
|
|
2140
|
+
);
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
// src/user-viewer/index.tsx
|
|
2144
|
+
var import_lucide_react4 = require("lucide-react");
|
|
2145
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
2146
|
+
function UserViewer({
|
|
2147
|
+
users,
|
|
2148
|
+
availableRoles,
|
|
2149
|
+
canEditUsers,
|
|
2150
|
+
onRoleUpdate,
|
|
2151
|
+
onRemoveUser
|
|
2152
|
+
}) {
|
|
2153
|
+
const [searchQuery, setSearchQuery] = (0, import_react4.useState)("");
|
|
2154
|
+
const [isUpdating, setIsUpdating] = (0, import_react4.useState)({});
|
|
2155
|
+
const getInitials = (firstName, lastName) => {
|
|
2156
|
+
return `${firstName.charAt(0)}${lastName.charAt(0)}`.toUpperCase();
|
|
2157
|
+
};
|
|
2158
|
+
const filteredUsers = (0, import_react4.useMemo)(() => {
|
|
2159
|
+
if (!searchQuery.trim()) return users;
|
|
2160
|
+
const query = searchQuery.toLowerCase();
|
|
2161
|
+
return users.filter(
|
|
2162
|
+
(user) => user.first_name.toLowerCase().includes(query) || user.last_name.toLowerCase().includes(query) || user.email.toLowerCase().includes(query) || user.role.toLowerCase().includes(query)
|
|
2163
|
+
);
|
|
2164
|
+
}, [users, searchQuery]);
|
|
2165
|
+
const handleRoleUpdate = async (userId, newRole) => {
|
|
2166
|
+
if (!onRoleUpdate) return;
|
|
2167
|
+
setIsUpdating((prev) => ({ ...prev, [userId]: true }));
|
|
2168
|
+
try {
|
|
2169
|
+
await onRoleUpdate(userId, newRole);
|
|
2170
|
+
} catch (error) {
|
|
2171
|
+
console.error("Failed to update role:", error);
|
|
2172
|
+
} finally {
|
|
2173
|
+
setIsUpdating((prev) => ({ ...prev, [userId]: false }));
|
|
2174
|
+
}
|
|
2175
|
+
};
|
|
2176
|
+
const handleRemoveUser = async (userId) => {
|
|
2177
|
+
if (!onRemoveUser) return;
|
|
2178
|
+
const confirmed = window.confirm(
|
|
2179
|
+
"Are you sure you want to remove this user from the organization?"
|
|
2180
|
+
);
|
|
2181
|
+
if (!confirmed) return;
|
|
2182
|
+
setIsUpdating((prev) => ({ ...prev, [userId]: true }));
|
|
2183
|
+
try {
|
|
2184
|
+
await onRemoveUser(userId);
|
|
2185
|
+
} catch (error) {
|
|
2186
|
+
console.error("Failed to remove user:", error);
|
|
2187
|
+
} finally {
|
|
2188
|
+
setIsUpdating((prev) => ({ ...prev, [userId]: false }));
|
|
2189
|
+
}
|
|
2190
|
+
};
|
|
2191
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Card, { className: "w-full max-w-6xl", children: [
|
|
2192
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(CardHeader, { children: [
|
|
2193
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(CardTitle, { children: "Team Members" }),
|
|
2194
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(CardDescription, { children: canEditUsers ? "View and manage users in your organization" : "View users in your organization" })
|
|
2195
|
+
] }),
|
|
2196
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(CardContent, { children: [
|
|
2197
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "mb-6", children: [
|
|
2198
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Label, { htmlFor: "search", className: "sr-only", children: "Search users" }),
|
|
2199
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "relative", children: [
|
|
2200
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react4.Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
|
|
2201
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
2202
|
+
Input,
|
|
2203
|
+
{
|
|
2204
|
+
id: "search",
|
|
2205
|
+
type: "text",
|
|
2206
|
+
placeholder: "Search by name, email, or role...",
|
|
2207
|
+
value: searchQuery,
|
|
2208
|
+
onChange: (e) => setSearchQuery(e.target.value),
|
|
2209
|
+
className: "pl-10"
|
|
2210
|
+
}
|
|
2211
|
+
)
|
|
2212
|
+
] }),
|
|
2213
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("p", { className: "text-xs text-muted-foreground mt-2", children: [
|
|
2214
|
+
"Showing ",
|
|
2215
|
+
filteredUsers.length,
|
|
2216
|
+
" of ",
|
|
2217
|
+
users.length,
|
|
2218
|
+
" users"
|
|
2219
|
+
] })
|
|
2220
|
+
] }),
|
|
2221
|
+
filteredUsers.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "border rounded-lg overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Table, { children: [
|
|
2222
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(TableRow, { children: [
|
|
2223
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableHead, { className: "w-[300px]", children: "User" }),
|
|
2224
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableHead, { children: "Email" }),
|
|
2225
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableHead, { className: "w-[180px]", children: "Role" }),
|
|
2226
|
+
canEditUsers && onRemoveUser && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableHead, { className: "w-[100px] text-right", children: "Actions" })
|
|
2227
|
+
] }) }),
|
|
2228
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableBody, { children: filteredUsers.map((user) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(TableRow, { children: [
|
|
2229
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableCell, { className: "font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
2230
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Avatar, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(AvatarFallback, { children: getInitials(user.first_name, user.last_name) }) }),
|
|
2231
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
|
|
2232
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "font-medium", children: [
|
|
2233
|
+
user.first_name,
|
|
2234
|
+
" ",
|
|
2235
|
+
user.last_name
|
|
2236
|
+
] }),
|
|
2237
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "text-xs text-muted-foreground md:hidden", children: user.email })
|
|
2238
|
+
] })
|
|
2239
|
+
] }) }),
|
|
2240
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableCell, { className: "hidden md:table-cell", children: user.email }),
|
|
2241
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableCell, { children: canEditUsers && onRoleUpdate ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
2242
|
+
Select,
|
|
2243
|
+
{
|
|
2244
|
+
value: user.role,
|
|
2245
|
+
onValueChange: (newRole) => handleRoleUpdate(user.user_id, newRole),
|
|
2246
|
+
disabled: isUpdating[user.user_id],
|
|
2247
|
+
children: [
|
|
2248
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(SelectTrigger, { className: "w-full", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(SelectValue, {}) }),
|
|
2249
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(SelectContent, { children: availableRoles.map((role) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(SelectItem, { value: role, children: role }, role)) })
|
|
2250
|
+
]
|
|
2251
|
+
}
|
|
2252
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "capitalize text-sm font-medium", children: user.role }) }),
|
|
2253
|
+
canEditUsers && onRemoveUser && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TableCell, { className: "text-right", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
2254
|
+
Button,
|
|
2255
|
+
{
|
|
2256
|
+
variant: "ghost",
|
|
2257
|
+
size: "icon",
|
|
2258
|
+
onClick: () => handleRemoveUser(user.user_id),
|
|
2259
|
+
disabled: isUpdating[user.user_id],
|
|
2260
|
+
className: "h-8 w-8",
|
|
2261
|
+
children: [
|
|
2262
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react4.UserX, { className: "h-4 w-4" }),
|
|
2263
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "sr-only", children: "Remove user" })
|
|
2264
|
+
]
|
|
2265
|
+
}
|
|
2266
|
+
) })
|
|
2267
|
+
] }, user.user_id)) })
|
|
2268
|
+
] }) }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "text-center py-12 border rounded-lg", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-muted-foreground", children: searchQuery ? "No users found matching your search" : "No users in this organization yet" }) })
|
|
2269
|
+
] })
|
|
2270
|
+
] });
|
|
2271
|
+
}
|
|
2021
2272
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2022
2273
|
0 && (module.exports = {
|
|
2023
2274
|
LoginForm,
|
|
@@ -2029,6 +2280,7 @@ function RoleCreator({
|
|
|
2029
2280
|
SwitchActiveTenant,
|
|
2030
2281
|
TenantCreator,
|
|
2031
2282
|
UserInvite,
|
|
2283
|
+
UserViewer,
|
|
2032
2284
|
VerificationForm,
|
|
2033
2285
|
filterInputNodes,
|
|
2034
2286
|
findAnchorNode,
|
package/dist/index.d.cts
CHANGED
|
@@ -157,4 +157,20 @@ interface RoleCreatorProps {
|
|
|
157
157
|
}
|
|
158
158
|
declare function RoleCreator({ definitions, roles, namespaceMap, onRoleCreate, onRoleUpdate, }: RoleCreatorProps): react_jsx_runtime.JSX.Element;
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
interface TenantUser {
|
|
161
|
+
user_id: string;
|
|
162
|
+
first_name: string;
|
|
163
|
+
last_name: string;
|
|
164
|
+
email: string;
|
|
165
|
+
role: string;
|
|
166
|
+
}
|
|
167
|
+
interface UserViewerProps {
|
|
168
|
+
users: TenantUser[];
|
|
169
|
+
availableRoles: string[];
|
|
170
|
+
canEditUsers: boolean;
|
|
171
|
+
onRoleUpdate?: (userId: string, newRole: string) => void | Promise<void>;
|
|
172
|
+
onRemoveUser?: (userId: string) => void | Promise<void>;
|
|
173
|
+
}
|
|
174
|
+
declare function UserViewer({ users, availableRoles, canEditUsers, onRoleUpdate, onRemoveUser, }: UserViewerProps): react_jsx_runtime.JSX.Element;
|
|
175
|
+
|
|
176
|
+
export { type CustomFormProps, type FlowType, LoginForm, type LoginFormProps, type NodesByGroup, PricingTable, type PricingTableProps, RecoveryForm, type RecoveryFormProps, RegistrationForm, type RegistrationFormProps, RoleCreator, SettingsForm, type SettingsFormProps, SwitchActiveTenant, type SwitchActiveTenantProps, TenantCreator, type TenantCreatorConfig, type TenantCreatorFormActions, type TenantCreatorProps, type TenantUser, UserInvite, UserViewer, VerificationForm, type VerificationFormProps, filterInputNodes, findAnchorNode, findCsrfToken, findSubmitButton, groupNodesByGroup, isUiNodeInputAttributes, sortNodes };
|
package/dist/index.d.ts
CHANGED
|
@@ -157,4 +157,20 @@ interface RoleCreatorProps {
|
|
|
157
157
|
}
|
|
158
158
|
declare function RoleCreator({ definitions, roles, namespaceMap, onRoleCreate, onRoleUpdate, }: RoleCreatorProps): react_jsx_runtime.JSX.Element;
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
interface TenantUser {
|
|
161
|
+
user_id: string;
|
|
162
|
+
first_name: string;
|
|
163
|
+
last_name: string;
|
|
164
|
+
email: string;
|
|
165
|
+
role: string;
|
|
166
|
+
}
|
|
167
|
+
interface UserViewerProps {
|
|
168
|
+
users: TenantUser[];
|
|
169
|
+
availableRoles: string[];
|
|
170
|
+
canEditUsers: boolean;
|
|
171
|
+
onRoleUpdate?: (userId: string, newRole: string) => void | Promise<void>;
|
|
172
|
+
onRemoveUser?: (userId: string) => void | Promise<void>;
|
|
173
|
+
}
|
|
174
|
+
declare function UserViewer({ users, availableRoles, canEditUsers, onRoleUpdate, onRemoveUser, }: UserViewerProps): react_jsx_runtime.JSX.Element;
|
|
175
|
+
|
|
176
|
+
export { type CustomFormProps, type FlowType, LoginForm, type LoginFormProps, type NodesByGroup, PricingTable, type PricingTableProps, RecoveryForm, type RecoveryFormProps, RegistrationForm, type RegistrationFormProps, RoleCreator, SettingsForm, type SettingsFormProps, SwitchActiveTenant, type SwitchActiveTenantProps, TenantCreator, type TenantCreatorConfig, type TenantCreatorFormActions, type TenantCreatorProps, type TenantUser, UserInvite, UserViewer, VerificationForm, type VerificationFormProps, filterInputNodes, findAnchorNode, findCsrfToken, findSubmitButton, groupNodesByGroup, isUiNodeInputAttributes, sortNodes };
|
package/dist/index.js
CHANGED
|
@@ -95,7 +95,7 @@ var alertVariants = cva(
|
|
|
95
95
|
destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
|
|
96
96
|
warning: "border-yellow-500/50 text-yellow-700 bg-yellow-50 dark:border-yellow-500 dark:text-yellow-200 dark:bg-yellow-950/20 [&>svg]:text-yellow-600 dark:[&>svg]:text-yellow-200",
|
|
97
97
|
success: "border-green-500/50 text-green-700 bg-green-50 dark:border-green-500 dark:text-green-200 dark:bg-green-950/20 [&>svg]:text-green-600 dark:[&>svg]:text-green-200",
|
|
98
|
-
info: "border-blue-500/50 text-blue-
|
|
98
|
+
info: "border-blue-500/50 text-blue-900 bg-blue-50 dark:border-blue-500 dark:text-blue-200 dark:bg-blue-950/20 [&>svg]:text-blue-900 dark:[&>svg]:text-blue-200"
|
|
99
99
|
}
|
|
100
100
|
},
|
|
101
101
|
defaultVariants: {
|
|
@@ -1967,6 +1967,256 @@ function RoleCreator({
|
|
|
1967
1967
|
] })
|
|
1968
1968
|
] });
|
|
1969
1969
|
}
|
|
1970
|
+
|
|
1971
|
+
// src/user-viewer/index.tsx
|
|
1972
|
+
import { useState as useState7, useMemo as useMemo3 } from "react";
|
|
1973
|
+
|
|
1974
|
+
// src/components/ui/table.tsx
|
|
1975
|
+
import "react";
|
|
1976
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
1977
|
+
function Table({ className, ...props }) {
|
|
1978
|
+
return /* @__PURE__ */ jsx27(
|
|
1979
|
+
"div",
|
|
1980
|
+
{
|
|
1981
|
+
"data-slot": "table-container",
|
|
1982
|
+
className: "relative w-full overflow-x-auto",
|
|
1983
|
+
children: /* @__PURE__ */ jsx27(
|
|
1984
|
+
"table",
|
|
1985
|
+
{
|
|
1986
|
+
"data-slot": "table",
|
|
1987
|
+
className: cn("w-full caption-bottom text-sm", className),
|
|
1988
|
+
...props
|
|
1989
|
+
}
|
|
1990
|
+
)
|
|
1991
|
+
}
|
|
1992
|
+
);
|
|
1993
|
+
}
|
|
1994
|
+
function TableHeader({ className, ...props }) {
|
|
1995
|
+
return /* @__PURE__ */ jsx27(
|
|
1996
|
+
"thead",
|
|
1997
|
+
{
|
|
1998
|
+
"data-slot": "table-header",
|
|
1999
|
+
className: cn("[&_tr]:border-b", className),
|
|
2000
|
+
...props
|
|
2001
|
+
}
|
|
2002
|
+
);
|
|
2003
|
+
}
|
|
2004
|
+
function TableBody({ className, ...props }) {
|
|
2005
|
+
return /* @__PURE__ */ jsx27(
|
|
2006
|
+
"tbody",
|
|
2007
|
+
{
|
|
2008
|
+
"data-slot": "table-body",
|
|
2009
|
+
className: cn("[&_tr:last-child]:border-0", className),
|
|
2010
|
+
...props
|
|
2011
|
+
}
|
|
2012
|
+
);
|
|
2013
|
+
}
|
|
2014
|
+
function TableRow({ className, ...props }) {
|
|
2015
|
+
return /* @__PURE__ */ jsx27(
|
|
2016
|
+
"tr",
|
|
2017
|
+
{
|
|
2018
|
+
"data-slot": "table-row",
|
|
2019
|
+
className: cn(
|
|
2020
|
+
"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
|
|
2021
|
+
className
|
|
2022
|
+
),
|
|
2023
|
+
...props
|
|
2024
|
+
}
|
|
2025
|
+
);
|
|
2026
|
+
}
|
|
2027
|
+
function TableHead({ className, ...props }) {
|
|
2028
|
+
return /* @__PURE__ */ jsx27(
|
|
2029
|
+
"th",
|
|
2030
|
+
{
|
|
2031
|
+
"data-slot": "table-head",
|
|
2032
|
+
className: cn(
|
|
2033
|
+
"text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
|
2034
|
+
className
|
|
2035
|
+
),
|
|
2036
|
+
...props
|
|
2037
|
+
}
|
|
2038
|
+
);
|
|
2039
|
+
}
|
|
2040
|
+
function TableCell({ className, ...props }) {
|
|
2041
|
+
return /* @__PURE__ */ jsx27(
|
|
2042
|
+
"td",
|
|
2043
|
+
{
|
|
2044
|
+
"data-slot": "table-cell",
|
|
2045
|
+
className: cn(
|
|
2046
|
+
"p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
|
2047
|
+
className
|
|
2048
|
+
),
|
|
2049
|
+
...props
|
|
2050
|
+
}
|
|
2051
|
+
);
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
// src/components/ui/avatar.tsx
|
|
2055
|
+
import "react";
|
|
2056
|
+
import * as AvatarPrimitive from "@radix-ui/react-avatar";
|
|
2057
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
2058
|
+
function Avatar({
|
|
2059
|
+
className,
|
|
2060
|
+
...props
|
|
2061
|
+
}) {
|
|
2062
|
+
return /* @__PURE__ */ jsx28(
|
|
2063
|
+
AvatarPrimitive.Root,
|
|
2064
|
+
{
|
|
2065
|
+
"data-slot": "avatar",
|
|
2066
|
+
className: cn(
|
|
2067
|
+
"relative flex size-8 shrink-0 overflow-hidden rounded-full",
|
|
2068
|
+
className
|
|
2069
|
+
),
|
|
2070
|
+
...props
|
|
2071
|
+
}
|
|
2072
|
+
);
|
|
2073
|
+
}
|
|
2074
|
+
function AvatarFallback({
|
|
2075
|
+
className,
|
|
2076
|
+
...props
|
|
2077
|
+
}) {
|
|
2078
|
+
return /* @__PURE__ */ jsx28(
|
|
2079
|
+
AvatarPrimitive.Fallback,
|
|
2080
|
+
{
|
|
2081
|
+
"data-slot": "avatar-fallback",
|
|
2082
|
+
className: cn(
|
|
2083
|
+
"bg-muted flex size-full items-center justify-center rounded-full",
|
|
2084
|
+
className
|
|
2085
|
+
),
|
|
2086
|
+
...props
|
|
2087
|
+
}
|
|
2088
|
+
);
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
// src/user-viewer/index.tsx
|
|
2092
|
+
import { Search, UserX } from "lucide-react";
|
|
2093
|
+
import { jsx as jsx29, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2094
|
+
function UserViewer({
|
|
2095
|
+
users,
|
|
2096
|
+
availableRoles,
|
|
2097
|
+
canEditUsers,
|
|
2098
|
+
onRoleUpdate,
|
|
2099
|
+
onRemoveUser
|
|
2100
|
+
}) {
|
|
2101
|
+
const [searchQuery, setSearchQuery] = useState7("");
|
|
2102
|
+
const [isUpdating, setIsUpdating] = useState7({});
|
|
2103
|
+
const getInitials = (firstName, lastName) => {
|
|
2104
|
+
return `${firstName.charAt(0)}${lastName.charAt(0)}`.toUpperCase();
|
|
2105
|
+
};
|
|
2106
|
+
const filteredUsers = useMemo3(() => {
|
|
2107
|
+
if (!searchQuery.trim()) return users;
|
|
2108
|
+
const query = searchQuery.toLowerCase();
|
|
2109
|
+
return users.filter(
|
|
2110
|
+
(user) => user.first_name.toLowerCase().includes(query) || user.last_name.toLowerCase().includes(query) || user.email.toLowerCase().includes(query) || user.role.toLowerCase().includes(query)
|
|
2111
|
+
);
|
|
2112
|
+
}, [users, searchQuery]);
|
|
2113
|
+
const handleRoleUpdate = async (userId, newRole) => {
|
|
2114
|
+
if (!onRoleUpdate) return;
|
|
2115
|
+
setIsUpdating((prev) => ({ ...prev, [userId]: true }));
|
|
2116
|
+
try {
|
|
2117
|
+
await onRoleUpdate(userId, newRole);
|
|
2118
|
+
} catch (error) {
|
|
2119
|
+
console.error("Failed to update role:", error);
|
|
2120
|
+
} finally {
|
|
2121
|
+
setIsUpdating((prev) => ({ ...prev, [userId]: false }));
|
|
2122
|
+
}
|
|
2123
|
+
};
|
|
2124
|
+
const handleRemoveUser = async (userId) => {
|
|
2125
|
+
if (!onRemoveUser) return;
|
|
2126
|
+
const confirmed = window.confirm(
|
|
2127
|
+
"Are you sure you want to remove this user from the organization?"
|
|
2128
|
+
);
|
|
2129
|
+
if (!confirmed) return;
|
|
2130
|
+
setIsUpdating((prev) => ({ ...prev, [userId]: true }));
|
|
2131
|
+
try {
|
|
2132
|
+
await onRemoveUser(userId);
|
|
2133
|
+
} catch (error) {
|
|
2134
|
+
console.error("Failed to remove user:", error);
|
|
2135
|
+
} finally {
|
|
2136
|
+
setIsUpdating((prev) => ({ ...prev, [userId]: false }));
|
|
2137
|
+
}
|
|
2138
|
+
};
|
|
2139
|
+
return /* @__PURE__ */ jsxs16(Card, { className: "w-full max-w-6xl", children: [
|
|
2140
|
+
/* @__PURE__ */ jsxs16(CardHeader, { children: [
|
|
2141
|
+
/* @__PURE__ */ jsx29(CardTitle, { children: "Team Members" }),
|
|
2142
|
+
/* @__PURE__ */ jsx29(CardDescription, { children: canEditUsers ? "View and manage users in your organization" : "View users in your organization" })
|
|
2143
|
+
] }),
|
|
2144
|
+
/* @__PURE__ */ jsxs16(CardContent, { children: [
|
|
2145
|
+
/* @__PURE__ */ jsxs16("div", { className: "mb-6", children: [
|
|
2146
|
+
/* @__PURE__ */ jsx29(Label, { htmlFor: "search", className: "sr-only", children: "Search users" }),
|
|
2147
|
+
/* @__PURE__ */ jsxs16("div", { className: "relative", children: [
|
|
2148
|
+
/* @__PURE__ */ jsx29(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
|
|
2149
|
+
/* @__PURE__ */ jsx29(
|
|
2150
|
+
Input,
|
|
2151
|
+
{
|
|
2152
|
+
id: "search",
|
|
2153
|
+
type: "text",
|
|
2154
|
+
placeholder: "Search by name, email, or role...",
|
|
2155
|
+
value: searchQuery,
|
|
2156
|
+
onChange: (e) => setSearchQuery(e.target.value),
|
|
2157
|
+
className: "pl-10"
|
|
2158
|
+
}
|
|
2159
|
+
)
|
|
2160
|
+
] }),
|
|
2161
|
+
/* @__PURE__ */ jsxs16("p", { className: "text-xs text-muted-foreground mt-2", children: [
|
|
2162
|
+
"Showing ",
|
|
2163
|
+
filteredUsers.length,
|
|
2164
|
+
" of ",
|
|
2165
|
+
users.length,
|
|
2166
|
+
" users"
|
|
2167
|
+
] })
|
|
2168
|
+
] }),
|
|
2169
|
+
filteredUsers.length > 0 ? /* @__PURE__ */ jsx29("div", { className: "border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxs16(Table, { children: [
|
|
2170
|
+
/* @__PURE__ */ jsx29(TableHeader, { children: /* @__PURE__ */ jsxs16(TableRow, { children: [
|
|
2171
|
+
/* @__PURE__ */ jsx29(TableHead, { className: "w-[300px]", children: "User" }),
|
|
2172
|
+
/* @__PURE__ */ jsx29(TableHead, { children: "Email" }),
|
|
2173
|
+
/* @__PURE__ */ jsx29(TableHead, { className: "w-[180px]", children: "Role" }),
|
|
2174
|
+
canEditUsers && onRemoveUser && /* @__PURE__ */ jsx29(TableHead, { className: "w-[100px] text-right", children: "Actions" })
|
|
2175
|
+
] }) }),
|
|
2176
|
+
/* @__PURE__ */ jsx29(TableBody, { children: filteredUsers.map((user) => /* @__PURE__ */ jsxs16(TableRow, { children: [
|
|
2177
|
+
/* @__PURE__ */ jsx29(TableCell, { className: "font-medium", children: /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-3", children: [
|
|
2178
|
+
/* @__PURE__ */ jsx29(Avatar, { children: /* @__PURE__ */ jsx29(AvatarFallback, { children: getInitials(user.first_name, user.last_name) }) }),
|
|
2179
|
+
/* @__PURE__ */ jsxs16("div", { children: [
|
|
2180
|
+
/* @__PURE__ */ jsxs16("div", { className: "font-medium", children: [
|
|
2181
|
+
user.first_name,
|
|
2182
|
+
" ",
|
|
2183
|
+
user.last_name
|
|
2184
|
+
] }),
|
|
2185
|
+
/* @__PURE__ */ jsx29("div", { className: "text-xs text-muted-foreground md:hidden", children: user.email })
|
|
2186
|
+
] })
|
|
2187
|
+
] }) }),
|
|
2188
|
+
/* @__PURE__ */ jsx29(TableCell, { className: "hidden md:table-cell", children: user.email }),
|
|
2189
|
+
/* @__PURE__ */ jsx29(TableCell, { children: canEditUsers && onRoleUpdate ? /* @__PURE__ */ jsxs16(
|
|
2190
|
+
Select,
|
|
2191
|
+
{
|
|
2192
|
+
value: user.role,
|
|
2193
|
+
onValueChange: (newRole) => handleRoleUpdate(user.user_id, newRole),
|
|
2194
|
+
disabled: isUpdating[user.user_id],
|
|
2195
|
+
children: [
|
|
2196
|
+
/* @__PURE__ */ jsx29(SelectTrigger, { className: "w-full", children: /* @__PURE__ */ jsx29(SelectValue, {}) }),
|
|
2197
|
+
/* @__PURE__ */ jsx29(SelectContent, { children: availableRoles.map((role) => /* @__PURE__ */ jsx29(SelectItem, { value: role, children: role }, role)) })
|
|
2198
|
+
]
|
|
2199
|
+
}
|
|
2200
|
+
) : /* @__PURE__ */ jsx29("span", { className: "capitalize text-sm font-medium", children: user.role }) }),
|
|
2201
|
+
canEditUsers && onRemoveUser && /* @__PURE__ */ jsx29(TableCell, { className: "text-right", children: /* @__PURE__ */ jsxs16(
|
|
2202
|
+
Button,
|
|
2203
|
+
{
|
|
2204
|
+
variant: "ghost",
|
|
2205
|
+
size: "icon",
|
|
2206
|
+
onClick: () => handleRemoveUser(user.user_id),
|
|
2207
|
+
disabled: isUpdating[user.user_id],
|
|
2208
|
+
className: "h-8 w-8",
|
|
2209
|
+
children: [
|
|
2210
|
+
/* @__PURE__ */ jsx29(UserX, { className: "h-4 w-4" }),
|
|
2211
|
+
/* @__PURE__ */ jsx29("span", { className: "sr-only", children: "Remove user" })
|
|
2212
|
+
]
|
|
2213
|
+
}
|
|
2214
|
+
) })
|
|
2215
|
+
] }, user.user_id)) })
|
|
2216
|
+
] }) }) : /* @__PURE__ */ jsx29("div", { className: "text-center py-12 border rounded-lg", children: /* @__PURE__ */ jsx29("p", { className: "text-muted-foreground", children: searchQuery ? "No users found matching your search" : "No users in this organization yet" }) })
|
|
2217
|
+
] })
|
|
2218
|
+
] });
|
|
2219
|
+
}
|
|
1970
2220
|
export {
|
|
1971
2221
|
LoginForm,
|
|
1972
2222
|
PricingTable,
|
|
@@ -1977,6 +2227,7 @@ export {
|
|
|
1977
2227
|
SwitchActiveTenant,
|
|
1978
2228
|
TenantCreator,
|
|
1979
2229
|
UserInvite,
|
|
2230
|
+
UserViewer,
|
|
1980
2231
|
VerificationForm,
|
|
1981
2232
|
filterInputNodes,
|
|
1982
2233
|
findAnchorNode,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omnibase/shadcn",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "OmniBase ShadCN UI Package",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"tailwind-merge": "^2.6.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@omnibase/core-js": "0.7.
|
|
52
|
+
"@omnibase/core-js": "0.7.6",
|
|
53
53
|
"@storybook/addon-docs": "^9.1.15",
|
|
54
54
|
"@storybook/react-vite": "^9.1.15",
|
|
55
55
|
"@tailwindcss/vite": "^4.1.16",
|