xladmin 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1670 @@
1
+ // src/client.ts
2
+ function createXLAdminClient(transport) {
3
+ return {
4
+ async getModels() {
5
+ return await transportGet(transport, "/xladmin/models/");
6
+ },
7
+ async getModel(slug) {
8
+ return await transportGet(transport, `/xladmin/models/${slug}/`);
9
+ },
10
+ async getItems(slug, params) {
11
+ return await transportGet(transport, `/xladmin/models/${slug}/items/`, { params });
12
+ },
13
+ async getItem(slug, id) {
14
+ return await transportGet(transport, `/xladmin/models/${slug}/items/${id}/`);
15
+ },
16
+ async createItem(slug, payload) {
17
+ return await transportPost(transport, `/xladmin/models/${slug}/items/`, payload);
18
+ },
19
+ async patchItem(slug, id, payload) {
20
+ return await transportPatch(transport, `/xladmin/models/${slug}/items/${id}/`, payload);
21
+ },
22
+ async deleteItem(slug, id) {
23
+ await transport.delete(`/xladmin/models/${slug}/items/${id}/`);
24
+ },
25
+ async bulkDelete(slug, ids) {
26
+ return await transportPost(transport, `/xladmin/models/${slug}/bulk-delete/`, { ids });
27
+ },
28
+ async runBulkAction(slug, actionSlug, ids, payload) {
29
+ return await transportPost(
30
+ transport,
31
+ `/xladmin/models/${slug}/bulk-actions/${actionSlug}/`,
32
+ { ids, ...payload != null ? payload : {} }
33
+ );
34
+ },
35
+ async runObjectAction(slug, id, actionSlug, payload) {
36
+ return await transportPost(
37
+ transport,
38
+ `/xladmin/models/${slug}/items/${id}/actions/${actionSlug}/`,
39
+ payload != null ? payload : {}
40
+ );
41
+ },
42
+ async getChoices(slug, fieldName, q, ids) {
43
+ return await transportGet(
44
+ transport,
45
+ `/xladmin/models/${slug}/fields/${fieldName}/choices/`,
46
+ {
47
+ params: {
48
+ ...q ? { q } : {},
49
+ ...ids && ids.length > 0 ? { ids: ids.join(",") } : {}
50
+ }
51
+ }
52
+ );
53
+ }
54
+ };
55
+ }
56
+ function createAxiosXLAdminClient(api) {
57
+ return createXLAdminClient(api);
58
+ }
59
+ function createFetchXLAdminClient(config) {
60
+ return createXLAdminClient(createFetchXLAdminTransport(config));
61
+ }
62
+ function createFetchXLAdminTransport(config) {
63
+ var _a;
64
+ const fetchImpl = (_a = config.fetch) != null ? _a : globalThis.fetch;
65
+ if (!fetchImpl) {
66
+ throw new Error("Fetch API is not available in the current environment.");
67
+ }
68
+ return {
69
+ get: async (url, options) => await requestJson(fetchImpl, config, "GET", url, void 0, options == null ? void 0 : options.params),
70
+ post: async (url, body) => await requestJson(fetchImpl, config, "POST", url, body),
71
+ patch: async (url, body) => await requestJson(fetchImpl, config, "PATCH", url, body),
72
+ delete: async (url) => {
73
+ await requestRaw(fetchImpl, config, "DELETE", url);
74
+ }
75
+ };
76
+ }
77
+ async function transportGet(transport, url, options) {
78
+ return unwrapTransportResponse(await transport.get(url, options));
79
+ }
80
+ async function transportPost(transport, url, body) {
81
+ return unwrapTransportResponse(await transport.post(url, body));
82
+ }
83
+ async function transportPatch(transport, url, body) {
84
+ return unwrapTransportResponse(await transport.patch(url, body));
85
+ }
86
+ function unwrapTransportResponse(response) {
87
+ if (isWrappedTransportResponse(response)) {
88
+ return response.data;
89
+ }
90
+ return response;
91
+ }
92
+ function isWrappedTransportResponse(response) {
93
+ return typeof response === "object" && response !== null && "data" in response;
94
+ }
95
+ async function requestJson(fetchImpl, config, method, url, body, params) {
96
+ const response = await requestRaw(fetchImpl, config, method, url, body, params);
97
+ return await response.json();
98
+ }
99
+ async function requestRaw(fetchImpl, config, method, url, body, params) {
100
+ var _a;
101
+ const headers = await resolveHeaders(config.headers);
102
+ const response = await fetchImpl(buildRequestUrl(config.baseUrl, url, params), {
103
+ method,
104
+ credentials: (_a = config.credentials) != null ? _a : "include",
105
+ headers: {
106
+ "Content-Type": "application/json",
107
+ ...headers
108
+ },
109
+ body: body === void 0 ? void 0 : JSON.stringify(body)
110
+ });
111
+ if (!response.ok) {
112
+ let detail = `${response.status} ${response.statusText}`;
113
+ try {
114
+ const errorData = await response.json();
115
+ if (typeof errorData.detail === "string" && errorData.detail) {
116
+ detail = errorData.detail;
117
+ }
118
+ } catch {
119
+ }
120
+ throw new Error(detail);
121
+ }
122
+ return response;
123
+ }
124
+ async function resolveHeaders(headers) {
125
+ if (headers === void 0) {
126
+ return {};
127
+ }
128
+ if (typeof headers === "function") {
129
+ return await headers();
130
+ }
131
+ return headers;
132
+ }
133
+ function buildRequestUrl(baseUrl, path, params) {
134
+ const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
135
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
136
+ const requestUrl = new URL(`${normalizedBaseUrl}${normalizedPath}`, "http://localhost");
137
+ const query = buildSearchParams(params);
138
+ if (query) {
139
+ requestUrl.search = query;
140
+ }
141
+ if (/^https?:\/\//i.test(normalizedBaseUrl)) {
142
+ return requestUrl.toString();
143
+ }
144
+ return `${normalizedBaseUrl}${normalizedPath}${query ? `?${query}` : ""}`;
145
+ }
146
+ function buildSearchParams(params) {
147
+ if (!params) {
148
+ return "";
149
+ }
150
+ const searchParams = new URLSearchParams();
151
+ for (const [key, value] of Object.entries(params)) {
152
+ if (value === void 0 || value === null || value === "") {
153
+ continue;
154
+ }
155
+ searchParams.set(key, String(value));
156
+ }
157
+ return searchParams.toString();
158
+ }
159
+
160
+ // src/components/AdminFormDialog.tsx
161
+ import { useEffect as useEffect2, useMemo as useMemo2, useState as useState2 } from "react";
162
+ import {
163
+ Box,
164
+ Button,
165
+ Dialog,
166
+ DialogActions,
167
+ DialogContent,
168
+ DialogTitle
169
+ } from "@mui/material";
170
+ import { LocalizationProvider } from "@mui/x-date-pickers";
171
+ import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
172
+
173
+ // src/utils/adminFields.ts
174
+ function buildAdminPayload(values, fields) {
175
+ const fieldMap = new Map(fields.map((field) => [field.name, field]));
176
+ const payload = {};
177
+ for (const [fieldName, value] of Object.entries(values)) {
178
+ const field = fieldMap.get(fieldName);
179
+ if (!field) {
180
+ continue;
181
+ }
182
+ if (value === void 0) {
183
+ continue;
184
+ }
185
+ if (value === "" && field.input_kind === "password") {
186
+ continue;
187
+ }
188
+ if (value === "" && field.nullable) {
189
+ payload[fieldName] = null;
190
+ continue;
191
+ }
192
+ if (value === "") {
193
+ continue;
194
+ }
195
+ payload[fieldName] = value;
196
+ }
197
+ return payload;
198
+ }
199
+ function formatAdminValue(value) {
200
+ if (value === null || value === void 0) {
201
+ return "";
202
+ }
203
+ if (Array.isArray(value)) {
204
+ return value.map((item) => formatAdminValue(item)).filter(Boolean).join(", ");
205
+ }
206
+ if (typeof value === "boolean") {
207
+ return value ? "\u0414\u0430" : "\u041D\u0435\u0442";
208
+ }
209
+ if (typeof value === "object") {
210
+ return JSON.stringify(value);
211
+ }
212
+ return String(value);
213
+ }
214
+
215
+ // src/components/AdminFieldEditor.tsx
216
+ import { useEffect, useMemo, useState } from "react";
217
+ import {
218
+ Autocomplete,
219
+ CircularProgress,
220
+ FormControlLabel,
221
+ Switch,
222
+ TextField
223
+ } from "@mui/material";
224
+ import { DatePicker, DateTimePicker } from "@mui/x-date-pickers";
225
+ import dayjs from "dayjs";
226
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
227
+ function AdminFieldEditor({
228
+ field,
229
+ value,
230
+ onChange,
231
+ slug,
232
+ client,
233
+ readOnly = false
234
+ }) {
235
+ var _a, _b, _c;
236
+ const [choices, setChoices] = useState([]);
237
+ const [searchValue, setSearchValue] = useState("");
238
+ const [isLoadingChoices, setIsLoadingChoices] = useState(false);
239
+ const selectedIds = useMemo(() => normalizeSelectedIds(value, field.is_relation_many), [field.is_relation_many, value]);
240
+ useEffect(() => {
241
+ if (!field.has_choices) {
242
+ setChoices([]);
243
+ return;
244
+ }
245
+ let isMounted = true;
246
+ setIsLoadingChoices(true);
247
+ client.getChoices(
248
+ slug,
249
+ field.name,
250
+ searchValue || void 0,
251
+ selectedIds
252
+ ).then((response) => {
253
+ if (!isMounted) return;
254
+ setChoices((current) => mergeChoices(current, response.items));
255
+ }).catch(() => {
256
+ if (!isMounted) return;
257
+ setChoices((current) => current);
258
+ }).finally(() => {
259
+ if (!isMounted) return;
260
+ setIsLoadingChoices(false);
261
+ });
262
+ return () => {
263
+ isMounted = false;
264
+ };
265
+ }, [client, field.has_choices, field.name, searchValue, selectedIds, slug]);
266
+ if (field.input_kind === "boolean") {
267
+ return /* @__PURE__ */ jsx(
268
+ FormControlLabel,
269
+ {
270
+ control: /* @__PURE__ */ jsx(
271
+ Switch,
272
+ {
273
+ checked: Boolean(value),
274
+ disabled: readOnly,
275
+ onChange: (_, checked) => onChange(checked)
276
+ }
277
+ ),
278
+ label: field.label
279
+ }
280
+ );
281
+ }
282
+ if (field.input_kind === "date") {
283
+ return /* @__PURE__ */ jsx(
284
+ DatePicker,
285
+ {
286
+ label: field.label,
287
+ disabled: readOnly,
288
+ value: value ? dayjs(String(value)) : null,
289
+ onChange: (nextValue) => onChange(nextValue ? nextValue.format("YYYY-MM-DD") : null),
290
+ slotProps: {
291
+ popper: {
292
+ disablePortal: true
293
+ },
294
+ desktopPaper: {
295
+ sx: {
296
+ borderRadius: "10px",
297
+ backgroundImage: "none",
298
+ backgroundColor: "background.paper"
299
+ }
300
+ },
301
+ mobilePaper: {
302
+ sx: {
303
+ borderRadius: "10px",
304
+ backgroundImage: "none",
305
+ backgroundColor: "background.paper"
306
+ }
307
+ },
308
+ textField: {
309
+ fullWidth: true,
310
+ size: "small",
311
+ helperText: (_a = field.help_text) != null ? _a : void 0
312
+ }
313
+ }
314
+ }
315
+ );
316
+ }
317
+ if (field.input_kind === "datetime") {
318
+ return /* @__PURE__ */ jsx(
319
+ DateTimePicker,
320
+ {
321
+ label: field.label,
322
+ disabled: readOnly,
323
+ value: value ? dayjs(String(value)) : null,
324
+ onChange: (nextValue) => onChange(nextValue ? nextValue.toISOString() : null),
325
+ slotProps: {
326
+ popper: {
327
+ disablePortal: true
328
+ },
329
+ desktopPaper: {
330
+ sx: {
331
+ borderRadius: "10px",
332
+ backgroundImage: "none",
333
+ backgroundColor: "background.paper"
334
+ }
335
+ },
336
+ mobilePaper: {
337
+ sx: {
338
+ borderRadius: "10px",
339
+ backgroundImage: "none",
340
+ backgroundColor: "background.paper"
341
+ }
342
+ },
343
+ textField: {
344
+ fullWidth: true,
345
+ size: "small",
346
+ helperText: (_b = field.help_text) != null ? _b : void 0
347
+ }
348
+ }
349
+ }
350
+ );
351
+ }
352
+ if (field.has_choices) {
353
+ return renderChoiceEditor({
354
+ field,
355
+ value,
356
+ onChange,
357
+ readOnly,
358
+ choices,
359
+ isLoadingChoices,
360
+ onSearchChange: setSearchValue
361
+ });
362
+ }
363
+ return /* @__PURE__ */ jsx(
364
+ TextField,
365
+ {
366
+ label: field.label,
367
+ value: value != null ? value : "",
368
+ onChange: (event) => onChange(event.target.value),
369
+ size: "small",
370
+ fullWidth: true,
371
+ disabled: readOnly,
372
+ helperText: (_c = field.help_text) != null ? _c : void 0,
373
+ type: resolveInputType(field),
374
+ multiline: field.input_kind === "textarea" || field.type.toLowerCase().includes("text"),
375
+ minRows: field.input_kind === "textarea" || field.type.toLowerCase().includes("text") ? 3 : void 0
376
+ }
377
+ );
378
+ }
379
+ function renderChoiceEditor({
380
+ field,
381
+ value,
382
+ onChange,
383
+ readOnly,
384
+ choices,
385
+ isLoadingChoices,
386
+ onSearchChange
387
+ }) {
388
+ var _a;
389
+ const selectedIds = normalizeSelectedIds(value, field.is_relation_many);
390
+ const selectedOptions = selectedIds.map((id) => {
391
+ var _a2;
392
+ return (_a2 = choices.find((choice) => String(choice.id) == String(id))) != null ? _a2 : {
393
+ id,
394
+ label: String(id)
395
+ };
396
+ });
397
+ if (field.is_relation_many || field.input_kind === "relation-multiple") {
398
+ return /* @__PURE__ */ jsx(
399
+ Autocomplete,
400
+ {
401
+ multiple: true,
402
+ options: choices,
403
+ value: selectedOptions,
404
+ loading: isLoadingChoices,
405
+ disabled: readOnly,
406
+ filterOptions: (options) => options,
407
+ size: "small",
408
+ disablePortal: true,
409
+ isOptionEqualToValue: (option, selected) => String(option.id) === String(selected.id),
410
+ getOptionLabel: (option) => option.label,
411
+ onChange: (_, nextValue) => onChange(nextValue.map((item) => item.id)),
412
+ onInputChange: (_, nextInputValue) => onSearchChange(nextInputValue),
413
+ slotProps: {
414
+ paper: {
415
+ sx: {
416
+ mt: 0.5,
417
+ borderRadius: "10px",
418
+ backgroundImage: "none",
419
+ backgroundColor: "background.paper"
420
+ }
421
+ }
422
+ },
423
+ ListboxProps: {
424
+ sx: {
425
+ maxHeight: 240
426
+ }
427
+ },
428
+ renderInput: (params) => {
429
+ var _a2;
430
+ return /* @__PURE__ */ jsx(
431
+ TextField,
432
+ {
433
+ ...params,
434
+ label: field.label,
435
+ placeholder: "\u041F\u043E\u0438\u0441\u043A",
436
+ helperText: (_a2 = field.help_text) != null ? _a2 : void 0,
437
+ InputProps: {
438
+ ...params.InputProps,
439
+ endAdornment: /* @__PURE__ */ jsxs(Fragment, { children: [
440
+ isLoadingChoices ? /* @__PURE__ */ jsx(CircularProgress, { color: "inherit", size: 16 }) : null,
441
+ params.InputProps.endAdornment
442
+ ] })
443
+ }
444
+ }
445
+ );
446
+ }
447
+ }
448
+ );
449
+ }
450
+ return /* @__PURE__ */ jsx(
451
+ Autocomplete,
452
+ {
453
+ options: choices,
454
+ value: (_a = selectedOptions[0]) != null ? _a : null,
455
+ loading: isLoadingChoices,
456
+ disabled: readOnly,
457
+ filterOptions: (options) => options,
458
+ size: "small",
459
+ disablePortal: true,
460
+ isOptionEqualToValue: (option, selected) => String(option.id) === String(selected.id),
461
+ getOptionLabel: (option) => option.label,
462
+ onChange: (_, nextValue) => {
463
+ var _a2;
464
+ return onChange((_a2 = nextValue == null ? void 0 : nextValue.id) != null ? _a2 : null);
465
+ },
466
+ onInputChange: (_, nextInputValue) => onSearchChange(nextInputValue),
467
+ slotProps: {
468
+ paper: {
469
+ sx: {
470
+ mt: 0.5,
471
+ borderRadius: "10px",
472
+ backgroundImage: "none",
473
+ backgroundColor: "background.paper"
474
+ }
475
+ }
476
+ },
477
+ ListboxProps: {
478
+ sx: {
479
+ maxHeight: 240
480
+ }
481
+ },
482
+ renderInput: (params) => {
483
+ var _a2;
484
+ return /* @__PURE__ */ jsx(
485
+ TextField,
486
+ {
487
+ ...params,
488
+ label: field.label,
489
+ placeholder: "\u041F\u043E\u0438\u0441\u043A",
490
+ helperText: (_a2 = field.help_text) != null ? _a2 : void 0,
491
+ InputProps: {
492
+ ...params.InputProps,
493
+ endAdornment: /* @__PURE__ */ jsxs(Fragment, { children: [
494
+ isLoadingChoices ? /* @__PURE__ */ jsx(CircularProgress, { color: "inherit", size: 16 }) : null,
495
+ params.InputProps.endAdornment
496
+ ] })
497
+ }
498
+ }
499
+ );
500
+ }
501
+ }
502
+ );
503
+ }
504
+ function normalizeSelectedIds(value, isMultiple) {
505
+ if (isMultiple) {
506
+ if (!Array.isArray(value)) {
507
+ return [];
508
+ }
509
+ return value.filter((item) => typeof item === "string" || typeof item === "number");
510
+ }
511
+ if (typeof value === "string" || typeof value === "number") {
512
+ return [value];
513
+ }
514
+ return [];
515
+ }
516
+ function mergeChoices(current, next) {
517
+ const choiceMap = /* @__PURE__ */ new Map();
518
+ for (const choice of [...current, ...next]) {
519
+ choiceMap.set(String(choice.id), choice);
520
+ }
521
+ return [...choiceMap.values()];
522
+ }
523
+ function resolveInputType(field) {
524
+ if (field.input_kind === "password") {
525
+ return "password";
526
+ }
527
+ if (field.input_kind === "number" || field.input_kind === "decimal") {
528
+ return "number";
529
+ }
530
+ return "text";
531
+ }
532
+
533
+ // src/components/AdminFormDialog.tsx
534
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
535
+ function AdminFormDialog({
536
+ open,
537
+ onClose,
538
+ onSuccess,
539
+ title,
540
+ slug,
541
+ mode,
542
+ meta,
543
+ client,
544
+ initialValues,
545
+ itemId
546
+ }) {
547
+ const [values, setValues] = useState2({});
548
+ const editableFieldNames = useMemo2(
549
+ () => mode === "create" ? meta.create_fields : meta.update_fields,
550
+ [meta.create_fields, meta.update_fields, mode]
551
+ );
552
+ const editableFields = useMemo2(
553
+ () => meta.fields.filter((field) => editableFieldNames.includes(field.name)),
554
+ [editableFieldNames, meta.fields]
555
+ );
556
+ useEffect2(() => {
557
+ setValues(initialValues != null ? initialValues : {});
558
+ }, [initialValues, open]);
559
+ const handleSave = async () => {
560
+ const payload = buildAdminPayload(values, editableFields);
561
+ if (mode === "create") {
562
+ await client.createItem(slug, payload);
563
+ } else if (itemId !== void 0) {
564
+ await client.patchItem(slug, itemId, payload);
565
+ }
566
+ onSuccess();
567
+ onClose();
568
+ };
569
+ return /* @__PURE__ */ jsxs2(Dialog, { open, onClose, fullWidth: true, maxWidth: "md", children: [
570
+ /* @__PURE__ */ jsx2(DialogTitle, { children: title }),
571
+ /* @__PURE__ */ jsx2(DialogContent, { children: /* @__PURE__ */ jsx2(LocalizationProvider, { dateAdapter: AdapterDayjs, children: /* @__PURE__ */ jsx2(Box, { sx: { display: "grid", gap: 2, pt: 1 }, children: editableFields.map((field) => /* @__PURE__ */ jsx2(
572
+ AdminFieldEditor,
573
+ {
574
+ field,
575
+ value: values[field.name],
576
+ slug,
577
+ client,
578
+ onChange: (nextValue) => {
579
+ setValues((current) => ({ ...current, [field.name]: nextValue }));
580
+ }
581
+ },
582
+ field.name
583
+ )) }) }) }),
584
+ /* @__PURE__ */ jsxs2(DialogActions, { children: [
585
+ /* @__PURE__ */ jsx2(Button, { onClick: onClose, children: "\u041E\u0442\u043C\u0435\u043D\u0430" }),
586
+ /* @__PURE__ */ jsx2(Button, { variant: "contained", onClick: handleSave, children: "\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C" })
587
+ ] })
588
+ ] });
589
+ }
590
+
591
+ // src/components/AdminHome.tsx
592
+ import Link from "next/link.js";
593
+ import { Alert, Box as Box2, Card, CardActionArea, CardContent, Grid, Paper, Stack, Typography } from "@mui/material";
594
+
595
+ // src/hooks/useAdminRequest.ts
596
+ import { useEffect as useEffect3, useState as useState3 } from "react";
597
+ function useAdminRequest(loader, deps) {
598
+ const [data, setData] = useState3(null);
599
+ const [isLoading, setIsLoading] = useState3(true);
600
+ const [error, setError] = useState3(null);
601
+ useEffect3(() => {
602
+ let isActive = true;
603
+ setIsLoading(true);
604
+ setError(null);
605
+ loader().then((response) => {
606
+ if (!isActive) return;
607
+ setData(response);
608
+ }).catch((reason) => {
609
+ if (!isActive) return;
610
+ setError(reason instanceof Error ? reason.message : "Request failed");
611
+ }).finally(() => {
612
+ if (!isActive) return;
613
+ setIsLoading(false);
614
+ });
615
+ return () => {
616
+ isActive = false;
617
+ };
618
+ }, deps);
619
+ return { data, isLoading, error, setData };
620
+ }
621
+
622
+ // src/components/AdminHome.tsx
623
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
624
+ function AdminHome({ client, basePath }) {
625
+ const { data, error, isLoading } = useAdminRequest(() => client.getModels(), [client]);
626
+ if (isLoading) {
627
+ return /* @__PURE__ */ jsx3(Typography, { sx: { p: 3 }, children: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439..." });
628
+ }
629
+ if (error || !data) {
630
+ return /* @__PURE__ */ jsx3(Alert, { severity: "error", children: error || "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043C\u043E\u0434\u0435\u043B\u0438." });
631
+ }
632
+ return /* @__PURE__ */ jsxs3(Stack, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
633
+ /* @__PURE__ */ jsxs3(Paper, { sx: { p: 2.5, borderRadius: "10px", flexShrink: 0 }, children: [
634
+ /* @__PURE__ */ jsx3(Typography, { variant: "h4", sx: { fontWeight: 800 }, children: "\u0410\u0434\u043C\u0438\u043D\u043A\u0430" }),
635
+ /* @__PURE__ */ jsx3(Typography, { color: "text.secondary", children: "\u0412\u0441\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0451\u043D\u043D\u044B\u0435 \u043C\u043E\u0434\u0435\u043B\u0438 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B \u0438 \u0432 \u0441\u0430\u0439\u0434\u0431\u0430\u0440\u0435, \u0438 \u043D\u0430 \u044D\u0442\u043E\u0439 \u0441\u0442\u0430\u0440\u0442\u043E\u0432\u043E\u0439 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0435." })
636
+ ] }),
637
+ /* @__PURE__ */ jsx3(Paper, { sx: { borderRadius: "10px", flex: 1, minHeight: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx3(Box2, { sx: { height: "100%", overflow: "auto", p: 2 }, children: /* @__PURE__ */ jsx3(Grid, { container: true, spacing: 2, children: data.items.map((model) => /* @__PURE__ */ jsx3(Grid, { size: { xs: 12, md: 6, xl: 4 }, children: /* @__PURE__ */ jsx3(Card, { sx: { borderRadius: "10px" }, children: /* @__PURE__ */ jsx3(Link, { href: `${basePath}/${model.slug}`, style: { textDecoration: "none" }, children: /* @__PURE__ */ jsx3(CardActionArea, { children: /* @__PURE__ */ jsxs3(CardContent, { children: [
638
+ /* @__PURE__ */ jsx3(Typography, { variant: "h6", sx: { fontWeight: 700 }, children: model.title }),
639
+ /* @__PURE__ */ jsx3(Typography, { color: "text.secondary", children: model.slug })
640
+ ] }) }) }) }) }, model.slug)) }) }) })
641
+ ] });
642
+ }
643
+
644
+ // src/components/AdminModelPage.tsx
645
+ import Link2 from "next/link.js";
646
+ import { usePathname, useSearchParams } from "next/navigation.js";
647
+ import { memo, useCallback, useEffect as useEffect4, useMemo as useMemo3, useRef, useState as useState4 } from "react";
648
+ import AddIcon from "@mui/icons-material/Add";
649
+ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
650
+ import MoreVertIcon from "@mui/icons-material/MoreVert";
651
+ import {
652
+ Alert as Alert2,
653
+ Box as Box3,
654
+ Button as Button2,
655
+ Checkbox,
656
+ IconButton,
657
+ LinearProgress,
658
+ Menu,
659
+ MenuItem,
660
+ Paper as Paper2,
661
+ Stack as Stack2,
662
+ Table,
663
+ TableBody,
664
+ TableCell,
665
+ TableHead,
666
+ TableRow,
667
+ TableSortLabel,
668
+ TextField as TextField2,
669
+ Typography as Typography2
670
+ } from "@mui/material";
671
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
672
+ var DEFAULT_PAGE_SIZE = 50;
673
+ var SEARCH_DEBOUNCE_MS = 300;
674
+ function AdminModelPage({ client, basePath, slug }) {
675
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
676
+ const pathname = usePathname();
677
+ const searchParams = useSearchParams();
678
+ const [selectedIds, setSelectedIds] = useState4([]);
679
+ const [createOpen, setCreateOpen] = useState4(false);
680
+ const [data, setData] = useState4(null);
681
+ const [modelMeta, setModelMeta] = useState4(null);
682
+ const [error, setError] = useState4(null);
683
+ const [isLoading, setIsLoading] = useState4(true);
684
+ const [isLoadingMore, setIsLoadingMore] = useState4(false);
685
+ const [rowActionMenuAnchor, setRowActionMenuAnchor] = useState4(null);
686
+ const [rowActionMenuId, setRowActionMenuId] = useState4(null);
687
+ const [bulkActionMenuAnchor, setBulkActionMenuAnchor] = useState4(null);
688
+ const [queryInput, setQueryInput] = useState4((_a = searchParams.get("q")) != null ? _a : "");
689
+ const [appliedQuery, setAppliedQuery] = useState4((_b = searchParams.get("q")) != null ? _b : "");
690
+ const [sortValue, setSortValue] = useState4((_c = searchParams.get("sort")) != null ? _c : "");
691
+ const scrollContainerRef = useRef(null);
692
+ const dataRef = useRef(null);
693
+ const requestIdRef = useRef(0);
694
+ const appendOffsetsRef = useRef(/* @__PURE__ */ new Set());
695
+ const isAppendingRef = useRef(false);
696
+ const sortFields = useMemo3(() => sortValue.split(",").filter(Boolean), [sortValue]);
697
+ const meta = (_d = data == null ? void 0 : data.meta) != null ? _d : modelMeta;
698
+ const rows = (_e = data == null ? void 0 : data.items) != null ? _e : [];
699
+ const total = (_f = data == null ? void 0 : data.pagination.total) != null ? _f : 0;
700
+ const pageSize = (_g = meta == null ? void 0 : meta.page_size) != null ? _g : DEFAULT_PAGE_SIZE;
701
+ const fieldMap = useMemo3(
702
+ () => {
703
+ var _a2;
704
+ return new Map(((_a2 = meta == null ? void 0 : meta.fields) != null ? _a2 : []).map((field) => [field.name, field]));
705
+ },
706
+ [meta == null ? void 0 : meta.fields]
707
+ );
708
+ const listFields = (_h = meta == null ? void 0 : meta.list_fields) != null ? _h : [];
709
+ const bulkActions = (_i = meta == null ? void 0 : meta.bulk_actions) != null ? _i : [];
710
+ const selectedIdSet = useMemo3(
711
+ () => new Set(selectedIds.map((item) => String(item))),
712
+ [selectedIds]
713
+ );
714
+ useEffect4(() => {
715
+ dataRef.current = data;
716
+ }, [data]);
717
+ useEffect4(() => {
718
+ let isMounted = true;
719
+ setModelMeta(null);
720
+ client.getModel(slug).then((response) => {
721
+ if (!isMounted) {
722
+ return;
723
+ }
724
+ setModelMeta(response);
725
+ }).catch(() => {
726
+ if (!isMounted) {
727
+ return;
728
+ }
729
+ setModelMeta(null);
730
+ });
731
+ return () => {
732
+ isMounted = false;
733
+ };
734
+ }, [client, slug]);
735
+ useEffect4(() => {
736
+ const timerId = window.setTimeout(() => {
737
+ setAppliedQuery(queryInput);
738
+ replaceUrlParams(pathname, queryInput, sortValue);
739
+ }, SEARCH_DEBOUNCE_MS);
740
+ return () => {
741
+ window.clearTimeout(timerId);
742
+ };
743
+ }, [pathname, queryInput, sortValue]);
744
+ useEffect4(() => {
745
+ const handlePopState = () => {
746
+ var _a2, _b2;
747
+ const params = new URLSearchParams(window.location.search);
748
+ const nextQuery = (_a2 = params.get("q")) != null ? _a2 : "";
749
+ const nextSort = (_b2 = params.get("sort")) != null ? _b2 : "";
750
+ setQueryInput(nextQuery);
751
+ setAppliedQuery(nextQuery);
752
+ setSortValue(nextSort);
753
+ };
754
+ window.addEventListener("popstate", handlePopState);
755
+ return () => {
756
+ window.removeEventListener("popstate", handlePopState);
757
+ };
758
+ }, []);
759
+ const loadItems = useCallback(async (append) => {
760
+ var _a2;
761
+ const currentData = dataRef.current;
762
+ const offset = append ? (_a2 = currentData == null ? void 0 : currentData.items.length) != null ? _a2 : 0 : 0;
763
+ const activeRequestId = append ? requestIdRef.current : requestIdRef.current + 1;
764
+ if (append) {
765
+ if (isAppendingRef.current || appendOffsetsRef.current.has(offset)) {
766
+ return;
767
+ }
768
+ isAppendingRef.current = true;
769
+ appendOffsetsRef.current.add(offset);
770
+ setIsLoadingMore(true);
771
+ } else {
772
+ requestIdRef.current = activeRequestId;
773
+ appendOffsetsRef.current.clear();
774
+ setIsLoading(true);
775
+ setError(null);
776
+ }
777
+ try {
778
+ const response = await client.getItems(slug, {
779
+ q: appliedQuery || void 0,
780
+ sort: sortValue || void 0,
781
+ limit: pageSize,
782
+ offset
783
+ });
784
+ if (activeRequestId !== requestIdRef.current) {
785
+ return;
786
+ }
787
+ setModelMeta(response.meta);
788
+ setData((previousData) => {
789
+ if (!append || !previousData) {
790
+ return response;
791
+ }
792
+ return mergeListResponse(previousData, response);
793
+ });
794
+ if (!append) {
795
+ setSelectedIds([]);
796
+ }
797
+ } catch (reason) {
798
+ setError(reason instanceof Error ? reason.message : "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043C\u043E\u0434\u0435\u043B\u044C.");
799
+ } finally {
800
+ if (append) {
801
+ isAppendingRef.current = false;
802
+ setIsLoadingMore(false);
803
+ } else {
804
+ setIsLoading(false);
805
+ }
806
+ }
807
+ }, [appliedQuery, client, pageSize, slug, sortValue]);
808
+ useEffect4(() => {
809
+ void loadItems(false);
810
+ }, [loadItems]);
811
+ const refresh = useCallback(async () => {
812
+ await loadItems(false);
813
+ }, [loadItems]);
814
+ const toggleSort = useCallback((fieldName) => {
815
+ const nextSortFields = sortFields.filter((item) => item !== fieldName && item !== `-${fieldName}`);
816
+ const currentSort = sortFields.find((item) => item === fieldName || item === `-${fieldName}`);
817
+ if (currentSort === void 0) {
818
+ nextSortFields.unshift(fieldName);
819
+ } else if (currentSort === fieldName) {
820
+ nextSortFields.unshift(`-${fieldName}`);
821
+ } else {
822
+ nextSortFields.unshift(fieldName);
823
+ }
824
+ const nextSortValue = nextSortFields.join(",");
825
+ setSortValue(nextSortValue);
826
+ replaceUrlParams(pathname, queryInput, nextSortValue);
827
+ }, [pathname, queryInput, sortFields]);
828
+ const handleRunNamedBulkAction = useCallback(async (actionSlug) => {
829
+ if (!actionSlug || selectedIds.length === 0) {
830
+ return;
831
+ }
832
+ if (actionSlug === "delete") {
833
+ await client.bulkDelete(slug, selectedIds);
834
+ } else {
835
+ await client.runBulkAction(slug, actionSlug, selectedIds);
836
+ }
837
+ setBulkActionMenuAnchor(null);
838
+ await refresh();
839
+ }, [client, refresh, selectedIds, slug]);
840
+ const handleRowDelete = useCallback(async (rowId) => {
841
+ await client.deleteItem(slug, rowId);
842
+ setRowActionMenuAnchor(null);
843
+ setRowActionMenuId(null);
844
+ await refresh();
845
+ }, [client, refresh, slug]);
846
+ const handleTableScroll = useCallback(async () => {
847
+ const element = scrollContainerRef.current;
848
+ if (!element || isLoading || isLoadingMore || rows.length >= total) {
849
+ return;
850
+ }
851
+ const remainingPixels = element.scrollHeight - element.scrollTop - element.clientHeight;
852
+ if (remainingPixels > 200) {
853
+ return;
854
+ }
855
+ await loadItems(true);
856
+ }, [isLoading, isLoadingMore, loadItems, rows.length, total]);
857
+ const handleToggleSelection = useCallback((rowId, checked) => {
858
+ setSelectedIds((current) => {
859
+ const rowKey = String(rowId);
860
+ if (checked) {
861
+ if (current.some((item) => String(item) === rowKey)) {
862
+ return current;
863
+ }
864
+ return [...current, rowId];
865
+ }
866
+ return current.filter((item) => String(item) !== rowKey);
867
+ });
868
+ }, []);
869
+ const handleOpenRowMenu = useCallback((event, rowId) => {
870
+ setRowActionMenuAnchor(event.currentTarget);
871
+ setRowActionMenuId(rowId);
872
+ }, []);
873
+ if (isLoading && !data) {
874
+ return /* @__PURE__ */ jsx4(Typography2, { sx: { p: 3 }, children: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u0441\u043F\u0438\u0441\u043A\u0430..." });
875
+ }
876
+ if (!isLoading && error && !data) {
877
+ return /* @__PURE__ */ jsx4(Alert2, { severity: "error", children: error });
878
+ }
879
+ if (!data || !meta) {
880
+ return /* @__PURE__ */ jsx4(Typography2, { sx: { p: 3 }, children: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0438..." });
881
+ }
882
+ return /* @__PURE__ */ jsxs4(Stack2, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
883
+ /* @__PURE__ */ jsxs4(
884
+ Paper2,
885
+ {
886
+ sx: {
887
+ p: 2.5,
888
+ borderRadius: "10px",
889
+ flexShrink: 0,
890
+ position: "sticky",
891
+ top: 0,
892
+ zIndex: 3
893
+ },
894
+ children: [
895
+ /* @__PURE__ */ jsx4(Typography2, { variant: "h4", sx: { fontWeight: 800 }, children: meta.title }),
896
+ /* @__PURE__ */ jsxs4(Typography2, { color: "text.secondary", children: [
897
+ meta.slug,
898
+ " \xB7 ",
899
+ total,
900
+ " \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u0432"
901
+ ] })
902
+ ]
903
+ }
904
+ ),
905
+ /* @__PURE__ */ jsx4(
906
+ Paper2,
907
+ {
908
+ sx: {
909
+ p: 1.5,
910
+ borderRadius: "10px",
911
+ flexShrink: 0
912
+ },
913
+ children: /* @__PURE__ */ jsxs4(Stack2, { direction: { xs: "column", lg: "row" }, spacing: 1.5, alignItems: { lg: "center" }, children: [
914
+ /* @__PURE__ */ jsx4(
915
+ TextField2,
916
+ {
917
+ size: "small",
918
+ placeholder: "\u041F\u043E\u0438\u0441\u043A",
919
+ value: queryInput,
920
+ onChange: (event) => setQueryInput(event.target.value),
921
+ sx: { minWidth: { xs: "100%", lg: 360 } }
922
+ }
923
+ ),
924
+ selectedIds.length > 0 && /* @__PURE__ */ jsxs4(Stack2, { direction: "row", spacing: 1, sx: { flex: 1, minWidth: 0 }, children: [
925
+ /* @__PURE__ */ jsx4(
926
+ Button2,
927
+ {
928
+ variant: "outlined",
929
+ endIcon: /* @__PURE__ */ jsx4(ExpandMoreIcon, {}),
930
+ onClick: (event) => setBulkActionMenuAnchor(event.currentTarget),
931
+ children: "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044F"
932
+ }
933
+ ),
934
+ /* @__PURE__ */ jsxs4(Typography2, { color: "text.secondary", sx: { alignSelf: "center" }, children: [
935
+ "\u0412\u044B\u0431\u0440\u0430\u043D\u043E: ",
936
+ selectedIds.length
937
+ ] })
938
+ ] }),
939
+ /* @__PURE__ */ jsx4(Box3, { sx: { marginLeft: "auto" }, children: /* @__PURE__ */ jsx4(Button2, { startIcon: /* @__PURE__ */ jsx4(AddIcon, {}), variant: "contained", onClick: () => setCreateOpen(true), children: "\u0421\u043E\u0437\u0434\u0430\u0442\u044C" }) })
940
+ ] })
941
+ }
942
+ ),
943
+ /* @__PURE__ */ jsx4(
944
+ Paper2,
945
+ {
946
+ sx: {
947
+ borderRadius: "10px",
948
+ flex: 1,
949
+ minHeight: 0,
950
+ overflow: "hidden"
951
+ },
952
+ children: /* @__PURE__ */ jsxs4(
953
+ Box3,
954
+ {
955
+ ref: scrollContainerRef,
956
+ onScroll: () => void handleTableScroll(),
957
+ sx: {
958
+ height: "100%",
959
+ overflow: "auto"
960
+ },
961
+ children: [
962
+ /* @__PURE__ */ jsxs4(Table, { stickyHeader: true, size: "small", children: [
963
+ /* @__PURE__ */ jsx4(TableHead, { children: /* @__PURE__ */ jsxs4(TableRow, { children: [
964
+ /* @__PURE__ */ jsx4(TableCell, { padding: "checkbox", sx: { backgroundColor: "#171719" } }),
965
+ listFields.map((fieldName) => {
966
+ var _a2, _b2;
967
+ const field = fieldMap.get(fieldName);
968
+ const sortDirection = resolveSortDirection(sortFields, fieldName);
969
+ const isSortable = resolveFieldSortable(field);
970
+ return /* @__PURE__ */ jsx4(
971
+ TableCell,
972
+ {
973
+ sortDirection: sortDirection || false,
974
+ sx: {
975
+ backgroundColor: "#171719",
976
+ color: "rgba(255, 255, 255, 0.96)",
977
+ fontWeight: 700,
978
+ cursor: isSortable ? "pointer" : "default",
979
+ userSelect: "none"
980
+ },
981
+ onClick: isSortable ? () => toggleSort(fieldName) : void 0,
982
+ children: isSortable ? /* @__PURE__ */ jsx4(
983
+ TableSortLabel,
984
+ {
985
+ active: Boolean(sortDirection),
986
+ direction: sortDirection != null ? sortDirection : "asc",
987
+ hideSortIcon: false,
988
+ sx: {
989
+ color: "rgba(255, 255, 255, 0.96)",
990
+ "&.Mui-active": {
991
+ color: "rgba(255, 255, 255, 0.96)"
992
+ },
993
+ "& .MuiTableSortLabel-icon": {
994
+ color: "rgba(255, 255, 255, 0.72) !important"
995
+ },
996
+ "&:hover": {
997
+ color: "#ffffff"
998
+ }
999
+ },
1000
+ children: (_a2 = field == null ? void 0 : field.label) != null ? _a2 : fieldName
1001
+ }
1002
+ ) : /* @__PURE__ */ jsx4(Typography2, { component: "span", sx: { fontSize: 14, fontWeight: 700, color: "rgba(255, 255, 255, 0.96)" }, children: (_b2 = field == null ? void 0 : field.label) != null ? _b2 : fieldName })
1003
+ },
1004
+ fieldName
1005
+ );
1006
+ }),
1007
+ /* @__PURE__ */ jsx4(TableCell, { align: "right", sx: { backgroundColor: "#171719", width: 56 } })
1008
+ ] }) }),
1009
+ /* @__PURE__ */ jsx4(TableBody, { children: rows.map((row) => {
1010
+ const rowId = row[meta.pk_field];
1011
+ return /* @__PURE__ */ jsx4(
1012
+ AdminModelRow,
1013
+ {
1014
+ row,
1015
+ pkField: meta.pk_field,
1016
+ listFields,
1017
+ basePath,
1018
+ slug,
1019
+ isSelected: selectedIdSet.has(String(rowId)),
1020
+ onToggleSelection: handleToggleSelection,
1021
+ onOpenMenu: handleOpenRowMenu
1022
+ },
1023
+ String(rowId)
1024
+ );
1025
+ }) })
1026
+ ] }),
1027
+ isLoadingMore && /* @__PURE__ */ jsx4(LinearProgress, {})
1028
+ ]
1029
+ }
1030
+ )
1031
+ }
1032
+ ),
1033
+ /* @__PURE__ */ jsx4(
1034
+ Menu,
1035
+ {
1036
+ anchorEl: bulkActionMenuAnchor,
1037
+ open: Boolean(bulkActionMenuAnchor),
1038
+ onClose: () => setBulkActionMenuAnchor(null),
1039
+ children: bulkActions.map((action) => /* @__PURE__ */ jsx4(MenuItem, { onClick: () => void handleRunNamedBulkAction(action.slug), children: action.label }, action.slug))
1040
+ }
1041
+ ),
1042
+ /* @__PURE__ */ jsx4(
1043
+ Menu,
1044
+ {
1045
+ anchorEl: rowActionMenuAnchor,
1046
+ open: Boolean(rowActionMenuAnchor),
1047
+ onClose: () => {
1048
+ setRowActionMenuAnchor(null);
1049
+ setRowActionMenuId(null);
1050
+ },
1051
+ children: /* @__PURE__ */ jsx4(
1052
+ MenuItem,
1053
+ {
1054
+ onClick: () => {
1055
+ if (rowActionMenuId !== null) {
1056
+ void handleRowDelete(rowActionMenuId);
1057
+ }
1058
+ },
1059
+ children: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C"
1060
+ }
1061
+ )
1062
+ }
1063
+ ),
1064
+ /* @__PURE__ */ jsx4(
1065
+ AdminFormDialog,
1066
+ {
1067
+ open: createOpen,
1068
+ onClose: () => setCreateOpen(false),
1069
+ onSuccess: () => void refresh(),
1070
+ title: `\u0421\u043E\u0437\u0434\u0430\u0442\u044C: ${meta.title}`,
1071
+ slug,
1072
+ mode: "create",
1073
+ meta,
1074
+ client
1075
+ }
1076
+ )
1077
+ ] });
1078
+ }
1079
+ var AdminModelRow = memo(function AdminModelRow2({
1080
+ row,
1081
+ pkField,
1082
+ listFields,
1083
+ basePath,
1084
+ slug,
1085
+ isSelected,
1086
+ onToggleSelection,
1087
+ onOpenMenu
1088
+ }) {
1089
+ const rowId = row[pkField];
1090
+ return /* @__PURE__ */ jsxs4(TableRow, { hover: true, children: [
1091
+ /* @__PURE__ */ jsx4(TableCell, { padding: "checkbox", children: /* @__PURE__ */ jsx4(
1092
+ Checkbox,
1093
+ {
1094
+ checked: isSelected,
1095
+ onChange: (_, checked) => onToggleSelection(rowId, checked)
1096
+ }
1097
+ ) }),
1098
+ listFields.map((fieldName, index) => {
1099
+ const fieldValue = formatAdminValue(row[fieldName]);
1100
+ if (index === 0) {
1101
+ return /* @__PURE__ */ jsx4(TableCell, { children: /* @__PURE__ */ jsx4(Link2, { href: `${basePath}/${slug}/${rowId}`, style: { textDecoration: "none" }, children: fieldValue }) }, fieldName);
1102
+ }
1103
+ return /* @__PURE__ */ jsx4(TableCell, { children: fieldValue }, fieldName);
1104
+ }),
1105
+ /* @__PURE__ */ jsx4(TableCell, { align: "right", children: /* @__PURE__ */ jsx4(IconButton, { size: "small", onClick: (event) => onOpenMenu(event, rowId), children: /* @__PURE__ */ jsx4(MoreVertIcon, { fontSize: "small" }) }) })
1106
+ ] });
1107
+ });
1108
+ function mergeListResponse(previousData, nextData) {
1109
+ const pkField = nextData.meta.pk_field;
1110
+ const itemsById = /* @__PURE__ */ new Map();
1111
+ for (const item of [...previousData.items, ...nextData.items]) {
1112
+ itemsById.set(String(item[pkField]), item);
1113
+ }
1114
+ return {
1115
+ ...nextData,
1116
+ items: [...itemsById.values()]
1117
+ };
1118
+ }
1119
+ function resolveSortDirection(sortFields, fieldName) {
1120
+ if (sortFields.includes(`-${fieldName}`)) {
1121
+ return "desc";
1122
+ }
1123
+ if (sortFields.includes(fieldName)) {
1124
+ return "asc";
1125
+ }
1126
+ return null;
1127
+ }
1128
+ function resolveFieldSortable(field) {
1129
+ if (!field) {
1130
+ return false;
1131
+ }
1132
+ if (field.is_sortable === true) {
1133
+ return true;
1134
+ }
1135
+ if (field.is_sortable === false) {
1136
+ return false;
1137
+ }
1138
+ if (field.is_relation_many || field.input_kind === "relation-multiple") {
1139
+ return false;
1140
+ }
1141
+ if (field.is_virtual) {
1142
+ return false;
1143
+ }
1144
+ return true;
1145
+ }
1146
+ function replaceUrlParams(pathname, query, sort) {
1147
+ const params = new URLSearchParams(window.location.search);
1148
+ if (query) {
1149
+ params.set("q", query);
1150
+ } else {
1151
+ params.delete("q");
1152
+ }
1153
+ if (sort) {
1154
+ params.set("sort", sort);
1155
+ } else {
1156
+ params.delete("sort");
1157
+ }
1158
+ const nextPath = pathname != null ? pathname : window.location.pathname;
1159
+ const nextUrl = params.toString() ? `${nextPath}?${params.toString()}` : nextPath;
1160
+ window.history.replaceState(window.history.state, "", nextUrl);
1161
+ }
1162
+
1163
+ // src/components/AdminObjectPage.tsx
1164
+ import { useEffect as useEffect5, useMemo as useMemo4, useState as useState5 } from "react";
1165
+ import { usePathname as usePathname2, useRouter } from "next/navigation.js";
1166
+ import {
1167
+ Alert as Alert3,
1168
+ Box as Box4,
1169
+ Button as Button3,
1170
+ Dialog as Dialog2,
1171
+ DialogActions as DialogActions2,
1172
+ DialogContent as DialogContent2,
1173
+ DialogTitle as DialogTitle2,
1174
+ Paper as Paper3,
1175
+ Stack as Stack3,
1176
+ TextField as TextField3,
1177
+ Typography as Typography3
1178
+ } from "@mui/material";
1179
+ import { LocalizationProvider as LocalizationProvider2 } from "@mui/x-date-pickers";
1180
+ import { AdapterDayjs as AdapterDayjs2 } from "@mui/x-date-pickers/AdapterDayjs";
1181
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1182
+ function AdminObjectPage({ client, slug, id }) {
1183
+ var _a, _b, _c, _d;
1184
+ const router = useRouter();
1185
+ const pathname = usePathname2();
1186
+ const [data, setData] = useState5(null);
1187
+ const [values, setValues] = useState5({});
1188
+ const [initialValues, setInitialValues] = useState5({});
1189
+ const [error, setError] = useState5(null);
1190
+ const [isLoading, setIsLoading] = useState5(true);
1191
+ const [isSaving, setIsSaving] = useState5(false);
1192
+ const [isDeleting, setIsDeleting] = useState5(false);
1193
+ const [activeActionSlug, setActiveActionSlug] = useState5(null);
1194
+ const [deleteConfirmOpen, setDeleteConfirmOpen] = useState5(false);
1195
+ useEffect5(() => {
1196
+ let isMounted = true;
1197
+ setIsLoading(true);
1198
+ setError(null);
1199
+ client.getItem(slug, id).then((response) => {
1200
+ if (!isMounted) {
1201
+ return;
1202
+ }
1203
+ setData(response);
1204
+ setValues(response.item);
1205
+ setInitialValues(response.item);
1206
+ }).catch((reason) => {
1207
+ if (!isMounted) {
1208
+ return;
1209
+ }
1210
+ setError(reason instanceof Error ? reason.message : "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043E\u0431\u044A\u0435\u043A\u0442.");
1211
+ }).finally(() => {
1212
+ if (!isMounted) {
1213
+ return;
1214
+ }
1215
+ setIsLoading(false);
1216
+ });
1217
+ return () => {
1218
+ isMounted = false;
1219
+ };
1220
+ }, [client, id, slug]);
1221
+ const meta = (_a = data == null ? void 0 : data.meta) != null ? _a : null;
1222
+ const detailFields = (_b = meta == null ? void 0 : meta.detail_fields) != null ? _b : [];
1223
+ const objectActions = (_c = meta == null ? void 0 : meta.object_actions) != null ? _c : [];
1224
+ const fieldMap = useMemo4(
1225
+ () => {
1226
+ var _a2;
1227
+ return new Map(((_a2 = meta == null ? void 0 : meta.fields) != null ? _a2 : []).map((field) => [field.name, field]));
1228
+ },
1229
+ [meta == null ? void 0 : meta.fields]
1230
+ );
1231
+ const editableFields = useMemo4(
1232
+ () => {
1233
+ var _a2;
1234
+ return ((_a2 = meta == null ? void 0 : meta.fields) != null ? _a2 : []).filter((field) => meta == null ? void 0 : meta.update_fields.includes(field.name));
1235
+ },
1236
+ [meta == null ? void 0 : meta.fields, meta == null ? void 0 : meta.update_fields]
1237
+ );
1238
+ const editableFieldNames = useMemo4(
1239
+ () => new Set(editableFields.map((field) => field.name)),
1240
+ [editableFields]
1241
+ );
1242
+ const currentPayload = useMemo4(
1243
+ () => buildAdminPayload(values, editableFields),
1244
+ [editableFields, values]
1245
+ );
1246
+ const initialPayload = useMemo4(
1247
+ () => buildAdminPayload(initialValues, editableFields),
1248
+ [editableFields, initialValues]
1249
+ );
1250
+ const isDirty = useMemo4(
1251
+ () => JSON.stringify(currentPayload) !== JSON.stringify(initialPayload),
1252
+ [currentPayload, initialPayload]
1253
+ );
1254
+ const handleSave = async () => {
1255
+ if (!meta || !isDirty) {
1256
+ return;
1257
+ }
1258
+ setIsSaving(true);
1259
+ setError(null);
1260
+ try {
1261
+ const response = await client.patchItem(slug, id, currentPayload);
1262
+ setData((current) => current ? { ...current, item: response.item } : null);
1263
+ setValues(response.item);
1264
+ setInitialValues(response.item);
1265
+ } catch (reason) {
1266
+ setError(reason instanceof Error ? reason.message : "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u043E\u0431\u044A\u0435\u043A\u0442.");
1267
+ } finally {
1268
+ setIsSaving(false);
1269
+ }
1270
+ };
1271
+ const handleDelete = async () => {
1272
+ setIsDeleting(true);
1273
+ setError(null);
1274
+ try {
1275
+ await client.deleteItem(slug, id);
1276
+ router.push(pathname.split("/").slice(0, -1).join("/"));
1277
+ } catch (reason) {
1278
+ setError(reason instanceof Error ? reason.message : "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u043E\u0431\u044A\u0435\u043A\u0442.");
1279
+ setIsDeleting(false);
1280
+ setDeleteConfirmOpen(false);
1281
+ }
1282
+ };
1283
+ const handleRunObjectAction = async (actionSlug) => {
1284
+ setActiveActionSlug(actionSlug);
1285
+ setError(null);
1286
+ try {
1287
+ const response = await client.runObjectAction(slug, id, actionSlug);
1288
+ setData((current) => current ? { ...current, item: response.item } : null);
1289
+ setValues(response.item);
1290
+ setInitialValues(response.item);
1291
+ } catch (reason) {
1292
+ setError(reason instanceof Error ? reason.message : "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435.");
1293
+ } finally {
1294
+ setActiveActionSlug(null);
1295
+ }
1296
+ };
1297
+ if (isLoading) {
1298
+ return /* @__PURE__ */ jsx5(Typography3, { sx: { p: 3 }, children: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043E\u0431\u044A\u0435\u043A\u0442\u0430..." });
1299
+ }
1300
+ if (error && !data) {
1301
+ return /* @__PURE__ */ jsx5(Alert3, { severity: "error", children: error });
1302
+ }
1303
+ if (!data || !meta) {
1304
+ return /* @__PURE__ */ jsx5(Alert3, { severity: "error", children: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043E\u0431\u044A\u0435\u043A\u0442." });
1305
+ }
1306
+ return /* @__PURE__ */ jsxs5(LocalizationProvider2, { dateAdapter: AdapterDayjs2, children: [
1307
+ /* @__PURE__ */ jsxs5(Stack3, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
1308
+ /* @__PURE__ */ jsxs5(
1309
+ Paper3,
1310
+ {
1311
+ sx: {
1312
+ p: 2.5,
1313
+ borderRadius: "10px",
1314
+ flexShrink: 0,
1315
+ position: "sticky",
1316
+ top: 0,
1317
+ zIndex: 2
1318
+ },
1319
+ children: [
1320
+ /* @__PURE__ */ jsx5(Typography3, { variant: "h4", sx: { fontWeight: 800 }, children: String((_d = data.item._display) != null ? _d : `${meta.title} #${id}`) }),
1321
+ /* @__PURE__ */ jsx5(Typography3, { color: "text.secondary", children: meta.slug }),
1322
+ error && /* @__PURE__ */ jsx5(Alert3, { severity: "error", sx: { mt: 2 }, children: error })
1323
+ ]
1324
+ }
1325
+ ),
1326
+ /* @__PURE__ */ jsxs5(Stack3, { direction: { xs: "column", lg: "row" }, spacing: 1.5, sx: { flex: 1, minHeight: 0, alignItems: "stretch" }, children: [
1327
+ /* @__PURE__ */ jsx5(
1328
+ Paper3,
1329
+ {
1330
+ sx: {
1331
+ borderRadius: "10px",
1332
+ flex: 1,
1333
+ minHeight: 0,
1334
+ overflow: "hidden"
1335
+ },
1336
+ children: /* @__PURE__ */ jsx5(Box4, { sx: { height: "100%", overflow: "auto", p: 2.5 }, children: /* @__PURE__ */ jsx5(Stack3, { spacing: 1.5, children: detailFields.map((fieldName) => {
1337
+ var _a2;
1338
+ const field = fieldMap.get(fieldName);
1339
+ if (!field) {
1340
+ return null;
1341
+ }
1342
+ if (editableFieldNames.has(fieldName)) {
1343
+ return /* @__PURE__ */ jsx5(
1344
+ AdminFieldEditor,
1345
+ {
1346
+ field,
1347
+ value: values[field.name],
1348
+ slug,
1349
+ client,
1350
+ onChange: (nextValue) => {
1351
+ setValues((current) => ({ ...current, [field.name]: nextValue }));
1352
+ }
1353
+ },
1354
+ field.name
1355
+ );
1356
+ }
1357
+ return /* @__PURE__ */ jsx5(
1358
+ TextField3,
1359
+ {
1360
+ label: field.label,
1361
+ value: formatAdminValue(values[field.name]),
1362
+ size: "small",
1363
+ fullWidth: true,
1364
+ disabled: true,
1365
+ helperText: (_a2 = field.help_text) != null ? _a2 : void 0
1366
+ },
1367
+ field.name
1368
+ );
1369
+ }) }) })
1370
+ }
1371
+ ),
1372
+ /* @__PURE__ */ jsx5(
1373
+ Paper3,
1374
+ {
1375
+ sx: {
1376
+ width: { xs: "100%", lg: 280 },
1377
+ flexShrink: 0,
1378
+ borderRadius: "10px",
1379
+ p: 1.5,
1380
+ alignSelf: "flex-start",
1381
+ position: { lg: "sticky" },
1382
+ top: { lg: 0 }
1383
+ },
1384
+ children: /* @__PURE__ */ jsxs5(Stack3, { spacing: 1, children: [
1385
+ /* @__PURE__ */ jsx5(Typography3, { variant: "subtitle2", color: "text.secondary", children: "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044F" }),
1386
+ isDirty && /* @__PURE__ */ jsx5(Button3, { variant: "contained", onClick: handleSave, disabled: isSaving, children: isSaving ? "\u0421\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u0438\u0435..." : "\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C" }),
1387
+ /* @__PURE__ */ jsx5(
1388
+ Button3,
1389
+ {
1390
+ variant: "outlined",
1391
+ color: "error",
1392
+ onClick: () => setDeleteConfirmOpen(true),
1393
+ disabled: isDeleting,
1394
+ children: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C"
1395
+ }
1396
+ ),
1397
+ objectActions.map((action) => /* @__PURE__ */ jsx5(
1398
+ Button3,
1399
+ {
1400
+ variant: "outlined",
1401
+ onClick: () => void handleRunObjectAction(action.slug),
1402
+ disabled: activeActionSlug !== null,
1403
+ children: activeActionSlug === action.slug ? "\u0412\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435..." : action.label
1404
+ },
1405
+ action.slug
1406
+ ))
1407
+ ] })
1408
+ }
1409
+ )
1410
+ ] })
1411
+ ] }),
1412
+ /* @__PURE__ */ jsxs5(Dialog2, { open: deleteConfirmOpen, onClose: () => setDeleteConfirmOpen(false), maxWidth: "xs", fullWidth: true, children: [
1413
+ /* @__PURE__ */ jsx5(DialogTitle2, { children: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u043E\u0431\u044A\u0435\u043A\u0442?" }),
1414
+ /* @__PURE__ */ jsx5(DialogContent2, { children: /* @__PURE__ */ jsx5(Typography3, { color: "text.secondary", children: "\u042D\u0442\u043E \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043D\u0435\u043B\u044C\u0437\u044F \u043E\u0442\u043C\u0435\u043D\u0438\u0442\u044C." }) }),
1415
+ /* @__PURE__ */ jsxs5(DialogActions2, { children: [
1416
+ /* @__PURE__ */ jsx5(Button3, { onClick: () => setDeleteConfirmOpen(false), children: "\u041E\u0442\u043C\u0435\u043D\u0430" }),
1417
+ /* @__PURE__ */ jsx5(Button3, { color: "error", variant: "contained", onClick: () => void handleDelete(), disabled: isDeleting, children: isDeleting ? "\u0423\u0434\u0430\u043B\u0435\u043D\u0438\u0435..." : "\u0423\u0434\u0430\u043B\u0438\u0442\u044C" })
1418
+ ] })
1419
+ ] })
1420
+ ] });
1421
+ }
1422
+
1423
+ // src/components/AdminShell.tsx
1424
+ import { Box as Box6, CssBaseline, GlobalStyles, Stack as Stack5 } from "@mui/material";
1425
+ import { ThemeProvider } from "@mui/material/styles";
1426
+
1427
+ // src/theme/defaultAdminTheme.ts
1428
+ import { createTheme } from "@mui/material/styles";
1429
+ var defaultAdminTheme = createTheme({
1430
+ palette: {
1431
+ mode: "dark",
1432
+ background: {
1433
+ default: "#0a0a0b",
1434
+ paper: "#121214"
1435
+ }
1436
+ },
1437
+ shape: {
1438
+ borderRadius: 8
1439
+ },
1440
+ components: {
1441
+ MuiPaper: {
1442
+ styleOverrides: {
1443
+ root: ({ theme }) => ({
1444
+ backgroundImage: "none",
1445
+ borderRadius: 10,
1446
+ backgroundColor: theme.palette.background.paper
1447
+ })
1448
+ }
1449
+ },
1450
+ MuiCard: {
1451
+ styleOverrides: {
1452
+ root: ({ theme }) => ({
1453
+ backgroundImage: "none",
1454
+ borderRadius: 10,
1455
+ backgroundColor: "#18181b",
1456
+ border: `1px solid ${theme.palette.divider}`
1457
+ })
1458
+ }
1459
+ },
1460
+ MuiListItemButton: {
1461
+ styleOverrides: {
1462
+ root: ({ theme }) => ({
1463
+ borderRadius: 8,
1464
+ backgroundColor: "rgba(255, 255, 255, 0.025)",
1465
+ transition: "background-color 0.15s ease",
1466
+ "&:hover": {
1467
+ backgroundColor: "rgba(255, 255, 255, 0.05)"
1468
+ },
1469
+ "& .MuiListItemText-secondary": {
1470
+ color: theme.palette.text.secondary
1471
+ }
1472
+ })
1473
+ }
1474
+ },
1475
+ MuiMenu: {
1476
+ styleOverrides: {
1477
+ paper: ({ theme }) => ({
1478
+ borderRadius: 10,
1479
+ backgroundImage: "none",
1480
+ backgroundColor: theme.palette.background.paper
1481
+ })
1482
+ }
1483
+ },
1484
+ MuiMenuItem: {
1485
+ styleOverrides: {
1486
+ root: {
1487
+ minHeight: 36,
1488
+ fontSize: 14
1489
+ }
1490
+ }
1491
+ },
1492
+ MuiTextField: {
1493
+ defaultProps: {
1494
+ size: "small"
1495
+ }
1496
+ },
1497
+ MuiFormControl: {
1498
+ defaultProps: {
1499
+ size: "small"
1500
+ }
1501
+ },
1502
+ MuiButton: {
1503
+ defaultProps: {
1504
+ size: "small"
1505
+ }
1506
+ },
1507
+ MuiOutlinedInput: {
1508
+ styleOverrides: {
1509
+ root: ({ theme }) => ({
1510
+ transition: theme.transitions.create(["border-color", "box-shadow", "background-color"], {
1511
+ duration: theme.transitions.duration.shorter
1512
+ }),
1513
+ "& .MuiOutlinedInput-notchedOutline": {
1514
+ transition: theme.transitions.create(["border-color", "box-shadow"], {
1515
+ duration: theme.transitions.duration.shorter
1516
+ })
1517
+ },
1518
+ "&:hover .MuiOutlinedInput-notchedOutline": {
1519
+ borderColor: "rgba(255, 255, 255, 0.28)"
1520
+ },
1521
+ "&.Mui-focused .MuiOutlinedInput-notchedOutline": {
1522
+ borderColor: "rgba(255, 255, 255, 0.42)",
1523
+ boxShadow: "0 0 0 1px rgba(255, 255, 255, 0.08)"
1524
+ }
1525
+ })
1526
+ }
1527
+ },
1528
+ MuiInputLabel: {
1529
+ styleOverrides: {
1530
+ root: ({ theme }) => ({
1531
+ transition: theme.transitions.create(["color", "transform"], {
1532
+ duration: theme.transitions.duration.shorter
1533
+ })
1534
+ })
1535
+ }
1536
+ },
1537
+ MuiTableCell: {
1538
+ styleOverrides: {
1539
+ stickyHeader: {
1540
+ backgroundColor: "#171719",
1541
+ backgroundImage: "none"
1542
+ }
1543
+ }
1544
+ }
1545
+ }
1546
+ });
1547
+
1548
+ // src/components/AdminSidebar.tsx
1549
+ import Link3 from "next/link.js";
1550
+ import { Box as Box5, List, ListItemButton, ListItemText, Paper as Paper4, Stack as Stack4, Typography as Typography4 } from "@mui/material";
1551
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1552
+ function AdminSidebar({ models, basePath }) {
1553
+ return /* @__PURE__ */ jsx6(
1554
+ Paper4,
1555
+ {
1556
+ sx: {
1557
+ p: 2,
1558
+ borderRadius: "10px",
1559
+ height: "100%",
1560
+ overflow: "hidden"
1561
+ },
1562
+ children: /* @__PURE__ */ jsxs6(Box5, { sx: { height: "100%", overflow: "auto", pr: 0.5 }, children: [
1563
+ /* @__PURE__ */ jsx6(Typography4, { variant: "h6", sx: { mb: 2, fontWeight: 700 }, children: "XLAdmin" }),
1564
+ /* @__PURE__ */ jsxs6(Stack4, { spacing: 1, children: [
1565
+ /* @__PURE__ */ jsx6(Link3, { href: basePath, style: { textDecoration: "none" }, children: /* @__PURE__ */ jsx6(ListItemButton, { sx: { borderRadius: "8px", backgroundColor: "rgba(255, 255, 255, 0.035)" }, children: /* @__PURE__ */ jsx6(ListItemText, { primary: "\u0412\u0441\u0435 \u043C\u043E\u0434\u0435\u043B\u0438" }) }) }),
1566
+ /* @__PURE__ */ jsx6(List, { dense: true, disablePadding: true, sx: { display: "flex", flexDirection: "column", gap: 1 }, children: models.map((model) => /* @__PURE__ */ jsx6(Link3, { href: `${basePath}/${model.slug}`, style: { textDecoration: "none" }, children: /* @__PURE__ */ jsx6(ListItemButton, { sx: { borderRadius: "8px" }, children: /* @__PURE__ */ jsx6(ListItemText, { primary: model.title, secondary: model.slug }) }) }, model.slug)) })
1567
+ ] })
1568
+ ] })
1569
+ }
1570
+ );
1571
+ }
1572
+
1573
+ // src/components/AdminShell.tsx
1574
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1575
+ function AdminShell({ client, models, basePath, children, theme }) {
1576
+ void client;
1577
+ return /* @__PURE__ */ jsxs7(ThemeProvider, { theme: theme != null ? theme : defaultAdminTheme, children: [
1578
+ /* @__PURE__ */ jsx7(CssBaseline, {}),
1579
+ /* @__PURE__ */ jsx7(
1580
+ GlobalStyles,
1581
+ {
1582
+ styles: (theme2) => ({
1583
+ "html, body": {
1584
+ backgroundColor: theme2.palette.background.default,
1585
+ backgroundImage: "none"
1586
+ },
1587
+ "*": {
1588
+ scrollbarWidth: "thin",
1589
+ scrollbarColor: "#35353a transparent"
1590
+ },
1591
+ "*::-webkit-scrollbar": {
1592
+ width: "3px",
1593
+ height: "3px"
1594
+ },
1595
+ "*::-webkit-scrollbar-track": {
1596
+ background: "transparent"
1597
+ },
1598
+ "*::-webkit-scrollbar-thumb": {
1599
+ backgroundColor: "#35353a",
1600
+ borderRadius: "999px"
1601
+ },
1602
+ '[data-xladmin-root="true"]': {
1603
+ backgroundColor: theme2.palette.background.default,
1604
+ backgroundImage: "none"
1605
+ },
1606
+ '[data-xladmin-root="true"] .MuiAutocomplete-popper .MuiPaper-root, [data-xladmin-root="true"] .MuiMenu-paper, [data-xladmin-root="true"] .MuiPopover-paper, [data-xladmin-root="true"] .MuiPickersPopper-root .MuiPaper-root': {
1607
+ backgroundImage: "none",
1608
+ backgroundColor: theme2.palette.background.paper,
1609
+ borderRadius: "10px"
1610
+ },
1611
+ '[data-xladmin-root="true"] .MuiMenuItem-root': {
1612
+ minHeight: "36px",
1613
+ fontSize: "14px"
1614
+ }
1615
+ })
1616
+ }
1617
+ ),
1618
+ /* @__PURE__ */ jsx7(
1619
+ Box6,
1620
+ {
1621
+ "data-xladmin-root": "true",
1622
+ sx: {
1623
+ height: "100dvh",
1624
+ overflow: "hidden",
1625
+ boxSizing: "border-box",
1626
+ p: 2,
1627
+ backgroundColor: "background.default",
1628
+ backgroundImage: "none"
1629
+ },
1630
+ children: /* @__PURE__ */ jsxs7(
1631
+ Stack5,
1632
+ {
1633
+ direction: { xs: "column", lg: "row" },
1634
+ spacing: 2,
1635
+ sx: { height: "100%", minHeight: 0, alignItems: "stretch" },
1636
+ children: [
1637
+ /* @__PURE__ */ jsx7(Box6, { sx: { width: { xs: "100%", lg: 320 }, flexShrink: 0, minHeight: 0 }, children: /* @__PURE__ */ jsx7(AdminSidebar, { models, basePath }) }),
1638
+ /* @__PURE__ */ jsx7(
1639
+ Box6,
1640
+ {
1641
+ sx: {
1642
+ flex: 1,
1643
+ minWidth: 0,
1644
+ minHeight: 0,
1645
+ display: "flex",
1646
+ flexDirection: "column"
1647
+ },
1648
+ children
1649
+ }
1650
+ )
1651
+ ]
1652
+ }
1653
+ )
1654
+ }
1655
+ )
1656
+ ] });
1657
+ }
1658
+ export {
1659
+ AdminFormDialog,
1660
+ AdminHome,
1661
+ AdminModelPage,
1662
+ AdminObjectPage,
1663
+ AdminShell,
1664
+ AdminSidebar,
1665
+ createAxiosXLAdminClient,
1666
+ createFetchXLAdminClient,
1667
+ createFetchXLAdminTransport,
1668
+ createXLAdminClient,
1669
+ defaultAdminTheme
1670
+ };