Merge branch 'master' into graphql-tests
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useReducer, useCallback } from 'react';
|
||||
import React, { useEffect, useReducer, useCallback, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
@@ -17,7 +17,7 @@ import './index.scss';
|
||||
|
||||
const baseClass = 'field-type array';
|
||||
|
||||
const Array = (props) => {
|
||||
const ArrayFieldType = (props) => {
|
||||
const {
|
||||
label,
|
||||
name,
|
||||
@@ -48,6 +48,8 @@ const Array = (props) => {
|
||||
return validationResult;
|
||||
}, [validate, maxRows, minRows, required]);
|
||||
|
||||
const [disableFormData, setDisableFormData] = useState(false);
|
||||
|
||||
const {
|
||||
showError,
|
||||
errorMessage,
|
||||
@@ -56,7 +58,7 @@ const Array = (props) => {
|
||||
} = useFieldType({
|
||||
path,
|
||||
validate: memoizedValidate,
|
||||
disableFormData: true,
|
||||
disableFormData,
|
||||
initialData: initialData?.length,
|
||||
defaultValue: defaultValue?.length,
|
||||
required,
|
||||
@@ -113,6 +115,16 @@ const Array = (props) => {
|
||||
});
|
||||
}, [dataToInitialize]);
|
||||
|
||||
useEffect(() => {
|
||||
if (value === 0 && dataToInitialize.length > 0 && disableFormData) {
|
||||
setDisableFormData(false);
|
||||
setValue(value);
|
||||
} else if (value > 0 && !disableFormData) {
|
||||
setDisableFormData(true);
|
||||
setValue(value);
|
||||
}
|
||||
}, [value, setValue, disableFormData, dataToInitialize]);
|
||||
|
||||
return (
|
||||
<DragDropContext onDragEnd={onDragEnd}>
|
||||
<div className={baseClass}>
|
||||
@@ -171,7 +183,7 @@ const Array = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
Array.defaultProps = {
|
||||
ArrayFieldType.defaultProps = {
|
||||
label: '',
|
||||
defaultValue: [],
|
||||
initialData: [],
|
||||
@@ -185,7 +197,7 @@ Array.defaultProps = {
|
||||
permissions: {},
|
||||
};
|
||||
|
||||
Array.propTypes = {
|
||||
ArrayFieldType.propTypes = {
|
||||
defaultValue: PropTypes.arrayOf(
|
||||
PropTypes.shape({}),
|
||||
),
|
||||
@@ -211,4 +223,4 @@ Array.propTypes = {
|
||||
}),
|
||||
};
|
||||
|
||||
export default withCondition(Array);
|
||||
export default withCondition(ArrayFieldType);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, {
|
||||
useEffect, useReducer, useCallback,
|
||||
useEffect, useReducer, useCallback, useState,
|
||||
} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
|
||||
@@ -50,6 +50,8 @@ const Blocks = (props) => {
|
||||
return validationResult;
|
||||
}, [validate, maxRows, minRows, singularLabel, blocks, required]);
|
||||
|
||||
const [disableFormData, setDisableFormData] = useState(false);
|
||||
|
||||
const {
|
||||
showError,
|
||||
errorMessage,
|
||||
@@ -58,7 +60,7 @@ const Blocks = (props) => {
|
||||
} = useFieldType({
|
||||
path,
|
||||
validate: memoizedValidate,
|
||||
disableFormData: true,
|
||||
disableFormData,
|
||||
initialData: initialData?.length,
|
||||
defaultValue: defaultValue?.length,
|
||||
required,
|
||||
@@ -126,6 +128,17 @@ const Blocks = (props) => {
|
||||
});
|
||||
}, [dataToInitialize]);
|
||||
|
||||
useEffect(() => {
|
||||
if (value === 0 && dataToInitialize.length > 0 && disableFormData) {
|
||||
setDisableFormData(false);
|
||||
setValue(value);
|
||||
} else if (value > 0 && !disableFormData) {
|
||||
setDisableFormData(true);
|
||||
setValue(value);
|
||||
}
|
||||
}, [value, setValue, disableFormData, dataToInitialize]);
|
||||
|
||||
|
||||
return (
|
||||
<DragDropContext onDragEnd={onDragEnd}>
|
||||
<div className={baseClass}>
|
||||
@@ -237,6 +250,9 @@ Blocks.defaultProps = {
|
||||
};
|
||||
|
||||
Blocks.propTypes = {
|
||||
blocks: PropTypes.arrayOf(
|
||||
PropTypes.shape({}),
|
||||
).isRequired,
|
||||
defaultValue: PropTypes.arrayOf(
|
||||
PropTypes.shape({}),
|
||||
),
|
||||
|
||||
@@ -28,6 +28,7 @@ function registerCollections() {
|
||||
plural,
|
||||
},
|
||||
fields: initialFields,
|
||||
timestamps,
|
||||
},
|
||||
} = collection;
|
||||
|
||||
@@ -48,18 +49,48 @@ function registerCollections() {
|
||||
|
||||
collection.graphQL = {};
|
||||
|
||||
const baseFields = {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLString),
|
||||
},
|
||||
};
|
||||
|
||||
const whereInputFields = [
|
||||
...fields,
|
||||
];
|
||||
|
||||
if (timestamps) {
|
||||
baseFields.createdAt = {
|
||||
type: new GraphQLNonNull(GraphQLString),
|
||||
};
|
||||
|
||||
baseFields.updatedAt = {
|
||||
type: new GraphQLNonNull(GraphQLString),
|
||||
};
|
||||
|
||||
whereInputFields.push({
|
||||
name: 'createdAt',
|
||||
label: 'Created At',
|
||||
type: 'date',
|
||||
});
|
||||
|
||||
whereInputFields.push({
|
||||
name: 'updatedAt',
|
||||
label: 'Upated At',
|
||||
type: 'date',
|
||||
});
|
||||
}
|
||||
|
||||
collection.graphQL.type = this.buildObjectType(
|
||||
singularLabel,
|
||||
fields,
|
||||
singularLabel,
|
||||
{
|
||||
id: { type: GraphQLString },
|
||||
},
|
||||
baseFields,
|
||||
);
|
||||
|
||||
collection.graphQL.whereInputType = this.buildWhereInputType(
|
||||
singularLabel,
|
||||
fields,
|
||||
whereInputFields,
|
||||
singularLabel,
|
||||
);
|
||||
|
||||
|
||||
@@ -113,6 +113,11 @@ module.exports = async (config, entityConfig, operation) => {
|
||||
const hasRowsOfData = Array.isArray(data[field.name]);
|
||||
const rowCount = hasRowsOfData ? data[field.name].length : 0;
|
||||
|
||||
if (data[field.name] === '0' || data[field.name] === 0 || data[field.name] === null) {
|
||||
const updatedData = data;
|
||||
updatedData[field.name] = [];
|
||||
}
|
||||
|
||||
validationPromises.push(createValidationPromise(rowCount, field, path));
|
||||
} else {
|
||||
validationPromises.push(createValidationPromise(data[field.name], field, path));
|
||||
|
||||
@@ -14,11 +14,9 @@ const errorHandler = require('./errorHandler');
|
||||
const { access } = require('../auth/graphql/resolvers');
|
||||
|
||||
class GraphQL {
|
||||
constructor(init, req, res) {
|
||||
constructor(init) {
|
||||
Object.assign(this, init);
|
||||
this.init = this.init.bind(this);
|
||||
this.req = req;
|
||||
this.res = res;
|
||||
|
||||
this.types = {
|
||||
blockTypes: {},
|
||||
@@ -46,9 +44,7 @@ class GraphQL {
|
||||
this.buildPoliciesType = buildPoliciesType.bind(this);
|
||||
this.initCollections = initCollections.bind(this);
|
||||
this.initGlobals = initGlobals.bind(this);
|
||||
}
|
||||
|
||||
init() {
|
||||
this.initCollections();
|
||||
this.initGlobals();
|
||||
|
||||
@@ -69,34 +65,37 @@ class GraphQL {
|
||||
|
||||
const query = new GraphQLObjectType(this.Query);
|
||||
const mutation = new GraphQLObjectType(this.Mutation);
|
||||
const schema = new GraphQLSchema({
|
||||
|
||||
this.schema = new GraphQLSchema({
|
||||
query,
|
||||
mutation,
|
||||
});
|
||||
|
||||
let errorExtensions = [];
|
||||
let errorExtensionIteration = 0;
|
||||
this.errorExtensions = [];
|
||||
this.errorExtensionIteration = 0;
|
||||
|
||||
const extensions = async (info) => {
|
||||
this.extensions = async (info) => {
|
||||
const { result } = info;
|
||||
if (result.errors) {
|
||||
const afterErrorHook = typeof this.config.hooks.afterError === 'function' ? this.config.hooks.afterError : null;
|
||||
errorExtensions = await errorHandler(info, this.config.debug, afterErrorHook);
|
||||
this.errorExtensions = await errorHandler(info, this.config.debug, afterErrorHook);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
init(req, res) {
|
||||
return graphQLHTTP({
|
||||
schema,
|
||||
schema: this.schema,
|
||||
customFormatErrorFn: () => {
|
||||
const response = {
|
||||
...errorExtensions[errorExtensionIteration],
|
||||
...this.errorExtensions[this.errorExtensionIteration],
|
||||
};
|
||||
errorExtensionIteration += 1;
|
||||
this.errorExtensionIteration += 1;
|
||||
return response;
|
||||
},
|
||||
extensions,
|
||||
context: { req: this.req, res: this.res },
|
||||
extensions: this.extensions,
|
||||
context: { req, res },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
const { GraphQLNonNull } = require('graphql');
|
||||
|
||||
const withNullableType = (field, type) => {
|
||||
if (field.required && !field.localized) {
|
||||
const hasReadAccessControl = field.access && field.access.read;
|
||||
|
||||
if (field.required && !field.localized && !hasReadAccessControl) {
|
||||
return new GraphQLNonNull(type);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,10 +55,12 @@ class Payload {
|
||||
|
||||
this.router.get('/access', access(this.config));
|
||||
|
||||
const graphQLHandler = new GraphQL(this);
|
||||
|
||||
this.router.use(
|
||||
this.config.routes.graphQL,
|
||||
identifyAPI('GraphQL'),
|
||||
(req, res) => new GraphQL(this, req, res).init()(req, res),
|
||||
(req, res) => graphQLHandler.init(req, res)(req, res),
|
||||
);
|
||||
|
||||
this.router.get(this.config.routes.graphQLPlayground, graphQLPlayground({
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
const connectMongoose = async (url) => {
|
||||
@@ -12,16 +13,16 @@ const connectMongoose = async (url) => {
|
||||
successfulConnectionMessage = 'Connected to in-memory Mongo server successfully!';
|
||||
}
|
||||
|
||||
mongoose.connect(urlToConnect, {
|
||||
useNewUrlParser: true,
|
||||
useUnifiedTopology: true,
|
||||
}, (err) => {
|
||||
if (err) {
|
||||
console.log('Unable to connect to the Mongo server. Please start the server. Error:', err);
|
||||
} else {
|
||||
console.log(successfulConnectionMessage);
|
||||
}
|
||||
});
|
||||
try {
|
||||
await mongoose.connect(urlToConnect, {
|
||||
useNewUrlParser: true,
|
||||
useUnifiedTopology: true,
|
||||
});
|
||||
console.log(successfulConnectionMessage);
|
||||
} catch (err) {
|
||||
console.error('Error: cannot connect to MongoDB. Details: ', err);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = connectMongoose;
|
||||
|
||||
Reference in New Issue
Block a user