@firecms/core 3.0.0-canary.285 → 3.0.0-canary.287

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.umd.js CHANGED
@@ -1052,6 +1052,12 @@
1052
1052
  };
1053
1053
  });
1054
1054
  };
1055
+ function getLocalChangesBackup(collection) {
1056
+ if (!collection.localChangesBackup) {
1057
+ return "manual_apply";
1058
+ }
1059
+ return collection.localChangesBackup;
1060
+ }
1055
1061
  const kebabCaseRegex = /[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g;
1056
1062
  const toKebabCase = (str) => {
1057
1063
  const regExpMatchArray = str.match(kebabCaseRegex);
@@ -9755,7 +9761,6 @@
9755
9761
  return value;
9756
9762
  }
9757
9763
  function saveEntityToCache(path, data) {
9758
- entityCache.set(path, data);
9759
9764
  if (isLocalStorageAvailable) {
9760
9765
  try {
9761
9766
  const key = LOCAL_STORAGE_PREFIX + path;
@@ -9766,17 +9771,22 @@
9766
9771
  }
9767
9772
  }
9768
9773
  }
9769
- function getEntityFromCache(path, useLocalStorage = true) {
9770
- if (entityCache.has(path)) {
9771
- return entityCache.get(path);
9772
- }
9773
- if (isLocalStorageAvailable && useLocalStorage) {
9774
+ function removeEntityFromMemoryCache(path) {
9775
+ entityCache.delete(path);
9776
+ }
9777
+ function saveEntityToMemoryCache(path, data) {
9778
+ entityCache.set(path, data);
9779
+ }
9780
+ function getEntityFromMemoryCache(path) {
9781
+ return entityCache.get(path);
9782
+ }
9783
+ function getEntityFromCache(path) {
9784
+ if (isLocalStorageAvailable) {
9774
9785
  try {
9775
9786
  const key = LOCAL_STORAGE_PREFIX + path;
9776
9787
  const entityString = localStorage.getItem(key);
9777
9788
  if (entityString) {
9778
9789
  const entity = JSON.parse(entityString, customReviver);
9779
- entityCache.set(path, entity);
9780
9790
  return entity;
9781
9791
  }
9782
9792
  } catch (error) {
@@ -9785,12 +9795,7 @@
9785
9795
  }
9786
9796
  return void 0;
9787
9797
  }
9788
- function hasEntityInCache(path) {
9789
- return entityCache.has(path);
9790
- }
9791
9798
  function removeEntityFromCache(path) {
9792
- console.debug("Removing entity from cache", path);
9793
- entityCache.delete(path);
9794
9799
  if (isLocalStorageAvailable) {
9795
9800
  try {
9796
9801
  const key = LOCAL_STORAGE_PREFIX + path;
@@ -9827,7 +9832,8 @@
9827
9832
  const hasCollapsedActions = actions.some((a) => a.collapsed || a.collapsed === void 0);
9828
9833
  const collapsedActions = actions.filter((a_0) => a_0.collapsed || a_0.collapsed === void 0);
9829
9834
  const uncollapsedActions = actions.filter((a_1) => a_1.collapsed === false);
9830
- const hasDraft = hasEntityInCache(fullPath + "/" + entity.id);
9835
+ const enableLocalChangesBackup = collection ? getLocalChangesBackup(collection) : false;
9836
+ const hasDraft = enableLocalChangesBackup ? getEntityFromCache(fullPath + "/" + entity.id) : false;
9831
9837
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("h-full flex items-center justify-center flex-col bg-surface-50 dark:bg-surface-900 bg-opacity-90 dark:bg-opacity-90 z-10", frozen ? "sticky left-0" : ""), onClick: React.useCallback((event) => {
9832
9838
  event.stopPropagation();
9833
9839
  }, []), style: {
@@ -15162,6 +15168,273 @@
15162
15168
  savingError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { color: "error", children: savingError.message }) })
15163
15169
  ] });
15164
15170
  }
15171
+ function LocalChangesMenu(t0) {
15172
+ const $ = reactCompilerRuntime.c(43);
15173
+ const {
15174
+ localChangesData,
15175
+ formex: formex$1,
15176
+ onClearLocalChanges,
15177
+ cacheKey,
15178
+ properties
15179
+ } = t0;
15180
+ const snackbarController = useSnackbarController();
15181
+ const [previewDialogOpen, setPreviewDialogOpen] = React.useState(false);
15182
+ const [open, setOpen] = React.useState(false);
15183
+ let t1;
15184
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
15185
+ t1 = () => {
15186
+ setOpen(true);
15187
+ };
15188
+ $[0] = t1;
15189
+ } else {
15190
+ t1 = $[0];
15191
+ }
15192
+ const handleOpenMenu = t1;
15193
+ let t2;
15194
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
15195
+ t2 = () => {
15196
+ setOpen(false);
15197
+ };
15198
+ $[1] = t2;
15199
+ } else {
15200
+ t2 = $[1];
15201
+ }
15202
+ const handleCloseMenu = t2;
15203
+ let t3;
15204
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
15205
+ t3 = () => {
15206
+ setPreviewDialogOpen(true);
15207
+ handleCloseMenu();
15208
+ };
15209
+ $[2] = t3;
15210
+ } else {
15211
+ t3 = $[2];
15212
+ }
15213
+ const handlePreview = t3;
15214
+ let t4;
15215
+ if ($[3] !== formex$1 || $[4] !== localChangesData || $[5] !== onClearLocalChanges || $[6] !== snackbarController) {
15216
+ t4 = () => {
15217
+ const mergedValues = mergeDeep(formex$1.values, localChangesData);
15218
+ const touched = {
15219
+ ...formex$1.touched
15220
+ };
15221
+ const newTouched = formex.flattenKeys(localChangesData);
15222
+ newTouched.forEach((key) => {
15223
+ touched[key] = true;
15224
+ });
15225
+ formex$1.setTouched(touched);
15226
+ formex$1.setValues(mergedValues);
15227
+ snackbarController.open({
15228
+ type: "info",
15229
+ message: "Local changes applied to the form"
15230
+ });
15231
+ handleCloseMenu();
15232
+ onClearLocalChanges?.();
15233
+ };
15234
+ $[3] = formex$1;
15235
+ $[4] = localChangesData;
15236
+ $[5] = onClearLocalChanges;
15237
+ $[6] = snackbarController;
15238
+ $[7] = t4;
15239
+ } else {
15240
+ t4 = $[7];
15241
+ }
15242
+ const handleApply = t4;
15243
+ let t5;
15244
+ if ($[8] !== cacheKey || $[9] !== onClearLocalChanges || $[10] !== snackbarController) {
15245
+ t5 = () => {
15246
+ removeEntityFromCache(cacheKey);
15247
+ snackbarController.open({
15248
+ type: "info",
15249
+ message: "Local changes discarded"
15250
+ });
15251
+ handleCloseMenu();
15252
+ onClearLocalChanges?.();
15253
+ };
15254
+ $[8] = cacheKey;
15255
+ $[9] = onClearLocalChanges;
15256
+ $[10] = snackbarController;
15257
+ $[11] = t5;
15258
+ } else {
15259
+ t5 = $[11];
15260
+ }
15261
+ const handleDiscard = t5;
15262
+ let t6;
15263
+ if ($[12] === Symbol.for("react.memo_cache_sentinel")) {
15264
+ t6 = /* @__PURE__ */ jsxRuntime.jsx(ui.WarningIcon, { size: "smallest", className: "mr-1 text-yellow-600 dark:text-yellow-400" });
15265
+ $[12] = t6;
15266
+ } else {
15267
+ t6 = $[12];
15268
+ }
15269
+ let t7;
15270
+ if ($[13] === Symbol.for("react.memo_cache_sentinel")) {
15271
+ t7 = /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", className: "font-semibold text-xs rounded-full px-4 py-1 bg-yellow-200 dark:bg-yellow-900 hover:bg-yellow-300 dark:hover:bg-yellow-800 text-yellow-800 dark:text-yellow-200", onClick: handleOpenMenu, children: [
15272
+ t6,
15273
+ "Unsaved Local changes",
15274
+ /* @__PURE__ */ jsxRuntime.jsx(ui.KeyboardArrowDownIcon, { size: "smallest" })
15275
+ ] });
15276
+ $[13] = t7;
15277
+ } else {
15278
+ t7 = $[13];
15279
+ }
15280
+ let t8;
15281
+ if ($[14] === Symbol.for("react.memo_cache_sentinel")) {
15282
+ t8 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-xs px-4 py-4 text-sm text-gray-700 dark:text-gray-300", children: "This document was edited locally and has unsaved changes." });
15283
+ $[14] = t8;
15284
+ } else {
15285
+ t8 = $[14];
15286
+ }
15287
+ let t9;
15288
+ if ($[15] === Symbol.for("react.memo_cache_sentinel")) {
15289
+ t9 = /* @__PURE__ */ jsxRuntime.jsxs(ui.MenuItem, { dense: true, onClick: handlePreview, children: [
15290
+ /* @__PURE__ */ jsxRuntime.jsx(ui.VisibilityIcon, { size: "small" }),
15291
+ "Preview Changes"
15292
+ ] });
15293
+ $[15] = t9;
15294
+ } else {
15295
+ t9 = $[15];
15296
+ }
15297
+ let t10;
15298
+ if ($[16] === Symbol.for("react.memo_cache_sentinel")) {
15299
+ t10 = /* @__PURE__ */ jsxRuntime.jsx(ui.CheckIcon, { size: "small" });
15300
+ $[16] = t10;
15301
+ } else {
15302
+ t10 = $[16];
15303
+ }
15304
+ let t11;
15305
+ if ($[17] !== handleApply) {
15306
+ t11 = /* @__PURE__ */ jsxRuntime.jsxs(ui.MenuItem, { dense: true, onClick: handleApply, children: [
15307
+ t10,
15308
+ "Apply Changes"
15309
+ ] });
15310
+ $[17] = handleApply;
15311
+ $[18] = t11;
15312
+ } else {
15313
+ t11 = $[18];
15314
+ }
15315
+ let t12;
15316
+ if ($[19] === Symbol.for("react.memo_cache_sentinel")) {
15317
+ t12 = /* @__PURE__ */ jsxRuntime.jsx(ui.CancelIcon, { size: "small" });
15318
+ $[19] = t12;
15319
+ } else {
15320
+ t12 = $[19];
15321
+ }
15322
+ let t13;
15323
+ if ($[20] !== handleDiscard) {
15324
+ t13 = /* @__PURE__ */ jsxRuntime.jsxs(ui.MenuItem, { dense: true, onClick: handleDiscard, children: [
15325
+ t12,
15326
+ "Discard Local Changes"
15327
+ ] });
15328
+ $[20] = handleDiscard;
15329
+ $[21] = t13;
15330
+ } else {
15331
+ t13 = $[21];
15332
+ }
15333
+ let t14;
15334
+ if ($[22] !== open || $[23] !== t11 || $[24] !== t13) {
15335
+ t14 = /* @__PURE__ */ jsxRuntime.jsxs(ui.Menu, { trigger: t7, open, onOpenChange: setOpen, children: [
15336
+ t8,
15337
+ t9,
15338
+ t11,
15339
+ t13
15340
+ ] });
15341
+ $[22] = open;
15342
+ $[23] = t11;
15343
+ $[24] = t13;
15344
+ $[25] = t14;
15345
+ } else {
15346
+ t14 = $[25];
15347
+ }
15348
+ let t15;
15349
+ let t16;
15350
+ if ($[26] === Symbol.for("react.memo_cache_sentinel")) {
15351
+ t15 = /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-2xl mb-4", children: "Preview Local Changes" });
15352
+ t16 = /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-4", children: "These are the local changes that will be applied to the form." });
15353
+ $[26] = t15;
15354
+ $[27] = t16;
15355
+ } else {
15356
+ t15 = $[26];
15357
+ t16 = $[27];
15358
+ }
15359
+ let t17;
15360
+ if ($[28] !== localChangesData || $[29] !== properties) {
15361
+ t17 = formex.flattenKeys(localChangesData).map((key_0) => {
15362
+ const value = formex.getIn(localChangesData, key_0);
15363
+ const property = getPropertyInPath(properties, key_0);
15364
+ if (!property) {
15365
+ return null;
15366
+ }
15367
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 gap-x-4 px-4 py-3 items-center", children: [
15368
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3 text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-gray-500 dark:text-gray-400 break-words", children: property.name || key_0 }) }),
15369
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-9", children: /* @__PURE__ */ jsxRuntime.jsx(PropertyPreview, { propertyKey: key_0, value, property, size: "small" }) })
15370
+ ] }, key_0);
15371
+ });
15372
+ $[28] = localChangesData;
15373
+ $[29] = properties;
15374
+ $[30] = t17;
15375
+ } else {
15376
+ t17 = $[30];
15377
+ }
15378
+ let t18;
15379
+ if ($[31] !== t17) {
15380
+ t18 = /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogContent, { children: [
15381
+ t15,
15382
+ t16,
15383
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `border rounded-lg divide-y divide-surface-200 divide-surface-opacity-40 dark:divide-surface-700 dark:divide-opacity-40 ${ui.defaultBorderMixin}`, children: t17 })
15384
+ ] });
15385
+ $[31] = t17;
15386
+ $[32] = t18;
15387
+ } else {
15388
+ t18 = $[32];
15389
+ }
15390
+ let t19;
15391
+ if ($[33] === Symbol.for("react.memo_cache_sentinel")) {
15392
+ t19 = /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { onClick: () => setPreviewDialogOpen(false), children: "Close" });
15393
+ $[33] = t19;
15394
+ } else {
15395
+ t19 = $[33];
15396
+ }
15397
+ let t20;
15398
+ if ($[34] !== handleApply) {
15399
+ t20 = /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogActions, { children: [
15400
+ t19,
15401
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "filled", onClick: () => {
15402
+ handleApply();
15403
+ setPreviewDialogOpen(false);
15404
+ }, children: "Apply changes" })
15405
+ ] });
15406
+ $[34] = handleApply;
15407
+ $[35] = t20;
15408
+ } else {
15409
+ t20 = $[35];
15410
+ }
15411
+ let t21;
15412
+ if ($[36] !== previewDialogOpen || $[37] !== t18 || $[38] !== t20) {
15413
+ t21 = /* @__PURE__ */ jsxRuntime.jsxs(ui.Dialog, { open: previewDialogOpen, onOpenChange: setPreviewDialogOpen, maxWidth: "4xl", children: [
15414
+ t18,
15415
+ t20
15416
+ ] });
15417
+ $[36] = previewDialogOpen;
15418
+ $[37] = t18;
15419
+ $[38] = t20;
15420
+ $[39] = t21;
15421
+ } else {
15422
+ t21 = $[39];
15423
+ }
15424
+ let t22;
15425
+ if ($[40] !== t14 || $[41] !== t21) {
15426
+ t22 = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
15427
+ t14,
15428
+ t21
15429
+ ] });
15430
+ $[40] = t14;
15431
+ $[41] = t21;
15432
+ $[42] = t22;
15433
+ } else {
15434
+ t22 = $[42];
15435
+ }
15436
+ return t22;
15437
+ }
15165
15438
  function extractTouchedValues(values, touched) {
15166
15439
  let acc = {};
15167
15440
  if (!touched || typeof touched !== "object") {
@@ -15249,6 +15522,12 @@
15249
15522
  const [entityIdError, setEntityIdError] = React.useState(false);
15250
15523
  const [savingError, setSavingError] = React.useState();
15251
15524
  const autoSave = collection.formAutoSave && !collection.customId;
15525
+ const baseInitialValues = React.useMemo(() => getInitialEntityValues(authController, collection, path, status, entity, customizationController.propertyConfigs), [authController, collection, path, status, entity, customizationController.propertyConfigs]);
15526
+ const localChangesDataRaw = React.useMemo(() => entityId ? getEntityFromCache(path + "/" + entityId) : getEntityFromCache(path + "#new"), [entityId, path]);
15527
+ const [localChangesCleared, setLocalChangesCleared] = React.useState(false);
15528
+ const localChangesBackup = getLocalChangesBackup(collection);
15529
+ const autoApplyLocalChanges = localChangesBackup === "auto_apply";
15530
+ const manualApplyLocalChanges = localChangesBackup === "manual_apply";
15252
15531
  const onSubmit = (values, formexController) => {
15253
15532
  if (mustSetCustomId && !entityId) {
15254
15533
  console.error("Missing custom Id");
@@ -15279,12 +15558,31 @@
15279
15558
  formexController.setSubmitting(false);
15280
15559
  });
15281
15560
  };
15282
- const baseInitialValues = getInitialEntityValues(authController, collection, path, status, entity, customizationController.propertyConfigs);
15283
- const initialValues = initialDirtyValues ? mergeDeep(baseInitialValues, initialDirtyValues) : baseInitialValues;
15284
- const initialDirty = Boolean(initialDirtyValues) && initialDirtyValues && Object.keys(initialDirtyValues).length > 0;
15561
+ const [initialValues_0, initialDirty_0] = React.useMemo(() => {
15562
+ const initialValuesWithLocalChanges = autoApplyLocalChanges && localChangesDataRaw ? mergeDeep(baseInitialValues, localChangesDataRaw) : baseInitialValues;
15563
+ const initialValues = initialDirtyValues ? mergeDeep(initialValuesWithLocalChanges, initialDirtyValues) : initialValuesWithLocalChanges;
15564
+ const initialDirty = Boolean(initialDirtyValues) && initialDirtyValues && Object.keys(initialDirtyValues).length > 0;
15565
+ return [initialValues, initialDirty];
15566
+ }, [autoApplyLocalChanges, localChangesDataRaw, baseInitialValues, initialDirtyValues]);
15567
+ const localChangesData = React.useMemo(() => {
15568
+ if (!localChangesDataRaw) {
15569
+ return void 0;
15570
+ }
15571
+ let filteredChanges = {};
15572
+ const flattenedKeys = formex.flattenKeys(localChangesDataRaw);
15573
+ flattenedKeys.forEach((key) => {
15574
+ const localValue = formex.getIn(localChangesDataRaw, key);
15575
+ const initialValue = formex.getIn(initialValues_0, key);
15576
+ if (!equal(localValue, initialValue)) {
15577
+ filteredChanges = formex.setIn(filteredChanges, key, localValue);
15578
+ }
15579
+ });
15580
+ return filteredChanges;
15581
+ }, [localChangesDataRaw, initialValues_0]);
15582
+ const hasLocalChanges = !localChangesCleared && localChangesData && Object.keys(localChangesData).length > 0;
15285
15583
  const formex$1 = formexProp ?? formex.useCreateFormex({
15286
- initialValues,
15287
- initialDirty,
15584
+ initialValues: initialValues_0,
15585
+ initialDirty: initialDirty_0,
15288
15586
  initialTouched: initialDirtyValues ? formex.flattenKeys(initialDirtyValues).reduce((previousValue, currentValue) => ({
15289
15587
  ...previousValue,
15290
15588
  [currentValue]: true
@@ -15292,13 +15590,13 @@
15292
15590
  onSubmit,
15293
15591
  onReset: () => {
15294
15592
  clearDirtyCache();
15295
- onValuesModified?.(false);
15593
+ onValuesModified?.(false, initialValues_0);
15296
15594
  },
15297
15595
  onValuesChangeDeferred: (values_0, controller) => {
15298
- const key = status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId;
15596
+ const key_0 = status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId;
15299
15597
  if (controller.dirty) {
15300
15598
  const touchedValues = extractTouchedValues(values_0, controller.touched);
15301
- saveEntityToCache(key, touchedValues);
15599
+ saveEntityToCache(key_0, touchedValues);
15302
15600
  }
15303
15601
  },
15304
15602
  validation: (values_1) => {
@@ -15351,14 +15649,16 @@
15351
15649
  }, [snackbarController]);
15352
15650
  function clearDirtyCache() {
15353
15651
  if (status === "new" || status === "copy") {
15652
+ removeEntityFromMemoryCache(path + "#new");
15354
15653
  removeEntityFromCache(path + "#new");
15355
15654
  } else {
15655
+ removeEntityFromMemoryCache(path + "/" + entityId);
15356
15656
  removeEntityFromCache(path + "/" + entityId);
15357
15657
  }
15358
15658
  }
15359
15659
  const onSaveSuccess = (updatedEntity) => {
15360
15660
  clearDirtyCache();
15361
- onValuesModified?.(false);
15661
+ onValuesModified?.(false, updatedEntity.values);
15362
15662
  if (!autoSave) snackbarController.open({
15363
15663
  type: "success",
15364
15664
  message: `${collection.singularName ?? collection.name}: Saved correctly`
@@ -15518,7 +15818,7 @@
15518
15818
  }, [doOnIdUpdate]);
15519
15819
  React.useEffect(() => {
15520
15820
  if (!autoSave) {
15521
- onValuesModified?.(modified);
15821
+ onValuesModified?.(modified, formex$1.values);
15522
15822
  }
15523
15823
  }, [formex$1.dirty]);
15524
15824
  const modified = formex$1.dirty;
@@ -15530,11 +15830,11 @@
15530
15830
  useOnAutoSave(autoSave, formex$1, lastSavedValues, save);
15531
15831
  React.useEffect(() => {
15532
15832
  if (!autoSave && !formex$1.isSubmitting && underlyingChanges && entity) {
15533
- Object.entries(underlyingChanges).forEach(([key_0, value_0]) => {
15534
- const formValue = formex$1.values[key_0];
15535
- if (!equal(value_0, formValue) && !formex$1.touched[key_0]) {
15536
- console.debug("Updated value from the datasource:", key_0, value_0);
15537
- formex$1.setFieldValue(key_0, value_0 !== void 0 ? value_0 : null);
15833
+ Object.entries(underlyingChanges).forEach(([key_1, value_0]) => {
15834
+ const formValue = formex$1.values[key_1];
15835
+ if (!equal(value_0, formValue) && !formex$1.touched[key_1]) {
15836
+ console.debug("Updated value from the datasource:", key_1, value_0);
15837
+ formex$1.setFieldValue(key_1, value_0 !== void 0 ? value_0 : null);
15538
15838
  }
15539
15839
  });
15540
15840
  }
@@ -15544,16 +15844,16 @@
15544
15844
  if (Builder) {
15545
15845
  return /* @__PURE__ */ jsxRuntime.jsx(Builder, { collection, entity, modifiedValues: formex$1.values, formContext });
15546
15846
  }
15547
- return /* @__PURE__ */ jsxRuntime.jsx(FormLayout, { children: formFieldKeys.map((key_1) => {
15548
- const property = resolvedCollection.properties[key_1];
15847
+ return /* @__PURE__ */ jsxRuntime.jsx(FormLayout, { children: formFieldKeys.map((key_2) => {
15848
+ const property = resolvedCollection.properties[key_2];
15549
15849
  if (property) {
15550
- const underlyingValueHasChanged = !!underlyingChanges && Object.keys(underlyingChanges).includes(key_1) && formex$1.touched[key_1];
15850
+ const underlyingValueHasChanged = !!underlyingChanges && Object.keys(underlyingChanges).includes(key_2) && formex$1.touched[key_2];
15551
15851
  const disabled_0 = disabledProp || !autoSave && formex$1.isSubmitting || isReadOnly(property) || Boolean(property.disabled);
15552
15852
  const hidden = isHidden(property);
15553
15853
  if (hidden) return null;
15554
15854
  const widthPercentage = property.widthPercentage ?? 100;
15555
15855
  const cmsFormFieldProps = {
15556
- propertyKey: key_1,
15856
+ propertyKey: key_2,
15557
15857
  disabled: disabled_0,
15558
15858
  property,
15559
15859
  includeDescription: property.description || property.longDescription,
@@ -15563,9 +15863,9 @@
15563
15863
  minimalistView: false,
15564
15864
  autoFocus: false
15565
15865
  };
15566
- return /* @__PURE__ */ jsxRuntime.jsx(FormEntry, { propertyKey: key_1, widthPercentage, children: /* @__PURE__ */ jsxRuntime.jsx(PropertyFieldBinding, { ...cmsFormFieldProps }) }, `field_${key_1}`);
15866
+ return /* @__PURE__ */ jsxRuntime.jsx(FormEntry, { propertyKey: key_2, widthPercentage, children: /* @__PURE__ */ jsxRuntime.jsx(PropertyFieldBinding, { ...cmsFormFieldProps }) }, `field_${key_2}`);
15567
15867
  }
15568
- const additionalField = resolvedCollection.additionalFields?.find((f) => f.key === key_1);
15868
+ const additionalField = resolvedCollection.additionalFields?.find((f) => f.key === key_2);
15569
15869
  if (additionalField && entity) {
15570
15870
  const Builder_0 = additionalField.Builder;
15571
15871
  if (!Builder_0 && !additionalField.value) {
@@ -15576,11 +15876,11 @@
15576
15876
  context
15577
15877
  })?.toString() });
15578
15878
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full", children: [
15579
- /* @__PURE__ */ jsxRuntime.jsx(LabelWithIconAndTooltip, { propertyKey: key_1, icon: /* @__PURE__ */ jsxRuntime.jsx(ui.NotesIcon, { size: "small" }), title: additionalField.name, className: "text-text-secondary dark:text-text-secondary-dark ml-3.5" }),
15879
+ /* @__PURE__ */ jsxRuntime.jsx(LabelWithIconAndTooltip, { propertyKey: key_2, icon: /* @__PURE__ */ jsxRuntime.jsx(ui.NotesIcon, { size: "small" }), title: additionalField.name, className: "text-text-secondary dark:text-text-secondary-dark ml-3.5" }),
15580
15880
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.cls(ui.paperMixin, "w-full min-h-14 p-4 md:p-6 overflow-x-scroll no-scrollbar"), children: /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary, { children: child }) })
15581
- ] }, `additional_${key_1}`);
15881
+ ] }, `additional_${key_2}`);
15582
15882
  }
15583
- console.warn(`Property ${key_1} not found in collection ${resolvedCollection.name} in properties or additional fields. Skipping.`);
15883
+ console.warn(`Property ${key_2} not found in collection ${resolvedCollection.name} in properties or additional fields. Skipping.`);
15584
15884
  return null;
15585
15885
  }).filter(Boolean) });
15586
15886
  };
@@ -15615,7 +15915,10 @@
15615
15915
  values: baseInitialValues
15616
15916
  }), noValidate: true, className: ui.cls("flex-1 flex flex-row w-full overflow-y-auto justify-center", className), children: [
15617
15917
  /* @__PURE__ */ jsxRuntime.jsx("div", { id: `form_${path}`, className: ui.cls("relative flex flex-row max-w-4xl lg:max-w-3xl xl:max-w-4xl 2xl:max-w-6xl w-full h-fit"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("flex flex-col w-full pt-12 pb-16 px-4 sm:px-8 md:px-10"), children: [
15618
- formex$1.dirty ? /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Local unsaved changes", className: "self-end sticky top-4 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Chip, { size: "small", colorScheme: "orangeDarker", children: /* @__PURE__ */ jsxRuntime.jsx(ui.EditIcon, { size: "smallest" }) }) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "In sync with the database", className: "self-end sticky top-4 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Chip, { size: "small", children: /* @__PURE__ */ jsxRuntime.jsx(ui.CheckIcon, { size: "smallest" }) }) }),
15918
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-row gap-4 self-end sticky top-4 z-10", children: [
15919
+ manualApplyLocalChanges && hasLocalChanges && /* @__PURE__ */ jsxRuntime.jsx(LocalChangesMenu, { cacheKey: status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId, properties: resolvedCollection.properties, localChangesData, formex: formex$1, onClearLocalChanges: () => setLocalChangesCleared(true) }),
15920
+ formex$1.dirty ? /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "There are local unsaved changes", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Chip, { size: "small", colorScheme: "orangeDarker", children: /* @__PURE__ */ jsxRuntime.jsx(ui.EditIcon, { size: "smallest" }) }) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "The current form is in sync with the database", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Chip, { size: "small", children: /* @__PURE__ */ jsxRuntime.jsx(ui.CheckIcon, { size: "smallest" }) }) })
15921
+ ] }),
15619
15922
  formView
