xladmin 0.1.8 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -45
- package/dist/cache.d.ts +22 -0
- package/dist/client.d.ts +9 -6
- package/dist/components/FieldEditor.d.ts +2 -2
- package/dist/components/ModelPage.d.ts +3 -1
- package/dist/components/NavLink.d.ts +3 -1
- package/dist/components/ObjectPage.d.ts +3 -1
- package/dist/components/Shell.d.ts +3 -1
- package/dist/components/layout/AdminDataContext.d.ts +1 -1
- package/dist/components/layout/Sidebar.d.ts +1 -1
- package/dist/components/model-page/ListFiltersBar.d.ts +2 -2
- package/dist/components/model-page/ListRow.d.ts +1 -1
- package/dist/components/model-page/useModelPageController.d.ts +73 -0
- package/dist/components/models-blocks/types.d.ts +1 -1
- package/dist/components/object-page/ObjectField.d.ts +2 -2
- package/dist/components/object-page/ReadonlyObjectField.d.ts +1 -1
- package/dist/components/object-page/useObjectPageController.d.ts +46 -0
- package/dist/hooks/useRemoteChoices.d.ts +15 -0
- package/dist/i18n.d.ts +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1472 -943
- package/dist/router.d.ts +35 -0
- package/dist/utils/adminFields.d.ts +1 -1
- package/dist/utils/isDeepEqual.d.ts +1 -0
- package/package.json +9 -25
package/dist/index.js
CHANGED
|
@@ -45,11 +45,12 @@ function createXLAdminClient(transport) {
|
|
|
45
45
|
payload != null ? payload : {}
|
|
46
46
|
);
|
|
47
47
|
},
|
|
48
|
-
async getChoices(slug, fieldName, q, ids) {
|
|
48
|
+
async getChoices(slug, fieldName, q, ids, options) {
|
|
49
49
|
return await transportGet(
|
|
50
50
|
transport,
|
|
51
51
|
`/xladmin/models/${slug}/fields/${fieldName}/choices/`,
|
|
52
52
|
{
|
|
53
|
+
signal: options == null ? void 0 : options.signal,
|
|
53
54
|
params: {
|
|
54
55
|
...q ? { q } : {},
|
|
55
56
|
...ids && ids.length > 0 ? { ids: ids.join(",") } : {}
|
|
@@ -57,11 +58,12 @@ function createXLAdminClient(transport) {
|
|
|
57
58
|
}
|
|
58
59
|
);
|
|
59
60
|
},
|
|
60
|
-
async getFilterChoices(slug, filterSlug, q, ids) {
|
|
61
|
+
async getFilterChoices(slug, filterSlug, q, ids, options) {
|
|
61
62
|
return await transportGet(
|
|
62
63
|
transport,
|
|
63
64
|
`/xladmin/models/${slug}/filters/${filterSlug}/choices/`,
|
|
64
65
|
{
|
|
66
|
+
signal: options == null ? void 0 : options.signal,
|
|
65
67
|
params: {
|
|
66
68
|
...q ? { q } : {},
|
|
67
69
|
...ids && ids.length > 0 ? { ids: ids.join(",") } : {}
|
|
@@ -84,22 +86,22 @@ function createFetchXLAdminTransport(config) {
|
|
|
84
86
|
throw new Error("Fetch API is not available in the current environment.");
|
|
85
87
|
}
|
|
86
88
|
return {
|
|
87
|
-
get: async (url, options) => await requestJson(fetchImpl, config, "GET", url, void 0, options == null ? void 0 : options.params),
|
|
88
|
-
post: async (url, body) => await requestJson(fetchImpl, config, "POST", url, body),
|
|
89
|
-
patch: async (url, body) => await requestJson(fetchImpl, config, "PATCH", url, body),
|
|
90
|
-
delete: async (url) => {
|
|
91
|
-
await requestRaw(fetchImpl, config, "DELETE", url);
|
|
89
|
+
get: async (url, options) => await requestJson(fetchImpl, config, "GET", url, void 0, options == null ? void 0 : options.params, options == null ? void 0 : options.signal),
|
|
90
|
+
post: async (url, body, options) => await requestJson(fetchImpl, config, "POST", url, body, void 0, options == null ? void 0 : options.signal),
|
|
91
|
+
patch: async (url, body, options) => await requestJson(fetchImpl, config, "PATCH", url, body, void 0, options == null ? void 0 : options.signal),
|
|
92
|
+
delete: async (url, options) => {
|
|
93
|
+
await requestRaw(fetchImpl, config, "DELETE", url, void 0, void 0, options == null ? void 0 : options.signal);
|
|
92
94
|
}
|
|
93
95
|
};
|
|
94
96
|
}
|
|
95
97
|
async function transportGet(transport, url, options) {
|
|
96
98
|
return unwrapTransportResponse(await transport.get(url, options));
|
|
97
99
|
}
|
|
98
|
-
async function transportPost(transport, url, body) {
|
|
99
|
-
return unwrapTransportResponse(await transport.post(url, body));
|
|
100
|
+
async function transportPost(transport, url, body, options) {
|
|
101
|
+
return unwrapTransportResponse(await transport.post(url, body, options));
|
|
100
102
|
}
|
|
101
|
-
async function transportPatch(transport, url, body) {
|
|
102
|
-
return unwrapTransportResponse(await transport.patch(url, body));
|
|
103
|
+
async function transportPatch(transport, url, body, options) {
|
|
104
|
+
return unwrapTransportResponse(await transport.patch(url, body, options));
|
|
103
105
|
}
|
|
104
106
|
function unwrapTransportResponse(response) {
|
|
105
107
|
if (isWrappedTransportResponse(response)) {
|
|
@@ -110,15 +112,16 @@ function unwrapTransportResponse(response) {
|
|
|
110
112
|
function isWrappedTransportResponse(response) {
|
|
111
113
|
return typeof response === "object" && response !== null && "data" in response;
|
|
112
114
|
}
|
|
113
|
-
async function requestJson(fetchImpl, config, method, url, body, params) {
|
|
114
|
-
const response = await requestRaw(fetchImpl, config, method, url, body, params);
|
|
115
|
+
async function requestJson(fetchImpl, config, method, url, body, params, signal) {
|
|
116
|
+
const response = await requestRaw(fetchImpl, config, method, url, body, params, signal);
|
|
115
117
|
return await response.json();
|
|
116
118
|
}
|
|
117
|
-
async function requestRaw(fetchImpl, config, method, url, body, params) {
|
|
119
|
+
async function requestRaw(fetchImpl, config, method, url, body, params, signal) {
|
|
118
120
|
var _a;
|
|
119
121
|
const headers = await resolveHeaders(config.headers);
|
|
120
122
|
const response = await fetchImpl(buildRequestUrl(config.baseUrl, url, params), {
|
|
121
123
|
method,
|
|
124
|
+
signal,
|
|
122
125
|
credentials: (_a = config.credentials) != null ? _a : "include",
|
|
123
126
|
headers: {
|
|
124
127
|
"Content-Type": "application/json",
|
|
@@ -134,6 +137,10 @@ async function requestRaw(fetchImpl, config, method, url, body, params) {
|
|
|
134
137
|
detail = errorData.detail;
|
|
135
138
|
}
|
|
136
139
|
} catch {
|
|
140
|
+
const fallbackText = await response.text().catch(() => "");
|
|
141
|
+
if (fallbackText.trim()) {
|
|
142
|
+
detail = fallbackText.trim();
|
|
143
|
+
}
|
|
137
144
|
}
|
|
138
145
|
throw new Error(detail);
|
|
139
146
|
}
|
|
@@ -175,9 +182,104 @@ function buildSearchParams(params) {
|
|
|
175
182
|
return searchParams.toString();
|
|
176
183
|
}
|
|
177
184
|
|
|
185
|
+
// src/router.tsx
|
|
186
|
+
import { createContext, useContext, useMemo, useRef, useSyncExternalStore } from "react";
|
|
187
|
+
import { jsx } from "react/jsx-runtime";
|
|
188
|
+
var XLAdminRouterContext = createContext(null);
|
|
189
|
+
var browserRouterInstance = null;
|
|
190
|
+
function XLAdminRouterProvider({ router, children }) {
|
|
191
|
+
return /* @__PURE__ */ jsx(XLAdminRouterContext.Provider, { value: router, children });
|
|
192
|
+
}
|
|
193
|
+
function createBrowserXLAdminRouter(browserWindow = window) {
|
|
194
|
+
return {
|
|
195
|
+
getLocation: () => ({
|
|
196
|
+
pathname: browserWindow.location.pathname,
|
|
197
|
+
search: browserWindow.location.search
|
|
198
|
+
}),
|
|
199
|
+
subscribe: (listener) => {
|
|
200
|
+
const handlePopState = () => listener();
|
|
201
|
+
browserWindow.addEventListener("popstate", handlePopState);
|
|
202
|
+
return () => {
|
|
203
|
+
browserWindow.removeEventListener("popstate", handlePopState);
|
|
204
|
+
};
|
|
205
|
+
},
|
|
206
|
+
push: (href) => {
|
|
207
|
+
browserWindow.history.pushState(browserWindow.history.state, "", href);
|
|
208
|
+
browserWindow.dispatchEvent(new PopStateEvent("popstate"));
|
|
209
|
+
},
|
|
210
|
+
replace: (href) => {
|
|
211
|
+
browserWindow.history.replaceState(browserWindow.history.state, "", href);
|
|
212
|
+
browserWindow.dispatchEvent(new PopStateEvent("popstate"));
|
|
213
|
+
},
|
|
214
|
+
back: () => {
|
|
215
|
+
browserWindow.history.back();
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function useXLAdminRouter(router) {
|
|
220
|
+
const contextRouter = useContext(XLAdminRouterContext);
|
|
221
|
+
return useMemo(() => {
|
|
222
|
+
if (router) {
|
|
223
|
+
return router;
|
|
224
|
+
}
|
|
225
|
+
if (contextRouter) {
|
|
226
|
+
return contextRouter;
|
|
227
|
+
}
|
|
228
|
+
if (browserRouterInstance === null) {
|
|
229
|
+
browserRouterInstance = createBrowserXLAdminRouter();
|
|
230
|
+
}
|
|
231
|
+
return browserRouterInstance;
|
|
232
|
+
}, [contextRouter, router]);
|
|
233
|
+
}
|
|
234
|
+
function useXLAdminLocation(router) {
|
|
235
|
+
const resolvedRouter = useXLAdminRouter(router);
|
|
236
|
+
const snapshotRef = useRef(null);
|
|
237
|
+
const getSnapshot = useMemo(() => () => {
|
|
238
|
+
const nextLocation = resolvedRouter.getLocation();
|
|
239
|
+
const cachedLocation = snapshotRef.current;
|
|
240
|
+
if (cachedLocation !== null && cachedLocation.pathname === nextLocation.pathname && cachedLocation.search === nextLocation.search) {
|
|
241
|
+
return cachedLocation;
|
|
242
|
+
}
|
|
243
|
+
snapshotRef.current = nextLocation;
|
|
244
|
+
return nextLocation;
|
|
245
|
+
}, [resolvedRouter]);
|
|
246
|
+
return useSyncExternalStore(
|
|
247
|
+
resolvedRouter.subscribe,
|
|
248
|
+
getSnapshot,
|
|
249
|
+
getSnapshot
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
function buildUrlWithParams(pathname, query, sort, page, filters) {
|
|
253
|
+
const params = new URLSearchParams();
|
|
254
|
+
if (query) {
|
|
255
|
+
params.set("q", query);
|
|
256
|
+
}
|
|
257
|
+
if (sort) {
|
|
258
|
+
params.set("sort", sort);
|
|
259
|
+
}
|
|
260
|
+
if (page > 1) {
|
|
261
|
+
params.set("page", String(page));
|
|
262
|
+
}
|
|
263
|
+
for (const [key, value] of Object.entries(filters)) {
|
|
264
|
+
if (value) {
|
|
265
|
+
params.set(key, value);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return params.toString() ? `${pathname}?${params.toString()}` : pathname;
|
|
269
|
+
}
|
|
270
|
+
function handleNavLinkClick(event, { href, onClick, router }) {
|
|
271
|
+
onClick == null ? void 0 : onClick();
|
|
272
|
+
if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
event.preventDefault();
|
|
276
|
+
router.push(href);
|
|
277
|
+
}
|
|
278
|
+
|
|
178
279
|
// src/components/FormDialog.tsx
|
|
179
|
-
import { useEffect as
|
|
280
|
+
import { useEffect as useEffect3, useMemo as useMemo4, useState as useState3 } from "react";
|
|
180
281
|
import {
|
|
282
|
+
Alert,
|
|
181
283
|
Box,
|
|
182
284
|
Button,
|
|
183
285
|
Dialog,
|
|
@@ -189,8 +291,8 @@ import { LocalizationProvider } from "@mui/x-date-pickers";
|
|
|
189
291
|
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
|
|
190
292
|
|
|
191
293
|
// src/i18n.tsx
|
|
192
|
-
import { createContext, useContext, useMemo } from "react";
|
|
193
|
-
import { jsx } from "react/jsx-runtime";
|
|
294
|
+
import { createContext as createContext2, useContext as useContext2, useMemo as useMemo2 } from "react";
|
|
295
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
194
296
|
var messages = {
|
|
195
297
|
ru: {
|
|
196
298
|
admin_title: "Admin",
|
|
@@ -301,7 +403,7 @@ var messages = {
|
|
|
301
403
|
staff_only: "Only staff users can access the admin."
|
|
302
404
|
}
|
|
303
405
|
};
|
|
304
|
-
var AdminLocaleContext =
|
|
406
|
+
var AdminLocaleContext = createContext2("ru");
|
|
305
407
|
function normalizeAdminLocale(locale) {
|
|
306
408
|
return locale === "en" ? "en" : "ru";
|
|
307
409
|
}
|
|
@@ -314,15 +416,15 @@ function translateAdmin(locale, key, params) {
|
|
|
314
416
|
});
|
|
315
417
|
}
|
|
316
418
|
function AdminLocaleProvider({ locale, children }) {
|
|
317
|
-
const normalizedLocale =
|
|
318
|
-
return /* @__PURE__ */
|
|
419
|
+
const normalizedLocale = useMemo2(() => normalizeAdminLocale(locale), [locale]);
|
|
420
|
+
return /* @__PURE__ */ jsx2(AdminLocaleContext.Provider, { value: normalizedLocale, children });
|
|
319
421
|
}
|
|
320
422
|
function useAdminLocale() {
|
|
321
|
-
return normalizeAdminLocale(
|
|
423
|
+
return normalizeAdminLocale(useContext2(AdminLocaleContext));
|
|
322
424
|
}
|
|
323
425
|
function useAdminTranslation() {
|
|
324
426
|
const locale = useAdminLocale();
|
|
325
|
-
return
|
|
427
|
+
return useMemo2(() => ((key, params) => translateAdmin(locale, key, params)), [locale]);
|
|
326
428
|
}
|
|
327
429
|
|
|
328
430
|
// src/utils/adminFields.ts
|
|
@@ -475,7 +577,7 @@ function trimAdminValue(value, maxLength) {
|
|
|
475
577
|
}
|
|
476
578
|
|
|
477
579
|
// src/components/FieldEditor.tsx
|
|
478
|
-
import { memo, useEffect, useMemo as
|
|
580
|
+
import { memo, useCallback, useEffect as useEffect2, useMemo as useMemo3, useState as useState2 } from "react";
|
|
479
581
|
import {
|
|
480
582
|
Autocomplete,
|
|
481
583
|
CircularProgress,
|
|
@@ -485,7 +587,93 @@ import {
|
|
|
485
587
|
} from "@mui/material";
|
|
486
588
|
import { DatePicker, DateTimePicker } from "@mui/x-date-pickers";
|
|
487
589
|
import dayjs from "dayjs";
|
|
488
|
-
|
|
590
|
+
|
|
591
|
+
// src/hooks/useRemoteChoices.ts
|
|
592
|
+
import { useEffect, useRef as useRef2, useState } from "react";
|
|
593
|
+
function useRemoteChoices({
|
|
594
|
+
enabled,
|
|
595
|
+
debounceMs = 250,
|
|
596
|
+
initialItems = [],
|
|
597
|
+
resetKey,
|
|
598
|
+
queryKey,
|
|
599
|
+
load,
|
|
600
|
+
merge
|
|
601
|
+
}) {
|
|
602
|
+
const [items, setItems] = useState(initialItems);
|
|
603
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
604
|
+
const previousResetKeyRef = useRef2(resetKey);
|
|
605
|
+
useEffect(() => {
|
|
606
|
+
if (previousResetKeyRef.current !== resetKey) {
|
|
607
|
+
previousResetKeyRef.current = resetKey;
|
|
608
|
+
setItems(initialItems);
|
|
609
|
+
setIsLoading(false);
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
setItems((currentItems) => {
|
|
613
|
+
if (areChoiceArraysShallowEqual(currentItems, initialItems)) {
|
|
614
|
+
return currentItems;
|
|
615
|
+
}
|
|
616
|
+
if (currentItems.length > 0 && initialItems.length === 0) {
|
|
617
|
+
return currentItems;
|
|
618
|
+
}
|
|
619
|
+
return initialItems;
|
|
620
|
+
});
|
|
621
|
+
}, [initialItems, resetKey]);
|
|
622
|
+
useEffect(() => {
|
|
623
|
+
if (!enabled) {
|
|
624
|
+
setIsLoading(false);
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
const controller = new AbortController();
|
|
628
|
+
const timeoutId = window.setTimeout(() => {
|
|
629
|
+
setIsLoading(true);
|
|
630
|
+
load(controller.signal).then((nextItems) => {
|
|
631
|
+
if (controller.signal.aborted) {
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
setItems((current) => merge ? merge(current, nextItems) : nextItems);
|
|
635
|
+
}).catch((reason) => {
|
|
636
|
+
if (isAbortReason(reason) || controller.signal.aborted) {
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
setItems((current) => current);
|
|
640
|
+
}).finally(() => {
|
|
641
|
+
if (controller.signal.aborted) {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
setIsLoading(false);
|
|
645
|
+
});
|
|
646
|
+
}, debounceMs);
|
|
647
|
+
return () => {
|
|
648
|
+
controller.abort();
|
|
649
|
+
window.clearTimeout(timeoutId);
|
|
650
|
+
};
|
|
651
|
+
}, [debounceMs, enabled, load, merge, queryKey]);
|
|
652
|
+
return { items, isLoading };
|
|
653
|
+
}
|
|
654
|
+
function areChoiceArraysShallowEqual(left, right) {
|
|
655
|
+
if (left === right) {
|
|
656
|
+
return true;
|
|
657
|
+
}
|
|
658
|
+
if (left.length !== right.length) {
|
|
659
|
+
return false;
|
|
660
|
+
}
|
|
661
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
662
|
+
if (!Object.is(left[index], right[index])) {
|
|
663
|
+
return false;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
return true;
|
|
667
|
+
}
|
|
668
|
+
function isAbortReason(reason) {
|
|
669
|
+
if (reason instanceof DOMException && reason.name === "AbortError") {
|
|
670
|
+
return true;
|
|
671
|
+
}
|
|
672
|
+
return typeof reason === "object" && reason !== null && "name" in reason && reason.name === "AbortError";
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// src/components/FieldEditor.tsx
|
|
676
|
+
import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
489
677
|
var FieldEditor = memo(function FieldEditor2({
|
|
490
678
|
field,
|
|
491
679
|
value,
|
|
@@ -496,45 +684,44 @@ var FieldEditor = memo(function FieldEditor2({
|
|
|
496
684
|
}) {
|
|
497
685
|
var _a, _b, _c, _d;
|
|
498
686
|
const t = useAdminTranslation();
|
|
499
|
-
const [
|
|
500
|
-
const [
|
|
501
|
-
const [
|
|
502
|
-
const
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
|
|
687
|
+
const [searchValue, setSearchValue] = useState2("");
|
|
688
|
+
const [jsonTextValue, setJsonTextValue] = useState2(() => stringifyJsonValue(value));
|
|
689
|
+
const [jsonError, setJsonError] = useState2(null);
|
|
690
|
+
const selectedIds = useMemo3(() => normalizeSelectedIds(value, field.is_relation_many), [field.is_relation_many, value]);
|
|
691
|
+
const loadChoices = useCallback(
|
|
692
|
+
async (signal) => {
|
|
693
|
+
const response = await client.getChoices(
|
|
694
|
+
slug,
|
|
695
|
+
field.name,
|
|
696
|
+
searchValue || void 0,
|
|
697
|
+
selectedIds,
|
|
698
|
+
{ signal }
|
|
699
|
+
);
|
|
700
|
+
return response.items;
|
|
701
|
+
},
|
|
702
|
+
[client, field.name, searchValue, selectedIds, slug]
|
|
703
|
+
);
|
|
704
|
+
const { items: choices, isLoading: isLoadingChoices } = useRemoteChoices({
|
|
705
|
+
enabled: field.has_choices,
|
|
706
|
+
debounceMs: 250,
|
|
707
|
+
initialItems: [],
|
|
708
|
+
resetKey: `${slug}:${field.name}`,
|
|
709
|
+
queryKey: `${slug}:${field.name}:${searchValue}:${selectedIds.join(",")}`,
|
|
710
|
+
load: loadChoices,
|
|
711
|
+
merge: mergeChoices
|
|
712
|
+
});
|
|
713
|
+
useEffect2(() => {
|
|
506
714
|
if (field.input_kind !== "json") {
|
|
507
715
|
return;
|
|
508
716
|
}
|
|
509
717
|
setJsonTextValue(stringifyJsonValue(value));
|
|
510
718
|
setJsonError(null);
|
|
511
719
|
}, [field.input_kind, value]);
|
|
512
|
-
useEffect(() => {
|
|
513
|
-
if (!field.has_choices) {
|
|
514
|
-
setChoices([]);
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
|
-
let isMounted = true;
|
|
518
|
-
setIsLoadingChoices(true);
|
|
519
|
-
client.getChoices(slug, field.name, searchValue || void 0, selectedIds).then((response) => {
|
|
520
|
-
if (!isMounted) return;
|
|
521
|
-
setChoices((current) => mergeChoices(current, response.items));
|
|
522
|
-
}).catch(() => {
|
|
523
|
-
if (!isMounted) return;
|
|
524
|
-
setChoices((current) => current);
|
|
525
|
-
}).finally(() => {
|
|
526
|
-
if (!isMounted) return;
|
|
527
|
-
setIsLoadingChoices(false);
|
|
528
|
-
});
|
|
529
|
-
return () => {
|
|
530
|
-
isMounted = false;
|
|
531
|
-
};
|
|
532
|
-
}, [client, field.has_choices, field.name, searchValue, selectedIds, slug]);
|
|
533
720
|
if (field.input_kind === "boolean") {
|
|
534
|
-
return /* @__PURE__ */
|
|
721
|
+
return /* @__PURE__ */ jsx3(
|
|
535
722
|
FormControlLabel,
|
|
536
723
|
{
|
|
537
|
-
control: /* @__PURE__ */
|
|
724
|
+
control: /* @__PURE__ */ jsx3(
|
|
538
725
|
Switch,
|
|
539
726
|
{
|
|
540
727
|
checked: Boolean(value),
|
|
@@ -547,7 +734,7 @@ var FieldEditor = memo(function FieldEditor2({
|
|
|
547
734
|
);
|
|
548
735
|
}
|
|
549
736
|
if (field.input_kind === "date") {
|
|
550
|
-
return /* @__PURE__ */
|
|
737
|
+
return /* @__PURE__ */ jsx3(
|
|
551
738
|
DatePicker,
|
|
552
739
|
{
|
|
553
740
|
label: field.label,
|
|
@@ -569,13 +756,13 @@ var FieldEditor = memo(function FieldEditor2({
|
|
|
569
756
|
);
|
|
570
757
|
}
|
|
571
758
|
if (field.input_kind === "datetime") {
|
|
572
|
-
return /* @__PURE__ */
|
|
759
|
+
return /* @__PURE__ */ jsx3(
|
|
573
760
|
DateTimePicker,
|
|
574
761
|
{
|
|
575
762
|
label: field.label,
|
|
576
763
|
disabled: readOnly,
|
|
577
764
|
value: value ? dayjs(String(value)) : null,
|
|
578
|
-
onChange: (nextValue) => onChange(nextValue ? nextValue.
|
|
765
|
+
onChange: (nextValue) => onChange(nextValue ? nextValue.format("YYYY-MM-DD[T]HH:mm:ss") : null),
|
|
579
766
|
slotProps: {
|
|
580
767
|
popper: { disablePortal: true },
|
|
581
768
|
desktopPaper: buildPickerPaperProps(),
|
|
@@ -603,7 +790,7 @@ var FieldEditor = memo(function FieldEditor2({
|
|
|
603
790
|
});
|
|
604
791
|
}
|
|
605
792
|
if (field.input_kind === "json") {
|
|
606
|
-
return /* @__PURE__ */
|
|
793
|
+
return /* @__PURE__ */ jsx3(
|
|
607
794
|
TextField,
|
|
608
795
|
{
|
|
609
796
|
label: field.label,
|
|
@@ -636,7 +823,7 @@ var FieldEditor = memo(function FieldEditor2({
|
|
|
636
823
|
}
|
|
637
824
|
);
|
|
638
825
|
}
|
|
639
|
-
return /* @__PURE__ */
|
|
826
|
+
return /* @__PURE__ */ jsx3(
|
|
640
827
|
TextField,
|
|
641
828
|
{
|
|
642
829
|
label: field.label,
|
|
@@ -675,7 +862,7 @@ function renderChoiceEditor({
|
|
|
675
862
|
};
|
|
676
863
|
});
|
|
677
864
|
if (field.is_relation_many || field.input_kind === "relation-multiple") {
|
|
678
|
-
return /* @__PURE__ */
|
|
865
|
+
return /* @__PURE__ */ jsx3(
|
|
679
866
|
Autocomplete,
|
|
680
867
|
{
|
|
681
868
|
multiple: true,
|
|
@@ -701,36 +888,37 @@ function renderChoiceEditor({
|
|
|
701
888
|
},
|
|
702
889
|
listbox: { sx: { maxHeight: 240 } }
|
|
703
890
|
},
|
|
704
|
-
renderInput: (params) => {
|
|
891
|
+
renderInput: (params) => (() => {
|
|
705
892
|
var _a2;
|
|
706
|
-
|
|
893
|
+
const { InputProps, inputProps, ...textFieldParams } = params;
|
|
894
|
+
return /* @__PURE__ */ jsx3(
|
|
707
895
|
TextField,
|
|
708
896
|
{
|
|
709
|
-
...
|
|
897
|
+
...textFieldParams,
|
|
710
898
|
label: field.label,
|
|
711
899
|
placeholder: searchPlaceholder,
|
|
712
900
|
helperText: (_a2 = field.help_text) != null ? _a2 : void 0,
|
|
713
901
|
slotProps: {
|
|
714
902
|
input: {
|
|
715
|
-
...
|
|
903
|
+
...InputProps,
|
|
716
904
|
endAdornment: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
717
|
-
isLoadingChoices ? /* @__PURE__ */
|
|
718
|
-
|
|
905
|
+
isLoadingChoices ? /* @__PURE__ */ jsx3(CircularProgress, { color: "inherit", size: 16 }) : null,
|
|
906
|
+
InputProps.endAdornment
|
|
719
907
|
] })
|
|
720
908
|
},
|
|
721
909
|
htmlInput: {
|
|
722
|
-
...
|
|
910
|
+
...inputProps,
|
|
723
911
|
autoComplete: "new-password",
|
|
724
912
|
name: `admin-choice-${field.name}`
|
|
725
913
|
}
|
|
726
914
|
}
|
|
727
915
|
}
|
|
728
916
|
);
|
|
729
|
-
}
|
|
917
|
+
})()
|
|
730
918
|
}
|
|
731
919
|
);
|
|
732
920
|
}
|
|
733
|
-
return /* @__PURE__ */
|
|
921
|
+
return /* @__PURE__ */ jsx3(
|
|
734
922
|
Autocomplete,
|
|
735
923
|
{
|
|
736
924
|
options: choices,
|
|
@@ -758,32 +946,33 @@ function renderChoiceEditor({
|
|
|
758
946
|
},
|
|
759
947
|
listbox: { sx: { maxHeight: 240 } }
|
|
760
948
|
},
|
|
761
|
-
renderInput: (params) => {
|
|
949
|
+
renderInput: (params) => (() => {
|
|
762
950
|
var _a2;
|
|
763
|
-
|
|
951
|
+
const { InputProps, inputProps, ...textFieldParams } = params;
|
|
952
|
+
return /* @__PURE__ */ jsx3(
|
|
764
953
|
TextField,
|
|
765
954
|
{
|
|
766
|
-
...
|
|
955
|
+
...textFieldParams,
|
|
767
956
|
label: field.label,
|
|
768
957
|
placeholder: searchPlaceholder,
|
|
769
958
|
helperText: (_a2 = field.help_text) != null ? _a2 : void 0,
|
|
770
959
|
slotProps: {
|
|
771
960
|
input: {
|
|
772
|
-
...
|
|
961
|
+
...InputProps,
|
|
773
962
|
endAdornment: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
774
|
-
isLoadingChoices ? /* @__PURE__ */
|
|
775
|
-
|
|
963
|
+
isLoadingChoices ? /* @__PURE__ */ jsx3(CircularProgress, { color: "inherit", size: 16 }) : null,
|
|
964
|
+
InputProps.endAdornment
|
|
776
965
|
] })
|
|
777
966
|
},
|
|
778
967
|
htmlInput: {
|
|
779
|
-
...
|
|
968
|
+
...inputProps,
|
|
780
969
|
autoComplete: "new-password",
|
|
781
970
|
name: `admin-choice-${field.name}`
|
|
782
971
|
}
|
|
783
972
|
}
|
|
784
973
|
}
|
|
785
974
|
);
|
|
786
|
-
}
|
|
975
|
+
})()
|
|
787
976
|
}
|
|
788
977
|
);
|
|
789
978
|
}
|
|
@@ -847,7 +1036,7 @@ function stringifyJsonValue(value) {
|
|
|
847
1036
|
}
|
|
848
1037
|
|
|
849
1038
|
// src/components/FormDialog.tsx
|
|
850
|
-
import { jsx as
|
|
1039
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
851
1040
|
function FormDialog({
|
|
852
1041
|
open,
|
|
853
1042
|
onClose,
|
|
@@ -860,27 +1049,43 @@ function FormDialog({
|
|
|
860
1049
|
initialValues,
|
|
861
1050
|
itemId
|
|
862
1051
|
}) {
|
|
863
|
-
const
|
|
864
|
-
const
|
|
1052
|
+
const t = useAdminTranslation();
|
|
1053
|
+
const [values, setValues] = useState3({});
|
|
1054
|
+
const [error, setError] = useState3(null);
|
|
1055
|
+
const [isSaving, setIsSaving] = useState3(false);
|
|
1056
|
+
const editableFieldNames = useMemo4(
|
|
865
1057
|
() => mode === "create" ? meta.create_fields : meta.update_fields,
|
|
866
1058
|
[meta.create_fields, meta.update_fields, mode]
|
|
867
1059
|
);
|
|
868
|
-
const editableFields =
|
|
1060
|
+
const editableFields = useMemo4(
|
|
869
1061
|
() => meta.fields.filter((field) => editableFieldNames.includes(field.name)),
|
|
870
1062
|
[editableFieldNames, meta.fields]
|
|
871
1063
|
);
|
|
872
|
-
|
|
1064
|
+
useEffect3(() => {
|
|
873
1065
|
setValues(initialValues != null ? initialValues : {});
|
|
1066
|
+
setError(null);
|
|
1067
|
+
setIsSaving(false);
|
|
874
1068
|
}, [initialValues, open]);
|
|
875
1069
|
const handleSave = async () => {
|
|
1070
|
+
if (isSaving) {
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
1073
|
+
setIsSaving(true);
|
|
1074
|
+
setError(null);
|
|
876
1075
|
const payload = buildAdminPayload(values, editableFields);
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
1076
|
+
try {
|
|
1077
|
+
if (mode === "create") {
|
|
1078
|
+
await client.createItem(slug, payload);
|
|
1079
|
+
} else if (itemId !== void 0) {
|
|
1080
|
+
await client.patchItem(slug, itemId, payload);
|
|
1081
|
+
}
|
|
1082
|
+
onSuccess();
|
|
1083
|
+
onClose();
|
|
1084
|
+
} catch (reason) {
|
|
1085
|
+
setError(reason instanceof Error ? reason.message : t("object_save_error"));
|
|
1086
|
+
} finally {
|
|
1087
|
+
setIsSaving(false);
|
|
881
1088
|
}
|
|
882
|
-
onSuccess();
|
|
883
|
-
onClose();
|
|
884
1089
|
};
|
|
885
1090
|
return /* @__PURE__ */ jsxs2(
|
|
886
1091
|
Dialog,
|
|
@@ -904,23 +1109,26 @@ function FormDialog({
|
|
|
904
1109
|
}
|
|
905
1110
|
},
|
|
906
1111
|
children: [
|
|
907
|
-
/* @__PURE__ */
|
|
908
|
-
/* @__PURE__ */
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
1112
|
+
/* @__PURE__ */ jsx4(DialogTitle, { children: title }),
|
|
1113
|
+
/* @__PURE__ */ jsx4(DialogContent, { children: /* @__PURE__ */ jsx4(LocalizationProvider, { dateAdapter: AdapterDayjs, adapterLocale: meta.locale, children: /* @__PURE__ */ jsxs2(Box, { sx: { display: "grid", gap: 2, pt: 1 }, children: [
|
|
1114
|
+
error ? /* @__PURE__ */ jsx4(Alert, { severity: "error", children: error }) : null,
|
|
1115
|
+
editableFields.map((field) => /* @__PURE__ */ jsx4(
|
|
1116
|
+
FieldEditor,
|
|
1117
|
+
{
|
|
1118
|
+
field,
|
|
1119
|
+
value: values[field.name],
|
|
1120
|
+
slug,
|
|
1121
|
+
client,
|
|
1122
|
+
onChange: (nextValue) => {
|
|
1123
|
+
setValues((current) => ({ ...current, [field.name]: nextValue }));
|
|
1124
|
+
}
|
|
1125
|
+
},
|
|
1126
|
+
field.name
|
|
1127
|
+
))
|
|
1128
|
+
] }) }) }),
|
|
921
1129
|
/* @__PURE__ */ jsxs2(DialogActions, { children: [
|
|
922
|
-
/* @__PURE__ */
|
|
923
|
-
/* @__PURE__ */
|
|
1130
|
+
/* @__PURE__ */ jsx4(Button, { onClick: onClose, disabled: isSaving, children: t("cancel") }),
|
|
1131
|
+
/* @__PURE__ */ jsx4(Button, { variant: "contained", onClick: () => void handleSave(), disabled: isSaving, children: isSaving ? t("saving") : t("save") })
|
|
924
1132
|
] })
|
|
925
1133
|
]
|
|
926
1134
|
}
|
|
@@ -928,13 +1136,13 @@ function FormDialog({
|
|
|
928
1136
|
}
|
|
929
1137
|
|
|
930
1138
|
// src/components/OverviewPage.tsx
|
|
931
|
-
import { useEffect as
|
|
932
|
-
import { Alert as
|
|
1139
|
+
import { useEffect as useEffect6, useMemo as useMemo6, useState as useState6 } from "react";
|
|
1140
|
+
import { Alert as Alert3, Box as Box5, Grid, Paper as Paper3, Skeleton as Skeleton2, Stack as Stack5 } from "@mui/material";
|
|
933
1141
|
|
|
934
1142
|
// src/hooks/useAdminDocumentTitle.ts
|
|
935
|
-
import { useEffect as
|
|
1143
|
+
import { useEffect as useEffect4 } from "react";
|
|
936
1144
|
function useAdminDocumentTitle(...parts) {
|
|
937
|
-
|
|
1145
|
+
useEffect4(() => {
|
|
938
1146
|
const title = parts.map((part) => part == null ? void 0 : part.trim()).filter((part) => Boolean(part)).join(" | ");
|
|
939
1147
|
if (!title) {
|
|
940
1148
|
return;
|
|
@@ -944,23 +1152,23 @@ function useAdminDocumentTitle(...parts) {
|
|
|
944
1152
|
}
|
|
945
1153
|
|
|
946
1154
|
// src/components/layout/AdminDataContext.tsx
|
|
947
|
-
import { createContext as
|
|
948
|
-
import { jsx as
|
|
1155
|
+
import { createContext as createContext3, useContext as useContext3 } from "react";
|
|
1156
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
949
1157
|
var defaultAdminDataContextValue = {
|
|
950
1158
|
locale: "ru",
|
|
951
1159
|
models: [],
|
|
952
1160
|
blocks: []
|
|
953
1161
|
};
|
|
954
|
-
var AdminDataContext =
|
|
1162
|
+
var AdminDataContext = createContext3(defaultAdminDataContextValue);
|
|
955
1163
|
function AdminDataProvider({ value, children }) {
|
|
956
|
-
return /* @__PURE__ */
|
|
1164
|
+
return /* @__PURE__ */ jsx5(AdminDataContext.Provider, { value, children });
|
|
957
1165
|
}
|
|
958
1166
|
function useAdminData() {
|
|
959
|
-
return
|
|
1167
|
+
return useContext3(AdminDataContext);
|
|
960
1168
|
}
|
|
961
1169
|
|
|
962
1170
|
// src/components/ModelsBlocks.tsx
|
|
963
|
-
import { memo as memo2, useMemo as
|
|
1171
|
+
import { memo as memo2, useMemo as useMemo5 } from "react";
|
|
964
1172
|
import { Box as Box3, Stack as Stack3, useMediaQuery, useTheme } from "@mui/material";
|
|
965
1173
|
|
|
966
1174
|
// src/components/models-blocks/DashboardModelsBlock.tsx
|
|
@@ -977,10 +1185,10 @@ import {
|
|
|
977
1185
|
|
|
978
1186
|
// src/components/models-blocks/BlockTitle.tsx
|
|
979
1187
|
import { Stack, Typography } from "@mui/material";
|
|
980
|
-
import { jsx as
|
|
1188
|
+
import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
981
1189
|
function BlockTitle({ block, compact = false }) {
|
|
982
1190
|
return /* @__PURE__ */ jsxs3(Stack, { spacing: 0.25, children: [
|
|
983
|
-
/* @__PURE__ */
|
|
1191
|
+
/* @__PURE__ */ jsx6(
|
|
984
1192
|
Typography,
|
|
985
1193
|
{
|
|
986
1194
|
variant: compact ? "subtitle1" : "h6",
|
|
@@ -992,7 +1200,7 @@ function BlockTitle({ block, compact = false }) {
|
|
|
992
1200
|
children: block.title
|
|
993
1201
|
}
|
|
994
1202
|
),
|
|
995
|
-
block.description && !compact ? /* @__PURE__ */
|
|
1203
|
+
block.description && !compact ? /* @__PURE__ */ jsx6(Typography, { color: "text.secondary", sx: { fontSize: compact ? 12 : 14, lineHeight: 1.3 }, children: block.description }) : null
|
|
996
1204
|
] });
|
|
997
1205
|
}
|
|
998
1206
|
|
|
@@ -1023,11 +1231,11 @@ function getBlockSurfaceSx(block, variant) {
|
|
|
1023
1231
|
}
|
|
1024
1232
|
|
|
1025
1233
|
// src/components/models-blocks/useBlockExpandedState.ts
|
|
1026
|
-
import { useCallback, useEffect as
|
|
1234
|
+
import { useCallback as useCallback2, useEffect as useEffect5, useState as useState4 } from "react";
|
|
1027
1235
|
var STORAGE_KEY_PREFIX = "xladmin.models-block.expanded";
|
|
1028
1236
|
function useBlockExpandedState(blockSlug, defaultExpanded) {
|
|
1029
|
-
const [isExpanded, setIsExpanded] =
|
|
1030
|
-
|
|
1237
|
+
const [isExpanded, setIsExpanded] = useState4(defaultExpanded);
|
|
1238
|
+
useEffect5(() => {
|
|
1031
1239
|
if (typeof window === "undefined") {
|
|
1032
1240
|
return;
|
|
1033
1241
|
}
|
|
@@ -1038,7 +1246,7 @@ function useBlockExpandedState(blockSlug, defaultExpanded) {
|
|
|
1038
1246
|
}
|
|
1039
1247
|
setIsExpanded(rawValue === "true");
|
|
1040
1248
|
}, [blockSlug, defaultExpanded]);
|
|
1041
|
-
const updateExpanded =
|
|
1249
|
+
const updateExpanded = useCallback2((nextExpanded) => {
|
|
1042
1250
|
setIsExpanded(nextExpanded);
|
|
1043
1251
|
if (typeof window !== "undefined") {
|
|
1044
1252
|
window.localStorage.setItem(getStorageKey(blockSlug), String(nextExpanded));
|
|
@@ -1051,14 +1259,23 @@ function getStorageKey(blockSlug) {
|
|
|
1051
1259
|
}
|
|
1052
1260
|
|
|
1053
1261
|
// src/components/NavLink.tsx
|
|
1054
|
-
import
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
return /* @__PURE__ */
|
|
1262
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1263
|
+
function NavLink({ href, children, style, title, onClick, router }) {
|
|
1264
|
+
const resolvedRouter = useXLAdminRouter(router);
|
|
1265
|
+
return /* @__PURE__ */ jsx7(
|
|
1266
|
+
"a",
|
|
1267
|
+
{
|
|
1268
|
+
href,
|
|
1269
|
+
style,
|
|
1270
|
+
title,
|
|
1271
|
+
onClick: (event) => handleNavLinkClick(event, { href, onClick, router: resolvedRouter }),
|
|
1272
|
+
children
|
|
1273
|
+
}
|
|
1274
|
+
);
|
|
1058
1275
|
}
|
|
1059
1276
|
|
|
1060
1277
|
// src/components/models-blocks/DashboardModelsBlock.tsx
|
|
1061
|
-
import { jsx as
|
|
1278
|
+
import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1062
1279
|
function DashboardModelsBlock({ block, basePath }) {
|
|
1063
1280
|
const [isExpanded, setIsExpanded] = useBlockExpandedState(block.slug, block.default_expanded);
|
|
1064
1281
|
return /* @__PURE__ */ jsxs4(
|
|
@@ -1077,10 +1294,10 @@ function DashboardModelsBlock({ block, basePath }) {
|
|
|
1077
1294
|
}
|
|
1078
1295
|
},
|
|
1079
1296
|
children: [
|
|
1080
|
-
/* @__PURE__ */
|
|
1297
|
+
/* @__PURE__ */ jsx8(
|
|
1081
1298
|
AccordionSummary,
|
|
1082
1299
|
{
|
|
1083
|
-
expandIcon: block.collapsible ? /* @__PURE__ */
|
|
1300
|
+
expandIcon: block.collapsible ? /* @__PURE__ */ jsx8(ExpandMoreIcon, { fontSize: "small" }) : void 0,
|
|
1084
1301
|
sx: {
|
|
1085
1302
|
minHeight: "48px",
|
|
1086
1303
|
pr: 1.75,
|
|
@@ -1102,33 +1319,41 @@ function DashboardModelsBlock({ block, basePath }) {
|
|
|
1102
1319
|
mb: 1.05
|
|
1103
1320
|
}
|
|
1104
1321
|
},
|
|
1105
|
-
children: /* @__PURE__ */
|
|
1322
|
+
children: /* @__PURE__ */ jsx8(BlockTitle, { block })
|
|
1106
1323
|
}
|
|
1107
1324
|
),
|
|
1108
|
-
/* @__PURE__ */
|
|
1109
|
-
|
|
1325
|
+
/* @__PURE__ */ jsx8(AccordionDetails, { sx: { px: 1.35, pb: 1.35, pt: 0 }, children: /* @__PURE__ */ jsx8(Stack2, { spacing: 0.5, sx: { px: 0.4 }, children: block.models.map((model) => /* @__PURE__ */ jsx8(
|
|
1326
|
+
NavLink,
|
|
1110
1327
|
{
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
borderRadius: "8px",
|
|
1116
|
-
overflow: "hidden"
|
|
1117
|
-
},
|
|
1118
|
-
children: /* @__PURE__ */ jsx7(
|
|
1119
|
-
ListItemButton,
|
|
1328
|
+
href: `${basePath}/${model.slug}`,
|
|
1329
|
+
style: { textDecoration: "none", display: "block" },
|
|
1330
|
+
children: /* @__PURE__ */ jsx8(
|
|
1331
|
+
ButtonBase,
|
|
1120
1332
|
{
|
|
1121
1333
|
sx: {
|
|
1334
|
+
width: "100%",
|
|
1335
|
+
textAlign: "left",
|
|
1336
|
+
display: "block",
|
|
1122
1337
|
borderRadius: "8px",
|
|
1123
|
-
|
|
1124
|
-
px: 1.25,
|
|
1125
|
-
py: 0.4
|
|
1338
|
+
overflow: "hidden"
|
|
1126
1339
|
},
|
|
1127
|
-
children: /* @__PURE__ */
|
|
1340
|
+
children: /* @__PURE__ */ jsx8(
|
|
1341
|
+
ListItemButton,
|
|
1342
|
+
{
|
|
1343
|
+
sx: {
|
|
1344
|
+
borderRadius: "8px",
|
|
1345
|
+
minHeight: 42,
|
|
1346
|
+
px: 1.25,
|
|
1347
|
+
py: 0.4
|
|
1348
|
+
},
|
|
1349
|
+
children: /* @__PURE__ */ jsx8(ListItemText, { primary: model.title })
|
|
1350
|
+
}
|
|
1351
|
+
)
|
|
1128
1352
|
}
|
|
1129
1353
|
)
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1354
|
+
},
|
|
1355
|
+
model.slug
|
|
1356
|
+
)) }) })
|
|
1132
1357
|
]
|
|
1133
1358
|
}
|
|
1134
1359
|
);
|
|
@@ -1146,7 +1371,7 @@ import {
|
|
|
1146
1371
|
ListItemText as ListItemText2,
|
|
1147
1372
|
Paper
|
|
1148
1373
|
} from "@mui/material";
|
|
1149
|
-
import { jsx as
|
|
1374
|
+
import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1150
1375
|
function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate }) {
|
|
1151
1376
|
const [isExpanded, setIsExpanded] = useBlockExpandedState(block.slug, block.default_expanded);
|
|
1152
1377
|
if (block.collapsible) {
|
|
@@ -1166,10 +1391,10 @@ function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate
|
|
|
1166
1391
|
}
|
|
1167
1392
|
},
|
|
1168
1393
|
children: [
|
|
1169
|
-
/* @__PURE__ */
|
|
1394
|
+
/* @__PURE__ */ jsx9(
|
|
1170
1395
|
AccordionSummary2,
|
|
1171
1396
|
{
|
|
1172
|
-
expandIcon: /* @__PURE__ */
|
|
1397
|
+
expandIcon: /* @__PURE__ */ jsx9(ExpandMoreIcon2, { fontSize: "small" }),
|
|
1173
1398
|
sx: {
|
|
1174
1399
|
minHeight: "42px",
|
|
1175
1400
|
pr: 1.25,
|
|
@@ -1185,10 +1410,10 @@ function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate
|
|
|
1185
1410
|
my: 0
|
|
1186
1411
|
}
|
|
1187
1412
|
},
|
|
1188
|
-
children: /* @__PURE__ */
|
|
1413
|
+
children: /* @__PURE__ */ jsx9(BlockTitle, { block, compact: true })
|
|
1189
1414
|
}
|
|
1190
1415
|
),
|
|
1191
|
-
/* @__PURE__ */
|
|
1416
|
+
/* @__PURE__ */ jsx9(AccordionDetails2, { sx: { p: 0 }, children: /* @__PURE__ */ jsx9(
|
|
1192
1417
|
SidebarModelsList,
|
|
1193
1418
|
{
|
|
1194
1419
|
models: block.models,
|
|
@@ -1210,8 +1435,8 @@ function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate
|
|
|
1210
1435
|
overflow: "hidden"
|
|
1211
1436
|
},
|
|
1212
1437
|
children: [
|
|
1213
|
-
/* @__PURE__ */
|
|
1214
|
-
/* @__PURE__ */
|
|
1438
|
+
/* @__PURE__ */ jsx9(Box2, { sx: { px: 1.25, py: 1 }, children: /* @__PURE__ */ jsx9(BlockTitle, { block, compact: true }) }),
|
|
1439
|
+
/* @__PURE__ */ jsx9(
|
|
1215
1440
|
SidebarModelsList,
|
|
1216
1441
|
{
|
|
1217
1442
|
models: block.models,
|
|
@@ -1225,16 +1450,16 @@ function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate
|
|
|
1225
1450
|
);
|
|
1226
1451
|
}
|
|
1227
1452
|
function SidebarModelsList({ models, basePath, activeModelSlug, onModelNavigate }) {
|
|
1228
|
-
return /* @__PURE__ */
|
|
1453
|
+
return /* @__PURE__ */ jsx9(List, { dense: true, disablePadding: true, sx: { display: "flex", flexDirection: "column", gap: 0.5, p: 1.35 }, children: models.map((model) => {
|
|
1229
1454
|
const href = `${basePath}/${model.slug}`;
|
|
1230
1455
|
const isActive = activeModelSlug === model.slug;
|
|
1231
|
-
return /* @__PURE__ */
|
|
1456
|
+
return /* @__PURE__ */ jsx9(
|
|
1232
1457
|
NavLink,
|
|
1233
1458
|
{
|
|
1234
1459
|
href,
|
|
1235
1460
|
style: { textDecoration: "none", display: "block" },
|
|
1236
1461
|
onClick: () => onModelNavigate == null ? void 0 : onModelNavigate(href),
|
|
1237
|
-
children: /* @__PURE__ */
|
|
1462
|
+
children: /* @__PURE__ */ jsx9(
|
|
1238
1463
|
ListItemButton2,
|
|
1239
1464
|
{
|
|
1240
1465
|
selected: isActive,
|
|
@@ -1253,7 +1478,7 @@ function SidebarModelsList({ models, basePath, activeModelSlug, onModelNavigate
|
|
|
1253
1478
|
backgroundColor: "rgba(255, 255, 255, 0.2)"
|
|
1254
1479
|
}
|
|
1255
1480
|
},
|
|
1256
|
-
children: /* @__PURE__ */
|
|
1481
|
+
children: /* @__PURE__ */ jsx9(ListItemText2, { primary: model.title })
|
|
1257
1482
|
}
|
|
1258
1483
|
)
|
|
1259
1484
|
},
|
|
@@ -1263,7 +1488,7 @@ function SidebarModelsList({ models, basePath, activeModelSlug, onModelNavigate
|
|
|
1263
1488
|
}
|
|
1264
1489
|
|
|
1265
1490
|
// src/components/ModelsBlocks.tsx
|
|
1266
|
-
import { jsx as
|
|
1491
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
1267
1492
|
var ModelsBlocks = memo2(function ModelsBlocks2({
|
|
1268
1493
|
basePath,
|
|
1269
1494
|
models,
|
|
@@ -1276,7 +1501,7 @@ var ModelsBlocks = memo2(function ModelsBlocks2({
|
|
|
1276
1501
|
const theme = useTheme();
|
|
1277
1502
|
const isMdUp = useMediaQuery(theme.breakpoints.up("md"));
|
|
1278
1503
|
const isXlUp = useMediaQuery(theme.breakpoints.up("xl"));
|
|
1279
|
-
const normalizedBlocks =
|
|
1504
|
+
const normalizedBlocks = useMemo5(() => [
|
|
1280
1505
|
...blocks,
|
|
1281
1506
|
{
|
|
1282
1507
|
slug: "all-models",
|
|
@@ -1289,12 +1514,12 @@ var ModelsBlocks = memo2(function ModelsBlocks2({
|
|
|
1289
1514
|
isAllModels: true
|
|
1290
1515
|
}
|
|
1291
1516
|
], [blocks, models, t, variant]);
|
|
1292
|
-
const dashboardColumns =
|
|
1517
|
+
const dashboardColumns = useMemo5(() => {
|
|
1293
1518
|
const columnCount = isXlUp ? 3 : isMdUp ? 2 : 1;
|
|
1294
1519
|
return distributeBlocksByHeight(normalizedBlocks, columnCount);
|
|
1295
1520
|
}, [isMdUp, isXlUp, normalizedBlocks]);
|
|
1296
1521
|
if (variant === "sidebar") {
|
|
1297
|
-
return /* @__PURE__ */
|
|
1522
|
+
return /* @__PURE__ */ jsx10(Stack3, { spacing: 1, children: normalizedBlocks.map((block) => /* @__PURE__ */ jsx10(
|
|
1298
1523
|
SidebarModelsBlock,
|
|
1299
1524
|
{
|
|
1300
1525
|
block,
|
|
@@ -1305,7 +1530,7 @@ var ModelsBlocks = memo2(function ModelsBlocks2({
|
|
|
1305
1530
|
block.slug
|
|
1306
1531
|
)) });
|
|
1307
1532
|
}
|
|
1308
|
-
return /* @__PURE__ */
|
|
1533
|
+
return /* @__PURE__ */ jsx10(Box3, { sx: { display: "flex", gap: 2, alignItems: "flex-start" }, children: dashboardColumns.map((column, columnIndex) => /* @__PURE__ */ jsx10(Box3, { sx: { flex: 1, minWidth: 0 }, children: /* @__PURE__ */ jsx10(Stack3, { spacing: 2, children: column.map((block) => /* @__PURE__ */ jsx10(DashboardModelsBlock, { block, basePath }, block.slug)) }) }, columnIndex)) });
|
|
1309
1534
|
});
|
|
1310
1535
|
function distributeBlocksByHeight(blocks, columnCount) {
|
|
1311
1536
|
const columns = Array.from({ length: columnCount }, () => []);
|
|
@@ -1327,15 +1552,15 @@ function getBlockWeight(block) {
|
|
|
1327
1552
|
}
|
|
1328
1553
|
|
|
1329
1554
|
// src/components/layout/MainHeader.tsx
|
|
1330
|
-
import { useState as
|
|
1555
|
+
import { useState as useState5 } from "react";
|
|
1331
1556
|
import MenuIcon from "@mui/icons-material/Menu";
|
|
1332
1557
|
import { Box as Box4 } from "@mui/material";
|
|
1333
1558
|
import ExpandMoreIcon3 from "@mui/icons-material/ExpandMore";
|
|
1334
|
-
import { Alert, Collapse, IconButton, Paper as Paper2, Skeleton, Stack as Stack4, Typography as Typography2 } from "@mui/material";
|
|
1559
|
+
import { Alert as Alert2, Collapse, IconButton, Paper as Paper2, Skeleton, Stack as Stack4, Typography as Typography2 } from "@mui/material";
|
|
1335
1560
|
|
|
1336
1561
|
// src/components/layout/ShellContext.tsx
|
|
1337
|
-
import { createContext as
|
|
1338
|
-
import { jsx as
|
|
1562
|
+
import { createContext as createContext4, useContext as useContext4 } from "react";
|
|
1563
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
1339
1564
|
var defaultShellContextValue = {
|
|
1340
1565
|
isMobile: false,
|
|
1341
1566
|
openMobileSidebar: () => {
|
|
@@ -1345,19 +1570,19 @@ var defaultShellContextValue = {
|
|
|
1345
1570
|
startPendingNavigation: () => {
|
|
1346
1571
|
}
|
|
1347
1572
|
};
|
|
1348
|
-
var ShellContext =
|
|
1573
|
+
var ShellContext = createContext4(defaultShellContextValue);
|
|
1349
1574
|
function ShellContextProvider({
|
|
1350
1575
|
value,
|
|
1351
1576
|
children
|
|
1352
1577
|
}) {
|
|
1353
|
-
return /* @__PURE__ */
|
|
1578
|
+
return /* @__PURE__ */ jsx11(ShellContext.Provider, { value, children });
|
|
1354
1579
|
}
|
|
1355
1580
|
function useShellContext() {
|
|
1356
|
-
return
|
|
1581
|
+
return useContext4(ShellContext);
|
|
1357
1582
|
}
|
|
1358
1583
|
|
|
1359
1584
|
// src/components/layout/MainHeader.tsx
|
|
1360
|
-
import { jsx as
|
|
1585
|
+
import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1361
1586
|
var MAIN_HEADER_PADDING_X = 2.5;
|
|
1362
1587
|
var MAIN_HEADER_PADDING_T = 1.35;
|
|
1363
1588
|
var MAIN_HEADER_PADDING_B = 1.8;
|
|
@@ -1366,7 +1591,7 @@ var MAIN_HEADER_SUBTITLE_HEIGHT = 16;
|
|
|
1366
1591
|
function MainHeader({ title, subtitle, details, error, beforeTitle, beforeSubtitle, actions }) {
|
|
1367
1592
|
const t = useAdminTranslation();
|
|
1368
1593
|
const { isMobile, openMobileSidebar } = useShellContext();
|
|
1369
|
-
const [isDetailsOpen, setIsDetailsOpen] =
|
|
1594
|
+
const [isDetailsOpen, setIsDetailsOpen] = useState5(false);
|
|
1370
1595
|
return /* @__PURE__ */ jsxs6(
|
|
1371
1596
|
Paper2,
|
|
1372
1597
|
{
|
|
@@ -1382,68 +1607,88 @@ function MainHeader({ title, subtitle, details, error, beforeTitle, beforeSubtit
|
|
|
1382
1607
|
},
|
|
1383
1608
|
children: [
|
|
1384
1609
|
/* @__PURE__ */ jsxs6(Stack4, { spacing: 0.5, children: [
|
|
1385
|
-
/* @__PURE__ */ jsxs6(
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1610
|
+
/* @__PURE__ */ jsxs6(
|
|
1611
|
+
Stack4,
|
|
1612
|
+
{
|
|
1613
|
+
direction: "row",
|
|
1614
|
+
spacing: 1.5,
|
|
1615
|
+
alignItems: "center",
|
|
1616
|
+
justifyContent: "space-between",
|
|
1617
|
+
sx: { minWidth: 0 },
|
|
1618
|
+
children: [
|
|
1619
|
+
/* @__PURE__ */ jsxs6(Stack4, { direction: "row", spacing: 1, alignItems: "center", sx: { minWidth: 0, flex: 1 }, children: [
|
|
1620
|
+
isMobile ? /* @__PURE__ */ jsx12(Box4, { sx: { display: "flex", alignItems: "center", flexShrink: 0 }, children: /* @__PURE__ */ jsx12(
|
|
1621
|
+
IconButton,
|
|
1622
|
+
{
|
|
1623
|
+
"aria-label": t("menu"),
|
|
1624
|
+
onClick: openMobileSidebar,
|
|
1625
|
+
size: "small",
|
|
1626
|
+
sx: { ml: -0.5 },
|
|
1627
|
+
children: /* @__PURE__ */ jsx12(MenuIcon, { fontSize: "small" })
|
|
1628
|
+
}
|
|
1629
|
+
) }) : null,
|
|
1630
|
+
beforeTitle ? /* @__PURE__ */ jsx12(Box4, { sx: { display: "flex", alignItems: "center", flexShrink: 0 }, children: beforeTitle }) : null,
|
|
1631
|
+
/* @__PURE__ */ jsx12(
|
|
1632
|
+
Typography2,
|
|
1633
|
+
{
|
|
1634
|
+
variant: "h5",
|
|
1635
|
+
sx: {
|
|
1636
|
+
fontWeight: 600,
|
|
1637
|
+
lineHeight: "2.125rem",
|
|
1638
|
+
minWidth: 0
|
|
1639
|
+
},
|
|
1640
|
+
children: title
|
|
1641
|
+
}
|
|
1642
|
+
)
|
|
1643
|
+
] }),
|
|
1644
|
+
actions ? /* @__PURE__ */ jsx12(Box4, { sx: { display: "flex", alignItems: "center", flexShrink: 0 }, children: actions }) : null
|
|
1645
|
+
]
|
|
1646
|
+
}
|
|
1647
|
+
),
|
|
1413
1648
|
subtitle && !details ? /* @__PURE__ */ jsxs6(Stack4, { direction: "row", spacing: 0.5, alignItems: "center", sx: { minWidth: 0 }, children: [
|
|
1414
|
-
beforeSubtitle ? /* @__PURE__ */
|
|
1415
|
-
/* @__PURE__ */
|
|
1649
|
+
beforeSubtitle ? /* @__PURE__ */ jsx12(Box4, { sx: { display: "flex", alignItems: "center", flexShrink: 0 }, children: beforeSubtitle }) : null,
|
|
1650
|
+
/* @__PURE__ */ jsx12(Typography2, { color: "text.secondary", sx: { lineHeight: "1rem", minWidth: 0 }, children: subtitle })
|
|
1416
1651
|
] }) : null,
|
|
1417
1652
|
details ? /* @__PURE__ */ jsxs6(Stack4, { spacing: 0.5, children: [
|
|
1418
|
-
/* @__PURE__ */ jsxs6(
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
{
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1653
|
+
/* @__PURE__ */ jsxs6(
|
|
1654
|
+
Stack4,
|
|
1655
|
+
{
|
|
1656
|
+
direction: "row",
|
|
1657
|
+
spacing: 0.5,
|
|
1658
|
+
alignItems: "center",
|
|
1659
|
+
justifyContent: "space-between",
|
|
1660
|
+
sx: { minWidth: 0 },
|
|
1661
|
+
children: [
|
|
1662
|
+
/* @__PURE__ */ jsxs6(Stack4, { direction: "row", spacing: 0.5, alignItems: "center", sx: { minWidth: 0, flex: 1 }, children: [
|
|
1663
|
+
beforeSubtitle ? /* @__PURE__ */ jsx12(Box4, { sx: { display: "flex", alignItems: "center", flexShrink: 0 }, children: beforeSubtitle }) : null,
|
|
1664
|
+
/* @__PURE__ */ jsx12(Typography2, { color: "text.secondary", sx: { lineHeight: "1rem", minWidth: 0 }, children: subtitle })
|
|
1665
|
+
] }),
|
|
1666
|
+
/* @__PURE__ */ jsx12(
|
|
1667
|
+
IconButton,
|
|
1432
1668
|
{
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1669
|
+
"aria-label": isDetailsOpen ? t("hide_details") : t("show_details"),
|
|
1670
|
+
onClick: () => setIsDetailsOpen((current) => !current),
|
|
1671
|
+
size: "small",
|
|
1672
|
+
sx: { mr: -0.5 },
|
|
1673
|
+
children: /* @__PURE__ */ jsx12(
|
|
1674
|
+
ExpandMoreIcon3,
|
|
1675
|
+
{
|
|
1676
|
+
fontSize: "small",
|
|
1677
|
+
sx: {
|
|
1678
|
+
transform: isDetailsOpen ? "rotate(180deg)" : "rotate(0deg)",
|
|
1679
|
+
transition: "transform 0.2s ease"
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
)
|
|
1438
1683
|
}
|
|
1439
1684
|
)
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
/* @__PURE__ */
|
|
1685
|
+
]
|
|
1686
|
+
}
|
|
1687
|
+
),
|
|
1688
|
+
/* @__PURE__ */ jsx12(Collapse, { in: isDetailsOpen, children: /* @__PURE__ */ jsx12(Box4, { sx: { pt: 0.5 }, children: details }) })
|
|
1444
1689
|
] }) : null
|
|
1445
1690
|
] }),
|
|
1446
|
-
error ? /* @__PURE__ */
|
|
1691
|
+
error ? /* @__PURE__ */ jsx12(Alert2, { severity: "error", sx: { mt: 2 }, children: error }) : null
|
|
1447
1692
|
]
|
|
1448
1693
|
}
|
|
1449
1694
|
);
|
|
@@ -1452,7 +1697,7 @@ function MainHeaderSkeleton({
|
|
|
1452
1697
|
titleWidth = 240,
|
|
1453
1698
|
subtitleWidth = "40%"
|
|
1454
1699
|
}) {
|
|
1455
|
-
return /* @__PURE__ */
|
|
1700
|
+
return /* @__PURE__ */ jsx12(
|
|
1456
1701
|
Paper2,
|
|
1457
1702
|
{
|
|
1458
1703
|
sx: {
|
|
@@ -1466,7 +1711,7 @@ function MainHeaderSkeleton({
|
|
|
1466
1711
|
zIndex: 3
|
|
1467
1712
|
},
|
|
1468
1713
|
children: /* @__PURE__ */ jsxs6(Stack4, { spacing: 1, children: [
|
|
1469
|
-
/* @__PURE__ */
|
|
1714
|
+
/* @__PURE__ */ jsx12(
|
|
1470
1715
|
Skeleton,
|
|
1471
1716
|
{
|
|
1472
1717
|
variant: "rounded",
|
|
@@ -1475,7 +1720,7 @@ function MainHeaderSkeleton({
|
|
|
1475
1720
|
sx: { transform: "none" }
|
|
1476
1721
|
}
|
|
1477
1722
|
),
|
|
1478
|
-
/* @__PURE__ */
|
|
1723
|
+
/* @__PURE__ */ jsx12(
|
|
1479
1724
|
Skeleton,
|
|
1480
1725
|
{
|
|
1481
1726
|
variant: "rounded",
|
|
@@ -1490,14 +1735,14 @@ function MainHeaderSkeleton({
|
|
|
1490
1735
|
}
|
|
1491
1736
|
|
|
1492
1737
|
// src/components/OverviewPage.tsx
|
|
1493
|
-
import { jsx as
|
|
1738
|
+
import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1494
1739
|
var cachedModelsResponse = null;
|
|
1495
1740
|
var inFlightModelsRequest = null;
|
|
1496
1741
|
function OverviewPage({ client, basePath }) {
|
|
1497
1742
|
const t = useAdminTranslation();
|
|
1498
1743
|
useAdminDocumentTitle(t("admin_title"), t("overview_title"));
|
|
1499
1744
|
const adminData = useAdminData();
|
|
1500
|
-
const shellModelsResponse =
|
|
1745
|
+
const shellModelsResponse = useMemo6(() => {
|
|
1501
1746
|
if (adminData.models.length === 0 && adminData.blocks.length === 0) {
|
|
1502
1747
|
return null;
|
|
1503
1748
|
}
|
|
@@ -1507,10 +1752,10 @@ function OverviewPage({ client, basePath }) {
|
|
|
1507
1752
|
blocks: adminData.blocks
|
|
1508
1753
|
};
|
|
1509
1754
|
}, [adminData.blocks, adminData.locale, adminData.models]);
|
|
1510
|
-
const [data, setData] =
|
|
1511
|
-
const [error, setError] =
|
|
1512
|
-
const [isLoading, setIsLoading] =
|
|
1513
|
-
|
|
1755
|
+
const [data, setData] = useState6(shellModelsResponse != null ? shellModelsResponse : cachedModelsResponse);
|
|
1756
|
+
const [error, setError] = useState6(null);
|
|
1757
|
+
const [isLoading, setIsLoading] = useState6(shellModelsResponse === null && cachedModelsResponse === null);
|
|
1758
|
+
useEffect6(() => {
|
|
1514
1759
|
let isMounted = true;
|
|
1515
1760
|
if (shellModelsResponse !== null) {
|
|
1516
1761
|
cachedModelsResponse = shellModelsResponse;
|
|
@@ -1550,20 +1795,20 @@ function OverviewPage({ client, basePath }) {
|
|
|
1550
1795
|
};
|
|
1551
1796
|
}, [client, shellModelsResponse, t]);
|
|
1552
1797
|
if (isLoading && !data) {
|
|
1553
|
-
return /* @__PURE__ */
|
|
1798
|
+
return /* @__PURE__ */ jsx13(OverviewPageSkeleton, {});
|
|
1554
1799
|
}
|
|
1555
1800
|
if (error || !data) {
|
|
1556
|
-
return /* @__PURE__ */
|
|
1801
|
+
return /* @__PURE__ */ jsx13(Alert3, { severity: "error", children: error || t("models_load_error") });
|
|
1557
1802
|
}
|
|
1558
1803
|
return /* @__PURE__ */ jsxs7(Stack5, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
|
|
1559
|
-
/* @__PURE__ */
|
|
1804
|
+
/* @__PURE__ */ jsx13(
|
|
1560
1805
|
MainHeader,
|
|
1561
1806
|
{
|
|
1562
1807
|
title: t("overview_title"),
|
|
1563
1808
|
subtitle: t("overview_subtitle")
|
|
1564
1809
|
}
|
|
1565
1810
|
),
|
|
1566
|
-
/* @__PURE__ */
|
|
1811
|
+
/* @__PURE__ */ jsx13(
|
|
1567
1812
|
Paper3,
|
|
1568
1813
|
{
|
|
1569
1814
|
sx: {
|
|
@@ -1574,7 +1819,7 @@ function OverviewPage({ client, basePath }) {
|
|
|
1574
1819
|
display: "flex",
|
|
1575
1820
|
flexDirection: "column"
|
|
1576
1821
|
},
|
|
1577
|
-
children: /* @__PURE__ */
|
|
1822
|
+
children: /* @__PURE__ */ jsx13(Box5, { sx: { flex: 1, minHeight: 0, overflow: "auto", p: 2 }, children: /* @__PURE__ */ jsx13(
|
|
1578
1823
|
ModelsBlocks,
|
|
1579
1824
|
{
|
|
1580
1825
|
models: data.items,
|
|
@@ -1589,8 +1834,8 @@ function OverviewPage({ client, basePath }) {
|
|
|
1589
1834
|
}
|
|
1590
1835
|
function OverviewPageSkeleton() {
|
|
1591
1836
|
return /* @__PURE__ */ jsxs7(Stack5, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
|
|
1592
|
-
/* @__PURE__ */
|
|
1593
|
-
/* @__PURE__ */
|
|
1837
|
+
/* @__PURE__ */ jsx13(MainHeaderSkeleton, { titleWidth: 220, subtitleWidth: "58%" }),
|
|
1838
|
+
/* @__PURE__ */ jsx13(
|
|
1594
1839
|
Paper3,
|
|
1595
1840
|
{
|
|
1596
1841
|
sx: {
|
|
@@ -1601,9 +1846,9 @@ function OverviewPageSkeleton() {
|
|
|
1601
1846
|
display: "flex",
|
|
1602
1847
|
flexDirection: "column"
|
|
1603
1848
|
},
|
|
1604
|
-
children: /* @__PURE__ */
|
|
1605
|
-
/* @__PURE__ */
|
|
1606
|
-
/* @__PURE__ */
|
|
1849
|
+
children: /* @__PURE__ */ jsx13(Box5, { sx: { flex: 1, minHeight: 0, overflow: "auto", p: 2 }, children: /* @__PURE__ */ jsx13(Grid, { container: true, spacing: 2, children: Array.from({ length: 8 }).map((_, index) => /* @__PURE__ */ jsx13(Grid, { size: { xs: 12, md: 6, xl: 4 }, children: /* @__PURE__ */ jsx13(Paper3, { sx: { p: 2.5, borderRadius: "10px" }, children: /* @__PURE__ */ jsxs7(Stack5, { spacing: 1, children: [
|
|
1850
|
+
/* @__PURE__ */ jsx13(Skeleton2, { variant: "text", width: "60%", height: 36 }),
|
|
1851
|
+
/* @__PURE__ */ jsx13(Skeleton2, { variant: "text", width: "40%", height: 24 })
|
|
1607
1852
|
] }) }) }, index)) }) })
|
|
1608
1853
|
}
|
|
1609
1854
|
)
|
|
@@ -1611,15 +1856,13 @@ function OverviewPageSkeleton() {
|
|
|
1611
1856
|
}
|
|
1612
1857
|
|
|
1613
1858
|
// src/components/ModelPage.tsx
|
|
1614
|
-
import { usePathname, useSearchParams } from "next/navigation.js";
|
|
1615
|
-
import { useCallback as useCallback3, useEffect as useEffect8, useMemo as useMemo7, useRef, useState as useState8 } from "react";
|
|
1616
1859
|
import AddIcon from "@mui/icons-material/Add";
|
|
1617
1860
|
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
|
|
1618
1861
|
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
|
1619
1862
|
import ExpandMoreIcon4 from "@mui/icons-material/ExpandMore";
|
|
1620
1863
|
import FilterListIcon from "@mui/icons-material/FilterList";
|
|
1621
1864
|
import {
|
|
1622
|
-
Alert as
|
|
1865
|
+
Alert as Alert5,
|
|
1623
1866
|
Box as Box9,
|
|
1624
1867
|
Button as Button4,
|
|
1625
1868
|
Checkbox as Checkbox2,
|
|
@@ -1645,8 +1888,19 @@ import {
|
|
|
1645
1888
|
import { useTheme as useTheme2 } from "@mui/material/styles";
|
|
1646
1889
|
|
|
1647
1890
|
// src/components/DeletePreviewDialog.tsx
|
|
1648
|
-
import {
|
|
1649
|
-
|
|
1891
|
+
import {
|
|
1892
|
+
Alert as Alert4,
|
|
1893
|
+
Box as Box6,
|
|
1894
|
+
Button as Button2,
|
|
1895
|
+
CircularProgress as CircularProgress2,
|
|
1896
|
+
Dialog as Dialog2,
|
|
1897
|
+
DialogActions as DialogActions2,
|
|
1898
|
+
DialogContent as DialogContent2,
|
|
1899
|
+
DialogTitle as DialogTitle2,
|
|
1900
|
+
Stack as Stack6,
|
|
1901
|
+
Typography as Typography3
|
|
1902
|
+
} from "@mui/material";
|
|
1903
|
+
import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1650
1904
|
function DeletePreviewDialog({
|
|
1651
1905
|
open,
|
|
1652
1906
|
title,
|
|
@@ -1680,33 +1934,47 @@ function DeletePreviewDialog({
|
|
|
1680
1934
|
}
|
|
1681
1935
|
},
|
|
1682
1936
|
children: [
|
|
1683
|
-
/* @__PURE__ */
|
|
1937
|
+
/* @__PURE__ */ jsx14(DialogTitle2, { children: title }),
|
|
1684
1938
|
/* @__PURE__ */ jsxs8(DialogContent2, { dividers: true, children: [
|
|
1685
1939
|
isLoading ? /* @__PURE__ */ jsxs8(Stack6, { spacing: 1.5, alignItems: "center", justifyContent: "center", sx: { minHeight: 180 }, children: [
|
|
1686
|
-
/* @__PURE__ */
|
|
1687
|
-
/* @__PURE__ */
|
|
1940
|
+
/* @__PURE__ */ jsx14(CircularProgress2, { size: 28, thickness: 4.2, color: "inherit" }),
|
|
1941
|
+
/* @__PURE__ */ jsx14(Typography3, { color: "text.secondary", children: t("delete_preview_loading") })
|
|
1688
1942
|
] }) : null,
|
|
1689
|
-
!isLoading && error ? /* @__PURE__ */
|
|
1943
|
+
!isLoading && error ? /* @__PURE__ */ jsx14(Alert4, { severity: "error", children: error }) : null,
|
|
1690
1944
|
!isLoading && !error && preview ? /* @__PURE__ */ jsxs8(Stack6, { spacing: 1.5, children: [
|
|
1691
|
-
/* @__PURE__ */
|
|
1692
|
-
!preview.can_delete ? /* @__PURE__ */
|
|
1945
|
+
/* @__PURE__ */ jsx14(Typography3, { color: "text.secondary", children: preview.can_delete ? t("delete_preview_hint") : t("delete_preview_blocked_hint") }),
|
|
1946
|
+
!preview.can_delete ? /* @__PURE__ */ jsx14(Alert4, { severity: "warning", children: t("delete_preview_blocked_hint") }) : null,
|
|
1693
1947
|
/* @__PURE__ */ jsxs8(Stack6, { spacing: 0.5, children: [
|
|
1694
|
-
/* @__PURE__ */
|
|
1695
|
-
/* @__PURE__ */
|
|
1696
|
-
/* @__PURE__ */
|
|
1697
|
-
/* @__PURE__ */
|
|
1698
|
-
/* @__PURE__ */
|
|
1948
|
+
/* @__PURE__ */ jsx14(Typography3, { variant: "body2", color: "text.secondary", children: t("delete_preview_roots", { count: preview.summary.roots }) }),
|
|
1949
|
+
/* @__PURE__ */ jsx14(Typography3, { variant: "body2", color: "text.secondary", children: t("delete_preview_delete", { count: preview.summary.delete }) }),
|
|
1950
|
+
/* @__PURE__ */ jsx14(Typography3, { variant: "body2", color: "text.secondary", children: t("delete_preview_protect", { count: preview.summary.protect }) }),
|
|
1951
|
+
/* @__PURE__ */ jsx14(Typography3, { variant: "body2", color: "text.secondary", children: t("delete_preview_set_null", { count: preview.summary.set_null }) }),
|
|
1952
|
+
/* @__PURE__ */ jsx14(Typography3, { variant: "body2", color: "text.secondary", children: t("delete_preview_total", { count: preview.summary.total }) })
|
|
1699
1953
|
] }),
|
|
1700
|
-
preview.summary.delete === 0 && preview.summary.protect === 0 && preview.summary.set_null === 0 ? /* @__PURE__ */
|
|
1701
|
-
preview.roots.length > 0 ? /* @__PURE__ */
|
|
1954
|
+
preview.summary.delete === 0 && preview.summary.protect === 0 && preview.summary.set_null === 0 ? /* @__PURE__ */ jsx14(Typography3, { variant: "body2", color: "text.secondary", children: t("delete_preview_empty") }) : null,
|
|
1955
|
+
preview.roots.length > 0 ? /* @__PURE__ */ jsx14(Stack6, { spacing: 1, children: preview.roots.map((rootNode, index) => {
|
|
1702
1956
|
var _a;
|
|
1703
|
-
return /* @__PURE__ */
|
|
1704
|
-
|
|
1957
|
+
return /* @__PURE__ */ jsx14(
|
|
1958
|
+
DeletePreviewNode,
|
|
1959
|
+
{
|
|
1960
|
+
node: rootNode,
|
|
1961
|
+
depth: 0
|
|
1962
|
+
},
|
|
1963
|
+
`${(_a = rootNode.model_slug) != null ? _a : "model"}:${rootNode.id}:${index}`
|
|
1964
|
+
);
|
|
1965
|
+
}) }) : /* @__PURE__ */ jsx14(
|
|
1966
|
+
Typography3,
|
|
1967
|
+
{
|
|
1968
|
+
variant: "body2",
|
|
1969
|
+
color: "text.secondary",
|
|
1970
|
+
children: t("delete_preview_no_selection")
|
|
1971
|
+
}
|
|
1972
|
+
)
|
|
1705
1973
|
] }) : null
|
|
1706
1974
|
] }),
|
|
1707
1975
|
/* @__PURE__ */ jsxs8(DialogActions2, { children: [
|
|
1708
|
-
/* @__PURE__ */
|
|
1709
|
-
/* @__PURE__ */
|
|
1976
|
+
/* @__PURE__ */ jsx14(Button2, { onClick: onClose, disabled: isSubmitting, children: t("cancel") }),
|
|
1977
|
+
/* @__PURE__ */ jsx14(
|
|
1710
1978
|
Button2,
|
|
1711
1979
|
{
|
|
1712
1980
|
color: "error",
|
|
@@ -1733,16 +2001,16 @@ function DeletePreviewNode({ node, depth }) {
|
|
|
1733
2001
|
},
|
|
1734
2002
|
children: [
|
|
1735
2003
|
/* @__PURE__ */ jsxs8(Stack6, { spacing: 0.25, children: [
|
|
1736
|
-
/* @__PURE__ */
|
|
2004
|
+
/* @__PURE__ */ jsx14(Typography3, { sx: { fontWeight: 600 }, children: node.label }),
|
|
1737
2005
|
/* @__PURE__ */ jsxs8(Typography3, { variant: "body2", color: "text.secondary", children: [
|
|
1738
2006
|
node.model_title,
|
|
1739
2007
|
node.relation_name ? ` \u2022 ${node.relation_name}` : "",
|
|
1740
2008
|
` \u2022 ${getEffectLabel(node.effect, t)}`
|
|
1741
2009
|
] })
|
|
1742
2010
|
] }),
|
|
1743
|
-
node.children.length > 0 ? /* @__PURE__ */
|
|
2011
|
+
node.children.length > 0 ? /* @__PURE__ */ jsx14(Stack6, { spacing: 0.75, sx: { mt: 1 }, children: node.children.map((childNode, index) => {
|
|
1744
2012
|
var _a;
|
|
1745
|
-
return /* @__PURE__ */
|
|
2013
|
+
return /* @__PURE__ */ jsx14(
|
|
1746
2014
|
DeletePreviewNode,
|
|
1747
2015
|
{
|
|
1748
2016
|
node: childNode,
|
|
@@ -1766,10 +2034,19 @@ function getEffectLabel(effect, t) {
|
|
|
1766
2034
|
}
|
|
1767
2035
|
|
|
1768
2036
|
// src/components/model-page/ListFiltersBar.tsx
|
|
1769
|
-
import { memo as memo3, useCallback as
|
|
1770
|
-
import {
|
|
1771
|
-
|
|
1772
|
-
|
|
2037
|
+
import { memo as memo3, useCallback as useCallback3, useEffect as useEffect7, useMemo as useMemo7, useState as useState7 } from "react";
|
|
2038
|
+
import {
|
|
2039
|
+
Autocomplete as Autocomplete2,
|
|
2040
|
+
Button as Button3,
|
|
2041
|
+
CircularProgress as CircularProgress3,
|
|
2042
|
+
Divider,
|
|
2043
|
+
MenuItem,
|
|
2044
|
+
Paper as Paper4,
|
|
2045
|
+
Stack as Stack7,
|
|
2046
|
+
TextField as TextField2,
|
|
2047
|
+
Typography as Typography4
|
|
2048
|
+
} from "@mui/material";
|
|
2049
|
+
import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1773
2050
|
var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
|
|
1774
2051
|
client,
|
|
1775
2052
|
slug,
|
|
@@ -1780,7 +2057,7 @@ var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
|
|
|
1780
2057
|
debounceMs = 300
|
|
1781
2058
|
}) {
|
|
1782
2059
|
const t = useAdminTranslation();
|
|
1783
|
-
const filterGroups =
|
|
2060
|
+
const filterGroups = useMemo7(() => {
|
|
1784
2061
|
var _a, _b;
|
|
1785
2062
|
const groupedFilters = /* @__PURE__ */ new Map();
|
|
1786
2063
|
for (const filter of filters) {
|
|
@@ -1799,12 +2076,12 @@ var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
|
|
|
1799
2076
|
}
|
|
1800
2077
|
return Array.from(groupedFilters.values());
|
|
1801
2078
|
}, [filters]);
|
|
1802
|
-
const activeFiltersCount =
|
|
2079
|
+
const activeFiltersCount = useMemo7(
|
|
1803
2080
|
() => filters.filter((filter) => Boolean(values[filter.slug])).length,
|
|
1804
2081
|
[filters, values]
|
|
1805
2082
|
);
|
|
1806
2083
|
if (filters.length === 0) return null;
|
|
1807
|
-
return /* @__PURE__ */
|
|
2084
|
+
return /* @__PURE__ */ jsx15(
|
|
1808
2085
|
Paper4,
|
|
1809
2086
|
{
|
|
1810
2087
|
sx: {
|
|
@@ -1819,10 +2096,10 @@ var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
|
|
|
1819
2096
|
children: /* @__PURE__ */ jsxs9(Stack7, { spacing: 1.5, children: [
|
|
1820
2097
|
/* @__PURE__ */ jsxs9(Stack7, { direction: "row", spacing: 1, alignItems: "center", justifyContent: "space-between", children: [
|
|
1821
2098
|
/* @__PURE__ */ jsxs9(Stack7, { spacing: 0.25, children: [
|
|
1822
|
-
/* @__PURE__ */
|
|
1823
|
-
activeFiltersCount > 0 ? /* @__PURE__ */
|
|
2099
|
+
/* @__PURE__ */ jsx15(Typography4, { sx: { fontSize: 15, fontWeight: 700 }, children: t("filters") }),
|
|
2100
|
+
activeFiltersCount > 0 ? /* @__PURE__ */ jsx15(Typography4, { color: "text.secondary", sx: { fontSize: 12 }, children: t("active_filters", { count: activeFiltersCount }) }) : null
|
|
1824
2101
|
] }),
|
|
1825
|
-
/* @__PURE__ */
|
|
2102
|
+
/* @__PURE__ */ jsx15(
|
|
1826
2103
|
Button3,
|
|
1827
2104
|
{
|
|
1828
2105
|
size: "small",
|
|
@@ -1833,8 +2110,8 @@ var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
|
|
|
1833
2110
|
}
|
|
1834
2111
|
)
|
|
1835
2112
|
] }),
|
|
1836
|
-
/* @__PURE__ */
|
|
1837
|
-
filterGroups.map((group) => /* @__PURE__ */
|
|
2113
|
+
/* @__PURE__ */ jsx15(Divider, {}),
|
|
2114
|
+
filterGroups.map((group) => /* @__PURE__ */ jsx15(
|
|
1838
2115
|
FilterGroupSection,
|
|
1839
2116
|
{
|
|
1840
2117
|
client,
|
|
@@ -1852,10 +2129,10 @@ var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
|
|
|
1852
2129
|
});
|
|
1853
2130
|
function FilterGroupSection({ client, slug, group, values, onChange, debounceMs }) {
|
|
1854
2131
|
return /* @__PURE__ */ jsxs9(Stack7, { spacing: 1, children: [
|
|
1855
|
-
/* @__PURE__ */
|
|
1856
|
-
/* @__PURE__ */
|
|
2132
|
+
/* @__PURE__ */ jsx15(Typography4, { sx: { fontSize: 13, fontWeight: 700, color: "text.secondary" }, children: group.title }),
|
|
2133
|
+
/* @__PURE__ */ jsx15(Stack7, { spacing: 1, children: group.filters.map((filter) => {
|
|
1857
2134
|
var _a;
|
|
1858
|
-
return /* @__PURE__ */
|
|
2135
|
+
return /* @__PURE__ */ jsx15(
|
|
1859
2136
|
ListFilterField,
|
|
1860
2137
|
{
|
|
1861
2138
|
client,
|
|
@@ -1871,52 +2148,44 @@ function FilterGroupSection({ client, slug, group, values, onChange, debounceMs
|
|
|
1871
2148
|
] });
|
|
1872
2149
|
}
|
|
1873
2150
|
function ListFilterField({ client, slug, filter, value, onChange, debounceMs }) {
|
|
1874
|
-
var _a;
|
|
2151
|
+
var _a, _b;
|
|
1875
2152
|
const t = useAdminTranslation();
|
|
1876
|
-
const [draftValue, setDraftValue] =
|
|
1877
|
-
const [
|
|
1878
|
-
const
|
|
1879
|
-
|
|
1880
|
-
|
|
2153
|
+
const [draftValue, setDraftValue] = useState7(value);
|
|
2154
|
+
const [searchValue, setSearchValue] = useState7("");
|
|
2155
|
+
const loadChoices = useCallback3(
|
|
2156
|
+
async (signal) => {
|
|
2157
|
+
const response = await client.getFilterChoices(
|
|
2158
|
+
slug,
|
|
2159
|
+
filter.slug,
|
|
2160
|
+
searchValue || void 0,
|
|
2161
|
+
value ? [value] : void 0,
|
|
2162
|
+
{ signal }
|
|
2163
|
+
);
|
|
2164
|
+
return response.items.map((item) => ({
|
|
2165
|
+
value: String(item.id),
|
|
2166
|
+
label: item.label
|
|
2167
|
+
}));
|
|
2168
|
+
},
|
|
2169
|
+
[client, filter.slug, searchValue, slug, value]
|
|
2170
|
+
);
|
|
2171
|
+
const { items: options, isLoading: isLoadingChoices } = useRemoteChoices({
|
|
2172
|
+
enabled: filter.has_choices && filter.input_kind === "select",
|
|
2173
|
+
debounceMs,
|
|
2174
|
+
initialItems: filter.options,
|
|
2175
|
+
resetKey: `${slug}:${filter.slug}`,
|
|
2176
|
+
queryKey: `${slug}:${filter.slug}:${searchValue}:${value}`,
|
|
2177
|
+
load: loadChoices
|
|
2178
|
+
});
|
|
2179
|
+
useEffect7(() => {
|
|
1881
2180
|
setDraftValue(value);
|
|
1882
2181
|
}, [value]);
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
setIsChoicesLoaded(filter.options.length > 0);
|
|
2182
|
+
useEffect7(() => {
|
|
2183
|
+
setSearchValue("");
|
|
1886
2184
|
}, [filter.slug]);
|
|
1887
|
-
|
|
1888
|
-
if (filter.
|
|
1889
|
-
return;
|
|
1890
|
-
}
|
|
1891
|
-
setOptions(filter.options);
|
|
1892
|
-
setIsChoicesLoaded(true);
|
|
1893
|
-
}, [filter.options]);
|
|
1894
|
-
const loadChoices = useCallback2(async () => {
|
|
1895
|
-
if (!filter.has_choices || filter.input_kind !== "select" || isChoicesLoaded) {
|
|
2185
|
+
useEffect7(() => {
|
|
2186
|
+
if (filter.input_kind !== "text") {
|
|
1896
2187
|
return;
|
|
1897
2188
|
}
|
|
1898
|
-
const requestKey = `${slug}:${filter.slug}`;
|
|
1899
|
-
const existingRequest = inFlightFilterChoicesRequests.get(requestKey);
|
|
1900
|
-
const request = existingRequest != null ? existingRequest : client.getFilterChoices(slug, filter.slug).then((response) => response.items.map((item) => ({
|
|
1901
|
-
value: String(item.id),
|
|
1902
|
-
label: item.label
|
|
1903
|
-
}))).finally(() => {
|
|
1904
|
-
inFlightFilterChoicesRequests.delete(requestKey);
|
|
1905
|
-
});
|
|
1906
|
-
if (!existingRequest) {
|
|
1907
|
-
inFlightFilterChoicesRequests.set(requestKey, request);
|
|
1908
|
-
}
|
|
1909
|
-
setIsLoadingChoices(true);
|
|
1910
|
-
try {
|
|
1911
|
-
const nextOptions = await request;
|
|
1912
|
-
setOptions(nextOptions);
|
|
1913
|
-
setIsChoicesLoaded(true);
|
|
1914
|
-
} finally {
|
|
1915
|
-
setIsLoadingChoices(false);
|
|
1916
|
-
}
|
|
1917
|
-
}, [client, filter.has_choices, filter.input_kind, filter.slug, isChoicesLoaded, slug]);
|
|
1918
|
-
useEffect6(() => {
|
|
1919
|
-
if (filter.input_kind !== "text") return;
|
|
1920
2189
|
const timeoutId = window.setTimeout(() => {
|
|
1921
2190
|
if (draftValue !== value) {
|
|
1922
2191
|
onChange(filter.slug, draftValue);
|
|
@@ -1926,23 +2195,7 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
|
|
|
1926
2195
|
window.clearTimeout(timeoutId);
|
|
1927
2196
|
};
|
|
1928
2197
|
}, [debounceMs, draftValue, filter.input_kind, filter.slug, onChange, value]);
|
|
1929
|
-
|
|
1930
|
-
if (!value || !filter.has_choices || filter.input_kind !== "select" || isChoicesLoaded) {
|
|
1931
|
-
return;
|
|
1932
|
-
}
|
|
1933
|
-
let isCancelled = false;
|
|
1934
|
-
void loadChoices().then(() => {
|
|
1935
|
-
if (isCancelled) return;
|
|
1936
|
-
}).catch(() => {
|
|
1937
|
-
if (isCancelled) return;
|
|
1938
|
-
setOptions([]);
|
|
1939
|
-
setIsChoicesLoaded(false);
|
|
1940
|
-
});
|
|
1941
|
-
return () => {
|
|
1942
|
-
isCancelled = true;
|
|
1943
|
-
};
|
|
1944
|
-
}, [filter.has_choices, filter.input_kind, isChoicesLoaded, loadChoices, value]);
|
|
1945
|
-
if (filter.input_kind === "boolean" || filter.input_kind === "select") {
|
|
2198
|
+
if (filter.input_kind === "boolean") {
|
|
1946
2199
|
return /* @__PURE__ */ jsxs9(
|
|
1947
2200
|
TextField2,
|
|
1948
2201
|
{
|
|
@@ -1952,27 +2205,66 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
|
|
|
1952
2205
|
label: filter.label,
|
|
1953
2206
|
value,
|
|
1954
2207
|
onChange: (event) => onChange(filter.slug, event.target.value),
|
|
1955
|
-
slotProps: {
|
|
1956
|
-
select: filter.input_kind === "select" ? { onOpen: () => void loadChoices() } : void 0
|
|
1957
|
-
},
|
|
1958
2208
|
children: [
|
|
1959
|
-
/* @__PURE__ */
|
|
1960
|
-
|
|
1961
|
-
/* @__PURE__ */ jsx14(CircularProgress3, { size: 14, thickness: 5 }),
|
|
1962
|
-
/* @__PURE__ */ jsx14(Typography4, { variant: "body2", children: t("loading") })
|
|
1963
|
-
] }) }) : null,
|
|
1964
|
-
options.map((option) => /* @__PURE__ */ jsx14(MenuItem, { value: option.value, children: option.label }, `${filter.slug}-${option.value}`))
|
|
2209
|
+
/* @__PURE__ */ jsx15(MenuItem, { value: "", children: t("all") }),
|
|
2210
|
+
filter.options.map((option) => /* @__PURE__ */ jsx15(MenuItem, { value: option.value, children: option.label }, `${filter.slug}-${option.value}`))
|
|
1965
2211
|
]
|
|
1966
2212
|
}
|
|
1967
2213
|
);
|
|
1968
2214
|
}
|
|
1969
|
-
|
|
2215
|
+
if (filter.input_kind === "select") {
|
|
2216
|
+
const selectedOption = (_a = options.find((option) => option.value === value)) != null ? _a : value ? {
|
|
2217
|
+
value,
|
|
2218
|
+
label: value
|
|
2219
|
+
} : null;
|
|
2220
|
+
return /* @__PURE__ */ jsx15(
|
|
2221
|
+
Autocomplete2,
|
|
2222
|
+
{
|
|
2223
|
+
options,
|
|
2224
|
+
value: selectedOption,
|
|
2225
|
+
loading: isLoadingChoices,
|
|
2226
|
+
filterOptions: (items) => items,
|
|
2227
|
+
size: "small",
|
|
2228
|
+
disablePortal: true,
|
|
2229
|
+
isOptionEqualToValue: (option, selected) => option.value === selected.value,
|
|
2230
|
+
getOptionLabel: (option) => option.label,
|
|
2231
|
+
onChange: (_, nextValue) => {
|
|
2232
|
+
var _a2;
|
|
2233
|
+
return onChange(filter.slug, (_a2 = nextValue == null ? void 0 : nextValue.value) != null ? _a2 : "");
|
|
2234
|
+
},
|
|
2235
|
+
onInputChange: (_, nextInputValue) => setSearchValue(nextInputValue),
|
|
2236
|
+
renderInput: (params) => (() => {
|
|
2237
|
+
var _a2;
|
|
2238
|
+
const { InputProps, inputProps, ...textFieldParams } = params;
|
|
2239
|
+
return /* @__PURE__ */ jsx15(
|
|
2240
|
+
TextField2,
|
|
2241
|
+
{
|
|
2242
|
+
...textFieldParams,
|
|
2243
|
+
label: filter.label,
|
|
2244
|
+
placeholder: (_a2 = filter.placeholder) != null ? _a2 : t("search"),
|
|
2245
|
+
slotProps: {
|
|
2246
|
+
input: {
|
|
2247
|
+
...InputProps,
|
|
2248
|
+
endAdornment: /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
2249
|
+
isLoadingChoices ? /* @__PURE__ */ jsx15(CircularProgress3, { color: "inherit", size: 16 }) : null,
|
|
2250
|
+
InputProps.endAdornment
|
|
2251
|
+
] })
|
|
2252
|
+
},
|
|
2253
|
+
htmlInput: inputProps
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
);
|
|
2257
|
+
})()
|
|
2258
|
+
}
|
|
2259
|
+
);
|
|
2260
|
+
}
|
|
2261
|
+
return /* @__PURE__ */ jsx15(
|
|
1970
2262
|
TextField2,
|
|
1971
2263
|
{
|
|
1972
2264
|
size: "small",
|
|
1973
2265
|
fullWidth: true,
|
|
1974
2266
|
label: filter.label,
|
|
1975
|
-
placeholder: (
|
|
2267
|
+
placeholder: (_b = filter.placeholder) != null ? _b : void 0,
|
|
1976
2268
|
value: draftValue,
|
|
1977
2269
|
onChange: (event) => setDraftValue(event.target.value)
|
|
1978
2270
|
}
|
|
@@ -1983,7 +2275,7 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
|
|
|
1983
2275
|
import { memo as memo4 } from "react";
|
|
1984
2276
|
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
|
1985
2277
|
import { Box as Box7, Checkbox, IconButton as IconButton2, TableCell, TableRow } from "@mui/material";
|
|
1986
|
-
import { jsx as
|
|
2278
|
+
import { jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1987
2279
|
var ListRow = memo4(function ListRow2({
|
|
1988
2280
|
row,
|
|
1989
2281
|
pkField,
|
|
@@ -2013,7 +2305,7 @@ var ListRow = memo4(function ListRow2({
|
|
|
2013
2305
|
}
|
|
2014
2306
|
},
|
|
2015
2307
|
children: [
|
|
2016
|
-
/* @__PURE__ */
|
|
2308
|
+
/* @__PURE__ */ jsx16(
|
|
2017
2309
|
TableCell,
|
|
2018
2310
|
{
|
|
2019
2311
|
padding: "none",
|
|
@@ -2025,7 +2317,7 @@ var ListRow = memo4(function ListRow2({
|
|
|
2025
2317
|
textAlign: "center",
|
|
2026
2318
|
px: 1
|
|
2027
2319
|
},
|
|
2028
|
-
children: /* @__PURE__ */
|
|
2320
|
+
children: /* @__PURE__ */ jsx16(
|
|
2029
2321
|
Checkbox,
|
|
2030
2322
|
{
|
|
2031
2323
|
checked: isSelected,
|
|
@@ -2050,7 +2342,7 @@ var ListRow = memo4(function ListRow2({
|
|
|
2050
2342
|
textOverflow: "ellipsis"
|
|
2051
2343
|
};
|
|
2052
2344
|
if (imageUrl) {
|
|
2053
|
-
return /* @__PURE__ */
|
|
2345
|
+
return /* @__PURE__ */ jsx16(TableCell, { title: fullFieldValue, sx: { ...commonCellSx, py: 0.75 }, children: /* @__PURE__ */ jsx16(
|
|
2054
2346
|
Box7,
|
|
2055
2347
|
{
|
|
2056
2348
|
component: "img",
|
|
@@ -2068,7 +2360,7 @@ var ListRow = memo4(function ListRow2({
|
|
|
2068
2360
|
) }, fieldName);
|
|
2069
2361
|
}
|
|
2070
2362
|
if (index === 0) {
|
|
2071
|
-
return /* @__PURE__ */
|
|
2363
|
+
return /* @__PURE__ */ jsx16(
|
|
2072
2364
|
TableCell,
|
|
2073
2365
|
{
|
|
2074
2366
|
title: fullFieldValue,
|
|
@@ -2086,7 +2378,7 @@ var ListRow = memo4(function ListRow2({
|
|
|
2086
2378
|
color: "primary.main"
|
|
2087
2379
|
}
|
|
2088
2380
|
},
|
|
2089
|
-
children: /* @__PURE__ */
|
|
2381
|
+
children: /* @__PURE__ */ jsx16(
|
|
2090
2382
|
NavLink,
|
|
2091
2383
|
{
|
|
2092
2384
|
href: `${basePath}/${slug}/${rowId}`,
|
|
@@ -2099,9 +2391,9 @@ var ListRow = memo4(function ListRow2({
|
|
|
2099
2391
|
fieldName
|
|
2100
2392
|
);
|
|
2101
2393
|
}
|
|
2102
|
-
return /* @__PURE__ */
|
|
2394
|
+
return /* @__PURE__ */ jsx16(TableCell, { title: fullFieldValue, sx: commonCellSx, children: fieldValue }, fieldName);
|
|
2103
2395
|
}),
|
|
2104
|
-
/* @__PURE__ */
|
|
2396
|
+
/* @__PURE__ */ jsx16(
|
|
2105
2397
|
TableCell,
|
|
2106
2398
|
{
|
|
2107
2399
|
align: "right",
|
|
@@ -2110,7 +2402,7 @@ var ListRow = memo4(function ListRow2({
|
|
|
2110
2402
|
minWidth: actionsColumnWidth,
|
|
2111
2403
|
maxWidth: actionsColumnWidth
|
|
2112
2404
|
},
|
|
2113
|
-
children: /* @__PURE__ */
|
|
2405
|
+
children: /* @__PURE__ */ jsx16(IconButton2, { size: "small", onClick: (event) => onOpenMenu(event, rowId), children: /* @__PURE__ */ jsx16(MoreVertIcon, { fontSize: "small" }) })
|
|
2114
2406
|
}
|
|
2115
2407
|
)
|
|
2116
2408
|
]
|
|
@@ -2119,20 +2411,20 @@ var ListRow = memo4(function ListRow2({
|
|
|
2119
2411
|
});
|
|
2120
2412
|
|
|
2121
2413
|
// src/components/model-page/SearchField.tsx
|
|
2122
|
-
import { memo as memo5, useEffect as
|
|
2414
|
+
import { memo as memo5, useEffect as useEffect8, useState as useState8 } from "react";
|
|
2123
2415
|
import { TextField as TextField3 } from "@mui/material";
|
|
2124
|
-
import { jsx as
|
|
2416
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
2125
2417
|
var SearchField = memo5(function SearchField2({
|
|
2126
2418
|
value,
|
|
2127
2419
|
onCommit,
|
|
2128
2420
|
debounceMs,
|
|
2129
2421
|
placeholder
|
|
2130
2422
|
}) {
|
|
2131
|
-
const [draftValue, setDraftValue] =
|
|
2132
|
-
|
|
2423
|
+
const [draftValue, setDraftValue] = useState8(value);
|
|
2424
|
+
useEffect8(() => {
|
|
2133
2425
|
setDraftValue(value);
|
|
2134
2426
|
}, [value]);
|
|
2135
|
-
|
|
2427
|
+
useEffect8(() => {
|
|
2136
2428
|
const timerId = window.setTimeout(() => {
|
|
2137
2429
|
if (draftValue !== value) {
|
|
2138
2430
|
onCommit(draftValue);
|
|
@@ -2142,7 +2434,7 @@ var SearchField = memo5(function SearchField2({
|
|
|
2142
2434
|
window.clearTimeout(timerId);
|
|
2143
2435
|
};
|
|
2144
2436
|
}, [debounceMs, draftValue, onCommit, value]);
|
|
2145
|
-
return /* @__PURE__ */
|
|
2437
|
+
return /* @__PURE__ */ jsx17(
|
|
2146
2438
|
TextField3,
|
|
2147
2439
|
{
|
|
2148
2440
|
size: "small",
|
|
@@ -2160,98 +2452,157 @@ var SearchField = memo5(function SearchField2({
|
|
|
2160
2452
|
);
|
|
2161
2453
|
});
|
|
2162
2454
|
|
|
2163
|
-
// src/components/model-page/
|
|
2164
|
-
import {
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
/* @__PURE__ */ jsx17(Skeleton3, { variant: "rounded", width: 128, height: 40 }),
|
|
2172
|
-
/* @__PURE__ */ jsx17(Box8, { sx: { flex: 1 } }),
|
|
2173
|
-
/* @__PURE__ */ jsx17(Skeleton3, { variant: "rounded", width: 110, height: 24 })
|
|
2174
|
-
] }) }),
|
|
2175
|
-
/* @__PURE__ */ jsx17(Paper5, { sx: { borderRadius: "10px", flex: 1, minHeight: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx17(ModelTableSkeleton, {}) })
|
|
2176
|
-
] });
|
|
2455
|
+
// src/components/model-page/useModelPageController.ts
|
|
2456
|
+
import { useCallback as useCallback4, useEffect as useEffect9, useMemo as useMemo8, useRef as useRef3, useState as useState9 } from "react";
|
|
2457
|
+
|
|
2458
|
+
// src/cache.ts
|
|
2459
|
+
var MAX_CACHE_ENTRIES = 100;
|
|
2460
|
+
var clientCaches = /* @__PURE__ */ new WeakMap();
|
|
2461
|
+
function buildDetailCacheKey(slug, id) {
|
|
2462
|
+
return `detail:${slug}:${id}`;
|
|
2177
2463
|
}
|
|
2178
|
-
function
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2464
|
+
function buildListCacheKey(slug, params) {
|
|
2465
|
+
const { q, sort, limit, offset, ...filters } = params;
|
|
2466
|
+
return `list:${slug}:${JSON.stringify({
|
|
2467
|
+
q: q != null ? q : null,
|
|
2468
|
+
sort: sort != null ? sort : null,
|
|
2469
|
+
limit: limit != null ? limit : 50,
|
|
2470
|
+
offset: offset != null ? offset : 0,
|
|
2471
|
+
filters: Object.fromEntries(
|
|
2472
|
+
Object.entries(filters).filter(([, value]) => value !== void 0 && value !== null && value !== "").sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey))
|
|
2473
|
+
)
|
|
2474
|
+
})}`;
|
|
2475
|
+
}
|
|
2476
|
+
function getClientCacheBucket(client) {
|
|
2477
|
+
const existingBucket = clientCaches.get(client);
|
|
2478
|
+
if (existingBucket) {
|
|
2479
|
+
return existingBucket;
|
|
2480
|
+
}
|
|
2481
|
+
const nextBucket = {
|
|
2482
|
+
detailResponseCache: /* @__PURE__ */ new Map(),
|
|
2483
|
+
inFlightDetailRequests: /* @__PURE__ */ new Map(),
|
|
2484
|
+
listResponseCache: /* @__PURE__ */ new Map(),
|
|
2485
|
+
inFlightListRequests: /* @__PURE__ */ new Map(),
|
|
2486
|
+
modelVersions: /* @__PURE__ */ new Map()
|
|
2487
|
+
};
|
|
2488
|
+
clientCaches.set(client, nextBucket);
|
|
2489
|
+
return nextBucket;
|
|
2490
|
+
}
|
|
2491
|
+
function getModelCacheVersion(client, slug) {
|
|
2492
|
+
var _a;
|
|
2493
|
+
return (_a = getClientCacheBucket(client).modelVersions.get(slug)) != null ? _a : 0;
|
|
2494
|
+
}
|
|
2495
|
+
function setCachedListResponse(client, key, response) {
|
|
2496
|
+
setBoundedMapEntry(getClientCacheBucket(client).listResponseCache, key, response);
|
|
2497
|
+
}
|
|
2498
|
+
function setCachedDetailResponse(client, key, response) {
|
|
2499
|
+
setBoundedMapEntry(getClientCacheBucket(client).detailResponseCache, key, response);
|
|
2500
|
+
}
|
|
2501
|
+
function invalidateModelCache(client, slug) {
|
|
2502
|
+
const bucket = getClientCacheBucket(client);
|
|
2503
|
+
bucket.modelVersions.set(slug, getModelCacheVersion(client, slug) + 1);
|
|
2504
|
+
for (const key of bucket.listResponseCache.keys()) {
|
|
2505
|
+
if (key.startsWith(`list:${slug}:`)) {
|
|
2506
|
+
bucket.listResponseCache.delete(key);
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
for (const key of bucket.inFlightListRequests.keys()) {
|
|
2510
|
+
if (key.startsWith(`list:${slug}:`)) {
|
|
2511
|
+
bucket.inFlightListRequests.delete(key);
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
for (const key of bucket.detailResponseCache.keys()) {
|
|
2515
|
+
if (key.startsWith(`detail:${slug}:`)) {
|
|
2516
|
+
bucket.detailResponseCache.delete(key);
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
for (const key of bucket.inFlightDetailRequests.keys()) {
|
|
2520
|
+
if (key.startsWith(`detail:${slug}:`)) {
|
|
2521
|
+
bucket.inFlightDetailRequests.delete(key);
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
function setBoundedMapEntry(map, key, value) {
|
|
2526
|
+
if (map.has(key)) {
|
|
2527
|
+
map.delete(key);
|
|
2528
|
+
}
|
|
2529
|
+
map.set(key, value);
|
|
2530
|
+
while (map.size > MAX_CACHE_ENTRIES) {
|
|
2531
|
+
const oldestKey = map.keys().next().value;
|
|
2532
|
+
if (!oldestKey) {
|
|
2533
|
+
break;
|
|
2534
|
+
}
|
|
2535
|
+
map.delete(oldestKey);
|
|
2536
|
+
}
|
|
2183
2537
|
}
|
|
2184
2538
|
|
|
2185
|
-
// src/components/
|
|
2186
|
-
import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2539
|
+
// src/components/model-page/useModelPageController.ts
|
|
2187
2540
|
var DEFAULT_PAGE_SIZE = 50;
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2541
|
+
function useModelPageController({
|
|
2542
|
+
client,
|
|
2543
|
+
slug,
|
|
2544
|
+
pathname,
|
|
2545
|
+
locationSearch,
|
|
2546
|
+
router,
|
|
2547
|
+
t
|
|
2548
|
+
}) {
|
|
2194
2549
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
2195
|
-
const
|
|
2196
|
-
const t = useAdminTranslation();
|
|
2197
|
-
const pathname = usePathname();
|
|
2198
|
-
const searchParams = useSearchParams();
|
|
2550
|
+
const searchParams = useMemo8(() => new URLSearchParams(locationSearch), [locationSearch]);
|
|
2199
2551
|
const initialQuery = (_a = searchParams.get("q")) != null ? _a : "";
|
|
2200
2552
|
const initialSort = (_b = searchParams.get("sort")) != null ? _b : "";
|
|
2201
2553
|
const initialPage = parsePageParam(searchParams.get("page"));
|
|
2202
2554
|
const initialFilters = extractFilterParams(searchParams);
|
|
2203
|
-
const initialCachedResponse =
|
|
2204
|
-
slug,
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
const [
|
|
2213
|
-
const [
|
|
2214
|
-
const [
|
|
2215
|
-
const [
|
|
2216
|
-
const [
|
|
2217
|
-
const [
|
|
2218
|
-
const [
|
|
2219
|
-
const [
|
|
2220
|
-
const [
|
|
2221
|
-
const [
|
|
2222
|
-
const [
|
|
2223
|
-
const [
|
|
2224
|
-
const [
|
|
2225
|
-
const [
|
|
2226
|
-
const [
|
|
2227
|
-
const [
|
|
2228
|
-
const [
|
|
2229
|
-
const [
|
|
2230
|
-
const [
|
|
2231
|
-
const [
|
|
2232
|
-
const
|
|
2233
|
-
const
|
|
2234
|
-
const
|
|
2235
|
-
const
|
|
2236
|
-
const
|
|
2237
|
-
const
|
|
2238
|
-
const
|
|
2239
|
-
const
|
|
2240
|
-
const
|
|
2241
|
-
const pageSize = (_g = meta == null ? void 0 : meta.page_size) != null ? _g : pageSizeRef.current;
|
|
2555
|
+
const initialCachedResponse = (_c = getClientCacheBucket(client).listResponseCache.get(
|
|
2556
|
+
buildListCacheKey(slug, {
|
|
2557
|
+
q: initialQuery || void 0,
|
|
2558
|
+
sort: initialSort || void 0,
|
|
2559
|
+
limit: DEFAULT_PAGE_SIZE,
|
|
2560
|
+
offset: (initialPage - 1) * DEFAULT_PAGE_SIZE,
|
|
2561
|
+
...initialFilters
|
|
2562
|
+
})
|
|
2563
|
+
)) != null ? _c : null;
|
|
2564
|
+
const [selectedIds, setSelectedIds] = useState9([]);
|
|
2565
|
+
const [createOpen, setCreateOpen] = useState9(false);
|
|
2566
|
+
const [data, setData] = useState9(() => initialCachedResponse);
|
|
2567
|
+
const [error, setError] = useState9(null);
|
|
2568
|
+
const [isLoading, setIsLoading] = useState9(initialCachedResponse === null);
|
|
2569
|
+
const [rowActionMenuAnchor, setRowActionMenuAnchor] = useState9(null);
|
|
2570
|
+
const [rowActionMenuId, setRowActionMenuId] = useState9(null);
|
|
2571
|
+
const [bulkActionMenuAnchor, setBulkActionMenuAnchor] = useState9(null);
|
|
2572
|
+
const [appliedQuery, setAppliedQuery] = useState9(initialQuery);
|
|
2573
|
+
const [sortValue, setSortValue] = useState9(initialSort);
|
|
2574
|
+
const [currentPage, setCurrentPage] = useState9(initialPage);
|
|
2575
|
+
const [pageInput, setPageInput] = useState9(String(initialPage));
|
|
2576
|
+
const [appliedFilters, setAppliedFilters] = useState9(initialFilters);
|
|
2577
|
+
const [deletePreviewOpen, setDeletePreviewOpen] = useState9(false);
|
|
2578
|
+
const [deletePreview, setDeletePreview] = useState9(null);
|
|
2579
|
+
const [deletePreviewError, setDeletePreviewError] = useState9(null);
|
|
2580
|
+
const [isDeletePreviewLoading, setIsDeletePreviewLoading] = useState9(false);
|
|
2581
|
+
const [isDeleteSubmitting, setIsDeleteSubmitting] = useState9(false);
|
|
2582
|
+
const [pendingDeleteIds, setPendingDeleteIds] = useState9([]);
|
|
2583
|
+
const [pendingDeleteMode, setPendingDeleteMode] = useState9("single");
|
|
2584
|
+
const [filtersOpen, setFiltersOpen] = useState9(false);
|
|
2585
|
+
const requestIdRef = useRef3(0);
|
|
2586
|
+
const dataRef = useRef3(initialCachedResponse);
|
|
2587
|
+
const pageSizeRef = useRef3((_d = initialCachedResponse == null ? void 0 : initialCachedResponse.meta.page_size) != null ? _d : DEFAULT_PAGE_SIZE);
|
|
2588
|
+
const sortFields = useMemo8(() => sortValue.split(",").filter(Boolean), [sortValue]);
|
|
2589
|
+
const meta = (_e = data == null ? void 0 : data.meta) != null ? _e : null;
|
|
2590
|
+
const rows = (_f = data == null ? void 0 : data.items) != null ? _f : [];
|
|
2591
|
+
const total = (_g = data == null ? void 0 : data.pagination.total) != null ? _g : 0;
|
|
2592
|
+
const pageSize = (_h = meta == null ? void 0 : meta.page_size) != null ? _h : pageSizeRef.current;
|
|
2242
2593
|
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
2243
|
-
const fieldMap =
|
|
2594
|
+
const fieldMap = useMemo8(
|
|
2244
2595
|
() => {
|
|
2245
2596
|
var _a2;
|
|
2246
2597
|
return new Map(((_a2 = meta == null ? void 0 : meta.fields) != null ? _a2 : []).map((field) => [field.name, field]));
|
|
2247
2598
|
},
|
|
2248
2599
|
[meta == null ? void 0 : meta.fields]
|
|
2249
2600
|
);
|
|
2250
|
-
const listFields = (
|
|
2251
|
-
const listFilters = (
|
|
2601
|
+
const listFields = (_i = meta == null ? void 0 : meta.list_fields) != null ? _i : [];
|
|
2602
|
+
const listFilters = (_j = meta == null ? void 0 : meta.list_filters) != null ? _j : [];
|
|
2252
2603
|
const hasListFilters = listFilters.length > 0;
|
|
2253
|
-
const bulkActions = (
|
|
2254
|
-
const selectedIdSet =
|
|
2604
|
+
const bulkActions = (_k = meta == null ? void 0 : meta.bulk_actions) != null ? _k : [];
|
|
2605
|
+
const selectedIdSet = useMemo8(() => new Set(selectedIds.map((item) => String(item))), [selectedIds]);
|
|
2255
2606
|
const allVisibleSelected = rows.length > 0 && rows.every((row) => {
|
|
2256
2607
|
var _a2;
|
|
2257
2608
|
return selectedIdSet.has(String(row[(_a2 = meta == null ? void 0 : meta.pk_field) != null ? _a2 : "id"]));
|
|
@@ -2260,34 +2611,27 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2260
2611
|
var _a2;
|
|
2261
2612
|
return selectedIdSet.has(String(row[(_a2 = meta == null ? void 0 : meta.pk_field) != null ? _a2 : "id"]));
|
|
2262
2613
|
});
|
|
2263
|
-
|
|
2264
|
-
useEffect8(() => {
|
|
2614
|
+
useEffect9(() => {
|
|
2265
2615
|
dataRef.current = data;
|
|
2266
2616
|
}, [data]);
|
|
2267
|
-
|
|
2617
|
+
useEffect9(() => {
|
|
2268
2618
|
setPageInput(String(currentPage));
|
|
2269
2619
|
}, [currentPage]);
|
|
2270
|
-
|
|
2271
|
-
const handlePopState = () => {
|
|
2272
|
-
var _a2, _b2;
|
|
2273
|
-
const params = new URLSearchParams(window.location.search);
|
|
2274
|
-
const nextQuery = (_a2 = params.get("q")) != null ? _a2 : "";
|
|
2275
|
-
const nextSort = (_b2 = params.get("sort")) != null ? _b2 : "";
|
|
2276
|
-
const nextPage = parsePageParam(params.get("page"));
|
|
2277
|
-
const nextFilters = extractFilterParams(params);
|
|
2278
|
-
setAppliedQuery(nextQuery);
|
|
2279
|
-
setSortValue(nextSort);
|
|
2280
|
-
setCurrentPage(nextPage);
|
|
2281
|
-
setPageInput(String(nextPage));
|
|
2282
|
-
setAppliedFilters(nextFilters);
|
|
2283
|
-
};
|
|
2284
|
-
window.addEventListener("popstate", handlePopState);
|
|
2285
|
-
return () => {
|
|
2286
|
-
window.removeEventListener("popstate", handlePopState);
|
|
2287
|
-
};
|
|
2288
|
-
}, []);
|
|
2289
|
-
const loadItems = useCallback3(async () => {
|
|
2620
|
+
useEffect9(() => {
|
|
2290
2621
|
var _a2, _b2;
|
|
2622
|
+
const nextSearchParams = new URLSearchParams(locationSearch);
|
|
2623
|
+
const nextQuery = (_a2 = nextSearchParams.get("q")) != null ? _a2 : "";
|
|
2624
|
+
const nextSort = (_b2 = nextSearchParams.get("sort")) != null ? _b2 : "";
|
|
2625
|
+
const nextPage = parsePageParam(nextSearchParams.get("page"));
|
|
2626
|
+
const nextFilters = extractFilterParams(nextSearchParams);
|
|
2627
|
+
setAppliedQuery(nextQuery);
|
|
2628
|
+
setSortValue(nextSort);
|
|
2629
|
+
setCurrentPage(nextPage);
|
|
2630
|
+
setPageInput(String(nextPage));
|
|
2631
|
+
setAppliedFilters(nextFilters);
|
|
2632
|
+
}, [locationSearch]);
|
|
2633
|
+
const loadItems = useCallback4(async () => {
|
|
2634
|
+
var _a2;
|
|
2291
2635
|
const activeRequestId = requestIdRef.current + 1;
|
|
2292
2636
|
requestIdRef.current = activeRequestId;
|
|
2293
2637
|
setError(null);
|
|
@@ -2298,14 +2642,8 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2298
2642
|
offset: (currentPage - 1) * pageSizeRef.current,
|
|
2299
2643
|
...appliedFilters
|
|
2300
2644
|
};
|
|
2301
|
-
const
|
|
2302
|
-
|
|
2303
|
-
requestParams.q,
|
|
2304
|
-
requestParams.sort,
|
|
2305
|
-
(_a2 = requestParams.limit) != null ? _a2 : DEFAULT_PAGE_SIZE,
|
|
2306
|
-
(_b2 = requestParams.offset) != null ? _b2 : 0,
|
|
2307
|
-
appliedFilters
|
|
2308
|
-
);
|
|
2645
|
+
const requestKey = buildListCacheKey(slug, requestParams);
|
|
2646
|
+
const cachedResponse = (_a2 = getClientCacheBucket(client).listResponseCache.get(requestKey)) != null ? _a2 : null;
|
|
2309
2647
|
if (cachedResponse) {
|
|
2310
2648
|
setData(cachedResponse);
|
|
2311
2649
|
setSelectedIds([]);
|
|
@@ -2317,7 +2655,7 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2317
2655
|
}
|
|
2318
2656
|
setIsLoading(true);
|
|
2319
2657
|
try {
|
|
2320
|
-
const response = await requestListItems(client, slug, requestParams);
|
|
2658
|
+
const response = await requestListItems(client, slug, requestParams, requestKey);
|
|
2321
2659
|
if (activeRequestId !== requestIdRef.current) {
|
|
2322
2660
|
return;
|
|
2323
2661
|
}
|
|
@@ -2332,32 +2670,36 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2332
2670
|
}
|
|
2333
2671
|
}
|
|
2334
2672
|
}, [appliedFilters, appliedQuery, client, currentPage, slug, sortValue, t]);
|
|
2335
|
-
|
|
2673
|
+
useEffect9(() => {
|
|
2336
2674
|
void loadItems();
|
|
2337
2675
|
}, [loadItems]);
|
|
2338
|
-
const refresh =
|
|
2676
|
+
const refresh = useCallback4(async () => {
|
|
2677
|
+
invalidateModelCache(client, slug);
|
|
2339
2678
|
await loadItems();
|
|
2340
|
-
}, [loadItems]);
|
|
2341
|
-
const
|
|
2679
|
+
}, [client, loadItems, slug]);
|
|
2680
|
+
const replaceLocation = useCallback4((nextQuery, nextSort, nextPage, nextFilters) => {
|
|
2681
|
+
router.replace(buildUrlWithParams(pathname, nextQuery, nextSort, nextPage, nextFilters));
|
|
2682
|
+
}, [pathname, router]);
|
|
2683
|
+
const handleSearchCommit = useCallback4((nextQuery) => {
|
|
2342
2684
|
if (nextQuery === appliedQuery) {
|
|
2343
2685
|
return;
|
|
2344
2686
|
}
|
|
2345
2687
|
setAppliedQuery(nextQuery);
|
|
2346
2688
|
setCurrentPage(1);
|
|
2347
2689
|
setPageInput("1");
|
|
2348
|
-
|
|
2349
|
-
}, [appliedFilters, appliedQuery,
|
|
2350
|
-
const handlePageChange =
|
|
2690
|
+
replaceLocation(nextQuery, sortValue, 1, appliedFilters);
|
|
2691
|
+
}, [appliedFilters, appliedQuery, replaceLocation, sortValue]);
|
|
2692
|
+
const handlePageChange = useCallback4((nextPage) => {
|
|
2351
2693
|
const safePage = Math.min(Math.max(nextPage, 1), totalPages);
|
|
2352
2694
|
setCurrentPage(safePage);
|
|
2353
2695
|
setPageInput(String(safePage));
|
|
2354
|
-
|
|
2355
|
-
}, [appliedFilters, appliedQuery,
|
|
2356
|
-
const handlePageInputCommit =
|
|
2696
|
+
replaceLocation(appliedQuery, sortValue, safePage, appliedFilters);
|
|
2697
|
+
}, [appliedFilters, appliedQuery, replaceLocation, sortValue, totalPages]);
|
|
2698
|
+
const handlePageInputCommit = useCallback4(() => {
|
|
2357
2699
|
const parsedPage = parsePageParam(pageInput);
|
|
2358
2700
|
handlePageChange(parsedPage);
|
|
2359
2701
|
}, [handlePageChange, pageInput]);
|
|
2360
|
-
const toggleSort =
|
|
2702
|
+
const toggleSort = useCallback4((fieldName) => {
|
|
2361
2703
|
const nextSortFields = sortFields.filter((item) => item !== fieldName && item !== `-${fieldName}`);
|
|
2362
2704
|
const currentSort = sortFields.find((item) => item === fieldName || item === `-${fieldName}`);
|
|
2363
2705
|
if (currentSort === void 0) {
|
|
@@ -2371,9 +2713,9 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2371
2713
|
setSortValue(nextSortValue);
|
|
2372
2714
|
setCurrentPage(1);
|
|
2373
2715
|
setPageInput("1");
|
|
2374
|
-
|
|
2375
|
-
}, [appliedFilters, appliedQuery,
|
|
2376
|
-
const handleFilterChange =
|
|
2716
|
+
replaceLocation(appliedQuery, nextSortValue, 1, appliedFilters);
|
|
2717
|
+
}, [appliedFilters, appliedQuery, replaceLocation, sortFields]);
|
|
2718
|
+
const handleFilterChange = useCallback4((filterSlug, value) => {
|
|
2377
2719
|
const nextFilters = {
|
|
2378
2720
|
...appliedFilters,
|
|
2379
2721
|
[filterSlug]: value
|
|
@@ -2384,18 +2726,18 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2384
2726
|
setAppliedFilters(nextFilters);
|
|
2385
2727
|
setCurrentPage(1);
|
|
2386
2728
|
setPageInput("1");
|
|
2387
|
-
|
|
2388
|
-
}, [appliedFilters, appliedQuery,
|
|
2389
|
-
const handleResetFilters =
|
|
2729
|
+
replaceLocation(appliedQuery, sortValue, 1, nextFilters);
|
|
2730
|
+
}, [appliedFilters, appliedQuery, replaceLocation, sortValue]);
|
|
2731
|
+
const handleResetFilters = useCallback4(() => {
|
|
2390
2732
|
if (Object.keys(appliedFilters).length === 0) {
|
|
2391
2733
|
return;
|
|
2392
2734
|
}
|
|
2393
2735
|
setAppliedFilters({});
|
|
2394
2736
|
setCurrentPage(1);
|
|
2395
2737
|
setPageInput("1");
|
|
2396
|
-
|
|
2397
|
-
}, [appliedFilters, appliedQuery,
|
|
2398
|
-
const openSingleDeletePreview =
|
|
2738
|
+
replaceLocation(appliedQuery, sortValue, 1, {});
|
|
2739
|
+
}, [appliedFilters, appliedQuery, replaceLocation, sortValue]);
|
|
2740
|
+
const openSingleDeletePreview = useCallback4(async (rowId) => {
|
|
2399
2741
|
setPendingDeleteIds([rowId]);
|
|
2400
2742
|
setPendingDeleteMode("single");
|
|
2401
2743
|
setDeletePreviewOpen(true);
|
|
@@ -2411,7 +2753,7 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2411
2753
|
setIsDeletePreviewLoading(false);
|
|
2412
2754
|
}
|
|
2413
2755
|
}, [client, slug, t]);
|
|
2414
|
-
const openBulkDeletePreview =
|
|
2756
|
+
const openBulkDeletePreview = useCallback4(async () => {
|
|
2415
2757
|
if (selectedIds.length === 0) {
|
|
2416
2758
|
return;
|
|
2417
2759
|
}
|
|
@@ -2431,7 +2773,7 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2431
2773
|
setBulkActionMenuAnchor(null);
|
|
2432
2774
|
}
|
|
2433
2775
|
}, [client, selectedIds, slug, t]);
|
|
2434
|
-
const handleConfirmDelete =
|
|
2776
|
+
const handleConfirmDelete = useCallback4(async () => {
|
|
2435
2777
|
if (pendingDeleteIds.length === 0) {
|
|
2436
2778
|
return;
|
|
2437
2779
|
}
|
|
@@ -2454,7 +2796,7 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2454
2796
|
setIsDeleteSubmitting(false);
|
|
2455
2797
|
}
|
|
2456
2798
|
}, [client, pendingDeleteIds, pendingDeleteMode, refresh, slug, t]);
|
|
2457
|
-
const handleRunNamedBulkAction =
|
|
2799
|
+
const handleRunNamedBulkAction = useCallback4(async (actionSlug) => {
|
|
2458
2800
|
if (!actionSlug || selectedIds.length === 0) {
|
|
2459
2801
|
return;
|
|
2460
2802
|
}
|
|
@@ -2470,12 +2812,12 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2470
2812
|
setError(reason instanceof Error ? reason.message : t("object_action_error"));
|
|
2471
2813
|
}
|
|
2472
2814
|
}, [client, openBulkDeletePreview, refresh, selectedIds, slug, t]);
|
|
2473
|
-
const handleRowDelete =
|
|
2815
|
+
const handleRowDelete = useCallback4(async (rowId) => {
|
|
2474
2816
|
setRowActionMenuAnchor(null);
|
|
2475
2817
|
setRowActionMenuId(null);
|
|
2476
2818
|
await openSingleDeletePreview(rowId);
|
|
2477
2819
|
}, [openSingleDeletePreview]);
|
|
2478
|
-
const handleToggleSelection =
|
|
2820
|
+
const handleToggleSelection = useCallback4((rowId, checked) => {
|
|
2479
2821
|
setSelectedIds((current) => {
|
|
2480
2822
|
const rowKey = String(rowId);
|
|
2481
2823
|
if (checked) {
|
|
@@ -2487,7 +2829,7 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2487
2829
|
return current.filter((item) => String(item) !== rowKey);
|
|
2488
2830
|
});
|
|
2489
2831
|
}, []);
|
|
2490
|
-
const handleToggleAllVisible =
|
|
2832
|
+
const handleToggleAllVisible = useCallback4((checked) => {
|
|
2491
2833
|
if (!meta) {
|
|
2492
2834
|
return;
|
|
2493
2835
|
}
|
|
@@ -2497,26 +2839,172 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2497
2839
|
}
|
|
2498
2840
|
setSelectedIds([]);
|
|
2499
2841
|
}, [meta, rows]);
|
|
2500
|
-
const handleOpenRowMenu =
|
|
2842
|
+
const handleOpenRowMenu = useCallback4((event, rowId) => {
|
|
2501
2843
|
setRowActionMenuAnchor(event.currentTarget);
|
|
2502
2844
|
setRowActionMenuId(rowId);
|
|
2503
2845
|
}, []);
|
|
2504
|
-
|
|
2505
|
-
|
|
2846
|
+
return {
|
|
2847
|
+
allVisibleSelected,
|
|
2848
|
+
appliedFilters,
|
|
2849
|
+
appliedQuery,
|
|
2850
|
+
bulkActionMenuAnchor,
|
|
2851
|
+
bulkActions,
|
|
2852
|
+
createOpen,
|
|
2853
|
+
currentPage,
|
|
2854
|
+
data,
|
|
2855
|
+
deletePreview,
|
|
2856
|
+
deletePreviewError,
|
|
2857
|
+
deletePreviewOpen,
|
|
2858
|
+
error,
|
|
2859
|
+
fieldMap,
|
|
2860
|
+
filtersOpen,
|
|
2861
|
+
handleConfirmDelete,
|
|
2862
|
+
handleFilterChange,
|
|
2863
|
+
handleOpenRowMenu,
|
|
2864
|
+
handlePageChange,
|
|
2865
|
+
handlePageInputCommit,
|
|
2866
|
+
handleResetFilters,
|
|
2867
|
+
handleRowDelete,
|
|
2868
|
+
handleRunNamedBulkAction,
|
|
2869
|
+
handleSearchCommit,
|
|
2870
|
+
handleToggleAllVisible,
|
|
2871
|
+
handleToggleSelection,
|
|
2872
|
+
hasListFilters,
|
|
2873
|
+
hasVisibleSelection,
|
|
2874
|
+
isDeletePreviewLoading,
|
|
2875
|
+
isDeleteSubmitting,
|
|
2876
|
+
isLoading,
|
|
2877
|
+
listFields,
|
|
2878
|
+
listFilters,
|
|
2879
|
+
meta,
|
|
2880
|
+
pageInput,
|
|
2881
|
+
pendingDeleteIds,
|
|
2882
|
+
pendingDeleteMode,
|
|
2883
|
+
refresh,
|
|
2884
|
+
rowActionMenuAnchor,
|
|
2885
|
+
rowActionMenuId,
|
|
2886
|
+
rows,
|
|
2887
|
+
selectedIdSet,
|
|
2888
|
+
selectedIds,
|
|
2889
|
+
setBulkActionMenuAnchor,
|
|
2890
|
+
setCreateOpen,
|
|
2891
|
+
setDeletePreview,
|
|
2892
|
+
setDeletePreviewError,
|
|
2893
|
+
setDeletePreviewOpen,
|
|
2894
|
+
setFiltersOpen,
|
|
2895
|
+
setPageInput,
|
|
2896
|
+
setPendingDeleteIds,
|
|
2897
|
+
setRowActionMenuAnchor,
|
|
2898
|
+
setRowActionMenuId,
|
|
2899
|
+
sortFields,
|
|
2900
|
+
toggleSort,
|
|
2901
|
+
total,
|
|
2902
|
+
totalPages
|
|
2903
|
+
};
|
|
2904
|
+
}
|
|
2905
|
+
function requestListItems(client, slug, params, requestKey) {
|
|
2906
|
+
const bucket = getClientCacheBucket(client);
|
|
2907
|
+
const cachedResponse = bucket.listResponseCache.get(requestKey);
|
|
2908
|
+
if (cachedResponse) {
|
|
2909
|
+
return Promise.resolve(cachedResponse);
|
|
2506
2910
|
}
|
|
2507
|
-
|
|
2508
|
-
|
|
2911
|
+
const existingRequest = bucket.inFlightListRequests.get(requestKey);
|
|
2912
|
+
if (existingRequest) {
|
|
2913
|
+
return existingRequest;
|
|
2509
2914
|
}
|
|
2510
|
-
|
|
2511
|
-
|
|
2915
|
+
const cacheVersion = getModelCacheVersion(client, slug);
|
|
2916
|
+
const request = client.getItems(slug, params).then((response) => {
|
|
2917
|
+
if (getModelCacheVersion(client, slug) === cacheVersion) {
|
|
2918
|
+
setCachedListResponse(client, requestKey, response);
|
|
2919
|
+
}
|
|
2920
|
+
return response;
|
|
2921
|
+
}).finally(() => {
|
|
2922
|
+
bucket.inFlightListRequests.delete(requestKey);
|
|
2923
|
+
});
|
|
2924
|
+
bucket.inFlightListRequests.set(requestKey, request);
|
|
2925
|
+
return request;
|
|
2926
|
+
}
|
|
2927
|
+
function parsePageParam(value) {
|
|
2928
|
+
const parsedValue = Number(value);
|
|
2929
|
+
if (!Number.isFinite(parsedValue) || parsedValue < 1) {
|
|
2930
|
+
return 1;
|
|
2931
|
+
}
|
|
2932
|
+
return Math.floor(parsedValue);
|
|
2933
|
+
}
|
|
2934
|
+
function extractFilterParams(params) {
|
|
2935
|
+
const result = {};
|
|
2936
|
+
for (const [key, value] of params.entries()) {
|
|
2937
|
+
if (key === "q" || key === "sort" || key === "page") {
|
|
2938
|
+
continue;
|
|
2939
|
+
}
|
|
2940
|
+
if (value) {
|
|
2941
|
+
result[key] = value;
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
return result;
|
|
2945
|
+
}
|
|
2946
|
+
|
|
2947
|
+
// src/components/model-page/Skeletons.tsx
|
|
2948
|
+
import { Box as Box8, Paper as Paper5, Skeleton as Skeleton3, Stack as Stack8 } from "@mui/material";
|
|
2949
|
+
import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2950
|
+
function ModelPageSkeleton() {
|
|
2951
|
+
return /* @__PURE__ */ jsxs11(Stack8, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
|
|
2952
|
+
/* @__PURE__ */ jsx18(MainHeaderSkeleton, { titleWidth: 240, subtitleWidth: "38%" }),
|
|
2953
|
+
/* @__PURE__ */ jsx18(Paper5, { sx: { p: 1.5, borderRadius: "10px", flexShrink: 0 }, children: /* @__PURE__ */ jsxs11(Stack8, { direction: { xs: "column", lg: "row" }, spacing: 1.5, alignItems: { lg: "center" }, children: [
|
|
2954
|
+
/* @__PURE__ */ jsx18(Skeleton3, { variant: "rounded", width: 360, height: 40 }),
|
|
2955
|
+
/* @__PURE__ */ jsx18(Skeleton3, { variant: "rounded", width: 128, height: 40 }),
|
|
2956
|
+
/* @__PURE__ */ jsx18(Box8, { sx: { flex: 1 } }),
|
|
2957
|
+
/* @__PURE__ */ jsx18(Skeleton3, { variant: "rounded", width: 110, height: 24 })
|
|
2958
|
+
] }) }),
|
|
2959
|
+
/* @__PURE__ */ jsx18(Paper5, { sx: { borderRadius: "10px", flex: 1, minHeight: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx18(ModelTableSkeleton, {}) })
|
|
2960
|
+
] });
|
|
2961
|
+
}
|
|
2962
|
+
function ModelTableSkeleton() {
|
|
2963
|
+
return /* @__PURE__ */ jsx18(Box8, { sx: { height: "100%", overflow: "auto", p: 1.5 }, children: /* @__PURE__ */ jsxs11(Stack8, { spacing: 1, children: [
|
|
2964
|
+
/* @__PURE__ */ jsx18(Skeleton3, { variant: "rounded", width: "100%", height: 42 }),
|
|
2965
|
+
Array.from({ length: 10 }).map((_, index) => /* @__PURE__ */ jsx18(Skeleton3, { variant: "rounded", width: "100%", height: 48 }, index))
|
|
2966
|
+
] }) });
|
|
2967
|
+
}
|
|
2968
|
+
|
|
2969
|
+
// src/components/ModelPage.tsx
|
|
2970
|
+
import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2971
|
+
var SEARCH_DEBOUNCE_MS = 300;
|
|
2972
|
+
var CHECKBOX_COLUMN_WIDTH = 56;
|
|
2973
|
+
var ACTIONS_COLUMN_WIDTH = 56;
|
|
2974
|
+
function ModelPage({ client, basePath, slug, router }) {
|
|
2975
|
+
var _a, _b;
|
|
2976
|
+
const locale = useAdminLocale();
|
|
2977
|
+
const t = useAdminTranslation();
|
|
2978
|
+
const resolvedRouter = useXLAdminRouter(router);
|
|
2979
|
+
const location = useXLAdminLocation(resolvedRouter);
|
|
2980
|
+
const theme = useTheme2();
|
|
2981
|
+
const isMobile = useMediaQuery2(theme.breakpoints.down("md"));
|
|
2982
|
+
const controller = useModelPageController({
|
|
2983
|
+
client,
|
|
2984
|
+
slug,
|
|
2985
|
+
pathname: location.pathname,
|
|
2986
|
+
locationSearch: location.search,
|
|
2987
|
+
router: resolvedRouter,
|
|
2988
|
+
t
|
|
2989
|
+
});
|
|
2990
|
+
useAdminDocumentTitle(t("admin_title"), (_b = (_a = controller.meta) == null ? void 0 : _a.title) != null ? _b : slug);
|
|
2991
|
+
if (!controller.isLoading && controller.error && !controller.data) {
|
|
2992
|
+
return /* @__PURE__ */ jsx19(Alert5, { severity: "error", children: controller.error });
|
|
2993
|
+
}
|
|
2994
|
+
if (!controller.data || !controller.meta) {
|
|
2995
|
+
return /* @__PURE__ */ jsx19(ModelPageSkeleton, {});
|
|
2996
|
+
}
|
|
2997
|
+
const meta = controller.meta;
|
|
2998
|
+
return /* @__PURE__ */ jsx19(XLAdminRouterProvider, { router: resolvedRouter, children: /* @__PURE__ */ jsxs12(Stack9, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
|
|
2999
|
+
/* @__PURE__ */ jsx19(
|
|
2512
3000
|
MainHeader,
|
|
2513
3001
|
{
|
|
2514
|
-
title: meta.title,
|
|
2515
|
-
actions: /* @__PURE__ */
|
|
3002
|
+
title: controller.meta.title,
|
|
3003
|
+
actions: /* @__PURE__ */ jsx19(Tooltip, { title: t("create"), children: /* @__PURE__ */ jsx19(
|
|
2516
3004
|
IconButton3,
|
|
2517
3005
|
{
|
|
2518
3006
|
"aria-label": t("create"),
|
|
2519
|
-
onClick: () => setCreateOpen(true),
|
|
3007
|
+
onClick: () => controller.setCreateOpen(true),
|
|
2520
3008
|
sx: {
|
|
2521
3009
|
width: 30,
|
|
2522
3010
|
height: 30,
|
|
@@ -2527,14 +3015,14 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2527
3015
|
backgroundColor: "primary.dark"
|
|
2528
3016
|
}
|
|
2529
3017
|
},
|
|
2530
|
-
children: /* @__PURE__ */
|
|
3018
|
+
children: /* @__PURE__ */ jsx19(AddIcon, { fontSize: "small" })
|
|
2531
3019
|
}
|
|
2532
3020
|
) }),
|
|
2533
|
-
subtitle: `${meta.slug}
|
|
2534
|
-
details: meta.description ? /* @__PURE__ */
|
|
3021
|
+
subtitle: `${controller.meta.slug} | ${t("objects_count", { count: controller.total })}`,
|
|
3022
|
+
details: controller.meta.description ? /* @__PURE__ */ jsx19(Typography5, { color: "text.secondary", sx: { fontSize: 14, lineHeight: 1.45 }, children: controller.meta.description }) : void 0
|
|
2535
3023
|
}
|
|
2536
3024
|
),
|
|
2537
|
-
/* @__PURE__ */
|
|
3025
|
+
/* @__PURE__ */ jsx19(
|
|
2538
3026
|
Paper6,
|
|
2539
3027
|
{
|
|
2540
3028
|
sx: {
|
|
@@ -2543,61 +3031,61 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2543
3031
|
flexShrink: 0
|
|
2544
3032
|
},
|
|
2545
3033
|
children: /* @__PURE__ */ jsxs12(Stack9, { direction: { xs: "column", lg: "row" }, spacing: 1.5, alignItems: { lg: "center" }, children: [
|
|
2546
|
-
/* @__PURE__ */
|
|
3034
|
+
/* @__PURE__ */ jsx19(Stack9, { direction: { xs: "column", xl: "row" }, spacing: 1.5, sx: { flex: 1, minWidth: 0 }, children: /* @__PURE__ */ jsx19(
|
|
2547
3035
|
SearchField,
|
|
2548
3036
|
{
|
|
2549
|
-
value: appliedQuery,
|
|
2550
|
-
onCommit: handleSearchCommit,
|
|
3037
|
+
value: controller.appliedQuery,
|
|
3038
|
+
onCommit: controller.handleSearchCommit,
|
|
2551
3039
|
debounceMs: SEARCH_DEBOUNCE_MS,
|
|
2552
3040
|
placeholder: t("search")
|
|
2553
3041
|
}
|
|
2554
3042
|
) }),
|
|
2555
|
-
selectedIds.length > 0 ? /* @__PURE__ */ jsxs12(Stack9, { direction: "row", spacing: 1, sx: { flex: { lg: 1 }, minWidth: 0 }, children: [
|
|
2556
|
-
/* @__PURE__ */
|
|
3043
|
+
controller.selectedIds.length > 0 ? /* @__PURE__ */ jsxs12(Stack9, { direction: "row", spacing: 1, sx: { flex: { lg: 1 }, minWidth: 0 }, children: [
|
|
3044
|
+
/* @__PURE__ */ jsx19(
|
|
2557
3045
|
Button4,
|
|
2558
3046
|
{
|
|
2559
3047
|
variant: "outlined",
|
|
2560
|
-
endIcon: /* @__PURE__ */
|
|
2561
|
-
onClick: (event) => setBulkActionMenuAnchor(event.currentTarget),
|
|
3048
|
+
endIcon: /* @__PURE__ */ jsx19(ExpandMoreIcon4, {}),
|
|
3049
|
+
onClick: (event) => controller.setBulkActionMenuAnchor(event.currentTarget),
|
|
2562
3050
|
children: t("actions")
|
|
2563
3051
|
}
|
|
2564
3052
|
),
|
|
2565
|
-
/* @__PURE__ */
|
|
3053
|
+
/* @__PURE__ */ jsx19(Typography5, { color: "text.secondary", sx: { alignSelf: "center" }, children: t("selected_count", { count: controller.selectedIds.length }) })
|
|
2566
3054
|
] }) : null,
|
|
2567
3055
|
/* @__PURE__ */ jsxs12(Stack9, { direction: "row", spacing: 1, alignItems: "center", sx: { marginLeft: "auto" }, children: [
|
|
2568
|
-
isMobile && hasListFilters ? /* @__PURE__ */
|
|
3056
|
+
isMobile && controller.hasListFilters ? /* @__PURE__ */ jsx19(Tooltip, { title: t("filters"), children: /* @__PURE__ */ jsx19(
|
|
2569
3057
|
IconButton3,
|
|
2570
3058
|
{
|
|
2571
3059
|
size: "small",
|
|
2572
3060
|
"aria-label": t("filters"),
|
|
2573
|
-
onClick: () => setFiltersOpen(true),
|
|
2574
|
-
children: /* @__PURE__ */
|
|
3061
|
+
onClick: () => controller.setFiltersOpen(true),
|
|
3062
|
+
children: /* @__PURE__ */ jsx19(FilterListIcon, { fontSize: "small" })
|
|
2575
3063
|
}
|
|
2576
3064
|
) }) : null,
|
|
2577
|
-
/* @__PURE__ */
|
|
3065
|
+
/* @__PURE__ */ jsx19(
|
|
2578
3066
|
IconButton3,
|
|
2579
3067
|
{
|
|
2580
3068
|
size: "small",
|
|
2581
|
-
onClick: () => handlePageChange(currentPage - 1),
|
|
2582
|
-
disabled: currentPage <= 1,
|
|
3069
|
+
onClick: () => controller.handlePageChange(controller.currentPage - 1),
|
|
3070
|
+
disabled: controller.currentPage <= 1,
|
|
2583
3071
|
sx: { mr: "-5px" },
|
|
2584
|
-
children: /* @__PURE__ */
|
|
3072
|
+
children: /* @__PURE__ */ jsx19(ChevronLeftIcon, { fontSize: "small" })
|
|
2585
3073
|
}
|
|
2586
3074
|
),
|
|
2587
|
-
/* @__PURE__ */
|
|
3075
|
+
/* @__PURE__ */ jsx19(
|
|
2588
3076
|
InputBase,
|
|
2589
3077
|
{
|
|
2590
|
-
value: pageInput,
|
|
2591
|
-
onChange: (event) => setPageInput(event.target.value.replace(/[^\d]/g, "") || "1"),
|
|
2592
|
-
onBlur: handlePageInputCommit,
|
|
3078
|
+
value: controller.pageInput,
|
|
3079
|
+
onChange: (event) => controller.setPageInput(event.target.value.replace(/[^\d]/g, "") || "1"),
|
|
3080
|
+
onBlur: controller.handlePageInputCommit,
|
|
2593
3081
|
onKeyDown: (event) => {
|
|
2594
3082
|
if (event.key === "Enter") {
|
|
2595
|
-
handlePageInputCommit();
|
|
3083
|
+
controller.handlePageInputCommit();
|
|
2596
3084
|
}
|
|
2597
3085
|
},
|
|
2598
3086
|
inputProps: { inputMode: "numeric" },
|
|
2599
3087
|
sx: {
|
|
2600
|
-
width: `${Math.max(String(totalPages).length, String(currentPage).length, 1)}ch`,
|
|
3088
|
+
width: `${Math.max(String(controller.totalPages).length, String(controller.currentPage).length, 1)}ch`,
|
|
2601
3089
|
minWidth: "1ch",
|
|
2602
3090
|
mr: 0.5,
|
|
2603
3091
|
fontSize: "1rem",
|
|
@@ -2621,18 +3109,18 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2621
3109
|
sx: { minWidth: "auto", fontSize: "1rem", lineHeight: "1rem" },
|
|
2622
3110
|
children: [
|
|
2623
3111
|
"/ ",
|
|
2624
|
-
totalPages
|
|
3112
|
+
controller.totalPages
|
|
2625
3113
|
]
|
|
2626
3114
|
}
|
|
2627
3115
|
),
|
|
2628
|
-
/* @__PURE__ */
|
|
3116
|
+
/* @__PURE__ */ jsx19(
|
|
2629
3117
|
IconButton3,
|
|
2630
3118
|
{
|
|
2631
3119
|
size: "small",
|
|
2632
|
-
onClick: () => handlePageChange(currentPage + 1),
|
|
2633
|
-
disabled: currentPage >= totalPages,
|
|
3120
|
+
onClick: () => controller.handlePageChange(controller.currentPage + 1),
|
|
3121
|
+
disabled: controller.currentPage >= controller.totalPages,
|
|
2634
3122
|
sx: { ml: "-5px" },
|
|
2635
|
-
children: /* @__PURE__ */
|
|
3123
|
+
children: /* @__PURE__ */ jsx19(ChevronRightIcon, { fontSize: "small" })
|
|
2636
3124
|
}
|
|
2637
3125
|
)
|
|
2638
3126
|
] })
|
|
@@ -2640,7 +3128,7 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2640
3128
|
}
|
|
2641
3129
|
),
|
|
2642
3130
|
/* @__PURE__ */ jsxs12(Stack9, { direction: { xs: "column", lg: "row" }, spacing: 1.5, sx: { flex: 1, minHeight: 0 }, children: [
|
|
2643
|
-
/* @__PURE__ */
|
|
3131
|
+
/* @__PURE__ */ jsx19(
|
|
2644
3132
|
Paper6,
|
|
2645
3133
|
{
|
|
2646
3134
|
sx: {
|
|
@@ -2650,9 +3138,9 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2650
3138
|
minHeight: 0,
|
|
2651
3139
|
overflow: "hidden"
|
|
2652
3140
|
},
|
|
2653
|
-
children: isLoading ? /* @__PURE__ */
|
|
2654
|
-
/* @__PURE__ */
|
|
2655
|
-
/* @__PURE__ */
|
|
3141
|
+
children: controller.isLoading ? /* @__PURE__ */ jsx19(ModelTableSkeleton, {}) : /* @__PURE__ */ jsx19(Box9, { sx: { height: "100%", overflow: "auto" }, children: /* @__PURE__ */ jsxs12(Table, { stickyHeader: true, size: "small", sx: { tableLayout: "fixed" }, children: [
|
|
3142
|
+
/* @__PURE__ */ jsx19(TableHead, { children: /* @__PURE__ */ jsxs12(TableRow2, { children: [
|
|
3143
|
+
/* @__PURE__ */ jsx19(
|
|
2656
3144
|
TableCell2,
|
|
2657
3145
|
{
|
|
2658
3146
|
padding: "none",
|
|
@@ -2665,22 +3153,22 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2665
3153
|
textAlign: "center",
|
|
2666
3154
|
px: 1
|
|
2667
3155
|
},
|
|
2668
|
-
children: /* @__PURE__ */
|
|
3156
|
+
children: /* @__PURE__ */ jsx19(
|
|
2669
3157
|
Checkbox2,
|
|
2670
3158
|
{
|
|
2671
|
-
checked: allVisibleSelected,
|
|
2672
|
-
indeterminate: !allVisibleSelected && hasVisibleSelection,
|
|
2673
|
-
onChange: (_, checked) => handleToggleAllVisible(checked)
|
|
3159
|
+
checked: controller.allVisibleSelected,
|
|
3160
|
+
indeterminate: !controller.allVisibleSelected && controller.hasVisibleSelection,
|
|
3161
|
+
onChange: (_, checked) => controller.handleToggleAllVisible(checked)
|
|
2674
3162
|
}
|
|
2675
3163
|
)
|
|
2676
3164
|
}
|
|
2677
3165
|
),
|
|
2678
|
-
listFields.map((fieldName) => {
|
|
3166
|
+
controller.listFields.map((fieldName) => {
|
|
2679
3167
|
var _a2, _b2;
|
|
2680
|
-
const field = fieldMap.get(fieldName);
|
|
2681
|
-
const sortDirection = resolveSortDirection(sortFields, fieldName);
|
|
3168
|
+
const field = controller.fieldMap.get(fieldName);
|
|
3169
|
+
const sortDirection = resolveSortDirection(controller.sortFields, fieldName);
|
|
2682
3170
|
const isSortable = resolveFieldSortable(field);
|
|
2683
|
-
return /* @__PURE__ */
|
|
3171
|
+
return /* @__PURE__ */ jsx19(
|
|
2684
3172
|
TableCell2,
|
|
2685
3173
|
{
|
|
2686
3174
|
sortDirection: sortDirection != null ? sortDirection : false,
|
|
@@ -2692,8 +3180,8 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2692
3180
|
minWidth: getListFieldWidthPx(field),
|
|
2693
3181
|
maxWidth: getListFieldWidthPx(field)
|
|
2694
3182
|
},
|
|
2695
|
-
onClick: isSortable ? () => toggleSort(fieldName) : void 0,
|
|
2696
|
-
children: isSortable ? /* @__PURE__ */
|
|
3183
|
+
onClick: isSortable ? () => controller.toggleSort(fieldName) : void 0,
|
|
3184
|
+
children: isSortable ? /* @__PURE__ */ jsx19(
|
|
2697
3185
|
TableSortLabel,
|
|
2698
3186
|
{
|
|
2699
3187
|
active: Boolean(sortDirection),
|
|
@@ -2707,7 +3195,7 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2707
3195
|
},
|
|
2708
3196
|
children: (_a2 = field == null ? void 0 : field.label) != null ? _a2 : fieldName
|
|
2709
3197
|
}
|
|
2710
|
-
) : /* @__PURE__ */
|
|
3198
|
+
) : /* @__PURE__ */ jsx19(Typography5, { component: "span", sx: {
|
|
2711
3199
|
fontSize: 14,
|
|
2712
3200
|
fontWeight: 700,
|
|
2713
3201
|
color: "rgba(255, 255, 255, 0.96)"
|
|
@@ -2716,7 +3204,7 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2716
3204
|
fieldName
|
|
2717
3205
|
);
|
|
2718
3206
|
}),
|
|
2719
|
-
/* @__PURE__ */
|
|
3207
|
+
/* @__PURE__ */ jsx19(
|
|
2720
3208
|
TableCell2,
|
|
2721
3209
|
{
|
|
2722
3210
|
align: "right",
|
|
@@ -2729,21 +3217,21 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2729
3217
|
}
|
|
2730
3218
|
)
|
|
2731
3219
|
] }) }),
|
|
2732
|
-
/* @__PURE__ */
|
|
3220
|
+
/* @__PURE__ */ jsx19(TableBody, { children: controller.rows.map((row) => {
|
|
2733
3221
|
const rowId = row[meta.pk_field];
|
|
2734
|
-
return /* @__PURE__ */
|
|
3222
|
+
return /* @__PURE__ */ jsx19(
|
|
2735
3223
|
ListRow,
|
|
2736
3224
|
{
|
|
2737
3225
|
row,
|
|
2738
3226
|
pkField: meta.pk_field,
|
|
2739
|
-
listFields,
|
|
3227
|
+
listFields: controller.listFields,
|
|
2740
3228
|
basePath,
|
|
2741
3229
|
slug,
|
|
2742
3230
|
locale,
|
|
2743
|
-
fieldMap,
|
|
2744
|
-
isSelected: selectedIdSet.has(String(rowId)),
|
|
2745
|
-
onToggleSelection: handleToggleSelection,
|
|
2746
|
-
onOpenMenu: handleOpenRowMenu
|
|
3231
|
+
fieldMap: controller.fieldMap,
|
|
3232
|
+
isSelected: controller.selectedIdSet.has(String(rowId)),
|
|
3233
|
+
onToggleSelection: controller.handleToggleSelection,
|
|
3234
|
+
onOpenMenu: controller.handleOpenRowMenu
|
|
2747
3235
|
},
|
|
2748
3236
|
String(rowId)
|
|
2749
3237
|
);
|
|
@@ -2751,43 +3239,50 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2751
3239
|
] }) })
|
|
2752
3240
|
}
|
|
2753
3241
|
),
|
|
2754
|
-
!isMobile && hasListFilters ? /* @__PURE__ */
|
|
3242
|
+
!isMobile && controller.hasListFilters ? /* @__PURE__ */ jsx19(
|
|
2755
3243
|
ListFiltersSidebar,
|
|
2756
3244
|
{
|
|
2757
3245
|
client,
|
|
2758
3246
|
slug,
|
|
2759
|
-
filters: listFilters,
|
|
2760
|
-
values: appliedFilters,
|
|
2761
|
-
onChange: handleFilterChange,
|
|
2762
|
-
onReset: handleResetFilters,
|
|
3247
|
+
filters: controller.listFilters,
|
|
3248
|
+
values: controller.appliedFilters,
|
|
3249
|
+
onChange: controller.handleFilterChange,
|
|
3250
|
+
onReset: controller.handleResetFilters,
|
|
2763
3251
|
debounceMs: SEARCH_DEBOUNCE_MS
|
|
2764
3252
|
}
|
|
2765
3253
|
) : null
|
|
2766
3254
|
] }),
|
|
2767
|
-
/* @__PURE__ */
|
|
3255
|
+
/* @__PURE__ */ jsx19(
|
|
2768
3256
|
Menu,
|
|
2769
3257
|
{
|
|
2770
|
-
anchorEl: bulkActionMenuAnchor,
|
|
2771
|
-
open: Boolean(bulkActionMenuAnchor),
|
|
2772
|
-
onClose: () => setBulkActionMenuAnchor(null),
|
|
2773
|
-
children: bulkActions.map((action) => /* @__PURE__ */
|
|
3258
|
+
anchorEl: controller.bulkActionMenuAnchor,
|
|
3259
|
+
open: Boolean(controller.bulkActionMenuAnchor),
|
|
3260
|
+
onClose: () => controller.setBulkActionMenuAnchor(null),
|
|
3261
|
+
children: controller.bulkActions.map((action) => /* @__PURE__ */ jsx19(
|
|
3262
|
+
MenuItem2,
|
|
3263
|
+
{
|
|
3264
|
+
onClick: () => void controller.handleRunNamedBulkAction(action.slug),
|
|
3265
|
+
children: action.label
|
|
3266
|
+
},
|
|
3267
|
+
action.slug
|
|
3268
|
+
))
|
|
2774
3269
|
}
|
|
2775
3270
|
),
|
|
2776
|
-
/* @__PURE__ */
|
|
3271
|
+
/* @__PURE__ */ jsx19(
|
|
2777
3272
|
Menu,
|
|
2778
3273
|
{
|
|
2779
|
-
anchorEl: rowActionMenuAnchor,
|
|
2780
|
-
open: Boolean(rowActionMenuAnchor),
|
|
3274
|
+
anchorEl: controller.rowActionMenuAnchor,
|
|
3275
|
+
open: Boolean(controller.rowActionMenuAnchor),
|
|
2781
3276
|
onClose: () => {
|
|
2782
|
-
setRowActionMenuAnchor(null);
|
|
2783
|
-
setRowActionMenuId(null);
|
|
3277
|
+
controller.setRowActionMenuAnchor(null);
|
|
3278
|
+
controller.setRowActionMenuId(null);
|
|
2784
3279
|
},
|
|
2785
|
-
children: /* @__PURE__ */
|
|
3280
|
+
children: /* @__PURE__ */ jsx19(
|
|
2786
3281
|
MenuItem2,
|
|
2787
3282
|
{
|
|
2788
3283
|
onClick: () => {
|
|
2789
|
-
if (rowActionMenuId !== null) {
|
|
2790
|
-
void handleRowDelete(rowActionMenuId);
|
|
3284
|
+
if (controller.rowActionMenuId !== null) {
|
|
3285
|
+
void controller.handleRowDelete(controller.rowActionMenuId);
|
|
2791
3286
|
}
|
|
2792
3287
|
},
|
|
2793
3288
|
children: t("delete")
|
|
@@ -2795,12 +3290,12 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2795
3290
|
)
|
|
2796
3291
|
}
|
|
2797
3292
|
),
|
|
2798
|
-
/* @__PURE__ */
|
|
3293
|
+
/* @__PURE__ */ jsx19(
|
|
2799
3294
|
FormDialog,
|
|
2800
3295
|
{
|
|
2801
|
-
open: createOpen,
|
|
2802
|
-
onClose: () => setCreateOpen(false),
|
|
2803
|
-
onSuccess: () => void refresh(),
|
|
3296
|
+
open: controller.createOpen,
|
|
3297
|
+
onClose: () => controller.setCreateOpen(false),
|
|
3298
|
+
onSuccess: () => void controller.refresh(),
|
|
2804
3299
|
title: `${t("create")}: ${meta.title}`,
|
|
2805
3300
|
slug,
|
|
2806
3301
|
mode: "create",
|
|
@@ -2811,8 +3306,8 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2811
3306
|
/* @__PURE__ */ jsxs12(
|
|
2812
3307
|
Dialog3,
|
|
2813
3308
|
{
|
|
2814
|
-
open: filtersOpen,
|
|
2815
|
-
onClose: () => setFiltersOpen(false),
|
|
3309
|
+
open: controller.filtersOpen,
|
|
3310
|
+
onClose: () => controller.setFiltersOpen(false),
|
|
2816
3311
|
fullWidth: true,
|
|
2817
3312
|
maxWidth: "xs",
|
|
2818
3313
|
slotProps: {
|
|
@@ -2829,44 +3324,44 @@ function ModelPage({ client, basePath, slug }) {
|
|
|
2829
3324
|
}
|
|
2830
3325
|
},
|
|
2831
3326
|
children: [
|
|
2832
|
-
/* @__PURE__ */
|
|
2833
|
-
/* @__PURE__ */
|
|
3327
|
+
/* @__PURE__ */ jsx19(DialogTitle3, { children: t("filters") }),
|
|
3328
|
+
/* @__PURE__ */ jsx19(DialogContent3, { sx: { px: 2, pb: 2 }, children: controller.hasListFilters ? /* @__PURE__ */ jsx19(
|
|
2834
3329
|
ListFiltersSidebar,
|
|
2835
3330
|
{
|
|
2836
3331
|
client,
|
|
2837
3332
|
slug,
|
|
2838
|
-
filters: listFilters,
|
|
2839
|
-
values: appliedFilters,
|
|
2840
|
-
onChange: handleFilterChange,
|
|
2841
|
-
onReset: handleResetFilters,
|
|
3333
|
+
filters: controller.listFilters,
|
|
3334
|
+
values: controller.appliedFilters,
|
|
3335
|
+
onChange: controller.handleFilterChange,
|
|
3336
|
+
onReset: controller.handleResetFilters,
|
|
2842
3337
|
debounceMs: SEARCH_DEBOUNCE_MS
|
|
2843
3338
|
}
|
|
2844
3339
|
) : null })
|
|
2845
3340
|
]
|
|
2846
3341
|
}
|
|
2847
3342
|
),
|
|
2848
|
-
/* @__PURE__ */
|
|
3343
|
+
/* @__PURE__ */ jsx19(
|
|
2849
3344
|
DeletePreviewDialog,
|
|
2850
3345
|
{
|
|
2851
|
-
open: deletePreviewOpen,
|
|
2852
|
-
title: pendingDeleteMode === "single" ? t("delete_object_title") : t("delete_bulk_title"),
|
|
2853
|
-
preview: deletePreview,
|
|
2854
|
-
error: deletePreviewError,
|
|
2855
|
-
isLoading: isDeletePreviewLoading,
|
|
2856
|
-
isSubmitting: isDeleteSubmitting,
|
|
3346
|
+
open: controller.deletePreviewOpen,
|
|
3347
|
+
title: controller.pendingDeleteMode === "single" ? t("delete_object_title") : t("delete_bulk_title"),
|
|
3348
|
+
preview: controller.deletePreview,
|
|
3349
|
+
error: controller.deletePreviewError,
|
|
3350
|
+
isLoading: controller.isDeletePreviewLoading,
|
|
3351
|
+
isSubmitting: controller.isDeleteSubmitting,
|
|
2857
3352
|
onClose: () => {
|
|
2858
|
-
if (isDeleteSubmitting) {
|
|
3353
|
+
if (controller.isDeleteSubmitting) {
|
|
2859
3354
|
return;
|
|
2860
3355
|
}
|
|
2861
|
-
setDeletePreviewOpen(false);
|
|
2862
|
-
setDeletePreview(null);
|
|
2863
|
-
setDeletePreviewError(null);
|
|
2864
|
-
setPendingDeleteIds([]);
|
|
3356
|
+
controller.setDeletePreviewOpen(false);
|
|
3357
|
+
controller.setDeletePreview(null);
|
|
3358
|
+
controller.setDeletePreviewError(null);
|
|
3359
|
+
controller.setPendingDeleteIds([]);
|
|
2865
3360
|
},
|
|
2866
|
-
onConfirm: () => void handleConfirmDelete()
|
|
3361
|
+
onConfirm: () => void controller.handleConfirmDelete()
|
|
2867
3362
|
}
|
|
2868
3363
|
)
|
|
2869
|
-
] });
|
|
3364
|
+
] }) });
|
|
2870
3365
|
}
|
|
2871
3366
|
function resolveSortDirection(sortFields, fieldName) {
|
|
2872
3367
|
if (sortFields.includes(`-${fieldName}`)) return "desc";
|
|
@@ -2879,89 +3374,12 @@ function resolveFieldSortable(field) {
|
|
|
2879
3374
|
}
|
|
2880
3375
|
return field.is_sortable && !field.is_relation_many && field.input_kind !== "relation-multiple" && !field.is_virtual;
|
|
2881
3376
|
}
|
|
2882
|
-
function requestListItems(client, slug, params) {
|
|
2883
|
-
const requestKey = buildListRequestKey(slug, params);
|
|
2884
|
-
const cachedResponse = listResponseCache.get(requestKey);
|
|
2885
|
-
if (cachedResponse) {
|
|
2886
|
-
return Promise.resolve(cachedResponse);
|
|
2887
|
-
}
|
|
2888
|
-
const existingRequest = inFlightListRequests.get(requestKey);
|
|
2889
|
-
if (existingRequest) {
|
|
2890
|
-
return existingRequest;
|
|
2891
|
-
}
|
|
2892
|
-
const request = client.getItems(slug, params).then((response) => {
|
|
2893
|
-
listResponseCache.set(requestKey, response);
|
|
2894
|
-
return response;
|
|
2895
|
-
}).finally(() => {
|
|
2896
|
-
inFlightListRequests.delete(requestKey);
|
|
2897
|
-
});
|
|
2898
|
-
inFlightListRequests.set(requestKey, request);
|
|
2899
|
-
return request;
|
|
2900
|
-
}
|
|
2901
|
-
function buildListRequestKey(slug, params) {
|
|
2902
|
-
const { q, sort, limit, offset, ...filters } = params;
|
|
2903
|
-
return JSON.stringify({
|
|
2904
|
-
slug,
|
|
2905
|
-
q: q != null ? q : null,
|
|
2906
|
-
sort: sort != null ? sort : null,
|
|
2907
|
-
limit: limit != null ? limit : DEFAULT_PAGE_SIZE,
|
|
2908
|
-
offset: offset != null ? offset : 0,
|
|
2909
|
-
filters: Object.fromEntries(
|
|
2910
|
-
Object.entries(filters).filter(([, value]) => value !== void 0 && value !== null && value !== "").sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey))
|
|
2911
|
-
)
|
|
2912
|
-
});
|
|
2913
|
-
}
|
|
2914
|
-
function findCachedListResponse(slug, query, sort, limit, offset, filters) {
|
|
2915
|
-
var _a;
|
|
2916
|
-
return (_a = listResponseCache.get(buildListRequestKey(slug, { q: query, sort, limit, offset, ...filters }))) != null ? _a : null;
|
|
2917
|
-
}
|
|
2918
|
-
function parsePageParam(value) {
|
|
2919
|
-
const parsedValue = Number(value);
|
|
2920
|
-
if (!Number.isFinite(parsedValue) || parsedValue < 1) {
|
|
2921
|
-
return 1;
|
|
2922
|
-
}
|
|
2923
|
-
return Math.floor(parsedValue);
|
|
2924
|
-
}
|
|
2925
|
-
function extractFilterParams(params) {
|
|
2926
|
-
const result = {};
|
|
2927
|
-
for (const [key, value] of params.entries()) {
|
|
2928
|
-
if (key === "q" || key === "sort" || key === "page") {
|
|
2929
|
-
continue;
|
|
2930
|
-
}
|
|
2931
|
-
if (value) {
|
|
2932
|
-
result[key] = value;
|
|
2933
|
-
}
|
|
2934
|
-
}
|
|
2935
|
-
return result;
|
|
2936
|
-
}
|
|
2937
|
-
function replaceUrlParams(pathname, query, sort, page, filters) {
|
|
2938
|
-
const params = new URLSearchParams();
|
|
2939
|
-
if (query) {
|
|
2940
|
-
params.set("q", query);
|
|
2941
|
-
}
|
|
2942
|
-
if (sort) {
|
|
2943
|
-
params.set("sort", sort);
|
|
2944
|
-
}
|
|
2945
|
-
if (page > 1) {
|
|
2946
|
-
params.set("page", String(page));
|
|
2947
|
-
}
|
|
2948
|
-
for (const [key, value] of Object.entries(filters)) {
|
|
2949
|
-
if (value) {
|
|
2950
|
-
params.set(key, value);
|
|
2951
|
-
}
|
|
2952
|
-
}
|
|
2953
|
-
const nextPath = pathname != null ? pathname : window.location.pathname;
|
|
2954
|
-
const nextUrl = params.toString() ? `${nextPath}?${params.toString()}` : nextPath;
|
|
2955
|
-
window.history.replaceState(window.history.state, "", nextUrl);
|
|
2956
|
-
}
|
|
2957
3377
|
|
|
2958
3378
|
// src/components/ObjectPage.tsx
|
|
2959
|
-
import { useCallback as useCallback5, useEffect as useEffect9, useMemo as useMemo8, useState as useState9 } from "react";
|
|
2960
|
-
import { usePathname as usePathname2, useRouter } from "next/navigation.js";
|
|
2961
3379
|
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
|
2962
3380
|
import MoreVertIcon2 from "@mui/icons-material/MoreVert";
|
|
2963
3381
|
import {
|
|
2964
|
-
Alert as
|
|
3382
|
+
Alert as Alert6,
|
|
2965
3383
|
Box as Box12,
|
|
2966
3384
|
Button as Button5,
|
|
2967
3385
|
IconButton as IconButton4,
|
|
@@ -2979,8 +3397,8 @@ import "dayjs/locale/en.js";
|
|
|
2979
3397
|
import "dayjs/locale/ru.js";
|
|
2980
3398
|
|
|
2981
3399
|
// src/components/object-page/ObjectField.tsx
|
|
2982
|
-
import { memo as memo6, useCallback as
|
|
2983
|
-
import { jsx as
|
|
3400
|
+
import { memo as memo6, useCallback as useCallback5 } from "react";
|
|
3401
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
2984
3402
|
var ObjectField = memo6(function ObjectField2({
|
|
2985
3403
|
field,
|
|
2986
3404
|
value,
|
|
@@ -2988,10 +3406,10 @@ var ObjectField = memo6(function ObjectField2({
|
|
|
2988
3406
|
client,
|
|
2989
3407
|
onFieldChange
|
|
2990
3408
|
}) {
|
|
2991
|
-
const handleChange =
|
|
3409
|
+
const handleChange = useCallback5((nextValue) => {
|
|
2992
3410
|
onFieldChange(field.name, nextValue);
|
|
2993
3411
|
}, [field.name, onFieldChange]);
|
|
2994
|
-
return /* @__PURE__ */
|
|
3412
|
+
return /* @__PURE__ */ jsx20(
|
|
2995
3413
|
FieldEditor,
|
|
2996
3414
|
{
|
|
2997
3415
|
field,
|
|
@@ -3005,37 +3423,45 @@ var ObjectField = memo6(function ObjectField2({
|
|
|
3005
3423
|
|
|
3006
3424
|
// src/components/object-page/ObjectPageSkeleton.tsx
|
|
3007
3425
|
import { Box as Box10, Paper as Paper7, Skeleton as Skeleton4, Stack as Stack10 } from "@mui/material";
|
|
3008
|
-
import { jsx as
|
|
3426
|
+
import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3009
3427
|
function ObjectPageSkeleton() {
|
|
3010
3428
|
return /* @__PURE__ */ jsxs13(Stack10, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
|
|
3011
|
-
/* @__PURE__ */
|
|
3012
|
-
/* @__PURE__ */ jsxs13(
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3429
|
+
/* @__PURE__ */ jsx21(MainHeaderSkeleton, { titleWidth: 420, subtitleWidth: "32%" }),
|
|
3430
|
+
/* @__PURE__ */ jsxs13(
|
|
3431
|
+
Stack10,
|
|
3432
|
+
{
|
|
3433
|
+
direction: { xs: "column", lg: "row" },
|
|
3434
|
+
spacing: 1.5,
|
|
3435
|
+
sx: { flex: 1, minHeight: 0, alignItems: "stretch" },
|
|
3436
|
+
children: [
|
|
3437
|
+
/* @__PURE__ */ jsx21(Paper7, { sx: { borderRadius: "10px", flex: 1, minHeight: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx21(Box10, { sx: { height: "100%", overflow: "auto", p: 2.5 }, children: /* @__PURE__ */ jsx21(Stack10, { spacing: 1.5, children: Array.from({ length: 9 }).map((_, index) => /* @__PURE__ */ jsx21(Skeleton4, { variant: "rounded", width: "100%", height: 56 }, index)) }) }) }),
|
|
3438
|
+
/* @__PURE__ */ jsx21(
|
|
3439
|
+
Paper7,
|
|
3440
|
+
{
|
|
3441
|
+
sx: {
|
|
3442
|
+
width: { xs: "100%", lg: 280 },
|
|
3443
|
+
flexShrink: 0,
|
|
3444
|
+
borderRadius: "10px",
|
|
3445
|
+
p: 1.5,
|
|
3446
|
+
alignSelf: "flex-start"
|
|
3447
|
+
},
|
|
3448
|
+
children: /* @__PURE__ */ jsxs13(Stack10, { spacing: 1, children: [
|
|
3449
|
+
/* @__PURE__ */ jsx21(Skeleton4, { variant: "text", width: 90, height: 28 }),
|
|
3450
|
+
/* @__PURE__ */ jsx21(Skeleton4, { variant: "rounded", width: "100%", height: 40 }),
|
|
3451
|
+
/* @__PURE__ */ jsx21(Skeleton4, { variant: "rounded", width: "100%", height: 40 })
|
|
3452
|
+
] })
|
|
3453
|
+
}
|
|
3454
|
+
)
|
|
3455
|
+
]
|
|
3456
|
+
}
|
|
3457
|
+
)
|
|
3032
3458
|
] });
|
|
3033
3459
|
}
|
|
3034
3460
|
|
|
3035
3461
|
// src/components/object-page/ReadonlyObjectField.tsx
|
|
3036
3462
|
import { memo as memo7 } from "react";
|
|
3037
3463
|
import { Box as Box11, Stack as Stack11, TextField as TextField4 } from "@mui/material";
|
|
3038
|
-
import { jsx as
|
|
3464
|
+
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3039
3465
|
var ReadonlyObjectField = memo7(function ReadonlyObjectField2({
|
|
3040
3466
|
field,
|
|
3041
3467
|
value,
|
|
@@ -3044,7 +3470,7 @@ var ReadonlyObjectField = memo7(function ReadonlyObjectField2({
|
|
|
3044
3470
|
var _a;
|
|
3045
3471
|
const isMultiline = field.input_kind === "textarea" || field.input_kind === "json" || field.type.toLowerCase().includes("text") || value.includes("\n") || value.length > 120;
|
|
3046
3472
|
return /* @__PURE__ */ jsxs14(Stack11, { spacing: 1, children: [
|
|
3047
|
-
imageUrl ? /* @__PURE__ */
|
|
3473
|
+
imageUrl ? /* @__PURE__ */ jsx22(
|
|
3048
3474
|
Box11,
|
|
3049
3475
|
{
|
|
3050
3476
|
component: "img",
|
|
@@ -3061,7 +3487,7 @@ var ReadonlyObjectField = memo7(function ReadonlyObjectField2({
|
|
|
3061
3487
|
}
|
|
3062
3488
|
}
|
|
3063
3489
|
) : null,
|
|
3064
|
-
/* @__PURE__ */
|
|
3490
|
+
/* @__PURE__ */ jsx22(
|
|
3065
3491
|
TextField4,
|
|
3066
3492
|
{
|
|
3067
3493
|
label: field.label,
|
|
@@ -3077,47 +3503,75 @@ var ReadonlyObjectField = memo7(function ReadonlyObjectField2({
|
|
|
3077
3503
|
] });
|
|
3078
3504
|
});
|
|
3079
3505
|
|
|
3080
|
-
// src/components/
|
|
3081
|
-
import {
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
function
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3506
|
+
// src/components/object-page/useObjectPageController.ts
|
|
3507
|
+
import { useCallback as useCallback6, useEffect as useEffect10, useMemo as useMemo9, useState as useState10 } from "react";
|
|
3508
|
+
|
|
3509
|
+
// src/utils/isDeepEqual.ts
|
|
3510
|
+
function isDeepEqual(left, right) {
|
|
3511
|
+
if (Object.is(left, right)) {
|
|
3512
|
+
return true;
|
|
3513
|
+
}
|
|
3514
|
+
if (left instanceof Date && right instanceof Date) {
|
|
3515
|
+
return left.getTime() === right.getTime();
|
|
3516
|
+
}
|
|
3517
|
+
if (Array.isArray(left) && Array.isArray(right)) {
|
|
3518
|
+
if (left.length !== right.length) {
|
|
3519
|
+
return false;
|
|
3520
|
+
}
|
|
3521
|
+
return left.every((item, index) => isDeepEqual(item, right[index]));
|
|
3522
|
+
}
|
|
3523
|
+
if (isPlainObject(left) && isPlainObject(right)) {
|
|
3524
|
+
const leftKeys = Object.keys(left).sort();
|
|
3525
|
+
const rightKeys = Object.keys(right).sort();
|
|
3526
|
+
if (!isDeepEqual(leftKeys, rightKeys)) {
|
|
3527
|
+
return false;
|
|
3528
|
+
}
|
|
3529
|
+
return leftKeys.every((key) => isDeepEqual(left[key], right[key]));
|
|
3530
|
+
}
|
|
3531
|
+
return false;
|
|
3532
|
+
}
|
|
3533
|
+
function isPlainObject(value) {
|
|
3534
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3535
|
+
}
|
|
3536
|
+
|
|
3537
|
+
// src/components/object-page/useObjectPageController.ts
|
|
3538
|
+
function useObjectPageController({
|
|
3539
|
+
client,
|
|
3540
|
+
slug,
|
|
3541
|
+
id,
|
|
3542
|
+
listPath,
|
|
3543
|
+
router,
|
|
3544
|
+
t
|
|
3545
|
+
}) {
|
|
3546
|
+
var _a, _b, _c;
|
|
3547
|
+
const cacheKey = buildDetailCacheKey(slug, id);
|
|
3548
|
+
const [data, setData] = useState10(() => {
|
|
3094
3549
|
var _a2;
|
|
3095
|
-
return (_a2 = detailResponseCache.get(cacheKey)) != null ? _a2 : null;
|
|
3550
|
+
return (_a2 = getClientCacheBucket(client).detailResponseCache.get(cacheKey)) != null ? _a2 : null;
|
|
3096
3551
|
});
|
|
3097
|
-
const [values, setValues] =
|
|
3552
|
+
const [values, setValues] = useState10(() => {
|
|
3098
3553
|
var _a2, _b2;
|
|
3099
|
-
return (_b2 = (_a2 = detailResponseCache.get(cacheKey)) == null ? void 0 : _a2.item) != null ? _b2 : {};
|
|
3554
|
+
return (_b2 = (_a2 = getClientCacheBucket(client).detailResponseCache.get(cacheKey)) == null ? void 0 : _a2.item) != null ? _b2 : {};
|
|
3100
3555
|
});
|
|
3101
|
-
const [initialValues, setInitialValues] =
|
|
3556
|
+
const [initialValues, setInitialValues] = useState10(() => {
|
|
3102
3557
|
var _a2, _b2;
|
|
3103
|
-
return (_b2 = (_a2 = detailResponseCache.get(cacheKey)) == null ? void 0 : _a2.item) != null ? _b2 : {};
|
|
3558
|
+
return (_b2 = (_a2 = getClientCacheBucket(client).detailResponseCache.get(cacheKey)) == null ? void 0 : _a2.item) != null ? _b2 : {};
|
|
3104
3559
|
});
|
|
3105
|
-
const [error, setError] =
|
|
3106
|
-
const [isLoading, setIsLoading] =
|
|
3107
|
-
const [isSaving, setIsSaving] =
|
|
3108
|
-
const [isDeleting, setIsDeleting] =
|
|
3109
|
-
const [activeActionSlug, setActiveActionSlug] =
|
|
3110
|
-
const [deleteConfirmOpen, setDeleteConfirmOpen] =
|
|
3111
|
-
const [deletePreview, setDeletePreview] =
|
|
3112
|
-
const [isDeletePreviewLoading, setIsDeletePreviewLoading] =
|
|
3113
|
-
const [deletePreviewError, setDeletePreviewError] =
|
|
3114
|
-
const [actionsAnchorEl, setActionsAnchorEl] =
|
|
3115
|
-
|
|
3116
|
-
const adminRootPath = useMemo8(() => listPath.split("/").slice(0, -1).join("/"), [listPath]);
|
|
3117
|
-
useEffect9(() => {
|
|
3560
|
+
const [error, setError] = useState10(null);
|
|
3561
|
+
const [isLoading, setIsLoading] = useState10(data === null);
|
|
3562
|
+
const [isSaving, setIsSaving] = useState10(false);
|
|
3563
|
+
const [isDeleting, setIsDeleting] = useState10(false);
|
|
3564
|
+
const [activeActionSlug, setActiveActionSlug] = useState10(null);
|
|
3565
|
+
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState10(false);
|
|
3566
|
+
const [deletePreview, setDeletePreview] = useState10(null);
|
|
3567
|
+
const [isDeletePreviewLoading, setIsDeletePreviewLoading] = useState10(false);
|
|
3568
|
+
const [deletePreviewError, setDeletePreviewError] = useState10(null);
|
|
3569
|
+
const [actionsAnchorEl, setActionsAnchorEl] = useState10(null);
|
|
3570
|
+
useEffect10(() => {
|
|
3118
3571
|
var _a2;
|
|
3119
3572
|
let isMounted = true;
|
|
3120
|
-
const
|
|
3573
|
+
const bucket = getClientCacheBucket(client);
|
|
3574
|
+
const cachedResponse = bucket.detailResponseCache.get(cacheKey);
|
|
3121
3575
|
if (cachedResponse) {
|
|
3122
3576
|
setData(cachedResponse);
|
|
3123
3577
|
setValues(cachedResponse.item);
|
|
@@ -3129,10 +3583,13 @@ function ObjectPage({ client, slug, id }) {
|
|
|
3129
3583
|
}
|
|
3130
3584
|
setIsLoading(true);
|
|
3131
3585
|
setError(null);
|
|
3132
|
-
const request = (_a2 = inFlightDetailRequests.get(cacheKey)) != null ? _a2 : client.getItem(slug, id);
|
|
3133
|
-
inFlightDetailRequests.set(cacheKey, request);
|
|
3586
|
+
const request = (_a2 = bucket.inFlightDetailRequests.get(cacheKey)) != null ? _a2 : client.getItem(slug, id);
|
|
3587
|
+
bucket.inFlightDetailRequests.set(cacheKey, request);
|
|
3588
|
+
const cacheVersion = getModelCacheVersion(client, slug);
|
|
3134
3589
|
request.then((response) => {
|
|
3135
|
-
|
|
3590
|
+
if (getModelCacheVersion(client, slug) === cacheVersion) {
|
|
3591
|
+
setCachedDetailResponse(client, cacheKey, response);
|
|
3592
|
+
}
|
|
3136
3593
|
if (!isMounted) return;
|
|
3137
3594
|
setData(response);
|
|
3138
3595
|
setValues(response.item);
|
|
@@ -3141,8 +3598,8 @@ function ObjectPage({ client, slug, id }) {
|
|
|
3141
3598
|
if (!isMounted) return;
|
|
3142
3599
|
setError(reason instanceof Error ? reason.message : t("object_load_error"));
|
|
3143
3600
|
}).finally(() => {
|
|
3144
|
-
if (inFlightDetailRequests.get(cacheKey) === request) {
|
|
3145
|
-
inFlightDetailRequests.delete(cacheKey);
|
|
3601
|
+
if (bucket.inFlightDetailRequests.get(cacheKey) === request) {
|
|
3602
|
+
bucket.inFlightDetailRequests.delete(cacheKey);
|
|
3146
3603
|
}
|
|
3147
3604
|
if (!isMounted) return;
|
|
3148
3605
|
setIsLoading(false);
|
|
@@ -3154,25 +3611,25 @@ function ObjectPage({ client, slug, id }) {
|
|
|
3154
3611
|
const meta = (_a = data == null ? void 0 : data.meta) != null ? _a : null;
|
|
3155
3612
|
const detailFields = (_b = meta == null ? void 0 : meta.detail_fields) != null ? _b : [];
|
|
3156
3613
|
const objectActions = (_c = meta == null ? void 0 : meta.object_actions) != null ? _c : [];
|
|
3157
|
-
const fieldMap =
|
|
3614
|
+
const fieldMap = useMemo9(
|
|
3158
3615
|
() => {
|
|
3159
3616
|
var _a2;
|
|
3160
3617
|
return new Map(((_a2 = meta == null ? void 0 : meta.fields) != null ? _a2 : []).map((field) => [field.name, field]));
|
|
3161
3618
|
},
|
|
3162
3619
|
[meta == null ? void 0 : meta.fields]
|
|
3163
3620
|
);
|
|
3164
|
-
const editableFields =
|
|
3621
|
+
const editableFields = useMemo9(
|
|
3165
3622
|
() => {
|
|
3166
3623
|
var _a2;
|
|
3167
3624
|
return ((_a2 = meta == null ? void 0 : meta.fields) != null ? _a2 : []).filter((field) => meta == null ? void 0 : meta.update_fields.includes(field.name));
|
|
3168
3625
|
},
|
|
3169
3626
|
[meta == null ? void 0 : meta.fields, meta == null ? void 0 : meta.update_fields]
|
|
3170
3627
|
);
|
|
3171
|
-
const editableFieldNames =
|
|
3628
|
+
const editableFieldNames = useMemo9(
|
|
3172
3629
|
() => new Set(editableFields.map((field) => field.name)),
|
|
3173
3630
|
[editableFields]
|
|
3174
3631
|
);
|
|
3175
|
-
const objectTitle =
|
|
3632
|
+
const objectTitle = useMemo9(
|
|
3176
3633
|
() => {
|
|
3177
3634
|
var _a2;
|
|
3178
3635
|
return String((_a2 = data == null ? void 0 : data.item._display) != null ? _a2 : meta ? `${meta.title} #${id}` : id);
|
|
@@ -3180,20 +3637,19 @@ function ObjectPage({ client, slug, id }) {
|
|
|
3180
3637
|
[data, id, meta]
|
|
3181
3638
|
);
|
|
3182
3639
|
const isActionsMenuOpen = actionsAnchorEl !== null;
|
|
3183
|
-
|
|
3184
|
-
const currentPayload = useMemo8(
|
|
3640
|
+
const currentPayload = useMemo9(
|
|
3185
3641
|
() => buildAdminPayload(values, editableFields),
|
|
3186
3642
|
[editableFields, values]
|
|
3187
3643
|
);
|
|
3188
|
-
const initialPayload =
|
|
3644
|
+
const initialPayload = useMemo9(
|
|
3189
3645
|
() => buildAdminPayload(initialValues, editableFields),
|
|
3190
3646
|
[editableFields, initialValues]
|
|
3191
3647
|
);
|
|
3192
|
-
const isDirty =
|
|
3193
|
-
() =>
|
|
3648
|
+
const isDirty = useMemo9(
|
|
3649
|
+
() => !isDeepEqual(currentPayload, initialPayload),
|
|
3194
3650
|
[currentPayload, initialPayload]
|
|
3195
3651
|
);
|
|
3196
|
-
const handleFieldChange =
|
|
3652
|
+
const handleFieldChange = useCallback6((fieldName, nextValue) => {
|
|
3197
3653
|
setValues((current) => {
|
|
3198
3654
|
if (Object.is(current[fieldName], nextValue)) {
|
|
3199
3655
|
return current;
|
|
@@ -3201,7 +3657,7 @@ function ObjectPage({ client, slug, id }) {
|
|
|
3201
3657
|
return { ...current, [fieldName]: nextValue };
|
|
3202
3658
|
});
|
|
3203
3659
|
}, []);
|
|
3204
|
-
const handleSave =
|
|
3660
|
+
const handleSave = useCallback6(async () => {
|
|
3205
3661
|
if (!meta || !isDirty) {
|
|
3206
3662
|
return;
|
|
3207
3663
|
}
|
|
@@ -3210,7 +3666,8 @@ function ObjectPage({ client, slug, id }) {
|
|
|
3210
3666
|
try {
|
|
3211
3667
|
const response = await client.patchItem(slug, id, currentPayload);
|
|
3212
3668
|
const nextDetail = { meta, item: response.item };
|
|
3213
|
-
|
|
3669
|
+
invalidateModelCache(client, slug);
|
|
3670
|
+
setCachedDetailResponse(client, cacheKey, nextDetail);
|
|
3214
3671
|
setData(nextDetail);
|
|
3215
3672
|
setValues(response.item);
|
|
3216
3673
|
setInitialValues(response.item);
|
|
@@ -3220,40 +3677,31 @@ function ObjectPage({ client, slug, id }) {
|
|
|
3220
3677
|
setIsSaving(false);
|
|
3221
3678
|
}
|
|
3222
3679
|
}, [cacheKey, client, currentPayload, id, isDirty, meta, slug, t]);
|
|
3223
|
-
const handleDelete =
|
|
3680
|
+
const handleDelete = useCallback6(async () => {
|
|
3224
3681
|
setIsDeleting(true);
|
|
3225
3682
|
setError(null);
|
|
3226
3683
|
try {
|
|
3227
3684
|
await client.deleteItem(slug, id);
|
|
3228
|
-
|
|
3685
|
+
invalidateModelCache(client, slug);
|
|
3229
3686
|
router.push(listPath);
|
|
3230
3687
|
} catch (reason) {
|
|
3231
3688
|
setError(reason instanceof Error ? reason.message : t("object_delete_error"));
|
|
3232
3689
|
setIsDeleting(false);
|
|
3233
3690
|
setDeleteConfirmOpen(false);
|
|
3234
3691
|
}
|
|
3235
|
-
}, [
|
|
3236
|
-
const handleNavigateBack =
|
|
3237
|
-
if (typeof window !== "undefined" && document.referrer) {
|
|
3238
|
-
try {
|
|
3239
|
-
const referrerUrl = new URL(document.referrer);
|
|
3240
|
-
if (referrerUrl.origin === window.location.origin && referrerUrl.pathname.startsWith(adminRootPath)) {
|
|
3241
|
-
router.back();
|
|
3242
|
-
return;
|
|
3243
|
-
}
|
|
3244
|
-
} catch {
|
|
3245
|
-
}
|
|
3246
|
-
}
|
|
3692
|
+
}, [client, id, listPath, router, slug, t]);
|
|
3693
|
+
const handleNavigateBack = useCallback6(() => {
|
|
3247
3694
|
router.push(listPath);
|
|
3248
|
-
}, [
|
|
3249
|
-
const handleRunObjectAction =
|
|
3695
|
+
}, [listPath, router]);
|
|
3696
|
+
const handleRunObjectAction = useCallback6(async (actionSlug) => {
|
|
3250
3697
|
setActiveActionSlug(actionSlug);
|
|
3251
3698
|
setError(null);
|
|
3252
3699
|
try {
|
|
3253
3700
|
const response = await client.runObjectAction(slug, id, actionSlug);
|
|
3254
3701
|
const nextDetail = data ? { ...data, item: response.item } : null;
|
|
3255
3702
|
if (nextDetail) {
|
|
3256
|
-
|
|
3703
|
+
invalidateModelCache(client, slug);
|
|
3704
|
+
setCachedDetailResponse(client, cacheKey, nextDetail);
|
|
3257
3705
|
}
|
|
3258
3706
|
setData(nextDetail);
|
|
3259
3707
|
setValues(response.item);
|
|
@@ -3264,7 +3712,7 @@ function ObjectPage({ client, slug, id }) {
|
|
|
3264
3712
|
setActiveActionSlug(null);
|
|
3265
3713
|
}
|
|
3266
3714
|
}, [cacheKey, client, data, id, slug, t]);
|
|
3267
|
-
const handleOpenDeletePreview =
|
|
3715
|
+
const handleOpenDeletePreview = useCallback6(async () => {
|
|
3268
3716
|
setActionsAnchorEl(null);
|
|
3269
3717
|
setDeleteConfirmOpen(true);
|
|
3270
3718
|
setDeletePreview(null);
|
|
@@ -3279,133 +3727,209 @@ function ObjectPage({ client, slug, id }) {
|
|
|
3279
3727
|
setIsDeletePreviewLoading(false);
|
|
3280
3728
|
}
|
|
3281
3729
|
}, [client, id, slug, t]);
|
|
3282
|
-
|
|
3283
|
-
|
|
3730
|
+
return {
|
|
3731
|
+
actionsAnchorEl,
|
|
3732
|
+
activeActionSlug,
|
|
3733
|
+
data,
|
|
3734
|
+
deleteConfirmOpen,
|
|
3735
|
+
deletePreview,
|
|
3736
|
+
deletePreviewError,
|
|
3737
|
+
detailFields,
|
|
3738
|
+
editableFieldNames,
|
|
3739
|
+
error,
|
|
3740
|
+
fieldMap,
|
|
3741
|
+
handleDelete,
|
|
3742
|
+
handleFieldChange,
|
|
3743
|
+
handleNavigateBack,
|
|
3744
|
+
handleOpenDeletePreview,
|
|
3745
|
+
handleRunObjectAction,
|
|
3746
|
+
handleSave,
|
|
3747
|
+
initialValues,
|
|
3748
|
+
isActionsMenuOpen,
|
|
3749
|
+
isDeletePreviewLoading,
|
|
3750
|
+
isDeleting,
|
|
3751
|
+
isDirty,
|
|
3752
|
+
isLoading,
|
|
3753
|
+
isSaving,
|
|
3754
|
+
meta,
|
|
3755
|
+
objectActions,
|
|
3756
|
+
objectTitle,
|
|
3757
|
+
setActionsAnchorEl,
|
|
3758
|
+
setDeleteConfirmOpen,
|
|
3759
|
+
setDeletePreview,
|
|
3760
|
+
setDeletePreviewError,
|
|
3761
|
+
values
|
|
3762
|
+
};
|
|
3763
|
+
}
|
|
3764
|
+
|
|
3765
|
+
// src/components/ObjectPage.tsx
|
|
3766
|
+
import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3767
|
+
function ObjectPage({ client, slug, id, router }) {
|
|
3768
|
+
var _a, _b;
|
|
3769
|
+
const locale = useAdminLocale();
|
|
3770
|
+
const t = useAdminTranslation();
|
|
3771
|
+
const resolvedRouter = useXLAdminRouter(router);
|
|
3772
|
+
const location = useXLAdminLocation(resolvedRouter);
|
|
3773
|
+
const pathname = location.pathname;
|
|
3774
|
+
const theme = useTheme3();
|
|
3775
|
+
const isPhone = useMediaQuery3(theme.breakpoints.down("sm"));
|
|
3776
|
+
const listPath = pathname.split("/").slice(0, -1).join("/");
|
|
3777
|
+
const controller = useObjectPageController({
|
|
3778
|
+
client,
|
|
3779
|
+
slug,
|
|
3780
|
+
id,
|
|
3781
|
+
listPath,
|
|
3782
|
+
router: resolvedRouter,
|
|
3783
|
+
t
|
|
3784
|
+
});
|
|
3785
|
+
useAdminDocumentTitle(t("admin_title"), (_b = (_a = controller.meta) == null ? void 0 : _a.title) != null ? _b : slug, controller.objectTitle);
|
|
3786
|
+
if (controller.isLoading && !controller.data) {
|
|
3787
|
+
return /* @__PURE__ */ jsx23(ObjectPageSkeleton, {});
|
|
3284
3788
|
}
|
|
3285
|
-
if (error && !data) {
|
|
3286
|
-
return /* @__PURE__ */
|
|
3789
|
+
if (controller.error && !controller.data) {
|
|
3790
|
+
return /* @__PURE__ */ jsx23(Alert6, { severity: "error", children: controller.error });
|
|
3287
3791
|
}
|
|
3288
|
-
if (!data || !meta) {
|
|
3289
|
-
return /* @__PURE__ */
|
|
3792
|
+
if (!controller.data || !controller.meta) {
|
|
3793
|
+
return /* @__PURE__ */ jsx23(ObjectPageSkeleton, {});
|
|
3290
3794
|
}
|
|
3291
|
-
return /* @__PURE__ */ jsxs15(LocalizationProvider2, { dateAdapter: AdapterDayjs2, adapterLocale: locale, children: [
|
|
3795
|
+
return /* @__PURE__ */ jsx23(XLAdminRouterProvider, { router: resolvedRouter, children: /* @__PURE__ */ jsxs15(LocalizationProvider2, { dateAdapter: AdapterDayjs2, adapterLocale: locale, children: [
|
|
3292
3796
|
/* @__PURE__ */ jsxs15(Stack12, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
|
|
3293
|
-
/* @__PURE__ */
|
|
3797
|
+
/* @__PURE__ */ jsx23(
|
|
3294
3798
|
MainHeader,
|
|
3295
3799
|
{
|
|
3296
|
-
title: objectTitle,
|
|
3297
|
-
subtitle: meta.slug,
|
|
3298
|
-
beforeSubtitle: /* @__PURE__ */
|
|
3800
|
+
title: controller.objectTitle,
|
|
3801
|
+
subtitle: controller.meta.slug,
|
|
3802
|
+
beforeSubtitle: /* @__PURE__ */ jsx23(
|
|
3299
3803
|
IconButton4,
|
|
3300
3804
|
{
|
|
3301
3805
|
"aria-label": t("back"),
|
|
3302
|
-
onClick: handleNavigateBack,
|
|
3806
|
+
onClick: controller.handleNavigateBack,
|
|
3303
3807
|
size: "small",
|
|
3304
3808
|
sx: { ml: -0.5 },
|
|
3305
|
-
children: /* @__PURE__ */
|
|
3809
|
+
children: /* @__PURE__ */ jsx23(ArrowBackIcon, { fontSize: "small" })
|
|
3306
3810
|
}
|
|
3307
3811
|
),
|
|
3308
|
-
actions: isPhone ? /* @__PURE__ */
|
|
3812
|
+
actions: isPhone ? /* @__PURE__ */ jsx23(
|
|
3309
3813
|
IconButton4,
|
|
3310
3814
|
{
|
|
3311
3815
|
"aria-label": t("actions"),
|
|
3312
|
-
onClick: (event) => setActionsAnchorEl(event.currentTarget),
|
|
3816
|
+
onClick: (event) => controller.setActionsAnchorEl(event.currentTarget),
|
|
3313
3817
|
size: "small",
|
|
3314
3818
|
sx: { mr: -0.5 },
|
|
3315
|
-
children: /* @__PURE__ */
|
|
3819
|
+
children: /* @__PURE__ */ jsx23(MoreVertIcon2, { fontSize: "small" })
|
|
3316
3820
|
}
|
|
3317
3821
|
) : void 0,
|
|
3318
|
-
details: meta.description ? /* @__PURE__ */
|
|
3319
|
-
error
|
|
3822
|
+
details: controller.meta.description ? /* @__PURE__ */ jsx23(Typography6, { color: "text.secondary", sx: { fontSize: 14, lineHeight: 1.45 }, children: controller.meta.description }) : void 0,
|
|
3823
|
+
error: controller.error
|
|
3320
3824
|
}
|
|
3321
3825
|
),
|
|
3322
|
-
/* @__PURE__ */ jsxs15(
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
{
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
if (editableFieldNames.has(fieldName)) {
|
|
3338
|
-
return /* @__PURE__ */ jsx22(
|
|
3339
|
-
ObjectField,
|
|
3340
|
-
{
|
|
3341
|
-
field,
|
|
3342
|
-
value: values[field.name],
|
|
3343
|
-
slug,
|
|
3344
|
-
client,
|
|
3345
|
-
onFieldChange: handleFieldChange
|
|
3346
|
-
},
|
|
3347
|
-
field.name
|
|
3348
|
-
);
|
|
3349
|
-
}
|
|
3350
|
-
return /* @__PURE__ */ jsx22(
|
|
3351
|
-
ReadonlyObjectField,
|
|
3352
|
-
{
|
|
3353
|
-
field,
|
|
3354
|
-
value: formatAdminValue(values[field.name], { locale, field, pretty: true }),
|
|
3355
|
-
imageUrl: field.display_kind === "image" ? resolveAdminMediaUrl(values[field.name], field) : null
|
|
3826
|
+
/* @__PURE__ */ jsxs15(
|
|
3827
|
+
Stack12,
|
|
3828
|
+
{
|
|
3829
|
+
direction: { xs: "column", lg: "row" },
|
|
3830
|
+
spacing: 1.5,
|
|
3831
|
+
sx: { flex: 1, minHeight: 0, alignItems: "stretch" },
|
|
3832
|
+
children: [
|
|
3833
|
+
/* @__PURE__ */ jsx23(
|
|
3834
|
+
Paper8,
|
|
3835
|
+
{
|
|
3836
|
+
sx: {
|
|
3837
|
+
borderRadius: "10px",
|
|
3838
|
+
flex: 1,
|
|
3839
|
+
minHeight: 0,
|
|
3840
|
+
overflow: "hidden"
|
|
3356
3841
|
},
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3842
|
+
children: /* @__PURE__ */ jsx23(Box12, { component: "form", autoComplete: "off", sx: { height: "100%", overflow: "auto", p: 2.5 }, children: /* @__PURE__ */ jsx23(Stack12, { spacing: 1.5, children: controller.detailFields.map((fieldName) => {
|
|
3843
|
+
const field = controller.fieldMap.get(fieldName);
|
|
3844
|
+
if (!field) {
|
|
3845
|
+
return null;
|
|
3846
|
+
}
|
|
3847
|
+
if (controller.editableFieldNames.has(fieldName)) {
|
|
3848
|
+
return /* @__PURE__ */ jsx23(
|
|
3849
|
+
ObjectField,
|
|
3850
|
+
{
|
|
3851
|
+
field,
|
|
3852
|
+
value: controller.values[field.name],
|
|
3853
|
+
slug,
|
|
3854
|
+
client,
|
|
3855
|
+
onFieldChange: controller.handleFieldChange
|
|
3856
|
+
},
|
|
3857
|
+
field.name
|
|
3858
|
+
);
|
|
3859
|
+
}
|
|
3860
|
+
return /* @__PURE__ */ jsx23(
|
|
3861
|
+
ReadonlyObjectField,
|
|
3862
|
+
{
|
|
3863
|
+
field,
|
|
3864
|
+
value: formatAdminValue(controller.values[field.name], {
|
|
3865
|
+
locale,
|
|
3866
|
+
field,
|
|
3867
|
+
pretty: true
|
|
3868
|
+
}),
|
|
3869
|
+
imageUrl: field.display_kind === "image" ? resolveAdminMediaUrl(controller.values[field.name], field) : null
|
|
3870
|
+
},
|
|
3871
|
+
field.name
|
|
3872
|
+
);
|
|
3873
|
+
}) }) })
|
|
3874
|
+
}
|
|
3875
|
+
),
|
|
3876
|
+
/* @__PURE__ */ jsx23(
|
|
3877
|
+
Paper8,
|
|
3878
|
+
{
|
|
3879
|
+
sx: {
|
|
3880
|
+
width: { xs: "100%", lg: 280 },
|
|
3881
|
+
flexShrink: 0,
|
|
3882
|
+
borderRadius: "10px",
|
|
3883
|
+
p: 1.5,
|
|
3884
|
+
alignSelf: "flex-start",
|
|
3885
|
+
position: { lg: "sticky" },
|
|
3886
|
+
top: { lg: 0 },
|
|
3887
|
+
display: isPhone ? "none" : void 0
|
|
3395
3888
|
},
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3889
|
+
children: /* @__PURE__ */ jsxs15(Stack12, { spacing: 1, children: [
|
|
3890
|
+
/* @__PURE__ */ jsx23(Typography6, { variant: "subtitle2", color: "text.secondary", children: t("actions") }),
|
|
3891
|
+
controller.isDirty ? /* @__PURE__ */ jsx23(
|
|
3892
|
+
Button5,
|
|
3893
|
+
{
|
|
3894
|
+
variant: "contained",
|
|
3895
|
+
onClick: () => void controller.handleSave(),
|
|
3896
|
+
disabled: controller.isSaving,
|
|
3897
|
+
children: controller.isSaving ? t("saving") : t("save")
|
|
3898
|
+
}
|
|
3899
|
+
) : null,
|
|
3900
|
+
/* @__PURE__ */ jsx23(
|
|
3901
|
+
Button5,
|
|
3902
|
+
{
|
|
3903
|
+
variant: "outlined",
|
|
3904
|
+
color: "error",
|
|
3905
|
+
onClick: () => void controller.handleOpenDeletePreview(),
|
|
3906
|
+
disabled: controller.isDeleting,
|
|
3907
|
+
children: t("delete")
|
|
3908
|
+
}
|
|
3909
|
+
),
|
|
3910
|
+
controller.objectActions.map((action) => /* @__PURE__ */ jsx23(
|
|
3911
|
+
Button5,
|
|
3912
|
+
{
|
|
3913
|
+
variant: "outlined",
|
|
3914
|
+
onClick: () => void controller.handleRunObjectAction(action.slug),
|
|
3915
|
+
disabled: controller.activeActionSlug !== null,
|
|
3916
|
+
children: controller.activeActionSlug === action.slug ? t("executing") : action.label
|
|
3917
|
+
},
|
|
3918
|
+
action.slug
|
|
3919
|
+
))
|
|
3920
|
+
] })
|
|
3921
|
+
}
|
|
3922
|
+
)
|
|
3923
|
+
]
|
|
3924
|
+
}
|
|
3925
|
+
)
|
|
3402
3926
|
] }),
|
|
3403
3927
|
/* @__PURE__ */ jsxs15(
|
|
3404
3928
|
Menu2,
|
|
3405
3929
|
{
|
|
3406
|
-
anchorEl: actionsAnchorEl,
|
|
3407
|
-
open: isActionsMenuOpen,
|
|
3408
|
-
onClose: () => setActionsAnchorEl(null),
|
|
3930
|
+
anchorEl: controller.actionsAnchorEl,
|
|
3931
|
+
open: controller.isActionsMenuOpen,
|
|
3932
|
+
onClose: () => controller.setActionsAnchorEl(null),
|
|
3409
3933
|
slotProps: {
|
|
3410
3934
|
paper: {
|
|
3411
3935
|
sx: {
|
|
@@ -3416,67 +3940,66 @@ function ObjectPage({ client, slug, id }) {
|
|
|
3416
3940
|
anchorOrigin: { vertical: "bottom", horizontal: "right" },
|
|
3417
3941
|
transformOrigin: { vertical: "top", horizontal: "right" },
|
|
3418
3942
|
children: [
|
|
3419
|
-
isDirty ? /* @__PURE__ */
|
|
3943
|
+
controller.isDirty ? /* @__PURE__ */ jsx23(
|
|
3420
3944
|
MenuItem3,
|
|
3421
3945
|
{
|
|
3422
3946
|
onClick: () => {
|
|
3423
|
-
setActionsAnchorEl(null);
|
|
3424
|
-
void handleSave();
|
|
3947
|
+
controller.setActionsAnchorEl(null);
|
|
3948
|
+
void controller.handleSave();
|
|
3425
3949
|
},
|
|
3426
|
-
disabled: isSaving,
|
|
3427
|
-
children: isSaving ? t("saving") : t("save")
|
|
3950
|
+
disabled: controller.isSaving,
|
|
3951
|
+
children: controller.isSaving ? t("saving") : t("save")
|
|
3428
3952
|
}
|
|
3429
3953
|
) : null,
|
|
3430
|
-
/* @__PURE__ */
|
|
3954
|
+
/* @__PURE__ */ jsx23(
|
|
3431
3955
|
MenuItem3,
|
|
3432
3956
|
{
|
|
3433
|
-
onClick: () => void handleOpenDeletePreview(),
|
|
3434
|
-
disabled: isDeleting,
|
|
3957
|
+
onClick: () => void controller.handleOpenDeletePreview(),
|
|
3958
|
+
disabled: controller.isDeleting,
|
|
3435
3959
|
sx: { color: "error.main" },
|
|
3436
3960
|
children: t("delete")
|
|
3437
3961
|
}
|
|
3438
3962
|
),
|
|
3439
|
-
objectActions.map((action) => /* @__PURE__ */
|
|
3963
|
+
controller.objectActions.map((action) => /* @__PURE__ */ jsx23(
|
|
3440
3964
|
MenuItem3,
|
|
3441
3965
|
{
|
|
3442
3966
|
onClick: () => {
|
|
3443
|
-
setActionsAnchorEl(null);
|
|
3444
|
-
void handleRunObjectAction(action.slug);
|
|
3967
|
+
controller.setActionsAnchorEl(null);
|
|
3968
|
+
void controller.handleRunObjectAction(action.slug);
|
|
3445
3969
|
},
|
|
3446
|
-
disabled: activeActionSlug !== null,
|
|
3447
|
-
children: activeActionSlug === action.slug ? t("executing") : action.label
|
|
3970
|
+
disabled: controller.activeActionSlug !== null,
|
|
3971
|
+
children: controller.activeActionSlug === action.slug ? t("executing") : action.label
|
|
3448
3972
|
},
|
|
3449
3973
|
action.slug
|
|
3450
3974
|
))
|
|
3451
3975
|
]
|
|
3452
3976
|
}
|
|
3453
3977
|
),
|
|
3454
|
-
/* @__PURE__ */
|
|
3978
|
+
/* @__PURE__ */ jsx23(
|
|
3455
3979
|
DeletePreviewDialog,
|
|
3456
3980
|
{
|
|
3457
|
-
open: deleteConfirmOpen,
|
|
3981
|
+
open: controller.deleteConfirmOpen,
|
|
3458
3982
|
title: t("delete_object_title"),
|
|
3459
|
-
preview: deletePreview,
|
|
3460
|
-
error: deletePreviewError,
|
|
3461
|
-
isLoading: isDeletePreviewLoading,
|
|
3462
|
-
isSubmitting: isDeleting,
|
|
3983
|
+
preview: controller.deletePreview,
|
|
3984
|
+
error: controller.deletePreviewError,
|
|
3985
|
+
isLoading: controller.isDeletePreviewLoading,
|
|
3986
|
+
isSubmitting: controller.isDeleting,
|
|
3463
3987
|
onClose: () => {
|
|
3464
|
-
if (isDeleting) {
|
|
3988
|
+
if (controller.isDeleting) {
|
|
3465
3989
|
return;
|
|
3466
3990
|
}
|
|
3467
|
-
setDeleteConfirmOpen(false);
|
|
3468
|
-
setDeletePreview(null);
|
|
3469
|
-
setDeletePreviewError(null);
|
|
3991
|
+
controller.setDeleteConfirmOpen(false);
|
|
3992
|
+
controller.setDeletePreview(null);
|
|
3993
|
+
controller.setDeletePreviewError(null);
|
|
3470
3994
|
},
|
|
3471
|
-
onConfirm: () => void handleDelete()
|
|
3995
|
+
onConfirm: () => void controller.handleDelete()
|
|
3472
3996
|
}
|
|
3473
3997
|
)
|
|
3474
|
-
] });
|
|
3998
|
+
] }) });
|
|
3475
3999
|
}
|
|
3476
4000
|
|
|
3477
4001
|
// src/components/Shell.tsx
|
|
3478
|
-
import { useEffect as
|
|
3479
|
-
import { usePathname as usePathname5 } from "next/navigation.js";
|
|
4002
|
+
import { useEffect as useEffect11, useMemo as useMemo10, useState as useState11 } from "react";
|
|
3480
4003
|
import { Box as Box15, CssBaseline, Drawer, GlobalStyles, Stack as Stack13, useMediaQuery as useMediaQuery4 } from "@mui/material";
|
|
3481
4004
|
import { ThemeProvider } from "@mui/material/styles";
|
|
3482
4005
|
|
|
@@ -3608,11 +4131,10 @@ var defaultAdminTheme = createTheme({
|
|
|
3608
4131
|
});
|
|
3609
4132
|
|
|
3610
4133
|
// src/components/layout/Main.tsx
|
|
3611
|
-
import { usePathname as usePathname3 } from "next/navigation.js";
|
|
3612
4134
|
import { Box as Box13 } from "@mui/material";
|
|
3613
|
-
import { jsx as
|
|
4135
|
+
import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
3614
4136
|
function Main({ children }) {
|
|
3615
|
-
const pathname =
|
|
4137
|
+
const { pathname } = useXLAdminLocation();
|
|
3616
4138
|
const { pendingPath, pendingView } = useShellContext();
|
|
3617
4139
|
const normalizeAdminPath2 = (path) => {
|
|
3618
4140
|
const normalizedPath = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
|
|
@@ -3633,7 +4155,7 @@ function Main({ children }) {
|
|
|
3633
4155
|
},
|
|
3634
4156
|
children: [
|
|
3635
4157
|
children,
|
|
3636
|
-
isPendingNavigation ? /* @__PURE__ */
|
|
4158
|
+
isPendingNavigation ? /* @__PURE__ */ jsx24(
|
|
3637
4159
|
Box13,
|
|
3638
4160
|
{
|
|
3639
4161
|
sx: {
|
|
@@ -3642,7 +4164,7 @@ function Main({ children }) {
|
|
|
3642
4164
|
zIndex: 5,
|
|
3643
4165
|
backgroundColor: "background.default"
|
|
3644
4166
|
},
|
|
3645
|
-
children: pendingView === "model" || pendingView === "overview" ? /* @__PURE__ */
|
|
4167
|
+
children: pendingView === "model" || pendingView === "overview" ? /* @__PURE__ */ jsx24(ModelPageSkeleton, {}) : /* @__PURE__ */ jsx24(ModelPageSkeleton, {})
|
|
3646
4168
|
}
|
|
3647
4169
|
) : null
|
|
3648
4170
|
]
|
|
@@ -3652,13 +4174,12 @@ function Main({ children }) {
|
|
|
3652
4174
|
|
|
3653
4175
|
// src/components/layout/Sidebar.tsx
|
|
3654
4176
|
import { memo as memo8 } from "react";
|
|
3655
|
-
import { usePathname as usePathname4 } from "next/navigation.js";
|
|
3656
4177
|
import { Box as Box14, ListItemButton as ListItemButton3, Typography as Typography7 } from "@mui/material";
|
|
3657
|
-
import { jsx as
|
|
4178
|
+
import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
3658
4179
|
var Sidebar = memo8(function Sidebar2({ models, blocks, basePath }) {
|
|
3659
4180
|
var _a;
|
|
3660
4181
|
const t = useAdminTranslation();
|
|
3661
|
-
const pathname =
|
|
4182
|
+
const { pathname } = useXLAdminLocation();
|
|
3662
4183
|
const { pendingPath, startPendingNavigation } = useShellContext();
|
|
3663
4184
|
const effectivePathname = pendingPath != null ? pendingPath : pathname;
|
|
3664
4185
|
const normalizedBasePath = basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
|
|
@@ -3667,7 +4188,7 @@ var Sidebar = memo8(function Sidebar2({ models, blocks, basePath }) {
|
|
|
3667
4188
|
const relativePath = matchedBasePath ? effectivePathname.slice(matchedBasePath.length) : "";
|
|
3668
4189
|
const activeModelSlug = (_a = relativePath.split("/").filter(Boolean)[0]) != null ? _a : null;
|
|
3669
4190
|
const isOverviewActive = matchedBasePath !== null && (effectivePathname === matchedBasePath || effectivePathname === `${matchedBasePath}/`);
|
|
3670
|
-
return /* @__PURE__ */
|
|
4191
|
+
return /* @__PURE__ */ jsx25(Box14, { sx: { height: "100%", overflow: "hidden" }, children: /* @__PURE__ */ jsx25(
|
|
3671
4192
|
Box14,
|
|
3672
4193
|
{
|
|
3673
4194
|
sx: {
|
|
@@ -3680,13 +4201,13 @@ var Sidebar = memo8(function Sidebar2({ models, blocks, basePath }) {
|
|
|
3680
4201
|
pl: 0
|
|
3681
4202
|
},
|
|
3682
4203
|
children: /* @__PURE__ */ jsxs17(Box14, { sx: { direction: "ltr", pl: 1 }, children: [
|
|
3683
|
-
/* @__PURE__ */
|
|
4204
|
+
/* @__PURE__ */ jsx25(
|
|
3684
4205
|
NavLink,
|
|
3685
4206
|
{
|
|
3686
4207
|
href: basePath,
|
|
3687
4208
|
style: { textDecoration: "none", display: "block" },
|
|
3688
4209
|
onClick: () => startPendingNavigation(basePath, "overview"),
|
|
3689
|
-
children: /* @__PURE__ */
|
|
4210
|
+
children: /* @__PURE__ */ jsx25(
|
|
3690
4211
|
ListItemButton3,
|
|
3691
4212
|
{
|
|
3692
4213
|
selected: isOverviewActive,
|
|
@@ -3699,12 +4220,12 @@ var Sidebar = memo8(function Sidebar2({ models, blocks, basePath }) {
|
|
|
3699
4220
|
backgroundColor: isOverviewActive ? "rgba(255, 255, 255, 0.2)" : "rgba(255, 255, 255, 0.055)"
|
|
3700
4221
|
}
|
|
3701
4222
|
},
|
|
3702
|
-
children: /* @__PURE__ */
|
|
4223
|
+
children: /* @__PURE__ */ jsx25(Typography7, { variant: "subtitle1", sx: { fontWeight: 700 }, children: t("overview") })
|
|
3703
4224
|
}
|
|
3704
4225
|
)
|
|
3705
4226
|
}
|
|
3706
4227
|
),
|
|
3707
|
-
/* @__PURE__ */
|
|
4228
|
+
/* @__PURE__ */ jsx25(
|
|
3708
4229
|
ModelsBlocks,
|
|
3709
4230
|
{
|
|
3710
4231
|
models,
|
|
@@ -3721,28 +4242,30 @@ var Sidebar = memo8(function Sidebar2({ models, blocks, basePath }) {
|
|
|
3721
4242
|
});
|
|
3722
4243
|
|
|
3723
4244
|
// src/components/Shell.tsx
|
|
3724
|
-
import { jsx as
|
|
4245
|
+
import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
3725
4246
|
function normalizeAdminPath(path) {
|
|
3726
4247
|
const normalizedPath = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
|
|
3727
4248
|
return normalizedPath.replace(/^\/(ru|en)(?=\/|$)/, "") || "/";
|
|
3728
4249
|
}
|
|
3729
|
-
function Shell({ client, models, blocks, basePath, locale, children, theme }) {
|
|
4250
|
+
function Shell({ client, models, blocks, basePath, locale, children, theme, router }) {
|
|
3730
4251
|
void client;
|
|
3731
4252
|
const activeTheme = theme != null ? theme : defaultAdminTheme;
|
|
3732
|
-
const
|
|
4253
|
+
const resolvedRouter = useXLAdminRouter(router);
|
|
4254
|
+
const location = useXLAdminLocation(resolvedRouter);
|
|
4255
|
+
const pathname = location.pathname;
|
|
3733
4256
|
const isDesktopSidebar = useMediaQuery4(activeTheme.breakpoints.up("lg"));
|
|
3734
|
-
const [isMobileSidebarOpen, setIsMobileSidebarOpen] =
|
|
3735
|
-
const [pendingPath, setPendingPath] =
|
|
3736
|
-
const [pendingView, setPendingView] =
|
|
3737
|
-
|
|
4257
|
+
const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState11(false);
|
|
4258
|
+
const [pendingPath, setPendingPath] = useState11(null);
|
|
4259
|
+
const [pendingView, setPendingView] = useState11(null);
|
|
4260
|
+
useEffect11(() => {
|
|
3738
4261
|
if (isDesktopSidebar) {
|
|
3739
4262
|
setIsMobileSidebarOpen(false);
|
|
3740
4263
|
}
|
|
3741
4264
|
}, [isDesktopSidebar]);
|
|
3742
|
-
|
|
4265
|
+
useEffect11(() => {
|
|
3743
4266
|
setIsMobileSidebarOpen(false);
|
|
3744
4267
|
}, [pathname]);
|
|
3745
|
-
|
|
4268
|
+
useEffect11(() => {
|
|
3746
4269
|
if (pendingPath === null) {
|
|
3747
4270
|
return;
|
|
3748
4271
|
}
|
|
@@ -3751,7 +4274,7 @@ function Shell({ client, models, blocks, basePath, locale, children, theme }) {
|
|
|
3751
4274
|
setPendingView(null);
|
|
3752
4275
|
}
|
|
3753
4276
|
}, [pathname, pendingPath]);
|
|
3754
|
-
const shellContextValue =
|
|
4277
|
+
const shellContextValue = useMemo10(() => ({
|
|
3755
4278
|
isMobile: !isDesktopSidebar,
|
|
3756
4279
|
openMobileSidebar: () => setIsMobileSidebarOpen(true),
|
|
3757
4280
|
pendingPath,
|
|
@@ -3764,9 +4287,9 @@ function Shell({ client, models, blocks, basePath, locale, children, theme }) {
|
|
|
3764
4287
|
setPendingView(view);
|
|
3765
4288
|
}
|
|
3766
4289
|
}), [isDesktopSidebar, pathname, pendingPath, pendingView]);
|
|
3767
|
-
return /* @__PURE__ */
|
|
3768
|
-
/* @__PURE__ */
|
|
3769
|
-
/* @__PURE__ */
|
|
4290
|
+
return /* @__PURE__ */ jsx26(XLAdminRouterProvider, { router: resolvedRouter, children: /* @__PURE__ */ jsx26(ThemeProvider, { theme: activeTheme, children: /* @__PURE__ */ jsx26(AdminLocaleProvider, { locale, children: /* @__PURE__ */ jsx26(AdminDataProvider, { value: { locale: locale === "en" ? "en" : "ru", models, blocks }, children: /* @__PURE__ */ jsxs18(ShellContextProvider, { value: shellContextValue, children: [
|
|
4291
|
+
/* @__PURE__ */ jsx26(CssBaseline, {}),
|
|
4292
|
+
/* @__PURE__ */ jsx26(
|
|
3770
4293
|
GlobalStyles,
|
|
3771
4294
|
{
|
|
3772
4295
|
styles: (muiTheme) => ({
|
|
@@ -3805,7 +4328,7 @@ function Shell({ client, models, blocks, basePath, locale, children, theme }) {
|
|
|
3805
4328
|
})
|
|
3806
4329
|
}
|
|
3807
4330
|
),
|
|
3808
|
-
/* @__PURE__ */
|
|
4331
|
+
/* @__PURE__ */ jsx26(
|
|
3809
4332
|
Box15,
|
|
3810
4333
|
{
|
|
3811
4334
|
"data-xladmin-root": "true",
|
|
@@ -3823,7 +4346,7 @@ function Shell({ client, models, blocks, basePath, locale, children, theme }) {
|
|
|
3823
4346
|
spacing: 0,
|
|
3824
4347
|
sx: { height: "100%", minHeight: 0, alignItems: "stretch" },
|
|
3825
4348
|
children: [
|
|
3826
|
-
/* @__PURE__ */
|
|
4349
|
+
/* @__PURE__ */ jsx26(
|
|
3827
4350
|
Box15,
|
|
3828
4351
|
{
|
|
3829
4352
|
sx: {
|
|
@@ -3835,10 +4358,10 @@ function Shell({ client, models, blocks, basePath, locale, children, theme }) {
|
|
|
3835
4358
|
pl: 0,
|
|
3836
4359
|
pr: 1
|
|
3837
4360
|
},
|
|
3838
|
-
children: /* @__PURE__ */
|
|
4361
|
+
children: /* @__PURE__ */ jsx26(Sidebar, { models, blocks, basePath })
|
|
3839
4362
|
}
|
|
3840
4363
|
),
|
|
3841
|
-
/* @__PURE__ */
|
|
4364
|
+
/* @__PURE__ */ jsx26(
|
|
3842
4365
|
Box15,
|
|
3843
4366
|
{
|
|
3844
4367
|
sx: {
|
|
@@ -3852,7 +4375,7 @@ function Shell({ client, models, blocks, basePath, locale, children, theme }) {
|
|
|
3852
4375
|
py: { xs: 1, sm: 1.5, lg: 2 },
|
|
3853
4376
|
pl: { xs: 1, sm: 1.5, lg: 1 }
|
|
3854
4377
|
},
|
|
3855
|
-
children: /* @__PURE__ */
|
|
4378
|
+
children: /* @__PURE__ */ jsx26(Main, { children })
|
|
3856
4379
|
}
|
|
3857
4380
|
)
|
|
3858
4381
|
]
|
|
@@ -3860,7 +4383,7 @@ function Shell({ client, models, blocks, basePath, locale, children, theme }) {
|
|
|
3860
4383
|
)
|
|
3861
4384
|
}
|
|
3862
4385
|
),
|
|
3863
|
-
/* @__PURE__ */
|
|
4386
|
+
/* @__PURE__ */ jsx26(
|
|
3864
4387
|
Drawer,
|
|
3865
4388
|
{
|
|
3866
4389
|
anchor: "left",
|
|
@@ -3879,10 +4402,10 @@ function Shell({ client, models, blocks, basePath, locale, children, theme }) {
|
|
|
3879
4402
|
}
|
|
3880
4403
|
}
|
|
3881
4404
|
},
|
|
3882
|
-
children: /* @__PURE__ */
|
|
4405
|
+
children: /* @__PURE__ */ jsx26(Box15, { sx: { height: "100%", minHeight: 0, pr: 1.5 }, children: /* @__PURE__ */ jsx26(Sidebar, { models, blocks, basePath }) })
|
|
3883
4406
|
}
|
|
3884
4407
|
)
|
|
3885
|
-
] }) }) }) });
|
|
4408
|
+
] }) }) }) }) });
|
|
3886
4409
|
}
|
|
3887
4410
|
export {
|
|
3888
4411
|
AdminLocaleProvider,
|
|
@@ -3898,13 +4421,19 @@ export {
|
|
|
3898
4421
|
OverviewPage,
|
|
3899
4422
|
Shell,
|
|
3900
4423
|
Sidebar,
|
|
4424
|
+
XLAdminRouterProvider,
|
|
4425
|
+
buildUrlWithParams,
|
|
3901
4426
|
createAxiosXLAdminClient,
|
|
4427
|
+
createBrowserXLAdminRouter,
|
|
3902
4428
|
createFetchXLAdminClient,
|
|
3903
4429
|
createFetchXLAdminTransport,
|
|
3904
4430
|
createXLAdminClient,
|
|
3905
4431
|
defaultAdminTheme,
|
|
4432
|
+
handleNavLinkClick,
|
|
3906
4433
|
normalizeAdminLocale,
|
|
3907
4434
|
translateAdmin,
|
|
3908
4435
|
useAdminLocale,
|
|
3909
|
-
useAdminTranslation
|
|
4436
|
+
useAdminTranslation,
|
|
4437
|
+
useXLAdminLocation,
|
|
4438
|
+
useXLAdminRouter
|
|
3910
4439
|
};
|