mirror of
				https://github.com/strapi/strapi.git
				synced 2025-10-25 23:23:54 +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": { | ||||
|       "type": "uid", | ||||
|       "targetField": "title" | ||||
|       "targetField": "title", | ||||
|       "required": true | ||||
|     }, | ||||
|     "single": { | ||||
|       "model": "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'], []); | ||||
| 
 | ||||
|  | ||||
| @ -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: '', | ||||
| }; | ||||
|  | ||||
| @ -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', | ||||
|             }); | ||||
|  | ||||
| @ -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 }; | ||||
|  | ||||
| @ -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, | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|  | ||||
| @ -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], () => { | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 cyril lopez
						cyril lopez