@pattern-stack/frontend-patterns 0.2.0-alpha.4 → 0.2.0-alpha.5
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/atoms/components/data/DataTable/DataTable.d.ts +1 -1
- package/dist/atoms/components/data/DataTable/DataTable.d.ts.map +1 -1
- package/dist/atoms/components/data/DataTable/DataTable.types.d.ts +28 -0
- package/dist/atoms/components/data/DataTable/DataTable.types.d.ts.map +1 -1
- package/dist/atoms/hooks/index.d.ts +1 -0
- package/dist/atoms/hooks/index.d.ts.map +1 -1
- package/dist/atoms/hooks/useEntityDetail.d.ts +43 -0
- package/dist/atoms/hooks/useEntityDetail.d.ts.map +1 -0
- package/dist/atoms/primitives/table.d.ts.map +1 -1
- package/dist/atoms/services/api/client.d.ts +12 -2
- package/dist/atoms/services/api/client.d.ts.map +1 -1
- package/dist/atoms/services/auth-service.d.ts +15 -0
- package/dist/atoms/services/auth-service.d.ts.map +1 -1
- package/dist/atoms/services/index.d.ts +2 -2
- package/dist/atoms/services/index.d.ts.map +1 -1
- package/dist/atoms/types/auth.d.ts +38 -2
- package/dist/atoms/types/auth.d.ts.map +1 -1
- package/dist/atoms/types/ui-config.d.ts +11 -0
- package/dist/atoms/types/ui-config.d.ts.map +1 -1
- package/dist/features/auth/components/ProtectedRoute.d.ts +3 -1
- package/dist/features/auth/components/ProtectedRoute.d.ts.map +1 -1
- package/dist/features/auth/hooks/useAuth.d.ts.map +1 -1
- package/dist/features/auth/providers/NoAuthProvider.d.ts +17 -0
- package/dist/features/auth/providers/NoAuthProvider.d.ts.map +1 -0
- package/dist/features/auth/providers/index.d.ts +1 -0
- package/dist/features/auth/providers/index.d.ts.map +1 -1
- package/dist/frontend-patterns.css +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +350 -79
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +348 -77
- package/dist/index.js.map +1 -1
- package/dist/molecules/layout/FieldGrid/FieldGrid.d.ts +61 -0
- package/dist/molecules/layout/FieldGrid/FieldGrid.d.ts.map +1 -0
- package/dist/molecules/layout/FieldGrid/index.d.ts +2 -0
- package/dist/molecules/layout/FieldGrid/index.d.ts.map +1 -0
- package/dist/molecules/layout/index.d.ts +1 -0
- package/dist/molecules/layout/index.d.ts.map +1 -1
- package/dist/templates/factory.d.ts.map +1 -1
- package/package.json +4 -5
package/dist/index.js
CHANGED
|
@@ -77,8 +77,8 @@ const UI_CONFIG = {
|
|
|
77
77
|
TOAST_DURATION: 5e3
|
|
78
78
|
};
|
|
79
79
|
const env = {
|
|
80
|
-
API_BASE_URL: "
|
|
81
|
-
OPENAPI_URL: "
|
|
80
|
+
API_BASE_URL: "",
|
|
81
|
+
OPENAPI_URL: "/openapi.json",
|
|
82
82
|
NODE_ENV: "development",
|
|
83
83
|
IS_DEVELOPMENT: false,
|
|
84
84
|
IS_PRODUCTION: false,
|
|
@@ -2052,16 +2052,18 @@ function renderField(value, fieldName, fieldType, breakpoint, item, customRender
|
|
|
2052
2052
|
function cn(...inputs) {
|
|
2053
2053
|
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
2054
2054
|
}
|
|
2055
|
-
const API_BASE_URL = "http://localhost:8080";
|
|
2056
2055
|
let globalAuthService = null;
|
|
2057
2056
|
function setGlobalAuthService(authService) {
|
|
2058
2057
|
globalAuthService = authService;
|
|
2059
2058
|
}
|
|
2059
|
+
function getGlobalAuthService() {
|
|
2060
|
+
return globalAuthService;
|
|
2061
|
+
}
|
|
2060
2062
|
class ApiClient {
|
|
2061
2063
|
constructor(config = {}) {
|
|
2062
2064
|
__publicField(this, "instance");
|
|
2063
2065
|
this.instance = axios.create({
|
|
2064
|
-
baseURL: config.baseURL ||
|
|
2066
|
+
baseURL: config.baseURL || "",
|
|
2065
2067
|
timeout: config.timeout || 1e4,
|
|
2066
2068
|
headers: {
|
|
2067
2069
|
"Content-Type": "application/json",
|
|
@@ -2101,11 +2103,12 @@ class ApiClient {
|
|
|
2101
2103
|
this.instance.interceptors.response.use(
|
|
2102
2104
|
(response) => response,
|
|
2103
2105
|
async (error) => {
|
|
2104
|
-
var _a;
|
|
2105
|
-
|
|
2106
|
+
var _a, _b, _c, _d;
|
|
2107
|
+
const status = (_a = error.response) == null ? void 0 : _a.status;
|
|
2108
|
+
if (status === 401 || status === 403) {
|
|
2106
2109
|
if (globalAuthService) {
|
|
2107
2110
|
const tokenData = globalAuthService.getTokenData();
|
|
2108
|
-
if ((tokenData == null ? void 0 : tokenData.refreshToken) && !error.config._retry) {
|
|
2111
|
+
if (status === 401 && (tokenData == null ? void 0 : tokenData.refreshToken) && !error.config._retry) {
|
|
2109
2112
|
error.config._retry = true;
|
|
2110
2113
|
try {
|
|
2111
2114
|
await globalAuthService.refreshToken();
|
|
@@ -2113,11 +2116,12 @@ class ApiClient {
|
|
|
2113
2116
|
error.config.headers.Authorization = `Bearer ${newTokenData == null ? void 0 : newTokenData.token}`;
|
|
2114
2117
|
return this.instance.request(error.config);
|
|
2115
2118
|
} catch {
|
|
2116
|
-
globalAuthService.clearAuth();
|
|
2117
|
-
window.location.reload();
|
|
2118
2119
|
}
|
|
2119
|
-
}
|
|
2120
|
-
|
|
2120
|
+
}
|
|
2121
|
+
globalAuthService.clearAuth();
|
|
2122
|
+
const errorInfo = { status, message: (_c = (_b = error.response) == null ? void 0 : _b.data) == null ? void 0 : _c.detail };
|
|
2123
|
+
const handled = (_d = globalAuthService.onAuthError) == null ? void 0 : _d.call(globalAuthService, errorInfo);
|
|
2124
|
+
if (!handled) {
|
|
2121
2125
|
window.location.reload();
|
|
2122
2126
|
}
|
|
2123
2127
|
} else {
|
|
@@ -2163,6 +2167,9 @@ class ApiClient {
|
|
|
2163
2167
|
return response.data;
|
|
2164
2168
|
}
|
|
2165
2169
|
}
|
|
2170
|
+
function createApiClient(config = {}) {
|
|
2171
|
+
return new ApiClient(config);
|
|
2172
|
+
}
|
|
2166
2173
|
const apiClient = new ApiClient();
|
|
2167
2174
|
function useToast() {
|
|
2168
2175
|
const [toasts, setToasts] = React.useState([]);
|
|
@@ -2433,7 +2440,7 @@ function useEntityData(entity, options = {}) {
|
|
|
2433
2440
|
const dataQuery = reactQuery.useQuery({
|
|
2434
2441
|
queryKey: [entity, "list", { limit, offset, filters }],
|
|
2435
2442
|
queryFn: () => apiClient.get(
|
|
2436
|
-
`/api/v1/${entity}
|
|
2443
|
+
`/api/v1/${entity}?${dataParams.toString()}`
|
|
2437
2444
|
),
|
|
2438
2445
|
enabled
|
|
2439
2446
|
});
|
|
@@ -2461,6 +2468,40 @@ function useEntityData(entity, options = {}) {
|
|
|
2461
2468
|
refetch
|
|
2462
2469
|
};
|
|
2463
2470
|
}
|
|
2471
|
+
function useEntityDetail(entity, id, options = {}) {
|
|
2472
|
+
var _a;
|
|
2473
|
+
const { view = "detail", sourceId, enabled = true } = options;
|
|
2474
|
+
const metadataParams = new URLSearchParams();
|
|
2475
|
+
metadataParams.set("view", view);
|
|
2476
|
+
if (sourceId) metadataParams.set("source_id", sourceId);
|
|
2477
|
+
const dataQuery = reactQuery.useQuery({
|
|
2478
|
+
queryKey: [entity, "detail", id],
|
|
2479
|
+
queryFn: () => apiClient.get(`/api/v1/${entity}/${id}`),
|
|
2480
|
+
enabled: enabled && !!id
|
|
2481
|
+
});
|
|
2482
|
+
const metadataQuery = reactQuery.useQuery({
|
|
2483
|
+
queryKey: [entity, "metadata", { view, sourceId }],
|
|
2484
|
+
queryFn: () => apiClient.get(
|
|
2485
|
+
`/api/v1/${entity}/fields/metadata?${metadataParams.toString()}`
|
|
2486
|
+
),
|
|
2487
|
+
enabled,
|
|
2488
|
+
staleTime: 5 * 60 * 1e3
|
|
2489
|
+
// 5 minutes
|
|
2490
|
+
});
|
|
2491
|
+
const refetch = () => {
|
|
2492
|
+
dataQuery.refetch();
|
|
2493
|
+
metadataQuery.refetch();
|
|
2494
|
+
};
|
|
2495
|
+
return {
|
|
2496
|
+
data: dataQuery.data ?? null,
|
|
2497
|
+
fields: ((_a = metadataQuery.data) == null ? void 0 : _a.columns) ?? [],
|
|
2498
|
+
isLoading: dataQuery.isLoading || metadataQuery.isLoading,
|
|
2499
|
+
isLoadingData: dataQuery.isLoading,
|
|
2500
|
+
isLoadingMetadata: metadataQuery.isLoading,
|
|
2501
|
+
error: dataQuery.error ?? metadataQuery.error ?? null,
|
|
2502
|
+
refetch
|
|
2503
|
+
};
|
|
2504
|
+
}
|
|
2464
2505
|
const buttonVariants = classVarianceAuthority.cva(
|
|
2465
2506
|
"inline-flex items-center justify-center whitespace-nowrap rounded-lg text-sm font-medium ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/20 focus-visible:ring-offset-0 disabled:pointer-events-none disabled:opacity-50 active:scale-[0.98]",
|
|
2466
2507
|
{
|
|
@@ -4151,7 +4192,9 @@ const TableHead$1 = React__namespace.forwardRef(({ className, ...props }, ref) =
|
|
|
4151
4192
|
{
|
|
4152
4193
|
ref,
|
|
4153
4194
|
className: cn(
|
|
4154
|
-
"h-12 px-4 xs:px-2 2xs:px-1 text-left align-middle font-semibold text-gray-700 text-xs uppercase tracking-wider
|
|
4195
|
+
"h-12 px-4 xs:px-2 2xs:px-1 text-left align-middle font-semibold text-gray-700 text-xs uppercase tracking-wider",
|
|
4196
|
+
// Compact padding for checkbox columns
|
|
4197
|
+
"[&:has(input[type=checkbox])]:px-2 [&:has(input[type=checkbox])]:w-8",
|
|
4155
4198
|
className
|
|
4156
4199
|
),
|
|
4157
4200
|
...props
|
|
@@ -4163,7 +4206,9 @@ const TableCell$1 = React__namespace.forwardRef(({ className, ...props }, ref) =
|
|
|
4163
4206
|
{
|
|
4164
4207
|
ref,
|
|
4165
4208
|
className: cn(
|
|
4166
|
-
"p-4 xs:p-2 2xs:p-1 align-middle
|
|
4209
|
+
"p-4 xs:p-2 2xs:p-1 align-middle",
|
|
4210
|
+
// Compact padding for checkbox columns
|
|
4211
|
+
"[&:has(input[type=checkbox])]:px-2 [&:has(input[type=checkbox])]:w-8",
|
|
4167
4212
|
className
|
|
4168
4213
|
),
|
|
4169
4214
|
...props
|
|
@@ -4213,7 +4258,12 @@ function DataTable({
|
|
|
4213
4258
|
ui,
|
|
4214
4259
|
error = null,
|
|
4215
4260
|
errorTitle,
|
|
4216
|
-
errorRetry
|
|
4261
|
+
errorRetry,
|
|
4262
|
+
selectable = false,
|
|
4263
|
+
selectedIds,
|
|
4264
|
+
onSelectionChange,
|
|
4265
|
+
getRowId,
|
|
4266
|
+
selectAllMode = "page"
|
|
4217
4267
|
}) {
|
|
4218
4268
|
const [searchTerm, setSearchTerm] = React.useState("");
|
|
4219
4269
|
const [sortColumn, setSortColumn] = React.useState(null);
|
|
@@ -4276,6 +4326,85 @@ function DataTable({
|
|
|
4276
4326
|
return true;
|
|
4277
4327
|
});
|
|
4278
4328
|
}, [normalizedColumns, currentBreakpoint, responsive]);
|
|
4329
|
+
const defaultGetRowId = React.useCallback((row) => {
|
|
4330
|
+
if ("id" in row && typeof row.id === "string") return row.id;
|
|
4331
|
+
if ("id" in row && typeof row.id === "number") return String(row.id);
|
|
4332
|
+
throw new Error("DataTable: selectable requires getRowId prop or row.id field");
|
|
4333
|
+
}, []);
|
|
4334
|
+
const effectiveGetRowId = getRowId ?? defaultGetRowId;
|
|
4335
|
+
const selectableData = selectAllMode === "all" ? sortedData : paginatedData;
|
|
4336
|
+
const selectableIds = React.useMemo(
|
|
4337
|
+
() => {
|
|
4338
|
+
if (!selectable) return /* @__PURE__ */ new Set();
|
|
4339
|
+
return new Set(selectableData.map((row) => effectiveGetRowId(row)));
|
|
4340
|
+
},
|
|
4341
|
+
[selectable, selectableData, effectiveGetRowId]
|
|
4342
|
+
);
|
|
4343
|
+
const selectedInScope = React.useMemo(
|
|
4344
|
+
() => {
|
|
4345
|
+
if (!selectable || !selectedIds) return /* @__PURE__ */ new Set();
|
|
4346
|
+
return new Set([...selectedIds].filter((id) => selectableIds.has(id)));
|
|
4347
|
+
},
|
|
4348
|
+
[selectable, selectedIds, selectableIds]
|
|
4349
|
+
);
|
|
4350
|
+
const isAllSelected = selectableIds.size > 0 && selectedInScope.size === selectableIds.size;
|
|
4351
|
+
const isIndeterminate = selectedInScope.size > 0 && selectedInScope.size < selectableIds.size;
|
|
4352
|
+
const handleSelectAll = React.useCallback(() => {
|
|
4353
|
+
if (!onSelectionChange) return;
|
|
4354
|
+
if (isAllSelected) {
|
|
4355
|
+
const newSelection = new Set([...selectedIds ?? []].filter((id) => !selectableIds.has(id)));
|
|
4356
|
+
onSelectionChange(newSelection);
|
|
4357
|
+
} else {
|
|
4358
|
+
const newSelection = /* @__PURE__ */ new Set([...selectedIds ?? [], ...selectableIds]);
|
|
4359
|
+
onSelectionChange(newSelection);
|
|
4360
|
+
}
|
|
4361
|
+
}, [isAllSelected, selectedIds, selectableIds, onSelectionChange]);
|
|
4362
|
+
const handleSelectRow = React.useCallback((rowId) => {
|
|
4363
|
+
if (!onSelectionChange) return;
|
|
4364
|
+
const newSelection = new Set(selectedIds);
|
|
4365
|
+
if (newSelection.has(rowId)) {
|
|
4366
|
+
newSelection.delete(rowId);
|
|
4367
|
+
} else {
|
|
4368
|
+
newSelection.add(rowId);
|
|
4369
|
+
}
|
|
4370
|
+
onSelectionChange(newSelection);
|
|
4371
|
+
}, [selectedIds, onSelectionChange]);
|
|
4372
|
+
const selectionColumn = React.useMemo(() => {
|
|
4373
|
+
return {
|
|
4374
|
+
key: "__selection__",
|
|
4375
|
+
header: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4376
|
+
Checkbox$1,
|
|
4377
|
+
{
|
|
4378
|
+
checked: isAllSelected,
|
|
4379
|
+
indeterminate: isIndeterminate,
|
|
4380
|
+
onCheckedChange: handleSelectAll,
|
|
4381
|
+
"aria-label": isAllSelected ? "Deselect all rows" : "Select all rows",
|
|
4382
|
+
size: "sm"
|
|
4383
|
+
}
|
|
4384
|
+
),
|
|
4385
|
+
cell: (row) => {
|
|
4386
|
+
const rowId = effectiveGetRowId(row);
|
|
4387
|
+
const isSelected = (selectedIds == null ? void 0 : selectedIds.has(rowId)) ?? false;
|
|
4388
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4389
|
+
Checkbox$1,
|
|
4390
|
+
{
|
|
4391
|
+
checked: isSelected,
|
|
4392
|
+
onCheckedChange: () => handleSelectRow(rowId),
|
|
4393
|
+
"aria-label": isSelected ? `Deselect row ${rowId}` : `Select row ${rowId}`,
|
|
4394
|
+
size: "sm",
|
|
4395
|
+
onClick: (e) => e.stopPropagation()
|
|
4396
|
+
}
|
|
4397
|
+
);
|
|
4398
|
+
},
|
|
4399
|
+
width: "32px",
|
|
4400
|
+
sortable: false,
|
|
4401
|
+
filterable: false
|
|
4402
|
+
};
|
|
4403
|
+
}, [isAllSelected, isIndeterminate, selectedIds, effectiveGetRowId, handleSelectAll, handleSelectRow]);
|
|
4404
|
+
const effectiveColumns = React.useMemo(() => {
|
|
4405
|
+
if (!selectable) return visibleColumns;
|
|
4406
|
+
return [selectionColumn, ...visibleColumns];
|
|
4407
|
+
}, [selectable, selectionColumn, visibleColumns]);
|
|
4279
4408
|
const handleSort = (columnKey) => {
|
|
4280
4409
|
if (sortColumn === columnKey) {
|
|
4281
4410
|
if (sortDirection === "asc") {
|
|
@@ -4338,8 +4467,8 @@ function DataTable({
|
|
|
4338
4467
|
children: [
|
|
4339
4468
|
showSearch && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex-1 max-w-sm", children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton$1, { className: "h-10 w-full" }) }) }),
|
|
4340
4469
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded border overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(Table$1, { children: [
|
|
4341
|
-
/* @__PURE__ */ jsxRuntime.jsx(TableHeader$1, { children: /* @__PURE__ */ jsxRuntime.jsx(TableRow$1, { children:
|
|
4342
|
-
/* @__PURE__ */ jsxRuntime.jsx(TableBody$1, { children: Array.from({ length: loadingItemCount }, (_, index) => /* @__PURE__ */ jsxRuntime.jsx(TableRow$1, { children:
|
|
4470
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableHeader$1, { children: /* @__PURE__ */ jsxRuntime.jsx(TableRow$1, { children: effectiveColumns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(TableHead$1, { style: { width: column.width }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton$1, { className: "h-4 w-20" }) }) }, column.key)) }) }),
|
|
4471
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableBody$1, { children: Array.from({ length: loadingItemCount }, (_, index) => /* @__PURE__ */ jsxRuntime.jsx(TableRow$1, { children: effectiveColumns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(TableCell$1, { children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton$1, { className: "h-4 w-full max-w-32" }) }, column.key)) }, index)) })
|
|
4343
4472
|
] }) }),
|
|
4344
4473
|
showPagination && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
4345
4474
|
/* @__PURE__ */ jsxRuntime.jsx(Skeleton$1, { className: "h-4 w-48" }),
|
|
@@ -4401,7 +4530,7 @@ function DataTable({
|
|
|
4401
4530
|
data: paginatedData,
|
|
4402
4531
|
onItemClick: onRowClick
|
|
4403
4532
|
}) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded border overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(Table$1, { children: [
|
|
4404
|
-
/* @__PURE__ */ jsxRuntime.jsx(TableHeader$1, { children: /* @__PURE__ */ jsxRuntime.jsx(TableRow$1, { children:
|
|
4533
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableHeader$1, { children: /* @__PURE__ */ jsxRuntime.jsx(TableRow$1, { children: effectiveColumns.map((column) => {
|
|
4405
4534
|
const width = column.width;
|
|
4406
4535
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4407
4536
|
TableHead$1,
|
|
@@ -4424,7 +4553,7 @@ function DataTable({
|
|
|
4424
4553
|
/* @__PURE__ */ jsxRuntime.jsx(TableBody$1, { children: paginatedData.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(TableRow$1, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4425
4554
|
TableCell$1,
|
|
4426
4555
|
{
|
|
4427
|
-
colSpan:
|
|
4556
|
+
colSpan: effectiveColumns.length,
|
|
4428
4557
|
className: "text-center py-8 text-muted-foreground",
|
|
4429
4558
|
children: emptyMessage
|
|
4430
4559
|
}
|
|
@@ -4436,7 +4565,7 @@ function DataTable({
|
|
|
4436
4565
|
(hover || onRowClick) && "hover:bg-muted/50"
|
|
4437
4566
|
),
|
|
4438
4567
|
onClick: () => onRowClick == null ? void 0 : onRowClick(item),
|
|
4439
|
-
children:
|
|
4568
|
+
children: effectiveColumns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(TableCell$1, { children: renderCell(column, item) }, column.key))
|
|
4440
4569
|
},
|
|
4441
4570
|
index
|
|
4442
4571
|
)) })
|
|
@@ -9261,6 +9390,55 @@ const ListToolbar = ({
|
|
|
9261
9390
|
}
|
|
9262
9391
|
);
|
|
9263
9392
|
};
|
|
9393
|
+
const FieldGrid = ({
|
|
9394
|
+
data,
|
|
9395
|
+
fields,
|
|
9396
|
+
sections,
|
|
9397
|
+
columns = 2,
|
|
9398
|
+
showLabels = true,
|
|
9399
|
+
compact = false,
|
|
9400
|
+
showEmpty = true,
|
|
9401
|
+
className
|
|
9402
|
+
}) => {
|
|
9403
|
+
const gridCols = {
|
|
9404
|
+
1: "grid-cols-1",
|
|
9405
|
+
2: "grid-cols-1 md:grid-cols-2",
|
|
9406
|
+
3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"
|
|
9407
|
+
};
|
|
9408
|
+
const renderValue = (field) => {
|
|
9409
|
+
const value = data[field.field];
|
|
9410
|
+
if (value === null || value === void 0 || value === "") {
|
|
9411
|
+
if (!showEmpty) return null;
|
|
9412
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "-" });
|
|
9413
|
+
}
|
|
9414
|
+
const format = field.format;
|
|
9415
|
+
return renderField(value, field.field, field.type, "lg", data, void 0, format);
|
|
9416
|
+
};
|
|
9417
|
+
const renderField_ = (field) => {
|
|
9418
|
+
const value = data[field.field];
|
|
9419
|
+
if (!showEmpty && (value === null || value === void 0 || value === "")) {
|
|
9420
|
+
return null;
|
|
9421
|
+
}
|
|
9422
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-1", compact ? "py-1" : "py-2"), children: [
|
|
9423
|
+
showLabels && /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-sm font-medium text-muted-foreground", children: field.label }),
|
|
9424
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { className: "text-sm text-foreground", children: renderValue(field) })
|
|
9425
|
+
] }, field.field);
|
|
9426
|
+
};
|
|
9427
|
+
const renderFields = (fieldList) => /* @__PURE__ */ jsxRuntime.jsx("dl", { className: cn("grid gap-x-6", gridCols[columns]), children: fieldList.map(renderField_) });
|
|
9428
|
+
if (sections && sections.length > 0) {
|
|
9429
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("space-y-6", className), children: sections.map((section) => /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: cn(compact ? "p-4" : "p-6"), children: [
|
|
9430
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4", children: [
|
|
9431
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-foreground", children: section.title }),
|
|
9432
|
+
section.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground mt-1", children: section.description })
|
|
9433
|
+
] }),
|
|
9434
|
+
renderFields(section.fields)
|
|
9435
|
+
] }, section.title)) });
|
|
9436
|
+
}
|
|
9437
|
+
if (fields && fields.length > 0) {
|
|
9438
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn(compact ? "p-4" : "p-6", className), children: renderFields(fields) });
|
|
9439
|
+
}
|
|
9440
|
+
return null;
|
|
9441
|
+
};
|
|
9264
9442
|
const Pagination = ({
|
|
9265
9443
|
currentPage,
|
|
9266
9444
|
totalPages,
|
|
@@ -9940,9 +10118,11 @@ function ProtectedRoute({
|
|
|
9940
10118
|
children,
|
|
9941
10119
|
requirePermission,
|
|
9942
10120
|
requireRole,
|
|
9943
|
-
fallback
|
|
10121
|
+
fallback,
|
|
10122
|
+
loginPath = "/login"
|
|
9944
10123
|
}) {
|
|
9945
10124
|
const { isAuthenticated, isLoading, hasPermission, hasRole } = useAuthContext();
|
|
10125
|
+
const location = reactRouterDom.useLocation();
|
|
9946
10126
|
if (isLoading) {
|
|
9947
10127
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
9948
10128
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto" }),
|
|
@@ -9950,7 +10130,7 @@ function ProtectedRoute({
|
|
|
9950
10130
|
] }) });
|
|
9951
10131
|
}
|
|
9952
10132
|
if (!isAuthenticated) {
|
|
9953
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10133
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: loginPath, state: { from: location }, replace: true });
|
|
9954
10134
|
}
|
|
9955
10135
|
if (requirePermission && !hasPermission(requirePermission)) {
|
|
9956
10136
|
return fallback || /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
@@ -9977,17 +10157,39 @@ function LogoutButton() {
|
|
|
9977
10157
|
/* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", size: "sm", onClick: logout, children: "Logout" })
|
|
9978
10158
|
] });
|
|
9979
10159
|
}
|
|
10160
|
+
const AUTH_TOKEN_KEY = "auth_token";
|
|
10161
|
+
const DEFAULT_ENDPOINTS = {
|
|
10162
|
+
login: "/auth/login",
|
|
10163
|
+
register: "/auth/register",
|
|
10164
|
+
refresh: "/auth/refresh",
|
|
10165
|
+
me: "/auth/me",
|
|
10166
|
+
logout: "/auth/logout"
|
|
10167
|
+
};
|
|
9980
10168
|
class AuthService {
|
|
9981
10169
|
constructor(config) {
|
|
9982
10170
|
__publicField(this, "config");
|
|
10171
|
+
__publicField(this, "apiClient");
|
|
9983
10172
|
__publicField(this, "refreshPromise", null);
|
|
10173
|
+
__publicField(this, "endpoints");
|
|
9984
10174
|
this.config = {
|
|
10175
|
+
mode: "pattern-stack",
|
|
9985
10176
|
tokenStorage: "localStorage",
|
|
9986
10177
|
tokenRefreshBuffer: 5,
|
|
9987
10178
|
// 5 minutes before expiry
|
|
9988
10179
|
autoRefresh: true,
|
|
9989
10180
|
...config
|
|
9990
10181
|
};
|
|
10182
|
+
this.endpoints = {
|
|
10183
|
+
...DEFAULT_ENDPOINTS,
|
|
10184
|
+
...config.endpoints
|
|
10185
|
+
};
|
|
10186
|
+
this.apiClient = createApiClient({ baseURL: this.config.apiUrl || "" });
|
|
10187
|
+
}
|
|
10188
|
+
/**
|
|
10189
|
+
* Get the auth mode
|
|
10190
|
+
*/
|
|
10191
|
+
get mode() {
|
|
10192
|
+
return this.config.mode || "pattern-stack";
|
|
9991
10193
|
}
|
|
9992
10194
|
getStorageKey(key) {
|
|
9993
10195
|
return `auth_${key}`;
|
|
@@ -10071,21 +10273,33 @@ class AuthService {
|
|
|
10071
10273
|
this.removeItem("user");
|
|
10072
10274
|
}
|
|
10073
10275
|
async login(credentials) {
|
|
10074
|
-
const response = await apiClient.post(`${this.config.apiUrl}${this.config.endpoints.login}`, credentials);
|
|
10075
10276
|
let token;
|
|
10076
10277
|
let refreshToken;
|
|
10077
10278
|
let expiresIn;
|
|
10078
|
-
|
|
10079
|
-
|
|
10080
|
-
|
|
10081
|
-
|
|
10279
|
+
let user;
|
|
10280
|
+
if (this.mode === "pattern-stack") {
|
|
10281
|
+
const response = await this.apiClient.post(
|
|
10282
|
+
this.endpoints.login,
|
|
10283
|
+
credentials
|
|
10284
|
+
);
|
|
10285
|
+
token = response.access_token;
|
|
10286
|
+
refreshToken = response.refresh_token;
|
|
10287
|
+
user = response.user;
|
|
10288
|
+
} else if (this.mode === "custom" && this.config.responseMapper) {
|
|
10289
|
+
const rawResponse = await this.apiClient.post(
|
|
10290
|
+
this.endpoints.login,
|
|
10291
|
+
credentials
|
|
10292
|
+
);
|
|
10293
|
+
const mapped = this.config.responseMapper(rawResponse);
|
|
10294
|
+
token = mapped.token;
|
|
10295
|
+
refreshToken = mapped.refreshToken;
|
|
10296
|
+
expiresIn = mapped.expiresIn;
|
|
10297
|
+
user = mapped.user;
|
|
10082
10298
|
} else {
|
|
10083
|
-
|
|
10084
|
-
|
|
10085
|
-
|
|
10086
|
-
expiresIn = oldResponse.expiresIn;
|
|
10299
|
+
throw new Error(
|
|
10300
|
+
`Invalid auth mode: ${this.mode}. Use 'pattern-stack' or 'custom' with responseMapper.`
|
|
10301
|
+
);
|
|
10087
10302
|
}
|
|
10088
|
-
const user = response.user;
|
|
10089
10303
|
const expiresAt = expiresIn ? Date.now() + expiresIn * 1e3 : void 0;
|
|
10090
10304
|
this.setTokenData({ token, refreshToken, expiresAt });
|
|
10091
10305
|
this.setStoredUser(user);
|
|
@@ -10111,21 +10325,27 @@ class AuthService {
|
|
|
10111
10325
|
}
|
|
10112
10326
|
async performTokenRefresh(currentRefreshToken) {
|
|
10113
10327
|
try {
|
|
10114
|
-
const response = await apiClient.post(`${this.config.apiUrl}${this.config.endpoints.refresh}`, {
|
|
10115
|
-
refresh_token: currentRefreshToken
|
|
10116
|
-
});
|
|
10117
10328
|
let token;
|
|
10118
10329
|
let newRefreshToken;
|
|
10119
10330
|
let expiresIn;
|
|
10120
|
-
if ("
|
|
10121
|
-
const
|
|
10122
|
-
|
|
10331
|
+
if (this.mode === "pattern-stack") {
|
|
10332
|
+
const response = await this.apiClient.post(
|
|
10333
|
+
this.endpoints.refresh,
|
|
10334
|
+
{ refresh_token: currentRefreshToken }
|
|
10335
|
+
);
|
|
10336
|
+
token = response.access_token;
|
|
10123
10337
|
newRefreshToken = currentRefreshToken;
|
|
10338
|
+
} else if (this.mode === "custom" && this.config.responseMapper) {
|
|
10339
|
+
const rawResponse = await this.apiClient.post(
|
|
10340
|
+
this.endpoints.refresh,
|
|
10341
|
+
{ refresh_token: currentRefreshToken }
|
|
10342
|
+
);
|
|
10343
|
+
const mapped = this.config.responseMapper(rawResponse);
|
|
10344
|
+
token = mapped.token;
|
|
10345
|
+
newRefreshToken = mapped.refreshToken || currentRefreshToken;
|
|
10346
|
+
expiresIn = mapped.expiresIn;
|
|
10124
10347
|
} else {
|
|
10125
|
-
|
|
10126
|
-
token = oldResponse.token;
|
|
10127
|
-
newRefreshToken = oldResponse.refreshToken;
|
|
10128
|
-
expiresIn = oldResponse.expiresIn;
|
|
10348
|
+
throw new Error(`Invalid auth mode for token refresh: ${this.mode}`);
|
|
10129
10349
|
}
|
|
10130
10350
|
const expiresAt = expiresIn ? Date.now() + expiresIn * 1e3 : void 0;
|
|
10131
10351
|
this.setTokenData({
|
|
@@ -10167,36 +10387,39 @@ class AuthService {
|
|
|
10167
10387
|
const tokenData = this.getTokenData();
|
|
10168
10388
|
if (!(tokenData == null ? void 0 : tokenData.token)) return null;
|
|
10169
10389
|
try {
|
|
10170
|
-
return await apiClient.get(
|
|
10171
|
-
`${this.config.apiUrl}${this.config.endpoints.me}`
|
|
10172
|
-
);
|
|
10390
|
+
return await this.apiClient.get(this.endpoints.me);
|
|
10173
10391
|
} catch {
|
|
10174
10392
|
return null;
|
|
10175
10393
|
}
|
|
10176
10394
|
}
|
|
10177
10395
|
async logout() {
|
|
10178
10396
|
const tokenData = this.getTokenData();
|
|
10179
|
-
if (this.
|
|
10397
|
+
if (this.endpoints.logout && (tokenData == null ? void 0 : tokenData.token)) {
|
|
10180
10398
|
try {
|
|
10181
|
-
await apiClient.post(
|
|
10182
|
-
`${this.config.apiUrl}${this.config.endpoints.logout}`
|
|
10183
|
-
);
|
|
10399
|
+
await this.apiClient.post(this.endpoints.logout);
|
|
10184
10400
|
} catch {
|
|
10185
10401
|
}
|
|
10186
10402
|
}
|
|
10187
10403
|
this.clearAuth();
|
|
10188
10404
|
}
|
|
10405
|
+
/**
|
|
10406
|
+
* Get the configured onAuthError handler
|
|
10407
|
+
*/
|
|
10408
|
+
get onAuthError() {
|
|
10409
|
+
return this.config.onAuthError;
|
|
10410
|
+
}
|
|
10189
10411
|
}
|
|
10190
10412
|
function AuthProvider({
|
|
10191
10413
|
children,
|
|
10192
10414
|
config
|
|
10193
10415
|
}) {
|
|
10416
|
+
var _a;
|
|
10194
10417
|
const [user, setUser] = React.useState(null);
|
|
10195
10418
|
const [isLoading, setIsLoading] = React.useState(true);
|
|
10196
10419
|
const [permissions, setPermissions] = React.useState([]);
|
|
10197
10420
|
const authService = React.useMemo(() => {
|
|
10198
10421
|
const defaultConfig = {
|
|
10199
|
-
apiUrl:
|
|
10422
|
+
apiUrl: (config == null ? void 0 : config.apiUrl) ?? "",
|
|
10200
10423
|
endpoints: {
|
|
10201
10424
|
login: "/auth/login",
|
|
10202
10425
|
register: "/auth/register",
|
|
@@ -10211,7 +10434,7 @@ function AuthProvider({
|
|
|
10211
10434
|
enabled: false
|
|
10212
10435
|
}
|
|
10213
10436
|
};
|
|
10214
|
-
const mergedConfig = config ? { ...defaultConfig, ...config } : defaultConfig;
|
|
10437
|
+
const mergedConfig = config ? { ...defaultConfig, ...config, apiUrl: config.apiUrl ?? defaultConfig.apiUrl } : defaultConfig;
|
|
10215
10438
|
const service = new AuthService(mergedConfig);
|
|
10216
10439
|
setGlobalAuthService(service);
|
|
10217
10440
|
return service;
|
|
@@ -10258,48 +10481,56 @@ function AuthProvider({
|
|
|
10258
10481
|
};
|
|
10259
10482
|
initAuth();
|
|
10260
10483
|
}, [authService]);
|
|
10261
|
-
const login = async (credentials) => {
|
|
10262
|
-
var _a;
|
|
10484
|
+
const login = React.useCallback(async (credentials) => {
|
|
10263
10485
|
setIsLoading(true);
|
|
10264
10486
|
try {
|
|
10265
|
-
const
|
|
10266
|
-
|
|
10267
|
-
|
|
10268
|
-
|
|
10269
|
-
|
|
10270
|
-
|
|
10271
|
-
|
|
10272
|
-
|
|
10273
|
-
|
|
10487
|
+
const loggedInUser = await authService.login(credentials);
|
|
10488
|
+
reactDom.flushSync(() => {
|
|
10489
|
+
var _a2;
|
|
10490
|
+
setUser(loggedInUser);
|
|
10491
|
+
if (((_a2 = config == null ? void 0 : config.permissions) == null ? void 0 : _a2.enabled) && "permissions" in loggedInUser) {
|
|
10492
|
+
const userPermissions = loggedInUser.permissions;
|
|
10493
|
+
setPermissions(
|
|
10494
|
+
Array.isArray(userPermissions) ? userPermissions : []
|
|
10495
|
+
);
|
|
10496
|
+
}
|
|
10497
|
+
setIsLoading(false);
|
|
10498
|
+
});
|
|
10499
|
+
} catch (error) {
|
|
10274
10500
|
setIsLoading(false);
|
|
10501
|
+
throw error;
|
|
10275
10502
|
}
|
|
10276
|
-
};
|
|
10277
|
-
const logout = async () => {
|
|
10503
|
+
}, [authService, (_a = config == null ? void 0 : config.permissions) == null ? void 0 : _a.enabled]);
|
|
10504
|
+
const logout = React.useCallback(async () => {
|
|
10278
10505
|
setIsLoading(true);
|
|
10279
10506
|
try {
|
|
10280
10507
|
await authService.logout();
|
|
10281
|
-
|
|
10282
|
-
|
|
10508
|
+
reactDom.flushSync(() => {
|
|
10509
|
+
setUser(null);
|
|
10510
|
+
setPermissions([]);
|
|
10511
|
+
setIsLoading(false);
|
|
10512
|
+
});
|
|
10283
10513
|
} catch (error) {
|
|
10284
10514
|
console.error("Logout error:", error);
|
|
10285
10515
|
authService.clearAuth();
|
|
10286
|
-
|
|
10287
|
-
|
|
10288
|
-
|
|
10289
|
-
|
|
10516
|
+
reactDom.flushSync(() => {
|
|
10517
|
+
setUser(null);
|
|
10518
|
+
setPermissions([]);
|
|
10519
|
+
setIsLoading(false);
|
|
10520
|
+
});
|
|
10290
10521
|
}
|
|
10291
|
-
};
|
|
10522
|
+
}, [authService]);
|
|
10292
10523
|
const refreshToken = async () => {
|
|
10293
10524
|
await authService.refreshToken();
|
|
10294
10525
|
};
|
|
10295
10526
|
const hasPermission = (permission) => {
|
|
10296
|
-
var
|
|
10297
|
-
if (!((
|
|
10527
|
+
var _a2;
|
|
10528
|
+
if (!((_a2 = config == null ? void 0 : config.permissions) == null ? void 0 : _a2.enabled)) return true;
|
|
10298
10529
|
return permissions.includes(permission);
|
|
10299
10530
|
};
|
|
10300
10531
|
const hasRole = (role) => {
|
|
10301
|
-
var
|
|
10302
|
-
if (!((
|
|
10532
|
+
var _a2;
|
|
10533
|
+
if (!((_a2 = config == null ? void 0 : config.permissions) == null ? void 0 : _a2.enabled)) return true;
|
|
10303
10534
|
if (user && "role" in user) {
|
|
10304
10535
|
return user.role === role;
|
|
10305
10536
|
}
|
|
@@ -10508,6 +10739,32 @@ function MockAuthProvider({
|
|
|
10508
10739
|
};
|
|
10509
10740
|
return /* @__PURE__ */ jsxRuntime.jsx(AuthContext.Provider, { value, children });
|
|
10510
10741
|
}
|
|
10742
|
+
function NoAuthProvider({ children }) {
|
|
10743
|
+
const noOpLogin = async () => {
|
|
10744
|
+
console.warn("NoAuthProvider: login() called but auth is disabled");
|
|
10745
|
+
};
|
|
10746
|
+
const noOpLogout = async () => {
|
|
10747
|
+
console.warn("NoAuthProvider: logout() called but auth is disabled");
|
|
10748
|
+
};
|
|
10749
|
+
const noOpRefresh = async () => {
|
|
10750
|
+
console.warn("NoAuthProvider: refreshToken() called but auth is disabled");
|
|
10751
|
+
};
|
|
10752
|
+
const value = {
|
|
10753
|
+
user: null,
|
|
10754
|
+
isAuthenticated: true,
|
|
10755
|
+
// Always authenticated in no-auth mode
|
|
10756
|
+
isLoading: false,
|
|
10757
|
+
permissions: [],
|
|
10758
|
+
login: noOpLogin,
|
|
10759
|
+
logout: noOpLogout,
|
|
10760
|
+
refreshToken: noOpRefresh,
|
|
10761
|
+
hasPermission: () => true,
|
|
10762
|
+
// All permissions granted
|
|
10763
|
+
hasRole: () => true
|
|
10764
|
+
// All roles granted
|
|
10765
|
+
};
|
|
10766
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AuthContext.Provider, { value, children });
|
|
10767
|
+
}
|
|
10511
10768
|
const MockAuthContext = React.createContext(
|
|
10512
10769
|
void 0
|
|
10513
10770
|
);
|
|
@@ -13647,7 +13904,13 @@ function createReactApp(config) {
|
|
|
13647
13904
|
tree = /* @__PURE__ */ jsxRuntime.jsx(NavigationProvider, { initialNavigation: navigation, children: /* @__PURE__ */ jsxRuntime.jsx(SidebarProvider, { children: tree }) });
|
|
13648
13905
|
}
|
|
13649
13906
|
if (enableAuth) {
|
|
13650
|
-
|
|
13907
|
+
const authMode = (auth == null ? void 0 : auth.mode) || "pattern-stack";
|
|
13908
|
+
if (authMode === "none") {
|
|
13909
|
+
setGlobalAuthService(null);
|
|
13910
|
+
tree = /* @__PURE__ */ jsxRuntime.jsx(NoAuthProvider, { children: tree });
|
|
13911
|
+
} else {
|
|
13912
|
+
tree = /* @__PURE__ */ jsxRuntime.jsx(AuthProvider, { config: auth, children: tree });
|
|
13913
|
+
}
|
|
13651
13914
|
}
|
|
13652
13915
|
if (enableQuery) {
|
|
13653
13916
|
tree = /* @__PURE__ */ jsxRuntime.jsxs(reactQuery.QueryClientProvider, { client: queryClient, children: [
|
|
@@ -13665,7 +13928,8 @@ function createReactApp(config) {
|
|
|
13665
13928
|
routes.push({ path, component });
|
|
13666
13929
|
},
|
|
13667
13930
|
render() {
|
|
13668
|
-
const
|
|
13931
|
+
const authMode = (auth == null ? void 0 : auth.mode) || "pattern-stack";
|
|
13932
|
+
const shouldProtect = enableAuth && authMode !== "none" && (auth == null ? void 0 : auth.requireAuth) !== false;
|
|
13669
13933
|
const publicPaths = (auth == null ? void 0 : auth.publicPaths) ?? ["/login", "/register", "/forgot-password"];
|
|
13670
13934
|
const isPublicPath = (path) => {
|
|
13671
13935
|
return publicPaths.some((p) => path === p || path.startsWith(p + "/"));
|
|
@@ -16852,12 +17116,14 @@ function capitalize(str) {
|
|
|
16852
17116
|
exports.APIDataTemplate = APIDataTemplate;
|
|
16853
17117
|
exports.API_ENDPOINTS = API_ENDPOINTS;
|
|
16854
17118
|
exports.APP_NAME = APP_NAME;
|
|
17119
|
+
exports.AUTH_TOKEN_KEY = AUTH_TOKEN_KEY;
|
|
16855
17120
|
exports.Accordion = Accordion;
|
|
16856
17121
|
exports.ActivityFeed = ActivityFeed;
|
|
16857
17122
|
exports.AdminCRUDTemplate = AdminCRUDTemplate;
|
|
16858
17123
|
exports.AdminDashboardTemplate = AdminDashboardTemplate;
|
|
16859
17124
|
exports.AdminDetailTemplate = AdminDetailTemplate;
|
|
16860
17125
|
exports.Alert = Alert;
|
|
17126
|
+
exports.ApiClient = ApiClient;
|
|
16861
17127
|
exports.AppHeader = AppHeader;
|
|
16862
17128
|
exports.AppLayout = AppLayout;
|
|
16863
17129
|
exports.AuthDivider = AuthDivider;
|
|
@@ -16924,6 +17190,7 @@ exports.EmptyState = EmptyState;
|
|
|
16924
17190
|
exports.EnhancedDataTemplate = EnhancedDataTemplate;
|
|
16925
17191
|
exports.EntityIcon = EntityIcon;
|
|
16926
17192
|
exports.ErrorBoundary = ErrorBoundary2;
|
|
17193
|
+
exports.FieldGrid = FieldGrid;
|
|
16927
17194
|
exports.FileUpload = FileUpload;
|
|
16928
17195
|
exports.FormField = FormField;
|
|
16929
17196
|
exports.FormGroup = FormGroup;
|
|
@@ -16943,6 +17210,7 @@ exports.MockAuthProvider = MockAuthProvider;
|
|
|
16943
17210
|
exports.Modal = Modal;
|
|
16944
17211
|
exports.NavMenu = NavMenu;
|
|
16945
17212
|
exports.NavigationProvider = NavigationProvider;
|
|
17213
|
+
exports.NoAuthProvider = NoAuthProvider;
|
|
16946
17214
|
exports.PageTemplate = PageTemplate;
|
|
16947
17215
|
exports.PageTitle = PageTitle;
|
|
16948
17216
|
exports.Pagination = Pagination;
|
|
@@ -17006,6 +17274,7 @@ exports.apiClient = apiClient;
|
|
|
17006
17274
|
exports.breakpoints = breakpoints;
|
|
17007
17275
|
exports.cn = cn;
|
|
17008
17276
|
exports.createAPIDataTemplate = createAPIDataTemplate;
|
|
17277
|
+
exports.createApiClient = createApiClient;
|
|
17009
17278
|
exports.createReactApp = createReactApp;
|
|
17010
17279
|
exports.createSimpleApp = createSimpleApp;
|
|
17011
17280
|
exports.defaultFieldRenderers = defaultFieldRenderers;
|
|
@@ -17019,6 +17288,7 @@ exports.getChartHeight = getChartHeight;
|
|
|
17019
17288
|
exports.getContainerHeightClass = getContainerHeightClass;
|
|
17020
17289
|
exports.getCurrentBreakpoint = getCurrentBreakpoint;
|
|
17021
17290
|
exports.getFieldType = getFieldType;
|
|
17291
|
+
exports.getGlobalAuthService = getGlobalAuthService;
|
|
17022
17292
|
exports.getIcon = getIcon;
|
|
17023
17293
|
exports.getNavigationItems = getNavigationItems;
|
|
17024
17294
|
exports.getResponsiveClasses = getResponsiveClasses;
|
|
@@ -17042,6 +17312,7 @@ exports.useCategoryColors = useCategoryColors;
|
|
|
17042
17312
|
exports.useCreateExample = useCreateExample;
|
|
17043
17313
|
exports.useDeleteExample = useDeleteExample;
|
|
17044
17314
|
exports.useEntityData = useEntityData;
|
|
17315
|
+
exports.useEntityDetail = useEntityDetail;
|
|
17045
17316
|
exports.useErrorBoundary = useErrorBoundary;
|
|
17046
17317
|
exports.useFieldMetadata = useFieldMetadata;
|
|
17047
17318
|
exports.useGetExample = useGetExample;
|