Merge pull request #5897 from strapi/fix/single-types-issues

Fix single types navigation
This commit is contained in:
cyril lopez 2020-04-24 09:44:53 +02:00 committed by GitHub
commit 81c94c9ea0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 48 additions and 47 deletions

View File

@ -14,7 +14,8 @@
},
"slug": {
"type": "uid",
"targetField": "title"
"targetField": "title",
"required": true
},
"single": {
"model": "file",

View File

@ -32,13 +32,8 @@ const FieldComponent = ({
const componentValue = get(modifiedData, name, null);
const componentValueLength = size(componentValue);
const isInitialized = componentValue !== null || isFromDynamicZone;
const showResetComponent =
!isRepeatable && isInitialized && !isFromDynamicZone;
const currentComponentSchema = get(
allLayoutData,
['components', componentUid],
{}
);
const showResetComponent = !isRepeatable && isInitialized && !isFromDynamicZone;
const currentComponentSchema = get(allLayoutData, ['components', componentUid], {});
const displayedFields = get(currentComponentSchema, ['layouts', 'edit'], []);

View File

@ -7,7 +7,7 @@ import { useDebounce, useClickAwayListener } from '@buffetjs/hooks';
import styled from 'styled-components';
import { request, LoadingIndicator } from 'strapi-helper-plugin';
import { FormattedMessage } from 'react-intl';
import { isEmpty } from 'lodash';
import { get } from 'lodash';
import pluginId from '../../pluginId';
import getRequestUrl from '../../utils/getRequestUrl';
@ -42,13 +42,12 @@ const InputUID = ({
error: inputError,
name,
onChange,
required,
validations,
value,
editable,
...inputProps
}) => {
const { modifiedData, initialData } = useDataManager();
const { modifiedData, initialData, layout } = useDataManager();
const [isLoading, setIsLoading] = useState(false);
const [availability, setAvailability] = useState(null);
const [isSuggestionOpen, setIsSuggestionOpen] = useState(true);
@ -59,9 +58,10 @@ const InputUID = ({
const wrapperRef = useRef(null);
const generateUid = useRef();
const initialValue = initialData[name];
const isCreation = isEmpty(initialData);
const createdAtName = get(layout, ['schema', 'options', 'timestamps', 0]);
const isCreation = !initialData[createdAtName];
generateUid.current = async () => {
generateUid.current = async (shouldSetInitialValue = false) => {
setIsLoading(true);
const requestURL = getRequestUrl('explorer/uid/generate');
try {
@ -73,7 +73,8 @@ const InputUID = ({
data: modifiedData,
},
});
onChange({ target: { name, value: data, type: 'text' } });
onChange({ target: { name, value: data, type: 'text' } }, shouldSetInitialValue);
setIsLoading(false);
} catch (err) {
console.error({ err });
@ -106,8 +107,8 @@ const InputUID = ({
};
useEffect(() => {
if (!value && required) {
generateUid.current();
if (!value && validations.required) {
generateUid.current(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
@ -143,9 +144,15 @@ const InputUID = ({
}, [availability]);
useEffect(() => {
if (!isCustomized && isCreation && debouncedTargetFieldValue !== null) {
generateUid.current();
if (
!isCustomized &&
isCreation &&
debouncedTargetFieldValue &&
modifiedData[attribute.targetField]
) {
generateUid.current(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [debouncedTargetFieldValue, isCustomized, isCreation]);
useClickAwayListener(wrapperRef, () => setIsSuggestionOpen(false));
@ -220,7 +227,7 @@ const InputUID = ({
<RegenerateButton
onMouseEnter={handleGenerateMouseEnter}
onMouseLeave={handleGenerateMouseLeave}
onClick={generateUid.current}
onClick={() => generateUid.current()}
>
{isLoading ? (
<LoadingIndicator small />
@ -264,7 +271,6 @@ InputUID.propTypes = {
error: PropTypes.string,
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
required: PropTypes.bool,
validations: PropTypes.object,
value: PropTypes.string,
};
@ -273,7 +279,6 @@ InputUID.defaultProps = {
description: '',
editable: false,
error: null,
required: false,
validations: {},
value: '',
};

View File

@ -53,13 +53,10 @@ const RepeatableComponent = ({
});
};
const missingComponentsValue = min - componentValueLength;
const errorsArray = componentErrorKeys.map(key =>
get(formErrors, [key, 'id'], '')
);
const errorsArray = componentErrorKeys.map(key => get(formErrors, [key, 'id'], ''));
const hasMinError =
get(errorsArray, [0], '').includes('min') &&
!collapses.some(obj => obj.isOpen === true);
get(errorsArray, [0], '').includes('min') && !collapses.some(obj => obj.isOpen === true);
return (
<div>
@ -84,9 +81,7 @@ const RepeatableComponent = ({
<DraggedItem
fields={fields}
componentFieldName={componentFieldName}
doesPreviousFieldContainErrorsAndIsOpen={
doesPreviousFieldContainErrorsAndIsOpen
}
doesPreviousFieldContainErrorsAndIsOpen={doesPreviousFieldContainErrorsAndIsOpen}
hasErrors={hasErrors}
hasMinError={hasMinError}
isFirst={index === 0}
@ -129,11 +124,7 @@ const RepeatableComponent = ({
if (componentValueLength < max) {
const shouldCheckErrors = hasMinError;
addRepeatableComponentToField(
name,
componentUid,
shouldCheckErrors
);
addRepeatableComponentToField(name, componentUid, shouldCheckErrors);
dispatch({
type: 'ADD_NEW_FIELD',
});

View File

@ -21,7 +21,7 @@ import reducer, { initialState } from './reducer';
/* eslint-disable react/no-array-index-key */
const EditView = ({ components, currentEnvironment, layouts, plugins, slug }) => {
const EditView = ({ components, currentEnvironment, deleteLayout, layouts, plugins, slug }) => {
const formatLayoutRef = useRef();
formatLayoutRef.current = createAttributesLayout;
// Retrieve push to programmatically navigate between views
@ -95,6 +95,9 @@ const EditView = ({ components, currentEnvironment, layouts, plugins, slug }) =>
currentContentTypeSchema.attributes
),
});
return () => deleteLayout(slug);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentContentTypeLayout, currentContentTypeSchema.attributes]);
const { formattedContentTypeLayout, isDraggingComponent } = reducerState.toJS();
@ -265,12 +268,13 @@ EditView.defaultProps = {
};
EditView.propTypes = {
currentEnvironment: PropTypes.string,
components: PropTypes.array.isRequired,
currentEnvironment: PropTypes.string,
deleteLayout: PropTypes.func.isRequired,
emitEvent: PropTypes.func,
layouts: PropTypes.object.isRequired,
slug: PropTypes.string.isRequired,
plugins: PropTypes.object,
slug: PropTypes.string.isRequired,
};
export { EditView };

View File

@ -77,6 +77,7 @@ const EditViewDataManagerProvider = ({ allLayoutData, children, redirectToPrevio
return acc;
}, {});
const contentTypeDataStructure = createDefaultForm(
currentContentTypeLayout.schema.attributes,
allLayoutData.components
@ -181,7 +182,7 @@ const EditViewDataManagerProvider = ({ allLayoutData, children, redirectToPrevio
});
};
const handleChange = ({ target: { name, value, type } }) => {
const handleChange = ({ target: { name, value, type } }, shouldSetInitialValue = false) => {
let inputValue = value;
// Empty string is not a valid date,
@ -213,6 +214,7 @@ const EditViewDataManagerProvider = ({ allLayoutData, children, redirectToPrevio
type: 'ON_CHANGE',
keys: name.split('.'),
value: inputValue,
shouldSetInitialValue,
});
};

View File

@ -135,11 +135,21 @@ const reducer = (state, action) => {
let newState = state;
const [nonRepeatableComponentKey] = action.keys;
// This is used to set the initialData for inputs
// that needs an asynchronous initial value like the UID field
// This is just a temporary patch.
// TODO : Refactor the default form creation (workflow) to accept async default values.
if (action.shouldSetInitialValue) {
newState = state.updateIn(['initialData', ...action.keys], () => {
return action.value;
});
}
if (
action.keys.length === 2 &&
state.getIn(['modifiedData', nonRepeatableComponentKey]) === null
) {
newState = state.updateIn(['modifiedData', nonRepeatableComponentKey], () => fromJS({}));
newState = newState.updateIn(['modifiedData', nonRepeatableComponentKey], () => fromJS({}));
}
return newState.updateIn(['modifiedData', ...action.keys], () => {

View File

@ -3,14 +3,7 @@ import { get } from 'lodash';
const createDefaultForm = (attributes, allComponentsSchema) => {
return Object.keys(attributes).reduce((acc, current) => {
const attribute = get(attributes, [current], {});
const {
default: defaultValue,
component,
type,
required,
min,
repeatable,
} = attribute;
const { default: defaultValue, component, type, required, min, repeatable } = attribute;
if (type === 'json') {
acc[current] = null;