mirror of
https://github.com/zhigang1992/firecms.git
synced 2026-06-14 01:34:55 +08:00
Added reorder feature for default arrays with drag n drop
This commit is contained in:
@@ -1084,6 +1084,13 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.2.0":
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740"
|
||||
integrity sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/template@^7.4.0", "@babel/template@^7.8.3", "@babel/template@^7.8.6":
|
||||
version "7.8.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b"
|
||||
@@ -2072,21 +2079,6 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-virtualized@^9.21.10":
|
||||
version "9.21.10"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.21.10.tgz#cd072dc9c889291ace2c4c9de8e8c050da8738b7"
|
||||
integrity sha512-f5Ti3A7gGdLkPPFNHTrvKblpsPNBiQoSorOEOD+JPx72g/Ng2lOt4MYfhvQFQNgyIrAro+Z643jbcKafsMW2ag==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-window@^1.8.2":
|
||||
version "1.8.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-window/-/react-window-1.8.2.tgz#a5a6b2762ce73ffaab7911ee1397cf645f2459fe"
|
||||
integrity sha512-gP1xam68Wc4ZTAee++zx6pTdDAH08rAkQrWm4B4F/y6hhmlT9Mgx2q8lTCXnrPHXsr15XjRN9+K2DLKcz44qEQ==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*":
|
||||
version "16.9.34"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.34.tgz#f7d5e331c468f53affed17a8a4d488cd44ea9349"
|
||||
@@ -4326,14 +4318,6 @@ dom-helpers@^5.0.1:
|
||||
"@babel/runtime" "^7.8.7"
|
||||
csstype "^2.6.7"
|
||||
|
||||
dom-helpers@^5.1.3:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.0.tgz#57fd054c5f8f34c52a3eeffdb7e7e93cd357d95b"
|
||||
integrity sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.8.7"
|
||||
csstype "^3.0.2"
|
||||
|
||||
dom-serializer@0:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
|
||||
@@ -9262,7 +9246,7 @@ prompts@^2.0.1:
|
||||
kleur "^3.0.3"
|
||||
sisteransi "^1.0.4"
|
||||
|
||||
prop-types@^15.0.0, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.0, prop-types@^15.7.2:
|
||||
prop-types@^15.0.0, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.0, prop-types@^15.7.2:
|
||||
version "15.7.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||
@@ -9529,11 +9513,6 @@ react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
react-lifecycles-compat@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
|
||||
|
||||
react-router-dom@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662"
|
||||
@@ -9581,6 +9560,15 @@ react-select@>=3:
|
||||
react-input-autosize "^2.2.2"
|
||||
react-transition-group "^4.3.0"
|
||||
|
||||
react-sortable-hoc@^1.11.0:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/react-sortable-hoc/-/react-sortable-hoc-1.11.0.tgz#fe4022362bbafc4b836f5104b9676608a40a278f"
|
||||
integrity sha512-v1CDCvdfoR3zLGNp6qsBa4J1BWMEVH25+UKxF/RvQRh+mrB+emqtVHMgZ+WreUiKJoEaiwYoScaueIKhMVBHUg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.2.0"
|
||||
invariant "^2.2.4"
|
||||
prop-types "^15.5.7"
|
||||
|
||||
react-transition-group@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.3.0.tgz#fea832e386cf8796c58b61874a3319704f5ce683"
|
||||
@@ -9606,19 +9594,7 @@ react-virtualized-auto-sizer@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.2.tgz#a61dd4f756458bbf63bd895a92379f9b70f803bd"
|
||||
integrity sha512-MYXhTY1BZpdJFjUovvYHVBmkq79szK/k7V3MO+36gJkWGkrXKtyr4vCPtpphaTLRAdDNoYEYFZWE8LjN+PIHNg==
|
||||
|
||||
react-virtualized@^9.22.2:
|
||||
version "9.22.2"
|
||||
resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.22.2.tgz#217a870bad91e5438f46f01a009e1d8ce1060a5a"
|
||||
integrity sha512-5j4h4FhxTdOpBKtePSs1yk6LDNT4oGtUwjT7Nkh61Z8vv3fTG/XeOf8J4li1AYaexOwTXnw0HFVxsV0GBUqwRw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.7.2"
|
||||
clsx "^1.0.4"
|
||||
dom-helpers "^5.1.3"
|
||||
loose-envify "^1.4.0"
|
||||
prop-types "^15.7.2"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
|
||||
react-window@^1.8.2, react-window@^1.8.5:
|
||||
react-window@^1.8.2:
|
||||
version "1.8.5"
|
||||
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.5.tgz#a56b39307e79979721021f5d06a67742ecca52d1"
|
||||
integrity sha512-HeTwlNa37AFa8MDZFZOKcNEkuF2YflA0hpGPiTT9vR7OawEt+GZbfM6wqkBahD3D3pUjIabQYzsnY/BSJbgq6Q==
|
||||
@@ -11027,6 +11003,11 @@ to-regex@^3.0.1, to-regex@^3.0.2:
|
||||
regex-not "^1.0.2"
|
||||
safe-regex "^1.1.0"
|
||||
|
||||
toggle-selection@^1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"
|
||||
integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI=
|
||||
|
||||
toidentifier@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
||||
@@ -11273,6 +11254,13 @@ url@^0.11.0:
|
||||
punycode "1.3.2"
|
||||
querystring "0.2.0"
|
||||
|
||||
use-clipboard-hook@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/use-clipboard-hook/-/use-clipboard-hook-1.1.1.tgz#9af992e9b7efebbb12f497c43b328ac3f4098fe9"
|
||||
integrity sha512-LXaBI25G1qMlSZMOEI2TRwKbrpok2G/udC9SX+QfljWwL+/PcBPJWTbG1+/FoMerGNF7NBWH2HXzWHLv8C/XbQ==
|
||||
dependencies:
|
||||
toggle-selection "^1.0.6"
|
||||
|
||||
use@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
"material-ui-popup-state": "^1.6.1",
|
||||
"object-hash": "^2.0.3",
|
||||
"react-base-table": "^1.12.0",
|
||||
"react-dnd": "^11.1.3",
|
||||
"react-dnd-html5-backend": "^11.1.3",
|
||||
"react-dropzone": "^11.2.0",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-select": ">=3",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useEffect } from "react";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { HTML5Backend } from "react-dnd-html5-backend";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -47,6 +48,7 @@ import { AuthContext, AuthProvider } from "./auth";
|
||||
import { SnackbarProvider } from "./snackbar_controller";
|
||||
import { CMSRoute } from "./routes/CMSRoute";
|
||||
import EntityDetailDialog from "./routes/SideCMSRoute";
|
||||
import { DndProvider } from "react-dnd";
|
||||
|
||||
const drawerWidth = 240;
|
||||
|
||||
@@ -335,17 +337,17 @@ export function CMSApp({
|
||||
<img className={classes.logo} src={logo}/>}
|
||||
</Box>
|
||||
|
||||
<Button variant="contained"
|
||||
color="primary"
|
||||
onClick={authContext.googleSignIn}>
|
||||
Google login
|
||||
</Button>
|
||||
<Button variant="contained"
|
||||
color="primary"
|
||||
onClick={authContext.googleSignIn}>
|
||||
Google login
|
||||
</Button>
|
||||
|
||||
{skipLoginButtonEnabled &&
|
||||
<Box m={2}>
|
||||
<Box m={2}>
|
||||
<Button onClick={authContext.skipLogin}>Skip
|
||||
login</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
}
|
||||
|
||||
<Grid item xs={12}>
|
||||
@@ -475,23 +477,27 @@ export function CMSApp({
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<MuiPickersUtilsProvider utils={DateFnsUtils}>
|
||||
{firebaseConfigError ?
|
||||
<Box>
|
||||
It seems like the provided Firebase config
|
||||
is not correct. If you are using the
|
||||
credentials provided automatically by
|
||||
Firebase Hosting, make sure you link your
|
||||
Firebase app to Firebase Hosting.
|
||||
</Box> :
|
||||
(
|
||||
authContext.authLoading ? (
|
||||
<CircularProgressCenter/>
|
||||
) : (!authenticationEnabled || authContext.loggedUser || authContext.loginSkipped) ? (
|
||||
renderMainView()
|
||||
) : (
|
||||
renderLoginView()
|
||||
)
|
||||
)}
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
{firebaseConfigError ?
|
||||
<Box>
|
||||
It seems like the provided Firebase
|
||||
config
|
||||
is not correct. If you are using the
|
||||
credentials provided automatically by
|
||||
Firebase Hosting, make sure you link
|
||||
your
|
||||
Firebase app to Firebase Hosting.
|
||||
</Box> :
|
||||
(
|
||||
authContext.authLoading ? (
|
||||
<CircularProgressCenter/>
|
||||
) : (!authenticationEnabled || authContext.loggedUser || authContext.loginSkipped) ? (
|
||||
renderMainView()
|
||||
) : (
|
||||
renderLoginView()
|
||||
)
|
||||
)}
|
||||
</DndProvider>
|
||||
</MuiPickersUtilsProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import * as firebase from "firebase";
|
||||
import * as firebase from "firebase/app";
|
||||
import "firebase/auth";
|
||||
|
||||
import { auth, User } from "firebase";
|
||||
import React, { useContext, useEffect } from "react";
|
||||
import { Authenticator } from "./authenticator";
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
} from "@material-ui/core";
|
||||
import { Entity, EntitySchema, EntityStatus, EntityValues } from "../models";
|
||||
import { Form, Formik, FormikHelpers } from "formik";
|
||||
import { createCustomIdField, createFormField } from "./index";
|
||||
import { createCustomIdField, createFormField, FormFieldProps } from "./index";
|
||||
import { initEntityValues } from "../firebase/firestore";
|
||||
import { getYupObjectSchema } from "./validation";
|
||||
import deepEqual from "deep-equal";
|
||||
@@ -87,6 +87,7 @@ export default function EntityForm<S extends EntitySchema>({
|
||||
onDiscard,
|
||||
onModified
|
||||
}: EntityFormProps<S>) {
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
const [customId, setCustomId] = React.useState<string | undefined>(undefined);
|
||||
@@ -229,7 +230,15 @@ export default function EntityForm<S extends EntitySchema>({
|
||||
&& Object.keys(underlyingChanges).includes(key)
|
||||
&& !!touched[key];
|
||||
|
||||
const formField = createFormField(key, property, true, underlyingValueHasChanged, schema);
|
||||
const formField = createFormField(
|
||||
{
|
||||
name : key,
|
||||
property,
|
||||
includeDescription:true ,
|
||||
underlyingValueHasChanged,
|
||||
entitySchema:schema,
|
||||
partOfArray: false
|
||||
});
|
||||
|
||||
return <Grid item
|
||||
xs={12}
|
||||
|
||||
@@ -17,6 +17,7 @@ import { Add, Remove } from "@material-ui/icons";
|
||||
import { formStyles } from "../../styles";
|
||||
import { CMSFieldProps } from "../form_props";
|
||||
import { FieldDescription } from "../../components";
|
||||
import { FormFieldProps } from "../index";
|
||||
|
||||
type ArrayMapFieldProps<T> = CMSFieldProps<T[]>;
|
||||
|
||||
@@ -68,11 +69,15 @@ export default function ArrayMapField<T>({
|
||||
return (
|
||||
<TableCell
|
||||
key={`field_${arrayKey}`}>
|
||||
{createFormField(`${field.name}[${index}].${arrayKey}`,
|
||||
childProperty,
|
||||
includeDescription,
|
||||
underlyingValueHasChanged,
|
||||
entitySchema)}
|
||||
{createFormField(
|
||||
{
|
||||
name:`${field.name}[${index}].${arrayKey}`,
|
||||
property:childProperty,
|
||||
includeDescription,
|
||||
underlyingValueHasChanged,
|
||||
entitySchema,
|
||||
partOfArray: false
|
||||
})}
|
||||
</TableCell>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -50,11 +50,15 @@ export default function ArrayShapedField<T>({
|
||||
return <Grid item
|
||||
xs={12}
|
||||
key={`array-shape-${field.name}-${index}`}>
|
||||
{createFormField(`${field.name}[${index}]`,
|
||||
childProperty,
|
||||
includeDescription,
|
||||
underlyingValueHasChanged,
|
||||
entitySchema)}
|
||||
{createFormField(
|
||||
{
|
||||
name:`${field.name}[${index}]`,
|
||||
property:childProperty,
|
||||
includeDescription,
|
||||
underlyingValueHasChanged,
|
||||
entitySchema,
|
||||
partOfArray: false
|
||||
})}
|
||||
</Grid>;
|
||||
}
|
||||
)}
|
||||
|
||||
@@ -14,7 +14,6 @@ export default function DateTimeField({
|
||||
field,
|
||||
form: { isSubmitting, errors, touched, setFieldValue, setFieldTouched },
|
||||
property,
|
||||
createFormField,
|
||||
includeDescription,
|
||||
}: DateTimeFieldProps) {
|
||||
|
||||
|
||||
@@ -92,11 +92,15 @@ export default function MapField<S extends EntitySchema>({
|
||||
.map(([entryKey, childProperty], index) => {
|
||||
return <Grid item sm={12} xs={12}
|
||||
key={`map-${field.name}-${index}`}>
|
||||
{createFormField(`${field.name}[${entryKey}]`,
|
||||
childProperty,
|
||||
includeDescription,
|
||||
underlyingValueHasChanged,
|
||||
entitySchema)}
|
||||
{createFormField(
|
||||
{
|
||||
name:`${field.name}[${entryKey}]`,
|
||||
property:childProperty,
|
||||
includeDescription,
|
||||
underlyingValueHasChanged,
|
||||
entitySchema,
|
||||
partOfArray: false
|
||||
})}
|
||||
</Grid>;
|
||||
}
|
||||
)}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { Entity, EntitySchema, FilterValues } from "../../models";
|
||||
import {
|
||||
Entity,
|
||||
EntitySchema,
|
||||
FilterValues,
|
||||
ReferenceProperty
|
||||
} from "../../models";
|
||||
import { getIn } from "formik";
|
||||
import {
|
||||
Box,
|
||||
@@ -60,7 +65,8 @@ export default function ReferenceField<S extends EntitySchema>({
|
||||
form: { isSubmitting, errors, touched, setFieldValue, setFieldTouched },
|
||||
property,
|
||||
includeDescription,
|
||||
entitySchema
|
||||
entitySchema,
|
||||
partOfArray
|
||||
}: ReferenceFieldProps<S>) {
|
||||
|
||||
|
||||
@@ -81,20 +87,18 @@ export default function ReferenceField<S extends EntitySchema>({
|
||||
return (
|
||||
<FormControl error={showError} fullWidth>
|
||||
|
||||
<FormHelperText filled
|
||||
required={property.validation?.required}>
|
||||
<LabelWithIcon scaledIcon={true} property={property}/>
|
||||
</FormHelperText>
|
||||
|
||||
<Box className={`${classes.root}`}>
|
||||
|
||||
<ReferenceDialog value={value}
|
||||
title={title}
|
||||
property={property}
|
||||
collectionPath={property.collectionPath}
|
||||
schema={property.schema === "self" ? entitySchema : property.schema}
|
||||
initialFilter={property.filter}
|
||||
previewProperties={property.previewProperties}
|
||||
textSearchDelegate={property.textSearchDelegate}
|
||||
onEntityClick={handleEntityClick}
|
||||
partOfArray={partOfArray}
|
||||
entitySchema={entitySchema}/>
|
||||
|
||||
</Box>
|
||||
@@ -116,6 +120,8 @@ export interface ReferenceDialogProps<S extends EntitySchema<Key>, Key extends s
|
||||
|
||||
title?: string,
|
||||
|
||||
property: ReferenceProperty;
|
||||
|
||||
/**
|
||||
* Absolute collection path
|
||||
*/
|
||||
@@ -138,6 +144,8 @@ export interface ReferenceDialogProps<S extends EntitySchema<Key>, Key extends s
|
||||
onEntityClick(entity?: Entity<S>): void;
|
||||
|
||||
entitySchema: EntitySchema;
|
||||
|
||||
partOfArray:boolean
|
||||
}
|
||||
|
||||
|
||||
@@ -146,12 +154,14 @@ export function ReferenceDialog<S extends EntitySchema>(
|
||||
onEntityClick,
|
||||
value,
|
||||
title,
|
||||
property,
|
||||
schema,
|
||||
initialFilter,
|
||||
previewProperties,
|
||||
textSearchDelegate,
|
||||
collectionPath,
|
||||
entitySchema
|
||||
entitySchema,
|
||||
partOfArray
|
||||
}: ReferenceDialogProps<S>) {
|
||||
|
||||
const classes = useStyles();
|
||||
@@ -233,23 +243,25 @@ export function ReferenceDialog<S extends EntitySchema>(
|
||||
flexDirection={"column"}
|
||||
flexGrow={1}
|
||||
m={1}>
|
||||
|
||||
{listProperties && listProperties.map((key, index) => {
|
||||
const property = schema.properties[key as string];
|
||||
const propertyKey = schema.properties[key as string];
|
||||
return (
|
||||
<Box key={"ref_prev_" + key + index}
|
||||
m={1}>
|
||||
mt={0.5}
|
||||
mb={0.5}>
|
||||
<ErrorBoundary>{
|
||||
entity ?
|
||||
React.createElement(PreviewComponent, {
|
||||
name: key as string,
|
||||
value: entity.values[key as string],
|
||||
property: property,
|
||||
property: propertyKey,
|
||||
size: "tiny",
|
||||
entitySchema: entitySchema
|
||||
})
|
||||
:
|
||||
<SkeletonComponent
|
||||
property={property}
|
||||
property={propertyKey}
|
||||
size={"tiny"}/>}
|
||||
</ErrorBoundary>
|
||||
</Box>
|
||||
@@ -263,7 +275,21 @@ export function ReferenceDialog<S extends EntitySchema>(
|
||||
<Box onClick={handleClickOpen}
|
||||
display="flex">
|
||||
|
||||
{body}
|
||||
<Box display={"flex"}
|
||||
flexDirection={"column"}
|
||||
flexGrow={1}>
|
||||
|
||||
<Tooltip title={value.path}>
|
||||
<FormHelperText filled
|
||||
required={property.validation?.required}>
|
||||
<LabelWithIcon scaledIcon={true}
|
||||
property={property}/>
|
||||
</FormHelperText>
|
||||
</Tooltip>
|
||||
|
||||
{body}
|
||||
|
||||
</Box>
|
||||
|
||||
{!missingEntity && <Box>
|
||||
<Tooltip title="See details">
|
||||
@@ -274,14 +300,14 @@ export function ReferenceDialog<S extends EntitySchema>(
|
||||
</Tooltip>
|
||||
</Box>}
|
||||
|
||||
<Box>
|
||||
{!partOfArray && <Box>
|
||||
<Tooltip title="Clear">
|
||||
<IconButton
|
||||
onClick={clearValue}>
|
||||
<ClearIcon/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</Box>}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -292,7 +318,7 @@ export function ReferenceDialog<S extends EntitySchema>(
|
||||
{value && buildEntityView()}
|
||||
|
||||
{!value &&
|
||||
<Box p={2}
|
||||
<Box p={1}
|
||||
onClick={handleClickOpen}
|
||||
justifyContent="center"
|
||||
display="flex">
|
||||
|
||||
@@ -21,7 +21,6 @@ export default function Select<T extends EnumType>({
|
||||
field,
|
||||
form: { isSubmitting, errors, touched, setFieldValue, setFieldTouched },
|
||||
property,
|
||||
createFormField,
|
||||
includeDescription,
|
||||
}: SelectProps<T>) {
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ export default React.forwardRef(function SwitchField({
|
||||
form: { isSubmitting, errors, touched, setFieldValue, setFieldTouched },
|
||||
property,
|
||||
includeDescription,
|
||||
createFormField,
|
||||
}: SwitchFieldProps, ref) {
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
@@ -29,7 +29,6 @@ export default function TextField({
|
||||
property,
|
||||
includeDescription,
|
||||
allowInfinity,
|
||||
createFormField,
|
||||
entitySchema,
|
||||
}: TextFieldProps) {
|
||||
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
import { EntitySchema, Property } from "../models";
|
||||
import { ReactElement } from "react";
|
||||
import { FieldProps as FormikFieldProps } from "formik/dist/Field";
|
||||
import { FormFieldProps } from "./index";
|
||||
|
||||
interface BaseCMSFieldProps<T> extends FormikFieldProps<T> {
|
||||
name: string,
|
||||
property: Property<T>,
|
||||
includeDescription: boolean,
|
||||
createFormField: (name: string,
|
||||
property: Property,
|
||||
includeDescription: boolean,
|
||||
underlyingValueHasChanged: boolean,
|
||||
entitySchema: EntitySchema) => ReactElement,
|
||||
createFormField: ({
|
||||
name,
|
||||
property,
|
||||
includeDescription,
|
||||
underlyingValueHasChanged,
|
||||
entitySchema
|
||||
}: FormFieldProps) => ReactElement,
|
||||
underlyingValueHasChanged: boolean;
|
||||
/**
|
||||
* Full schema of the entity
|
||||
*/
|
||||
entitySchema: EntitySchema,
|
||||
|
||||
[key: string]: any
|
||||
partOfArray: boolean,
|
||||
|
||||
}
|
||||
|
||||
export type CMSFieldProps<T> = any & BaseCMSFieldProps<T>;
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
Tooltip
|
||||
} from "@material-ui/core";
|
||||
import { Entity, EntitySchema, EntityStatus, Property } from "../models";
|
||||
import { ErrorMessage, Field, FieldProps } from "formik";
|
||||
import { ErrorMessage, FastField, FieldProps } from "formik";
|
||||
|
||||
import OpenInNewIcon from "@material-ui/icons/OpenInNew";
|
||||
import Select from "./fields/Select";
|
||||
@@ -31,54 +31,26 @@ import { FirebaseConfigContext } from "../contexts";
|
||||
import { useClipboard } from "use-clipboard-hook";
|
||||
import { useSnackbarContext } from "../snackbar_controller";
|
||||
|
||||
function buildField<P extends Property<T>, T = any>(name: string,
|
||||
property: P,
|
||||
includeDescription: boolean,
|
||||
component: React.ComponentType<CMSFieldProps<T>>,
|
||||
underlyingValueHasChanged: boolean,
|
||||
entitySchema: EntitySchema
|
||||
) {
|
||||
|
||||
const additionalFieldProps: any = property.config?.fieldProps;
|
||||
|
||||
return (
|
||||
<Field
|
||||
required={property.validation?.required}
|
||||
name={`${name}`}
|
||||
>
|
||||
{(fieldProps: FieldProps<T>) => (
|
||||
<React.Fragment>
|
||||
|
||||
{React.createElement(component, {
|
||||
...fieldProps,
|
||||
...additionalFieldProps,
|
||||
name: fieldProps.field.name,
|
||||
includeDescription,
|
||||
property,
|
||||
createFormField,
|
||||
underlyingValueHasChanged,
|
||||
entitySchema
|
||||
})}
|
||||
|
||||
{underlyingValueHasChanged && !fieldProps.form.isSubmitting &&
|
||||
<FormHelperText>
|
||||
This value has been updated in Firestore
|
||||
</FormHelperText>}
|
||||
|
||||
</React.Fragment>)
|
||||
}
|
||||
|
||||
</Field>);
|
||||
export interface FormFieldProps {
|
||||
name: string,
|
||||
property: Property,
|
||||
includeDescription: boolean,
|
||||
underlyingValueHasChanged: boolean,
|
||||
entitySchema: EntitySchema,
|
||||
partOfArray: boolean,
|
||||
}
|
||||
|
||||
export function createFormField<T>(name: string,
|
||||
property: Property,
|
||||
includeDescription: boolean,
|
||||
underlyingValueHasChanged: boolean,
|
||||
entitySchema: EntitySchema): JSX.Element {
|
||||
export function createFormField<T>({
|
||||
name,
|
||||
property,
|
||||
includeDescription,
|
||||
underlyingValueHasChanged,
|
||||
entitySchema,
|
||||
partOfArray
|
||||
}: FormFieldProps): JSX.Element {
|
||||
|
||||
if (property.disabled) {
|
||||
return buildField(name, property, includeDescription, DisabledField, underlyingValueHasChanged, entitySchema);
|
||||
return buildFieldInternal(name, property, includeDescription, DisabledField, underlyingValueHasChanged, entitySchema, partOfArray);
|
||||
}
|
||||
|
||||
let component: React.ComponentType<CMSFieldProps<T>> | undefined;
|
||||
@@ -122,13 +94,55 @@ export function createFormField<T>(name: string,
|
||||
}
|
||||
}
|
||||
if (component)
|
||||
return buildField(name, property, includeDescription, component, underlyingValueHasChanged, entitySchema);
|
||||
return buildFieldInternal(name, property, includeDescription, component, underlyingValueHasChanged, entitySchema, partOfArray);
|
||||
|
||||
return (
|
||||
<div>{`Currently the field ${property.dataType} is not supported`}</div>
|
||||
);
|
||||
}
|
||||
|
||||
function buildFieldInternal<P extends Property<T>, T = any>(name: string,
|
||||
property: P,
|
||||
includeDescription: boolean,
|
||||
component: React.ComponentType<CMSFieldProps<T>>,
|
||||
underlyingValueHasChanged: boolean,
|
||||
entitySchema: EntitySchema,
|
||||
partOfArray:boolean
|
||||
) {
|
||||
|
||||
const additionalFieldProps: any = property.config?.fieldProps;
|
||||
|
||||
return (
|
||||
<FastField
|
||||
required={property.validation?.required}
|
||||
name={`${name}`}
|
||||
>
|
||||
{(fieldProps: FieldProps<T>) => (
|
||||
<React.Fragment>
|
||||
|
||||
{React.createElement(component, {
|
||||
...fieldProps,
|
||||
...additionalFieldProps,
|
||||
name: fieldProps.field.name,
|
||||
includeDescription,
|
||||
property,
|
||||
createFormField,
|
||||
underlyingValueHasChanged,
|
||||
entitySchema,
|
||||
partOfArray
|
||||
})}
|
||||
|
||||
{underlyingValueHasChanged && !fieldProps.form.isSubmitting &&
|
||||
<FormHelperText>
|
||||
This value has been updated in Firestore
|
||||
</FormHelperText>}
|
||||
|
||||
</React.Fragment>)
|
||||
}
|
||||
|
||||
</FastField>);
|
||||
}
|
||||
|
||||
|
||||
export function createCustomIdField<S extends EntitySchema>(schema: EntitySchema, formType: EntityStatus, onChange: Function, error: boolean, entity: Entity<S> | undefined) {
|
||||
|
||||
@@ -137,11 +151,11 @@ export function createCustomIdField<S extends EntitySchema>(schema: EntitySchema
|
||||
const hasEnumValues = typeof schema.customId === "object";
|
||||
|
||||
const snackbarContext = useSnackbarContext();
|
||||
const {ref, copy, cut} = useClipboard({
|
||||
onSuccess: (text) => snackbarContext.open({
|
||||
const { ref, copy, cut } = useClipboard({
|
||||
onSuccess: (text) => snackbarContext.open({
|
||||
type: "success",
|
||||
message: `Copied ${text}`
|
||||
}),
|
||||
})
|
||||
});
|
||||
|
||||
const inputProps = entity ? {
|
||||
@@ -182,7 +196,7 @@ export function createCustomIdField<S extends EntitySchema>(schema: EntitySchema
|
||||
name: "id",
|
||||
type: null,
|
||||
value: entity ? entity.id : undefined,
|
||||
variant: "filled",
|
||||
variant: "filled"
|
||||
};
|
||||
return (
|
||||
<FormControl fullWidth error={error}
|
||||
|
||||
@@ -286,9 +286,10 @@ export function EntityFormRoute<S extends EntitySchema>({
|
||||
message: e?.message
|
||||
});
|
||||
}
|
||||
history.goBack();
|
||||
}
|
||||
|
||||
history.goBack();
|
||||
|
||||
})
|
||||
.catch((e) => {
|
||||
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
/* add css module styles here (optional) */
|
||||
|
||||
.test {
|
||||
margin: 2em;
|
||||
padding: 0.5em;
|
||||
border: 2px solid #000;
|
||||
font-size: 2em;
|
||||
text-align: center;
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
67
yarn.lock
67
yarn.lock
@@ -2816,6 +2816,21 @@
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
|
||||
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
|
||||
|
||||
"@react-dnd/asap@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-dnd/asap/-/asap-4.0.0.tgz#b300eeed83e9801f51bd66b0337c9a6f04548651"
|
||||
integrity sha512-0XhqJSc6pPoNnf8DhdsPHtUhRzZALVzYMTzRwV4VI6DJNJ/5xxfL9OQUwb8IH5/2x7lSf7nAZrnzUD+16VyOVQ==
|
||||
|
||||
"@react-dnd/invariant@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-dnd/invariant/-/invariant-2.0.0.tgz#09d2e81cd39e0e767d7da62df9325860f24e517e"
|
||||
integrity sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==
|
||||
|
||||
"@react-dnd/shallowequal@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz#a3031eb54129f2c66b2753f8404266ec7bf67f0a"
|
||||
integrity sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==
|
||||
|
||||
"@rollup/plugin-alias@^3.0.1":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-alias/-/plugin-alias-3.1.0.tgz#4f7bc9d15e030d75da9224aaa5105129c54a3ffd"
|
||||
@@ -3151,6 +3166,14 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.5.tgz#527d20ef68571a4af02ed74350164e7a67544860"
|
||||
integrity sha512-wLD/Aq2VggCJXSjxEwrMafIP51Z+13H78nXIX0ABEuIGhmB5sNGbR113MOKo+yfw+RDo1ZU3DM6yfnnRF/+ouw==
|
||||
|
||||
"@types/hoist-non-react-statics@^3.3.1":
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
|
||||
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
|
||||
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
|
||||
@@ -5784,6 +5807,15 @@ dir-glob@^3.0.1:
|
||||
dependencies:
|
||||
path-type "^4.0.0"
|
||||
|
||||
dnd-core@^11.1.3:
|
||||
version "11.1.3"
|
||||
resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-11.1.3.tgz#f92099ba7245e49729d2433157031a6267afcc98"
|
||||
integrity sha512-QugF55dNW+h+vzxVJ/LSJeTeUw9MCJ2cllhmVThVPEtF16ooBkxj0WBE5RB+AceFxMFo1rO6bJKXtqKl+JNnyA==
|
||||
dependencies:
|
||||
"@react-dnd/asap" "^4.0.0"
|
||||
"@react-dnd/invariant" "^2.0.0"
|
||||
redux "^4.0.4"
|
||||
|
||||
dns-equal@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
|
||||
@@ -7859,6 +7891,11 @@ immer@1.10.0:
|
||||
resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d"
|
||||
integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==
|
||||
|
||||
immutability-helper@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/immutability-helper/-/immutability-helper-3.1.1.tgz#2b86b2286ed3b1241c9e23b7b21e0444f52f77b7"
|
||||
integrity sha512-Q0QaXjPjwIju/28TsugCHNEASwoCcJSyJV3uO1sOIQGI0jKgm9f41Lvz0DZj3n46cNCyAZTsEYoY4C2bVRUzyQ==
|
||||
|
||||
import-cwd@^2.0.0, import-cwd@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
|
||||
@@ -11875,6 +11912,23 @@ react-dev-utils@^10.2.1:
|
||||
strip-ansi "6.0.0"
|
||||
text-table "0.2.0"
|
||||
|
||||
react-dnd-html5-backend@^11.1.3:
|
||||
version "11.1.3"
|
||||
resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-11.1.3.tgz#2749f04f416ec230ea193f5c1fbea2de7dffb8f7"
|
||||
integrity sha512-/1FjNlJbW/ivkUxlxQd7o3trA5DE33QiRZgxent3zKme8DwF4Nbw3OFVhTRFGaYhHFNL1rZt6Rdj1D78BjnNLw==
|
||||
dependencies:
|
||||
dnd-core "^11.1.3"
|
||||
|
||||
react-dnd@^11.1.3:
|
||||
version "11.1.3"
|
||||
resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-11.1.3.tgz#f9844f5699ccc55dfc81462c2c19f726e670c1af"
|
||||
integrity sha512-8rtzzT8iwHgdSC89VktwhqdKKtfXaAyC4wiqp0SywpHG12TTLvfOoL6xNEIUWXwIEWu+CFfDn4GZJyynCEuHIQ==
|
||||
dependencies:
|
||||
"@react-dnd/shallowequal" "^2.0.0"
|
||||
"@types/hoist-non-react-statics" "^3.3.1"
|
||||
dnd-core "^11.1.3"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
|
||||
react-dom@^16.13.1:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f"
|
||||
@@ -12147,6 +12201,14 @@ recursive-readdir@2.2.2:
|
||||
dependencies:
|
||||
minimatch "3.0.4"
|
||||
|
||||
redux@^4.0.4:
|
||||
version "4.0.5"
|
||||
resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f"
|
||||
integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==
|
||||
dependencies:
|
||||
loose-envify "^1.4.0"
|
||||
symbol-observable "^1.2.0"
|
||||
|
||||
regenerate-unicode-properties@^8.2.0:
|
||||
version "8.2.0"
|
||||
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
|
||||
@@ -13497,6 +13559,11 @@ svgo@^1.0.0, svgo@^1.2.2:
|
||||
unquote "~1.1.1"
|
||||
util.promisify "~1.0.0"
|
||||
|
||||
symbol-observable@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
|
||||
integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
|
||||
|
||||
symbol-tree@^3.2.2:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
|
||||
|
||||
Reference in New Issue
Block a user