@specscreen/backoffice-core 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +553 -0
- package/dist/index.cjs +1635 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +665 -0
- package/dist/index.d.ts +665 -0
- package/dist/index.js +1565 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +103 -0
- package/package.json +60 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import React__default, { ComponentType, ReactNode } from 'react';
|
|
4
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
5
|
+
import { VariantProps } from 'class-variance-authority';
|
|
6
|
+
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
7
|
+
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
8
|
+
import { ColumnDef } from '@tanstack/react-table';
|
|
9
|
+
import { ClassValue } from 'clsx';
|
|
10
|
+
|
|
11
|
+
interface User {
|
|
12
|
+
id: string;
|
|
13
|
+
email: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
roles?: string[];
|
|
16
|
+
permissions?: string[];
|
|
17
|
+
}
|
|
18
|
+
interface AuthProvider {
|
|
19
|
+
/**
|
|
20
|
+
* Authenticate the user with the given credentials.
|
|
21
|
+
* Should throw or reject on failure.
|
|
22
|
+
*/
|
|
23
|
+
login(params: {
|
|
24
|
+
email: string;
|
|
25
|
+
password: string;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
/** Terminate the current session. */
|
|
28
|
+
logout(): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Verify whether the current session is still valid.
|
|
31
|
+
* Return true if authenticated, false otherwise.
|
|
32
|
+
* Should NOT throw — return false on any error.
|
|
33
|
+
*/
|
|
34
|
+
checkAuth(): Promise<boolean>;
|
|
35
|
+
/**
|
|
36
|
+
* Retrieve the current authenticated user profile including roles/permissions.
|
|
37
|
+
* Return null if not authenticated or user cannot be fetched.
|
|
38
|
+
*/
|
|
39
|
+
getUser(): Promise<User | null>;
|
|
40
|
+
}
|
|
41
|
+
interface AuthState {
|
|
42
|
+
isLoading: boolean;
|
|
43
|
+
isAuthenticated: boolean;
|
|
44
|
+
user: User | null;
|
|
45
|
+
error: string | null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface ResourceMeta {
|
|
49
|
+
/**
|
|
50
|
+
* Roles required to access this resource.
|
|
51
|
+
* If set, the user must have at least one of these roles.
|
|
52
|
+
*/
|
|
53
|
+
requiredRoles?: string[];
|
|
54
|
+
/**
|
|
55
|
+
* Permissions required to access this resource.
|
|
56
|
+
* If set, the user must have ALL of these permissions.
|
|
57
|
+
*/
|
|
58
|
+
requiredPermissions?: string[];
|
|
59
|
+
/**
|
|
60
|
+
* If true (default), hide this resource from navigation when the user lacks access.
|
|
61
|
+
* If false, show it but disable/restrict it.
|
|
62
|
+
*/
|
|
63
|
+
hideIfUnauthorized?: boolean;
|
|
64
|
+
}
|
|
65
|
+
interface Resource {
|
|
66
|
+
/** Unique identifier for the resource (e.g. "users", "projects") */
|
|
67
|
+
name: string;
|
|
68
|
+
/** Human-readable display label shown in the sidebar */
|
|
69
|
+
label: string;
|
|
70
|
+
/** Route path (e.g. "/users", "/projects") */
|
|
71
|
+
path: string;
|
|
72
|
+
/** Lucide icon name or a React component */
|
|
73
|
+
icon?: ComponentType<{
|
|
74
|
+
className?: string;
|
|
75
|
+
}>;
|
|
76
|
+
/** Component rendered for the list/index view */
|
|
77
|
+
list?: ComponentType;
|
|
78
|
+
/** Component rendered for the create view */
|
|
79
|
+
create?: ComponentType;
|
|
80
|
+
/** Component rendered for the edit view */
|
|
81
|
+
edit?: ComponentType;
|
|
82
|
+
/** Component rendered for the show/detail view */
|
|
83
|
+
show?: ComponentType;
|
|
84
|
+
/** Access control and display metadata */
|
|
85
|
+
meta?: ResourceMeta;
|
|
86
|
+
}
|
|
87
|
+
interface SidebarGroup {
|
|
88
|
+
/** Group label (e.g. "Platform", "Documents") */
|
|
89
|
+
label: string;
|
|
90
|
+
resources: Resource[];
|
|
91
|
+
}
|
|
92
|
+
interface BackofficeConfig {
|
|
93
|
+
/**
|
|
94
|
+
* Application name shown in the sidebar header.
|
|
95
|
+
*/
|
|
96
|
+
appName: string;
|
|
97
|
+
/**
|
|
98
|
+
* Optional company name shown in the sidebar header.
|
|
99
|
+
* When omitted, `appName` is used.
|
|
100
|
+
*/
|
|
101
|
+
companyName?: string;
|
|
102
|
+
/**
|
|
103
|
+
* Optional logo component or URL shown next to the app name.
|
|
104
|
+
*/
|
|
105
|
+
logo?: ComponentType<{
|
|
106
|
+
className?: string;
|
|
107
|
+
}> | string;
|
|
108
|
+
/**
|
|
109
|
+
* Flat list of resources OR grouped sidebar resources.
|
|
110
|
+
*/
|
|
111
|
+
resources?: Resource[];
|
|
112
|
+
/**
|
|
113
|
+
* Grouped sidebar navigation. Takes precedence over `resources` for sidebar.
|
|
114
|
+
*/
|
|
115
|
+
sidebarGroups?: SidebarGroup[];
|
|
116
|
+
/**
|
|
117
|
+
* Bottom-of-sidebar utility links (e.g. Settings, Analytics, Go to website).
|
|
118
|
+
*/
|
|
119
|
+
sidebarFooterLinks?: Array<{
|
|
120
|
+
label: string;
|
|
121
|
+
path: string;
|
|
122
|
+
icon?: ComponentType<{
|
|
123
|
+
className?: string;
|
|
124
|
+
}>;
|
|
125
|
+
}>;
|
|
126
|
+
/**
|
|
127
|
+
* Optional dedicated external website link shown at the bottom of the sidebar.
|
|
128
|
+
*/
|
|
129
|
+
goToWebsite?: {
|
|
130
|
+
/** Destination URL, e.g. https://example.com */
|
|
131
|
+
url: string;
|
|
132
|
+
/** Label in the sidebar. Default: "Go to website" */
|
|
133
|
+
label?: string;
|
|
134
|
+
/** Optional icon component shown before the label */
|
|
135
|
+
icon?: ComponentType<{
|
|
136
|
+
className?: string;
|
|
137
|
+
}>;
|
|
138
|
+
/** Link target. Default: "_blank" */
|
|
139
|
+
target?: "_self" | "_blank";
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Redirect path after successful login. Default: "/" or first accessible resource.
|
|
143
|
+
*/
|
|
144
|
+
loginRedirect?: string;
|
|
145
|
+
/**
|
|
146
|
+
* Redirect path after logout. Default: "/login".
|
|
147
|
+
*/
|
|
148
|
+
logoutRedirect?: string;
|
|
149
|
+
/**
|
|
150
|
+
* Children rendered inside the main content area.
|
|
151
|
+
* Used when the consumer manages routing themselves (e.g. Next.js App Router).
|
|
152
|
+
*/
|
|
153
|
+
children?: ReactNode;
|
|
154
|
+
}
|
|
155
|
+
interface DataProvider {
|
|
156
|
+
/** Fetch a paginated list of records for a resource */
|
|
157
|
+
getList(resource: string, params?: GetListParams): Promise<GetListResult>;
|
|
158
|
+
/** Fetch a single record by ID */
|
|
159
|
+
getOne(resource: string, id: string | number): Promise<Record<string, unknown>>;
|
|
160
|
+
/** Create a new record */
|
|
161
|
+
create(resource: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
162
|
+
/** Update an existing record */
|
|
163
|
+
update(resource: string, id: string | number, data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
164
|
+
/** Delete a record */
|
|
165
|
+
delete(resource: string, id: string | number): Promise<void>;
|
|
166
|
+
}
|
|
167
|
+
interface GetListParams {
|
|
168
|
+
page?: number;
|
|
169
|
+
perPage?: number;
|
|
170
|
+
sort?: {
|
|
171
|
+
field: string;
|
|
172
|
+
order: "asc" | "desc";
|
|
173
|
+
};
|
|
174
|
+
filter?: Record<string, unknown>;
|
|
175
|
+
}
|
|
176
|
+
interface GetListResult {
|
|
177
|
+
data: Record<string, unknown>[];
|
|
178
|
+
total: number;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
interface NavLinkProps {
|
|
182
|
+
href: string;
|
|
183
|
+
children: React__default.ReactNode;
|
|
184
|
+
className?: string;
|
|
185
|
+
isActive?: boolean;
|
|
186
|
+
onClick?: () => void;
|
|
187
|
+
}
|
|
188
|
+
/** Render adapter consumed by the sidebar. Defaults to a plain anchor element. */
|
|
189
|
+
type NavLinkComponent = React__default.ComponentType<NavLinkProps>;
|
|
190
|
+
interface SidebarProps {
|
|
191
|
+
config: BackofficeConfig;
|
|
192
|
+
/** Current active path (used to highlight the active item) */
|
|
193
|
+
currentPath?: string;
|
|
194
|
+
/** Custom NavLink component for framework-specific routing (e.g. Next.js Link) */
|
|
195
|
+
NavLink?: NavLinkComponent;
|
|
196
|
+
/** Called when the user clicks their profile area at the bottom */
|
|
197
|
+
onUserMenuClick?: () => void;
|
|
198
|
+
/** Called when the user clicks the logout option */
|
|
199
|
+
onLogout?: () => void;
|
|
200
|
+
}
|
|
201
|
+
declare function Sidebar({ config, currentPath, NavLink, onLogout, }: SidebarProps): react_jsx_runtime.JSX.Element;
|
|
202
|
+
interface SidebarToggleProps {
|
|
203
|
+
collapsed: boolean;
|
|
204
|
+
onToggle: () => void;
|
|
205
|
+
}
|
|
206
|
+
declare function SidebarToggle({ collapsed, onToggle }: SidebarToggleProps): react_jsx_runtime.JSX.Element;
|
|
207
|
+
|
|
208
|
+
interface LoginPageProps {
|
|
209
|
+
/** Application name shown as the heading. Default: "backoffice" */
|
|
210
|
+
appName?: string;
|
|
211
|
+
/** Logo element shown above the title */
|
|
212
|
+
logo?: React__default.ReactNode;
|
|
213
|
+
/** Called after a successful login (e.g. for router redirect) */
|
|
214
|
+
onLoginSuccess?: () => void;
|
|
215
|
+
/** Optional "Forgot password?" click handler */
|
|
216
|
+
onForgotPassword?: () => void;
|
|
217
|
+
/** Custom subtitle / hint shown below the heading. Overrides the default description. */
|
|
218
|
+
description?: React__default.ReactNode;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Full-page login form matching the Figma design.
|
|
222
|
+
* Delegates credential validation to the configured AuthProvider.
|
|
223
|
+
*/
|
|
224
|
+
declare function LoginPage({ appName, logo, onLoginSuccess, onForgotPassword, description, }: LoginPageProps): react_jsx_runtime.JSX.Element;
|
|
225
|
+
|
|
226
|
+
interface BackofficeAppProps {
|
|
227
|
+
/** Global configuration: app name, resources, sidebar groups, etc. */
|
|
228
|
+
config: BackofficeConfig;
|
|
229
|
+
/** Auth backend adapter — login, logout, checkAuth, getUser */
|
|
230
|
+
authProvider: AuthProvider;
|
|
231
|
+
/**
|
|
232
|
+
* Data backend adapter — getList, getOne, create, update, delete.
|
|
233
|
+
* Optional: only needed when using built-in data-aware components.
|
|
234
|
+
*/
|
|
235
|
+
dataProvider?: DataProvider;
|
|
236
|
+
/**
|
|
237
|
+
* Custom NavLink component for framework-specific routing.
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* // Next.js App Router
|
|
241
|
+
* import Link from "next/link"
|
|
242
|
+
* const NavLink = ({ href, children, className }) => (
|
|
243
|
+
* <Link href={href} className={className}>{children}</Link>
|
|
244
|
+
* )
|
|
245
|
+
*/
|
|
246
|
+
NavLink?: NavLinkComponent;
|
|
247
|
+
/**
|
|
248
|
+
* Current path used to highlight the active sidebar item.
|
|
249
|
+
* In Next.js: use `usePathname()` from "next/navigation".
|
|
250
|
+
*/
|
|
251
|
+
currentPath?: string;
|
|
252
|
+
/**
|
|
253
|
+
* Props forwarded to the default LoginPage.
|
|
254
|
+
* Ignored when `renderLogin` is provided.
|
|
255
|
+
*/
|
|
256
|
+
loginPageProps?: Omit<LoginPageProps, "onLoginSuccess">;
|
|
257
|
+
/**
|
|
258
|
+
* Render a completely custom login page instead of the default.
|
|
259
|
+
* The custom component MUST call the `login` method from `useAuth()`.
|
|
260
|
+
*/
|
|
261
|
+
renderLogin?: () => React__default.ReactNode;
|
|
262
|
+
/**
|
|
263
|
+
* Render a custom loading screen shown during the auth boot phase.
|
|
264
|
+
*/
|
|
265
|
+
renderLoading?: () => React__default.ReactNode;
|
|
266
|
+
/**
|
|
267
|
+
* Label for the primary action button in the top-right of the header.
|
|
268
|
+
*/
|
|
269
|
+
headerActionLabel?: string;
|
|
270
|
+
/** Callback for the primary action button */
|
|
271
|
+
onHeaderAction?: () => void;
|
|
272
|
+
/**
|
|
273
|
+
* Called after a successful login (e.g. router.push to the default resource).
|
|
274
|
+
*/
|
|
275
|
+
onLoginSuccess?: () => void;
|
|
276
|
+
/**
|
|
277
|
+
* Page content — your routes/pages rendered inside the main area.
|
|
278
|
+
* In Next.js App Router, pass `{children}` from your layout.
|
|
279
|
+
*/
|
|
280
|
+
children?: React__default.ReactNode;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Root component of the backoffice framework.
|
|
284
|
+
*
|
|
285
|
+
* Sets up:
|
|
286
|
+
* - AuthContext (boot flow: checkAuth → getUser → store state)
|
|
287
|
+
* - AuthGuard (shows LoginPage when unauthenticated)
|
|
288
|
+
* - AppShell (sidebar + header + main content area)
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* // app/layout.tsx (Next.js App Router)
|
|
292
|
+
* export default function RootLayout({ children }) {
|
|
293
|
+
* return (
|
|
294
|
+
* <BackofficeApp
|
|
295
|
+
* config={config}
|
|
296
|
+
* authProvider={authProvider}
|
|
297
|
+
* currentPath={usePathname()}
|
|
298
|
+
* NavLink={NextNavLink}
|
|
299
|
+
* >
|
|
300
|
+
* {children}
|
|
301
|
+
* </BackofficeApp>
|
|
302
|
+
* )
|
|
303
|
+
* }
|
|
304
|
+
*/
|
|
305
|
+
declare function BackofficeApp({ config, authProvider, NavLink, currentPath, loginPageProps, renderLogin, renderLoading, headerActionLabel, onHeaderAction, onLoginSuccess, children, }: BackofficeAppProps): react_jsx_runtime.JSX.Element;
|
|
306
|
+
|
|
307
|
+
interface UseAuthReturn extends AuthState {
|
|
308
|
+
login(params: {
|
|
309
|
+
email: string;
|
|
310
|
+
password: string;
|
|
311
|
+
}): Promise<void>;
|
|
312
|
+
logout(): Promise<void>;
|
|
313
|
+
refreshUser(): Promise<void>;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Access the current authentication state and login/logout actions.
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* const { isAuthenticated, user, login, logout } = useAuth()
|
|
320
|
+
*/
|
|
321
|
+
declare function useAuth(): UseAuthReturn;
|
|
322
|
+
|
|
323
|
+
interface UsePermissionsReturn {
|
|
324
|
+
/** All roles assigned to the current user */
|
|
325
|
+
roles: string[];
|
|
326
|
+
/** All permissions assigned to the current user */
|
|
327
|
+
permissions: string[];
|
|
328
|
+
/**
|
|
329
|
+
* Returns true if the user has the specified permission.
|
|
330
|
+
* Always returns false when the user is not authenticated.
|
|
331
|
+
*
|
|
332
|
+
* @example
|
|
333
|
+
* can("users.delete") // true | false
|
|
334
|
+
*/
|
|
335
|
+
can(permission: string): boolean;
|
|
336
|
+
/**
|
|
337
|
+
* Returns true if the user has ANY of the specified permissions.
|
|
338
|
+
*
|
|
339
|
+
* @example
|
|
340
|
+
* canAny(["posts.edit", "posts.create"])
|
|
341
|
+
*/
|
|
342
|
+
canAny(permissions: string[]): boolean;
|
|
343
|
+
/**
|
|
344
|
+
* Returns true if the user has ALL of the specified permissions.
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* canAll(["orders.view", "orders.export"])
|
|
348
|
+
*/
|
|
349
|
+
canAll(permissions: string[]): boolean;
|
|
350
|
+
/**
|
|
351
|
+
* Returns true if the user has the specified role.
|
|
352
|
+
* Always returns false when the user is not authenticated.
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* hasRole("admin") // true | false
|
|
356
|
+
*/
|
|
357
|
+
hasRole(role: string): boolean;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Access the current user's RBAC permissions and roles.
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* const { can, hasRole } = usePermissions()
|
|
364
|
+
* can("users.create") // true | false
|
|
365
|
+
* hasRole("admin") // true | false
|
|
366
|
+
*/
|
|
367
|
+
declare function usePermissions(): UsePermissionsReturn;
|
|
368
|
+
|
|
369
|
+
interface AuthGuardProps {
|
|
370
|
+
/** Content to show when authenticated */
|
|
371
|
+
children: React__default.ReactNode;
|
|
372
|
+
/** Props forwarded to the built-in LoginPage. Ignored when renderLogin is provided. */
|
|
373
|
+
loginPageProps?: Omit<LoginPageProps, "onLoginSuccess">;
|
|
374
|
+
/** Render a custom login UI instead of the default LoginPage */
|
|
375
|
+
renderLogin?: () => React__default.ReactNode;
|
|
376
|
+
/** Render a custom loading state instead of the default LoadingScreen */
|
|
377
|
+
renderLoading?: () => React__default.ReactNode;
|
|
378
|
+
/** Called after successful login (e.g. router.push) */
|
|
379
|
+
onLoginSuccess?: () => void;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Redirects to the login page if the user is not authenticated.
|
|
383
|
+
* Shows a loading screen during the auth boot phase.
|
|
384
|
+
*
|
|
385
|
+
* Place this at the root of the protected area.
|
|
386
|
+
*/
|
|
387
|
+
declare function AuthGuard({ children, loginPageProps, renderLogin, renderLoading, onLoginSuccess, }: AuthGuardProps): react_jsx_runtime.JSX.Element;
|
|
388
|
+
|
|
389
|
+
interface ResourceGuardProps {
|
|
390
|
+
/** The access requirements to evaluate */
|
|
391
|
+
meta: ResourceMeta;
|
|
392
|
+
/** Protected content */
|
|
393
|
+
children: React__default.ReactNode;
|
|
394
|
+
/** Custom fallback rendered when access is denied. Defaults to <AccessDenied /> */
|
|
395
|
+
fallback?: React__default.ReactNode;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Renders `children` only when the current user satisfies the resource's
|
|
399
|
+
* `requiredRoles` and `requiredPermissions` constraints.
|
|
400
|
+
*
|
|
401
|
+
* @example
|
|
402
|
+
* <ResourceGuard meta={{ requiredPermissions: ["users.read"] }}>
|
|
403
|
+
* <UsersPage />
|
|
404
|
+
* </ResourceGuard>
|
|
405
|
+
*/
|
|
406
|
+
declare function ResourceGuard({ meta, children, fallback }: ResourceGuardProps): react_jsx_runtime.JSX.Element | null;
|
|
407
|
+
|
|
408
|
+
interface CanProps {
|
|
409
|
+
/** Permission string to check */
|
|
410
|
+
permission?: string;
|
|
411
|
+
/** Role string to check */
|
|
412
|
+
role?: string;
|
|
413
|
+
/** If true, checks ALL listed permissions instead of just one */
|
|
414
|
+
permissions?: string[];
|
|
415
|
+
/** Content rendered when access is granted */
|
|
416
|
+
children: React__default.ReactNode;
|
|
417
|
+
/**
|
|
418
|
+
* Content rendered when access is denied.
|
|
419
|
+
* Pass a disabled button or any placeholder. Defaults to null (hidden).
|
|
420
|
+
*/
|
|
421
|
+
fallback?: React__default.ReactNode;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Conditionally renders `children` based on a permission or role check.
|
|
425
|
+
*
|
|
426
|
+
* @example
|
|
427
|
+
* // Hide a button when user lacks the permission
|
|
428
|
+
* <Can permission="users.delete">
|
|
429
|
+
* <DeleteButton />
|
|
430
|
+
* </Can>
|
|
431
|
+
*
|
|
432
|
+
* // Disable a button instead of hiding it
|
|
433
|
+
* <Can permission="users.create" fallback={<CreateButton disabled />}>
|
|
434
|
+
* <CreateButton />
|
|
435
|
+
* </Can>
|
|
436
|
+
*
|
|
437
|
+
* // Role-based
|
|
438
|
+
* <Can role="admin">
|
|
439
|
+
* <AdminPanel />
|
|
440
|
+
* </Can>
|
|
441
|
+
*/
|
|
442
|
+
declare function Can({ permission, role, permissions, children, fallback }: CanProps): react_jsx_runtime.JSX.Element;
|
|
443
|
+
|
|
444
|
+
interface AppShellProps {
|
|
445
|
+
config: BackofficeConfig;
|
|
446
|
+
/** Current path for active link highlighting */
|
|
447
|
+
currentPath?: string;
|
|
448
|
+
/** Custom NavLink component (e.g. next/link wrapper) */
|
|
449
|
+
NavLink?: NavLinkComponent;
|
|
450
|
+
/** Primary action button label for the header */
|
|
451
|
+
headerActionLabel?: string;
|
|
452
|
+
/** Primary action click handler */
|
|
453
|
+
onHeaderAction?: () => void;
|
|
454
|
+
/** Content to render in the main area */
|
|
455
|
+
children: React__default.ReactNode;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Main application shell: sidebar + header bar + content area.
|
|
459
|
+
* Matches the Figma backoffice layout design.
|
|
460
|
+
*/
|
|
461
|
+
declare function AppShell({ config, currentPath, NavLink, headerActionLabel, onHeaderAction, children, }: AppShellProps): react_jsx_runtime.JSX.Element;
|
|
462
|
+
|
|
463
|
+
interface AccessDeniedProps {
|
|
464
|
+
/** Custom message. Default: "You do not have permission to access this page." */
|
|
465
|
+
message?: string;
|
|
466
|
+
/** Label for the action button. If provided, onAction must also be set. */
|
|
467
|
+
actionLabel?: string;
|
|
468
|
+
/** Callback for the action button (e.g. navigate back or to home) */
|
|
469
|
+
onAction?: () => void;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Default access-denied page shown when a user attempts to access
|
|
473
|
+
* a resource they are not authorized to view.
|
|
474
|
+
*/
|
|
475
|
+
declare function AccessDenied({ message, actionLabel, onAction, }: AccessDeniedProps): react_jsx_runtime.JSX.Element;
|
|
476
|
+
|
|
477
|
+
interface LoadingScreenProps {
|
|
478
|
+
/** Custom message shown below the spinner */
|
|
479
|
+
message?: string;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Full-screen loading indicator shown during the auth boot phase.
|
|
483
|
+
*/
|
|
484
|
+
declare function LoadingScreen({ message }: LoadingScreenProps): react_jsx_runtime.JSX.Element;
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Evaluate whether a user has access to a resource based on its meta constraints.
|
|
488
|
+
*
|
|
489
|
+
* Rules:
|
|
490
|
+
* - If no constraints are defined (no requiredRoles, no requiredPermissions), access is GRANTED.
|
|
491
|
+
* - If requiredRoles is set, the user must have AT LEAST ONE matching role.
|
|
492
|
+
* - If requiredPermissions is set, the user must have ALL of the listed permissions.
|
|
493
|
+
* - If both are set, BOTH conditions must pass.
|
|
494
|
+
* - If a condition is set but the user has no roles/permissions at all, access is DENIED.
|
|
495
|
+
*/
|
|
496
|
+
declare function canAccessResource(user: User | null, meta: ResourceMeta | undefined): boolean;
|
|
497
|
+
/** Check whether a user possesses a specific permission string. */
|
|
498
|
+
declare function evaluateCan(user: User | null, permission: string): boolean;
|
|
499
|
+
/** Check whether a user possesses a specific role string. */
|
|
500
|
+
declare function evaluateHasRole(user: User | null, role: string): boolean;
|
|
501
|
+
/** Check whether a user possesses ANY of the given permissions. */
|
|
502
|
+
declare function evaluateCanAny(user: User | null, permissions: string[]): boolean;
|
|
503
|
+
/** Check whether a user possesses ALL of the given permissions. */
|
|
504
|
+
declare function evaluateCanAll(user: User | null, permissions: string[]): boolean;
|
|
505
|
+
|
|
506
|
+
interface AuthContextValue extends AuthState {
|
|
507
|
+
/** Log in with email + password via the configured AuthProvider */
|
|
508
|
+
login(params: {
|
|
509
|
+
email: string;
|
|
510
|
+
password: string;
|
|
511
|
+
}): Promise<void>;
|
|
512
|
+
/** Log out and clear auth state */
|
|
513
|
+
logout(): Promise<void>;
|
|
514
|
+
/** Re-fetch the user profile and update context */
|
|
515
|
+
refreshUser(): Promise<void>;
|
|
516
|
+
/** Check a single permission */
|
|
517
|
+
can(permission: string): boolean;
|
|
518
|
+
/** Check if user has ANY of the given permissions */
|
|
519
|
+
canAny(permissions: string[]): boolean;
|
|
520
|
+
/** Check if user has ALL of the given permissions */
|
|
521
|
+
canAll(permissions: string[]): boolean;
|
|
522
|
+
/** Check if user has a specific role */
|
|
523
|
+
hasRole(role: string): boolean;
|
|
524
|
+
}
|
|
525
|
+
declare const AuthContext: React__default.Context<AuthContextValue | null>;
|
|
526
|
+
interface AuthContextProviderProps {
|
|
527
|
+
authProvider: AuthProvider;
|
|
528
|
+
children: React__default.ReactNode;
|
|
529
|
+
}
|
|
530
|
+
declare function AuthContextProvider({ authProvider, children, }: AuthContextProviderProps): react_jsx_runtime.JSX.Element;
|
|
531
|
+
declare function useAuthContext(): AuthContextValue;
|
|
532
|
+
|
|
533
|
+
declare const buttonVariants: (props?: ({
|
|
534
|
+
variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
|
|
535
|
+
size?: "default" | "sm" | "lg" | "icon" | null | undefined;
|
|
536
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
537
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
538
|
+
asChild?: boolean;
|
|
539
|
+
}
|
|
540
|
+
declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
541
|
+
|
|
542
|
+
declare const Input: React.ForwardRefExoticComponent<React.InputHTMLAttributes<HTMLInputElement> & React.RefAttributes<HTMLInputElement>>;
|
|
543
|
+
|
|
544
|
+
declare const Label: React.ForwardRefExoticComponent<Omit<LabelPrimitive.LabelProps & React.RefAttributes<HTMLLabelElement>, "ref"> & React.RefAttributes<HTMLLabelElement>>;
|
|
545
|
+
|
|
546
|
+
declare const Select: React.FC<SelectPrimitive.SelectProps>;
|
|
547
|
+
declare const SelectGroup: React.ForwardRefExoticComponent<SelectPrimitive.SelectGroupProps & React.RefAttributes<HTMLDivElement>>;
|
|
548
|
+
declare const SelectValue: React.ForwardRefExoticComponent<SelectPrimitive.SelectValueProps & React.RefAttributes<HTMLSpanElement>>;
|
|
549
|
+
declare const SelectTrigger: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectTriggerProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
550
|
+
declare const SelectScrollUpButton: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectScrollUpButtonProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
551
|
+
declare const SelectScrollDownButton: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectScrollDownButtonProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
552
|
+
declare const SelectContent: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
553
|
+
declare const SelectItem: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectItemProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
554
|
+
declare const SelectSeparator: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectSeparatorProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
555
|
+
|
|
556
|
+
type ModalWidth = "sm" | "md" | "lg" | "xl" | "2xl" | "full";
|
|
557
|
+
interface RenderModalProps {
|
|
558
|
+
open: boolean;
|
|
559
|
+
onOpenChange: (open: boolean) => void;
|
|
560
|
+
title?: React__default.ReactNode;
|
|
561
|
+
description?: React__default.ReactNode;
|
|
562
|
+
children?: React__default.ReactNode;
|
|
563
|
+
renderContent?: () => React__default.ReactNode;
|
|
564
|
+
footer?: React__default.ReactNode;
|
|
565
|
+
width?: ModalWidth;
|
|
566
|
+
closeOnOverlayClick?: boolean;
|
|
567
|
+
showCloseButton?: boolean;
|
|
568
|
+
overlayClassName?: string;
|
|
569
|
+
panelClassName?: string;
|
|
570
|
+
contentClassName?: string;
|
|
571
|
+
}
|
|
572
|
+
declare function RenderModal({ open, onOpenChange, title, description, children, renderContent, footer, width, closeOnOverlayClick, showCloseButton, overlayClassName, panelClassName, contentClassName, }: RenderModalProps): React__default.ReactPortal | null;
|
|
573
|
+
|
|
574
|
+
type SettingsSection = "general" | "personalization" | "users";
|
|
575
|
+
interface AccentOption {
|
|
576
|
+
value: string;
|
|
577
|
+
label: string;
|
|
578
|
+
previewClassName?: string;
|
|
579
|
+
}
|
|
580
|
+
interface SettingsModalProps {
|
|
581
|
+
open: boolean;
|
|
582
|
+
onOpenChange: (open: boolean) => void;
|
|
583
|
+
mode: "light" | "dark";
|
|
584
|
+
onModeChange: (mode: "light" | "dark") => void;
|
|
585
|
+
accent: string;
|
|
586
|
+
onAccentChange: (accent: string) => void;
|
|
587
|
+
accentOptions?: AccentOption[];
|
|
588
|
+
personalizationContent?: React__default.ReactNode;
|
|
589
|
+
usersContent?: React__default.ReactNode;
|
|
590
|
+
defaultSection?: SettingsSection;
|
|
591
|
+
width?: RenderModalProps["width"];
|
|
592
|
+
closeOnOverlayClick?: boolean;
|
|
593
|
+
overlayClassName?: string;
|
|
594
|
+
panelClassName?: string;
|
|
595
|
+
contentClassName?: string;
|
|
596
|
+
sidebarClassName?: string;
|
|
597
|
+
bodyClassName?: string;
|
|
598
|
+
}
|
|
599
|
+
declare function SettingsModal({ open, onOpenChange, mode, onModeChange, accent, onAccentChange, accentOptions, personalizationContent, usersContent, defaultSection, width, closeOnOverlayClick, overlayClassName, panelClassName, contentClassName, sidebarClassName, bodyClassName, }: SettingsModalProps): react_jsx_runtime.JSX.Element | null;
|
|
600
|
+
|
|
601
|
+
interface TableActionConfirmOptions {
|
|
602
|
+
title?: string;
|
|
603
|
+
description?: string;
|
|
604
|
+
confirmLabel?: string;
|
|
605
|
+
cancelLabel?: string;
|
|
606
|
+
}
|
|
607
|
+
interface TableActionItem {
|
|
608
|
+
key: string;
|
|
609
|
+
label: string;
|
|
610
|
+
onSelect: () => void;
|
|
611
|
+
disabled?: boolean;
|
|
612
|
+
variant?: "default" | "destructive";
|
|
613
|
+
confirm?: boolean | TableActionConfirmOptions;
|
|
614
|
+
}
|
|
615
|
+
interface TableActionMenuProps {
|
|
616
|
+
items: TableActionItem[];
|
|
617
|
+
ariaLabel?: string;
|
|
618
|
+
}
|
|
619
|
+
declare function TableActionMenu({ items, ariaLabel, }: TableActionMenuProps): react_jsx_runtime.JSX.Element | null;
|
|
620
|
+
|
|
621
|
+
interface TableBadgeProps {
|
|
622
|
+
children: React__default.ReactNode;
|
|
623
|
+
tone?: "neutral" | "success" | "danger" | "warning";
|
|
624
|
+
className?: string;
|
|
625
|
+
}
|
|
626
|
+
declare function TableBadge({ children, tone, className, }: TableBadgeProps): react_jsx_runtime.JSX.Element;
|
|
627
|
+
|
|
628
|
+
declare const Table: React.ForwardRefExoticComponent<React.TableHTMLAttributes<HTMLTableElement> & React.RefAttributes<HTMLTableElement>>;
|
|
629
|
+
declare const TableHeader: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableSectionElement> & React.RefAttributes<HTMLTableSectionElement>>;
|
|
630
|
+
declare const TableBody: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableSectionElement> & React.RefAttributes<HTMLTableSectionElement>>;
|
|
631
|
+
declare const TableFooter: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableSectionElement> & React.RefAttributes<HTMLTableSectionElement>>;
|
|
632
|
+
declare const TableRow: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableRowElement> & React.RefAttributes<HTMLTableRowElement>>;
|
|
633
|
+
declare const TableHead: React.ForwardRefExoticComponent<React.ThHTMLAttributes<HTMLTableCellElement> & React.RefAttributes<HTMLTableCellElement>>;
|
|
634
|
+
declare const TableCell: React.ForwardRefExoticComponent<React.TdHTMLAttributes<HTMLTableCellElement> & React.RefAttributes<HTMLTableCellElement>>;
|
|
635
|
+
declare const TableCaption: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableCaptionElement> & React.RefAttributes<HTMLTableCaptionElement>>;
|
|
636
|
+
|
|
637
|
+
interface DataTableRowDragOptions<TData> {
|
|
638
|
+
getRowId: (row: TData) => string;
|
|
639
|
+
onReorder: (reorderedRows: TData[]) => void;
|
|
640
|
+
}
|
|
641
|
+
interface DataTableProps<TData, TValue> {
|
|
642
|
+
columns: ColumnDef<TData, TValue>[];
|
|
643
|
+
data: TData[];
|
|
644
|
+
className?: string;
|
|
645
|
+
emptyMessage?: string;
|
|
646
|
+
rowDragOptions?: DataTableRowDragOptions<TData>;
|
|
647
|
+
}
|
|
648
|
+
declare function DataTable<TData, TValue>({ columns, data, className, emptyMessage, rowDragOptions, }: DataTableProps<TData, TValue>): react_jsx_runtime.JSX.Element;
|
|
649
|
+
|
|
650
|
+
type TablePageSizeOption = number | "all";
|
|
651
|
+
interface TablePaginationProps {
|
|
652
|
+
totalRows: number;
|
|
653
|
+
selectedRows?: number;
|
|
654
|
+
page: number;
|
|
655
|
+
pageSize: number;
|
|
656
|
+
pageSizeOptions?: TablePageSizeOption[];
|
|
657
|
+
onPageChange: (page: number) => void;
|
|
658
|
+
onPageSizeChange: (pageSize: number) => void;
|
|
659
|
+
className?: string;
|
|
660
|
+
}
|
|
661
|
+
declare function TablePagination({ totalRows, selectedRows, page, pageSize, pageSizeOptions, onPageChange, onPageSizeChange, className, }: TablePaginationProps): react_jsx_runtime.JSX.Element;
|
|
662
|
+
|
|
663
|
+
declare function cn(...inputs: ClassValue[]): string;
|
|
664
|
+
|
|
665
|
+
export { type AccentOption, type AccessDeniedProps, type AppShellProps, type AuthContextProviderProps, type AuthContextValue, type AuthGuardProps, type AuthProvider, type AuthState, type BackofficeAppProps, type BackofficeConfig, type ButtonProps, type CanProps, type DataProvider, type DataTableProps, type GetListParams, type GetListResult, type LoadingScreenProps, type LoginPageProps, type NavLinkComponent, type NavLinkProps, type RenderModalProps, type Resource, type ResourceGuardProps, type ResourceMeta, AccessDenied as SPC_AccessDenied, AppShell as SPC_AppShell, AuthContext as SPC_AuthContext, AuthContextProvider as SPC_AuthContextProvider, AuthGuard as SPC_AuthGuard, BackofficeApp as SPC_BackofficeApp, Button as SPC_Button, Can as SPC_Can, DataTable as SPC_DataTable, Input as SPC_Input, Label as SPC_Label, LoadingScreen as SPC_LoadingScreen, LoginPage as SPC_LoginPage, RenderModal as SPC_RenderModal, ResourceGuard as SPC_ResourceGuard, Select as SPC_Select, SelectContent as SPC_SelectContent, SelectGroup as SPC_SelectGroup, SelectItem as SPC_SelectItem, SelectScrollDownButton as SPC_SelectScrollDownButton, SelectScrollUpButton as SPC_SelectScrollUpButton, SelectSeparator as SPC_SelectSeparator, SelectTrigger as SPC_SelectTrigger, SelectValue as SPC_SelectValue, SettingsModal as SPC_SettingsModal, Sidebar as SPC_Sidebar, SidebarToggle as SPC_SidebarToggle, Table as SPC_Table, TableActionMenu as SPC_TableActionMenu, TableBadge as SPC_TableBadge, TableBody as SPC_TableBody, TableCaption as SPC_TableCaption, TableCell as SPC_TableCell, TableFooter as SPC_TableFooter, TableHead as SPC_TableHead, TableHeader as SPC_TableHeader, TablePagination as SPC_TablePagination, TableRow as SPC_TableRow, buttonVariants as SPC_buttonVariants, canAccessResource as SPC_canAccessResource, cn as SPC_cn, evaluateCan as SPC_evaluateCan, evaluateCanAll as SPC_evaluateCanAll, evaluateCanAny as SPC_evaluateCanAny, evaluateHasRole as SPC_evaluateHasRole, useAuth as SPC_useAuth, useAuthContext as SPC_useAuthContext, usePermissions as SPC_usePermissions, type SettingsModalProps, type SettingsSection, type SidebarGroup, type SidebarProps, type TableActionItem, type TableActionMenuProps, type TableBadgeProps, type TablePaginationProps, type UseAuthReturn, type UsePermissionsReturn, type User };
|