15620
15923
  ] }) }),
15621
15924
  dialogActions
@@ -20425,7 +20728,7 @@
20425
20728
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "subtitle2", children: "So empty..." }),
20426
20729
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { color: "primary", variant: "outlined", onClick: onNewClick, className: "mt-4", children: [
20427
20730
  /* @__PURE__ */ jsxRuntime.jsx(ui.AddIcon, {}),
20428
- "Create your first entity"
20731
+ "Create your first entry"
20429
20732
  ] })
20430
20733
  ] }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "label", children: "No results with the applied filter/sort" }), hoverRow, inlineEditing: checkInlineEditing(), AdditionalHeaderWidget: buildAdditionalHeaderWidget, AddColumnComponent: addColumnComponentInternal, getIdColumnWidth, additionalIDHeaderWidget: /* @__PURE__ */ jsxRuntime.jsx(EntityIdHeaderWidget, { path: fullPath, fullIdPath: fullIdPath ?? fullPath, collection }), openEntityMode }, `collection_table_${fullPath}`),
20431
20734
  popupCell && /* @__PURE__ */ jsxRuntime.jsx(PopupFormField, { open: Boolean(popupCell), onClose: onPopupClose, cellRect: popupCell?.cellRect, propertyKey: popupCell?.propertyKey, collection, entityId: popupCell.entityId, tableKey: tableKey.current, customFieldValidator: uniqueFieldValidator, path: resolvedFullPath, onCellValueChange: onValueChange, container: containerRef.current }, `popup_form_${popupCell?.propertyKey}_${popupCell?.entityId}`),
