mirror of
https://github.com/strapi/strapi.git
synced 2025-08-13 11:17:42 +00:00
Merge pull request #5897 from strapi/fix/single-types-issues
Fix single types navigation
This commit is contained in:
commit
81c94c9ea0
@ -14,7 +14,8 @@
|
|||||||
},
|
},
|
||||||
"slug": {
|
"slug": {
|
||||||
"type": "uid",
|
"type": "uid",
|
||||||
"targetField": "title"
|
"targetField": "title",
|
||||||
|
"required": true
|
||||||
},
|
},
|
||||||
"single": {
|
"single": {
|
||||||
"model": "file",
|
"model": "file",
|
||||||
|
@ -32,13 +32,8 @@ const FieldComponent = ({
|
|||||||
const componentValue = get(modifiedData, name, null);
|
const componentValue = get(modifiedData, name, null);
|
||||||
const componentValueLength = size(componentValue);
|
const componentValueLength = size(componentValue);
|
||||||
const isInitialized = componentValue !== null || isFromDynamicZone;
|
const isInitialized = componentValue !== null || isFromDynamicZone;
|
||||||
const showResetComponent =
|
const showResetComponent = !isRepeatable && isInitialized && !isFromDynamicZone;
|
||||||
!isRepeatable && isInitialized && !isFromDynamicZone;
|
const currentComponentSchema = get(allLayoutData, ['components', componentUid], {});
|
||||||
const currentComponentSchema = get(
|
|
||||||
allLayoutData,
|
|
||||||
['components', componentUid],
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
|
|
||||||
const displayedFields = get(currentComponentSchema, ['layouts', 'edit'], []);
|
const displayedFields = get(currentComponentSchema, ['layouts', 'edit'], []);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import { useDebounce, useClickAwayListener } from '@buffetjs/hooks';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { request, LoadingIndicator } from 'strapi-helper-plugin';
|
import { request, LoadingIndicator } from 'strapi-helper-plugin';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { isEmpty } from 'lodash';
|
import { get } from 'lodash';
|
||||||
|
|
||||||
import pluginId from '../../pluginId';
|
import pluginId from '../../pluginId';
|
||||||
import getRequestUrl from '../../utils/getRequestUrl';
|
import getRequestUrl from '../../utils/getRequestUrl';
|
||||||
@ -42,13 +42,12 @@ const InputUID = ({
|
|||||||
error: inputError,
|
error: inputError,
|
||||||
name,
|
name,
|
||||||
onChange,
|
onChange,
|
||||||
required,
|
|
||||||
validations,
|
validations,
|
||||||
value,
|
value,
|
||||||
editable,
|
editable,
|
||||||
...inputProps
|
...inputProps
|
||||||
}) => {
|
}) => {
|
||||||
const { modifiedData, initialData } = useDataManager();
|
const { modifiedData, initialData, layout } = useDataManager();
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [availability, setAvailability] = useState(null);
|
const [availability, setAvailability] = useState(null);
|
||||||
const [isSuggestionOpen, setIsSuggestionOpen] = useState(true);
|
const [isSuggestionOpen, setIsSuggestionOpen] = useState(true);
|
||||||
@ -59,9 +58,10 @@ const InputUID = ({
|
|||||||
const wrapperRef = useRef(null);
|
const wrapperRef = useRef(null);
|
||||||
const generateUid = useRef();
|
const generateUid = useRef();
|
||||||
const initialValue = initialData[name];
|
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);
|
setIsLoading(true);
|
||||||
const requestURL = getRequestUrl('explorer/uid/generate');
|
const requestURL = getRequestUrl('explorer/uid/generate');
|
||||||
try {
|
try {
|
||||||
@ -73,7 +73,8 @@ const InputUID = ({
|
|||||||
data: modifiedData,
|
data: modifiedData,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
onChange({ target: { name, value: data, type: 'text' } });
|
|
||||||
|
onChange({ target: { name, value: data, type: 'text' } }, shouldSetInitialValue);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error({ err });
|
console.error({ err });
|
||||||
@ -106,8 +107,8 @@ const InputUID = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!value && required) {
|
if (!value && validations.required) {
|
||||||
generateUid.current();
|
generateUid.current(true);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
@ -143,9 +144,15 @@ const InputUID = ({
|
|||||||
}, [availability]);
|
}, [availability]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isCustomized && isCreation && debouncedTargetFieldValue !== null) {
|
if (
|
||||||
generateUid.current();
|
!isCustomized &&
|
||||||
|
isCreation &&
|
||||||
|
debouncedTargetFieldValue &&
|
||||||
|
modifiedData[attribute.targetField]
|
||||||
|
) {
|
||||||
|
generateUid.current(true);
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [debouncedTargetFieldValue, isCustomized, isCreation]);
|
}, [debouncedTargetFieldValue, isCustomized, isCreation]);
|
||||||
|
|
||||||
useClickAwayListener(wrapperRef, () => setIsSuggestionOpen(false));
|
useClickAwayListener(wrapperRef, () => setIsSuggestionOpen(false));
|
||||||
@ -220,7 +227,7 @@ const InputUID = ({
|
|||||||
<RegenerateButton
|
<RegenerateButton
|
||||||
onMouseEnter={handleGenerateMouseEnter}
|
onMouseEnter={handleGenerateMouseEnter}
|
||||||
onMouseLeave={handleGenerateMouseLeave}
|
onMouseLeave={handleGenerateMouseLeave}
|
||||||
onClick={generateUid.current}
|
onClick={() => generateUid.current()}
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<LoadingIndicator small />
|
<LoadingIndicator small />
|
||||||
@ -264,7 +271,6 @@ InputUID.propTypes = {
|
|||||||
error: PropTypes.string,
|
error: PropTypes.string,
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
onChange: PropTypes.func.isRequired,
|
onChange: PropTypes.func.isRequired,
|
||||||
required: PropTypes.bool,
|
|
||||||
validations: PropTypes.object,
|
validations: PropTypes.object,
|
||||||
value: PropTypes.string,
|
value: PropTypes.string,
|
||||||
};
|
};
|
||||||
@ -273,7 +279,6 @@ InputUID.defaultProps = {
|
|||||||
description: '',
|
description: '',
|
||||||
editable: false,
|
editable: false,
|
||||||
error: null,
|
error: null,
|
||||||
required: false,
|
|
||||||
validations: {},
|
validations: {},
|
||||||
value: '',
|
value: '',
|
||||||
};
|
};
|
||||||
|
@ -53,13 +53,10 @@ const RepeatableComponent = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
const missingComponentsValue = min - componentValueLength;
|
const missingComponentsValue = min - componentValueLength;
|
||||||
const errorsArray = componentErrorKeys.map(key =>
|
const errorsArray = componentErrorKeys.map(key => get(formErrors, [key, 'id'], ''));
|
||||||
get(formErrors, [key, 'id'], '')
|
|
||||||
);
|
|
||||||
|
|
||||||
const hasMinError =
|
const hasMinError =
|
||||||
get(errorsArray, [0], '').includes('min') &&
|
get(errorsArray, [0], '').includes('min') && !collapses.some(obj => obj.isOpen === true);
|
||||||
!collapses.some(obj => obj.isOpen === true);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -84,9 +81,7 @@ const RepeatableComponent = ({
|
|||||||
<DraggedItem
|
<DraggedItem
|
||||||
fields={fields}
|
fields={fields}
|
||||||
componentFieldName={componentFieldName}
|
componentFieldName={componentFieldName}
|
||||||
doesPreviousFieldContainErrorsAndIsOpen={
|
doesPreviousFieldContainErrorsAndIsOpen={doesPreviousFieldContainErrorsAndIsOpen}
|
||||||
doesPreviousFieldContainErrorsAndIsOpen
|
|
||||||
}
|
|
||||||
hasErrors={hasErrors}
|
hasErrors={hasErrors}
|
||||||
hasMinError={hasMinError}
|
hasMinError={hasMinError}
|
||||||
isFirst={index === 0}
|
isFirst={index === 0}
|
||||||
@ -129,11 +124,7 @@ const RepeatableComponent = ({
|
|||||||
if (componentValueLength < max) {
|
if (componentValueLength < max) {
|
||||||
const shouldCheckErrors = hasMinError;
|
const shouldCheckErrors = hasMinError;
|
||||||
|
|
||||||
addRepeatableComponentToField(
|
addRepeatableComponentToField(name, componentUid, shouldCheckErrors);
|
||||||
name,
|
|
||||||
componentUid,
|
|
||||||
shouldCheckErrors
|
|
||||||
);
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'ADD_NEW_FIELD',
|
type: 'ADD_NEW_FIELD',
|
||||||
});
|
});
|
||||||
|
@ -21,7 +21,7 @@ import reducer, { initialState } from './reducer';
|
|||||||
|
|
||||||
/* eslint-disable react/no-array-index-key */
|
/* 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();
|
const formatLayoutRef = useRef();
|
||||||
formatLayoutRef.current = createAttributesLayout;
|
formatLayoutRef.current = createAttributesLayout;
|
||||||
// Retrieve push to programmatically navigate between views
|
// Retrieve push to programmatically navigate between views
|
||||||
@ -95,6 +95,9 @@ const EditView = ({ components, currentEnvironment, layouts, plugins, slug }) =>
|
|||||||
currentContentTypeSchema.attributes
|
currentContentTypeSchema.attributes
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return () => deleteLayout(slug);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [currentContentTypeLayout, currentContentTypeSchema.attributes]);
|
}, [currentContentTypeLayout, currentContentTypeSchema.attributes]);
|
||||||
|
|
||||||
const { formattedContentTypeLayout, isDraggingComponent } = reducerState.toJS();
|
const { formattedContentTypeLayout, isDraggingComponent } = reducerState.toJS();
|
||||||
@ -265,12 +268,13 @@ EditView.defaultProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
EditView.propTypes = {
|
EditView.propTypes = {
|
||||||
currentEnvironment: PropTypes.string,
|
|
||||||
components: PropTypes.array.isRequired,
|
components: PropTypes.array.isRequired,
|
||||||
|
currentEnvironment: PropTypes.string,
|
||||||
|
deleteLayout: PropTypes.func.isRequired,
|
||||||
emitEvent: PropTypes.func,
|
emitEvent: PropTypes.func,
|
||||||
layouts: PropTypes.object.isRequired,
|
layouts: PropTypes.object.isRequired,
|
||||||
slug: PropTypes.string.isRequired,
|
|
||||||
plugins: PropTypes.object,
|
plugins: PropTypes.object,
|
||||||
|
slug: PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export { EditView };
|
export { EditView };
|
||||||
|
@ -77,6 +77,7 @@ const EditViewDataManagerProvider = ({ allLayoutData, children, redirectToPrevio
|
|||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
const contentTypeDataStructure = createDefaultForm(
|
const contentTypeDataStructure = createDefaultForm(
|
||||||
currentContentTypeLayout.schema.attributes,
|
currentContentTypeLayout.schema.attributes,
|
||||||
allLayoutData.components
|
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;
|
let inputValue = value;
|
||||||
|
|
||||||
// Empty string is not a valid date,
|
// Empty string is not a valid date,
|
||||||
@ -213,6 +214,7 @@ const EditViewDataManagerProvider = ({ allLayoutData, children, redirectToPrevio
|
|||||||
type: 'ON_CHANGE',
|
type: 'ON_CHANGE',
|
||||||
keys: name.split('.'),
|
keys: name.split('.'),
|
||||||
value: inputValue,
|
value: inputValue,
|
||||||
|
shouldSetInitialValue,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -135,11 +135,21 @@ const reducer = (state, action) => {
|
|||||||
let newState = state;
|
let newState = state;
|
||||||
const [nonRepeatableComponentKey] = action.keys;
|
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 (
|
if (
|
||||||
action.keys.length === 2 &&
|
action.keys.length === 2 &&
|
||||||
state.getIn(['modifiedData', nonRepeatableComponentKey]) === null
|
state.getIn(['modifiedData', nonRepeatableComponentKey]) === null
|
||||||
) {
|
) {
|
||||||
newState = state.updateIn(['modifiedData', nonRepeatableComponentKey], () => fromJS({}));
|
newState = newState.updateIn(['modifiedData', nonRepeatableComponentKey], () => fromJS({}));
|
||||||
}
|
}
|
||||||
|
|
||||||
return newState.updateIn(['modifiedData', ...action.keys], () => {
|
return newState.updateIn(['modifiedData', ...action.keys], () => {
|
||||||
|
@ -3,14 +3,7 @@ import { get } from 'lodash';
|
|||||||
const createDefaultForm = (attributes, allComponentsSchema) => {
|
const createDefaultForm = (attributes, allComponentsSchema) => {
|
||||||
return Object.keys(attributes).reduce((acc, current) => {
|
return Object.keys(attributes).reduce((acc, current) => {
|
||||||
const attribute = get(attributes, [current], {});
|
const attribute = get(attributes, [current], {});
|
||||||
const {
|
const { default: defaultValue, component, type, required, min, repeatable } = attribute;
|
||||||
default: defaultValue,
|
|
||||||
component,
|
|
||||||
type,
|
|
||||||
required,
|
|
||||||
min,
|
|
||||||
repeatable,
|
|
||||||
} = attribute;
|
|
||||||
|
|
||||||
if (type === 'json') {
|
if (type === 'json') {
|
||||||
acc[current] = null;
|
acc[current] = null;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user