xladmin 0.3.6 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -53,6 +53,32 @@ function createAdminClient(transport) {
53
53
  payload != null ? payload : {}
54
54
  );
55
55
  },
56
+ async getBulkActionChoices(slug, actionSlug, fieldName, q, ids, options) {
57
+ return await transportGet(
58
+ transport,
59
+ `/xladmin/models/${slug}/bulk-actions/${actionSlug}/fields/${fieldName}/choices/`,
60
+ {
61
+ signal: options == null ? void 0 : options.signal,
62
+ params: {
63
+ ...q ? { q } : {},
64
+ ...ids && ids.length > 0 ? { ids: ids.join(",") } : {}
65
+ }
66
+ }
67
+ );
68
+ },
69
+ async getObjectActionChoices(slug, id, actionSlug, fieldName, q, ids, options) {
70
+ return await transportGet(
71
+ transport,
72
+ `/xladmin/models/${slug}/items/${id}/actions/${actionSlug}/fields/${fieldName}/choices/`,
73
+ {
74
+ signal: options == null ? void 0 : options.signal,
75
+ params: {
76
+ ...q ? { q } : {},
77
+ ...ids && ids.length > 0 ? { ids: ids.join(",") } : {}
78
+ }
79
+ }
80
+ );
81
+ },
56
82
  async getChoices(slug, fieldName, q, ids, options) {
57
83
  return await transportGet(
58
84
  transport,
@@ -302,7 +328,7 @@ function handleNavLinkClick(event, { href, onClick, router }) {
302
328
  }
303
329
 
304
330
  // src/components/FormDialog.tsx
305
- import { useEffect as useEffect4, useMemo as useMemo5, useState as useState4 } from "react";
331
+ import { useEffect as useEffect4, useMemo as useMemo5, useRef as useRef4, useState as useState4 } from "react";
306
332
  import { Alert, Box as Box2, Button, Dialog, DialogActions, DialogContent, DialogTitle } from "@mui/material";
307
333
  import { LocalizationProvider } from "@mui/x-date-pickers";
308
334
  import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
@@ -455,6 +481,7 @@ function useAdminTranslation() {
455
481
  }
456
482
 
457
483
  // src/utils/adminFields.ts
484
+ import dayjs from "dayjs";
458
485
  function buildAdminPayload(values, fields) {
459
486
  const fieldMap = new Map(fields.map((field) => [field.name, field]));
460
487
  const payload = {};
@@ -477,6 +504,26 @@ function buildAdminPayload(values, fields) {
477
504
  }
478
505
  return payload;
479
506
  }
507
+ function buildAdminFormInitialValues(fields, initialValues) {
508
+ var _a, _b, _c, _d;
509
+ const values = { ...initialValues != null ? initialValues : {} };
510
+ for (const field of fields) {
511
+ if (values[field.name] === void 0 && field.required && field.input_kind === "select" && ((_b = (_a = field.options) == null ? void 0 : _a.length) != null ? _b : 0) > 0) {
512
+ values[field.name] = (_d = (_c = field.options) == null ? void 0 : _c[0]) == null ? void 0 : _d.value;
513
+ }
514
+ if (!field.auto_now || values[field.name] !== void 0) {
515
+ continue;
516
+ }
517
+ if (field.input_kind === "date") {
518
+ values[field.name] = dayjs().format("YYYY-MM-DD");
519
+ continue;
520
+ }
521
+ if (field.input_kind === "datetime") {
522
+ values[field.name] = dayjs().format("YYYY-MM-DD[T]HH:mm:ss");
523
+ }
524
+ }
525
+ return values;
526
+ }
480
527
  function formatAdminValue(value, options) {
481
528
  const locale = normalizeAdminLocale(options == null ? void 0 : options.locale);
482
529
  const maxLength = options == null ? void 0 : options.maxLength;
@@ -603,11 +650,21 @@ function trimAdminValue(value, maxLength) {
603
650
  return `${value.slice(0, maxLength).trimEnd()}\u2026`;
604
651
  }
605
652
 
653
+ // src/utils/pickersLocale.ts
654
+ import { enUS, ruRU } from "@mui/x-date-pickers/locales";
655
+ var pickersLocaleTextByLocale = {
656
+ en: enUS.components.MuiLocalizationProvider.defaultProps.localeText,
657
+ ru: ruRU.components.MuiLocalizationProvider.defaultProps.localeText
658
+ };
659
+ function getMuiPickersLocaleText(locale) {
660
+ return pickersLocaleTextByLocale[locale];
661
+ }
662
+
606
663
  // src/components/FieldEditor.tsx
607
664
  import { memo, useCallback, useEffect as useEffect2, useMemo as useMemo3, useState as useState2 } from "react";
608
- import { Autocomplete, CircularProgress, FormControlLabel, Switch, TextField } from "@mui/material";
665
+ import { Autocomplete, CircularProgress, FormControlLabel, MenuItem, Switch, TextField } from "@mui/material";
609
666
  import { DatePicker, DateTimePicker } from "@mui/x-date-pickers";
610
- import dayjs from "dayjs";
667
+ import dayjs2 from "dayjs";
611
668
 
612
669
  // src/hooks/useRemoteChoices.ts
613
670
  import { useEffect, useRef as useRef2, useState } from "react";
@@ -695,23 +752,53 @@ function isAbortReason(reason) {
695
752
 
696
753
  // src/components/FieldEditor.tsx
697
754
  import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
755
+ var DEFAULT_CHOICE_SCOPE = { kind: "model" };
756
+ function handlePickerButtonMouseDown(event, hasAnotherPickerOpen, onRequestPickerOpen) {
757
+ if (!hasAnotherPickerOpen) {
758
+ return;
759
+ }
760
+ event.preventDefault();
761
+ event.stopPropagation();
762
+ onRequestPickerOpen == null ? void 0 : onRequestPickerOpen();
763
+ }
698
764
  var FieldEditor = memo(function FieldEditor2({
699
765
  field,
700
766
  value,
701
767
  onChange,
702
768
  slug,
703
769
  client,
704
- readOnly = false
770
+ choiceScope,
771
+ readOnly = false,
772
+ isPickerOpen,
773
+ hasAnotherPickerOpen = false,
774
+ onRequestPickerOpen,
775
+ onRequestPickerClose
705
776
  }) {
706
- var _a, _b, _c, _d;
777
+ var _a, _b, _c, _d, _e, _f, _g, _h;
707
778
  const t = useAdminTranslation();
708
779
  const [searchValue, setSearchValue] = useState2("");
709
780
  const [jsonTextValue, setJsonTextValue] = useState2(() => stringifyJsonValue(value));
710
781
  const [jsonError, setJsonError] = useState2(null);
782
+ const resolvedChoiceScope = choiceScope != null ? choiceScope : DEFAULT_CHOICE_SCOPE;
711
783
  const selectedIds = useMemo3(() => normalizeSelectedIds(value, field.is_relation_many), [field.is_relation_many, value]);
712
784
  const loadChoices = useCallback(
713
785
  async (signal) => {
714
- const response = await client.getChoices(
786
+ const response = resolvedChoiceScope.kind === "bulk-action" ? await client.getBulkActionChoices(
787
+ slug,
788
+ resolvedChoiceScope.actionSlug,
789
+ field.name,
790
+ searchValue || void 0,
791
+ selectedIds,
792
+ { signal }
793
+ ) : resolvedChoiceScope.kind === "object-action" ? await client.getObjectActionChoices(
794
+ slug,
795
+ resolvedChoiceScope.itemId,
796
+ resolvedChoiceScope.actionSlug,
797
+ field.name,
798
+ searchValue || void 0,
799
+ selectedIds,
800
+ { signal }
801
+ ) : await client.getChoices(
715
802
  slug,
716
803
  field.name,
717
804
  searchValue || void 0,
@@ -720,7 +807,17 @@ var FieldEditor = memo(function FieldEditor2({
720
807
  );
721
808
  return response.items;
722
809
  },
723
- [client, field.name, searchValue, selectedIds, slug]
810
+ [
811
+ client,
812
+ field.name,
813
+ resolvedChoiceScope.kind,
814
+ resolvedChoiceScope.kind === "bulk-action" ? resolvedChoiceScope.actionSlug : null,
815
+ resolvedChoiceScope.kind === "object-action" ? resolvedChoiceScope.actionSlug : null,
816
+ resolvedChoiceScope.kind === "object-action" ? resolvedChoiceScope.itemId : null,
817
+ searchValue,
818
+ selectedIds,
819
+ slug
820
+ ]
724
821
  );
725
822
  const { items: choices, isLoading: isLoadingChoices } = useRemoteChoices({
726
823
  enabled: field.has_choices,
@@ -742,6 +839,7 @@ var FieldEditor = memo(function FieldEditor2({
742
839
  return /* @__PURE__ */ jsx3(
743
840
  FormControlLabel,
744
841
  {
842
+ required: field.required,
745
843
  control: /* @__PURE__ */ jsx3(
746
844
  Switch,
747
845
  {
@@ -750,7 +848,8 @@ var FieldEditor = memo(function FieldEditor2({
750
848
  onChange: (_, checked) => onChange(checked)
751
849
  }
752
850
  ),
753
- label: field.label
851
+ label: field.label,
852
+ sx: buildRequiredLabelSx()
754
853
  }
755
854
  );
756
855
  }
@@ -760,16 +859,25 @@ var FieldEditor = memo(function FieldEditor2({
760
859
  {
761
860
  label: field.label,
762
861
  disabled: readOnly,
763
- value: value ? dayjs(String(value)) : null,
862
+ open: isPickerOpen,
863
+ value: value ? dayjs2(String(value)) : null,
864
+ onOpen: onRequestPickerOpen,
865
+ onClose: onRequestPickerClose,
764
866
  onChange: (nextValue) => onChange(nextValue ? nextValue.format("YYYY-MM-DD") : null),
765
867
  slotProps: {
766
868
  popper: { disablePortal: true },
767
869
  desktopPaper: buildPickerPaperProps(),
768
870
  mobilePaper: buildPickerPaperProps(),
871
+ openPickerButton: {
872
+ onMouseDown: (event) => handlePickerButtonMouseDown(event, hasAnotherPickerOpen, onRequestPickerOpen)
873
+ },
769
874
  textField: {
770
875
  fullWidth: true,
771
876
  size: "small",
772
- helperText: (_a = field.help_text) != null ? _a : void 0,
877
+ required: field.required,
878
+ sx: buildRequiredLabelSx(),
879
+ placeholder: (_a = field.placeholder) != null ? _a : void 0,
880
+ helperText: (_b = field.help_text) != null ? _b : void 0,
773
881
  slotProps: { htmlInput: buildHtmlInputProps(field) }
774
882
  }
775
883
  }
@@ -782,22 +890,42 @@ var FieldEditor = memo(function FieldEditor2({
782
890
  {
783
891
  label: field.label,
784
892
  disabled: readOnly,
785
- value: value ? dayjs(String(value)) : null,
893
+ open: isPickerOpen,
894
+ value: value ? dayjs2(String(value)) : null,
895
+ onOpen: onRequestPickerOpen,
896
+ onClose: onRequestPickerClose,
786
897
  onChange: (nextValue) => onChange(nextValue ? nextValue.format("YYYY-MM-DD[T]HH:mm:ss") : null),
787
898
  slotProps: {
899
+ actionBar: {
900
+ actions: ["today", "cancel", "accept"]
901
+ },
788
902
  popper: { disablePortal: true },
789
903
  desktopPaper: buildPickerPaperProps(),
790
904
  mobilePaper: buildPickerPaperProps(),
905
+ openPickerButton: {
906
+ onMouseDown: (event) => handlePickerButtonMouseDown(event, hasAnotherPickerOpen, onRequestPickerOpen)
907
+ },
791
908
  textField: {
792
909
  fullWidth: true,
793
910
  size: "small",
794
- helperText: (_b = field.help_text) != null ? _b : void 0,
911
+ required: field.required,
912
+ sx: buildRequiredLabelSx(),
913
+ placeholder: (_c = field.placeholder) != null ? _c : void 0,
914
+ helperText: (_d = field.help_text) != null ? _d : void 0,
795
915
  slotProps: { htmlInput: buildHtmlInputProps(field) }
796
916
  }
797
917
  }
798
918
  }
799
919
  );
800
920
  }
921
+ if (hasStaticOptions(field)) {
922
+ return renderStaticChoiceEditor({
923
+ field,
924
+ value,
925
+ onChange,
926
+ readOnly
927
+ });
928
+ }
801
929
  if (field.has_choices) {
802
930
  return renderChoiceEditor({
803
931
  field,
@@ -837,7 +965,10 @@ var FieldEditor = memo(function FieldEditor2({
837
965
  multiline: true,
838
966
  minRows: 6,
839
967
  error: jsonError !== null,
840
- helperText: (_c = jsonError != null ? jsonError : field.help_text) != null ? _c : void 0,
968
+ required: field.required,
969
+ sx: buildRequiredLabelSx(),
970
+ helperText: (_e = jsonError != null ? jsonError : field.help_text) != null ? _e : void 0,
971
+ placeholder: (_f = field.placeholder) != null ? _f : void 0,
841
972
  slotProps: {
842
973
  htmlInput: buildHtmlInputProps(field)
843
974
  }
@@ -853,7 +984,10 @@ var FieldEditor = memo(function FieldEditor2({
853
984
  size: "small",
854
985
  fullWidth: true,
855
986
  disabled: readOnly,
856
- helperText: (_d = field.help_text) != null ? _d : void 0,
987
+ required: field.required,
988
+ sx: buildRequiredLabelSx(),
989
+ helperText: (_g = field.help_text) != null ? _g : void 0,
990
+ placeholder: (_h = field.placeholder) != null ? _h : void 0,
857
991
  type: resolveInputType(field),
858
992
  multiline: field.input_kind === "textarea" || field.type.toLowerCase().includes("text"),
859
993
  minRows: field.input_kind === "textarea" || field.type.toLowerCase().includes("text") ? 3 : void 0,
@@ -910,15 +1044,17 @@ function renderChoiceEditor({
910
1044
  listbox: { sx: { maxHeight: 240 } }
911
1045
  },
912
1046
  renderInput: (params) => (() => {
913
- var _a2;
1047
+ var _a2, _b;
914
1048
  const { InputProps, inputProps, ...textFieldParams } = params;
915
1049
  return /* @__PURE__ */ jsx3(
916
1050
  TextField,
917
1051
  {
918
1052
  ...textFieldParams,
919
1053
  label: field.label,
920
- placeholder: searchPlaceholder,
921
- helperText: (_a2 = field.help_text) != null ? _a2 : void 0,
1054
+ required: field.required,
1055
+ sx: buildRequiredLabelSx(),
1056
+ placeholder: (_a2 = field.placeholder) != null ? _a2 : searchPlaceholder,
1057
+ helperText: (_b = field.help_text) != null ? _b : void 0,
922
1058
  slotProps: {
923
1059
  input: {
924
1060
  ...InputProps,
@@ -968,15 +1104,17 @@ function renderChoiceEditor({
968
1104
  listbox: { sx: { maxHeight: 240 } }
969
1105
  },
970
1106
  renderInput: (params) => (() => {
971
- var _a2;
1107
+ var _a2, _b;
972
1108
  const { InputProps, inputProps, ...textFieldParams } = params;
973
1109
  return /* @__PURE__ */ jsx3(
974
1110
  TextField,
975
1111
  {
976
1112
  ...textFieldParams,
977
1113
  label: field.label,
978
- placeholder: searchPlaceholder,
979
- helperText: (_a2 = field.help_text) != null ? _a2 : void 0,
1114
+ required: field.required,
1115
+ sx: buildRequiredLabelSx(),
1116
+ placeholder: (_a2 = field.placeholder) != null ? _a2 : searchPlaceholder,
1117
+ helperText: (_b = field.help_text) != null ? _b : void 0,
980
1118
  slotProps: {
981
1119
  input: {
982
1120
  ...InputProps,
@@ -997,6 +1135,90 @@ function renderChoiceEditor({
997
1135
  }
998
1136
  );
999
1137
  }
1138
+ function renderStaticChoiceEditor({
1139
+ field,
1140
+ value,
1141
+ onChange,
1142
+ readOnly
1143
+ }) {
1144
+ var _a, _b, _c, _d;
1145
+ const options = (_a = field.options) != null ? _a : [];
1146
+ const optionValueMap = new Map(options.map((option) => [String(option.value), option.value]));
1147
+ const canClear = !field.required;
1148
+ if (field.input_kind === "select-multiple") {
1149
+ const selectedValues = Array.isArray(value) ? value.map((item) => String(item)) : [];
1150
+ return /* @__PURE__ */ jsx3(
1151
+ TextField,
1152
+ {
1153
+ select: true,
1154
+ label: field.label,
1155
+ value: selectedValues,
1156
+ onChange: (event) => {
1157
+ const rawValues = event.target.value;
1158
+ const nextValues = Array.isArray(rawValues) ? rawValues : [rawValues];
1159
+ onChange(nextValues.map((item) => {
1160
+ var _a2;
1161
+ return (_a2 = optionValueMap.get(String(item))) != null ? _a2 : item;
1162
+ }));
1163
+ },
1164
+ size: "small",
1165
+ fullWidth: true,
1166
+ disabled: readOnly,
1167
+ required: field.required,
1168
+ sx: buildRequiredLabelSx(),
1169
+ helperText: (_b = field.help_text) != null ? _b : void 0,
1170
+ slotProps: {
1171
+ htmlInput: buildHtmlInputProps(field),
1172
+ select: {
1173
+ multiple: true,
1174
+ displayEmpty: true,
1175
+ renderValue: (selected) => {
1176
+ var _a2;
1177
+ const selectedItems = Array.isArray(selected) ? selected : [selected];
1178
+ if (selectedItems.length === 0) {
1179
+ return (_a2 = field.placeholder) != null ? _a2 : "";
1180
+ }
1181
+ return selectedItems.map((item) => {
1182
+ var _a3, _b2;
1183
+ return (_b2 = (_a3 = options.find((option) => String(option.value) === String(item))) == null ? void 0 : _a3.label) != null ? _b2 : String(item);
1184
+ }).join(", ");
1185
+ }
1186
+ }
1187
+ },
1188
+ children: options.map((option) => /* @__PURE__ */ jsx3(MenuItem, { value: String(option.value), children: option.label }, String(option.value)))
1189
+ }
1190
+ );
1191
+ }
1192
+ return /* @__PURE__ */ jsxs(
1193
+ TextField,
1194
+ {
1195
+ select: true,
1196
+ label: field.label,
1197
+ value: value === null || value === void 0 ? "" : String(value),
1198
+ onChange: (event) => {
1199
+ var _a2;
1200
+ const nextValue = event.target.value;
1201
+ onChange(nextValue === "" ? null : (_a2 = optionValueMap.get(String(nextValue))) != null ? _a2 : nextValue);
1202
+ },
1203
+ size: "small",
1204
+ fullWidth: true,
1205
+ disabled: readOnly,
1206
+ required: field.required,
1207
+ sx: buildRequiredLabelSx(),
1208
+ helperText: (_c = field.help_text) != null ? _c : void 0,
1209
+ slotProps: {
1210
+ htmlInput: buildHtmlInputProps(field),
1211
+ select: {
1212
+ displayEmpty: canClear || Boolean(field.placeholder)
1213
+ }
1214
+ },
1215
+ children: [
1216
+ canClear || field.placeholder ? /* @__PURE__ */ jsx3(MenuItem, { value: "", children: (_d = field.placeholder) != null ? _d : "" }) : null,
1217
+ options.map((option) => /* @__PURE__ */ jsx3(MenuItem, { value: String(option.value), children: option.label }, String(option.value)))
1218
+ ]
1219
+ }
1220
+ );
1221
+ }
1000
1222
  function normalizeSelectedIds(value, isMultiple) {
1001
1223
  if (isMultiple) {
1002
1224
  if (!Array.isArray(value)) {
@@ -1016,6 +1238,20 @@ function mergeChoices(current, next) {
1016
1238
  }
1017
1239
  return [...choiceMap.values()];
1018
1240
  }
1241
+ function hasStaticOptions(field) {
1242
+ var _a, _b;
1243
+ return ((_b = (_a = field.options) == null ? void 0 : _a.length) != null ? _b : 0) > 0 || field.input_kind === "select" || field.input_kind === "select-multiple";
1244
+ }
1245
+ function buildRequiredLabelSx() {
1246
+ return {
1247
+ "& .MuiFormLabel-asterisk": {
1248
+ color: "error.main"
1249
+ },
1250
+ "& .MuiFormControlLabel-asterisk": {
1251
+ color: "error.main"
1252
+ }
1253
+ };
1254
+ }
1019
1255
  function resolveInputType(field) {
1020
1256
  if (field.input_kind === "password") {
1021
1257
  return "password";
@@ -1285,19 +1521,57 @@ function FormDialog({
1285
1521
  const [values, setValues] = useState4({});
1286
1522
  const [error, setError] = useState4(null);
1287
1523
  const [isSaving, setIsSaving] = useState4(false);
1288
- const editableFieldNames = useMemo5(
1289
- () => mode === "create" ? meta.create_fields : meta.update_fields,
1290
- [meta.create_fields, meta.update_fields, mode]
1291
- );
1292
1524
  const editableFields = useMemo5(
1293
- () => meta.fields.filter((field) => editableFieldNames.includes(field.name)),
1294
- [editableFieldNames, meta.fields]
1525
+ () => {
1526
+ if (mode === "create" && meta.create_form && meta.create_form.length > 0) {
1527
+ return meta.create_form;
1528
+ }
1529
+ const editableFieldNames = mode === "create" ? meta.create_fields : meta.update_fields;
1530
+ return meta.fields.filter((field) => editableFieldNames.includes(field.name));
1531
+ },
1532
+ [meta.create_fields, meta.create_form, meta.fields, meta.update_fields, mode]
1295
1533
  );
1534
+ const [openPickerFieldName, setOpenPickerFieldName] = useState4(null);
1535
+ const pendingPickerFrameRef = useRef4(null);
1296
1536
  useEffect4(() => {
1297
- setValues(initialValues != null ? initialValues : {});
1537
+ setValues(buildAdminFormInitialValues(editableFields, initialValues));
1298
1538
  setError(null);
1299
1539
  setIsSaving(false);
1300
- }, [initialValues, open]);
1540
+ setOpenPickerFieldName(null);
1541
+ }, [editableFields, initialValues, open]);
1542
+ useEffect4(() => {
1543
+ return () => {
1544
+ if (pendingPickerFrameRef.current !== null) {
1545
+ window.cancelAnimationFrame(pendingPickerFrameRef.current);
1546
+ pendingPickerFrameRef.current = null;
1547
+ }
1548
+ };
1549
+ }, []);
1550
+ const requestPickerOpen = (fieldName) => {
1551
+ if (openPickerFieldName === fieldName) {
1552
+ return;
1553
+ }
1554
+ if (pendingPickerFrameRef.current !== null) {
1555
+ window.cancelAnimationFrame(pendingPickerFrameRef.current);
1556
+ pendingPickerFrameRef.current = null;
1557
+ }
1558
+ if (openPickerFieldName !== null) {
1559
+ setOpenPickerFieldName(null);
1560
+ pendingPickerFrameRef.current = window.requestAnimationFrame(() => {
1561
+ setOpenPickerFieldName(fieldName);
1562
+ pendingPickerFrameRef.current = null;
1563
+ });
1564
+ return;
1565
+ }
1566
+ setOpenPickerFieldName(fieldName);
1567
+ };
1568
+ const requestPickerClose = (fieldName) => {
1569
+ if (pendingPickerFrameRef.current !== null && openPickerFieldName === fieldName) {
1570
+ window.cancelAnimationFrame(pendingPickerFrameRef.current);
1571
+ pendingPickerFrameRef.current = null;
1572
+ }
1573
+ setOpenPickerFieldName((current) => current === fieldName ? null : current);
1574
+ };
1301
1575
  const handleSave = async () => {
1302
1576
  if (isSaving) {
1303
1577
  return;
@@ -1346,22 +1620,34 @@ function FormDialog({
1346
1620
  },
1347
1621
  children: [
1348
1622
  /* @__PURE__ */ jsx5(DialogTitle, { children: title }),
1349
- /* @__PURE__ */ jsx5(DialogContent, { children: /* @__PURE__ */ jsx5(LocalizationProvider, { dateAdapter: AdapterDayjs, adapterLocale: meta.locale, children: /* @__PURE__ */ jsxs3(Box2, { sx: { display: "grid", gap: 2, pt: 1 }, children: [
1350
- error ? /* @__PURE__ */ jsx5(Alert, { severity: "error", children: error }) : null,
1351
- editableFields.map((field) => /* @__PURE__ */ jsx5(
1352
- FieldEditor,
1353
- {
1354
- field,
1355
- value: values[field.name],
1356
- slug,
1357
- client,
1358
- onChange: (nextValue) => {
1359
- setValues((current) => ({ ...current, [field.name]: nextValue }));
1360
- }
1361
- },
1362
- field.name
1363
- ))
1364
- ] }) }) }),
1623
+ /* @__PURE__ */ jsx5(DialogContent, { children: /* @__PURE__ */ jsx5(
1624
+ LocalizationProvider,
1625
+ {
1626
+ dateAdapter: AdapterDayjs,
1627
+ adapterLocale: meta.locale,
1628
+ localeText: getMuiPickersLocaleText(meta.locale),
1629
+ children: /* @__PURE__ */ jsxs3(Box2, { sx: { display: "grid", gap: 2, pt: 1 }, children: [
1630
+ error ? /* @__PURE__ */ jsx5(Alert, { severity: "error", children: error }) : null,
1631
+ editableFields.map((field) => /* @__PURE__ */ jsx5(
1632
+ FieldEditor,
1633
+ {
1634
+ field,
1635
+ value: values[field.name],
1636
+ slug,
1637
+ client,
1638
+ isPickerOpen: openPickerFieldName === field.name,
1639
+ hasAnotherPickerOpen: openPickerFieldName !== null && openPickerFieldName !== field.name,
1640
+ onChange: (nextValue) => {
1641
+ setValues((current) => ({ ...current, [field.name]: nextValue }));
1642
+ },
1643
+ onRequestPickerOpen: () => requestPickerOpen(field.name),
1644
+ onRequestPickerClose: () => requestPickerClose(field.name)
1645
+ },
1646
+ field.name
1647
+ ))
1648
+ ] })
1649
+ }
1650
+ ) }),
1365
1651
  /* @__PURE__ */ jsxs3(DialogActions, { children: [
1366
1652
  /* @__PURE__ */ jsx5(Button, { onClick: onClose, disabled: isSaving, children: t("cancel") }),
1367
1653
  /* @__PURE__ */ jsx5(Button, { variant: "contained", onClick: () => void handleSave(), disabled: isSaving, children: isSaving ? t("saving") : t("save") })
@@ -1372,7 +1658,7 @@ function FormDialog({
1372
1658
  }
1373
1659
 
1374
1660
  // src/components/OverviewPage.tsx
1375
- import { useEffect as useEffect7, useMemo as useMemo7, useState as useState7 } from "react";
1661
+ import { useEffect as useEffect8, useLayoutEffect, useMemo as useMemo7, useState as useState7 } from "react";
1376
1662
  import { Alert as Alert3, Box as Box6, Grid, Paper as Paper4, Skeleton as Skeleton2, Stack as Stack6 } from "@mui/material";
1377
1663
 
1378
1664
  // src/hooks/useAdminDocumentTitle.ts
@@ -1403,6 +1689,31 @@ function useAdminData() {
1403
1689
  return useContext4(AdminDataContext);
1404
1690
  }
1405
1691
 
1692
+ // src/components/layout/ShellContext.tsx
1693
+ import { createContext as createContext5, useContext as useContext5 } from "react";
1694
+ import { jsx as jsx7 } from "react/jsx-runtime";
1695
+ var defaultShellContextValue = {
1696
+ isMobile: false,
1697
+ openMobileSidebar: () => {
1698
+ },
1699
+ pendingPath: null,
1700
+ pendingView: null,
1701
+ startPendingNavigation: () => {
1702
+ },
1703
+ finishPendingNavigation: () => {
1704
+ }
1705
+ };
1706
+ var ShellContext = createContext5(defaultShellContextValue);
1707
+ function ShellContextProvider({
1708
+ value,
1709
+ children
1710
+ }) {
1711
+ return /* @__PURE__ */ jsx7(ShellContext.Provider, { value, children });
1712
+ }
1713
+ function useShellContext() {
1714
+ return useContext5(ShellContext);
1715
+ }
1716
+
1406
1717
  // src/components/ModelsBlocks.tsx
1407
1718
  import { memo as memo2, useMemo as useMemo6 } from "react";
1408
1719
  import { Box as Box4, Stack as Stack4, useMediaQuery, useTheme as useTheme2 } from "@mui/material";
@@ -1421,10 +1732,10 @@ import {
1421
1732
 
1422
1733
  // src/components/models-blocks/BlockTitle.tsx
1423
1734
  import { Stack as Stack2, Typography as Typography2 } from "@mui/material";
1424
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
1735
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
1425
1736
  function BlockTitle({ block, compact = false }) {
1426
1737
  return /* @__PURE__ */ jsxs4(Stack2, { spacing: 0.25, children: [
1427
- /* @__PURE__ */ jsx7(
1738
+ /* @__PURE__ */ jsx8(
1428
1739
  Typography2,
1429
1740
  {
1430
1741
  variant: compact ? "subtitle1" : "h6",
@@ -1436,7 +1747,7 @@ function BlockTitle({ block, compact = false }) {
1436
1747
  children: block.title
1437
1748
  }
1438
1749
  ),
1439
- block.description && !compact ? /* @__PURE__ */ jsx7(Typography2, { color: "text.secondary", sx: { fontSize: compact ? 12 : 14, lineHeight: 1.3 }, children: block.description }) : null
1750
+ block.description && !compact ? /* @__PURE__ */ jsx8(Typography2, { color: "text.secondary", sx: { fontSize: compact ? 12 : 14, lineHeight: 1.3 }, children: block.description }) : null
1440
1751
  ] });
1441
1752
  }
1442
1753
 
@@ -1495,10 +1806,10 @@ function getStorageKey(blockSlug) {
1495
1806
  }
1496
1807
 
1497
1808
  // src/components/NavLink.tsx
1498
- import { jsx as jsx8 } from "react/jsx-runtime";
1809
+ import { jsx as jsx9 } from "react/jsx-runtime";
1499
1810
  function NavLink({ href, children, style, title, onClick, router }) {
1500
1811
  const resolvedRouter = useAdminRouter(router);
1501
- return /* @__PURE__ */ jsx8(
1812
+ return /* @__PURE__ */ jsx9(
1502
1813
  "a",
1503
1814
  {
1504
1815
  href,
@@ -1514,7 +1825,7 @@ function NavLink({ href, children, style, title, onClick, router }) {
1514
1825
  }
1515
1826
 
1516
1827
  // src/components/models-blocks/DashboardModelsBlock.tsx
1517
- import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
1828
+ import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
1518
1829
  function DashboardModelsBlock({ block, basePath }) {
1519
1830
  const [isExpanded, setIsExpanded] = useBlockExpandedState(block.slug, block.default_expanded);
1520
1831
  return /* @__PURE__ */ jsxs5(
@@ -1533,10 +1844,10 @@ function DashboardModelsBlock({ block, basePath }) {
1533
1844
  }
1534
1845
  },
1535
1846
  children: [
1536
- /* @__PURE__ */ jsx9(
1847
+ /* @__PURE__ */ jsx10(
1537
1848
  AccordionSummary,
1538
1849
  {
1539
- expandIcon: block.collapsible ? /* @__PURE__ */ jsx9(ExpandMoreIcon, { fontSize: "small" }) : void 0,
1850
+ expandIcon: block.collapsible ? /* @__PURE__ */ jsx10(ExpandMoreIcon, { fontSize: "small" }) : void 0,
1540
1851
  sx: {
1541
1852
  minHeight: "48px",
1542
1853
  pr: 1.75,
@@ -1558,15 +1869,15 @@ function DashboardModelsBlock({ block, basePath }) {
1558
1869
  mb: 1.05
1559
1870
  }
1560
1871
  },
1561
- children: /* @__PURE__ */ jsx9(BlockTitle, { block })
1872
+ children: /* @__PURE__ */ jsx10(BlockTitle, { block })
1562
1873
  }
1563
1874
  ),
1564
- /* @__PURE__ */ jsx9(AccordionDetails, { sx: { px: 1.35, pb: 1.35, pt: 0 }, children: /* @__PURE__ */ jsx9(Stack3, { spacing: 0.5, sx: { px: 0.4 }, children: block.models.map((model) => /* @__PURE__ */ jsx9(
1875
+ /* @__PURE__ */ jsx10(AccordionDetails, { sx: { px: 1.35, pb: 1.35, pt: 0 }, children: /* @__PURE__ */ jsx10(Stack3, { spacing: 0.5, sx: { px: 0.4 }, children: block.models.map((model) => /* @__PURE__ */ jsx10(
1565
1876
  NavLink,
1566
1877
  {
1567
1878
  href: `${basePath}/${model.slug}`,
1568
1879
  style: { textDecoration: "none", display: "block" },
1569
- children: /* @__PURE__ */ jsx9(
1880
+ children: /* @__PURE__ */ jsx10(
1570
1881
  ButtonBase,
1571
1882
  {
1572
1883
  sx: {
@@ -1576,7 +1887,7 @@ function DashboardModelsBlock({ block, basePath }) {
1576
1887
  borderRadius: "8px",
1577
1888
  overflow: "hidden"
1578
1889
  },
1579
- children: /* @__PURE__ */ jsx9(
1890
+ children: /* @__PURE__ */ jsx10(
1580
1891
  ListItemButton,
1581
1892
  {
1582
1893
  sx: {
@@ -1585,7 +1896,7 @@ function DashboardModelsBlock({ block, basePath }) {
1585
1896
  px: 1.25,
1586
1897
  py: 0.4
1587
1898
  },
1588
- children: /* @__PURE__ */ jsx9(ListItemText, { primary: model.title })
1899
+ children: /* @__PURE__ */ jsx10(ListItemText, { primary: model.title })
1589
1900
  }
1590
1901
  )
1591
1902
  }
@@ -1599,6 +1910,7 @@ function DashboardModelsBlock({ block, basePath }) {
1599
1910
  }
1600
1911
 
1601
1912
  // src/components/models-blocks/SidebarModelsBlock.tsx
1913
+ import { useEffect as useEffect7 } from "react";
1602
1914
  import ExpandMoreIcon2 from "@mui/icons-material/ExpandMore";
1603
1915
  import {
1604
1916
  Accordion as Accordion2,
@@ -1610,9 +1922,15 @@ import {
1610
1922
  ListItemText as ListItemText2,
1611
1923
  Paper as Paper2
1612
1924
  } from "@mui/material";
1613
- import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
1925
+ import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
1614
1926
  function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate }) {
1615
1927
  const [isExpanded, setIsExpanded] = useBlockExpandedState(block.slug, block.default_expanded);
1928
+ const hasActiveModel = block.models.some((model) => model.slug === activeModelSlug);
1929
+ useEffect7(() => {
1930
+ if (hasActiveModel && !isExpanded) {
1931
+ setIsExpanded(true);
1932
+ }
1933
+ }, [hasActiveModel, isExpanded, setIsExpanded]);
1616
1934
  if (block.collapsible) {
1617
1935
  return /* @__PURE__ */ jsxs6(
1618
1936
  Accordion2,
@@ -1621,6 +1939,8 @@ function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate
1621
1939
  onChange: (_, expanded) => setIsExpanded(expanded),
1622
1940
  disableGutters: true,
1623
1941
  elevation: 0,
1942
+ "data-xladmin-active-block": hasActiveModel ? "true" : void 0,
1943
+ "data-xladmin-block-origin": block.isAllModels ? "all-models" : "block",
1624
1944
  sx: {
1625
1945
  ...getBlockSurfaceSx(block, "sidebar"),
1626
1946
  borderRadius: "8px",
@@ -1630,10 +1950,10 @@ function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate
1630
1950
  }
1631
1951
  },
1632
1952
  children: [
1633
- /* @__PURE__ */ jsx10(
1953
+ /* @__PURE__ */ jsx11(
1634
1954
  AccordionSummary2,
1635
1955
  {
1636
- expandIcon: /* @__PURE__ */ jsx10(ExpandMoreIcon2, { fontSize: "small" }),
1956
+ expandIcon: /* @__PURE__ */ jsx11(ExpandMoreIcon2, { fontSize: "small" }),
1637
1957
  sx: {
1638
1958
  minHeight: "42px",
1639
1959
  pr: 1.25,
@@ -1649,15 +1969,16 @@ function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate
1649
1969
  my: 0
1650
1970
  }
1651
1971
  },
1652
- children: /* @__PURE__ */ jsx10(BlockTitle, { block, compact: true })
1972
+ children: /* @__PURE__ */ jsx11(BlockTitle, { block, compact: true })
1653
1973
  }
1654
1974
  ),
1655
- /* @__PURE__ */ jsx10(AccordionDetails2, { sx: { p: 0 }, children: /* @__PURE__ */ jsx10(
1975
+ /* @__PURE__ */ jsx11(AccordionDetails2, { sx: { p: 0 }, children: /* @__PURE__ */ jsx11(
1656
1976
  SidebarModelsList,
1657
1977
  {
1658
1978
  models: block.models,
1659
1979
  basePath,
1660
1980
  activeModelSlug,
1981
+ modelOrigin: block.isAllModels ? "all-models" : "block",
1661
1982
  onModelNavigate
1662
1983
  }
1663
1984
  ) })
@@ -1668,19 +1989,22 @@ function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate
1668
1989
  return /* @__PURE__ */ jsxs6(
1669
1990
  Paper2,
1670
1991
  {
1992
+ "data-xladmin-active-block": hasActiveModel ? "true" : void 0,
1993
+ "data-xladmin-block-origin": block.isAllModels ? "all-models" : "block",
1671
1994
  sx: {
1672
1995
  ...getBlockSurfaceSx(block, "sidebar"),
1673
1996
  borderRadius: "8px",
1674
1997
  overflow: "hidden"
1675
1998
  },
1676
1999
  children: [
1677
- /* @__PURE__ */ jsx10(Box3, { sx: { px: 1.25, py: 1 }, children: /* @__PURE__ */ jsx10(BlockTitle, { block, compact: true }) }),
1678
- /* @__PURE__ */ jsx10(
2000
+ /* @__PURE__ */ jsx11(Box3, { sx: { px: 1.25, py: 1 }, children: /* @__PURE__ */ jsx11(BlockTitle, { block, compact: true }) }),
2001
+ /* @__PURE__ */ jsx11(
1679
2002
  SidebarModelsList,
1680
2003
  {
1681
2004
  models: block.models,
1682
2005
  basePath,
1683
2006
  activeModelSlug,
2007
+ modelOrigin: block.isAllModels ? "all-models" : "block",
1684
2008
  onModelNavigate
1685
2009
  }
1686
2010
  )
@@ -1688,46 +2012,51 @@ function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate
1688
2012
  }
1689
2013
  );
1690
2014
  }
1691
- function SidebarModelsList({ models, basePath, activeModelSlug, onModelNavigate }) {
1692
- return /* @__PURE__ */ jsx10(List, { dense: true, disablePadding: true, sx: { display: "flex", flexDirection: "column", gap: 0.5, p: 1.35 }, children: models.map((model) => {
2015
+ function SidebarModelsList({ models, basePath, activeModelSlug, modelOrigin, onModelNavigate }) {
2016
+ return /* @__PURE__ */ jsx11(List, { dense: true, disablePadding: true, sx: { display: "flex", flexDirection: "column", gap: 0.5, p: 1.35 }, children: models.map((model) => {
1693
2017
  const href = `${basePath}/${model.slug}`;
1694
2018
  const isActive = activeModelSlug === model.slug;
1695
- return /* @__PURE__ */ jsx10(
2019
+ return /* @__PURE__ */ jsx11(
1696
2020
  NavLink,
1697
2021
  {
1698
2022
  href,
1699
2023
  style: { textDecoration: "none", display: "block" },
1700
2024
  onClick: () => onModelNavigate == null ? void 0 : onModelNavigate(href),
1701
- children: /* @__PURE__ */ jsx10(
1702
- ListItemButton2,
1703
- {
1704
- selected: isActive,
1705
- sx: {
1706
- borderRadius: "8px",
1707
- px: 1.4,
1708
- backgroundColor: isActive ? "rgba(255, 255, 255, 0.18)" : "rgba(255, 255, 255, 0.04)",
1709
- boxShadow: isActive ? "inset 0 0 0 1px rgba(255, 255, 255, 0.08)" : "none",
1710
- "&:hover": {
1711
- backgroundColor: isActive ? "rgba(255, 255, 255, 0.2)" : "rgba(255, 255, 255, 0.06)"
1712
- },
1713
- "&.Mui-selected": {
1714
- backgroundColor: "rgba(255, 255, 255, 0.18)"
1715
- },
1716
- "&.Mui-selected:hover": {
1717
- backgroundColor: "rgba(255, 255, 255, 0.2)"
1718
- }
1719
- },
1720
- children: /* @__PURE__ */ jsx10(ListItemText2, { primary: model.title })
1721
- }
1722
- )
2025
+ children: /* @__PURE__ */ jsx11(SidebarModelListItem, { title: model.title, isActive, modelOrigin })
1723
2026
  },
1724
2027
  model.slug
1725
2028
  );
1726
2029
  }) });
1727
2030
  }
2031
+ function SidebarModelListItem({ title, isActive, modelOrigin }) {
2032
+ return /* @__PURE__ */ jsx11(
2033
+ ListItemButton2,
2034
+ {
2035
+ selected: isActive,
2036
+ "data-xladmin-active-model": isActive ? "true" : void 0,
2037
+ "data-xladmin-model-origin": isActive ? modelOrigin : void 0,
2038
+ sx: {
2039
+ borderRadius: "8px",
2040
+ px: 1.4,
2041
+ backgroundColor: isActive ? "rgba(255, 255, 255, 0.18)" : "rgba(255, 255, 255, 0.04)",
2042
+ boxShadow: isActive ? "inset 0 0 0 1px rgba(255, 255, 255, 0.08)" : "none",
2043
+ "&:hover": {
2044
+ backgroundColor: isActive ? "rgba(255, 255, 255, 0.2)" : "rgba(255, 255, 255, 0.06)"
2045
+ },
2046
+ "&.Mui-selected": {
2047
+ backgroundColor: "rgba(255, 255, 255, 0.18)"
2048
+ },
2049
+ "&.Mui-selected:hover": {
2050
+ backgroundColor: "rgba(255, 255, 255, 0.2)"
2051
+ }
2052
+ },
2053
+ children: /* @__PURE__ */ jsx11(ListItemText2, { primary: title })
2054
+ }
2055
+ );
2056
+ }
1728
2057
 
1729
2058
  // src/components/ModelsBlocks.tsx
1730
- import { jsx as jsx11 } from "react/jsx-runtime";
2059
+ import { jsx as jsx12 } from "react/jsx-runtime";
1731
2060
  var ModelsBlocks = memo2(function ModelsBlocks2({
1732
2061
  basePath,
1733
2062
  models,
@@ -1758,7 +2087,7 @@ var ModelsBlocks = memo2(function ModelsBlocks2({
1758
2087
  return distributeBlocksByHeight(normalizedBlocks, columnCount);
1759
2088
  }, [isMdUp, isXlUp, normalizedBlocks]);
1760
2089
  if (variant === "sidebar") {
1761
- return /* @__PURE__ */ jsx11(Stack4, { spacing: 1, children: normalizedBlocks.map((block) => /* @__PURE__ */ jsx11(
2090
+ return /* @__PURE__ */ jsx12(Stack4, { spacing: 1, children: normalizedBlocks.map((block) => /* @__PURE__ */ jsx12(
1762
2091
  SidebarModelsBlock,
1763
2092
  {
1764
2093
  block,
@@ -1769,7 +2098,7 @@ var ModelsBlocks = memo2(function ModelsBlocks2({
1769
2098
  block.slug
1770
2099
  )) });
1771
2100
  }
1772
- return /* @__PURE__ */ jsx11(Box4, { sx: { display: "flex", gap: 2, alignItems: "flex-start" }, children: dashboardColumns.map((column, columnIndex) => /* @__PURE__ */ jsx11(Box4, { sx: { flex: 1, minWidth: 0 }, children: /* @__PURE__ */ jsx11(Stack4, { spacing: 2, children: column.map((block) => /* @__PURE__ */ jsx11(DashboardModelsBlock, { block, basePath }, block.slug)) }) }, columnIndex)) });
2101
+ return /* @__PURE__ */ jsx12(Box4, { sx: { display: "flex", gap: 2, alignItems: "flex-start" }, children: dashboardColumns.map((column, columnIndex) => /* @__PURE__ */ jsx12(Box4, { sx: { flex: 1, minWidth: 0 }, children: /* @__PURE__ */ jsx12(Stack4, { spacing: 2, children: column.map((block) => /* @__PURE__ */ jsx12(DashboardModelsBlock, { block, basePath }, block.slug)) }) }, columnIndex)) });
1773
2102
  });
1774
2103
  function distributeBlocksByHeight(blocks, columnCount) {
1775
2104
  const columns = Array.from({ length: columnCount }, () => []);
@@ -1796,31 +2125,6 @@ import MenuIcon from "@mui/icons-material/Menu";
1796
2125
  import { Box as Box5 } from "@mui/material";
1797
2126
  import ExpandMoreIcon3 from "@mui/icons-material/ExpandMore";
1798
2127
  import { Alert as Alert2, Collapse, IconButton, Paper as Paper3, Skeleton, Stack as Stack5, Typography as Typography3 } from "@mui/material";
1799
-
1800
- // src/components/layout/ShellContext.tsx
1801
- import { createContext as createContext5, useContext as useContext5 } from "react";
1802
- import { jsx as jsx12 } from "react/jsx-runtime";
1803
- var defaultShellContextValue = {
1804
- isMobile: false,
1805
- openMobileSidebar: () => {
1806
- },
1807
- pendingPath: null,
1808
- pendingView: null,
1809
- startPendingNavigation: () => {
1810
- }
1811
- };
1812
- var ShellContext = createContext5(defaultShellContextValue);
1813
- function ShellContextProvider({
1814
- value,
1815
- children
1816
- }) {
1817
- return /* @__PURE__ */ jsx12(ShellContext.Provider, { value, children });
1818
- }
1819
- function useShellContext() {
1820
- return useContext5(ShellContext);
1821
- }
1822
-
1823
- // src/components/layout/MainHeader.tsx
1824
2128
  import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
1825
2129
  var MAIN_HEADER_PADDING_X = 2.5;
1826
2130
  var MAIN_HEADER_PADDING_T = 1.35;
@@ -1980,6 +2284,7 @@ var inFlightModelsRequest = null;
1980
2284
  function OverviewPage({ client, basePath }) {
1981
2285
  const t = useAdminTranslation();
1982
2286
  useAdminDocumentTitle(t("admin_title"), t("overview_title"));
2287
+ const { pendingPath, finishPendingNavigation } = useShellContext();
1983
2288
  const adminData = useAdminData();
1984
2289
  const shellModelsResponse = useMemo7(() => {
1985
2290
  if (adminData.models.length === 0 && adminData.blocks.length === 0) {
@@ -1994,7 +2299,7 @@ function OverviewPage({ client, basePath }) {
1994
2299
  const [data, setData] = useState7(shellModelsResponse != null ? shellModelsResponse : cachedModelsResponse);
1995
2300
  const [error, setError] = useState7(null);
1996
2301
  const [isLoading, setIsLoading] = useState7(shellModelsResponse === null && cachedModelsResponse === null);
1997
- useEffect7(() => {
2302
+ useEffect8(() => {
1998
2303
  let isMounted = true;
1999
2304
  if (shellModelsResponse !== null) {
2000
2305
  cachedModelsResponse = shellModelsResponse;
@@ -2033,6 +2338,18 @@ function OverviewPage({ client, basePath }) {
2033
2338
  isMounted = false;
2034
2339
  };
2035
2340
  }, [client, shellModelsResponse, t]);
2341
+ useLayoutEffect(() => {
2342
+ if (pendingPath === null) {
2343
+ return;
2344
+ }
2345
+ if (isLoading) {
2346
+ return;
2347
+ }
2348
+ if (!data && !error) {
2349
+ return;
2350
+ }
2351
+ finishPendingNavigation();
2352
+ }, [data, error, finishPendingNavigation, isLoading, pendingPath]);
2036
2353
  if (isLoading && !data) {
2037
2354
  return /* @__PURE__ */ jsx14(OverviewPageSkeleton, {});
2038
2355
  }
@@ -2095,23 +2412,24 @@ function OverviewPageSkeleton() {
2095
2412
  }
2096
2413
 
2097
2414
  // src/components/ModelPage.tsx
2415
+ import { useLayoutEffect as useLayoutEffect3 } from "react";
2098
2416
  import AddIcon from "@mui/icons-material/Add";
2099
2417
  import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
2100
2418
  import ChevronRightIcon from "@mui/icons-material/ChevronRight";
2101
2419
  import ExpandMoreIcon4 from "@mui/icons-material/ExpandMore";
2102
2420
  import FilterListIcon from "@mui/icons-material/FilterList";
2103
2421
  import {
2104
- Alert as Alert5,
2105
- Box as Box10,
2106
- Button as Button4,
2422
+ Alert as Alert6,
2423
+ Box as Box11,
2424
+ Button as Button5,
2107
2425
  Checkbox as Checkbox2,
2108
- Dialog as Dialog3,
2109
- DialogContent as DialogContent3,
2110
- DialogTitle as DialogTitle3,
2426
+ Dialog as Dialog4,
2427
+ DialogContent as DialogContent4,
2428
+ DialogTitle as DialogTitle4,
2111
2429
  IconButton as IconButton3,
2112
2430
  InputBase,
2113
2431
  Menu,
2114
- MenuItem as MenuItem2,
2432
+ MenuItem as MenuItem3,
2115
2433
  Paper as Paper7,
2116
2434
  Stack as Stack10,
2117
2435
  Table,
@@ -2126,44 +2444,103 @@ import {
2126
2444
  } from "@mui/material";
2127
2445
  import { useTheme as useTheme3 } from "@mui/material/styles";
2128
2446
 
2129
- // src/components/DeletePreviewDialog.tsx
2130
- import {
2131
- Alert as Alert4,
2132
- Box as Box7,
2133
- Button as Button2,
2134
- CircularProgress as CircularProgress2,
2135
- Dialog as Dialog2,
2136
- DialogActions as DialogActions2,
2137
- DialogContent as DialogContent2,
2138
- DialogTitle as DialogTitle2,
2139
- Stack as Stack7,
2140
- Typography as Typography4
2141
- } from "@mui/material";
2447
+ // src/components/ActionFormDialog.tsx
2448
+ import { useEffect as useEffect9, useRef as useRef5, useState as useState8 } from "react";
2449
+ import { Alert as Alert4, Box as Box7, Button as Button2, Dialog as Dialog2, DialogActions as DialogActions2, DialogContent as DialogContent2, DialogTitle as DialogTitle2 } from "@mui/material";
2450
+ import { LocalizationProvider as LocalizationProvider2 } from "@mui/x-date-pickers";
2451
+ import { AdapterDayjs as AdapterDayjs2 } from "@mui/x-date-pickers/AdapterDayjs";
2142
2452
  import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
2143
- function DeletePreviewDialog({
2453
+ function ActionFormDialog({
2144
2454
  open,
2145
- title,
2146
- preview,
2147
- error,
2148
- isLoading,
2149
- isSubmitting,
2150
2455
  onClose,
2151
- onConfirm
2456
+ onSuccess,
2457
+ title,
2458
+ submitLabel,
2459
+ slug,
2460
+ locale,
2461
+ fields,
2462
+ client,
2463
+ choiceScope,
2464
+ initialValues,
2465
+ onSubmit
2152
2466
  }) {
2153
2467
  const t = useAdminTranslation();
2154
- return /* @__PURE__ */ jsxs9(
2155
- Dialog2,
2156
- {
2157
- open,
2158
- onClose: isSubmitting ? void 0 : onClose,
2159
- fullWidth: true,
2160
- maxWidth: "sm",
2468
+ const message = useAdminMessage();
2469
+ const [values, setValues] = useState8({});
2470
+ const [error, setError] = useState8(null);
2471
+ const [isSubmitting, setIsSubmitting] = useState8(false);
2472
+ const [openPickerFieldName, setOpenPickerFieldName] = useState8(null);
2473
+ const pendingPickerFrameRef = useRef5(null);
2474
+ useEffect9(() => {
2475
+ setValues(buildAdminFormInitialValues(fields, initialValues));
2476
+ setError(null);
2477
+ setIsSubmitting(false);
2478
+ setOpenPickerFieldName(null);
2479
+ }, [fields, initialValues, open]);
2480
+ useEffect9(() => {
2481
+ return () => {
2482
+ if (pendingPickerFrameRef.current !== null) {
2483
+ window.cancelAnimationFrame(pendingPickerFrameRef.current);
2484
+ pendingPickerFrameRef.current = null;
2485
+ }
2486
+ };
2487
+ }, []);
2488
+ const requestPickerOpen = (fieldName) => {
2489
+ if (openPickerFieldName === fieldName) {
2490
+ return;
2491
+ }
2492
+ if (pendingPickerFrameRef.current !== null) {
2493
+ window.cancelAnimationFrame(pendingPickerFrameRef.current);
2494
+ pendingPickerFrameRef.current = null;
2495
+ }
2496
+ if (openPickerFieldName !== null) {
2497
+ setOpenPickerFieldName(null);
2498
+ pendingPickerFrameRef.current = window.requestAnimationFrame(() => {
2499
+ setOpenPickerFieldName(fieldName);
2500
+ pendingPickerFrameRef.current = null;
2501
+ });
2502
+ return;
2503
+ }
2504
+ setOpenPickerFieldName(fieldName);
2505
+ };
2506
+ const requestPickerClose = (fieldName) => {
2507
+ if (pendingPickerFrameRef.current !== null && openPickerFieldName === fieldName) {
2508
+ window.cancelAnimationFrame(pendingPickerFrameRef.current);
2509
+ pendingPickerFrameRef.current = null;
2510
+ }
2511
+ setOpenPickerFieldName((current) => current === fieldName ? null : current);
2512
+ };
2513
+ const handleSubmit = async () => {
2514
+ if (isSubmitting) {
2515
+ return;
2516
+ }
2517
+ setIsSubmitting(true);
2518
+ setError(null);
2519
+ try {
2520
+ await onSubmit(buildAdminPayload(values, fields));
2521
+ onSuccess();
2522
+ onClose();
2523
+ } catch (reason) {
2524
+ const nextError = reason instanceof Error ? reason.message : t("object_action_error");
2525
+ setError(nextError);
2526
+ message.error(nextError);
2527
+ } finally {
2528
+ setIsSubmitting(false);
2529
+ }
2530
+ };
2531
+ return /* @__PURE__ */ jsxs9(
2532
+ Dialog2,
2533
+ {
2534
+ open,
2535
+ onClose,
2536
+ fullWidth: true,
2537
+ maxWidth: "md",
2161
2538
  slotProps: {
2162
2539
  paper: {
2163
2540
  sx: {
2164
2541
  m: { xs: 1, sm: 2, md: 3 },
2165
2542
  width: { xs: "calc(100% - 16px)", sm: void 0 },
2166
- maxWidth: { xs: "calc(100% - 16px)", sm: 600 },
2543
+ maxWidth: { xs: "calc(100% - 16px)", md: 900 },
2167
2544
  maxHeight: {
2168
2545
  xs: "calc(100% - 16px)",
2169
2546
  sm: "calc(100% - 32px)",
@@ -2174,26 +2551,112 @@ function DeletePreviewDialog({
2174
2551
  },
2175
2552
  children: [
2176
2553
  /* @__PURE__ */ jsx15(DialogTitle2, { children: title }),
2177
- /* @__PURE__ */ jsxs9(DialogContent2, { dividers: true, children: [
2178
- isLoading ? /* @__PURE__ */ jsxs9(Stack7, { spacing: 1.5, alignItems: "center", justifyContent: "center", sx: { minHeight: 180 }, children: [
2179
- /* @__PURE__ */ jsx15(CircularProgress2, { size: 28, thickness: 4.2, color: "inherit" }),
2180
- /* @__PURE__ */ jsx15(Typography4, { color: "text.secondary", children: t("delete_preview_loading") })
2554
+ /* @__PURE__ */ jsx15(DialogContent2, { children: /* @__PURE__ */ jsx15(
2555
+ LocalizationProvider2,
2556
+ {
2557
+ dateAdapter: AdapterDayjs2,
2558
+ adapterLocale: locale,
2559
+ localeText: getMuiPickersLocaleText(locale),
2560
+ children: /* @__PURE__ */ jsxs9(Box7, { sx: { display: "grid", gap: 2, pt: 1 }, children: [
2561
+ error ? /* @__PURE__ */ jsx15(Alert4, { severity: "error", children: error }) : null,
2562
+ fields.map((field) => /* @__PURE__ */ jsx15(
2563
+ FieldEditor,
2564
+ {
2565
+ field,
2566
+ value: values[field.name],
2567
+ slug,
2568
+ client,
2569
+ choiceScope,
2570
+ isPickerOpen: openPickerFieldName === field.name,
2571
+ hasAnotherPickerOpen: openPickerFieldName !== null && openPickerFieldName !== field.name,
2572
+ onChange: (nextValue) => {
2573
+ setValues((current) => ({ ...current, [field.name]: nextValue }));
2574
+ },
2575
+ onRequestPickerOpen: () => requestPickerOpen(field.name),
2576
+ onRequestPickerClose: () => requestPickerClose(field.name)
2577
+ },
2578
+ field.name
2579
+ ))
2580
+ ] })
2581
+ }
2582
+ ) }),
2583
+ /* @__PURE__ */ jsxs9(DialogActions2, { children: [
2584
+ /* @__PURE__ */ jsx15(Button2, { onClick: onClose, disabled: isSubmitting, children: t("cancel") }),
2585
+ /* @__PURE__ */ jsx15(Button2, { variant: "contained", onClick: () => void handleSubmit(), disabled: isSubmitting, children: isSubmitting ? t("saving") : submitLabel != null ? submitLabel : t("save") })
2586
+ ] })
2587
+ ]
2588
+ }
2589
+ );
2590
+ }
2591
+
2592
+ // src/components/DeletePreviewDialog.tsx
2593
+ import {
2594
+ Alert as Alert5,
2595
+ Box as Box8,
2596
+ Button as Button3,
2597
+ CircularProgress as CircularProgress2,
2598
+ Dialog as Dialog3,
2599
+ DialogActions as DialogActions3,
2600
+ DialogContent as DialogContent3,
2601
+ DialogTitle as DialogTitle3,
2602
+ Stack as Stack7,
2603
+ Typography as Typography4
2604
+ } from "@mui/material";
2605
+ import { jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
2606
+ function DeletePreviewDialog({
2607
+ open,
2608
+ title,
2609
+ preview,
2610
+ error,
2611
+ isLoading,
2612
+ isSubmitting,
2613
+ onClose,
2614
+ onConfirm
2615
+ }) {
2616
+ const t = useAdminTranslation();
2617
+ return /* @__PURE__ */ jsxs10(
2618
+ Dialog3,
2619
+ {
2620
+ open,
2621
+ onClose: isSubmitting ? void 0 : onClose,
2622
+ fullWidth: true,
2623
+ maxWidth: "sm",
2624
+ slotProps: {
2625
+ paper: {
2626
+ sx: {
2627
+ m: { xs: 1, sm: 2, md: 3 },
2628
+ width: { xs: "calc(100% - 16px)", sm: void 0 },
2629
+ maxWidth: { xs: "calc(100% - 16px)", sm: 600 },
2630
+ maxHeight: {
2631
+ xs: "calc(100% - 16px)",
2632
+ sm: "calc(100% - 32px)",
2633
+ md: "calc(100% - 48px)"
2634
+ }
2635
+ }
2636
+ }
2637
+ },
2638
+ children: [
2639
+ /* @__PURE__ */ jsx16(DialogTitle3, { children: title }),
2640
+ /* @__PURE__ */ jsxs10(DialogContent3, { dividers: true, children: [
2641
+ isLoading ? /* @__PURE__ */ jsxs10(Stack7, { spacing: 1.5, alignItems: "center", justifyContent: "center", sx: { minHeight: 180 }, children: [
2642
+ /* @__PURE__ */ jsx16(CircularProgress2, { size: 28, thickness: 4.2, color: "inherit" }),
2643
+ /* @__PURE__ */ jsx16(Typography4, { color: "text.secondary", children: t("delete_preview_loading") })
2181
2644
  ] }) : null,
2182
- !isLoading && error ? /* @__PURE__ */ jsx15(Alert4, { severity: "error", children: error }) : null,
2183
- !isLoading && !error && preview ? /* @__PURE__ */ jsxs9(Stack7, { spacing: 1.5, children: [
2184
- /* @__PURE__ */ jsx15(Typography4, { color: "text.secondary", children: preview.can_delete ? t("delete_preview_hint") : t("delete_preview_blocked_hint") }),
2185
- !preview.can_delete ? /* @__PURE__ */ jsx15(Alert4, { severity: "warning", children: t("delete_preview_blocked_hint") }) : null,
2186
- /* @__PURE__ */ jsxs9(Stack7, { spacing: 0.5, children: [
2187
- /* @__PURE__ */ jsx15(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_roots", { count: preview.summary.roots }) }),
2188
- /* @__PURE__ */ jsx15(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_delete", { count: preview.summary.delete }) }),
2189
- /* @__PURE__ */ jsx15(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_protect", { count: preview.summary.protect }) }),
2190
- /* @__PURE__ */ jsx15(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_set_null", { count: preview.summary.set_null }) }),
2191
- /* @__PURE__ */ jsx15(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_total", { count: preview.summary.total }) })
2645
+ !isLoading && error ? /* @__PURE__ */ jsx16(Alert5, { severity: "error", children: error }) : null,
2646
+ !isLoading && !error && preview ? /* @__PURE__ */ jsxs10(Stack7, { spacing: 1.5, children: [
2647
+ /* @__PURE__ */ jsx16(Typography4, { color: "text.secondary", children: preview.can_delete ? t("delete_preview_hint") : t("delete_preview_blocked_hint") }),
2648
+ !preview.can_delete ? /* @__PURE__ */ jsx16(Alert5, { severity: "warning", children: t("delete_preview_blocked_hint") }) : null,
2649
+ /* @__PURE__ */ jsxs10(Stack7, { spacing: 0.5, children: [
2650
+ /* @__PURE__ */ jsx16(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_roots", { count: preview.summary.roots }) }),
2651
+ /* @__PURE__ */ jsx16(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_delete", { count: preview.summary.delete }) }),
2652
+ /* @__PURE__ */ jsx16(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_protect", { count: preview.summary.protect }) }),
2653
+ /* @__PURE__ */ jsx16(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_set_null", { count: preview.summary.set_null }) }),
2654
+ /* @__PURE__ */ jsx16(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_total", { count: preview.summary.total }) })
2192
2655
  ] }),
2193
- preview.summary.delete === 0 && preview.summary.protect === 0 && preview.summary.set_null === 0 ? /* @__PURE__ */ jsx15(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_empty") }) : null,
2194
- preview.roots.length > 0 ? /* @__PURE__ */ jsx15(Stack7, { spacing: 1, children: preview.roots.map((rootNode, index) => {
2656
+ preview.summary.delete === 0 && preview.summary.protect === 0 && preview.summary.set_null === 0 ? /* @__PURE__ */ jsx16(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_empty") }) : null,
2657
+ preview.roots.length > 0 ? /* @__PURE__ */ jsx16(Stack7, { spacing: 1, children: preview.roots.map((rootNode, index) => {
2195
2658
  var _a;
2196
- return /* @__PURE__ */ jsx15(
2659
+ return /* @__PURE__ */ jsx16(
2197
2660
  DeletePreviewNode,
2198
2661
  {
2199
2662
  node: rootNode,
@@ -2201,7 +2664,7 @@ function DeletePreviewDialog({
2201
2664
  },
2202
2665
  `${(_a = rootNode.model_slug) != null ? _a : "model"}:${rootNode.id}:${index}`
2203
2666
  );
2204
- }) }) : /* @__PURE__ */ jsx15(
2667
+ }) }) : /* @__PURE__ */ jsx16(
2205
2668
  Typography4,
2206
2669
  {
2207
2670
  variant: "body2",
@@ -2211,10 +2674,10 @@ function DeletePreviewDialog({
2211
2674
  )
2212
2675
  ] }) : null
2213
2676
  ] }),
2214
- /* @__PURE__ */ jsxs9(DialogActions2, { children: [
2215
- /* @__PURE__ */ jsx15(Button2, { onClick: onClose, disabled: isSubmitting, children: t("cancel") }),
2216
- /* @__PURE__ */ jsx15(
2217
- Button2,
2677
+ /* @__PURE__ */ jsxs10(DialogActions3, { children: [
2678
+ /* @__PURE__ */ jsx16(Button3, { onClick: onClose, disabled: isSubmitting, children: t("cancel") }),
2679
+ /* @__PURE__ */ jsx16(
2680
+ Button3,
2218
2681
  {
2219
2682
  color: "error",
2220
2683
  variant: "contained",
@@ -2230,8 +2693,8 @@ function DeletePreviewDialog({
2230
2693
  }
2231
2694
  function DeletePreviewNode({ node, depth }) {
2232
2695
  const t = useAdminTranslation();
2233
- return /* @__PURE__ */ jsxs9(
2234
- Box7,
2696
+ return /* @__PURE__ */ jsxs10(
2697
+ Box8,
2235
2698
  {
2236
2699
  sx: {
2237
2700
  pl: depth === 0 ? 0 : 1.5,
@@ -2239,17 +2702,17 @@ function DeletePreviewNode({ node, depth }) {
2239
2702
  borderLeft: depth === 0 ? "none" : "1px solid rgba(255, 255, 255, 0.08)"
2240
2703
  },
2241
2704
  children: [
2242
- /* @__PURE__ */ jsxs9(Stack7, { spacing: 0.25, children: [
2243
- /* @__PURE__ */ jsx15(Typography4, { sx: { fontWeight: 600 }, children: node.label }),
2244
- /* @__PURE__ */ jsxs9(Typography4, { variant: "body2", color: "text.secondary", children: [
2705
+ /* @__PURE__ */ jsxs10(Stack7, { spacing: 0.25, children: [
2706
+ /* @__PURE__ */ jsx16(Typography4, { sx: { fontWeight: 600 }, children: node.label }),
2707
+ /* @__PURE__ */ jsxs10(Typography4, { variant: "body2", color: "text.secondary", children: [
2245
2708
  node.model_title,
2246
2709
  node.relation_name ? ` \u2022 ${node.relation_name}` : "",
2247
2710
  ` \u2022 ${getEffectLabel(node.effect, t)}`
2248
2711
  ] })
2249
2712
  ] }),
2250
- node.children.length > 0 ? /* @__PURE__ */ jsx15(Stack7, { spacing: 0.75, sx: { mt: 1 }, children: node.children.map((childNode, index) => {
2713
+ node.children.length > 0 ? /* @__PURE__ */ jsx16(Stack7, { spacing: 0.75, sx: { mt: 1 }, children: node.children.map((childNode, index) => {
2251
2714
  var _a;
2252
- return /* @__PURE__ */ jsx15(
2715
+ return /* @__PURE__ */ jsx16(
2253
2716
  DeletePreviewNode,
2254
2717
  {
2255
2718
  node: childNode,
@@ -2273,19 +2736,19 @@ function getEffectLabel(effect, t) {
2273
2736
  }
2274
2737
 
2275
2738
  // src/components/model-page/ListFiltersBar.tsx
2276
- import { memo as memo3, useCallback as useCallback4, useEffect as useEffect8, useMemo as useMemo8, useState as useState8 } from "react";
2739
+ import { memo as memo3, useCallback as useCallback4, useEffect as useEffect10, useMemo as useMemo8, useState as useState9 } from "react";
2277
2740
  import {
2278
2741
  Autocomplete as Autocomplete2,
2279
- Button as Button3,
2742
+ Button as Button4,
2280
2743
  CircularProgress as CircularProgress3,
2281
2744
  Divider,
2282
- MenuItem,
2745
+ MenuItem as MenuItem2,
2283
2746
  Paper as Paper5,
2284
2747
  Stack as Stack8,
2285
2748
  TextField as TextField2,
2286
2749
  Typography as Typography5
2287
2750
  } from "@mui/material";
2288
- import { Fragment as Fragment2, jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
2751
+ import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
2289
2752
  var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
2290
2753
  client,
2291
2754
  slug,
@@ -2320,7 +2783,7 @@ var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
2320
2783
  [filters, values]
2321
2784
  );
2322
2785
  if (filters.length === 0) return null;
2323
- return /* @__PURE__ */ jsx16(
2786
+ return /* @__PURE__ */ jsx17(
2324
2787
  Paper5,
2325
2788
  {
2326
2789
  sx: {
@@ -2332,14 +2795,14 @@ var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
2332
2795
  p: 1.5,
2333
2796
  overflow: "auto"
2334
2797
  },
2335
- children: /* @__PURE__ */ jsxs10(Stack8, { spacing: 1.5, children: [
2336
- /* @__PURE__ */ jsxs10(Stack8, { direction: "row", spacing: 1, alignItems: "center", justifyContent: "space-between", children: [
2337
- /* @__PURE__ */ jsxs10(Stack8, { spacing: 0.25, children: [
2338
- /* @__PURE__ */ jsx16(Typography5, { sx: { fontSize: 15, fontWeight: 700 }, children: t("filters") }),
2339
- activeFiltersCount > 0 ? /* @__PURE__ */ jsx16(Typography5, { color: "text.secondary", sx: { fontSize: 12 }, children: t("active_filters", { count: activeFiltersCount }) }) : null
2798
+ children: /* @__PURE__ */ jsxs11(Stack8, { spacing: 1.5, children: [
2799
+ /* @__PURE__ */ jsxs11(Stack8, { direction: "row", spacing: 1, alignItems: "center", justifyContent: "space-between", children: [
2800
+ /* @__PURE__ */ jsxs11(Stack8, { spacing: 0.25, children: [
2801
+ /* @__PURE__ */ jsx17(Typography5, { sx: { fontSize: 15, fontWeight: 700 }, children: t("filters") }),
2802
+ activeFiltersCount > 0 ? /* @__PURE__ */ jsx17(Typography5, { color: "text.secondary", sx: { fontSize: 12 }, children: t("active_filters", { count: activeFiltersCount }) }) : null
2340
2803
  ] }),
2341
- /* @__PURE__ */ jsx16(
2342
- Button3,
2804
+ /* @__PURE__ */ jsx17(
2805
+ Button4,
2343
2806
  {
2344
2807
  size: "small",
2345
2808
  onClick: onReset,
@@ -2349,8 +2812,8 @@ var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
2349
2812
  }
2350
2813
  )
2351
2814
  ] }),
2352
- /* @__PURE__ */ jsx16(Divider, {}),
2353
- filterGroups.map((group) => /* @__PURE__ */ jsx16(
2815
+ /* @__PURE__ */ jsx17(Divider, {}),
2816
+ filterGroups.map((group) => /* @__PURE__ */ jsx17(
2354
2817
  FilterGroupSection,
2355
2818
  {
2356
2819
  client,
@@ -2367,11 +2830,11 @@ var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
2367
2830
  );
2368
2831
  });
2369
2832
  function FilterGroupSection({ client, slug, group, values, onChange, debounceMs }) {
2370
- return /* @__PURE__ */ jsxs10(Stack8, { spacing: 1, children: [
2371
- /* @__PURE__ */ jsx16(Typography5, { sx: { fontSize: 13, fontWeight: 700, color: "text.secondary" }, children: group.title }),
2372
- /* @__PURE__ */ jsx16(Stack8, { spacing: 1, children: group.filters.map((filter) => {
2833
+ return /* @__PURE__ */ jsxs11(Stack8, { spacing: 1, children: [
2834
+ /* @__PURE__ */ jsx17(Typography5, { sx: { fontSize: 13, fontWeight: 700, color: "text.secondary" }, children: group.title }),
2835
+ /* @__PURE__ */ jsx17(Stack8, { spacing: 1, children: group.filters.map((filter) => {
2373
2836
  var _a;
2374
- return /* @__PURE__ */ jsx16(
2837
+ return /* @__PURE__ */ jsx17(
2375
2838
  ListFilterField,
2376
2839
  {
2377
2840
  client,
@@ -2389,8 +2852,8 @@ function FilterGroupSection({ client, slug, group, values, onChange, debounceMs
2389
2852
  function ListFilterField({ client, slug, filter, value, onChange, debounceMs }) {
2390
2853
  var _a, _b;
2391
2854
  const t = useAdminTranslation();
2392
- const [draftValue, setDraftValue] = useState8(value);
2393
- const [searchValue, setSearchValue] = useState8("");
2855
+ const [draftValue, setDraftValue] = useState9(value);
2856
+ const [searchValue, setSearchValue] = useState9("");
2394
2857
  const selectedValues = useMemo8(() => parseSelectedFilterValues(value, filter.multiple), [filter.multiple, value]);
2395
2858
  const isSelectFilter = filter.input_kind === "select" || filter.input_kind === "select-multiple";
2396
2859
  const loadChoices = useCallback4(
@@ -2417,13 +2880,13 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
2417
2880
  queryKey: `${slug}:${filter.slug}:${searchValue}:${value}`,
2418
2881
  load: loadChoices
2419
2882
  });
2420
- useEffect8(() => {
2883
+ useEffect10(() => {
2421
2884
  setDraftValue(value);
2422
2885
  }, [value]);
2423
- useEffect8(() => {
2886
+ useEffect10(() => {
2424
2887
  setSearchValue("");
2425
2888
  }, [filter.slug]);
2426
- useEffect8(() => {
2889
+ useEffect10(() => {
2427
2890
  if (filter.input_kind !== "text") {
2428
2891
  return;
2429
2892
  }
@@ -2437,7 +2900,7 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
2437
2900
  };
2438
2901
  }, [debounceMs, draftValue, filter.input_kind, filter.slug, onChange, value]);
2439
2902
  if (filter.input_kind === "boolean") {
2440
- return /* @__PURE__ */ jsxs10(
2903
+ return /* @__PURE__ */ jsxs11(
2441
2904
  TextField2,
2442
2905
  {
2443
2906
  select: true,
@@ -2447,8 +2910,8 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
2447
2910
  value,
2448
2911
  onChange: (event) => onChange(filter.slug, event.target.value),
2449
2912
  children: [
2450
- /* @__PURE__ */ jsx16(MenuItem, { value: "", children: t("all") }),
2451
- filter.options.map((option) => /* @__PURE__ */ jsx16(MenuItem, { value: option.value, children: option.label }, `${filter.slug}-${option.value}`))
2913
+ /* @__PURE__ */ jsx17(MenuItem2, { value: "", children: t("all") }),
2914
+ filter.options.map((option) => /* @__PURE__ */ jsx17(MenuItem2, { value: option.value, children: option.label }, `${filter.slug}-${option.value}`))
2452
2915
  ]
2453
2916
  }
2454
2917
  );
@@ -2462,7 +2925,7 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
2462
2925
  };
2463
2926
  });
2464
2927
  const selectedOption = filter.multiple ? selectedOptions : (_a = selectedOptions[0]) != null ? _a : null;
2465
- return /* @__PURE__ */ jsx16(
2928
+ return /* @__PURE__ */ jsx17(
2466
2929
  Autocomplete2,
2467
2930
  {
2468
2931
  options,
@@ -2488,7 +2951,7 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
2488
2951
  renderInput: (params) => (() => {
2489
2952
  var _a2;
2490
2953
  const { InputProps, inputProps, ...textFieldParams } = params;
2491
- return /* @__PURE__ */ jsx16(
2954
+ return /* @__PURE__ */ jsx17(
2492
2955
  TextField2,
2493
2956
  {
2494
2957
  ...textFieldParams,
@@ -2497,8 +2960,8 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
2497
2960
  slotProps: {
2498
2961
  input: {
2499
2962
  ...InputProps,
2500
- endAdornment: /* @__PURE__ */ jsxs10(Fragment2, { children: [
2501
- isLoadingChoices ? /* @__PURE__ */ jsx16(CircularProgress3, { color: "inherit", size: 16 }) : null,
2963
+ endAdornment: /* @__PURE__ */ jsxs11(Fragment2, { children: [
2964
+ isLoadingChoices ? /* @__PURE__ */ jsx17(CircularProgress3, { color: "inherit", size: 16 }) : null,
2502
2965
  InputProps.endAdornment
2503
2966
  ] })
2504
2967
  },
@@ -2510,7 +2973,7 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
2510
2973
  }
2511
2974
  );
2512
2975
  }
2513
- return /* @__PURE__ */ jsx16(
2976
+ return /* @__PURE__ */ jsx17(
2514
2977
  TextField2,
2515
2978
  {
2516
2979
  size: "small",
@@ -2535,8 +2998,8 @@ function parseSelectedFilterValues(value, multiple) {
2535
2998
  // src/components/model-page/ListRow.tsx
2536
2999
  import { memo as memo4 } from "react";
2537
3000
  import MoreVertIcon from "@mui/icons-material/MoreVert";
2538
- import { Box as Box8, Checkbox, IconButton as IconButton2, TableCell, TableRow } from "@mui/material";
2539
- import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
3001
+ import { Box as Box9, Checkbox, IconButton as IconButton2, TableCell, TableRow } from "@mui/material";
3002
+ import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
2540
3003
  var ListRow = memo4(function ListRow2({
2541
3004
  row,
2542
3005
  pkField,
@@ -2552,7 +3015,7 @@ var ListRow = memo4(function ListRow2({
2552
3015
  const checkboxColumnWidth = 56;
2553
3016
  const actionsColumnWidth = 56;
2554
3017
  const rowId = row[pkField];
2555
- return /* @__PURE__ */ jsxs11(
3018
+ return /* @__PURE__ */ jsxs12(
2556
3019
  TableRow,
2557
3020
  {
2558
3021
  hover: true,
@@ -2566,7 +3029,7 @@ var ListRow = memo4(function ListRow2({
2566
3029
  }
2567
3030
  },
2568
3031
  children: [
2569
- /* @__PURE__ */ jsx17(
3032
+ /* @__PURE__ */ jsx18(
2570
3033
  TableCell,
2571
3034
  {
2572
3035
  padding: "none",
@@ -2578,7 +3041,7 @@ var ListRow = memo4(function ListRow2({
2578
3041
  textAlign: "center",
2579
3042
  px: 1
2580
3043
  },
2581
- children: /* @__PURE__ */ jsx17(
3044
+ children: /* @__PURE__ */ jsx18(
2582
3045
  Checkbox,
2583
3046
  {
2584
3047
  checked: isSelected,
@@ -2603,8 +3066,8 @@ var ListRow = memo4(function ListRow2({
2603
3066
  textOverflow: "ellipsis"
2604
3067
  };
2605
3068
  if (imageUrl) {
2606
- return /* @__PURE__ */ jsx17(TableCell, { title: fullFieldValue, sx: { ...commonCellSx, py: 0.75 }, children: /* @__PURE__ */ jsx17(
2607
- Box8,
3069
+ return /* @__PURE__ */ jsx18(TableCell, { title: fullFieldValue, sx: { ...commonCellSx, py: 0.75 }, children: /* @__PURE__ */ jsx18(
3070
+ Box9,
2608
3071
  {
2609
3072
  component: "img",
2610
3073
  src: imageUrl,
@@ -2621,7 +3084,7 @@ var ListRow = memo4(function ListRow2({
2621
3084
  ) }, fieldName);
2622
3085
  }
2623
3086
  if (index === 0) {
2624
- return /* @__PURE__ */ jsx17(
3087
+ return /* @__PURE__ */ jsx18(
2625
3088
  TableCell,
2626
3089
  {
2627
3090
  title: fullFieldValue,
@@ -2639,7 +3102,7 @@ var ListRow = memo4(function ListRow2({
2639
3102
  color: "primary.main"
2640
3103
  }
2641
3104
  },
2642
- children: /* @__PURE__ */ jsx17(
3105
+ children: /* @__PURE__ */ jsx18(
2643
3106
  NavLink,
2644
3107
  {
2645
3108
  href: `${basePath}/${slug}/${rowId}`,
@@ -2652,9 +3115,9 @@ var ListRow = memo4(function ListRow2({
2652
3115
  fieldName
2653
3116
  );
2654
3117
  }
2655
- return /* @__PURE__ */ jsx17(TableCell, { title: fullFieldValue, sx: commonCellSx, children: fieldValue }, fieldName);
3118
+ return /* @__PURE__ */ jsx18(TableCell, { title: fullFieldValue, sx: commonCellSx, children: fieldValue }, fieldName);
2656
3119
  }),
2657
- /* @__PURE__ */ jsx17(
3120
+ /* @__PURE__ */ jsx18(
2658
3121
  TableCell,
2659
3122
  {
2660
3123
  align: "right",
@@ -2663,7 +3126,7 @@ var ListRow = memo4(function ListRow2({
2663
3126
  minWidth: actionsColumnWidth,
2664
3127
  maxWidth: actionsColumnWidth
2665
3128
  },
2666
- children: /* @__PURE__ */ jsx17(IconButton2, { size: "small", onClick: (event) => onOpenMenu(event, rowId), children: /* @__PURE__ */ jsx17(MoreVertIcon, { fontSize: "small" }) })
3129
+ children: /* @__PURE__ */ jsx18(IconButton2, { size: "small", onClick: (event) => onOpenMenu(event, rowId), children: /* @__PURE__ */ jsx18(MoreVertIcon, { fontSize: "small" }) })
2667
3130
  }
2668
3131
  )
2669
3132
  ]
@@ -2672,20 +3135,20 @@ var ListRow = memo4(function ListRow2({
2672
3135
  });
2673
3136
 
2674
3137
  // src/components/model-page/SearchField.tsx
2675
- import { memo as memo5, useEffect as useEffect9, useState as useState9 } from "react";
3138
+ import { memo as memo5, useEffect as useEffect11, useState as useState10 } from "react";
2676
3139
  import { TextField as TextField3 } from "@mui/material";
2677
- import { jsx as jsx18 } from "react/jsx-runtime";
3140
+ import { jsx as jsx19 } from "react/jsx-runtime";
2678
3141
  var SearchField = memo5(function SearchField2({
2679
3142
  value,
2680
3143
  onCommit,
2681
3144
  debounceMs,
2682
3145
  placeholder
2683
3146
  }) {
2684
- const [draftValue, setDraftValue] = useState9(value);
2685
- useEffect9(() => {
3147
+ const [draftValue, setDraftValue] = useState10(value);
3148
+ useEffect11(() => {
2686
3149
  setDraftValue(value);
2687
3150
  }, [value]);
2688
- useEffect9(() => {
3151
+ useEffect11(() => {
2689
3152
  const timerId = window.setTimeout(() => {
2690
3153
  if (draftValue !== value) {
2691
3154
  onCommit(draftValue);
@@ -2695,7 +3158,7 @@ var SearchField = memo5(function SearchField2({
2695
3158
  window.clearTimeout(timerId);
2696
3159
  };
2697
3160
  }, [debounceMs, draftValue, onCommit, value]);
2698
- return /* @__PURE__ */ jsx18(
3161
+ return /* @__PURE__ */ jsx19(
2699
3162
  TextField3,
2700
3163
  {
2701
3164
  size: "small",
@@ -2714,7 +3177,7 @@ var SearchField = memo5(function SearchField2({
2714
3177
  });
2715
3178
 
2716
3179
  // src/components/model-page/useModelPageController.ts
2717
- import { useCallback as useCallback5, useEffect as useEffect10, useMemo as useMemo9, useRef as useRef4, useState as useState10 } from "react";
3180
+ import { useCallback as useCallback5, useEffect as useEffect12, useLayoutEffect as useLayoutEffect2, useMemo as useMemo9, useRef as useRef6, useState as useState11 } from "react";
2718
3181
 
2719
3182
  // src/cache.ts
2720
3183
  var MAX_CACHE_ENTRIES = 100;
@@ -2823,34 +3286,35 @@ function useModelPageController({
2823
3286
  ...initialFilters
2824
3287
  })
2825
3288
  )) != null ? _c : null;
2826
- const [selectedIds, setSelectedIds] = useState10([]);
2827
- const [isAllMatchingSelected, setIsAllMatchingSelected] = useState10(false);
2828
- const [createOpen, setCreateOpen] = useState10(false);
2829
- const [data, setData] = useState10(() => initialCachedResponse);
2830
- const [error, setError] = useState10(null);
2831
- const [isLoading, setIsLoading] = useState10(initialCachedResponse === null);
2832
- const [rowActionMenuAnchor, setRowActionMenuAnchor] = useState10(null);
2833
- const [rowActionMenuId, setRowActionMenuId] = useState10(null);
2834
- const [bulkActionMenuAnchor, setBulkActionMenuAnchor] = useState10(null);
2835
- const [appliedQuery, setAppliedQuery] = useState10(initialQuery);
2836
- const [sortValue, setSortValue] = useState10(initialSort);
2837
- const [currentPage, setCurrentPage] = useState10(initialPage);
2838
- const [pageInput, setPageInput] = useState10(String(initialPage));
2839
- const [appliedFilters, setAppliedFilters] = useState10(initialFilters);
2840
- const [deletePreviewOpen, setDeletePreviewOpen] = useState10(false);
2841
- const [deletePreview, setDeletePreview] = useState10(null);
2842
- const [deletePreviewError, setDeletePreviewError] = useState10(null);
2843
- const [isDeletePreviewLoading, setIsDeletePreviewLoading] = useState10(false);
2844
- const [isDeleteSubmitting, setIsDeleteSubmitting] = useState10(false);
2845
- const [pendingDeleteIds, setPendingDeleteIds] = useState10([]);
2846
- const [pendingDeleteSelectAll, setPendingDeleteSelectAll] = useState10(false);
2847
- const [pendingDeleteScope, setPendingDeleteScope] = useState10(null);
2848
- const [pendingDeleteMode, setPendingDeleteMode] = useState10("single");
2849
- const [filtersOpen, setFiltersOpen] = useState10(false);
2850
- const requestIdRef = useRef4(0);
2851
- const dataRef = useRef4(initialCachedResponse);
2852
- const pageSizeRef = useRef4((_d = initialCachedResponse == null ? void 0 : initialCachedResponse.meta.page_size) != null ? _d : DEFAULT_PAGE_SIZE);
2853
- const previousSlugRef = useRef4(slug);
3289
+ const [selectedIds, setSelectedIds] = useState11([]);
3290
+ const [isAllMatchingSelected, setIsAllMatchingSelected] = useState11(false);
3291
+ const [createOpen, setCreateOpen] = useState11(false);
3292
+ const [data, setData] = useState11(() => initialCachedResponse);
3293
+ const [error, setError] = useState11(null);
3294
+ const [isLoading, setIsLoading] = useState11(initialCachedResponse === null);
3295
+ const [rowActionMenuAnchor, setRowActionMenuAnchor] = useState11(null);
3296
+ const [rowActionMenuId, setRowActionMenuId] = useState11(null);
3297
+ const [bulkActionMenuAnchor, setBulkActionMenuAnchor] = useState11(null);
3298
+ const [bulkActionFormSlug, setBulkActionFormSlug] = useState11(null);
3299
+ const [appliedQuery, setAppliedQuery] = useState11(initialQuery);
3300
+ const [sortValue, setSortValue] = useState11(initialSort);
3301
+ const [currentPage, setCurrentPage] = useState11(initialPage);
3302
+ const [pageInput, setPageInput] = useState11(String(initialPage));
3303
+ const [appliedFilters, setAppliedFilters] = useState11(initialFilters);
3304
+ const [deletePreviewOpen, setDeletePreviewOpen] = useState11(false);
3305
+ const [deletePreview, setDeletePreview] = useState11(null);
3306
+ const [deletePreviewError, setDeletePreviewError] = useState11(null);
3307
+ const [isDeletePreviewLoading, setIsDeletePreviewLoading] = useState11(false);
3308
+ const [isDeleteSubmitting, setIsDeleteSubmitting] = useState11(false);
3309
+ const [pendingDeleteIds, setPendingDeleteIds] = useState11([]);
3310
+ const [pendingDeleteSelectAll, setPendingDeleteSelectAll] = useState11(false);
3311
+ const [pendingDeleteScope, setPendingDeleteScope] = useState11(null);
3312
+ const [pendingDeleteMode, setPendingDeleteMode] = useState11("single");
3313
+ const [filtersOpen, setFiltersOpen] = useState11(false);
3314
+ const requestIdRef = useRef6(0);
3315
+ const dataRef = useRef6(initialCachedResponse);
3316
+ const pageSizeRef = useRef6((_d = initialCachedResponse == null ? void 0 : initialCachedResponse.meta.page_size) != null ? _d : DEFAULT_PAGE_SIZE);
3317
+ const previousSlugRef = useRef6(slug);
2854
3318
  const sortFields = useMemo9(() => sortValue.split(",").filter(Boolean), [sortValue]);
2855
3319
  const meta = (_e = data == null ? void 0 : data.meta) != null ? _e : null;
2856
3320
  const rows = (_f = data == null ? void 0 : data.items) != null ? _f : [];
@@ -2894,13 +3358,13 @@ function useModelPageController({
2894
3358
  });
2895
3359
  const hasSelection = isAllMatchingSelected || selectedIds.length > 0;
2896
3360
  const selectionCount = isAllMatchingSelected ? total : selectedIds.length;
2897
- useEffect10(() => {
3361
+ useEffect12(() => {
2898
3362
  dataRef.current = data;
2899
3363
  }, [data]);
2900
- useEffect10(() => {
3364
+ useEffect12(() => {
2901
3365
  setPageInput(String(currentPage));
2902
3366
  }, [currentPage]);
2903
- useEffect10(() => {
3367
+ useLayoutEffect2(() => {
2904
3368
  var _a2, _b2, _c2, _d2;
2905
3369
  if (previousSlugRef.current === slug) {
2906
3370
  return;
@@ -2930,6 +3394,7 @@ function useModelPageController({
2930
3394
  setRowActionMenuAnchor(null);
2931
3395
  setRowActionMenuId(null);
2932
3396
  setBulkActionMenuAnchor(null);
3397
+ setBulkActionFormSlug(null);
2933
3398
  setDeletePreviewOpen(false);
2934
3399
  setDeletePreview(null);
2935
3400
  setDeletePreviewError(null);
@@ -2940,7 +3405,7 @@ function useModelPageController({
2940
3405
  setPendingDeleteScope(null);
2941
3406
  setPendingDeleteMode("single");
2942
3407
  }, [client, locationSearch, slug]);
2943
- useEffect10(() => {
3408
+ useLayoutEffect2(() => {
2944
3409
  var _a2, _b2;
2945
3410
  const nextSearchParams = new URLSearchParams(locationSearch);
2946
3411
  const nextQuery = (_a2 = nextSearchParams.get("q")) != null ? _a2 : "";
@@ -3001,7 +3466,7 @@ function useModelPageController({
3001
3466
  }
3002
3467
  }
3003
3468
  }, [appliedFilters, appliedQuery, client, currentPage, isAllMatchingSelected, slug, sortValue, t]);
3004
- useEffect10(() => {
3469
+ useEffect12(() => {
3005
3470
  void loadItems();
3006
3471
  }, [loadItems]);
3007
3472
  const refresh = useCallback5(async () => {
@@ -3153,7 +3618,7 @@ function useModelPageController({
3153
3618
  }
3154
3619
  }, [clearSelection, client, message, pendingDeleteIds, pendingDeleteMode, pendingDeleteScope, pendingDeleteSelectAll, refresh, slug, t]);
3155
3620
  const handleRunNamedBulkAction = useCallback5(async (actionSlug) => {
3156
- var _a2, _b2;
3621
+ var _a2, _b2, _c2, _d2;
3157
3622
  if (!actionSlug || !hasSelection) {
3158
3623
  return;
3159
3624
  }
@@ -3161,6 +3626,12 @@ function useModelPageController({
3161
3626
  await openBulkDeletePreview();
3162
3627
  return;
3163
3628
  }
3629
+ const action = bulkActions.find((item) => item.slug === actionSlug);
3630
+ if (((_b2 = (_a2 = action == null ? void 0 : action.form) == null ? void 0 : _a2.length) != null ? _b2 : 0) > 0) {
3631
+ setBulkActionMenuAnchor(null);
3632
+ setBulkActionFormSlug(actionSlug);
3633
+ return;
3634
+ }
3164
3635
  try {
3165
3636
  const response = await client.runBulkAction(
3166
3637
  slug,
@@ -3172,7 +3643,7 @@ function useModelPageController({
3172
3643
  setBulkActionMenuAnchor(null);
3173
3644
  clearSelection();
3174
3645
  await refresh();
3175
- const actionLabel = (_b2 = (_a2 = bulkActions.find((item) => item.slug === actionSlug)) == null ? void 0 : _a2.label) != null ? _b2 : actionSlug;
3646
+ const actionLabel = (_d2 = (_c2 = bulkActions.find((item) => item.slug === actionSlug)) == null ? void 0 : _c2.label) != null ? _d2 : actionSlug;
3176
3647
  message.success(t("action_success", { action: actionLabel, count: response.processed }));
3177
3648
  } catch (reason) {
3178
3649
  const nextError = reason instanceof Error ? reason.message : t("object_action_error");
@@ -3180,6 +3651,34 @@ function useModelPageController({
3180
3651
  message.error(nextError);
3181
3652
  }
3182
3653
  }, [bulkActions, clearSelection, client, hasSelection, isAllMatchingSelected, message, openBulkDeletePreview, refresh, selectedIds, selectionScope, slug, t]);
3654
+ const handleSubmitBulkActionForm = useCallback5(async (payload) => {
3655
+ var _a2, _b2;
3656
+ if (!bulkActionFormSlug || !hasSelection) {
3657
+ return;
3658
+ }
3659
+ const response = await client.runBulkAction(
3660
+ slug,
3661
+ bulkActionFormSlug,
3662
+ isAllMatchingSelected ? [] : selectedIds,
3663
+ payload,
3664
+ isAllMatchingSelected ? { selectAll: true, selectionScope } : void 0
3665
+ );
3666
+ setBulkActionFormSlug(null);
3667
+ clearSelection();
3668
+ await refresh();
3669
+ const actionLabel = (_b2 = (_a2 = bulkActions.find((item) => item.slug === bulkActionFormSlug)) == null ? void 0 : _a2.label) != null ? _b2 : bulkActionFormSlug;
3670
+ message.success(t("action_success", { action: actionLabel, count: response.processed }));
3671
+ }, [bulkActionFormSlug, bulkActions, clearSelection, client, hasSelection, isAllMatchingSelected, message, refresh, selectedIds, selectionScope, slug, t]);
3672
+ const handleCloseBulkActionForm = useCallback5(() => {
3673
+ setBulkActionFormSlug(null);
3674
+ }, []);
3675
+ const activeBulkAction = useMemo9(
3676
+ () => {
3677
+ var _a2;
3678
+ return (_a2 = bulkActions.find((item) => item.slug === bulkActionFormSlug)) != null ? _a2 : null;
3679
+ },
3680
+ [bulkActionFormSlug, bulkActions]
3681
+ );
3183
3682
  const handleRowDelete = useCallback5(async (rowId) => {
3184
3683
  setRowActionMenuAnchor(null);
3185
3684
  setRowActionMenuId(null);
@@ -3257,6 +3756,7 @@ function useModelPageController({
3257
3756
  appliedQuery,
3258
3757
  bulkActionMenuAnchor,
3259
3758
  bulkActions,
3759
+ activeBulkAction,
3260
3760
  clearBulkDeleteState,
3261
3761
  createOpen,
3262
3762
  currentPage,
@@ -3269,6 +3769,7 @@ function useModelPageController({
3269
3769
  filtersOpen,
3270
3770
  handleClearDeletePreview,
3271
3771
  handleCloseBulkActionMenu,
3772
+ handleCloseBulkActionForm,
3272
3773
  handleCloseRowMenu,
3273
3774
  handleConfirmDelete,
3274
3775
  handleFilterChange,
@@ -3278,6 +3779,7 @@ function useModelPageController({
3278
3779
  handleResetFilters,
3279
3780
  handleRowDelete,
3280
3781
  handleRunNamedBulkAction,
3782
+ handleSubmitBulkActionForm,
3281
3783
  handleSearchCommit,
3282
3784
  handleSelectAllMatching,
3283
3785
  handleToggleAllVisible,
@@ -3359,34 +3861,34 @@ function extractFilterParams(params) {
3359
3861
  }
3360
3862
 
3361
3863
  // src/components/model-page/Skeletons.tsx
3362
- import { Box as Box9, Paper as Paper6, Skeleton as Skeleton3, Stack as Stack9 } from "@mui/material";
3363
- import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
3864
+ import { Box as Box10, Paper as Paper6, Skeleton as Skeleton3, Stack as Stack9 } from "@mui/material";
3865
+ import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
3364
3866
  function ModelPageSkeleton() {
3365
- return /* @__PURE__ */ jsxs12(Stack9, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
3366
- /* @__PURE__ */ jsx19(MainHeaderSkeleton, { titleWidth: 240, subtitleWidth: "38%" }),
3367
- /* @__PURE__ */ jsx19(Paper6, { sx: { p: 1.5, borderRadius: "10px", flexShrink: 0 }, children: /* @__PURE__ */ jsxs12(Stack9, { direction: { xs: "column", lg: "row" }, spacing: 1.5, alignItems: { lg: "center" }, children: [
3368
- /* @__PURE__ */ jsx19(Skeleton3, { variant: "rounded", width: 360, height: 40 }),
3369
- /* @__PURE__ */ jsx19(Skeleton3, { variant: "rounded", width: 128, height: 40 }),
3370
- /* @__PURE__ */ jsx19(Box9, { sx: { flex: 1 } }),
3371
- /* @__PURE__ */ jsx19(Skeleton3, { variant: "rounded", width: 110, height: 24 })
3867
+ return /* @__PURE__ */ jsxs13(Stack9, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
3868
+ /* @__PURE__ */ jsx20(MainHeaderSkeleton, { titleWidth: 240, subtitleWidth: "38%" }),
3869
+ /* @__PURE__ */ jsx20(Paper6, { sx: { p: 1.5, borderRadius: "10px", flexShrink: 0 }, children: /* @__PURE__ */ jsxs13(Stack9, { direction: { xs: "column", lg: "row" }, spacing: 1.5, alignItems: { lg: "center" }, children: [
3870
+ /* @__PURE__ */ jsx20(Skeleton3, { variant: "rounded", width: 360, height: 40 }),
3871
+ /* @__PURE__ */ jsx20(Skeleton3, { variant: "rounded", width: 128, height: 40 }),
3872
+ /* @__PURE__ */ jsx20(Box10, { sx: { flex: 1 } }),
3873
+ /* @__PURE__ */ jsx20(Skeleton3, { variant: "rounded", width: 110, height: 24 })
3372
3874
  ] }) }),
3373
- /* @__PURE__ */ jsx19(Paper6, { sx: { borderRadius: "10px", flex: 1, minHeight: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx19(ModelTableSkeleton, {}) })
3875
+ /* @__PURE__ */ jsx20(Paper6, { sx: { borderRadius: "10px", flex: 1, minHeight: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx20(ModelTableSkeleton, {}) })
3374
3876
  ] });
3375
3877
  }
3376
3878
  function ModelTableSkeleton() {
3377
- return /* @__PURE__ */ jsx19(Box9, { sx: { height: "100%", overflow: "auto", p: 1.5 }, children: /* @__PURE__ */ jsxs12(Stack9, { spacing: 1, children: [
3378
- /* @__PURE__ */ jsx19(Skeleton3, { variant: "rounded", width: "100%", height: 42 }),
3379
- Array.from({ length: 10 }).map((_, index) => /* @__PURE__ */ jsx19(Skeleton3, { variant: "rounded", width: "100%", height: 48 }, index))
3879
+ return /* @__PURE__ */ jsx20(Box10, { sx: { height: "100%", overflow: "auto", p: 1.5 }, children: /* @__PURE__ */ jsxs13(Stack9, { spacing: 1, children: [
3880
+ /* @__PURE__ */ jsx20(Skeleton3, { variant: "rounded", width: "100%", height: 42 }),
3881
+ Array.from({ length: 10 }).map((_, index) => /* @__PURE__ */ jsx20(Skeleton3, { variant: "rounded", width: "100%", height: 48 }, index))
3380
3882
  ] }) });
3381
3883
  }
3382
3884
 
3383
3885
  // src/components/ModelPage.tsx
3384
- import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
3886
+ import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
3385
3887
  var SEARCH_DEBOUNCE_MS = 300;
3386
3888
  var CHECKBOX_COLUMN_WIDTH = 56;
3387
3889
  var ACTIONS_COLUMN_WIDTH = 56;
3388
3890
  function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3389
- var _a, _b;
3891
+ var _a, _b, _c;
3390
3892
  const locale = useAdminLocale();
3391
3893
  const t = useAdminTranslation();
3392
3894
  const selectAllLabel = locale === "ru" ? "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0432\u0441\u0435" : "Select All";
@@ -3394,6 +3896,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3394
3896
  const location = useAdminLocation(resolvedRouter);
3395
3897
  const theme = useTheme3();
3396
3898
  const isMobile = useMediaQuery2(theme.breakpoints.down("md"));
3899
+ const { pendingPath, finishPendingNavigation } = useShellContext();
3397
3900
  const controller = useModelPageController({
3398
3901
  client,
3399
3902
  slug,
@@ -3402,12 +3905,27 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3402
3905
  router: resolvedRouter,
3403
3906
  t
3404
3907
  });
3908
+ useLayoutEffect3(() => {
3909
+ if (pendingPath === null) {
3910
+ return;
3911
+ }
3912
+ if (controller.isLoading) {
3913
+ return;
3914
+ }
3915
+ if (!controller.meta && !controller.error) {
3916
+ return;
3917
+ }
3918
+ if (controller.meta && controller.meta.slug !== slug) {
3919
+ return;
3920
+ }
3921
+ finishPendingNavigation(location.pathname);
3922
+ }, [controller.error, controller.isLoading, controller.meta, finishPendingNavigation, location.pathname, pendingPath, slug]);
3405
3923
  useAdminDocumentTitle(t("admin_title"), (_b = (_a = controller.meta) == null ? void 0 : _a.title) != null ? _b : slug);
3406
3924
  if (!controller.isLoading && controller.error && !controller.data) {
3407
- return /* @__PURE__ */ jsx20(Alert5, { severity: "error", children: controller.error });
3925
+ return /* @__PURE__ */ jsx21(Alert6, { severity: "error", children: controller.error });
3408
3926
  }
3409
3927
  if (!controller.data || !controller.meta) {
3410
- return /* @__PURE__ */ jsx20(ModelPageSkeleton, {});
3928
+ return /* @__PURE__ */ jsx21(ModelPageSkeleton, {});
3411
3929
  }
3412
3930
  const meta = controller.meta;
3413
3931
  const beforePagination = renderBeforePagination == null ? void 0 : renderBeforePagination({
@@ -3426,12 +3944,12 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3426
3944
  appliedFilters: controller.appliedFilters,
3427
3945
  refresh: controller.refresh
3428
3946
  });
3429
- return /* @__PURE__ */ jsx20(AdminRouterProvider, { router: resolvedRouter, children: /* @__PURE__ */ jsxs13(Stack10, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
3430
- /* @__PURE__ */ jsx20(
3947
+ return /* @__PURE__ */ jsx21(AdminRouterProvider, { router: resolvedRouter, children: /* @__PURE__ */ jsxs14(Stack10, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
3948
+ /* @__PURE__ */ jsx21(
3431
3949
  MainHeader,
3432
3950
  {
3433
3951
  title: controller.meta.title,
3434
- actions: /* @__PURE__ */ jsx20(Tooltip, { title: t("create"), children: /* @__PURE__ */ jsx20(
3952
+ actions: /* @__PURE__ */ jsx21(Tooltip, { title: t("create"), children: /* @__PURE__ */ jsx21(
3435
3953
  IconButton3,
3436
3954
  {
3437
3955
  "aria-label": t("create"),
@@ -3446,14 +3964,14 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3446
3964
  backgroundColor: "primary.dark"
3447
3965
  }
3448
3966
  },
3449
- children: /* @__PURE__ */ jsx20(AddIcon, { fontSize: "small" })
3967
+ children: /* @__PURE__ */ jsx21(AddIcon, { fontSize: "small" })
3450
3968
  }
3451
3969
  ) }),
3452
3970
  subtitle: `${controller.meta.slug} | ${t("objects_count", { count: controller.total })}`,
3453
- details: controller.meta.description ? /* @__PURE__ */ jsx20(Typography6, { color: "text.secondary", sx: { fontSize: 14, lineHeight: 1.45 }, children: controller.meta.description }) : void 0
3971
+ details: controller.meta.description ? /* @__PURE__ */ jsx21(Typography6, { color: "text.secondary", sx: { fontSize: 14, lineHeight: 1.45 }, children: controller.meta.description }) : void 0
3454
3972
  }
3455
3973
  ),
3456
- /* @__PURE__ */ jsx20(
3974
+ /* @__PURE__ */ jsx21(
3457
3975
  Paper7,
3458
3976
  {
3459
3977
  sx: {
@@ -3461,8 +3979,8 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3461
3979
  borderRadius: "10px",
3462
3980
  flexShrink: 0
3463
3981
  },
3464
- children: /* @__PURE__ */ jsxs13(Stack10, { direction: { xs: "column", lg: "row" }, spacing: 1.5, alignItems: { lg: "center" }, children: [
3465
- /* @__PURE__ */ jsxs13(
3982
+ children: /* @__PURE__ */ jsxs14(Stack10, { direction: { xs: "column", lg: "row" }, spacing: 1.5, alignItems: { lg: "center" }, children: [
3983
+ /* @__PURE__ */ jsxs14(
3466
3984
  Stack10,
3467
3985
  {
3468
3986
  direction: { xs: "column", xl: "row" },
@@ -3470,7 +3988,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3470
3988
  alignItems: { xl: "center" },
3471
3989
  sx: { flex: 1, minWidth: 0 },
3472
3990
  children: [
3473
- /* @__PURE__ */ jsx20(
3991
+ /* @__PURE__ */ jsx21(
3474
3992
  SearchField,
3475
3993
  {
3476
3994
  value: controller.appliedQuery,
@@ -3479,18 +3997,18 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3479
3997
  placeholder: t("search")
3480
3998
  }
3481
3999
  ),
3482
- controller.hasSelection ? /* @__PURE__ */ jsxs13(Stack10, { direction: "row", spacing: 1, alignItems: "center", sx: { minWidth: 0, flexWrap: "wrap" }, children: [
3483
- /* @__PURE__ */ jsx20(
3484
- Button4,
4000
+ controller.hasSelection ? /* @__PURE__ */ jsxs14(Stack10, { direction: "row", spacing: 1, alignItems: "center", sx: { minWidth: 0, flexWrap: "wrap" }, children: [
4001
+ /* @__PURE__ */ jsx21(
4002
+ Button5,
3485
4003
  {
3486
4004
  variant: "outlined",
3487
- endIcon: /* @__PURE__ */ jsx20(ExpandMoreIcon4, {}),
4005
+ endIcon: /* @__PURE__ */ jsx21(ExpandMoreIcon4, {}),
3488
4006
  onClick: (event) => controller.setBulkActionMenuAnchor(event.currentTarget),
3489
4007
  children: t("actions")
3490
4008
  }
3491
4009
  ),
3492
- !controller.isAllMatchingSelected && controller.selectionCount < controller.total ? /* @__PURE__ */ jsx20(
3493
- Button4,
4010
+ !controller.isAllMatchingSelected && controller.selectionCount < controller.total ? /* @__PURE__ */ jsx21(
4011
+ Button5,
3494
4012
  {
3495
4013
  variant: "text",
3496
4014
  onClick: controller.handleSelectAllMatching,
@@ -3498,7 +4016,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3498
4016
  children: selectAllLabel
3499
4017
  }
3500
4018
  ) : null,
3501
- /* @__PURE__ */ jsxs13(Typography6, { color: "text.secondary", sx: { alignSelf: "center", whiteSpace: "nowrap" }, children: [
4019
+ /* @__PURE__ */ jsxs14(Typography6, { color: "text.secondary", sx: { alignSelf: "center", whiteSpace: "nowrap" }, children: [
3502
4020
  t("selected_count", { count: controller.selectionCount }),
3503
4021
  " / ",
3504
4022
  controller.total
@@ -3507,28 +4025,28 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3507
4025
  ]
3508
4026
  }
3509
4027
  ),
3510
- /* @__PURE__ */ jsxs13(Stack10, { direction: "row", spacing: 1, alignItems: "center", sx: { marginLeft: "auto" }, children: [
3511
- beforePagination ? /* @__PURE__ */ jsx20(Box10, { sx: { display: "flex", alignItems: "center", flexShrink: 0 }, children: beforePagination }) : null,
3512
- isMobile && controller.hasListFilters ? /* @__PURE__ */ jsx20(Tooltip, { title: t("filters"), children: /* @__PURE__ */ jsx20(
4028
+ /* @__PURE__ */ jsxs14(Stack10, { direction: "row", spacing: 1, alignItems: "center", sx: { marginLeft: "auto" }, children: [
4029
+ beforePagination ? /* @__PURE__ */ jsx21(Box11, { sx: { display: "flex", alignItems: "center", flexShrink: 0 }, children: beforePagination }) : null,
4030
+ isMobile && controller.hasListFilters ? /* @__PURE__ */ jsx21(Tooltip, { title: t("filters"), children: /* @__PURE__ */ jsx21(
3513
4031
  IconButton3,
3514
4032
  {
3515
4033
  size: "small",
3516
4034
  "aria-label": t("filters"),
3517
4035
  onClick: () => controller.setFiltersOpen(true),
3518
- children: /* @__PURE__ */ jsx20(FilterListIcon, { fontSize: "small" })
4036
+ children: /* @__PURE__ */ jsx21(FilterListIcon, { fontSize: "small" })
3519
4037
  }
3520
4038
  ) }) : null,
3521
- /* @__PURE__ */ jsx20(
4039
+ /* @__PURE__ */ jsx21(
3522
4040
  IconButton3,
3523
4041
  {
3524
4042
  size: "small",
3525
4043
  onClick: () => controller.handlePageChange(controller.currentPage - 1),
3526
4044
  disabled: controller.currentPage <= 1,
3527
4045
  sx: { mr: "-5px" },
3528
- children: /* @__PURE__ */ jsx20(ChevronLeftIcon, { fontSize: "small" })
4046
+ children: /* @__PURE__ */ jsx21(ChevronLeftIcon, { fontSize: "small" })
3529
4047
  }
3530
4048
  ),
3531
- /* @__PURE__ */ jsx20(
4049
+ /* @__PURE__ */ jsx21(
3532
4050
  InputBase,
3533
4051
  {
3534
4052
  value: controller.pageInput,
@@ -3558,7 +4076,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3558
4076
  }
3559
4077
  }
3560
4078
  ),
3561
- /* @__PURE__ */ jsxs13(
4079
+ /* @__PURE__ */ jsxs14(
3562
4080
  Typography6,
3563
4081
  {
3564
4082
  color: "text.secondary",
@@ -3569,22 +4087,22 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3569
4087
  ]
3570
4088
  }
3571
4089
  ),
3572
- /* @__PURE__ */ jsx20(
4090
+ /* @__PURE__ */ jsx21(
3573
4091
  IconButton3,
3574
4092
  {
3575
4093
  size: "small",
3576
4094
  onClick: () => controller.handlePageChange(controller.currentPage + 1),
3577
4095
  disabled: controller.currentPage >= controller.totalPages,
3578
4096
  sx: { ml: "-5px" },
3579
- children: /* @__PURE__ */ jsx20(ChevronRightIcon, { fontSize: "small" })
4097
+ children: /* @__PURE__ */ jsx21(ChevronRightIcon, { fontSize: "small" })
3580
4098
  }
3581
4099
  )
3582
4100
  ] })
3583
4101
  ] })
3584
4102
  }
3585
4103
  ),
3586
- /* @__PURE__ */ jsxs13(Stack10, { direction: { xs: "column", lg: "row" }, spacing: 1.5, sx: { flex: 1, minHeight: 0 }, children: [
3587
- /* @__PURE__ */ jsx20(
4104
+ /* @__PURE__ */ jsxs14(Stack10, { direction: { xs: "column", lg: "row" }, spacing: 1.5, sx: { flex: 1, minHeight: 0 }, children: [
4105
+ /* @__PURE__ */ jsx21(
3588
4106
  Paper7,
3589
4107
  {
3590
4108
  sx: {
@@ -3594,9 +4112,9 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3594
4112
  minHeight: 0,
3595
4113
  overflow: "hidden"
3596
4114
  },
3597
- children: controller.isLoading ? /* @__PURE__ */ jsx20(ModelTableSkeleton, {}) : /* @__PURE__ */ jsx20(Box10, { sx: { height: "100%", overflow: "auto" }, children: /* @__PURE__ */ jsxs13(Table, { stickyHeader: true, size: "small", sx: { tableLayout: "fixed" }, children: [
3598
- /* @__PURE__ */ jsx20(TableHead, { children: /* @__PURE__ */ jsxs13(TableRow2, { children: [
3599
- /* @__PURE__ */ jsx20(
4115
+ children: controller.isLoading ? /* @__PURE__ */ jsx21(ModelTableSkeleton, {}) : /* @__PURE__ */ jsx21(Box11, { sx: { height: "100%", overflow: "auto" }, children: /* @__PURE__ */ jsxs14(Table, { stickyHeader: true, size: "small", sx: { tableLayout: "fixed" }, children: [
4116
+ /* @__PURE__ */ jsx21(TableHead, { children: /* @__PURE__ */ jsxs14(TableRow2, { children: [
4117
+ /* @__PURE__ */ jsx21(
3600
4118
  TableCell2,
3601
4119
  {
3602
4120
  padding: "none",
@@ -3609,7 +4127,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3609
4127
  textAlign: "center",
3610
4128
  px: 1
3611
4129
  },
3612
- children: /* @__PURE__ */ jsx20(
4130
+ children: /* @__PURE__ */ jsx21(
3613
4131
  Checkbox2,
3614
4132
  {
3615
4133
  checked: controller.allVisibleSelected,
@@ -3624,7 +4142,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3624
4142
  const field = controller.fieldMap.get(fieldName);
3625
4143
  const sortDirection = resolveSortDirection(controller.sortFields, fieldName);
3626
4144
  const isSortable = resolveFieldSortable(field);
3627
- return /* @__PURE__ */ jsx20(
4145
+ return /* @__PURE__ */ jsx21(
3628
4146
  TableCell2,
3629
4147
  {
3630
4148
  sortDirection: sortDirection != null ? sortDirection : false,
@@ -3637,7 +4155,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3637
4155
  maxWidth: getListFieldWidthPx(field)
3638
4156
  },
3639
4157
  onClick: isSortable ? () => controller.toggleSort(fieldName) : void 0,
3640
- children: isSortable ? /* @__PURE__ */ jsx20(
4158
+ children: isSortable ? /* @__PURE__ */ jsx21(
3641
4159
  TableSortLabel,
3642
4160
  {
3643
4161
  active: Boolean(sortDirection),
@@ -3651,7 +4169,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3651
4169
  },
3652
4170
  children: (_a2 = field == null ? void 0 : field.label) != null ? _a2 : fieldName
3653
4171
  }
3654
- ) : /* @__PURE__ */ jsx20(Typography6, { component: "span", sx: {
4172
+ ) : /* @__PURE__ */ jsx21(Typography6, { component: "span", sx: {
3655
4173
  fontSize: 14,
3656
4174
  fontWeight: 700,
3657
4175
  color: "rgba(255, 255, 255, 0.96)"
@@ -3660,7 +4178,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3660
4178
  fieldName
3661
4179
  );
3662
4180
  }),
3663
- /* @__PURE__ */ jsx20(
4181
+ /* @__PURE__ */ jsx21(
3664
4182
  TableCell2,
3665
4183
  {
3666
4184
  align: "right",
@@ -3673,9 +4191,9 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3673
4191
  }
3674
4192
  )
3675
4193
  ] }) }),
3676
- /* @__PURE__ */ jsx20(TableBody, { children: controller.rows.map((row) => {
4194
+ /* @__PURE__ */ jsx21(TableBody, { children: controller.rows.map((row) => {
3677
4195
  const rowId = row[meta.pk_field];
3678
- return /* @__PURE__ */ jsx20(
4196
+ return /* @__PURE__ */ jsx21(
3679
4197
  ListRow,
3680
4198
  {
3681
4199
  row,
@@ -3695,7 +4213,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3695
4213
  ] }) })
3696
4214
  }
3697
4215
  ),
3698
- !isMobile && controller.hasListFilters ? /* @__PURE__ */ jsx20(
4216
+ !isMobile && controller.hasListFilters ? /* @__PURE__ */ jsx21(
3699
4217
  ListFiltersSidebar,
3700
4218
  {
3701
4219
  client,
@@ -3708,14 +4226,14 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3708
4226
  }
3709
4227
  ) : null
3710
4228
  ] }),
3711
- /* @__PURE__ */ jsx20(
4229
+ /* @__PURE__ */ jsx21(
3712
4230
  Menu,
3713
4231
  {
3714
4232
  anchorEl: controller.bulkActionMenuAnchor,
3715
4233
  open: Boolean(controller.bulkActionMenuAnchor),
3716
4234
  onClose: controller.handleCloseBulkActionMenu,
3717
- children: controller.bulkActions.map((action) => /* @__PURE__ */ jsx20(
3718
- MenuItem2,
4235
+ children: controller.bulkActions.map((action) => /* @__PURE__ */ jsx21(
4236
+ MenuItem3,
3719
4237
  {
3720
4238
  onClick: () => void controller.handleRunNamedBulkAction(action.slug),
3721
4239
  children: action.label
@@ -3724,14 +4242,14 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3724
4242
  ))
3725
4243
  }
3726
4244
  ),
3727
- /* @__PURE__ */ jsx20(
4245
+ /* @__PURE__ */ jsx21(
3728
4246
  Menu,
3729
4247
  {
3730
4248
  anchorEl: controller.rowActionMenuAnchor,
3731
4249
  open: Boolean(controller.rowActionMenuAnchor),
3732
4250
  onClose: controller.handleCloseRowMenu,
3733
- children: /* @__PURE__ */ jsx20(
3734
- MenuItem2,
4251
+ children: /* @__PURE__ */ jsx21(
4252
+ MenuItem3,
3735
4253
  {
3736
4254
  onClick: () => {
3737
4255
  if (controller.rowActionMenuId !== null) {
@@ -3743,7 +4261,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3743
4261
  )
3744
4262
  }
3745
4263
  ),
3746
- /* @__PURE__ */ jsx20(
4264
+ /* @__PURE__ */ jsx21(
3747
4265
  FormDialog,
3748
4266
  {
3749
4267
  open: controller.createOpen,
@@ -3756,8 +4274,24 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3756
4274
  client
3757
4275
  }
3758
4276
  ),
3759
- /* @__PURE__ */ jsxs13(
3760
- Dialog3,
4277
+ ((_c = controller.activeBulkAction) == null ? void 0 : _c.form) ? /* @__PURE__ */ jsx21(
4278
+ ActionFormDialog,
4279
+ {
4280
+ open: true,
4281
+ onClose: controller.handleCloseBulkActionForm,
4282
+ onSuccess: () => void 0,
4283
+ title: `${controller.activeBulkAction.label}: ${meta.title}`,
4284
+ submitLabel: controller.activeBulkAction.label,
4285
+ slug,
4286
+ locale: meta.locale,
4287
+ fields: controller.activeBulkAction.form,
4288
+ client,
4289
+ choiceScope: { kind: "bulk-action", actionSlug: controller.activeBulkAction.slug },
4290
+ onSubmit: controller.handleSubmitBulkActionForm
4291
+ }
4292
+ ) : null,
4293
+ /* @__PURE__ */ jsxs14(
4294
+ Dialog4,
3761
4295
  {
3762
4296
  open: controller.filtersOpen,
3763
4297
  onClose: () => controller.setFiltersOpen(false),
@@ -3777,8 +4311,8 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3777
4311
  }
3778
4312
  },
3779
4313
  children: [
3780
- /* @__PURE__ */ jsx20(DialogTitle3, { children: t("filters") }),
3781
- /* @__PURE__ */ jsx20(DialogContent3, { sx: { px: 2, pb: 2 }, children: controller.hasListFilters ? /* @__PURE__ */ jsx20(
4314
+ /* @__PURE__ */ jsx21(DialogTitle4, { children: t("filters") }),
4315
+ /* @__PURE__ */ jsx21(DialogContent4, { sx: { px: 2, pb: 2 }, children: controller.hasListFilters ? /* @__PURE__ */ jsx21(
3782
4316
  ListFiltersSidebar,
3783
4317
  {
3784
4318
  client,
@@ -3793,7 +4327,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3793
4327
  ]
3794
4328
  }
3795
4329
  ),
3796
- /* @__PURE__ */ jsx20(
4330
+ /* @__PURE__ */ jsx21(
3797
4331
  DeletePreviewDialog,
3798
4332
  {
3799
4333
  open: controller.deletePreviewOpen,
@@ -3826,18 +4360,19 @@ function resolveFieldSortable(field) {
3826
4360
  }
3827
4361
 
3828
4362
  // src/components/ObjectPage.tsx
4363
+ import { useLayoutEffect as useLayoutEffect5 } from "react";
3829
4364
  import ArrowBackIcon from "@mui/icons-material/ArrowBack";
3830
4365
  import MoreVertIcon2 from "@mui/icons-material/MoreVert";
3831
- import { Alert as Alert6, Box as Box13, Button as Button5, IconButton as IconButton4, Menu as Menu2, MenuItem as MenuItem3, Paper as Paper9, Stack as Stack13, Typography as Typography7, useMediaQuery as useMediaQuery3 } from "@mui/material";
3832
- import { LocalizationProvider as LocalizationProvider2 } from "@mui/x-date-pickers";
3833
- import { AdapterDayjs as AdapterDayjs2 } from "@mui/x-date-pickers/AdapterDayjs";
4366
+ import { Alert as Alert7, Box as Box14, Button as Button6, IconButton as IconButton4, Menu as Menu2, MenuItem as MenuItem4, Paper as Paper9, Stack as Stack13, Typography as Typography7, useMediaQuery as useMediaQuery3 } from "@mui/material";
4367
+ import { LocalizationProvider as LocalizationProvider3 } from "@mui/x-date-pickers";
4368
+ import { AdapterDayjs as AdapterDayjs3 } from "@mui/x-date-pickers/AdapterDayjs";
3834
4369
  import { useTheme as useTheme4 } from "@mui/material/styles";
3835
4370
  import "dayjs/locale/en.js";
3836
4371
  import "dayjs/locale/ru.js";
3837
4372
 
3838
4373
  // src/components/object-page/ObjectField.tsx
3839
4374
  import { memo as memo6, useCallback as useCallback6 } from "react";
3840
- import { jsx as jsx21 } from "react/jsx-runtime";
4375
+ import { jsx as jsx22 } from "react/jsx-runtime";
3841
4376
  var ObjectField = memo6(function ObjectField2({
3842
4377
  field,
3843
4378
  value,
@@ -3848,7 +4383,7 @@ var ObjectField = memo6(function ObjectField2({
3848
4383
  const handleChange = useCallback6((nextValue) => {
3849
4384
  onFieldChange(field.name, nextValue);
3850
4385
  }, [field.name, onFieldChange]);
3851
- return /* @__PURE__ */ jsx21(
4386
+ return /* @__PURE__ */ jsx22(
3852
4387
  FieldEditor,
3853
4388
  {
3854
4389
  field,
@@ -3861,20 +4396,20 @@ var ObjectField = memo6(function ObjectField2({
3861
4396
  });
3862
4397
 
3863
4398
  // src/components/object-page/ObjectPageSkeleton.tsx
3864
- import { Box as Box11, Paper as Paper8, Skeleton as Skeleton4, Stack as Stack11 } from "@mui/material";
3865
- import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
4399
+ import { Box as Box12, Paper as Paper8, Skeleton as Skeleton4, Stack as Stack11 } from "@mui/material";
4400
+ import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
3866
4401
  function ObjectPageSkeleton() {
3867
- return /* @__PURE__ */ jsxs14(Stack11, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
3868
- /* @__PURE__ */ jsx22(MainHeaderSkeleton, { titleWidth: 420, subtitleWidth: "32%" }),
3869
- /* @__PURE__ */ jsxs14(
4402
+ return /* @__PURE__ */ jsxs15(Stack11, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
4403
+ /* @__PURE__ */ jsx23(MainHeaderSkeleton, { titleWidth: 420, subtitleWidth: "32%" }),
4404
+ /* @__PURE__ */ jsxs15(
3870
4405
  Stack11,
3871
4406
  {
3872
4407
  direction: { xs: "column", lg: "row" },
3873
4408
  spacing: 1.5,
3874
4409
  sx: { flex: 1, minHeight: 0, alignItems: "stretch" },
3875
4410
  children: [
3876
- /* @__PURE__ */ jsx22(Paper8, { sx: { borderRadius: "10px", flex: 1, minHeight: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx22(Box11, { sx: { height: "100%", overflow: "auto", p: 2.5 }, children: /* @__PURE__ */ jsx22(Stack11, { spacing: 1.5, children: Array.from({ length: 9 }).map((_, index) => /* @__PURE__ */ jsx22(Skeleton4, { variant: "rounded", width: "100%", height: 56 }, index)) }) }) }),
3877
- /* @__PURE__ */ jsx22(
4411
+ /* @__PURE__ */ jsx23(Paper8, { sx: { borderRadius: "10px", flex: 1, minHeight: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx23(Box12, { sx: { height: "100%", overflow: "auto", p: 2.5 }, children: /* @__PURE__ */ jsx23(Stack11, { spacing: 1.5, children: Array.from({ length: 9 }).map((_, index) => /* @__PURE__ */ jsx23(Skeleton4, { variant: "rounded", width: "100%", height: 56 }, index)) }) }) }),
4412
+ /* @__PURE__ */ jsx23(
3878
4413
  Paper8,
3879
4414
  {
3880
4415
  sx: {
@@ -3884,10 +4419,10 @@ function ObjectPageSkeleton() {
3884
4419
  p: 1.5,
3885
4420
  alignSelf: "flex-start"
3886
4421
  },
3887
- children: /* @__PURE__ */ jsxs14(Stack11, { spacing: 1, children: [
3888
- /* @__PURE__ */ jsx22(Skeleton4, { variant: "text", width: 90, height: 28 }),
3889
- /* @__PURE__ */ jsx22(Skeleton4, { variant: "rounded", width: "100%", height: 40 }),
3890
- /* @__PURE__ */ jsx22(Skeleton4, { variant: "rounded", width: "100%", height: 40 })
4422
+ children: /* @__PURE__ */ jsxs15(Stack11, { spacing: 1, children: [
4423
+ /* @__PURE__ */ jsx23(Skeleton4, { variant: "text", width: 90, height: 28 }),
4424
+ /* @__PURE__ */ jsx23(Skeleton4, { variant: "rounded", width: "100%", height: 40 }),
4425
+ /* @__PURE__ */ jsx23(Skeleton4, { variant: "rounded", width: "100%", height: 40 })
3891
4426
  ] })
3892
4427
  }
3893
4428
  )
@@ -3899,8 +4434,8 @@ function ObjectPageSkeleton() {
3899
4434
 
3900
4435
  // src/components/object-page/ReadonlyObjectField.tsx
3901
4436
  import { memo as memo7 } from "react";
3902
- import { Box as Box12, Stack as Stack12, TextField as TextField4 } from "@mui/material";
3903
- import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
4437
+ import { Box as Box13, Stack as Stack12, TextField as TextField4 } from "@mui/material";
4438
+ import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
3904
4439
  var ReadonlyObjectField = memo7(function ReadonlyObjectField2({
3905
4440
  field,
3906
4441
  value,
@@ -3908,9 +4443,9 @@ var ReadonlyObjectField = memo7(function ReadonlyObjectField2({
3908
4443
  }) {
3909
4444
  var _a;
3910
4445
  const isMultiline = field.input_kind === "textarea" || field.input_kind === "json" || field.type.toLowerCase().includes("text") || value.includes("\n") || value.length > 120;
3911
- return /* @__PURE__ */ jsxs15(Stack12, { spacing: 1, children: [
3912
- imageUrl ? /* @__PURE__ */ jsx23(
3913
- Box12,
4446
+ return /* @__PURE__ */ jsxs16(Stack12, { spacing: 1, children: [
4447
+ imageUrl ? /* @__PURE__ */ jsx24(
4448
+ Box13,
3914
4449
  {
3915
4450
  component: "img",
3916
4451
  src: imageUrl,
@@ -3926,7 +4461,7 @@ var ReadonlyObjectField = memo7(function ReadonlyObjectField2({
3926
4461
  }
3927
4462
  }
3928
4463
  ) : null,
3929
- /* @__PURE__ */ jsx23(
4464
+ /* @__PURE__ */ jsx24(
3930
4465
  TextField4,
3931
4466
  {
3932
4467
  label: field.label,
@@ -3943,7 +4478,7 @@ var ReadonlyObjectField = memo7(function ReadonlyObjectField2({
3943
4478
  });
3944
4479
 
3945
4480
  // src/components/object-page/useObjectPageController.ts
3946
- import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo10, useState as useState11 } from "react";
4481
+ import { useCallback as useCallback7, useLayoutEffect as useLayoutEffect4, useMemo as useMemo10, useState as useState12 } from "react";
3947
4482
 
3948
4483
  // src/utils/isDeepEqual.ts
3949
4484
  function isDeepEqual(left, right) {
@@ -3985,29 +4520,30 @@ function useObjectPageController({
3985
4520
  var _a, _b, _c;
3986
4521
  const message = useAdminMessage();
3987
4522
  const cacheKey = buildDetailCacheKey(slug, id);
3988
- const [data, setData] = useState11(() => {
4523
+ const [data, setData] = useState12(() => {
3989
4524
  var _a2;
3990
4525
  return (_a2 = getClientCacheBucket(client).detailResponseCache.get(cacheKey)) != null ? _a2 : null;
3991
4526
  });
3992
- const [values, setValues] = useState11(() => {
4527
+ const [values, setValues] = useState12(() => {
3993
4528
  var _a2, _b2;
3994
4529
  return (_b2 = (_a2 = getClientCacheBucket(client).detailResponseCache.get(cacheKey)) == null ? void 0 : _a2.item) != null ? _b2 : {};
3995
4530
  });
3996
- const [initialValues, setInitialValues] = useState11(() => {
4531
+ const [initialValues, setInitialValues] = useState12(() => {
3997
4532
  var _a2, _b2;
3998
4533
  return (_b2 = (_a2 = getClientCacheBucket(client).detailResponseCache.get(cacheKey)) == null ? void 0 : _a2.item) != null ? _b2 : {};
3999
4534
  });
4000
- const [error, setError] = useState11(null);
4001
- const [isLoading, setIsLoading] = useState11(data === null);
4002
- const [isSaving, setIsSaving] = useState11(false);
4003
- const [isDeleting, setIsDeleting] = useState11(false);
4004
- const [activeActionSlug, setActiveActionSlug] = useState11(null);
4005
- const [deleteConfirmOpen, setDeleteConfirmOpen] = useState11(false);
4006
- const [deletePreview, setDeletePreview] = useState11(null);
4007
- const [isDeletePreviewLoading, setIsDeletePreviewLoading] = useState11(false);
4008
- const [deletePreviewError, setDeletePreviewError] = useState11(null);
4009
- const [actionsAnchorEl, setActionsAnchorEl] = useState11(null);
4010
- useEffect11(() => {
4535
+ const [error, setError] = useState12(null);
4536
+ const [isLoading, setIsLoading] = useState12(data === null);
4537
+ const [isSaving, setIsSaving] = useState12(false);
4538
+ const [isDeleting, setIsDeleting] = useState12(false);
4539
+ const [activeActionSlug, setActiveActionSlug] = useState12(null);
4540
+ const [deleteConfirmOpen, setDeleteConfirmOpen] = useState12(false);
4541
+ const [deletePreview, setDeletePreview] = useState12(null);
4542
+ const [isDeletePreviewLoading, setIsDeletePreviewLoading] = useState12(false);
4543
+ const [deletePreviewError, setDeletePreviewError] = useState12(null);
4544
+ const [actionsAnchorEl, setActionsAnchorEl] = useState12(null);
4545
+ const [objectActionFormSlug, setObjectActionFormSlug] = useState12(null);
4546
+ useLayoutEffect4(() => {
4011
4547
  var _a2;
4012
4548
  let isMounted = true;
4013
4549
  const bucket = getClientCacheBucket(client);
@@ -4077,6 +4613,13 @@ function useObjectPageController({
4077
4613
  [data, id, meta]
4078
4614
  );
4079
4615
  const isActionsMenuOpen = actionsAnchorEl !== null;
4616
+ const activeObjectAction = useMemo10(
4617
+ () => {
4618
+ var _a2;
4619
+ return (_a2 = objectActions.find((item) => item.slug === objectActionFormSlug)) != null ? _a2 : null;
4620
+ },
4621
+ [objectActionFormSlug, objectActions]
4622
+ );
4080
4623
  const currentPayload = useMemo10(
4081
4624
  () => buildAdminPayload(values, editableFields),
4082
4625
  [editableFields, values]
@@ -4140,7 +4683,13 @@ function useObjectPageController({
4140
4683
  router.push(listPath);
4141
4684
  }, [listPath, router]);
4142
4685
  const handleRunObjectAction = useCallback7(async (actionSlug) => {
4143
- var _a2, _b2;
4686
+ var _a2, _b2, _c2, _d;
4687
+ const action = objectActions.find((item) => item.slug === actionSlug);
4688
+ if (((_b2 = (_a2 = action == null ? void 0 : action.form) == null ? void 0 : _a2.length) != null ? _b2 : 0) > 0) {
4689
+ setActionsAnchorEl(null);
4690
+ setObjectActionFormSlug(actionSlug);
4691
+ return;
4692
+ }
4144
4693
  setActiveActionSlug(actionSlug);
4145
4694
  setError(null);
4146
4695
  try {
@@ -4153,7 +4702,7 @@ function useObjectPageController({
4153
4702
  setData(nextDetail);
4154
4703
  setValues(response.item);
4155
4704
  setInitialValues(response.item);
4156
- const actionLabel = (_b2 = (_a2 = objectActions.find((item) => item.slug === actionSlug)) == null ? void 0 : _a2.label) != null ? _b2 : actionSlug;
4705
+ const actionLabel = (_d = (_c2 = objectActions.find((item) => item.slug === actionSlug)) == null ? void 0 : _c2.label) != null ? _d : actionSlug;
4157
4706
  message.success(t("action_success", { action: actionLabel, count: 1 }));
4158
4707
  } catch (reason) {
4159
4708
  const nextError = reason instanceof Error ? reason.message : t("object_action_error");
@@ -4163,6 +4712,33 @@ function useObjectPageController({
4163
4712
  setActiveActionSlug(null);
4164
4713
  }
4165
4714
  }, [cacheKey, client, data, id, message, objectActions, slug, t]);
4715
+ const handleSubmitObjectActionForm = useCallback7(async (payload) => {
4716
+ var _a2, _b2;
4717
+ if (!objectActionFormSlug) {
4718
+ return;
4719
+ }
4720
+ setActiveActionSlug(objectActionFormSlug);
4721
+ setError(null);
4722
+ try {
4723
+ const response = await client.runObjectAction(slug, id, objectActionFormSlug, payload);
4724
+ const nextDetail = data ? { ...data, item: response.item } : null;
4725
+ if (nextDetail) {
4726
+ invalidateModelCache(client, slug);
4727
+ setCachedDetailResponse(client, cacheKey, nextDetail);
4728
+ }
4729
+ setData(nextDetail);
4730
+ setValues(response.item);
4731
+ setInitialValues(response.item);
4732
+ const actionLabel = (_b2 = (_a2 = objectActions.find((item) => item.slug === objectActionFormSlug)) == null ? void 0 : _a2.label) != null ? _b2 : objectActionFormSlug;
4733
+ message.success(t("action_success", { action: actionLabel, count: 1 }));
4734
+ setObjectActionFormSlug(null);
4735
+ } finally {
4736
+ setActiveActionSlug(null);
4737
+ }
4738
+ }, [cacheKey, client, data, id, message, objectActionFormSlug, objectActions, slug, t]);
4739
+ const handleCloseObjectActionForm = useCallback7(() => {
4740
+ setObjectActionFormSlug(null);
4741
+ }, []);
4166
4742
  const handleOpenDeletePreview = useCallback7(async () => {
4167
4743
  setActionsAnchorEl(null);
4168
4744
  setDeleteConfirmOpen(true);
@@ -4181,6 +4757,7 @@ function useObjectPageController({
4181
4757
  return {
4182
4758
  actionsAnchorEl,
4183
4759
  activeActionSlug,
4760
+ activeObjectAction,
4184
4761
  data,
4185
4762
  deleteConfirmOpen,
4186
4763
  deletePreview,
@@ -4195,6 +4772,8 @@ function useObjectPageController({
4195
4772
  handleOpenDeletePreview,
4196
4773
  handleRunObjectAction,
4197
4774
  handleSave,
4775
+ handleCloseObjectActionForm,
4776
+ handleSubmitObjectActionForm,
4198
4777
  initialValues,
4199
4778
  isActionsMenuOpen,
4200
4779
  isDeletePreviewLoading,
@@ -4214,9 +4793,9 @@ function useObjectPageController({
4214
4793
  }
4215
4794
 
4216
4795
  // src/components/ObjectPage.tsx
4217
- import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
4796
+ import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
4218
4797
  function ObjectPage({ client, slug, id, router }) {
4219
- var _a, _b;
4798
+ var _a, _b, _c;
4220
4799
  const locale = useAdminLocale();
4221
4800
  const t = useAdminTranslation();
4222
4801
  const resolvedRouter = useAdminRouter(router);
@@ -4224,6 +4803,7 @@ function ObjectPage({ client, slug, id, router }) {
4224
4803
  const pathname = location.pathname;
4225
4804
  const theme = useTheme4();
4226
4805
  const isPhone = useMediaQuery3(theme.breakpoints.down("sm"));
4806
+ const { pendingPath, finishPendingNavigation } = useShellContext();
4227
4807
  const listPath = pathname.split("/").slice(0, -1).join("/");
4228
4808
  const controller = useObjectPageController({
4229
4809
  client,
@@ -4233,225 +4813,268 @@ function ObjectPage({ client, slug, id, router }) {
4233
4813
  router: resolvedRouter,
4234
4814
  t
4235
4815
  });
4816
+ useLayoutEffect5(() => {
4817
+ if (pendingPath === null) {
4818
+ return;
4819
+ }
4820
+ if (controller.isLoading) {
4821
+ return;
4822
+ }
4823
+ if (!controller.meta && !controller.error) {
4824
+ return;
4825
+ }
4826
+ if (controller.meta && controller.meta.slug !== slug) {
4827
+ return;
4828
+ }
4829
+ finishPendingNavigation(pathname);
4830
+ }, [controller.error, controller.isLoading, controller.meta, finishPendingNavigation, pathname, pendingPath, slug]);
4236
4831
  useAdminDocumentTitle(t("admin_title"), (_b = (_a = controller.meta) == null ? void 0 : _a.title) != null ? _b : slug, controller.objectTitle);
4237
4832
  if (controller.isLoading && !controller.data) {
4238
- return /* @__PURE__ */ jsx24(ObjectPageSkeleton, {});
4833
+ return /* @__PURE__ */ jsx25(ObjectPageSkeleton, {});
4239
4834
  }
4240
4835
  if (controller.error && !controller.data) {
4241
- return /* @__PURE__ */ jsx24(Alert6, { severity: "error", children: controller.error });
4836
+ return /* @__PURE__ */ jsx25(Alert7, { severity: "error", children: controller.error });
4242
4837
  }
4243
4838
  if (!controller.data || !controller.meta) {
4244
- return /* @__PURE__ */ jsx24(ObjectPageSkeleton, {});
4839
+ return /* @__PURE__ */ jsx25(ObjectPageSkeleton, {});
4245
4840
  }
4246
- return /* @__PURE__ */ jsx24(AdminRouterProvider, { router: resolvedRouter, children: /* @__PURE__ */ jsxs16(LocalizationProvider2, { dateAdapter: AdapterDayjs2, adapterLocale: locale, children: [
4247
- /* @__PURE__ */ jsxs16(Stack13, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
4248
- /* @__PURE__ */ jsx24(
4249
- MainHeader,
4250
- {
4251
- title: controller.objectTitle,
4252
- subtitle: controller.meta.slug,
4253
- beforeSubtitle: /* @__PURE__ */ jsx24(
4254
- IconButton4,
4841
+ return /* @__PURE__ */ jsx25(AdminRouterProvider, { router: resolvedRouter, children: /* @__PURE__ */ jsxs17(
4842
+ LocalizationProvider3,
4843
+ {
4844
+ dateAdapter: AdapterDayjs3,
4845
+ adapterLocale: locale,
4846
+ localeText: getMuiPickersLocaleText(locale),
4847
+ children: [
4848
+ /* @__PURE__ */ jsxs17(Stack13, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
4849
+ /* @__PURE__ */ jsx25(
4850
+ MainHeader,
4255
4851
  {
4256
- "aria-label": t("back"),
4257
- onClick: controller.handleNavigateBack,
4258
- size: "small",
4259
- sx: { ml: -0.5 },
4260
- children: /* @__PURE__ */ jsx24(ArrowBackIcon, { fontSize: "small" })
4852
+ title: controller.objectTitle,
4853
+ subtitle: controller.meta.slug,
4854
+ beforeSubtitle: /* @__PURE__ */ jsx25(
4855
+ IconButton4,
4856
+ {
4857
+ "aria-label": t("back"),
4858
+ onClick: controller.handleNavigateBack,
4859
+ size: "small",
4860
+ sx: { ml: -0.5 },
4861
+ children: /* @__PURE__ */ jsx25(ArrowBackIcon, { fontSize: "small" })
4862
+ }
4863
+ ),
4864
+ actions: isPhone ? /* @__PURE__ */ jsx25(
4865
+ IconButton4,
4866
+ {
4867
+ "aria-label": t("actions"),
4868
+ onClick: (event) => controller.setActionsAnchorEl(event.currentTarget),
4869
+ size: "small",
4870
+ sx: { mr: -0.5 },
4871
+ children: /* @__PURE__ */ jsx25(MoreVertIcon2, { fontSize: "small" })
4872
+ }
4873
+ ) : void 0,
4874
+ details: controller.meta.description ? /* @__PURE__ */ jsx25(Typography7, { color: "text.secondary", sx: { fontSize: 14, lineHeight: 1.45 }, children: controller.meta.description }) : void 0,
4875
+ error: controller.error
4261
4876
  }
4262
4877
  ),
4263
- actions: isPhone ? /* @__PURE__ */ jsx24(
4264
- IconButton4,
4878
+ /* @__PURE__ */ jsxs17(
4879
+ Stack13,
4265
4880
  {
4266
- "aria-label": t("actions"),
4267
- onClick: (event) => controller.setActionsAnchorEl(event.currentTarget),
4268
- size: "small",
4269
- sx: { mr: -0.5 },
4270
- children: /* @__PURE__ */ jsx24(MoreVertIcon2, { fontSize: "small" })
4271
- }
4272
- ) : void 0,
4273
- details: controller.meta.description ? /* @__PURE__ */ jsx24(Typography7, { color: "text.secondary", sx: { fontSize: 14, lineHeight: 1.45 }, children: controller.meta.description }) : void 0,
4274
- error: controller.error
4275
- }
4276
- ),
4277
- /* @__PURE__ */ jsxs16(
4278
- Stack13,
4279
- {
4280
- direction: { xs: "column", lg: "row" },
4281
- spacing: 1.5,
4282
- sx: { flex: 1, minHeight: 0, alignItems: "stretch" },
4283
- children: [
4284
- /* @__PURE__ */ jsx24(
4285
- Paper9,
4286
- {
4287
- sx: {
4288
- borderRadius: "10px",
4289
- flex: 1,
4290
- minHeight: 0,
4291
- overflow: "hidden"
4292
- },
4293
- children: /* @__PURE__ */ jsx24(Box13, { component: "form", autoComplete: "off", sx: { height: "100%", overflow: "auto", p: 2.5 }, children: /* @__PURE__ */ jsx24(Stack13, { spacing: 1.5, children: controller.detailFields.map((fieldName) => {
4294
- const field = controller.fieldMap.get(fieldName);
4295
- if (!field) {
4296
- return null;
4297
- }
4298
- if (controller.editableFieldNames.has(fieldName)) {
4299
- return /* @__PURE__ */ jsx24(
4300
- ObjectField,
4301
- {
4302
- field,
4303
- value: controller.values[field.name],
4304
- slug,
4305
- client,
4306
- onFieldChange: controller.handleFieldChange
4307
- },
4308
- field.name
4309
- );
4881
+ direction: { xs: "column", lg: "row" },
4882
+ spacing: 1.5,
4883
+ sx: { flex: 1, minHeight: 0, alignItems: "stretch" },
4884
+ children: [
4885
+ /* @__PURE__ */ jsx25(
4886
+ Paper9,
4887
+ {
4888
+ sx: {
4889
+ borderRadius: "10px",
4890
+ flex: 1,
4891
+ minHeight: 0,
4892
+ overflow: "hidden"
4893
+ },
4894
+ children: /* @__PURE__ */ jsx25(Box14, { component: "form", autoComplete: "off", sx: { height: "100%", overflow: "auto", p: 2.5 }, children: /* @__PURE__ */ jsx25(Stack13, { spacing: 1.5, children: controller.detailFields.map((fieldName) => {
4895
+ const field = controller.fieldMap.get(fieldName);
4896
+ if (!field) {
4897
+ return null;
4898
+ }
4899
+ if (controller.editableFieldNames.has(fieldName)) {
4900
+ return /* @__PURE__ */ jsx25(
4901
+ ObjectField,
4902
+ {
4903
+ field,
4904
+ value: controller.values[field.name],
4905
+ slug,
4906
+ client,
4907
+ onFieldChange: controller.handleFieldChange
4908
+ },
4909
+ field.name
4910
+ );
4911
+ }
4912
+ return /* @__PURE__ */ jsx25(
4913
+ ReadonlyObjectField,
4914
+ {
4915
+ field,
4916
+ value: formatAdminValue(controller.values[field.name], {
4917
+ locale,
4918
+ field,
4919
+ pretty: true
4920
+ }),
4921
+ imageUrl: field.display_kind === "image" ? resolveAdminMediaUrl(controller.values[field.name], field) : null
4922
+ },
4923
+ field.name
4924
+ );
4925
+ }) }) })
4310
4926
  }
4311
- return /* @__PURE__ */ jsx24(
4312
- ReadonlyObjectField,
4313
- {
4314
- field,
4315
- value: formatAdminValue(controller.values[field.name], {
4316
- locale,
4317
- field,
4318
- pretty: true
4319
- }),
4320
- imageUrl: field.display_kind === "image" ? resolveAdminMediaUrl(controller.values[field.name], field) : null
4927
+ ),
4928
+ /* @__PURE__ */ jsx25(
4929
+ Paper9,
4930
+ {
4931
+ sx: {
4932
+ width: { xs: "100%", lg: 280 },
4933
+ flexShrink: 0,
4934
+ borderRadius: "10px",
4935
+ p: 1.5,
4936
+ alignSelf: "flex-start",
4937
+ position: { lg: "sticky" },
4938
+ top: { lg: 0 },
4939
+ display: isPhone ? "none" : void 0
4321
4940
  },
4322
- field.name
4323
- );
4324
- }) }) })
4325
- }
4326
- ),
4327
- /* @__PURE__ */ jsx24(
4328
- Paper9,
4329
- {
4941
+ children: /* @__PURE__ */ jsxs17(Stack13, { spacing: 1, children: [
4942
+ /* @__PURE__ */ jsx25(Typography7, { variant: "subtitle2", color: "text.secondary", children: t("actions") }),
4943
+ controller.isDirty ? /* @__PURE__ */ jsx25(
4944
+ Button6,
4945
+ {
4946
+ variant: "contained",
4947
+ onClick: () => void controller.handleSave(),
4948
+ disabled: controller.isSaving,
4949
+ children: controller.isSaving ? t("saving") : t("save")
4950
+ }
4951
+ ) : null,
4952
+ /* @__PURE__ */ jsx25(
4953
+ Button6,
4954
+ {
4955
+ variant: "outlined",
4956
+ color: "error",
4957
+ onClick: () => void controller.handleOpenDeletePreview(),
4958
+ disabled: controller.isDeleting,
4959
+ children: t("delete")
4960
+ }
4961
+ ),
4962
+ controller.objectActions.map((action) => /* @__PURE__ */ jsx25(
4963
+ Button6,
4964
+ {
4965
+ variant: "outlined",
4966
+ onClick: () => void controller.handleRunObjectAction(action.slug),
4967
+ disabled: controller.activeActionSlug !== null,
4968
+ children: controller.activeActionSlug === action.slug ? t("executing") : action.label
4969
+ },
4970
+ action.slug
4971
+ ))
4972
+ ] })
4973
+ }
4974
+ )
4975
+ ]
4976
+ }
4977
+ )
4978
+ ] }),
4979
+ /* @__PURE__ */ jsxs17(
4980
+ Menu2,
4981
+ {
4982
+ anchorEl: controller.actionsAnchorEl,
4983
+ open: controller.isActionsMenuOpen,
4984
+ onClose: () => controller.setActionsAnchorEl(null),
4985
+ slotProps: {
4986
+ paper: {
4330
4987
  sx: {
4331
- width: { xs: "100%", lg: 280 },
4332
- flexShrink: 0,
4333
- borderRadius: "10px",
4334
- p: 1.5,
4335
- alignSelf: "flex-start",
4336
- position: { lg: "sticky" },
4337
- top: { lg: 0 },
4338
- display: isPhone ? "none" : void 0
4988
+ minWidth: 220
4989
+ }
4990
+ }
4991
+ },
4992
+ anchorOrigin: { vertical: "bottom", horizontal: "right" },
4993
+ transformOrigin: { vertical: "top", horizontal: "right" },
4994
+ children: [
4995
+ controller.isDirty ? /* @__PURE__ */ jsx25(
4996
+ MenuItem4,
4997
+ {
4998
+ onClick: () => {
4999
+ controller.setActionsAnchorEl(null);
5000
+ void controller.handleSave();
5001
+ },
5002
+ disabled: controller.isSaving,
5003
+ children: controller.isSaving ? t("saving") : t("save")
5004
+ }
5005
+ ) : null,
5006
+ /* @__PURE__ */ jsx25(
5007
+ MenuItem4,
5008
+ {
5009
+ onClick: () => void controller.handleOpenDeletePreview(),
5010
+ disabled: controller.isDeleting,
5011
+ sx: { color: "error.main" },
5012
+ children: t("delete")
5013
+ }
5014
+ ),
5015
+ controller.objectActions.map((action) => /* @__PURE__ */ jsx25(
5016
+ MenuItem4,
5017
+ {
5018
+ onClick: () => {
5019
+ controller.setActionsAnchorEl(null);
5020
+ void controller.handleRunObjectAction(action.slug);
5021
+ },
5022
+ disabled: controller.activeActionSlug !== null,
5023
+ children: controller.activeActionSlug === action.slug ? t("executing") : action.label
4339
5024
  },
4340
- children: /* @__PURE__ */ jsxs16(Stack13, { spacing: 1, children: [
4341
- /* @__PURE__ */ jsx24(Typography7, { variant: "subtitle2", color: "text.secondary", children: t("actions") }),
4342
- controller.isDirty ? /* @__PURE__ */ jsx24(
4343
- Button5,
4344
- {
4345
- variant: "contained",
4346
- onClick: () => void controller.handleSave(),
4347
- disabled: controller.isSaving,
4348
- children: controller.isSaving ? t("saving") : t("save")
4349
- }
4350
- ) : null,
4351
- /* @__PURE__ */ jsx24(
4352
- Button5,
4353
- {
4354
- variant: "outlined",
4355
- color: "error",
4356
- onClick: () => void controller.handleOpenDeletePreview(),
4357
- disabled: controller.isDeleting,
4358
- children: t("delete")
4359
- }
4360
- ),
4361
- controller.objectActions.map((action) => /* @__PURE__ */ jsx24(
4362
- Button5,
4363
- {
4364
- variant: "outlined",
4365
- onClick: () => void controller.handleRunObjectAction(action.slug),
4366
- disabled: controller.activeActionSlug !== null,
4367
- children: controller.activeActionSlug === action.slug ? t("executing") : action.label
4368
- },
4369
- action.slug
4370
- ))
4371
- ] })
5025
+ action.slug
5026
+ ))
5027
+ ]
5028
+ }
5029
+ ),
5030
+ /* @__PURE__ */ jsx25(
5031
+ DeletePreviewDialog,
5032
+ {
5033
+ open: controller.deleteConfirmOpen,
5034
+ title: t("delete_object_title"),
5035
+ preview: controller.deletePreview,
5036
+ error: controller.deletePreviewError,
5037
+ isLoading: controller.isDeletePreviewLoading,
5038
+ isSubmitting: controller.isDeleting,
5039
+ onClose: () => {
5040
+ if (controller.isDeleting) {
5041
+ return;
4372
5042
  }
4373
- )
4374
- ]
4375
- }
4376
- )
4377
- ] }),
4378
- /* @__PURE__ */ jsxs16(
4379
- Menu2,
4380
- {
4381
- anchorEl: controller.actionsAnchorEl,
4382
- open: controller.isActionsMenuOpen,
4383
- onClose: () => controller.setActionsAnchorEl(null),
4384
- slotProps: {
4385
- paper: {
4386
- sx: {
4387
- minWidth: 220
4388
- }
5043
+ controller.setDeleteConfirmOpen(false);
5044
+ controller.setDeletePreview(null);
5045
+ controller.setDeletePreviewError(null);
5046
+ },
5047
+ onConfirm: () => void controller.handleDelete()
4389
5048
  }
4390
- },
4391
- anchorOrigin: { vertical: "bottom", horizontal: "right" },
4392
- transformOrigin: { vertical: "top", horizontal: "right" },
4393
- children: [
4394
- controller.isDirty ? /* @__PURE__ */ jsx24(
4395
- MenuItem3,
4396
- {
4397
- onClick: () => {
4398
- controller.setActionsAnchorEl(null);
4399
- void controller.handleSave();
4400
- },
4401
- disabled: controller.isSaving,
4402
- children: controller.isSaving ? t("saving") : t("save")
4403
- }
4404
- ) : null,
4405
- /* @__PURE__ */ jsx24(
4406
- MenuItem3,
4407
- {
4408
- onClick: () => void controller.handleOpenDeletePreview(),
4409
- disabled: controller.isDeleting,
4410
- sx: { color: "error.main" },
4411
- children: t("delete")
4412
- }
4413
- ),
4414
- controller.objectActions.map((action) => /* @__PURE__ */ jsx24(
4415
- MenuItem3,
4416
- {
4417
- onClick: () => {
4418
- controller.setActionsAnchorEl(null);
4419
- void controller.handleRunObjectAction(action.slug);
4420
- },
4421
- disabled: controller.activeActionSlug !== null,
4422
- children: controller.activeActionSlug === action.slug ? t("executing") : action.label
5049
+ ),
5050
+ ((_c = controller.activeObjectAction) == null ? void 0 : _c.form) ? /* @__PURE__ */ jsx25(
5051
+ ActionFormDialog,
5052
+ {
5053
+ open: true,
5054
+ onClose: controller.handleCloseObjectActionForm,
5055
+ onSuccess: () => void 0,
5056
+ title: `${controller.activeObjectAction.label}: ${controller.objectTitle}`,
5057
+ submitLabel: controller.activeObjectAction.label,
5058
+ slug,
5059
+ locale,
5060
+ fields: controller.activeObjectAction.form,
5061
+ client,
5062
+ choiceScope: {
5063
+ kind: "object-action",
5064
+ actionSlug: controller.activeObjectAction.slug,
5065
+ itemId: id
4423
5066
  },
4424
- action.slug
4425
- ))
4426
- ]
4427
- }
4428
- ),
4429
- /* @__PURE__ */ jsx24(
4430
- DeletePreviewDialog,
4431
- {
4432
- open: controller.deleteConfirmOpen,
4433
- title: t("delete_object_title"),
4434
- preview: controller.deletePreview,
4435
- error: controller.deletePreviewError,
4436
- isLoading: controller.isDeletePreviewLoading,
4437
- isSubmitting: controller.isDeleting,
4438
- onClose: () => {
4439
- if (controller.isDeleting) {
4440
- return;
5067
+ onSubmit: controller.handleSubmitObjectActionForm
4441
5068
  }
4442
- controller.setDeleteConfirmOpen(false);
4443
- controller.setDeletePreview(null);
4444
- controller.setDeletePreviewError(null);
4445
- },
4446
- onConfirm: () => void controller.handleDelete()
4447
- }
4448
- )
4449
- ] }) });
5069
+ ) : null
5070
+ ]
5071
+ }
5072
+ ) });
4450
5073
  }
4451
5074
 
4452
5075
  // src/components/Shell.tsx
4453
- import { useEffect as useEffect12, useMemo as useMemo11, useState as useState12 } from "react";
4454
- import { Box as Box16, CssBaseline, Drawer, GlobalStyles, Stack as Stack14, useMediaQuery as useMediaQuery4 } from "@mui/material";
5076
+ import { useEffect as useEffect14, useMemo as useMemo11, useState as useState13 } from "react";
5077
+ import { Box as Box17, CssBaseline, Drawer, GlobalStyles, Stack as Stack14, useMediaQuery as useMediaQuery4 } from "@mui/material";
4455
5078
  import { ThemeProvider } from "@mui/material/styles";
4456
5079
 
4457
5080
  // src/theme/defaultAdminTheme.ts
@@ -4582,18 +5205,14 @@ var defaultAdminTheme = createTheme({
4582
5205
  });
4583
5206
 
4584
5207
  // src/components/layout/Main.tsx
4585
- import { Box as Box14 } from "@mui/material";
4586
- import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
5208
+ import { Box as Box15 } from "@mui/material";
5209
+ import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
4587
5210
  function Main({ children }) {
4588
- const { pathname } = useAdminLocation();
5211
+ useAdminLocation();
4589
5212
  const { pendingPath, pendingView } = useShellContext();
4590
- const normalizeAdminPath2 = (path) => {
4591
- const normalizedPath = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
4592
- return normalizedPath.replace(/^\/(ru|en)(?=\/|$)/, "") || "/";
4593
- };
4594
- const isPendingNavigation = pendingPath !== null && normalizeAdminPath2(pathname) !== normalizeAdminPath2(pendingPath);
4595
- return /* @__PURE__ */ jsxs17(
4596
- Box14,
5213
+ const isPendingNavigation = pendingPath !== null;
5214
+ return /* @__PURE__ */ jsxs18(
5215
+ Box15,
4597
5216
  {
4598
5217
  sx: {
4599
5218
  flex: 1,
@@ -4606,8 +5225,8 @@ function Main({ children }) {
4606
5225
  },
4607
5226
  children: [
4608
5227
  children,
4609
- isPendingNavigation ? /* @__PURE__ */ jsx25(
4610
- Box14,
5228
+ isPendingNavigation ? /* @__PURE__ */ jsx26(
5229
+ Box15,
4611
5230
  {
4612
5231
  sx: {
4613
5232
  position: "absolute",
@@ -4615,7 +5234,7 @@ function Main({ children }) {
4615
5234
  zIndex: 5,
4616
5235
  backgroundColor: "background.default"
4617
5236
  },
4618
- children: pendingView === "model" || pendingView === "overview" ? /* @__PURE__ */ jsx25(ModelPageSkeleton, {}) : /* @__PURE__ */ jsx25(ModelPageSkeleton, {})
5237
+ children: pendingView === "model" || pendingView === "overview" ? /* @__PURE__ */ jsx26(ModelPageSkeleton, {}) : /* @__PURE__ */ jsx26(ModelPageSkeleton, {})
4619
5238
  }
4620
5239
  ) : null
4621
5240
  ]
@@ -4624,14 +5243,24 @@ function Main({ children }) {
4624
5243
  }
4625
5244
 
4626
5245
  // src/components/layout/Sidebar.tsx
4627
- import { memo as memo8 } from "react";
4628
- import { Box as Box15, ListItemButton as ListItemButton3, Typography as Typography8 } from "@mui/material";
4629
- import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
5246
+ import { memo as memo8, useEffect as useEffect13, useRef as useRef7 } from "react";
5247
+ import { Box as Box16, ListItemButton as ListItemButton3, Typography as Typography8 } from "@mui/material";
5248
+ import { jsx as jsx27, jsxs as jsxs19 } from "react/jsx-runtime";
5249
+ function getOffsetTopWithinContainer(element, container) {
5250
+ let offsetTop = element.offsetTop;
5251
+ let currentParent = element.offsetParent;
5252
+ while (currentParent instanceof HTMLElement && currentParent !== container) {
5253
+ offsetTop += currentParent.offsetTop;
5254
+ currentParent = currentParent.offsetParent;
5255
+ }
5256
+ return offsetTop;
5257
+ }
4630
5258
  var Sidebar = memo8(function Sidebar2({ models, blocks, basePath }) {
4631
5259
  var _a;
4632
5260
  const t = useAdminTranslation();
4633
5261
  const { pathname } = useAdminLocation();
4634
5262
  const { pendingPath, startPendingNavigation } = useShellContext();
5263
+ const scrollContainerRef = useRef7(null);
4635
5264
  const effectivePathname = pendingPath != null ? pendingPath : pathname;
4636
5265
  const normalizedBasePath = basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
4637
5266
  const fallbackBasePath = normalizedBasePath.replace(/^\/(ru|en)(?=\/|$)/, "") || "/";
@@ -4639,9 +5268,80 @@ var Sidebar = memo8(function Sidebar2({ models, blocks, basePath }) {
4639
5268
  const relativePath = matchedBasePath ? effectivePathname.slice(matchedBasePath.length) : "";
4640
5269
  const activeModelSlug = (_a = relativePath.split("/").filter(Boolean)[0]) != null ? _a : null;
4641
5270
  const isOverviewActive = matchedBasePath !== null && (effectivePathname === matchedBasePath || effectivePathname === `${matchedBasePath}/`);
4642
- return /* @__PURE__ */ jsx26(Box15, { sx: { height: "100%", overflow: "hidden" }, children: /* @__PURE__ */ jsx26(
4643
- Box15,
5271
+ useEffect13(() => {
5272
+ if (!activeModelSlug) {
5273
+ return;
5274
+ }
5275
+ const container = scrollContainerRef.current;
5276
+ if (!container) {
5277
+ return;
5278
+ }
5279
+ let scheduledFrame = null;
5280
+ let cancelled = false;
5281
+ let startedAt = 0;
5282
+ let lastTargetScrollTop = null;
5283
+ let stableFrames = 0;
5284
+ const ensureActiveModelVisible = (timestamp) => {
5285
+ if (cancelled) {
5286
+ return;
5287
+ }
5288
+ if (startedAt === 0) {
5289
+ startedAt = timestamp;
5290
+ }
5291
+ const elapsed = timestamp - startedAt;
5292
+ const allowAllModelsFallback = elapsed >= 250;
5293
+ const blockContainer = container.querySelector(
5294
+ '[data-xladmin-active-block="true"][data-xladmin-block-origin="block"]'
5295
+ );
5296
+ const fallbackBlockContainer = container.querySelector(
5297
+ '[data-xladmin-active-block="true"][data-xladmin-block-origin="all-models"]'
5298
+ );
5299
+ const blockItem = container.querySelector(
5300
+ '[data-xladmin-active-model="true"][data-xladmin-model-origin="block"]'
5301
+ );
5302
+ const fallbackItem = container.querySelector(
5303
+ '[data-xladmin-active-model="true"][data-xladmin-model-origin="all-models"]'
5304
+ );
5305
+ const activeBlock = blockContainer != null ? blockContainer : allowAllModelsFallback ? fallbackBlockContainer : null;
5306
+ const activeItem = blockItem != null ? blockItem : allowAllModelsFallback ? fallbackItem : null;
5307
+ if (!activeBlock || !activeItem) {
5308
+ if (elapsed < 1200) {
5309
+ scheduledFrame = window.requestAnimationFrame(ensureActiveModelVisible);
5310
+ }
5311
+ return;
5312
+ }
5313
+ const rangeTop = getOffsetTopWithinContainer(activeBlock, container);
5314
+ const rangeBottom = getOffsetTopWithinContainer(activeItem, container) + activeItem.offsetHeight;
5315
+ const rangeCenter = (rangeTop + rangeBottom) / 2;
5316
+ const maxScrollTop = Math.max(0, container.scrollHeight - container.clientHeight);
5317
+ const targetScrollTop = Math.min(
5318
+ maxScrollTop,
5319
+ Math.max(0, rangeCenter - container.clientHeight / 2)
5320
+ );
5321
+ container.scrollTop = targetScrollTop;
5322
+ if (lastTargetScrollTop !== null && Math.abs(lastTargetScrollTop - targetScrollTop) < 1) {
5323
+ stableFrames += 1;
5324
+ } else {
5325
+ stableFrames = 0;
5326
+ }
5327
+ lastTargetScrollTop = targetScrollTop;
5328
+ if (stableFrames >= 3 || elapsed >= 1200) {
5329
+ return;
5330
+ }
5331
+ scheduledFrame = window.requestAnimationFrame(ensureActiveModelVisible);
5332
+ };
5333
+ scheduledFrame = window.requestAnimationFrame(ensureActiveModelVisible);
5334
+ return () => {
5335
+ cancelled = true;
5336
+ if (scheduledFrame !== null) {
5337
+ window.cancelAnimationFrame(scheduledFrame);
5338
+ }
5339
+ };
5340
+ }, [activeModelSlug, blocks]);
5341
+ return /* @__PURE__ */ jsx27(Box16, { sx: { height: "100%", overflow: "hidden" }, children: /* @__PURE__ */ jsx27(
5342
+ Box16,
4644
5343
  {
5344
+ ref: scrollContainerRef,
4645
5345
  sx: {
4646
5346
  height: "100%",
4647
5347
  overflowY: "scroll",
@@ -4651,14 +5351,14 @@ var Sidebar = memo8(function Sidebar2({ models, blocks, basePath }) {
4651
5351
  ml: 0,
4652
5352
  pl: 0
4653
5353
  },
4654
- children: /* @__PURE__ */ jsxs18(Box15, { sx: { direction: "ltr", pl: 1 }, children: [
4655
- /* @__PURE__ */ jsx26(
5354
+ children: /* @__PURE__ */ jsxs19(Box16, { sx: { direction: "ltr", pl: 1 }, children: [
5355
+ /* @__PURE__ */ jsx27(
4656
5356
  NavLink,
4657
5357
  {
4658
5358
  href: basePath,
4659
5359
  style: { textDecoration: "none", display: "block" },
4660
5360
  onClick: () => startPendingNavigation(basePath, "overview"),
4661
- children: /* @__PURE__ */ jsx26(
5361
+ children: /* @__PURE__ */ jsx27(
4662
5362
  ListItemButton3,
4663
5363
  {
4664
5364
  selected: isOverviewActive,
@@ -4671,12 +5371,12 @@ var Sidebar = memo8(function Sidebar2({ models, blocks, basePath }) {
4671
5371
  backgroundColor: isOverviewActive ? "rgba(255, 255, 255, 0.2)" : "rgba(255, 255, 255, 0.055)"
4672
5372
  }
4673
5373
  },
4674
- children: /* @__PURE__ */ jsx26(Typography8, { variant: "subtitle1", sx: { fontWeight: 700 }, children: t("overview") })
5374
+ children: /* @__PURE__ */ jsx27(Typography8, { variant: "subtitle1", sx: { fontWeight: 700 }, children: t("overview") })
4675
5375
  }
4676
5376
  )
4677
5377
  }
4678
5378
  ),
4679
- /* @__PURE__ */ jsx26(
5379
+ /* @__PURE__ */ jsx27(
4680
5380
  ModelsBlocks,
4681
5381
  {
4682
5382
  models,
@@ -4693,7 +5393,7 @@ var Sidebar = memo8(function Sidebar2({ models, blocks, basePath }) {
4693
5393
  });
4694
5394
 
4695
5395
  // src/components/Shell.tsx
4696
- import { jsx as jsx27, jsxs as jsxs19 } from "react/jsx-runtime";
5396
+ import { jsx as jsx28, jsxs as jsxs20 } from "react/jsx-runtime";
4697
5397
  function normalizeAdminPath(path) {
4698
5398
  const normalizedPath = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
4699
5399
  return normalizedPath.replace(/^\/(ru|en)(?=\/|$)/, "") || "/";
@@ -4705,26 +5405,17 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4705
5405
  const location = useAdminLocation(resolvedRouter);
4706
5406
  const pathname = location.pathname;
4707
5407
  const isDesktopSidebar = useMediaQuery4(activeTheme.breakpoints.up("lg"));
4708
- const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState12(false);
4709
- const [pendingPath, setPendingPath] = useState12(null);
4710
- const [pendingView, setPendingView] = useState12(null);
4711
- useEffect12(() => {
5408
+ const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState13(false);
5409
+ const [pendingPath, setPendingPath] = useState13(null);
5410
+ const [pendingView, setPendingView] = useState13(null);
5411
+ useEffect14(() => {
4712
5412
  if (isDesktopSidebar) {
4713
5413
  setIsMobileSidebarOpen(false);
4714
5414
  }
4715
5415
  }, [isDesktopSidebar]);
4716
- useEffect12(() => {
5416
+ useEffect14(() => {
4717
5417
  setIsMobileSidebarOpen(false);
4718
5418
  }, [pathname]);
4719
- useEffect12(() => {
4720
- if (pendingPath === null) {
4721
- return;
4722
- }
4723
- if (normalizeAdminPath(pathname) === normalizeAdminPath(pendingPath)) {
4724
- setPendingPath(null);
4725
- setPendingView(null);
4726
- }
4727
- }, [pathname, pendingPath]);
4728
5419
  const shellContextValue = useMemo11(() => ({
4729
5420
  isMobile: !isDesktopSidebar,
4730
5421
  openMobileSidebar: () => setIsMobileSidebarOpen(true),
@@ -4736,11 +5427,21 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4736
5427
  }
4737
5428
  setPendingPath(path);
4738
5429
  setPendingView(view);
5430
+ },
5431
+ finishPendingNavigation: (path) => {
5432
+ if (pendingPath === null) {
5433
+ return;
5434
+ }
5435
+ if (path && normalizeAdminPath(path) !== normalizeAdminPath(pendingPath)) {
5436
+ return;
5437
+ }
5438
+ setPendingPath(null);
5439
+ setPendingView(null);
4739
5440
  }
4740
5441
  }), [isDesktopSidebar, pathname, pendingPath, pendingView]);
4741
- return /* @__PURE__ */ jsx27(AdminRouterProvider, { router: resolvedRouter, children: /* @__PURE__ */ jsx27(ThemeProvider, { theme: activeTheme, children: /* @__PURE__ */ jsx27(AdminLocaleProvider, { locale, children: /* @__PURE__ */ jsx27(AdminDataProvider, { value: { locale: locale === "en" ? "en" : "ru", models, blocks }, children: /* @__PURE__ */ jsx27(ShellContextProvider, { value: shellContextValue, children: /* @__PURE__ */ jsxs19(AdminMessageProvider, { children: [
4742
- /* @__PURE__ */ jsx27(CssBaseline, {}),
4743
- /* @__PURE__ */ jsx27(
5442
+ return /* @__PURE__ */ jsx28(AdminRouterProvider, { router: resolvedRouter, children: /* @__PURE__ */ jsx28(ThemeProvider, { theme: activeTheme, children: /* @__PURE__ */ jsx28(AdminLocaleProvider, { locale, children: /* @__PURE__ */ jsx28(AdminDataProvider, { value: { locale: locale === "en" ? "en" : "ru", models, blocks }, children: /* @__PURE__ */ jsx28(ShellContextProvider, { value: shellContextValue, children: /* @__PURE__ */ jsxs20(AdminMessageProvider, { children: [
5443
+ /* @__PURE__ */ jsx28(CssBaseline, {}),
5444
+ /* @__PURE__ */ jsx28(
4744
5445
  GlobalStyles,
4745
5446
  {
4746
5447
  styles: (muiTheme) => ({
@@ -4779,8 +5480,8 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4779
5480
  })
4780
5481
  }
4781
5482
  ),
4782
- /* @__PURE__ */ jsx27(
4783
- Box16,
5483
+ /* @__PURE__ */ jsx28(
5484
+ Box17,
4784
5485
  {
4785
5486
  "data-xladmin-root": "true",
4786
5487
  sx: {
@@ -4790,15 +5491,15 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4790
5491
  backgroundColor: "background.default",
4791
5492
  backgroundImage: "none"
4792
5493
  },
4793
- children: /* @__PURE__ */ jsxs19(
5494
+ children: /* @__PURE__ */ jsxs20(
4794
5495
  Stack14,
4795
5496
  {
4796
5497
  direction: { xs: "column", lg: "row" },
4797
5498
  spacing: 0,
4798
5499
  sx: { height: "100%", minHeight: 0, alignItems: "stretch" },
4799
5500
  children: [
4800
- /* @__PURE__ */ jsx27(
4801
- Box16,
5501
+ /* @__PURE__ */ jsx28(
5502
+ Box17,
4802
5503
  {
4803
5504
  sx: {
4804
5505
  display: { xs: "none", lg: "block" },
@@ -4809,11 +5510,11 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4809
5510
  pl: 0,
4810
5511
  pr: 1
4811
5512
  },
4812
- children: /* @__PURE__ */ jsx27(Sidebar, { models, blocks, basePath })
5513
+ children: /* @__PURE__ */ jsx28(Sidebar, { models, blocks, basePath })
4813
5514
  }
4814
5515
  ),
4815
- /* @__PURE__ */ jsx27(
4816
- Box16,
5516
+ /* @__PURE__ */ jsx28(
5517
+ Box17,
4817
5518
  {
4818
5519
  sx: {
4819
5520
  flex: 1,
@@ -4826,7 +5527,7 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4826
5527
  py: { xs: 1, sm: 1.5, lg: 2 },
4827
5528
  pl: { xs: 1, sm: 1.5, lg: 1 }
4828
5529
  },
4829
- children: /* @__PURE__ */ jsx27(Main, { children })
5530
+ children: /* @__PURE__ */ jsx28(Main, { children })
4830
5531
  }
4831
5532
  )
4832
5533
  ]
@@ -4834,7 +5535,7 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4834
5535
  )
4835
5536
  }
4836
5537
  ),
4837
- /* @__PURE__ */ jsx27(
5538
+ /* @__PURE__ */ jsx28(
4838
5539
  Drawer,
4839
5540
  {
4840
5541
  anchor: "left",
@@ -4853,7 +5554,7 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4853
5554
  }
4854
5555
  }
4855
5556
  },
4856
- children: /* @__PURE__ */ jsx27(Box16, { sx: { height: "100%", minHeight: 0, pr: 1.5 }, children: /* @__PURE__ */ jsx27(Sidebar, { models, blocks, basePath }) })
5557
+ children: /* @__PURE__ */ jsx28(Box17, { sx: { height: "100%", minHeight: 0, pr: 1.5 }, children: /* @__PURE__ */ jsx28(Sidebar, { models, blocks, basePath }) })
4857
5558
  }
4858
5559
  )
4859
5560
  ] }) }) }) }) }) });