@@ -23084,6 +23387,7 @@
23084
23387
  function createFormexStub(values) {
23085
23388
  const errorMessage = "You are in a read-only context. You cannot modify the formex controller.";
23086
23389
  return {
23390
+ debugId: "",
23087
23391
  values,
23088
23392
  initialValues: values,
23089
23393
  touched: {},
@@ -23098,6 +23402,9 @@
23098
23402
  setValues: () => {
23099
23403
  throw new Error(errorMessage);
23100
23404
  },
23405
+ setTouched(touched) {
23406
+ throw new Error(errorMessage);
23407
+ },
23101
23408
  setFieldValue: () => {
23102
23409
  throw new Error(errorMessage);
23103
23410
  },
@@ -23157,8 +23464,7 @@
23157
23464
  databaseId: props.databaseId,
23158
23465
  useCache: false
23159
23466
  });
23160
- const enableLocalChangesBackup = props.collection.enableLocalChangesBackup !== void 0 ? props.collection.enableLocalChangesBackup : true;
23161
- const initialDirtyValues = entityId ? getEntityFromCache(props.path + "/" + entityId, enableLocalChangesBackup) : getEntityFromCache(props.path + "#new", enableLocalChangesBackup);
23467
+ const initialDirtyValues = entityId ? getEntityFromMemoryCache(props.path + "/" + entityId) : getEntityFromMemoryCache(props.path + "#new");
23162
23468
  const authController = useAuthController();
