xladmin 0.3.7 → 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, useLayoutEffect, 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
@@ -1624,6 +1910,7 @@ function DashboardModelsBlock({ block, basePath }) {
1624
1910
  }
1625
1911
 
1626
1912
  // src/components/models-blocks/SidebarModelsBlock.tsx
1913
+ import { useEffect as useEffect7 } from "react";
1627
1914
  import ExpandMoreIcon2 from "@mui/icons-material/ExpandMore";
1628
1915
  import {
1629
1916
  Accordion as Accordion2,
@@ -1638,6 +1925,12 @@ import {
1638
1925
  import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
1639
1926
  function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate }) {
1640
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]);
1641
1934
  if (block.collapsible) {
1642
1935
  return /* @__PURE__ */ jsxs6(
1643
1936
  Accordion2,
@@ -1646,6 +1939,8 @@ function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate
1646
1939
  onChange: (_, expanded) => setIsExpanded(expanded),
1647
1940
  disableGutters: true,
1648
1941
  elevation: 0,
1942
+ "data-xladmin-active-block": hasActiveModel ? "true" : void 0,
1943
+ "data-xladmin-block-origin": block.isAllModels ? "all-models" : "block",
1649
1944
  sx: {
1650
1945
  ...getBlockSurfaceSx(block, "sidebar"),
1651
1946
  borderRadius: "8px",
@@ -1683,6 +1978,7 @@ function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate
1683
1978
  models: block.models,
1684
1979
  basePath,
1685
1980
  activeModelSlug,
1981
+ modelOrigin: block.isAllModels ? "all-models" : "block",
1686
1982
  onModelNavigate
1687
1983
  }
1688
1984
  ) })
@@ -1693,6 +1989,8 @@ function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate
1693
1989
  return /* @__PURE__ */ jsxs6(
1694
1990
  Paper2,
1695
1991
  {
1992
+ "data-xladmin-active-block": hasActiveModel ? "true" : void 0,
1993
+ "data-xladmin-block-origin": block.isAllModels ? "all-models" : "block",
1696
1994
  sx: {
1697
1995
  ...getBlockSurfaceSx(block, "sidebar"),
1698
1996
  borderRadius: "8px",
@@ -1706,6 +2004,7 @@ function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate
1706
2004
  models: block.models,
1707
2005
  basePath,
1708
2006
  activeModelSlug,
2007
+ modelOrigin: block.isAllModels ? "all-models" : "block",
1709
2008
  onModelNavigate
1710
2009
  }
1711
2010
  )
@@ -1713,7 +2012,7 @@ function SidebarModelsBlock({ block, basePath, activeModelSlug, onModelNavigate
1713
2012
  }
1714
2013
  );
1715
2014
  }
