@firecms/core 3.0.0-canary.283 → 3.0.0-canary.285
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/core/EntityEditView.d.ts +2 -2
- package/dist/form/EntityForm.d.ts +3 -1
- package/dist/form/index.d.ts +2 -1
- package/dist/index.es.js +123 -120
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +121 -118
- package/dist/index.umd.js.map +1 -1
- package/dist/types/collections.d.ts +7 -0
- package/dist/util/entity_cache.d.ts +2 -1
- package/package.json +5 -5
- package/src/core/EntityEditView.tsx +11 -10
- package/src/core/EntityEditViewFormActions.tsx +33 -18
- package/src/form/EntityForm.tsx +49 -25
- package/src/form/EntityFormActions.tsx +30 -15
- package/src/form/components/ErrorFocus.tsx +22 -29
- package/src/form/index.tsx +5 -1
- package/src/types/collections.ts +8 -0
- package/src/util/entity_cache.ts +22 -34
|
@@ -44,9 +44,9 @@ export interface EntityEditViewProps<M extends Record<string, any>> {
|
|
|
44
44
|
* an entity is opened.
|
|
45
45
|
*/
|
|
46
46
|
export declare function EntityEditView<M extends Record<string, any>, USER extends User>({ entityId, ...props }: EntityEditViewProps<M>): import("react/jsx-runtime").JSX.Element;
|
|
47
|
-
export declare function EntityEditViewInner<M extends Record<string, any>>({ path, fullIdPath, entityId, selectedTab: selectedTabProp, collection, parentCollectionIds, onValuesModified, onSaved, onTabChange, entity,
|
|
47
|
+
export declare function EntityEditViewInner<M extends Record<string, any>>({ path, fullIdPath, entityId, selectedTab: selectedTabProp, collection, parentCollectionIds, onValuesModified, onSaved, onTabChange, entity, initialDirtyValues, dataLoading, layout, barActions, status, setStatus, formProps, canEdit }: EntityEditViewProps<M> & {
|
|
48
48
|
entity?: Entity<M>;
|
|
49
|
-
|
|
49
|
+
initialDirtyValues?: Partial<M>;
|
|
50
50
|
dataLoading: boolean;
|
|
51
51
|
status: EntityStatus;
|
|
52
52
|
setStatus: (status: EntityStatus) => void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { Entity, EntityCollection, EntityCustomViewParams, EntityStatus, FormContext } from "../types";
|
|
2
|
+
import { AuthController, Entity, EntityCollection, EntityCustomViewParams, EntityStatus, EntityValues, FormContext, PropertyConfig } from "../types";
|
|
3
3
|
import { FormexController } from "@firecms/formex";
|
|
4
4
|
import { ValidationError } from "yup";
|
|
5
5
|
import { EntityFormActionsProps } from "./EntityFormActions";
|
|
@@ -46,5 +46,7 @@ export type EntityFormProps<M extends Record<string, any>> = {
|
|
|
46
46
|
Builder?: React.ComponentType<EntityCustomViewParams<M>>;
|
|
47
47
|
children?: React.ReactNode;
|
|
48
48
|
};
|
|
49
|
+
export declare function extractTouchedValues(values: any, touched: Record<string, boolean>): Record<string, any>;
|
|
49
50
|
export declare function EntityForm<M extends Record<string, any>>({ path, fullIdPath, entityId: entityIdProp, collection, onValuesModified, onIdChange, onSaved, entity, initialDirtyValues, onFormContextReady, forceActionsAtTheBottom, initialStatus, className, onStatusChange, onEntityChange, openEntityMode, formex: formexProp, disabled: disabledProp, Builder, EntityFormActionsComponent, showDefaultActions, showEntityPath, children }: EntityFormProps<M>): import("react/jsx-runtime").JSX.Element;
|
|
51
|
+
export declare function getInitialEntityValues<M extends object>(authController: AuthController, collection: EntityCollection, path: string, status: "new" | "existing" | "copy", entity: Entity<M> | undefined, propertyConfigs?: Record<string, PropertyConfig>): Partial<EntityValues<M>>;
|
|
50
52
|
export declare function yupToFormErrors(yupError: ValidationError): Record<string, any>;
|
package/dist/form/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { EntityForm, yupToFormErrors, } from "./EntityForm";
|
|
2
|
+
export type { EntityFormProps } from "./EntityForm";
|
|
2
3
|
export { SelectFieldBinding } from "./field_bindings/SelectFieldBinding";
|
|
3
4
|
export { MultiSelectFieldBinding } from "./field_bindings/MultiSelectFieldBinding";
|
|
4
5
|
export { ArrayOfReferencesFieldBinding } from "./field_bindings/ArrayOfReferencesFieldBinding";
|
package/dist/index.es.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsx, Fragment, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { c } from "react-compiler-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import React__default, { useRef, useEffect, useContext, useCallback, useMemo, useState, createElement, createRef, createContext, forwardRef, useLayoutEffect
|
|
4
|
+
import React__default, { useRef, useEffect, useContext, useCallback, useMemo, useState, createElement, createRef, createContext, forwardRef, useLayoutEffect } from "react";
|
|
5
5
|
import { getColorSchemeForSeed, CHIP_COLORS, FunctionsIcon, CircleIcon, iconKeys, coolIconKeys, Icon, Tooltip, ErrorIcon, Typography, IconButton, ContentCopyIcon, OpenInNewIcon, DescriptionIcon, cls, Skeleton, Chip, defaultBorderMixin, KeyboardTabIcon, Checkbox, AccountCircleIcon, Markdown, TextareaAutosize, focusedDisabled, MultiSelect, MultiSelectItem, Select, SelectItem, BooleanSwitch, DateTimeField, paperMixin, EditIcon, DoNotDisturbOnIcon, Menu, MenuItem, MoreVertIcon, CircularProgress, SearchBar, Badge, ArrowUpwardIcon, Popover, FilterListIcon, Button, CenteredView, AssignmentIcon, Label, CloseIcon, TextField, BooleanSwitchWithLabel, useOutsideAlerter, Dialog, DialogTitle, DialogContent, DialogActions, FileCopyIcon, DeleteIcon, AddIcon, StarIcon, Collapse, ExpandablePanel, ArrowForwardIcon, Card, cardMixin, cardClickableMixin, Container, LoadingButton, Alert, CheckIcon, NotesIcon, InfoIcon, fieldBackgroundMixin, RemoveIcon, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, ArrowDropDownIcon, FilterListOffIcon, SearchIcon, Avatar, DarkModeIcon, LightModeIcon, BrightnessMediumIcon, LogoutIcon, HandleIcon, KeyboardArrowUpIcon, KeyboardArrowDownIcon, debounce, Sheet, Tab, Tabs, CodeIcon, OpenInFullIcon, ViewStreamIcon, RepeatIcon, BallotIcon, ScheduleIcon, AddLinkIcon, LinkIcon, DriveFolderUploadIcon, UploadFileIcon, FormatListNumberedIcon, NumbersIcon, PersonIcon, ListAltIcon, ListIcon, FlagIcon, MailIcon, HttpIcon, FormatQuoteIcon, SubjectIcon, ShortTextIcon, MenuIcon, ChevronLeftIcon } from "@firecms/ui";
|
|
6
6
|
import { SnackbarProvider as SnackbarProvider$1, useSnackbar } from "notistack";
|
|
7
7
|
import hash from "object-hash";
|
|
8
|
-
import { getIn, useFormex, setIn, useCreateFormex, Formex, Field } from "@firecms/formex";
|
|
8
|
+
import { getIn, useFormex, setIn, useCreateFormex, flattenKeys, Formex, Field } from "@firecms/formex";
|
|
9
9
|
import { useNavigate, useLocation, Link, NavLink, Routes, Route, createBrowserRouter, RouterProvider } from "react-router-dom";
|
|
10
10
|
import Fuse from "fuse.js";
|
|
11
11
|
import equal from "react-fast-compare";
|
|
@@ -9756,27 +9756,6 @@ function customReviver(key, value) {
|
|
|
9756
9756
|
}
|
|
9757
9757
|
return value;
|
|
9758
9758
|
}
|
|
9759
|
-
if (isLocalStorageAvailable) {
|
|
9760
|
-
try {
|
|
9761
|
-
for (let i = 0; i < localStorage.length; i++) {
|
|
9762
|
-
const fullKey = localStorage.key(i);
|
|
9763
|
-
if (fullKey && fullKey.startsWith(LOCAL_STORAGE_PREFIX)) {
|
|
9764
|
-
const path = fullKey.substring(LOCAL_STORAGE_PREFIX.length);
|
|
9765
|
-
const entityString = localStorage.getItem(fullKey);
|
|
9766
|
-
if (entityString) {
|
|
9767
|
-
try {
|
|
9768
|
-
const entity = JSON.parse(entityString, customReviver);
|
|
9769
|
-
entityCache.set(path, entity);
|
|
9770
|
-
} catch (parseError) {
|
|
9771
|
-
console.error(`Failed to parse entity for path "${path}" from localStorage:`, parseError);
|
|
9772
|
-
}
|
|
9773
|
-
}
|
|
9774
|
-
}
|
|
9775
|
-
}
|
|
9776
|
-
} catch (error) {
|
|
9777
|
-
console.error("Error accessing localStorage during initialization:", error);
|
|
9778
|
-
}
|
|
9779
|
-
}
|
|
9780
9759
|
function saveEntityToCache(path, data) {
|
|
9781
9760
|
entityCache.set(path, data);
|
|
9782
9761
|
if (isLocalStorageAvailable) {
|
|
@@ -9789,11 +9768,11 @@ function saveEntityToCache(path, data) {
|
|
|
9789
9768
|
}
|
|
9790
9769
|
}
|
|
9791
9770
|
}
|
|
9792
|
-
function getEntityFromCache(path) {
|
|
9771
|
+
function getEntityFromCache(path, useLocalStorage = true) {
|
|
9793
9772
|
if (entityCache.has(path)) {
|
|
9794
9773
|
return entityCache.get(path);
|
|
9795
9774
|
}
|
|
9796
|
-
if (isLocalStorageAvailable) {
|
|
9775
|
+
if (isLocalStorageAvailable && useLocalStorage) {
|
|
9797
9776
|
try {
|
|
9798
9777
|
const key = LOCAL_STORAGE_PREFIX + path;
|
|
9799
9778
|
const entityString = localStorage.getItem(key);
|
|
@@ -14989,61 +14968,60 @@ function CustomIdField({
|
|
|
14989
14968
|
] });
|
|
14990
14969
|
}
|
|
14991
14970
|
const ErrorFocus = (t0) => {
|
|
14992
|
-
const $ = c(
|
|
14971
|
+
const $ = c(10);
|
|
14993
14972
|
const {
|
|
14994
14973
|
containerRef
|
|
14995
14974
|
} = t0;
|
|
14996
14975
|
const {
|
|
14997
|
-
isSubmitting,
|
|
14998
14976
|
isValidating,
|
|
14999
|
-
errors
|
|
14977
|
+
errors,
|
|
14978
|
+
version
|
|
15000
14979
|
} = useFormex();
|
|
14980
|
+
const prevVersion = useRef(version);
|
|
15001
14981
|
let t1;
|
|
15002
|
-
|
|
15003
|
-
if ($[0] !== containerRef || $[1] !== errors || $[2] !== isSubmitting || $[3] !== isValidating) {
|
|
14982
|
+
if ($[0] !== containerRef?.current || $[1] !== errors || $[2] !== isValidating || $[3] !== version) {
|
|
15004
14983
|
t1 = () => {
|
|
14984
|
+
if (version === prevVersion.current) {
|
|
14985
|
+
return;
|
|
14986
|
+
}
|
|
15005
14987
|
const keys = Object.keys(errors);
|
|
15006
|
-
if (keys.length > 0
|
|
14988
|
+
if (!isValidating && keys.length > 0) {
|
|
15007
14989
|
const errorElement = containerRef?.current?.querySelector(`#form_field_${keys[0]}`);
|
|
15008
|
-
if (errorElement
|
|
15009
|
-
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
top: scrollableParent.scrollTop + top - 196,
|
|
15014
|
-
behavior: "smooth"
|
|
15015
|
-
});
|
|
15016
|
-
}
|
|
14990
|
+
if (errorElement) {
|
|
14991
|
+
errorElement.scrollIntoView({
|
|
14992
|
+
behavior: "smooth",
|
|
14993
|
+
block: "center"
|
|
14994
|
+
});
|
|
15017
14995
|
const input = errorElement.querySelector("input");
|
|
15018
14996
|
if (input) {
|
|
15019
14997
|
input.focus();
|
|
15020
14998
|
}
|
|
15021
14999
|
}
|
|
15000
|
+
prevVersion.current = version;
|
|
15022
15001
|
}
|
|
15023
15002
|
};
|
|
15024
|
-
|
|
15025
|
-
$[0] = containerRef;
|
|
15003
|
+
$[0] = containerRef?.current;
|
|
15026
15004
|
$[1] = errors;
|
|
15027
|
-
$[2] =
|
|
15028
|
-
$[3] =
|
|
15005
|
+
$[2] = isValidating;
|
|
15006
|
+
$[3] = version;
|
|
15029
15007
|
$[4] = t1;
|
|
15030
|
-
$[5] = t2;
|
|
15031
15008
|
} else {
|
|
15032
15009
|
t1 = $[4];
|
|
15033
|
-
|
|
15010
|
+
}
|
|
15011
|
+
let t2;
|
|
15012
|
+
if ($[5] !== containerRef || $[6] !== errors || $[7] !== isValidating || $[8] !== version) {
|
|
15013
|
+
t2 = [isValidating, errors, containerRef, version];
|
|
15014
|
+
$[5] = containerRef;
|
|
15015
|
+
$[6] = errors;
|
|
15016
|
+
$[7] = isValidating;
|
|
15017
|
+
$[8] = version;
|
|
15018
|
+
$[9] = t2;
|
|
15019
|
+
} else {
|
|
15020
|
+
t2 = $[9];
|
|
15034
15021
|
}
|
|
15035
15022
|
useEffect(t1, t2);
|
|
15036
15023
|
return null;
|
|
15037
15024
|
};
|
|
15038
|
-
const isScrollable = (ele) => {
|
|
15039
|
-
const hasScrollableContent = ele && ele.scrollHeight > ele.clientHeight;
|
|
15040
|
-
const overflowYStyle = ele ? window.getComputedStyle(ele).overflowY : null;
|
|
15041
|
-
const isOverflowHidden = overflowYStyle && overflowYStyle.indexOf("hidden") !== -1;
|
|
15042
|
-
return hasScrollableContent && !isOverflowHidden;
|
|
15043
|
-
};
|
|
15044
|
-
const getScrollableParent = (ele) => {
|
|
15045
|
-
return !ele || ele === document.body ? document.body : isScrollable(ele) ? ele : getScrollableParent(ele.parentNode);
|
|
15046
|
-
};
|
|
15047
15025
|
function EntityFormActions(t0) {
|
|
15048
15026
|
const $ = c(16);
|
|
15049
15027
|
const {
|
|
@@ -15064,7 +15042,7 @@ function EntityFormActions(t0) {
|
|
|
15064
15042
|
const context = useFireCMSContext();
|
|
15065
15043
|
const sideEntityController = useSideEntityController();
|
|
15066
15044
|
let t1;
|
|
15067
|
-
if ($[0] !== collection || $[1] !== context || $[2] !== disabled || $[3] !== entity || $[4] !== formContext || $[5] !== formex
|
|
15045
|
+
if ($[0] !== collection || $[1] !== context || $[2] !== disabled || $[3] !== entity || $[4] !== formContext || $[5] !== formex || $[6] !== fullIdPath || $[7] !== fullPath || $[8] !== layout || $[9] !== navigateBack || $[10] !== openEntityMode || $[11] !== pluginActions || $[12] !== savingError || $[13] !== sideEntityController || $[14] !== status) {
|
|
15068
15046
|
t1 = layout === "bottom" ? buildBottomActions$1({
|
|
15069
15047
|
fullPath,
|
|
15070
15048
|
fullIdPath,
|
|
@@ -15073,13 +15051,13 @@ function EntityFormActions(t0) {
|
|
|
15073
15051
|
collection,
|
|
15074
15052
|
context,
|
|
15075
15053
|
sideEntityController,
|
|
15076
|
-
isSubmitting: formex.isSubmitting,
|
|
15077
15054
|
disabled,
|
|
15078
15055
|
status,
|
|
15079
15056
|
pluginActions,
|
|
15080
15057
|
openEntityMode,
|
|
15081
15058
|
navigateBack,
|
|
15082
|
-
formContext
|
|
15059
|
+
formContext,
|
|
15060
|
+
formex
|
|
15083
15061
|
}) : buildSideActions$1({
|
|
15084
15062
|
fullPath,
|
|
15085
15063
|
fullIdPath,
|
|
@@ -15088,18 +15066,18 @@ function EntityFormActions(t0) {
|
|
|
15088
15066
|
collection,
|
|
15089
15067
|
context,
|
|
15090
15068
|
sideEntityController,
|
|
15091
|
-
isSubmitting: formex.isSubmitting,
|
|
15092
15069
|
disabled,
|
|
15093
15070
|
status,
|
|
15094
15071
|
pluginActions,
|
|
15095
|
-
openEntityMode
|
|
15072
|
+
openEntityMode,
|
|
15073
|
+
formex
|
|
15096
15074
|
});
|
|
15097
15075
|
$[0] = collection;
|
|
15098
15076
|
$[1] = context;
|
|
15099
15077
|
$[2] = disabled;
|
|
15100
15078
|
$[3] = entity;
|
|
15101
15079
|
$[4] = formContext;
|
|
15102
|
-
$[5] = formex
|
|
15080
|
+
$[5] = formex;
|
|
15103
15081
|
$[6] = fullIdPath;
|
|
15104
15082
|
$[7] = fullPath;
|
|
15105
15083
|
$[8] = layout;
|
|
@@ -15124,14 +15102,15 @@ function buildBottomActions$1({
|
|
|
15124
15102
|
collection,
|
|
15125
15103
|
context,
|
|
15126
15104
|
sideEntityController,
|
|
15127
|
-
isSubmitting,
|
|
15128
15105
|
disabled,
|
|
15129
15106
|
status,
|
|
15130
15107
|
pluginActions,
|
|
15131
15108
|
openEntityMode,
|
|
15132
15109
|
navigateBack,
|
|
15133
|
-
formContext
|
|
15110
|
+
formContext,
|
|
15111
|
+
formex
|
|
15134
15112
|
}) {
|
|
15113
|
+
const hasErrors = Object.keys(formex.errors).length > 0 && formex.submitCount > 0;
|
|
15135
15114
|
return /* @__PURE__ */ jsxs(DialogActions, { position: "absolute", children: [
|
|
15136
15115
|
savingError && /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Typography, { color: "error", children: savingError.message }) }),
|
|
15137
15116
|
entity && (formActions ?? []).length > 0 && /* @__PURE__ */ jsx("div", { className: "flex-grow flex overflow-auto no-scrollbar", children: (formActions ?? []).map((action) => /* @__PURE__ */ jsx(IconButton, { color: "primary", onClick: (event) => {
|
|
@@ -15150,8 +15129,8 @@ function buildBottomActions$1({
|
|
|
15150
15129
|
});
|
|
15151
15130
|
}, children: action.icon }, action.name)) }),
|
|
15152
15131
|
pluginActions,
|
|
15153
|
-
/* @__PURE__ */ jsx(Button, { variant: "text", disabled: disabled || isSubmitting, color: "primary", type: "reset", children: status === "existing" ? "Discard" : "Clear" }),
|
|
15154
|
-
/* @__PURE__ */ jsxs(Button, { variant: "filled", color: "primary", type: "submit", disabled: disabled || isSubmitting, children: [
|
|
15132
|
+
/* @__PURE__ */ jsx(Button, { variant: "text", disabled: disabled || formex.isSubmitting, color: "primary", type: "reset", children: status === "existing" ? "Discard" : "Clear" }),
|
|
15133
|
+
/* @__PURE__ */ jsxs(Button, { variant: "filled", color: "primary", type: "submit", disabled: disabled || formex.isSubmitting, startIcon: hasErrors ? /* @__PURE__ */ jsx(ErrorIcon, {}) : void 0, children: [
|
|
15155
15134
|
status === "existing" && "Save",
|
|
15156
15135
|
status === "copy" && "Create copy",
|
|
15157
15136
|
status === "new" && "Create"
|
|
@@ -15168,22 +15147,35 @@ function buildSideActions$1({
|
|
|
15168
15147
|
collection,
|
|
15169
15148
|
context,
|
|
15170
15149
|
sideEntityController,
|
|
15171
|
-
isSubmitting,
|
|
15172
15150
|
disabled,
|
|
15173
15151
|
status,
|
|
15174
|
-
pluginActions
|
|
15152
|
+
pluginActions,
|
|
15153
|
+
formex
|
|
15175
15154
|
}) {
|
|
15155
|
+
const hasErrors = Object.keys(formex.errors).length > 0 && formex.submitCount > 0;
|
|
15176
15156
|
return /* @__PURE__ */ jsxs("div", { className: cls("overflow-auto h-full flex flex-col gap-2 w-80 2xl:w-96 px-4 py-16 sticky top-0 border-l", defaultBorderMixin), children: [
|
|
15177
|
-
/* @__PURE__ */ jsxs(LoadingButton, { fullWidth: true, variant: "filled", color: "primary", type: "submit", size: "large", disabled: disabled || isSubmitting, children: [
|
|
15157
|
+
/* @__PURE__ */ jsxs(LoadingButton, { fullWidth: true, variant: "filled", color: "primary", type: "submit", size: "large", startIcon: hasErrors ? /* @__PURE__ */ jsx(ErrorIcon, {}) : void 0, disabled: disabled || formex.isSubmitting, children: [
|
|
15178
15158
|
status === "existing" && "Save",
|
|
15179
15159
|
status === "copy" && "Create copy",
|
|
15180
15160
|
status === "new" && "Create"
|
|
15181
15161
|
] }),
|
|
15182
|
-
/* @__PURE__ */ jsx(Button, { fullWidth: true, variant: "text", disabled: disabled || isSubmitting, type: "reset", children: status === "existing" ? "Discard" : "Clear" }),
|
|
15162
|
+
/* @__PURE__ */ jsx(Button, { fullWidth: true, variant: "text", disabled: disabled || formex.isSubmitting, type: "reset", children: status === "existing" ? "Discard" : "Clear" }),
|
|
15183
15163
|
pluginActions,
|
|
15184
15164
|
savingError && /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Typography, { color: "error", children: savingError.message }) })
|
|
15185
15165
|
] });
|
|
15186
15166
|
}
|
|
15167
|
+
function extractTouchedValues(values, touched) {
|
|
15168
|
+
let acc = {};
|
|
15169
|
+
if (!touched || typeof touched !== "object") {
|
|
15170
|
+
return acc;
|
|
15171
|
+
}
|
|
15172
|
+
Object.entries(touched).forEach(([key, value]) => {
|
|
15173
|
+
if (value) {
|
|
15174
|
+
acc = setIn(acc, key, getIn(values, key));
|
|
15175
|
+
}
|
|
15176
|
+
});
|
|
15177
|
+
return acc;
|
|
15178
|
+
}
|
|
15187
15179
|
function EntityForm({
|
|
15188
15180
|
path,
|
|
15189
15181
|
fullIdPath,
|
|
@@ -15241,7 +15233,7 @@ function EntityForm({
|
|
|
15241
15233
|
const customizationController = useCustomizationController();
|
|
15242
15234
|
const context = useFireCMSContext();
|
|
15243
15235
|
const analyticsController = useAnalyticsController();
|
|
15244
|
-
const [underlyingChanges
|
|
15236
|
+
const [underlyingChanges] = useState({});
|
|
15245
15237
|
const [customIdLoading, setCustomIdLoading] = useState(false);
|
|
15246
15238
|
const mustSetCustomId = (status === "new" || status === "copy") && Boolean(collection.customId) && collection.customId !== "optional";
|
|
15247
15239
|
const initialEntityId = useMemo(() => {
|
|
@@ -15289,16 +15281,30 @@ function EntityForm({
|
|
|
15289
15281
|
formexController.setSubmitting(false);
|
|
15290
15282
|
});
|
|
15291
15283
|
};
|
|
15284
|
+
const baseInitialValues = getInitialEntityValues(authController, collection, path, status, entity, customizationController.propertyConfigs);
|
|
15285
|
+
const initialValues = initialDirtyValues ? mergeDeep(baseInitialValues, initialDirtyValues) : baseInitialValues;
|
|
15286
|
+
const initialDirty = Boolean(initialDirtyValues) && initialDirtyValues && Object.keys(initialDirtyValues).length > 0;
|
|
15292
15287
|
const formex = formexProp ?? useCreateFormex({
|
|
15293
|
-
initialValues
|
|
15294
|
-
initialDirty
|
|
15288
|
+
initialValues,
|
|
15289
|
+
initialDirty,
|
|
15290
|
+
initialTouched: initialDirtyValues ? flattenKeys(initialDirtyValues).reduce((previousValue, currentValue) => ({
|
|
15291
|
+
...previousValue,
|
|
15292
|
+
[currentValue]: true
|
|
15293
|
+
}), {}) : {},
|
|
15295
15294
|
onSubmit,
|
|
15296
15295
|
onReset: () => {
|
|
15297
15296
|
clearDirtyCache();
|
|
15298
15297
|
onValuesModified?.(false);
|
|
15299
15298
|
},
|
|
15300
|
-
|
|
15301
|
-
|
|
15299
|
+
onValuesChangeDeferred: (values_0, controller) => {
|
|
15300
|
+
const key = status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId;
|
|
15301
|
+
if (controller.dirty) {
|
|
15302
|
+
const touchedValues = extractTouchedValues(values_0, controller.touched);
|
|
15303
|
+
saveEntityToCache(key, touchedValues);
|
|
15304
|
+
}
|
|
15305
|
+
},
|
|
15306
|
+
validation: (values_1) => {
|
|
15307
|
+
return validationSchema?.validate(values_1, {
|
|
15302
15308
|
abortEarly: false
|
|
15303
15309
|
}).then(() => {
|
|
15304
15310
|
return {};
|
|
@@ -15381,7 +15387,7 @@ function EntityForm({
|
|
|
15381
15387
|
console.error(e_3);
|
|
15382
15388
|
}, [entityId, path, snackbarController]);
|
|
15383
15389
|
const saveEntity = ({
|
|
15384
|
-
values:
|
|
15390
|
+
values: values_2,
|
|
15385
15391
|
previousValues,
|
|
15386
15392
|
entityId: entityId_0,
|
|
15387
15393
|
collection: collection_0,
|
|
@@ -15390,7 +15396,7 @@ function EntityForm({
|
|
|
15390
15396
|
return saveEntityWithCallbacks({
|
|
15391
15397
|
path: path_0,
|
|
15392
15398
|
entityId: entityId_0,
|
|
15393
|
-
values:
|
|
15399
|
+
values: values_2,
|
|
15394
15400
|
previousValues,
|
|
15395
15401
|
collection: collection_0,
|
|
15396
15402
|
status,
|
|
@@ -15406,34 +15412,34 @@ function EntityForm({
|
|
|
15406
15412
|
collection: collection_1,
|
|
15407
15413
|
path: path_1,
|
|
15408
15414
|
entityId: entityId_1,
|
|
15409
|
-
values:
|
|
15415
|
+
values: values_3,
|
|
15410
15416
|
previousValues: previousValues_0,
|
|
15411
15417
|
autoSave: autoSave_0
|
|
15412
15418
|
}) => {
|
|
15413
15419
|
if (!status) return;
|
|
15414
15420
|
if (autoSave_0) {
|
|
15415
|
-
setValuesToBeSaved(
|
|
15421
|
+
setValuesToBeSaved(values_3);
|
|
15416
15422
|
} else {
|
|
15417
15423
|
return saveEntity({
|
|
15418
15424
|
collection: collection_1,
|
|
15419
15425
|
path: path_1,
|
|
15420
15426
|
entityId: entityId_1,
|
|
15421
|
-
values:
|
|
15427
|
+
values: values_3,
|
|
15422
15428
|
previousValues: previousValues_0
|
|
15423
15429
|
});
|
|
15424
15430
|
}
|
|
15425
15431
|
};
|
|
15426
15432
|
const lastSavedValues = useRef(entity?.values);
|
|
15427
|
-
const save = (
|
|
15428
|
-
lastSavedValues.current =
|
|
15433
|
+
const save = (values_4) => {
|
|
15434
|
+
lastSavedValues.current = values_4;
|
|
15429
15435
|
return onSaveEntityRequest({
|
|
15430
15436
|
collection: resolvedCollection,
|
|
15431
15437
|
path,
|
|
15432
15438
|
entityId,
|
|
15433
|
-
values:
|
|
15439
|
+
values: values_4,
|
|
15434
15440
|
previousValues: entity?.values,
|
|
15435
15441
|
autoSave: autoSave ?? false
|
|
15436
|
-
}).then((
|
|
15442
|
+
}).then(() => {
|
|
15437
15443
|
const eventName = status === "new" ? "new_entity_saved" : status === "copy" ? "entity_copied" : status === "existing" ? "entity_edited" : "unmapped_event";
|
|
15438
15444
|
analyticsController.onAnalyticsEvent?.(eventName, {
|
|
15439
15445
|
path
|
|
@@ -15467,7 +15473,8 @@ function EntityForm({
|
|
|
15467
15473
|
type: "error",
|
|
15468
15474
|
message: "Error updating id, check the console"
|
|
15469
15475
|
});
|
|
15470
|
-
|
|
15476
|
+
console.error(error);
|
|
15477
|
+
}, [snackbarController]);
|
|
15471
15478
|
const pluginActions = [];
|
|
15472
15479
|
const plugins = customizationController.plugins;
|
|
15473
15480
|
const actionsDisabled = disabled || formex.isSubmitting || status === "existing" && !formex.dirty || Boolean(disabledProp);
|
|
@@ -15516,20 +15523,12 @@ function EntityForm({
|
|
|
15516
15523
|
onValuesModified?.(modified);
|
|
15517
15524
|
}
|
|
15518
15525
|
}, [formex.dirty]);
|
|
15519
|
-
const deferredValues = useDeferredValue(formex.values);
|
|
15520
15526
|
const modified = formex.dirty;
|
|
15521
15527
|
const uniqueFieldValidator = useCallback(({
|
|
15522
15528
|
name,
|
|
15523
|
-
value
|
|
15524
|
-
property
|
|
15529
|
+
value
|
|
15525
15530
|
}) => dataSource.checkUniqueField(path, name, value, entityId, collection), [dataSource, path, entityId]);
|
|
15526
15531
|
const validationSchema = useMemo(() => entityId ? getYupEntitySchema(entityId, resolvedCollection.properties, uniqueFieldValidator) : void 0, [entityId, resolvedCollection.properties, uniqueFieldValidator]);
|
|
15527
|
-
useEffect(() => {
|
|
15528
|
-
const key = status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId;
|
|
15529
|
-
if (modified) {
|
|
15530
|
-
saveEntityToCache(key, deferredValues);
|
|
15531
|
-
}
|
|
15532
|
-
}, [deferredValues, modified, path, entityId, status]);
|
|
15533
15532
|
useOnAutoSave(autoSave, formex, lastSavedValues, save);
|
|
15534
15533
|
useEffect(() => {
|
|
15535
15534
|
if (!autoSave && !formex.isSubmitting && underlyingChanges && entity) {
|
|
@@ -15548,18 +15547,18 @@ function EntityForm({
|
|
|
15548
15547
|
return /* @__PURE__ */ jsx(Builder, { collection, entity, modifiedValues: formex.values, formContext });
|
|
15549
15548
|
}
|
|
15550
15549
|
return /* @__PURE__ */ jsx(FormLayout, { children: formFieldKeys.map((key_1) => {
|
|
15551
|
-
const
|
|
15552
|
-
if (
|
|
15550
|
+
const property = resolvedCollection.properties[key_1];
|
|
15551
|
+
if (property) {
|
|
15553
15552
|
const underlyingValueHasChanged = !!underlyingChanges && Object.keys(underlyingChanges).includes(key_1) && formex.touched[key_1];
|
|
15554
|
-
const disabled_0 = disabledProp || !autoSave && formex.isSubmitting || isReadOnly(
|
|
15555
|
-
const hidden = isHidden(
|
|
15553
|
+
const disabled_0 = disabledProp || !autoSave && formex.isSubmitting || isReadOnly(property) || Boolean(property.disabled);
|
|
15554
|
+
const hidden = isHidden(property);
|
|
15556
15555
|
if (hidden) return null;
|
|
15557
|
-
const widthPercentage =
|
|
15556
|
+
const widthPercentage = property.widthPercentage ?? 100;
|
|
15558
15557
|
const cmsFormFieldProps = {
|
|
15559
15558
|
propertyKey: key_1,
|
|
15560
15559
|
disabled: disabled_0,
|
|
15561
|
-
property
|
|
15562
|
-
includeDescription:
|
|
15560
|
+
property,
|
|
15561
|
+
includeDescription: property.description || property.longDescription,
|
|
15563
15562
|
underlyingValueHasChanged: underlyingValueHasChanged && !autoSave,
|
|
15564
15563
|
context: formContext,
|
|
15565
15564
|
partOfArray: false,
|
|
@@ -15615,7 +15614,7 @@ function EntityForm({
|
|
|
15615
15614
|
}
|
|
15616
15615
|
const dialogActions = /* @__PURE__ */ jsx(EntityFormActionsComponent, { collection: resolvedCollection, path, fullPath: path, fullIdPath, entity, layout: forceActionsAtTheBottom ? "bottom" : "side", savingError, formex, disabled: actionsDisabled, status, pluginActions: pluginActions ?? [], openEntityMode, showDefaultActions, navigateBack, formContext });
|
|
15617
15616
|
return /* @__PURE__ */ jsx(Formex, { value: formex, children: /* @__PURE__ */ jsxs("form", { onSubmit: formex.handleSubmit, onReset: () => formex.resetForm({
|
|
15618
|
-
values:
|
|
15617
|
+
values: baseInitialValues
|
|
15619
15618
|
}), noValidate: true, className: cls("flex-1 flex flex-row w-full overflow-y-auto justify-center", className), children: [
|
|
15620
15619
|
/* @__PURE__ */ jsx("div", { id: `form_${path}`, className: 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__ */ jsxs("div", { className: cls("flex flex-col w-full pt-12 pb-16 px-4 sm:px-8 md:px-10"), children: [
|
|
15621
15620
|
formex.dirty ? /* @__PURE__ */ jsx(Tooltip, { title: "Local unsaved changes", className: "self-end sticky top-4 z-10", children: /* @__PURE__ */ jsx(Chip, { size: "small", colorScheme: "orangeDarker", children: /* @__PURE__ */ jsx(EditIcon, { size: "smallest" }) }) }) : /* @__PURE__ */ jsx(Tooltip, { title: "In sync with the database", className: "self-end sticky top-4 z-10", children: /* @__PURE__ */ jsx(Chip, { size: "small", children: /* @__PURE__ */ jsx(CheckIcon, { size: "smallest" }) }) }),
|
|
@@ -22828,14 +22827,14 @@ function EntityEditViewFormActions({
|
|
|
22828
22827
|
collection,
|
|
22829
22828
|
context,
|
|
22830
22829
|
sideEntityController,
|
|
22831
|
-
isSubmitting: formex.isSubmitting,
|
|
22832
22830
|
disabled,
|
|
22833
22831
|
status,
|
|
22834
22832
|
sideDialogContext,
|
|
22835
22833
|
pluginActions,
|
|
22836
22834
|
openEntityMode,
|
|
22837
22835
|
navigateBack,
|
|
22838
|
-
formContext
|
|
22836
|
+
formContext,
|
|
22837
|
+
formex
|
|
22839
22838
|
}) : buildSideActions({
|
|
22840
22839
|
savingError,
|
|
22841
22840
|
entity,
|
|
@@ -22843,14 +22842,14 @@ function EntityEditViewFormActions({
|
|
|
22843
22842
|
collection,
|
|
22844
22843
|
context,
|
|
22845
22844
|
sideEntityController,
|
|
22846
|
-
isSubmitting: formex.isSubmitting,
|
|
22847
22845
|
sideDialogContext,
|
|
22848
22846
|
disabled,
|
|
22849
22847
|
status,
|
|
22850
22848
|
pluginActions,
|
|
22851
22849
|
openEntityMode,
|
|
22852
22850
|
navigateBack,
|
|
22853
|
-
formContext
|
|
22851
|
+
formContext,
|
|
22852
|
+
formex
|
|
22854
22853
|
});
|
|
22855
22854
|
}
|
|
22856
22855
|
function buildBottomActions({
|
|
@@ -22860,15 +22859,16 @@ function buildBottomActions({
|
|
|
22860
22859
|
collection,
|
|
22861
22860
|
context,
|
|
22862
22861
|
sideEntityController,
|
|
22863
|
-
isSubmitting,
|
|
22864
22862
|
disabled,
|
|
22865
22863
|
status,
|
|
22866
22864
|
sideDialogContext,
|
|
22867
22865
|
pluginActions,
|
|
22868
22866
|
openEntityMode,
|
|
22869
22867
|
navigateBack,
|
|
22870
|
-
formContext
|
|
22868
|
+
formContext,
|
|
22869
|
+
formex
|
|
22871
22870
|
}) {
|
|
22871
|
+
const hasErrors = Object.keys(formex.errors).length > 0 && formex.submitCount > 0;
|
|
22872
22872
|
const canClose = openEntityMode === "side_panel";
|
|
22873
22873
|
return /* @__PURE__ */ jsxs(DialogActions, { position: "absolute", children: [
|
|
22874
22874
|
savingError && /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Typography, { color: "error", children: savingError.message }) }),
|
|
@@ -22888,15 +22888,16 @@ function buildBottomActions({
|
|
|
22888
22888
|
return /* @__PURE__ */ jsx(EntityActionButton, { action, enabled: isEnabled, props }, action.key);
|
|
22889
22889
|
}) }),
|
|
22890
22890
|
pluginActions,
|
|
22891
|
-
/* @__PURE__ */ jsx(
|
|
22892
|
-
/* @__PURE__ */
|
|
22891
|
+
hasErrors ? /* @__PURE__ */ jsx(ErrorTooltip, { title: "This form has errors", children: /* @__PURE__ */ jsx(ErrorIcon, { className: "ml-4", color: "error", size: "smallest" }) }) : null,
|
|
22892
|
+
/* @__PURE__ */ jsx(Button, { variant: "text", color: "primary", disabled: disabled || formex.isSubmitting, type: "reset", children: status === "existing" ? "Discard" : "Clear" }),
|
|
22893
|
+
/* @__PURE__ */ jsxs(Button, { variant: canClose ? "text" : "filled", color: "primary", type: "submit", disabled: disabled || formex.isSubmitting, onClick: () => {
|
|
22893
22894
|
sideDialogContext.setPendingClose(false);
|
|
22894
22895
|
}, children: [
|
|
22895
22896
|
status === "existing" && "Save",
|
|
22896
22897
|
status === "copy" && "Create copy",
|
|
22897
22898
|
status === "new" && "Create"
|
|
22898
22899
|
] }),
|
|
22899
|
-
canClose && /* @__PURE__ */ jsxs(LoadingButton, { variant: "filled", color: "primary", type: "submit", loading: isSubmitting, disabled, onClick: () => {
|
|
22900
|
+
canClose && /* @__PURE__ */ jsxs(LoadingButton, { variant: "filled", color: "primary", type: "submit", loading: formex.isSubmitting, disabled, onClick: () => {
|
|
22900
22901
|
sideDialogContext.setPendingClose?.(true);
|
|
22901
22902
|
}, children: [
|
|
22902
22903
|
status === "existing" && "Save and close",
|
|
@@ -22912,24 +22913,25 @@ function buildSideActions({
|
|
|
22912
22913
|
collection,
|
|
22913
22914
|
context,
|
|
22914
22915
|
sideEntityController,
|
|
22915
|
-
isSubmitting,
|
|
22916
22916
|
disabled,
|
|
22917
22917
|
status,
|
|
22918
22918
|
sideDialogContext,
|
|
22919
22919
|
pluginActions,
|
|
22920
22920
|
openEntityMode,
|
|
22921
22921
|
navigateBack,
|
|
22922
|
-
formContext
|
|
22922
|
+
formContext,
|
|
22923
|
+
formex
|
|
22923
22924
|
}) {
|
|
22925
|
+
const hasErrors = Object.keys(formex.errors).length > 0 && formex.submitCount > 0;
|
|
22924
22926
|
return /* @__PURE__ */ jsxs("div", { className: cls("overflow-auto h-full flex flex-col gap-2 w-80 2xl:w-96 px-4 py-16 sticky top-0 border-l", defaultBorderMixin), children: [
|
|
22925
|
-
/* @__PURE__ */ jsxs(LoadingButton, { fullWidth: true, variant: "filled", color: "primary", type: "submit", size: "large", disabled: disabled || isSubmitting, onClick: () => {
|
|
22927
|
+
/* @__PURE__ */ jsxs(LoadingButton, { fullWidth: true, variant: "filled", color: "primary", type: "submit", size: "large", startIcon: hasErrors ? /* @__PURE__ */ jsx(ErrorIcon, {}) : void 0, disabled: disabled || formex.isSubmitting, onClick: () => {
|
|
22926
22928
|
sideDialogContext.setPendingClose?.(false);
|
|
22927
22929
|
}, children: [
|
|
22928
22930
|
status === "existing" && "Save",
|
|
22929
22931
|
status === "copy" && "Create copy",
|
|
22930
22932
|
status === "new" && "Create"
|
|
22931
22933
|
] }),
|
|
22932
|
-
/* @__PURE__ */ jsx(Button, { fullWidth: true, variant: "text", disabled: disabled || isSubmitting, type: "reset", children: status === "existing" ? "Discard" : "Clear" }),
|
|
22934
|
+
/* @__PURE__ */ jsx(Button, { fullWidth: true, variant: "text", disabled: disabled || formex.isSubmitting, type: "reset", children: status === "existing" ? "Discard" : "Clear" }),
|
|
22933
22935
|
pluginActions,
|
|
22934
22936
|
formActions.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-row flex-wrap mt-2", children: formActions.map((action) => {
|
|
22935
22937
|
const props = {
|
|
@@ -23157,7 +23159,8 @@ function EntityEditView({
|
|
|
23157
23159
|
databaseId: props.databaseId,
|
|
23158
23160
|
useCache: false
|
|
23159
23161
|
});
|
|
23160
|
-
const
|
|
23162
|
+
const enableLocalChangesBackup = props.collection.enableLocalChangesBackup !== void 0 ? props.collection.enableLocalChangesBackup : true;
|
|
23163
|
+
const initialDirtyValues = entityId ? getEntityFromCache(props.path + "/" + entityId, enableLocalChangesBackup) : getEntityFromCache(props.path + "#new", enableLocalChangesBackup);
|
|
23161
23164
|
const authController = useAuthController();
|
|
23162
23165
|
const initialStatus = props.copy ? "copy" : entityId ? "existing" : "new";
|
|
23163
23166
|
const [status, setStatus] = useState(initialStatus);
|
|
@@ -23168,13 +23171,13 @@ function EntityEditView({
|
|
|
23168
23171
|
return entity ? canEditEntity(props.collection, authController, props.path, entity ?? null) : void 0;
|
|
23169
23172
|
}
|
|
23170
23173
|
}, [authController, entity, status]);
|
|
23171
|
-
if (dataLoading && !
|
|
23174
|
+
if (dataLoading && !initialDirtyValues || (!entity || canEdit === void 0) && (status === "existing" || status === "copy")) {
|
|
23172
23175
|
return /* @__PURE__ */ jsx(CircularProgressCenter, {});
|
|
23173
23176
|
}
|
|
23174
|
-
if (entityId && !entity && !
|
|
23177
|
+
if (entityId && !entity && !initialDirtyValues) {
|
|
23175
23178
|
console.error(`Entity with id ${entityId} not found in collection ${props.path}`);
|
|
23176
23179
|
}
|
|
23177
|
-
return /* @__PURE__ */ jsx(EntityEditViewInner, { ...props, entityId, entity,
|
|
23180
|
+
return /* @__PURE__ */ jsx(EntityEditViewInner, { ...props, entityId, entity, initialDirtyValues, dataLoading, status, setStatus, canEdit });
|
|
23178
23181
|
}
|
|
23179
23182
|
function EntityEditViewInner({
|
|
23180
23183
|
path,
|
|
@@ -23187,7 +23190,7 @@ function EntityEditViewInner({
|
|
|
23187
23190
|
onSaved,
|
|
23188
23191
|
onTabChange,
|
|
23189
23192
|
entity,
|
|
23190
|
-
|
|
23193
|
+
initialDirtyValues,
|
|
23191
23194
|
dataLoading,
|
|
23192
23195
|
layout = "side_panel",
|
|
23193
23196
|
barActions,
|
|
@@ -23315,7 +23318,7 @@ function EntityEditViewInner({
|
|
|
23315
23318
|
/* @__PURE__ */ jsx(EntityView, { className: "px-8 h-full overflow-auto", entity, path, collection }),
|
|
23316
23319
|
/* @__PURE__ */ jsx("div", { className: "h-16" })
|
|
23317
23320
|
] }) }) : null;
|
|
23318
|
-
const entityView = /* @__PURE__ */ jsx(EntityForm, { fullIdPath, collection, path, entityId: entityId ?? usedEntity?.id, onValuesModified, entity, initialDirtyValues
|
|
23321
|
+
const entityView = /* @__PURE__ */ jsx(EntityForm, { fullIdPath, collection, path, entityId: entityId ?? usedEntity?.id, onValuesModified, entity, initialDirtyValues, openEntityMode: layout, forceActionsAtTheBottom: actionsAtTheBottom, initialStatus: status, className: cls((!mainViewVisible || !canEdit) && !selectedSecondaryForm ? "hidden" : "", formProps?.className), EntityFormActionsComponent: EntityEditViewFormActions, disabled: !canEdit, ...formProps, onEntityChange: (entity_0) => {
|
|
23319
23322
|
setUsedEntity(entity_0);
|
|
23320
23323
|
formProps?.onEntityChange?.(entity_0);
|
|
23321
23324
|
}, onStatusChange: (status_0) => {
|