23163
23469
  const initialStatus = props.copy ? "copy" : entityId ? "existing" : "new";
23164
23470
  const [status, setStatus] = React.useState(initialStatus);
@@ -23317,6 +23623,7 @@
23317
23623
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-16" })
23318
23624
  ] }) }) : null;
23319
23625
  const entityView = /* @__PURE__ */ jsxRuntime.jsx(EntityForm, { fullIdPath, collection, path, entityId: entityId ?? usedEntity?.id, onValuesModified, entity, initialDirtyValues, openEntityMode: layout, forceActionsAtTheBottom: actionsAtTheBottom, initialStatus: status, className: ui.cls((!mainViewVisible || !canEdit) && !selectedSecondaryForm ? "hidden" : "", formProps?.className), EntityFormActionsComponent: EntityEditViewFormActions, disabled: !canEdit, ...formProps, onEntityChange: (entity_0) => {
23626
+ console.log("333 EntityEditView onEntityChange:", entity_0);
23320
23627
  setUsedEntity(entity_0);
23321
23628
  formProps?.onEntityChange?.(entity_0);
23322
23629
  }, onStatusChange: (status_0) => {
@@ -23339,7 +23646,12 @@
23339
23646
  const shouldShowTopBar = Boolean(barActions) || hasAdditionalViews;
23340
23647
  let result = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-col h-full w-full bg-white dark:bg-surface-900", children: [
23341
23648
  shouldShowTopBar && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("h-14 items-center flex overflow-visible overflow-x-scroll w-full no-scrollbar h-14 border-b pl-2 pr-2 pt-1 flex bg-surface-50 dark:bg-surface-900", ui.defaultBorderMixin), children: [
23342
- barActions,
23649
+ barActions?.({
23650
+ path: fullIdPath ?? path,
23651
+ entityId,
23652
+ values: formContext?.values ?? usedEntity?.values ?? {},
23653
+ status
23654
+ }),
23343
23655
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-grow" }),
23344
23656
  pluginActionsTop,
23345
23657
  globalLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "self-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.CircularProgress, { size: "small" }) }),
@@ -23442,9 +23754,14 @@
23442
23754
  if (!props || !collection) {
23443
23755
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full" });
23444
23756
  }
23445
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxRuntime.jsx(EntityEditView, { ...props, fullIdPath, layout: "side_panel", collection, parentCollectionIds, onValuesModified, onSaved: onUpdate, barActions: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
23757
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxRuntime.jsx(EntityEditView, { ...props, fullIdPath, layout: "side_panel", collection, parentCollectionIds, onValuesModified, onSaved: onUpdate, barActions: ({
23758
+ status,
23759
+ values
23760
+ }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
23446
23761
  /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { className: "self-center", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(ui.CloseIcon, { size: "small" }) }),
23447
23762
  allowFullScreen && /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { className: "self-center", onClick: () => {
23763
+ const key = status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId;
23764
+ saveEntityToMemoryCache(key, values);
23448
23765
  if (entityId) navigate(location.pathname);
23449
23766
  else navigate(location.pathname + "#new");
23450
23767
  }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.OpenInFullIcon, { size: "small" }) })
@@ -26224,6 +26541,7 @@
26224
26541
  exports2.getIdIcon = getIdIcon;
26225
26542
  exports2.getLabelOrConfigFrom = getLabelOrConfigFrom;
26226
26543
  exports2.getLastSegment = getLastSegment;
26544
+ exports2.getLocalChangesBackup = getLocalChangesBackup;
26227
26545
  exports2.getPropertiesWithPropertiesOrder = getPropertiesWithPropertiesOrder;
26228
26546
  exports2.getPropertyInPath = getPropertyInPath;
26229
26547
  exports2.getRandomId = getRandomId;