1716
- function SidebarModelsList({ models, basePath, activeModelSlug, onModelNavigate }) {
2015
+ function SidebarModelsList({ models, basePath, activeModelSlug, modelOrigin, onModelNavigate }) {
1717
2016
  return /* @__PURE__ */ jsx11(List, { dense: true, disablePadding: true, sx: { display: "flex", flexDirection: "column", gap: 0.5, p: 1.35 }, children: models.map((model) => {
1718
2017
  const href = `${basePath}/${model.slug}`;
1719
2018
  const isActive = activeModelSlug === model.slug;
@@ -1723,33 +2022,38 @@ function SidebarModelsList({ models, basePath, activeModelSlug, onModelNavigate
1723
2022
  href,
1724
2023
  style: { textDecoration: "none", display: "block" },
1725
2024
  onClick: () => onModelNavigate == null ? void 0 : onModelNavigate(href),
1726
- children: /* @__PURE__ */ jsx11(
1727
- ListItemButton2,
1728
- {
1729
- selected: isActive,
1730
- sx: {
1731
- borderRadius: "8px",
1732
- px: 1.4,
1733
- backgroundColor: isActive ? "rgba(255, 255, 255, 0.18)" : "rgba(255, 255, 255, 0.04)",
1734
- boxShadow: isActive ? "inset 0 0 0 1px rgba(255, 255, 255, 0.08)" : "none",
1735
- "&:hover": {
1736
- backgroundColor: isActive ? "rgba(255, 255, 255, 0.2)" : "rgba(255, 255, 255, 0.06)"
1737
- },
1738
- "&.Mui-selected": {
1739
- backgroundColor: "rgba(255, 255, 255, 0.18)"
1740
- },
1741
- "&.Mui-selected:hover": {
1742
- backgroundColor: "rgba(255, 255, 255, 0.2)"
1743
- }
1744
- },
1745
- children: /* @__PURE__ */ jsx11(ListItemText2, { primary: model.title })
1746
- }
1747
- )
2025
+ children: /* @__PURE__ */ jsx11(SidebarModelListItem, { title: model.title, isActive, modelOrigin })
1748
2026
  },
1749
2027
  model.slug
1750
2028
  );
1751
2029
  }) });
1752
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
+ }
1753
2057
 
1754
2058
  // src/components/ModelsBlocks.tsx
1755
2059
  import { jsx as jsx12 } from "react/jsx-runtime";
@@ -1995,7 +2299,7 @@ function OverviewPage({ client, basePath }) {
1995
2299
  const [data, setData] = useState7(shellModelsResponse != null ? shellModelsResponse : cachedModelsResponse);
1996
2300
  const [error, setError] = useState7(null);
1997
2301
  const [isLoading, setIsLoading] = useState7(shellModelsResponse === null && cachedModelsResponse === null);
1998
- useEffect7(() => {
2302
+ useEffect8(() => {
1999
2303
  let isMounted = true;
2000
2304
  if (shellModelsResponse !== null) {
2001
2305
  cachedModelsResponse = shellModelsResponse;
@@ -2115,17 +2419,17 @@ import ChevronRightIcon from "@mui/icons-material/ChevronRight";
2115
2419
  import ExpandMoreIcon4 from "@mui/icons-material/ExpandMore";
2116
2420
  import FilterListIcon from "@mui/icons-material/FilterList";
2117
2421
  import {
2118
- Alert as Alert5,
2119
- Box as Box10,
2120
- Button as Button4,
2422
+ Alert as Alert6,
2423
+ Box as Box11,
2424
+ Button as Button5,
2121
2425
  Checkbox as Checkbox2,
2122
- Dialog as Dialog3,
2123
- DialogContent as DialogContent3,
2124
- DialogTitle as DialogTitle3,
2426
+ Dialog as Dialog4,
2427
+ DialogContent as DialogContent4,
2428
+ DialogTitle as DialogTitle4,
2125
2429
  IconButton as IconButton3,
2126
2430
  InputBase,
2127
2431
  Menu,
2128
- MenuItem as MenuItem2,
2432
+ MenuItem as MenuItem3,
2129
2433
  Paper as Paper7,
2130
2434
  Stack as Stack10,
2131
2435
  Table,
@@ -2140,20 +2444,165 @@ import {
2140
2444
  } from "@mui/material";
2141
2445
  import { useTheme as useTheme3 } from "@mui/material/styles";
2142
2446
 
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";
2452
+ import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
2453
+ function ActionFormDialog({
2454
+ open,
2455
+ onClose,
2456
+ onSuccess,
2457
+ title,
2458
+ submitLabel,
2459
+ slug,
2460
+ locale,
2461
+ fields,
2462
+ client,
2463
+ choiceScope,
2464
+ initialValues,
2465
+ onSubmit
2466
+ }) {
2467
+ const t = useAdminTranslation();
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",
2538
+ slotProps: {
2539
+ paper: {
2540
+ sx: {
2541
+ m: { xs: 1, sm: 2, md: 3 },
2542
+ width: { xs: "calc(100% - 16px)", sm: void 0 },
2543
+ maxWidth: { xs: "calc(100% - 16px)", md: 900 },
2544
+ maxHeight: {
2545
+ xs: "calc(100% - 16px)",
2546
+ sm: "calc(100% - 32px)",
2547
+ md: "calc(100% - 48px)"
2548
+ }
2549
+ }
2550
+ }
2551
+ },
2552
+ children: [
2553
+ /* @__PURE__ */ jsx15(DialogTitle2, { children: title }),
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
+
2143
2592
  // src/components/DeletePreviewDialog.tsx
2144
2593
  import {
2145
- Alert as Alert4,
2146
- Box as Box7,
2147
- Button as Button2,
2594
+ Alert as Alert5,
2595
+ Box as Box8,
2596
+ Button as Button3,
2148
2597
  CircularProgress as CircularProgress2,
2149
- Dialog as Dialog2,
2150
- DialogActions as DialogActions2,
2151
- DialogContent as DialogContent2,
2152
- DialogTitle as DialogTitle2,
2598
+ Dialog as Dialog3,
2599
+ DialogActions as DialogActions3,
2600
+ DialogContent as DialogContent3,
2601
+ DialogTitle as DialogTitle3,
2153
2602
  Stack as Stack7,
2154
2603
  Typography as Typography4
2155
2604
  } from "@mui/material";
2156
- import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
2605
+ import { jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
2157
2606
  function DeletePreviewDialog({
2158
2607
  open,
2159
2608
  title,
@@ -2165,8 +2614,8 @@ function DeletePreviewDialog({
2165
2614
  onConfirm
2166
2615
  }) {
2167
2616
  const t = useAdminTranslation();
2168
- return /* @__PURE__ */ jsxs9(
2169
- Dialog2,
2617
+ return /* @__PURE__ */ jsxs10(
2618
+ Dialog3,
2170
2619
  {
2171
2620
  open,
2172
2621
  onClose: isSubmitting ? void 0 : onClose,
@@ -2187,27 +2636,27 @@ function DeletePreviewDialog({
2187
2636
  }
2188
2637
  },
2189
2638
  children: [
2190
- /* @__PURE__ */ jsx15(DialogTitle2, { children: title }),
2191
- /* @__PURE__ */ jsxs9(DialogContent2, { dividers: true, children: [
2192
- isLoading ? /* @__PURE__ */ jsxs9(Stack7, { spacing: 1.5, alignItems: "center", justifyContent: "center", sx: { minHeight: 180 }, children: [
2193
- /* @__PURE__ */ jsx15(CircularProgress2, { size: 28, thickness: 4.2, color: "inherit" }),
2194
- /* @__PURE__ */ jsx15(Typography4, { color: "text.secondary", children: t("delete_preview_loading") })
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") })
2195
2644
  ] }) : null,
2196
- !isLoading && error ? /* @__PURE__ */ jsx15(Alert4, { severity: "error", children: error }) : null,
2197
- !isLoading && !error && preview ? /* @__PURE__ */ jsxs9(Stack7, { spacing: 1.5, children: [
2198
- /* @__PURE__ */ jsx15(Typography4, { color: "text.secondary", children: preview.can_delete ? t("delete_preview_hint") : t("delete_preview_blocked_hint") }),
2199
- !preview.can_delete ? /* @__PURE__ */ jsx15(Alert4, { severity: "warning", children: t("delete_preview_blocked_hint") }) : null,
2200
- /* @__PURE__ */ jsxs9(Stack7, { spacing: 0.5, children: [
2201
- /* @__PURE__ */ jsx15(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_roots", { count: preview.summary.roots }) }),
2202
- /* @__PURE__ */ jsx15(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_delete", { count: preview.summary.delete }) }),
2203
- /* @__PURE__ */ jsx15(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_protect", { count: preview.summary.protect }) }),
2204
- /* @__PURE__ */ jsx15(Typography4, { variant: "body2", color: "text.secondary", children: t("delete_preview_set_null", { count: preview.summary.set_null }) }),
2205
- /* @__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 }) })
2206
2655
  ] }),
2207
- 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,
2208
- 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) => {
2209
2658
  var _a;
2210
- return /* @__PURE__ */ jsx15(
2659
+ return /* @__PURE__ */ jsx16(
2211
2660
  DeletePreviewNode,
2212
2661
  {
2213
2662
  node: rootNode,
@@ -2215,7 +2664,7 @@ function DeletePreviewDialog({
2215
2664
  },
2216
2665
  `${(_a = rootNode.model_slug) != null ? _a : "model"}:${rootNode.id}:${index}`
2217
2666
  );
2218
- }) }) : /* @__PURE__ */ jsx15(
2667
+ }) }) : /* @__PURE__ */ jsx16(
2219
2668
  Typography4,
2220
2669
  {
2221
2670
  variant: "body2",
@@ -2225,10 +2674,10 @@ function DeletePreviewDialog({
2225
2674
  )
2226
2675
  ] }) : null
2227
2676
  ] }),
2228
- /* @__PURE__ */ jsxs9(DialogActions2, { children: [
2229
- /* @__PURE__ */ jsx15(Button2, { onClick: onClose, disabled: isSubmitting, children: t("cancel") }),
2230
- /* @__PURE__ */ jsx15(
2231
- Button2,
2677
+ /* @__PURE__ */ jsxs10(DialogActions3, { children: [
2678
+ /* @__PURE__ */ jsx16(Button3, { onClick: onClose, disabled: isSubmitting, children: t("cancel") }),
2679
+ /* @__PURE__ */ jsx16(
2680
+ Button3,
2232
2681
  {
2233
2682
  color: "error",
2234
2683
  variant: "contained",
@@ -2244,8 +2693,8 @@ function DeletePreviewDialog({
2244
2693
  }
2245
2694
  function DeletePreviewNode({ node, depth }) {
2246
2695
  const t = useAdminTranslation();
2247
- return /* @__PURE__ */ jsxs9(
2248
- Box7,
2696
+ return /* @__PURE__ */ jsxs10(
2697
+ Box8,
2249
2698
  {
2250
2699
  sx: {
2251
2700
  pl: depth === 0 ? 0 : 1.5,
@@ -2253,17 +2702,17 @@ function DeletePreviewNode({ node, depth }) {
2253
2702
  borderLeft: depth === 0 ? "none" : "1px solid rgba(255, 255, 255, 0.08)"
2254
2703
  },
2255
2704
  children: [
2256
- /* @__PURE__ */ jsxs9(Stack7, { spacing: 0.25, children: [
2257
- /* @__PURE__ */ jsx15(Typography4, { sx: { fontWeight: 600 }, children: node.label }),
2258
- /* @__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: [
2259
2708
  node.model_title,
2260
2709
  node.relation_name ? ` \u2022 ${node.relation_name}` : "",
2261
2710
  ` \u2022 ${getEffectLabel(node.effect, t)}`
2262
2711
  ] })
2263
2712
  ] }),
2264
- 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) => {
2265
2714
  var _a;
2266
- return /* @__PURE__ */ jsx15(
2715
+ return /* @__PURE__ */ jsx16(
2267
2716
  DeletePreviewNode,
2268
2717
  {
2269
2718
  node: childNode,
@@ -2287,19 +2736,19 @@ function getEffectLabel(effect, t) {
2287
2736
  }
2288
2737
 
2289
2738
  // src/components/model-page/ListFiltersBar.tsx
2290
- 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";
2291
2740
  import {
2292
2741
  Autocomplete as Autocomplete2,
2293
- Button as Button3,
2742
+ Button as Button4,
2294
2743
  CircularProgress as CircularProgress3,
2295
2744
  Divider,
2296
- MenuItem,
2745
+ MenuItem as MenuItem2,
2297
2746
  Paper as Paper5,
2298
2747
  Stack as Stack8,
2299
2748
  TextField as TextField2,
2300
2749
  Typography as Typography5
2301
2750
  } from "@mui/material";
2302
- 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";
2303
2752
  var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
2304
2753
  client,
2305
2754
  slug,
@@ -2334,7 +2783,7 @@ var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
2334
2783
  [filters, values]
2335
2784
  );
2336
2785
  if (filters.length === 0) return null;
2337
- return /* @__PURE__ */ jsx16(
2786
+ return /* @__PURE__ */ jsx17(
2338
2787
  Paper5,
2339
2788
  {
2340
2789
  sx: {
@@ -2346,14 +2795,14 @@ var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
2346
2795
  p: 1.5,
2347
2796
  overflow: "auto"
2348
2797
  },
2349
- children: /* @__PURE__ */ jsxs10(Stack8, { spacing: 1.5, children: [
2350
- /* @__PURE__ */ jsxs10(Stack8, { direction: "row", spacing: 1, alignItems: "center", justifyContent: "space-between", children: [
2351
- /* @__PURE__ */ jsxs10(Stack8, { spacing: 0.25, children: [
2352
- /* @__PURE__ */ jsx16(Typography5, { sx: { fontSize: 15, fontWeight: 700 }, children: t("filters") }),
2353
- 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
2354
2803
  ] }),
2355
- /* @__PURE__ */ jsx16(
2356
- Button3,
2804
+ /* @__PURE__ */ jsx17(
2805
+ Button4,
2357
2806
  {
2358
2807
  size: "small",
2359
2808
  onClick: onReset,
@@ -2363,8 +2812,8 @@ var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
2363
2812
  }
2364
2813
  )
2365
2814
  ] }),
2366
- /* @__PURE__ */ jsx16(Divider, {}),
2367
- filterGroups.map((group) => /* @__PURE__ */ jsx16(
2815
+ /* @__PURE__ */ jsx17(Divider, {}),
2816
+ filterGroups.map((group) => /* @__PURE__ */ jsx17(
2368
2817
  FilterGroupSection,
2369
2818
  {
2370
2819
  client,
@@ -2381,11 +2830,11 @@ var ListFiltersSidebar = memo3(function ListFiltersSidebar2({
2381
2830
  );
2382
2831
  });
2383
2832
  function FilterGroupSection({ client, slug, group, values, onChange, debounceMs }) {
2384
- return /* @__PURE__ */ jsxs10(Stack8, { spacing: 1, children: [
2385
- /* @__PURE__ */ jsx16(Typography5, { sx: { fontSize: 13, fontWeight: 700, color: "text.secondary" }, children: group.title }),
2386
- /* @__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) => {
2387
2836
  var _a;
2388
- return /* @__PURE__ */ jsx16(
2837
+ return /* @__PURE__ */ jsx17(
2389
2838
  ListFilterField,
2390
2839
  {
2391
2840
  client,
@@ -2403,8 +2852,8 @@ function FilterGroupSection({ client, slug, group, values, onChange, debounceMs
2403
2852
  function ListFilterField({ client, slug, filter, value, onChange, debounceMs }) {
2404
2853
  var _a, _b;
2405
2854
  const t = useAdminTranslation();
2406
- const [draftValue, setDraftValue] = useState8(value);
2407
- const [searchValue, setSearchValue] = useState8("");
2855
+ const [draftValue, setDraftValue] = useState9(value);
2856
+ const [searchValue, setSearchValue] = useState9("");
2408
2857
  const selectedValues = useMemo8(() => parseSelectedFilterValues(value, filter.multiple), [filter.multiple, value]);
2409
2858
  const isSelectFilter = filter.input_kind === "select" || filter.input_kind === "select-multiple";
2410
2859
  const loadChoices = useCallback4(
@@ -2431,13 +2880,13 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
2431
2880
  queryKey: `${slug}:${filter.slug}:${searchValue}:${value}`,
2432
2881
  load: loadChoices
2433
2882
  });
2434
- useEffect8(() => {
2883
+ useEffect10(() => {
2435
2884
  setDraftValue(value);
2436
2885
  }, [value]);
2437
- useEffect8(() => {
2886
+ useEffect10(() => {
2438
2887
  setSearchValue("");
2439
2888
  }, [filter.slug]);
2440
- useEffect8(() => {
2889
+ useEffect10(() => {
2441
2890
  if (filter.input_kind !== "text") {
2442
2891
  return;
2443
2892
  }
@@ -2451,7 +2900,7 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
2451
2900
  };
2452
2901
  }, [debounceMs, draftValue, filter.input_kind, filter.slug, onChange, value]);
2453
2902
  if (filter.input_kind === "boolean") {
2454
- return /* @__PURE__ */ jsxs10(
2903
+ return /* @__PURE__ */ jsxs11(
2455
2904
  TextField2,
2456
2905
  {
2457
2906
  select: true,
@@ -2461,8 +2910,8 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
2461
2910
  value,
2462
2911
  onChange: (event) => onChange(filter.slug, event.target.value),
2463
2912
  children: [
2464
- /* @__PURE__ */ jsx16(MenuItem, { value: "", children: t("all") }),
2465
- 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}`))
2466
2915
  ]
2467
2916
  }
2468
2917
  );
@@ -2476,7 +2925,7 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
2476
2925
  };
2477
2926
  });
2478
2927
  const selectedOption = filter.multiple ? selectedOptions : (_a = selectedOptions[0]) != null ? _a : null;
2479
- return /* @__PURE__ */ jsx16(
2928
+ return /* @__PURE__ */ jsx17(
2480
2929
  Autocomplete2,
2481
2930
  {
2482
2931
  options,
@@ -2502,7 +2951,7 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
2502
2951
  renderInput: (params) => (() => {
2503
2952
  var _a2;
2504
2953
  const { InputProps, inputProps, ...textFieldParams } = params;
2505
- return /* @__PURE__ */ jsx16(
2954
+ return /* @__PURE__ */ jsx17(
2506
2955
  TextField2,
2507
2956
  {
2508
2957
  ...textFieldParams,
@@ -2511,8 +2960,8 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
2511
2960
  slotProps: {
2512
2961
  input: {
2513
2962
  ...InputProps,
2514
- endAdornment: /* @__PURE__ */ jsxs10(Fragment2, { children: [
2515
- 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,
2516
2965
  InputProps.endAdornment
2517
2966
  ] })
2518
2967
  },
@@ -2524,7 +2973,7 @@ function ListFilterField({ client, slug, filter, value, onChange, debounceMs })
2524
2973
  }
2525
2974
  );
2526
2975
  }
2527
- return /* @__PURE__ */ jsx16(
2976
+ return /* @__PURE__ */ jsx17(
2528
2977
  TextField2,
2529
2978
  {
2530
2979
  size: "small",
@@ -2549,8 +2998,8 @@ function parseSelectedFilterValues(value, multiple) {
2549
2998
  // src/components/model-page/ListRow.tsx
2550
2999
  import { memo as memo4 } from "react";
2551
3000
  import MoreVertIcon from "@mui/icons-material/MoreVert";
2552
- import { Box as Box8, Checkbox, IconButton as IconButton2, TableCell, TableRow } from "@mui/material";
2553
- 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";
2554
3003
  var ListRow = memo4(function ListRow2({
2555
3004
  row,
2556
3005
  pkField,
@@ -2566,7 +3015,7 @@ var ListRow = memo4(function ListRow2({
2566
3015
  const checkboxColumnWidth = 56;
2567
3016
  const actionsColumnWidth = 56;
2568
3017
  const rowId = row[pkField];
2569
- return /* @__PURE__ */ jsxs11(
3018
+ return /* @__PURE__ */ jsxs12(
2570
3019
  TableRow,
2571
3020
  {
2572
3021
  hover: true,
@@ -2580,7 +3029,7 @@ var ListRow = memo4(function ListRow2({
2580
3029
  }
2581
3030
  },
2582
3031
  children: [
2583
- /* @__PURE__ */ jsx17(
3032
+ /* @__PURE__ */ jsx18(
2584
3033
  TableCell,
2585
3034
  {
2586
3035
  padding: "none",
@@ -2592,7 +3041,7 @@ var ListRow = memo4(function ListRow2({
2592
3041
  textAlign: "center",
2593
3042
  px: 1
2594
3043
  },
2595
- children: /* @__PURE__ */ jsx17(
3044
+ children: /* @__PURE__ */ jsx18(
2596
3045
  Checkbox,
2597
3046
  {
2598
3047
  checked: isSelected,
@@ -2617,8 +3066,8 @@ var ListRow = memo4(function ListRow2({
2617
3066
  textOverflow: "ellipsis"
2618
3067
  };
2619
3068
  if (imageUrl) {
2620
- return /* @__PURE__ */ jsx17(TableCell, { title: fullFieldValue, sx: { ...commonCellSx, py: 0.75 }, children: /* @__PURE__ */ jsx17(
2621
- Box8,
3069
+ return /* @__PURE__ */ jsx18(TableCell, { title: fullFieldValue, sx: { ...commonCellSx, py: 0.75 }, children: /* @__PURE__ */ jsx18(
3070
+ Box9,
2622
3071
  {
2623
3072
  component: "img",
2624
3073
  src: imageUrl,
@@ -2635,7 +3084,7 @@ var ListRow = memo4(function ListRow2({
2635
3084
  ) }, fieldName);
2636
3085
  }
2637
3086
  if (index === 0) {
2638
- return /* @__PURE__ */ jsx17(
3087
+ return /* @__PURE__ */ jsx18(
2639
3088
  TableCell,
2640
3089
  {
2641
3090
  title: fullFieldValue,
@@ -2653,7 +3102,7 @@ var ListRow = memo4(function ListRow2({
2653
3102
  color: "primary.main"
2654
3103
  }
2655
3104
  },
2656
- children: /* @__PURE__ */ jsx17(
3105
+ children: /* @__PURE__ */ jsx18(
2657
3106
  NavLink,
2658
3107
  {
2659
3108
  href: `${basePath}/${slug}/${rowId}`,
@@ -2666,9 +3115,9 @@ var ListRow = memo4(function ListRow2({
2666
3115
  fieldName
2667
3116
  );
2668
3117
  }
2669
- return /* @__PURE__ */ jsx17(TableCell, { title: fullFieldValue, sx: commonCellSx, children: fieldValue }, fieldName);
3118
+ return /* @__PURE__ */ jsx18(TableCell, { title: fullFieldValue, sx: commonCellSx, children: fieldValue }, fieldName);
2670
3119
  }),
2671
- /* @__PURE__ */ jsx17(
3120
+ /* @__PURE__ */ jsx18(
2672
3121
  TableCell,
2673
3122
  {
2674
3123
  align: "right",
@@ -2677,7 +3126,7 @@ var ListRow = memo4(function ListRow2({
2677
3126
  minWidth: actionsColumnWidth,
2678
3127
  maxWidth: actionsColumnWidth
2679
3128
  },
2680
- 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" }) })
2681
3130
  }
2682
3131
  )
2683
3132
  ]
@@ -2686,20 +3135,20 @@ var ListRow = memo4(function ListRow2({
2686
3135
  });
2687
3136
 
2688
3137
  // src/components/model-page/SearchField.tsx
2689
- 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";
2690
3139
  import { TextField as TextField3 } from "@mui/material";
2691
- import { jsx as jsx18 } from "react/jsx-runtime";
3140
+ import { jsx as jsx19 } from "react/jsx-runtime";
2692
3141
  var SearchField = memo5(function SearchField2({
2693
3142
  value,
2694
3143
  onCommit,
2695
3144
  debounceMs,
2696
3145
  placeholder
2697
3146
  }) {
2698
- const [draftValue, setDraftValue] = useState9(value);
2699
- useEffect9(() => {
3147
+ const [draftValue, setDraftValue] = useState10(value);
3148
+ useEffect11(() => {
2700
3149
  setDraftValue(value);
2701
3150
  }, [value]);
2702
- useEffect9(() => {
3151
+ useEffect11(() => {
2703
3152
  const timerId = window.setTimeout(() => {
2704
3153
  if (draftValue !== value) {
2705
3154
  onCommit(draftValue);
@@ -2709,7 +3158,7 @@ var SearchField = memo5(function SearchField2({
2709
3158
  window.clearTimeout(timerId);
2710
3159
  };
2711
3160
  }, [debounceMs, draftValue, onCommit, value]);
2712
- return /* @__PURE__ */ jsx18(
3161
+ return /* @__PURE__ */ jsx19(
2713
3162
  TextField3,
2714
3163
  {
2715
3164
  size: "small",
@@ -2728,7 +3177,7 @@ var SearchField = memo5(function SearchField2({
2728
3177
  });
2729
3178
 
2730
3179
  // src/components/model-page/useModelPageController.ts
2731
- import { useCallback as useCallback5, useEffect as useEffect10, useLayoutEffect as useLayoutEffect2, 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";
2732
3181
 
2733
3182
  // src/cache.ts
2734
3183
  var MAX_CACHE_ENTRIES = 100;
@@ -2837,34 +3286,35 @@ function useModelPageController({
2837
3286
  ...initialFilters
2838
3287
  })
2839
3288
  )) != null ? _c : null;
2840
- const [selectedIds, setSelectedIds] = useState10([]);
2841
- const [isAllMatchingSelected, setIsAllMatchingSelected] = useState10(false);
2842
- const [createOpen, setCreateOpen] = useState10(false);
2843
- const [data, setData] = useState10(() => initialCachedResponse);
2844
- const [error, setError] = useState10(null);
2845
- const [isLoading, setIsLoading] = useState10(initialCachedResponse === null);
2846
- const [rowActionMenuAnchor, setRowActionMenuAnchor] = useState10(null);
2847
- const [rowActionMenuId, setRowActionMenuId] = useState10(null);
2848
- const [bulkActionMenuAnchor, setBulkActionMenuAnchor] = useState10(null);
2849
- const [appliedQuery, setAppliedQuery] = useState10(initialQuery);
2850
- const [sortValue, setSortValue] = useState10(initialSort);
2851
- const [currentPage, setCurrentPage] = useState10(initialPage);
2852
- const [pageInput, setPageInput] = useState10(String(initialPage));
2853
- const [appliedFilters, setAppliedFilters] = useState10(initialFilters);
2854
- const [deletePreviewOpen, setDeletePreviewOpen] = useState10(false);
2855
- const [deletePreview, setDeletePreview] = useState10(null);
2856
- const [deletePreviewError, setDeletePreviewError] = useState10(null);
2857
- const [isDeletePreviewLoading, setIsDeletePreviewLoading] = useState10(false);
2858
- const [isDeleteSubmitting, setIsDeleteSubmitting] = useState10(false);
2859
- const [pendingDeleteIds, setPendingDeleteIds] = useState10([]);
2860
- const [pendingDeleteSelectAll, setPendingDeleteSelectAll] = useState10(false);
2861
- const [pendingDeleteScope, setPendingDeleteScope] = useState10(null);
2862
- const [pendingDeleteMode, setPendingDeleteMode] = useState10("single");
2863
- const [filtersOpen, setFiltersOpen] = useState10(false);
2864
- const requestIdRef = useRef4(0);
2865
- const dataRef = useRef4(initialCachedResponse);
2866
- const pageSizeRef = useRef4((_d = initialCachedResponse == null ? void 0 : initialCachedResponse.meta.page_size) != null ? _d : DEFAULT_PAGE_SIZE);
2867
- 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);
2868
3318
  const sortFields = useMemo9(() => sortValue.split(",").filter(Boolean), [sortValue]);
2869
3319
  const meta = (_e = data == null ? void 0 : data.meta) != null ? _e : null;
2870
3320
  const rows = (_f = data == null ? void 0 : data.items) != null ? _f : [];
@@ -2908,10 +3358,10 @@ function useModelPageController({
2908
3358
  });
2909
3359
  const hasSelection = isAllMatchingSelected || selectedIds.length > 0;
2910
3360
  const selectionCount = isAllMatchingSelected ? total : selectedIds.length;
2911
- useEffect10(() => {
3361
+ useEffect12(() => {
2912
3362
  dataRef.current = data;
2913
3363
  }, [data]);
2914
- useEffect10(() => {
3364
+ useEffect12(() => {
2915
3365
  setPageInput(String(currentPage));
2916
3366
  }, [currentPage]);
2917
3367
  useLayoutEffect2(() => {
@@ -2944,6 +3394,7 @@ function useModelPageController({
2944
3394
  setRowActionMenuAnchor(null);
2945
3395
  setRowActionMenuId(null);
2946
3396
  setBulkActionMenuAnchor(null);
3397
+ setBulkActionFormSlug(null);
2947
3398
  setDeletePreviewOpen(false);
2948
3399
  setDeletePreview(null);
2949
3400
  setDeletePreviewError(null);
@@ -3015,7 +3466,7 @@ function useModelPageController({
3015
3466
  }
3016
3467
  }
3017
3468
  }, [appliedFilters, appliedQuery, client, currentPage, isAllMatchingSelected, slug, sortValue, t]);
3018
- useEffect10(() => {
3469
+ useEffect12(() => {
3019
3470
  void loadItems();
3020
3471
  }, [loadItems]);
3021
3472
  const refresh = useCallback5(async () => {
@@ -3167,7 +3618,7 @@ function useModelPageController({
3167
3618
  }
3168
3619
  }, [clearSelection, client, message, pendingDeleteIds, pendingDeleteMode, pendingDeleteScope, pendingDeleteSelectAll, refresh, slug, t]);
3169
3620
  const handleRunNamedBulkAction = useCallback5(async (actionSlug) => {
3170
- var _a2, _b2;
3621
+ var _a2, _b2, _c2, _d2;
3171
3622
  if (!actionSlug || !hasSelection) {
3172
3623
  return;
3173
3624
  }
@@ -3175,6 +3626,12 @@ function useModelPageController({
3175
3626
  await openBulkDeletePreview();
3176
3627
  return;
3177
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
+ }
3178
3635
  try {
3179
3636
  const response = await client.runBulkAction(
3180
3637
  slug,
@@ -3186,7 +3643,7 @@ function useModelPageController({
3186
3643
  setBulkActionMenuAnchor(null);
3187
3644
  clearSelection();
3188
3645
  await refresh();
3189
- 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;
3190
3647
  message.success(t("action_success", { action: actionLabel, count: response.processed }));
3191
3648
  } catch (reason) {
3192
3649
  const nextError = reason instanceof Error ? reason.message : t("object_action_error");
@@ -3194,6 +3651,34 @@ function useModelPageController({
3194
3651
  message.error(nextError);
3195
3652
  }
3196
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
+ );
3197
3682
  const handleRowDelete = useCallback5(async (rowId) => {
3198
3683
  setRowActionMenuAnchor(null);
3199
3684
  setRowActionMenuId(null);
@@ -3271,6 +3756,7 @@ function useModelPageController({
3271
3756
  appliedQuery,
3272
3757
  bulkActionMenuAnchor,
3273
3758
  bulkActions,
3759
+ activeBulkAction,
3274
3760
  clearBulkDeleteState,
3275
3761
  createOpen,
3276
3762
  currentPage,
@@ -3283,6 +3769,7 @@ function useModelPageController({
3283
3769
  filtersOpen,
3284
3770
  handleClearDeletePreview,
3285
3771
  handleCloseBulkActionMenu,
3772
+ handleCloseBulkActionForm,
3286
3773
  handleCloseRowMenu,
3287
3774
  handleConfirmDelete,
3288
3775
  handleFilterChange,
@@ -3292,6 +3779,7 @@ function useModelPageController({
3292
3779
  handleResetFilters,
3293
3780
  handleRowDelete,
3294
3781
  handleRunNamedBulkAction,
3782
+ handleSubmitBulkActionForm,
3295
3783
  handleSearchCommit,
3296
3784
  handleSelectAllMatching,
3297
3785
  handleToggleAllVisible,
@@ -3373,34 +3861,34 @@ function extractFilterParams(params) {
3373
3861
  }
3374
3862
 
3375
3863
  // src/components/model-page/Skeletons.tsx
3376
- import { Box as Box9, Paper as Paper6, Skeleton as Skeleton3, Stack as Stack9 } from "@mui/material";
3377
- 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";
3378
3866
  function ModelPageSkeleton() {
3379
- return /* @__PURE__ */ jsxs12(Stack9, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
3380
- /* @__PURE__ */ jsx19(MainHeaderSkeleton, { titleWidth: 240, subtitleWidth: "38%" }),
3381
- /* @__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: [
3382
- /* @__PURE__ */ jsx19(Skeleton3, { variant: "rounded", width: 360, height: 40 }),
3383
- /* @__PURE__ */ jsx19(Skeleton3, { variant: "rounded", width: 128, height: 40 }),
3384
- /* @__PURE__ */ jsx19(Box9, { sx: { flex: 1 } }),
3385
- /* @__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 })
3386
3874
  ] }) }),
3387
- /* @__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, {}) })
3388
3876
  ] });
3389
3877
  }
3390
3878
  function ModelTableSkeleton() {
3391
- return /* @__PURE__ */ jsx19(Box9, { sx: { height: "100%", overflow: "auto", p: 1.5 }, children: /* @__PURE__ */ jsxs12(Stack9, { spacing: 1, children: [
3392
- /* @__PURE__ */ jsx19(Skeleton3, { variant: "rounded", width: "100%", height: 42 }),
3393
- 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))
3394
3882
  ] }) });
3395
3883
  }
3396
3884
 
3397
3885
  // src/components/ModelPage.tsx
3398
- import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
3886
+ import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
3399
3887
  var SEARCH_DEBOUNCE_MS = 300;
3400
3888
  var CHECKBOX_COLUMN_WIDTH = 56;
3401
3889
  var ACTIONS_COLUMN_WIDTH = 56;
3402
3890
  function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3403
- var _a, _b;
3891
+ var _a, _b, _c;
3404
3892
  const locale = useAdminLocale();
3405
3893
  const t = useAdminTranslation();
3406
3894
  const selectAllLabel = locale === "ru" ? "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0432\u0441\u0435" : "Select All";
@@ -3434,10 +3922,10 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3434
3922
  }, [controller.error, controller.isLoading, controller.meta, finishPendingNavigation, location.pathname, pendingPath, slug]);
3435
3923
  useAdminDocumentTitle(t("admin_title"), (_b = (_a = controller.meta) == null ? void 0 : _a.title) != null ? _b : slug);
3436
3924
  if (!controller.isLoading && controller.error && !controller.data) {
3437
- return /* @__PURE__ */ jsx20(Alert5, { severity: "error", children: controller.error });
3925
+ return /* @__PURE__ */ jsx21(Alert6, { severity: "error", children: controller.error });
3438
3926
  }
3439
3927
  if (!controller.data || !controller.meta) {
3440
- return /* @__PURE__ */ jsx20(ModelPageSkeleton, {});
3928
+ return /* @__PURE__ */ jsx21(ModelPageSkeleton, {});
3441
3929
  }
3442
3930
  const meta = controller.meta;
3443
3931
  const beforePagination = renderBeforePagination == null ? void 0 : renderBeforePagination({
@@ -3456,12 +3944,12 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3456
3944
  appliedFilters: controller.appliedFilters,
3457
3945
  refresh: controller.refresh
3458
3946
  });
3459
- return /* @__PURE__ */ jsx20(AdminRouterProvider, { router: resolvedRouter, children: /* @__PURE__ */ jsxs13(Stack10, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
3460
- /* @__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(
3461
3949
  MainHeader,
3462
3950
  {
3463
3951
  title: controller.meta.title,
3464
- actions: /* @__PURE__ */ jsx20(Tooltip, { title: t("create"), children: /* @__PURE__ */ jsx20(
3952
+ actions: /* @__PURE__ */ jsx21(Tooltip, { title: t("create"), children: /* @__PURE__ */ jsx21(
3465
3953
  IconButton3,
3466
3954
  {
3467
3955
  "aria-label": t("create"),
@@ -3476,14 +3964,14 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3476
3964
  backgroundColor: "primary.dark"
3477
3965
  }
3478
3966
  },
3479
- children: /* @__PURE__ */ jsx20(AddIcon, { fontSize: "small" })
3967
+ children: /* @__PURE__ */ jsx21(AddIcon, { fontSize: "small" })
3480
3968
  }
3481
3969
  ) }),
3482
3970
  subtitle: `${controller.meta.slug} | ${t("objects_count", { count: controller.total })}`,
3483
- 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
3484
3972
  }
3485
3973
  ),
3486
- /* @__PURE__ */ jsx20(
3974
+ /* @__PURE__ */ jsx21(
3487
3975
  Paper7,
3488
3976
  {
3489
3977
  sx: {
@@ -3491,8 +3979,8 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3491
3979
  borderRadius: "10px",
3492
3980
  flexShrink: 0
3493
3981
  },
3494
- children: /* @__PURE__ */ jsxs13(Stack10, { direction: { xs: "column", lg: "row" }, spacing: 1.5, alignItems: { lg: "center" }, children: [
3495
- /* @__PURE__ */ jsxs13(
3982
+ children: /* @__PURE__ */ jsxs14(Stack10, { direction: { xs: "column", lg: "row" }, spacing: 1.5, alignItems: { lg: "center" }, children: [
3983
+ /* @__PURE__ */ jsxs14(
3496
3984
  Stack10,
3497
3985
  {
3498
3986
  direction: { xs: "column", xl: "row" },
@@ -3500,7 +3988,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3500
3988
  alignItems: { xl: "center" },
3501
3989
  sx: { flex: 1, minWidth: 0 },
3502
3990
  children: [
3503
- /* @__PURE__ */ jsx20(
3991
+ /* @__PURE__ */ jsx21(
3504
3992
  SearchField,
3505
3993
  {
3506
3994
  value: controller.appliedQuery,
@@ -3509,18 +3997,18 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3509
3997
  placeholder: t("search")
3510
3998
  }
3511
3999
  ),
3512
- controller.hasSelection ? /* @__PURE__ */ jsxs13(Stack10, { direction: "row", spacing: 1, alignItems: "center", sx: { minWidth: 0, flexWrap: "wrap" }, children: [
3513
- /* @__PURE__ */ jsx20(
3514
- Button4,
4000
+ controller.hasSelection ? /* @__PURE__ */ jsxs14(Stack10, { direction: "row", spacing: 1, alignItems: "center", sx: { minWidth: 0, flexWrap: "wrap" }, children: [
4001
+ /* @__PURE__ */ jsx21(
4002
+ Button5,
3515
4003
  {
3516
4004
  variant: "outlined",
3517
- endIcon: /* @__PURE__ */ jsx20(ExpandMoreIcon4, {}),
4005
+ endIcon: /* @__PURE__ */ jsx21(ExpandMoreIcon4, {}),
3518
4006
  onClick: (event) => controller.setBulkActionMenuAnchor(event.currentTarget),
3519
4007
  children: t("actions")
3520
4008
  }
3521
4009
  ),
3522
- !controller.isAllMatchingSelected && controller.selectionCount < controller.total ? /* @__PURE__ */ jsx20(
3523
- Button4,
4010
+ !controller.isAllMatchingSelected && controller.selectionCount < controller.total ? /* @__PURE__ */ jsx21(
4011
+ Button5,
3524
4012
  {
3525
4013
  variant: "text",
3526
4014
  onClick: controller.handleSelectAllMatching,
@@ -3528,7 +4016,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3528
4016
  children: selectAllLabel
3529
4017
  }
3530
4018
  ) : null,
3531
- /* @__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: [
3532
4020
  t("selected_count", { count: controller.selectionCount }),
3533
4021
  " / ",
3534
4022
  controller.total
@@ -3537,28 +4025,28 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3537
4025
  ]
3538
4026
  }
3539
4027
  ),
3540
- /* @__PURE__ */ jsxs13(Stack10, { direction: "row", spacing: 1, alignItems: "center", sx: { marginLeft: "auto" }, children: [
3541
- beforePagination ? /* @__PURE__ */ jsx20(Box10, { sx: { display: "flex", alignItems: "center", flexShrink: 0 }, children: beforePagination }) : null,
3542
- 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(
3543
4031
  IconButton3,
3544
4032
  {
3545
4033
  size: "small",
3546
4034
  "aria-label": t("filters"),
3547
4035
  onClick: () => controller.setFiltersOpen(true),
3548
- children: /* @__PURE__ */ jsx20(FilterListIcon, { fontSize: "small" })
4036
+ children: /* @__PURE__ */ jsx21(FilterListIcon, { fontSize: "small" })
3549
4037
  }
3550
4038
  ) }) : null,
3551
- /* @__PURE__ */ jsx20(
4039
+ /* @__PURE__ */ jsx21(
3552
4040
  IconButton3,
3553
4041
  {
3554
4042
  size: "small",
3555
4043
  onClick: () => controller.handlePageChange(controller.currentPage - 1),
3556
4044
  disabled: controller.currentPage <= 1,
3557
4045
  sx: { mr: "-5px" },
3558
- children: /* @__PURE__ */ jsx20(ChevronLeftIcon, { fontSize: "small" })
4046
+ children: /* @__PURE__ */ jsx21(ChevronLeftIcon, { fontSize: "small" })
3559
4047
  }
3560
4048
  ),
3561
- /* @__PURE__ */ jsx20(
4049
+ /* @__PURE__ */ jsx21(
3562
4050
  InputBase,
3563
4051
  {
3564
4052
  value: controller.pageInput,
@@ -3588,7 +4076,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3588
4076
  }
3589
4077
  }
3590
4078
  ),
3591
- /* @__PURE__ */ jsxs13(
4079
+ /* @__PURE__ */ jsxs14(
3592
4080
  Typography6,
3593
4081
  {
3594
4082
  color: "text.secondary",
@@ -3599,22 +4087,22 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3599
4087
  ]
3600
4088
  }
3601
4089
  ),
3602
- /* @__PURE__ */ jsx20(
4090
+ /* @__PURE__ */ jsx21(
3603
4091
  IconButton3,
3604
4092
  {
3605
4093
  size: "small",
3606
4094
  onClick: () => controller.handlePageChange(controller.currentPage + 1),
3607
4095
  disabled: controller.currentPage >= controller.totalPages,
3608
4096
  sx: { ml: "-5px" },
3609
- children: /* @__PURE__ */ jsx20(ChevronRightIcon, { fontSize: "small" })
4097
+ children: /* @__PURE__ */ jsx21(ChevronRightIcon, { fontSize: "small" })
3610
4098
  }
3611
4099
  )
3612
4100
  ] })
3613
4101
  ] })
3614
4102
  }
3615
4103
  ),
3616
- /* @__PURE__ */ jsxs13(Stack10, { direction: { xs: "column", lg: "row" }, spacing: 1.5, sx: { flex: 1, minHeight: 0 }, children: [
3617
- /* @__PURE__ */ jsx20(
4104
+ /* @__PURE__ */ jsxs14(Stack10, { direction: { xs: "column", lg: "row" }, spacing: 1.5, sx: { flex: 1, minHeight: 0 }, children: [
4105
+ /* @__PURE__ */ jsx21(
3618
4106
  Paper7,
3619
4107
  {
3620
4108
  sx: {
@@ -3624,9 +4112,9 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3624
4112
  minHeight: 0,
3625
4113
  overflow: "hidden"
3626
4114
  },
3627
- 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: [
3628
- /* @__PURE__ */ jsx20(TableHead, { children: /* @__PURE__ */ jsxs13(TableRow2, { children: [
3629
- /* @__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(
3630
4118
  TableCell2,
3631
4119
  {
3632
4120
  padding: "none",
@@ -3639,7 +4127,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3639
4127
  textAlign: "center",
3640
4128
  px: 1
3641
4129
  },
3642
- children: /* @__PURE__ */ jsx20(
4130
+ children: /* @__PURE__ */ jsx21(
3643
4131
  Checkbox2,
3644
4132
  {
3645
4133
  checked: controller.allVisibleSelected,
@@ -3654,7 +4142,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3654
4142
  const field = controller.fieldMap.get(fieldName);
3655
4143
  const sortDirection = resolveSortDirection(controller.sortFields, fieldName);
3656
4144
  const isSortable = resolveFieldSortable(field);
3657
- return /* @__PURE__ */ jsx20(
4145
+ return /* @__PURE__ */ jsx21(
3658
4146
  TableCell2,
3659
4147
  {
3660
4148
  sortDirection: sortDirection != null ? sortDirection : false,
@@ -3667,7 +4155,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3667
4155
  maxWidth: getListFieldWidthPx(field)
3668
4156
  },
3669
4157
  onClick: isSortable ? () => controller.toggleSort(fieldName) : void 0,
3670
- children: isSortable ? /* @__PURE__ */ jsx20(
4158
+ children: isSortable ? /* @__PURE__ */ jsx21(
3671
4159
  TableSortLabel,
3672
4160
  {
3673
4161
  active: Boolean(sortDirection),
@@ -3681,7 +4169,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3681
4169
  },
3682
4170
  children: (_a2 = field == null ? void 0 : field.label) != null ? _a2 : fieldName
3683
4171
  }
3684
- ) : /* @__PURE__ */ jsx20(Typography6, { component: "span", sx: {
4172
+ ) : /* @__PURE__ */ jsx21(Typography6, { component: "span", sx: {
3685
4173
  fontSize: 14,
3686
4174
  fontWeight: 700,
3687
4175
  color: "rgba(255, 255, 255, 0.96)"
@@ -3690,7 +4178,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3690
4178
  fieldName
3691
4179
  );
3692
4180
  }),
3693
- /* @__PURE__ */ jsx20(
4181
+ /* @__PURE__ */ jsx21(
3694
4182
  TableCell2,
3695
4183
  {
3696
4184
  align: "right",
@@ -3703,9 +4191,9 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3703
4191
  }
3704
4192
  )
3705
4193
  ] }) }),
3706
- /* @__PURE__ */ jsx20(TableBody, { children: controller.rows.map((row) => {
4194
+ /* @__PURE__ */ jsx21(TableBody, { children: controller.rows.map((row) => {
3707
4195
  const rowId = row[meta.pk_field];
3708
- return /* @__PURE__ */ jsx20(
4196
+ return /* @__PURE__ */ jsx21(
3709
4197
  ListRow,
3710
4198
  {
3711
4199
  row,
@@ -3725,7 +4213,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3725
4213
  ] }) })
3726
4214
  }
3727
4215
  ),
3728
- !isMobile && controller.hasListFilters ? /* @__PURE__ */ jsx20(
4216
+ !isMobile && controller.hasListFilters ? /* @__PURE__ */ jsx21(
3729
4217
  ListFiltersSidebar,
3730
4218
  {
3731
4219
  client,
@@ -3738,14 +4226,14 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3738
4226
  }
3739
4227
  ) : null
3740
4228
  ] }),
3741
- /* @__PURE__ */ jsx20(
4229
+ /* @__PURE__ */ jsx21(
3742
4230
  Menu,
3743
4231
  {
3744
4232
  anchorEl: controller.bulkActionMenuAnchor,
3745
4233
  open: Boolean(controller.bulkActionMenuAnchor),
3746
4234
  onClose: controller.handleCloseBulkActionMenu,
3747
- children: controller.bulkActions.map((action) => /* @__PURE__ */ jsx20(
3748
- MenuItem2,
4235
+ children: controller.bulkActions.map((action) => /* @__PURE__ */ jsx21(
4236
+ MenuItem3,
3749
4237
  {
3750
4238
  onClick: () => void controller.handleRunNamedBulkAction(action.slug),
3751
4239
  children: action.label
@@ -3754,14 +4242,14 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3754
4242
  ))
3755
4243
  }
3756
4244
  ),
3757
- /* @__PURE__ */ jsx20(
4245
+ /* @__PURE__ */ jsx21(
3758
4246
  Menu,
3759
4247
  {
3760
4248
  anchorEl: controller.rowActionMenuAnchor,
3761
4249
  open: Boolean(controller.rowActionMenuAnchor),
3762
4250
  onClose: controller.handleCloseRowMenu,
3763
- children: /* @__PURE__ */ jsx20(
3764
- MenuItem2,
4251
+ children: /* @__PURE__ */ jsx21(
4252
+ MenuItem3,
3765
4253
  {
3766
4254
  onClick: () => {
3767
4255
  if (controller.rowActionMenuId !== null) {
@@ -3773,7 +4261,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3773
4261
  )
3774
4262
  }
3775
4263
  ),
3776
- /* @__PURE__ */ jsx20(
4264
+ /* @__PURE__ */ jsx21(
3777
4265
  FormDialog,
3778
4266
  {
3779
4267
  open: controller.createOpen,
@@ -3786,8 +4274,24 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3786
4274
  client
3787
4275
  }
3788
4276
  ),
3789
- /* @__PURE__ */ jsxs13(
3790
- 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,
3791
4295
  {
3792
4296
  open: controller.filtersOpen,
3793
4297
  onClose: () => controller.setFiltersOpen(false),
@@ -3807,8 +4311,8 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3807
4311
  }
3808
4312
  },
3809
4313
  children: [
3810
- /* @__PURE__ */ jsx20(DialogTitle3, { children: t("filters") }),
3811
- /* @__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(
3812
4316
  ListFiltersSidebar,
3813
4317
  {
3814
4318
  client,
@@ -3823,7 +4327,7 @@ function ModelPage({ client, basePath, slug, router, renderBeforePagination }) {
3823
4327
  ]
3824
4328
  }
3825
4329
  ),
3826
- /* @__PURE__ */ jsx20(
4330
+ /* @__PURE__ */ jsx21(
3827
4331
  DeletePreviewDialog,
3828
4332
  {
3829
4333
  open: controller.deletePreviewOpen,
@@ -3859,16 +4363,16 @@ function resolveFieldSortable(field) {
3859
4363
  import { useLayoutEffect as useLayoutEffect5 } from "react";
3860
4364
  import ArrowBackIcon from "@mui/icons-material/ArrowBack";
3861
4365
  import MoreVertIcon2 from "@mui/icons-material/MoreVert";
3862
- 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";
3863
- import { LocalizationProvider as LocalizationProvider2 } from "@mui/x-date-pickers";
3864
- 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";
3865
4369
  import { useTheme as useTheme4 } from "@mui/material/styles";
3866
4370
  import "dayjs/locale/en.js";
3867
4371
  import "dayjs/locale/ru.js";
3868
4372
 
3869
4373
  // src/components/object-page/ObjectField.tsx
3870
4374
  import { memo as memo6, useCallback as useCallback6 } from "react";
3871
- import { jsx as jsx21 } from "react/jsx-runtime";
4375
+ import { jsx as jsx22 } from "react/jsx-runtime";
3872
4376
  var ObjectField = memo6(function ObjectField2({
3873
4377
  field,
3874
4378
  value,
@@ -3879,7 +4383,7 @@ var ObjectField = memo6(function ObjectField2({
3879
4383
  const handleChange = useCallback6((nextValue) => {
3880
4384
  onFieldChange(field.name, nextValue);
3881
4385
  }, [field.name, onFieldChange]);
3882
- return /* @__PURE__ */ jsx21(
4386
+ return /* @__PURE__ */ jsx22(
3883
4387
  FieldEditor,
3884
4388
  {
3885
4389
  field,
@@ -3892,20 +4396,20 @@ var ObjectField = memo6(function ObjectField2({
3892
4396
  });
3893
4397
 
3894
4398
  // src/components/object-page/ObjectPageSkeleton.tsx
3895
- import { Box as Box11, Paper as Paper8, Skeleton as Skeleton4, Stack as Stack11 } from "@mui/material";
3896
- 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";
3897
4401
  function ObjectPageSkeleton() {
3898
- return /* @__PURE__ */ jsxs14(Stack11, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
3899
- /* @__PURE__ */ jsx22(MainHeaderSkeleton, { titleWidth: 420, subtitleWidth: "32%" }),
3900
- /* @__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(
3901
4405
  Stack11,
3902
4406
  {
3903
4407
  direction: { xs: "column", lg: "row" },
3904
4408
  spacing: 1.5,
3905
4409
  sx: { flex: 1, minHeight: 0, alignItems: "stretch" },
3906
4410
  children: [
3907
- /* @__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)) }) }) }),
3908
- /* @__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(
3909
4413
  Paper8,
3910
4414
  {
3911
4415
  sx: {
@@ -3915,10 +4419,10 @@ function ObjectPageSkeleton() {
3915
4419
  p: 1.5,
3916
4420
  alignSelf: "flex-start"
3917
4421
  },
3918
- children: /* @__PURE__ */ jsxs14(Stack11, { spacing: 1, children: [
3919
- /* @__PURE__ */ jsx22(Skeleton4, { variant: "text", width: 90, height: 28 }),
3920
- /* @__PURE__ */ jsx22(Skeleton4, { variant: "rounded", width: "100%", height: 40 }),
3921
- /* @__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 })
3922
4426
  ] })
3923
4427
  }
3924
4428
  )
@@ -3930,8 +4434,8 @@ function ObjectPageSkeleton() {
3930
4434
 
3931
4435
  // src/components/object-page/ReadonlyObjectField.tsx
3932
4436
  import { memo as memo7 } from "react";
3933
- import { Box as Box12, Stack as Stack12, TextField as TextField4 } from "@mui/material";
3934
- 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";
3935
4439
  var ReadonlyObjectField = memo7(function ReadonlyObjectField2({
3936
4440
  field,
3937
4441
  value,
@@ -3939,9 +4443,9 @@ var ReadonlyObjectField = memo7(function ReadonlyObjectField2({
3939
4443
  }) {
3940
4444
  var _a;
3941
4445
  const isMultiline = field.input_kind === "textarea" || field.input_kind === "json" || field.type.toLowerCase().includes("text") || value.includes("\n") || value.length > 120;
3942
- return /* @__PURE__ */ jsxs15(Stack12, { spacing: 1, children: [
3943
- imageUrl ? /* @__PURE__ */ jsx23(
3944
- Box12,
4446
+ return /* @__PURE__ */ jsxs16(Stack12, { spacing: 1, children: [
4447
+ imageUrl ? /* @__PURE__ */ jsx24(
4448
+ Box13,
3945
4449
  {
3946
4450
  component: "img",
3947
4451
  src: imageUrl,
@@ -3957,7 +4461,7 @@ var ReadonlyObjectField = memo7(function ReadonlyObjectField2({
3957
4461
  }
3958
4462
  }
3959
4463
  ) : null,
3960
- /* @__PURE__ */ jsx23(
4464
+ /* @__PURE__ */ jsx24(
3961
4465
  TextField4,
3962
4466
  {
3963
4467
  label: field.label,
@@ -3974,7 +4478,7 @@ var ReadonlyObjectField = memo7(function ReadonlyObjectField2({
3974
4478
  });
3975
4479
 
3976
4480
  // src/components/object-page/useObjectPageController.ts
3977
- import { useCallback as useCallback7, useLayoutEffect as useLayoutEffect4, useMemo as useMemo10, useState as useState11 } from "react";
4481
+ import { useCallback as useCallback7, useLayoutEffect as useLayoutEffect4, useMemo as useMemo10, useState as useState12 } from "react";
3978
4482
 
3979
4483
  // src/utils/isDeepEqual.ts
3980
4484
  function isDeepEqual(left, right) {
@@ -4016,28 +4520,29 @@ function useObjectPageController({
4016
4520
  var _a, _b, _c;
4017
4521
  const message = useAdminMessage();
4018
4522
  const cacheKey = buildDetailCacheKey(slug, id);
4019
- const [data, setData] = useState11(() => {
4523
+ const [data, setData] = useState12(() => {
4020
4524
  var _a2;
4021
4525
  return (_a2 = getClientCacheBucket(client).detailResponseCache.get(cacheKey)) != null ? _a2 : null;
4022
4526
  });
4023
- const [values, setValues] = useState11(() => {
4527
+ const [values, setValues] = useState12(() => {
4024
4528
  var _a2, _b2;
4025
4529
  return (_b2 = (_a2 = getClientCacheBucket(client).detailResponseCache.get(cacheKey)) == null ? void 0 : _a2.item) != null ? _b2 : {};
4026
4530
  });
4027
- const [initialValues, setInitialValues] = useState11(() => {
4531
+ const [initialValues, setInitialValues] = useState12(() => {
4028
4532
  var _a2, _b2;
4029
4533
  return (_b2 = (_a2 = getClientCacheBucket(client).detailResponseCache.get(cacheKey)) == null ? void 0 : _a2.item) != null ? _b2 : {};
4030
4534
  });
4031
- const [error, setError] = useState11(null);
4032
- const [isLoading, setIsLoading] = useState11(data === null);
4033
- const [isSaving, setIsSaving] = useState11(false);
4034
- const [isDeleting, setIsDeleting] = useState11(false);
4035
- const [activeActionSlug, setActiveActionSlug] = useState11(null);
4036
- const [deleteConfirmOpen, setDeleteConfirmOpen] = useState11(false);
4037
- const [deletePreview, setDeletePreview] = useState11(null);
4038
- const [isDeletePreviewLoading, setIsDeletePreviewLoading] = useState11(false);
4039
- const [deletePreviewError, setDeletePreviewError] = useState11(null);
4040
- const [actionsAnchorEl, setActionsAnchorEl] = useState11(null);
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);
4041
4546
  useLayoutEffect4(() => {
4042
4547
  var _a2;
4043
4548
  let isMounted = true;
@@ -4108,6 +4613,13 @@ function useObjectPageController({
4108
4613
  [data, id, meta]
4109
4614
  );
4110
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
+ );
4111
4623
  const currentPayload = useMemo10(
4112
4624
  () => buildAdminPayload(values, editableFields),
4113
4625
  [editableFields, values]
@@ -4171,7 +4683,13 @@ function useObjectPageController({
4171
4683
  router.push(listPath);
4172
4684
  }, [listPath, router]);
4173
4685
  const handleRunObjectAction = useCallback7(async (actionSlug) => {
4174
- 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
+ }
4175
4693
  setActiveActionSlug(actionSlug);
4176
4694
  setError(null);
4177
4695
  try {
@@ -4184,7 +4702,7 @@ function useObjectPageController({
4184
4702
  setData(nextDetail);
4185
4703
  setValues(response.item);
4186
4704
  setInitialValues(response.item);
4187
- 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;
4188
4706
  message.success(t("action_success", { action: actionLabel, count: 1 }));
4189
4707
  } catch (reason) {
4190
4708
  const nextError = reason instanceof Error ? reason.message : t("object_action_error");
@@ -4194,6 +4712,33 @@ function useObjectPageController({
4194
4712
  setActiveActionSlug(null);
4195
4713
  }
4196
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
+ }, []);
4197
4742
  const handleOpenDeletePreview = useCallback7(async () => {
4198
4743
  setActionsAnchorEl(null);
4199
4744
  setDeleteConfirmOpen(true);
@@ -4212,6 +4757,7 @@ function useObjectPageController({
4212
4757
  return {
4213
4758
  actionsAnchorEl,
4214
4759
  activeActionSlug,
4760
+ activeObjectAction,
4215
4761
  data,
4216
4762
  deleteConfirmOpen,
4217
4763
  deletePreview,
@@ -4226,6 +4772,8 @@ function useObjectPageController({
4226
4772
  handleOpenDeletePreview,
4227
4773
  handleRunObjectAction,
4228
4774
  handleSave,
4775
+ handleCloseObjectActionForm,
4776
+ handleSubmitObjectActionForm,
4229
4777
  initialValues,
4230
4778
  isActionsMenuOpen,
4231
4779
  isDeletePreviewLoading,
@@ -4245,9 +4793,9 @@ function useObjectPageController({
4245
4793
  }
4246
4794
 
4247
4795
  // src/components/ObjectPage.tsx
4248
- import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
4796
+ import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
4249
4797
  function ObjectPage({ client, slug, id, router }) {
4250
- var _a, _b;
4798
+ var _a, _b, _c;
4251
4799
  const locale = useAdminLocale();
4252
4800
  const t = useAdminTranslation();
4253
4801
  const resolvedRouter = useAdminRouter(router);
@@ -4282,223 +4830,251 @@ function ObjectPage({ client, slug, id, router }) {
4282
4830
  }, [controller.error, controller.isLoading, controller.meta, finishPendingNavigation, pathname, pendingPath, slug]);
4283
4831
  useAdminDocumentTitle(t("admin_title"), (_b = (_a = controller.meta) == null ? void 0 : _a.title) != null ? _b : slug, controller.objectTitle);
4284
4832
  if (controller.isLoading && !controller.data) {
4285
- return /* @__PURE__ */ jsx24(ObjectPageSkeleton, {});
4833
+ return /* @__PURE__ */ jsx25(ObjectPageSkeleton, {});
4286
4834
  }
4287
4835
  if (controller.error && !controller.data) {
4288
- return /* @__PURE__ */ jsx24(Alert6, { severity: "error", children: controller.error });
4836
+ return /* @__PURE__ */ jsx25(Alert7, { severity: "error", children: controller.error });
4289
4837
  }
4290
4838
  if (!controller.data || !controller.meta) {
4291
- return /* @__PURE__ */ jsx24(ObjectPageSkeleton, {});
4839
+ return /* @__PURE__ */ jsx25(ObjectPageSkeleton, {});
4292
4840
  }
4293
- return /* @__PURE__ */ jsx24(AdminRouterProvider, { router: resolvedRouter, children: /* @__PURE__ */ jsxs16(LocalizationProvider2, { dateAdapter: AdapterDayjs2, adapterLocale: locale, children: [
4294
- /* @__PURE__ */ jsxs16(Stack13, { spacing: 1.5, sx: { height: "100%", minHeight: 0 }, children: [
4295
- /* @__PURE__ */ jsx24(
4296
- MainHeader,
4297
- {
4298
- title: controller.objectTitle,
4299
- subtitle: controller.meta.slug,
4300
- beforeSubtitle: /* @__PURE__ */ jsx24(
4301
- 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,
4302
4851
  {
4303
- "aria-label": t("back"),
4304
- onClick: controller.handleNavigateBack,
4305
- size: "small",
4306
- sx: { ml: -0.5 },
4307
- 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
4308
4876
  }
4309
4877
  ),
4310
- actions: isPhone ? /* @__PURE__ */ jsx24(
4311
- IconButton4,
4878
+ /* @__PURE__ */ jsxs17(
4879
+ Stack13,
4312
4880
  {
4313
- "aria-label": t("actions"),
4314
- onClick: (event) => controller.setActionsAnchorEl(event.currentTarget),
4315
- size: "small",
4316
- sx: { mr: -0.5 },
4317
- children: /* @__PURE__ */ jsx24(MoreVertIcon2, { fontSize: "small" })
4318
- }
4319
- ) : void 0,
4320
- details: controller.meta.description ? /* @__PURE__ */ jsx24(Typography7, { color: "text.secondary", sx: { fontSize: 14, lineHeight: 1.45 }, children: controller.meta.description }) : void 0,
4321
- error: controller.error
4322
- }
4323
- ),
4324
- /* @__PURE__ */ jsxs16(
4325
- Stack13,
4326
- {
4327
- direction: { xs: "column", lg: "row" },
4328
- spacing: 1.5,
4329
- sx: { flex: 1, minHeight: 0, alignItems: "stretch" },
4330
- children: [
4331
- /* @__PURE__ */ jsx24(
4332
- Paper9,
4333
- {
4334
- sx: {
4335
- borderRadius: "10px",
4336
- flex: 1,
4337
- minHeight: 0,
4338
- overflow: "hidden"
4339
- },
4340
- 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) => {
4341
- const field = controller.fieldMap.get(fieldName);
4342
- if (!field) {
4343
- return null;
4344
- }
4345
- if (controller.editableFieldNames.has(fieldName)) {
4346
- return /* @__PURE__ */ jsx24(
4347
- ObjectField,
4348
- {
4349
- field,
4350
- value: controller.values[field.name],
4351
- slug,
4352
- client,
4353
- onFieldChange: controller.handleFieldChange
4354
- },
4355
- field.name
4356
- );
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
+ }) }) })
4357
4926
  }
4358
- return /* @__PURE__ */ jsx24(
4359
- ReadonlyObjectField,
4360
- {
4361
- field,
4362
- value: formatAdminValue(controller.values[field.name], {
4363
- locale,
4364
- field,
4365
- pretty: true
4366
- }),
4367
- 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
4368
4940
  },
4369
- field.name
4370
- );
4371
- }) }) })
4372
- }
4373
- ),
4374
- /* @__PURE__ */ jsx24(
4375
- Paper9,
4376
- {
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: {
4377
4987
  sx: {
4378
- width: { xs: "100%", lg: 280 },
4379
- flexShrink: 0,
4380
- borderRadius: "10px",
4381
- p: 1.5,
4382
- alignSelf: "flex-start",
4383
- position: { lg: "sticky" },
4384
- top: { lg: 0 },
4385
- 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
4386
5024
  },
4387
- children: /* @__PURE__ */ jsxs16(Stack13, { spacing: 1, children: [
4388
- /* @__PURE__ */ jsx24(Typography7, { variant: "subtitle2", color: "text.secondary", children: t("actions") }),
4389
- controller.isDirty ? /* @__PURE__ */ jsx24(
4390
- Button5,
4391
- {
4392
- variant: "contained",
4393
- onClick: () => void controller.handleSave(),
4394
- disabled: controller.isSaving,
4395
- children: controller.isSaving ? t("saving") : t("save")
4396
- }
4397
- ) : null,
4398
- /* @__PURE__ */ jsx24(
4399
- Button5,
4400
- {
4401
- variant: "outlined",
4402
- color: "error",
4403
- onClick: () => void controller.handleOpenDeletePreview(),
4404
- disabled: controller.isDeleting,
4405
- children: t("delete")
4406
- }
4407
- ),
4408
- controller.objectActions.map((action) => /* @__PURE__ */ jsx24(
4409
- Button5,
4410
- {
4411
- variant: "outlined",
4412
- onClick: () => void controller.handleRunObjectAction(action.slug),
4413
- disabled: controller.activeActionSlug !== null,
4414
- children: controller.activeActionSlug === action.slug ? t("executing") : action.label
4415
- },
4416
- action.slug
4417
- ))
4418
- ] })
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;
4419
5042
  }
4420
- )
4421
- ]
4422
- }
4423
- )
4424
- ] }),
4425
- /* @__PURE__ */ jsxs16(
4426
- Menu2,
4427
- {
4428
- anchorEl: controller.actionsAnchorEl,
4429
- open: controller.isActionsMenuOpen,
4430
- onClose: () => controller.setActionsAnchorEl(null),
4431
- slotProps: {
4432
- paper: {
4433
- sx: {
4434
- minWidth: 220
4435
- }
5043
+ controller.setDeleteConfirmOpen(false);
5044
+ controller.setDeletePreview(null);
5045
+ controller.setDeletePreviewError(null);
5046
+ },
5047
+ onConfirm: () => void controller.handleDelete()
4436
5048
  }
4437
- },
4438
- anchorOrigin: { vertical: "bottom", horizontal: "right" },
4439
- transformOrigin: { vertical: "top", horizontal: "right" },
4440
- children: [
4441
- controller.isDirty ? /* @__PURE__ */ jsx24(
4442
- MenuItem3,
4443
- {
4444
- onClick: () => {
4445
- controller.setActionsAnchorEl(null);
4446
- void controller.handleSave();
4447
- },
4448
- disabled: controller.isSaving,
4449
- children: controller.isSaving ? t("saving") : t("save")
4450
- }
4451
- ) : null,
4452
- /* @__PURE__ */ jsx24(
4453
- MenuItem3,
4454
- {
4455
- onClick: () => void controller.handleOpenDeletePreview(),
4456
- disabled: controller.isDeleting,
4457
- sx: { color: "error.main" },
4458
- children: t("delete")
4459
- }
4460
- ),
4461
- controller.objectActions.map((action) => /* @__PURE__ */ jsx24(
4462
- MenuItem3,
4463
- {
4464
- onClick: () => {
4465
- controller.setActionsAnchorEl(null);
4466
- void controller.handleRunObjectAction(action.slug);
4467
- },
4468
- disabled: controller.activeActionSlug !== null,
4469
- 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
4470
5066
  },
4471
- action.slug
4472
- ))
4473
- ]
4474
- }
4475
- ),
4476
- /* @__PURE__ */ jsx24(
4477
- DeletePreviewDialog,
4478
- {
4479
- open: controller.deleteConfirmOpen,
4480
- title: t("delete_object_title"),
4481
- preview: controller.deletePreview,
4482
- error: controller.deletePreviewError,
4483
- isLoading: controller.isDeletePreviewLoading,
4484
- isSubmitting: controller.isDeleting,
4485
- onClose: () => {
4486
- if (controller.isDeleting) {
4487
- return;
5067
+ onSubmit: controller.handleSubmitObjectActionForm
4488
5068
  }
4489
- controller.setDeleteConfirmOpen(false);
4490
- controller.setDeletePreview(null);
4491
- controller.setDeletePreviewError(null);
4492
- },
4493
- onConfirm: () => void controller.handleDelete()
4494
- }
4495
- )
4496
- ] }) });
5069
+ ) : null
5070
+ ]
5071
+ }
5072
+ ) });
4497
5073
  }
4498
5074
 
4499
5075
  // src/components/Shell.tsx
4500
- import { useEffect as useEffect11, useMemo as useMemo11, useState as useState12 } from "react";
4501
- 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";
4502
5078
  import { ThemeProvider } from "@mui/material/styles";
4503
5079
 
4504
5080
  // src/theme/defaultAdminTheme.ts
@@ -4629,14 +5205,14 @@ var defaultAdminTheme = createTheme({
4629
5205
  });
4630
5206
 
4631
5207
  // src/components/layout/Main.tsx
4632
- import { Box as Box14 } from "@mui/material";
4633
- 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";
4634
5210
  function Main({ children }) {
4635
5211
  useAdminLocation();
4636
5212
  const { pendingPath, pendingView } = useShellContext();
4637
5213
  const isPendingNavigation = pendingPath !== null;
4638
- return /* @__PURE__ */ jsxs17(
4639
- Box14,
5214
+ return /* @__PURE__ */ jsxs18(
5215
+ Box15,
4640
5216
  {
4641
5217
  sx: {
4642
5218
  flex: 1,
@@ -4649,8 +5225,8 @@ function Main({ children }) {
4649
5225
  },
4650
5226
  children: [
4651
5227
  children,
4652
- isPendingNavigation ? /* @__PURE__ */ jsx25(
4653
- Box14,
5228
+ isPendingNavigation ? /* @__PURE__ */ jsx26(
5229
+ Box15,
4654
5230
  {
4655
5231
  sx: {
4656
5232
  position: "absolute",
@@ -4658,7 +5234,7 @@ function Main({ children }) {
4658
5234
  zIndex: 5,
4659
5235
  backgroundColor: "background.default"
4660
5236
  },
4661
- children: pendingView === "model" || pendingView === "overview" ? /* @__PURE__ */ jsx25(ModelPageSkeleton, {}) : /* @__PURE__ */ jsx25(ModelPageSkeleton, {})
5237
+ children: pendingView === "model" || pendingView === "overview" ? /* @__PURE__ */ jsx26(ModelPageSkeleton, {}) : /* @__PURE__ */ jsx26(ModelPageSkeleton, {})
4662
5238
  }
4663
5239
  ) : null
4664
5240
  ]
@@ -4667,14 +5243,24 @@ function Main({ children }) {
4667
5243
  }
4668
5244
 
4669
5245
  // src/components/layout/Sidebar.tsx
4670
- import { memo as memo8 } from "react";
4671
- import { Box as Box15, ListItemButton as ListItemButton3, Typography as Typography8 } from "@mui/material";
4672
- 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
+ }
4673
5258
  var Sidebar = memo8(function Sidebar2({ models, blocks, basePath }) {
4674
5259
  var _a;
4675
5260
  const t = useAdminTranslation();
4676
5261
  const { pathname } = useAdminLocation();
4677
5262
  const { pendingPath, startPendingNavigation } = useShellContext();
5263
+ const scrollContainerRef = useRef7(null);
4678
5264
  const effectivePathname = pendingPath != null ? pendingPath : pathname;
4679
5265
  const normalizedBasePath = basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
4680
5266
  const fallbackBasePath = normalizedBasePath.replace(/^\/(ru|en)(?=\/|$)/, "") || "/";
@@ -4682,9 +5268,80 @@ var Sidebar = memo8(function Sidebar2({ models, blocks, basePath }) {
4682
5268
  const relativePath = matchedBasePath ? effectivePathname.slice(matchedBasePath.length) : "";
4683
5269
  const activeModelSlug = (_a = relativePath.split("/").filter(Boolean)[0]) != null ? _a : null;
4684
5270
  const isOverviewActive = matchedBasePath !== null && (effectivePathname === matchedBasePath || effectivePathname === `${matchedBasePath}/`);
4685
- return /* @__PURE__ */ jsx26(Box15, { sx: { height: "100%", overflow: "hidden" }, children: /* @__PURE__ */ jsx26(
4686
- 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,
4687
5343
  {
5344
+ ref: scrollContainerRef,
4688
5345
  sx: {
4689
5346
  height: "100%",
4690
5347
  overflowY: "scroll",
@@ -4694,14 +5351,14 @@ var Sidebar = memo8(function Sidebar2({ models, blocks, basePath }) {
4694
5351
  ml: 0,
4695
5352
  pl: 0
4696
5353
  },
4697
- children: /* @__PURE__ */ jsxs18(Box15, { sx: { direction: "ltr", pl: 1 }, children: [
4698
- /* @__PURE__ */ jsx26(
5354
+ children: /* @__PURE__ */ jsxs19(Box16, { sx: { direction: "ltr", pl: 1 }, children: [
5355
+ /* @__PURE__ */ jsx27(
4699
5356
  NavLink,
4700
5357
  {
4701
5358
  href: basePath,
4702
5359
  style: { textDecoration: "none", display: "block" },
4703
5360
  onClick: () => startPendingNavigation(basePath, "overview"),
4704
- children: /* @__PURE__ */ jsx26(
5361
+ children: /* @__PURE__ */ jsx27(
4705
5362
  ListItemButton3,
4706
5363
  {
4707
5364
  selected: isOverviewActive,
@@ -4714,12 +5371,12 @@ var Sidebar = memo8(function Sidebar2({ models, blocks, basePath }) {
4714
5371
  backgroundColor: isOverviewActive ? "rgba(255, 255, 255, 0.2)" : "rgba(255, 255, 255, 0.055)"
4715
5372
  }
4716
5373
  },
4717
- 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") })
4718
5375
  }
4719
5376
  )
4720
5377
  }
4721
5378
  ),
4722
- /* @__PURE__ */ jsx26(
5379
+ /* @__PURE__ */ jsx27(
4723
5380
  ModelsBlocks,
4724
5381
  {
4725
5382
  models,
@@ -4736,7 +5393,7 @@ var Sidebar = memo8(function Sidebar2({ models, blocks, basePath }) {
4736
5393
  });
4737
5394
 
4738
5395
  // src/components/Shell.tsx
4739
- import { jsx as jsx27, jsxs as jsxs19 } from "react/jsx-runtime";
5396
+ import { jsx as jsx28, jsxs as jsxs20 } from "react/jsx-runtime";
4740
5397
  function normalizeAdminPath(path) {
4741
5398
  const normalizedPath = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
4742
5399
  return normalizedPath.replace(/^\/(ru|en)(?=\/|$)/, "") || "/";
@@ -4748,15 +5405,15 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4748
5405
  const location = useAdminLocation(resolvedRouter);
4749
5406
  const pathname = location.pathname;
4750
5407
  const isDesktopSidebar = useMediaQuery4(activeTheme.breakpoints.up("lg"));
4751
- const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState12(false);
4752
- const [pendingPath, setPendingPath] = useState12(null);
4753
- const [pendingView, setPendingView] = useState12(null);
4754
- useEffect11(() => {
5408
+ const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState13(false);
5409
+ const [pendingPath, setPendingPath] = useState13(null);
5410
+ const [pendingView, setPendingView] = useState13(null);
5411
+ useEffect14(() => {
4755
5412
  if (isDesktopSidebar) {
4756
5413
  setIsMobileSidebarOpen(false);
4757
5414
  }
4758
5415
  }, [isDesktopSidebar]);
4759
- useEffect11(() => {
5416
+ useEffect14(() => {
4760
5417
  setIsMobileSidebarOpen(false);
4761
5418
  }, [pathname]);
4762
5419
  const shellContextValue = useMemo11(() => ({
@@ -4782,9 +5439,9 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4782
5439
  setPendingView(null);
4783
5440
  }
4784
5441
  }), [isDesktopSidebar, pathname, pendingPath, pendingView]);
4785
- 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: [
4786
- /* @__PURE__ */ jsx27(CssBaseline, {}),
4787
- /* @__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(
4788
5445
  GlobalStyles,
4789
5446
  {
4790
5447
  styles: (muiTheme) => ({
@@ -4823,8 +5480,8 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4823
5480
  })
4824
5481
  }
4825
5482
  ),
4826
- /* @__PURE__ */ jsx27(
4827
- Box16,
5483
+ /* @__PURE__ */ jsx28(
5484
+ Box17,
4828
5485
  {
4829
5486
  "data-xladmin-root": "true",
4830
5487
  sx: {
@@ -4834,15 +5491,15 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4834
5491
  backgroundColor: "background.default",
4835
5492
  backgroundImage: "none"
4836
5493
  },
4837
- children: /* @__PURE__ */ jsxs19(
5494
+ children: /* @__PURE__ */ jsxs20(
4838
5495
  Stack14,
4839
5496
  {
4840
5497
  direction: { xs: "column", lg: "row" },
4841
5498
  spacing: 0,
4842
5499
  sx: { height: "100%", minHeight: 0, alignItems: "stretch" },
4843
5500
  children: [
4844
- /* @__PURE__ */ jsx27(
4845
- Box16,
5501
+ /* @__PURE__ */ jsx28(
5502
+ Box17,
4846
5503
  {
4847
5504
  sx: {
4848
5505
  display: { xs: "none", lg: "block" },
@@ -4853,11 +5510,11 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4853
5510
  pl: 0,
4854
5511
  pr: 1
4855
5512
  },
4856
- children: /* @__PURE__ */ jsx27(Sidebar, { models, blocks, basePath })
5513
+ children: /* @__PURE__ */ jsx28(Sidebar, { models, blocks, basePath })
4857
5514
  }
4858
5515
  ),
4859
- /* @__PURE__ */ jsx27(
4860
- Box16,
5516
+ /* @__PURE__ */ jsx28(
5517
+ Box17,
4861
5518
  {
4862
5519
  sx: {
4863
5520
  flex: 1,
@@ -4870,7 +5527,7 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4870
5527
  py: { xs: 1, sm: 1.5, lg: 2 },
4871
5528
  pl: { xs: 1, sm: 1.5, lg: 1 }
4872
5529
  },
4873
- children: /* @__PURE__ */ jsx27(Main, { children })
5530
+ children: /* @__PURE__ */ jsx28(Main, { children })
4874
5531
  }
4875
5532
  )
4876
5533
  ]
@@ -4878,7 +5535,7 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4878
5535
  )
4879
5536
  }
4880
5537
  ),
4881
- /* @__PURE__ */ jsx27(
5538
+ /* @__PURE__ */ jsx28(
4882
5539
  Drawer,
4883
5540
  {
4884
5541
  anchor: "left",
@@ -4897,7 +5554,7 @@ function Shell({ client, models, blocks, basePath, locale, children, theme, rout
4897
5554
  }
4898
5555
  }
4899
5556
  },
4900
- 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 }) })
4901
5558
  }
4902
5559
  )
4903
5560
  ] }) }) }) }) }) });