mirror of
https://github.com/strapi/strapi.git
synced 2025-11-11 15:49:50 +00:00
Merge pull request #5286 from strapi/single-types/uid
add Uid attributes in CTB
This commit is contained in:
commit
da7ebced8d
@ -7,12 +7,7 @@ import {
|
||||
useGlobalContext,
|
||||
PopUpWarning,
|
||||
} from 'strapi-helper-plugin';
|
||||
import {
|
||||
useHistory,
|
||||
useLocation,
|
||||
useRouteMatch,
|
||||
Redirect,
|
||||
} from 'react-router-dom';
|
||||
import { useHistory, useLocation, useRouteMatch, Redirect } from 'react-router-dom';
|
||||
import DataManagerContext from '../../contexts/DataManagerContext';
|
||||
import getTrad from '../../utils/getTrad';
|
||||
import makeUnique from '../../utils/makeUnique';
|
||||
@ -55,21 +50,17 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
||||
} = reducerState.toJS();
|
||||
const { pathname } = useLocation();
|
||||
const { push } = useHistory();
|
||||
const contentTypeMatch = useRouteMatch(
|
||||
`/plugins/${pluginId}/content-types/:uid`
|
||||
);
|
||||
const contentTypeMatch = useRouteMatch(`/plugins/${pluginId}/content-types/:uid`);
|
||||
const componentMatch = useRouteMatch(
|
||||
`/plugins/${pluginId}/component-categories/:categoryUid/:componentUid`
|
||||
);
|
||||
|
||||
const formatMessageRef = useRef();
|
||||
formatMessageRef.current = formatMessage;
|
||||
const isInDevelopmentMode =
|
||||
currentEnvironment === 'development' && autoReload;
|
||||
const isInDevelopmentMode = currentEnvironment === 'development' && autoReload;
|
||||
|
||||
const isInContentTypeView = contentTypeMatch !== null;
|
||||
const firstKeyToMainSchema = isInContentTypeView
|
||||
? 'contentType'
|
||||
: 'component';
|
||||
const firstKeyToMainSchema = isInContentTypeView ? 'contentType' : 'component';
|
||||
const currentUid = isInContentTypeView
|
||||
? get(contentTypeMatch, 'params.uid', null)
|
||||
: get(componentMatch, 'params.componentUid', null);
|
||||
@ -80,10 +71,7 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
||||
|
||||
getDataRef.current = async () => {
|
||||
try {
|
||||
const [
|
||||
{ data: componentsArray },
|
||||
{ data: contentTypesArray },
|
||||
] = await Promise.all(
|
||||
const [{ data: componentsArray }, { data: contentTypesArray }] = await Promise.all(
|
||||
['components', 'content-types'].map(endPoint => {
|
||||
return request(`/${pluginId}/${endPoint}`, {
|
||||
method: 'GET',
|
||||
@ -118,11 +106,11 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
||||
useEffect(() => {
|
||||
// We need to set the modifiedData after the data has been retrieved
|
||||
// and also on pathname change
|
||||
if (!isLoading) {
|
||||
if (!isLoading && currentUid) {
|
||||
setModifiedData();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isLoading, pathname]);
|
||||
}, [isLoading, pathname, currentUid]);
|
||||
|
||||
useEffect(() => {
|
||||
if (currentEnvironment === 'development' && !autoReload) {
|
||||
@ -135,8 +123,7 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
||||
}, [autoReload, currentEnvironment]);
|
||||
|
||||
const didModifiedComponents =
|
||||
getCreatedAndModifiedComponents(modifiedData.components || {}, components)
|
||||
.length > 0;
|
||||
getCreatedAndModifiedComponents(modifiedData.components || {}, components).length > 0;
|
||||
|
||||
const addAttribute = (
|
||||
attributeToSet,
|
||||
@ -158,10 +145,7 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
||||
});
|
||||
};
|
||||
|
||||
const addCreatedComponentToDynamicZone = (
|
||||
dynamicZoneTarget,
|
||||
componentsToAdd
|
||||
) => {
|
||||
const addCreatedComponentToDynamicZone = (dynamicZoneTarget, componentsToAdd) => {
|
||||
dispatch({
|
||||
type: 'ADD_CREATED_COMPONENT_TO_DYNAMIC_ZONE',
|
||||
dynamicZoneTarget,
|
||||
@ -181,10 +165,7 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
||||
componentCategory,
|
||||
shouldAddComponentToData = false
|
||||
) => {
|
||||
const type =
|
||||
schemaType === 'contentType'
|
||||
? 'CREATE_SCHEMA'
|
||||
: 'CREATE_COMPONENT_SCHEMA';
|
||||
const type = schemaType === 'contentType' ? 'CREATE_SCHEMA' : 'CREATE_COMPONENT_SCHEMA';
|
||||
|
||||
dispatch({
|
||||
type,
|
||||
@ -204,15 +185,9 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
||||
});
|
||||
};
|
||||
|
||||
const removeAttribute = (
|
||||
mainDataKey,
|
||||
attributeToRemoveName,
|
||||
componentUid = ''
|
||||
) => {
|
||||
const removeAttribute = (mainDataKey, attributeToRemoveName, componentUid = '') => {
|
||||
const type =
|
||||
mainDataKey === 'components'
|
||||
? 'REMOVE_FIELD_FROM_DISPLAYED_COMPONENT'
|
||||
: 'REMOVE_FIELD';
|
||||
mainDataKey === 'components' ? 'REMOVE_FIELD_FROM_DISPLAYED_COMPONENT' : 'REMOVE_FIELD';
|
||||
|
||||
if (mainDataKey === 'contentType') {
|
||||
emitEvent('willDeleteFieldOfContentType');
|
||||
@ -253,17 +228,11 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
||||
const deleteData = async () => {
|
||||
try {
|
||||
const requestURL = `/${pluginId}/${endPoint}/${currentUid}`;
|
||||
const isTemporary = get(
|
||||
modifiedData,
|
||||
[firstKeyToMainSchema, 'isTemporary'],
|
||||
false
|
||||
);
|
||||
const isTemporary = get(modifiedData, [firstKeyToMainSchema, 'isTemporary'], false);
|
||||
const userConfirm = window.confirm(
|
||||
formatMessage({
|
||||
id: getTrad(
|
||||
`popUpWarning.bodyMessage.${
|
||||
isInContentTypeView ? 'contentType' : 'component'
|
||||
}.delete`
|
||||
`popUpWarning.bodyMessage.${isInContentTypeView ? 'contentType' : 'component'}.delete`
|
||||
),
|
||||
})
|
||||
);
|
||||
@ -338,9 +307,7 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
||||
|
||||
const getAllNestedComponents = () => {
|
||||
const appNestedCompo = retrieveNestedComponents(components);
|
||||
const editingDataNestedCompos = retrieveNestedComponents(
|
||||
modifiedData.components || {}
|
||||
);
|
||||
const editingDataNestedCompos = retrieveNestedComponents(modifiedData.components || {});
|
||||
|
||||
return makeUnique([...editingDataNestedCompos, ...appNestedCompo]);
|
||||
};
|
||||
@ -370,10 +337,7 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
||||
isInContentTypeView
|
||||
);
|
||||
|
||||
const dataShape = orderAllDataAttributesWithImmutable(
|
||||
newSchemaToSet,
|
||||
isInContentTypeView
|
||||
);
|
||||
const dataShape = orderAllDataAttributesWithImmutable(newSchemaToSet, isInContentTypeView);
|
||||
|
||||
// This prevents from losing the created content type or component when clicking on the link from the left menu
|
||||
const hasJustCreatedSchema =
|
||||
@ -401,11 +365,7 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
||||
|
||||
const submitData = async additionalContentTypeData => {
|
||||
try {
|
||||
const isCreating = get(
|
||||
modifiedData,
|
||||
[firstKeyToMainSchema, 'isTemporary'],
|
||||
false
|
||||
);
|
||||
const isCreating = get(modifiedData, [firstKeyToMainSchema, 'isTemporary'], false);
|
||||
const body = {
|
||||
components: getComponentsToPost(
|
||||
modifiedData.components,
|
||||
@ -505,14 +465,11 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
||||
value={{
|
||||
addAttribute,
|
||||
addCreatedComponentToDynamicZone,
|
||||
allComponentsCategories: retrieveSpecificInfoFromComponents(
|
||||
components,
|
||||
['category']
|
||||
),
|
||||
allComponentsIconAlreadyTaken: retrieveSpecificInfoFromComponents(
|
||||
components,
|
||||
['schema', 'icon']
|
||||
),
|
||||
allComponentsCategories: retrieveSpecificInfoFromComponents(components, ['category']),
|
||||
allComponentsIconAlreadyTaken: retrieveSpecificInfoFromComponents(components, [
|
||||
'schema',
|
||||
'icon',
|
||||
]),
|
||||
allIcons,
|
||||
changeDynamicZoneComponents,
|
||||
components,
|
||||
|
||||
@ -34,8 +34,7 @@ const addComponentsToState = (state, componentToAddUid, objToUpdate) => {
|
||||
const isTemporaryComponent = componentToAdd.get('isTemporary');
|
||||
const componentToAddSchema = componentToAdd.getIn(['schema', 'attributes']);
|
||||
const hasComponentAlreadyBeenAdded =
|
||||
state.getIn(['modifiedData', 'components', componentToAddUid]) !==
|
||||
undefined;
|
||||
state.getIn(['modifiedData', 'components', componentToAddUid]) !== undefined;
|
||||
|
||||
// created components are already in the modifiedData.components
|
||||
// We don't add them because all modifications will be lost
|
||||
@ -52,17 +51,13 @@ const addComponentsToState = (state, componentToAddUid, objToUpdate) => {
|
||||
|
||||
// We need to add the nested components to the modifiedData.components as well
|
||||
nestedComponents.forEach(componentUid => {
|
||||
const isTemporary =
|
||||
state.getIn(['components', componentUid, 'isTemporary']) || false;
|
||||
const isTemporary = state.getIn(['components', componentUid, 'isTemporary']) || false;
|
||||
const hasNestedComponentAlreadyBeenAdded =
|
||||
state.getIn(['modifiedData', 'components', componentUid]) !== undefined;
|
||||
|
||||
// Same logic here otherwise we will lose the modifications added to the components
|
||||
if (!isTemporary && !hasNestedComponentAlreadyBeenAdded) {
|
||||
newObj = newObj.set(
|
||||
componentUid,
|
||||
state.getIn(['components', componentUid])
|
||||
);
|
||||
newObj = newObj.set(componentUid, state.getIn(['components', componentUid]));
|
||||
}
|
||||
});
|
||||
|
||||
@ -84,23 +79,14 @@ const reducer = (state, action) => {
|
||||
: [forTarget, targetUid];
|
||||
|
||||
return state
|
||||
.updateIn(
|
||||
['modifiedData', ...pathToDataToEdit, 'schema', 'attributes', name],
|
||||
() => {
|
||||
.updateIn(['modifiedData', ...pathToDataToEdit, 'schema', 'attributes', name], () => {
|
||||
return fromJS(rest);
|
||||
}
|
||||
)
|
||||
.updateIn(
|
||||
['modifiedData', ...pathToDataToEdit, 'schema', 'attributes'],
|
||||
obj => {
|
||||
})
|
||||
.updateIn(['modifiedData', ...pathToDataToEdit, 'schema', 'attributes'], obj => {
|
||||
const type = get(rest, 'type', 'relation');
|
||||
const target = get(rest, 'target', null);
|
||||
const nature = get(rest, 'nature', null);
|
||||
const currentUid = state.getIn([
|
||||
'modifiedData',
|
||||
...pathToDataToEdit,
|
||||
'uid',
|
||||
]);
|
||||
const currentUid = state.getIn(['modifiedData', ...pathToDataToEdit, 'uid']);
|
||||
|
||||
// When the user in creating a relation with the same content type we need to create another attribute
|
||||
// that is the opposite of the created one
|
||||
@ -128,8 +114,7 @@ const reducer = (state, action) => {
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
)
|
||||
})
|
||||
.updateIn(['modifiedData', 'components'], existingCompos => {
|
||||
if (action.shouldAddComponentToData) {
|
||||
return addComponentsToState(state, rest.component, existingCompos);
|
||||
@ -142,14 +127,7 @@ const reducer = (state, action) => {
|
||||
const { dynamicZoneTarget, componentsToAdd } = action;
|
||||
|
||||
return state.updateIn(
|
||||
[
|
||||
'modifiedData',
|
||||
'contentType',
|
||||
'schema',
|
||||
'attributes',
|
||||
dynamicZoneTarget,
|
||||
'components',
|
||||
],
|
||||
['modifiedData', 'contentType', 'schema', 'attributes', dynamicZoneTarget, 'components'],
|
||||
list => {
|
||||
return list.concat(componentsToAdd);
|
||||
}
|
||||
@ -165,14 +143,7 @@ const reducer = (state, action) => {
|
||||
|
||||
return state
|
||||
.updateIn(
|
||||
[
|
||||
'modifiedData',
|
||||
'contentType',
|
||||
'schema',
|
||||
'attributes',
|
||||
dynamicZoneTarget,
|
||||
'components',
|
||||
],
|
||||
['modifiedData', 'contentType', 'schema', 'attributes', dynamicZoneTarget, 'components'],
|
||||
list => {
|
||||
return fromJS(makeUnique([...list.toJS(), ...newComponents]));
|
||||
}
|
||||
@ -196,9 +167,7 @@ const reducer = (state, action) => {
|
||||
},
|
||||
};
|
||||
|
||||
return state.updateIn(['contentTypes', action.uid], () =>
|
||||
fromJS(newSchema)
|
||||
);
|
||||
return state.updateIn(['contentTypes', action.uid], () => fromJS(newSchema));
|
||||
}
|
||||
case 'CREATE_COMPONENT_SCHEMA': {
|
||||
const newSchema = {
|
||||
@ -214,14 +183,10 @@ const reducer = (state, action) => {
|
||||
if (action.shouldAddComponentToData) {
|
||||
return state
|
||||
.updateIn(['components', action.uid], () => fromJS(newSchema))
|
||||
.updateIn(['modifiedData', 'components', action.uid], () =>
|
||||
fromJS(newSchema)
|
||||
);
|
||||
.updateIn(['modifiedData', 'components', action.uid], () => fromJS(newSchema));
|
||||
}
|
||||
|
||||
return state.updateIn(['components', action.uid], () =>
|
||||
fromJS(newSchema)
|
||||
);
|
||||
return state.updateIn(['components', action.uid], () => fromJS(newSchema));
|
||||
}
|
||||
case 'DELETE_NOT_SAVED_TYPE': {
|
||||
// Doing so will also reset the modified and the initial data
|
||||
@ -243,9 +208,7 @@ const reducer = (state, action) => {
|
||||
? [forTarget]
|
||||
: [forTarget, targetUid];
|
||||
|
||||
return newState.updateIn(
|
||||
['modifiedData', ...pathToDataToEdit, 'schema'],
|
||||
obj => {
|
||||
return newState.updateIn(['modifiedData', ...pathToDataToEdit, 'schema'], obj => {
|
||||
let oppositeAttributeNameToRemove = null;
|
||||
let oppositeAttributeNameToUpdate = null;
|
||||
let oppositeAttributeNameToCreateBecauseOfNatureChange = null;
|
||||
@ -256,25 +219,17 @@ const reducer = (state, action) => {
|
||||
.get('attributes')
|
||||
.keySeq()
|
||||
.reduce((acc, current) => {
|
||||
const isEditingCurrentAttribute =
|
||||
current === initialAttributeName;
|
||||
const isEditingCurrentAttribute = current === initialAttributeName;
|
||||
|
||||
if (isEditingCurrentAttribute) {
|
||||
const currentUid = state.getIn([
|
||||
'modifiedData',
|
||||
...pathToDataToEdit,
|
||||
'uid',
|
||||
]);
|
||||
const currentUid = state.getIn(['modifiedData', ...pathToDataToEdit, 'uid']);
|
||||
const isEditingRelation = has(initialAttribute, 'nature');
|
||||
const didChangeTargetRelation =
|
||||
initialAttribute.target !== rest.target;
|
||||
const didChangeTargetRelation = initialAttribute.target !== rest.target;
|
||||
const didCreateInternalRelation = rest.target === currentUid;
|
||||
const nature = rest.nature;
|
||||
const initialNature = initialAttribute.nature;
|
||||
const hadInternalRelation =
|
||||
initialAttribute.target === currentUid;
|
||||
const didChangeRelationNature =
|
||||
initialAttribute.nature !== nature;
|
||||
const hadInternalRelation = initialAttribute.target === currentUid;
|
||||
const didChangeRelationNature = initialAttribute.nature !== nature;
|
||||
const shouldRemoveOppositeAttributeBecauseOfTargetChange =
|
||||
didChangeTargetRelation &&
|
||||
!didCreateInternalRelation &&
|
||||
@ -307,8 +262,7 @@ const reducer = (state, action) => {
|
||||
shouldRemoveOppositeAttributeBecauseOfTargetChange ||
|
||||
shouldRemoveOppositeAttributeBecauseOfNatureChange
|
||||
) {
|
||||
oppositeAttributeNameToRemove =
|
||||
initialAttribute.targetAttribute;
|
||||
oppositeAttributeNameToRemove = initialAttribute.targetAttribute;
|
||||
}
|
||||
|
||||
// Set the opposite attribute that will be updated when the loop attribute matches the name
|
||||
@ -317,10 +271,8 @@ const reducer = (state, action) => {
|
||||
shouldCreateOppositeAttributeBecauseOfNatureChange ||
|
||||
shouldCreateOppositeAttributeBecauseOfTargetChange
|
||||
) {
|
||||
oppositeAttributeNameToUpdate =
|
||||
initialAttribute.targetAttribute;
|
||||
oppositeAttributeNameToCreateBecauseOfNatureChange =
|
||||
rest.targetAttribute;
|
||||
oppositeAttributeNameToUpdate = initialAttribute.targetAttribute;
|
||||
oppositeAttributeNameToCreateBecauseOfNatureChange = rest.targetAttribute;
|
||||
|
||||
oppositeAttributeToCreate = {
|
||||
nature: getOppositeNature(rest.nature),
|
||||
@ -328,8 +280,7 @@ const reducer = (state, action) => {
|
||||
unique: rest.unique,
|
||||
// Leave this if we allow the required on the relation
|
||||
// required: rest.required,
|
||||
dominant:
|
||||
rest.nature === 'manyToMany' ? !rest.dominant : null,
|
||||
dominant: rest.nature === 'manyToMany' ? !rest.dominant : null,
|
||||
targetAttribute: name,
|
||||
columnName: rest.targetColumnName,
|
||||
targetColumnName: rest.columnName,
|
||||
@ -345,9 +296,9 @@ const reducer = (state, action) => {
|
||||
shouldCreateOppositeAttributeBecauseOfNatureChange ||
|
||||
shouldCreateOppositeAttributeBecauseOfTargetChange
|
||||
) {
|
||||
acc[
|
||||
oppositeAttributeNameToCreateBecauseOfNatureChange
|
||||
] = fromJS(oppositeAttributeToCreate);
|
||||
acc[oppositeAttributeNameToCreateBecauseOfNatureChange] = fromJS(
|
||||
oppositeAttributeToCreate
|
||||
);
|
||||
|
||||
oppositeAttributeToCreate = null;
|
||||
oppositeAttributeNameToCreateBecauseOfNatureChange = null;
|
||||
@ -358,9 +309,9 @@ const reducer = (state, action) => {
|
||||
|
||||
acc[name] = fromJS(rest);
|
||||
} else if (current === oppositeAttributeNameToUpdate) {
|
||||
acc[
|
||||
oppositeAttributeNameToCreateBecauseOfNatureChange
|
||||
] = fromJS(oppositeAttributeToCreate);
|
||||
acc[oppositeAttributeNameToCreateBecauseOfNatureChange] = fromJS(
|
||||
oppositeAttributeToCreate
|
||||
);
|
||||
} else {
|
||||
acc[current] = obj.getIn(['attributes', current]);
|
||||
}
|
||||
@ -379,8 +330,7 @@ const reducer = (state, action) => {
|
||||
}
|
||||
|
||||
return obj.set('attributes', updatedObj);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
case 'GET_DATA_SUCCEEDED': {
|
||||
@ -418,35 +368,18 @@ const reducer = (state, action) => {
|
||||
]);
|
||||
case 'REMOVE_FIELD': {
|
||||
const { mainDataKey, attributeToRemoveName } = action;
|
||||
const pathToAttributes = [
|
||||
'modifiedData',
|
||||
mainDataKey,
|
||||
'schema',
|
||||
'attributes',
|
||||
];
|
||||
const pathToAttributeToRemove = [
|
||||
...pathToAttributes,
|
||||
attributeToRemoveName,
|
||||
];
|
||||
const pathToAttributes = ['modifiedData', mainDataKey, 'schema', 'attributes'];
|
||||
const pathToAttributeToRemove = [...pathToAttributes, attributeToRemoveName];
|
||||
|
||||
const attributeToRemoveData = state.getIn(pathToAttributeToRemove);
|
||||
|
||||
const isRemovingRelationAttribute =
|
||||
attributeToRemoveData.get('nature') !== undefined;
|
||||
const isRemovingRelationAttribute = attributeToRemoveData.get('nature') !== undefined;
|
||||
// Only content types can have relations with themselves since
|
||||
// components can only have oneWay or manyWay relations
|
||||
const canTheAttributeToRemoveHaveARelationWithItself =
|
||||
mainDataKey === 'contentType';
|
||||
const canTheAttributeToRemoveHaveARelationWithItself = mainDataKey === 'contentType';
|
||||
|
||||
if (
|
||||
isRemovingRelationAttribute &&
|
||||
canTheAttributeToRemoveHaveARelationWithItself
|
||||
) {
|
||||
const {
|
||||
target,
|
||||
nature,
|
||||
targetAttribute,
|
||||
} = attributeToRemoveData.toJS();
|
||||
if (isRemovingRelationAttribute && canTheAttributeToRemoveHaveARelationWithItself) {
|
||||
const { target, nature, targetAttribute } = attributeToRemoveData.toJS();
|
||||
const uid = state.getIn(['modifiedData', 'contentType', 'uid']);
|
||||
const shouldRemoveOppositeAttribute =
|
||||
target === uid && !ONE_SIDE_RELATIONS.includes(nature);
|
||||
@ -458,7 +391,15 @@ const reducer = (state, action) => {
|
||||
}
|
||||
}
|
||||
|
||||
return state.removeIn(pathToAttributeToRemove);
|
||||
return state.removeIn(pathToAttributeToRemove).updateIn([...pathToAttributes], attributes => {
|
||||
return attributes.keySeq().reduce((acc, current) => {
|
||||
if (acc.getIn([current, 'targetField']) === attributeToRemoveName) {
|
||||
return acc.removeIn([current, 'targetField']);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, attributes);
|
||||
});
|
||||
}
|
||||
case 'SET_MODIFIED_DATA': {
|
||||
let newState = state
|
||||
@ -502,9 +443,7 @@ const reducer = (state, action) => {
|
||||
|
||||
if (schemaType === 'component') {
|
||||
newState = newState.updateIn(['components'], obj => {
|
||||
return obj.update(uid, () =>
|
||||
newState.getIn(['modifiedData', 'component'])
|
||||
);
|
||||
return obj.update(uid, () => newState.getIn(['modifiedData', 'component']));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -417,13 +417,7 @@ const data = {
|
||||
collectionName: '',
|
||||
attributes: {
|
||||
price_range: {
|
||||
enum: [
|
||||
'very_cheap',
|
||||
'cheap',
|
||||
'average',
|
||||
'expensive',
|
||||
'very_expensive',
|
||||
],
|
||||
enum: ['very_cheap', 'cheap', 'average', 'expensive', 'very_expensive'],
|
||||
type: 'enumeration',
|
||||
},
|
||||
closing_period: {
|
||||
@ -479,6 +473,17 @@ const data = {
|
||||
},
|
||||
},
|
||||
},
|
||||
'application::homepage.homepage': {
|
||||
uid: 'application::homepage.homepage',
|
||||
schema: {
|
||||
name: 'homepage',
|
||||
attributes: {
|
||||
title: { type: 'string' },
|
||||
description: { type: 'string' },
|
||||
homepageuidfield: { type: 'uid', targetField: 'description' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -17,10 +17,7 @@ describe('CTB | containers | DataManagerProvider | reducer | REMOVE_FIELD', () =
|
||||
const state = initialState
|
||||
.set('contentTypes', fromJS(testData.contentTypes))
|
||||
.set('initialContentTypes', fromJS(testData.contentTypes))
|
||||
.setIn(
|
||||
['modifiedData', 'contentType'],
|
||||
fromJS(testData.contentTypes[contentTypeUID])
|
||||
)
|
||||
.setIn(['modifiedData', 'contentType'], fromJS(testData.contentTypes[contentTypeUID]))
|
||||
.setIn(['modifiedData', 'components'], fromJS({}));
|
||||
|
||||
const expected = state.removeIn([
|
||||
@ -49,10 +46,7 @@ describe('CTB | containers | DataManagerProvider | reducer | REMOVE_FIELD', () =
|
||||
const state = initialState
|
||||
.set('contentTypes', fromJS(testData.contentTypes))
|
||||
.set('initialContentTypes', fromJS(testData.contentTypes))
|
||||
.setIn(
|
||||
['modifiedData', 'contentType'],
|
||||
fromJS(testData.contentTypes[contentTypeUID])
|
||||
)
|
||||
.setIn(['modifiedData', 'contentType'], fromJS(testData.contentTypes[contentTypeUID]))
|
||||
.setIn(['modifiedData', 'components'], fromJS({}));
|
||||
|
||||
const expected = state.removeIn([
|
||||
@ -163,10 +157,7 @@ describe('CTB | containers | DataManagerProvider | reducer | REMOVE_FIELD', () =
|
||||
.setIn(['contentTypes', contentTypeUID], fromJS(contentType))
|
||||
.setIn(['modifiedData', 'contentType'], fromJS(contentType));
|
||||
|
||||
const expected = state.setIn(
|
||||
['modifiedData', 'contentType'],
|
||||
fromJS(expectedContentType)
|
||||
);
|
||||
const expected = state.setIn(['modifiedData', 'contentType'], fromJS(expectedContentType));
|
||||
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
});
|
||||
@ -257,10 +248,7 @@ describe('CTB | containers | DataManagerProvider | reducer | REMOVE_FIELD', () =
|
||||
.setIn(['contentTypes', contentTypeUID], fromJS(contentType))
|
||||
.setIn(['modifiedData', 'contentType'], fromJS(contentType));
|
||||
|
||||
const expected = state.setIn(
|
||||
['modifiedData', 'contentType'],
|
||||
fromJS(expectedContentType)
|
||||
);
|
||||
const expected = state.setIn(['modifiedData', 'contentType'], fromJS(expectedContentType));
|
||||
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
expect(
|
||||
@ -271,4 +259,35 @@ describe('CTB | containers | DataManagerProvider | reducer | REMOVE_FIELD', () =
|
||||
).toEqual(expected);
|
||||
});
|
||||
});
|
||||
describe('Removing a field that is targeted by a UID field', () => {
|
||||
it('Should remove the attribute correctly and remove the targetField from the UID field', () => {
|
||||
const contentTypeUID = 'application::homepage.homepage';
|
||||
const attributeToRemoveName = 'description';
|
||||
const action = {
|
||||
type: 'REMOVE_FIELD',
|
||||
mainDataKey: 'contentType',
|
||||
attributeToRemoveName,
|
||||
componentUid: '',
|
||||
};
|
||||
|
||||
const state = initialState
|
||||
.set('contentTypes', fromJS(testData.contentTypes))
|
||||
.set('initialContentTypes', fromJS(testData.contentTypes))
|
||||
.setIn(['modifiedData', 'contentType'], fromJS(testData.contentTypes[contentTypeUID]))
|
||||
.setIn(['modifiedData', 'components'], fromJS({}));
|
||||
|
||||
const expected = state
|
||||
.removeIn(['modifiedData', 'contentType', 'schema', 'attributes', attributeToRemoveName])
|
||||
.removeIn([
|
||||
'modifiedData',
|
||||
'contentType',
|
||||
'schema',
|
||||
'attributes',
|
||||
'homepageuidfield',
|
||||
'targetField',
|
||||
]);
|
||||
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -327,6 +327,7 @@ const FormModal = () => {
|
||||
const isOpen = !isEmpty(search);
|
||||
const isPickingAttribute = state.modalType === 'chooseAttribute';
|
||||
const uid = createUid(modifiedData.name || '');
|
||||
const attributes = get(allDataSchema, [...state.pathToSchema, 'schema', 'attributes'], null);
|
||||
|
||||
const checkFormValidity = async () => {
|
||||
let schema;
|
||||
@ -394,7 +395,6 @@ const FormModal = () => {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
schema = forms[state.modalType].schema(
|
||||
get(allDataSchema, state.pathToSchema, {}),
|
||||
type,
|
||||
@ -1090,8 +1090,13 @@ const FormModal = () => {
|
||||
</div>
|
||||
);
|
||||
})
|
||||
: form(modifiedData, state.attributeType, state.step, state.actionType).items.map(
|
||||
(row, index) => {
|
||||
: form(
|
||||
modifiedData,
|
||||
state.attributeType,
|
||||
state.step,
|
||||
state.actionType,
|
||||
attributes
|
||||
).items.map((row, index) => {
|
||||
return (
|
||||
<div className="row" key={index} style={{ marginBottom: 4 }}>
|
||||
{row.map((input, i) => {
|
||||
@ -1262,8 +1267,7 @@ const FormModal = () => {
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
)}
|
||||
})}
|
||||
</div>
|
||||
</ModalBody>
|
||||
</ModalForm>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
import * as yup from 'yup';
|
||||
import { get, isEmpty, toLower, trim, toNumber } from 'lodash';
|
||||
import { translatedErrors as errorsTrads } from 'strapi-helper-plugin';
|
||||
@ -8,22 +8,14 @@ import getTrad from '../../../utils/getTrad';
|
||||
import { createComponentUid, createUid, nameToSlug } from './createUid';
|
||||
import componentForm from './componentForm';
|
||||
import fields from './staticFields';
|
||||
import {
|
||||
NAME_REGEX,
|
||||
ENUM_REGEX,
|
||||
CATEGORY_NAME_REGEX,
|
||||
} from './attributesRegexes';
|
||||
import { NAME_REGEX, ENUM_REGEX, CATEGORY_NAME_REGEX } from './attributesRegexes';
|
||||
import RESERVED_NAMES from './reservedNames';
|
||||
|
||||
/* eslint-disable indent */
|
||||
/* eslint-disable prefer-arrow-callback */
|
||||
|
||||
yup.addMethod(yup.mixed, 'defined', function() {
|
||||
return this.test(
|
||||
'defined',
|
||||
errorsTrads.required,
|
||||
value => value !== undefined
|
||||
);
|
||||
return this.test('defined', errorsTrads.required, value => value !== undefined);
|
||||
});
|
||||
|
||||
yup.addMethod(yup.string, 'unique', function(
|
||||
@ -83,12 +75,7 @@ yup.addMethod(yup.array, 'matchesEnumRegex', function(message) {
|
||||
});
|
||||
});
|
||||
|
||||
const ATTRIBUTES_THAT_DONT_HAVE_MIN_MAX_SETTINGS = [
|
||||
'boolean',
|
||||
'date',
|
||||
'enumeration',
|
||||
'media',
|
||||
];
|
||||
const ATTRIBUTES_THAT_DONT_HAVE_MIN_MAX_SETTINGS = ['boolean', 'date', 'enumeration', 'media'];
|
||||
|
||||
const forms = {
|
||||
attribute: {
|
||||
@ -193,10 +180,7 @@ const forms = {
|
||||
.integer()
|
||||
.when('maxLength', (maxLength, schema) => {
|
||||
if (maxLength) {
|
||||
return schema.max(
|
||||
maxLength,
|
||||
getTrad('error.validation.minSupMax')
|
||||
);
|
||||
return schema.max(maxLength, getTrad('error.validation.minSupMax'));
|
||||
}
|
||||
|
||||
return schema;
|
||||
@ -232,10 +216,7 @@ const forms = {
|
||||
.of(yup.string())
|
||||
.min(1, errorsTrads.min)
|
||||
.matchesEnumRegex(errorsTrads.regex)
|
||||
.hasNotEmptyValues(
|
||||
'Empty strings are not allowed',
|
||||
dataToValidate.enum
|
||||
),
|
||||
.hasNotEmptyValues('Empty strings are not allowed', dataToValidate.enum),
|
||||
enumName: yup.string().nullable(),
|
||||
});
|
||||
case 'number':
|
||||
@ -256,10 +237,7 @@ const forms = {
|
||||
.matches(/^\d*$/)
|
||||
.when('max', (max, schema) => {
|
||||
if (max) {
|
||||
return schema.isInferior(
|
||||
getTrad('error.validation.minSupMax'),
|
||||
max
|
||||
);
|
||||
return schema.isInferior(getTrad('error.validation.minSupMax'), max);
|
||||
}
|
||||
|
||||
return schema;
|
||||
@ -275,9 +253,7 @@ const forms = {
|
||||
let defaultType = yup.number();
|
||||
|
||||
if (dataToValidate.type === 'integer') {
|
||||
defaultType = yup
|
||||
.number()
|
||||
.integer('component.Input.error.validation.integer');
|
||||
defaultType = yup.number().integer('component.Input.error.validation.integer');
|
||||
}
|
||||
|
||||
return yup.object().shape({
|
||||
@ -344,8 +320,7 @@ const forms = {
|
||||
},
|
||||
{
|
||||
autoFocus: false,
|
||||
disabled:
|
||||
targetAttributeValue === null || targetAttributeValue === '-',
|
||||
disabled: targetAttributeValue === null || targetAttributeValue === '-',
|
||||
name: 'targetColumnName',
|
||||
label: '',
|
||||
type: 'addon',
|
||||
@ -366,12 +341,7 @@ const forms = {
|
||||
[fields.required],
|
||||
[fields.unique],
|
||||
];
|
||||
const dynamiczoneItems = [
|
||||
[fields.required],
|
||||
[fields.divider],
|
||||
[fields.max],
|
||||
[fields.min],
|
||||
];
|
||||
const dynamiczoneItems = [[fields.required], [fields.divider], [fields.max], [fields.min]];
|
||||
|
||||
if (type === 'component') {
|
||||
if (step === '1') {
|
||||
@ -386,11 +356,10 @@ const forms = {
|
||||
};
|
||||
}
|
||||
|
||||
const items = defaultItems.slice();
|
||||
let items = defaultItems.slice();
|
||||
|
||||
if (type === 'number' && data.type !== 'biginteger') {
|
||||
const step =
|
||||
data.type === 'decimal' || data.type === 'float' ? 'any' : '1';
|
||||
const step = data.type === 'decimal' || data.type === 'float' ? 'any' : '1';
|
||||
|
||||
items.splice(0, 1, [
|
||||
{
|
||||
@ -441,10 +410,7 @@ const forms = {
|
||||
].concat(
|
||||
data.enum
|
||||
? data.enum
|
||||
.filter(
|
||||
(val, index) =>
|
||||
data.enum.indexOf(val) === index && !isEmpty(val)
|
||||
)
|
||||
.filter((val, index) => data.enum.indexOf(val) === index && !isEmpty(val))
|
||||
.map(val => (
|
||||
<option key={val} value={val}>
|
||||
{val}
|
||||
@ -463,9 +429,7 @@ const forms = {
|
||||
type: 'text',
|
||||
validations: {},
|
||||
description: {
|
||||
id: getTrad(
|
||||
'form.attribute.item.enumeration.graphql.description'
|
||||
),
|
||||
id: getTrad('form.attribute.item.enumeration.graphql.description'),
|
||||
},
|
||||
},
|
||||
]);
|
||||
@ -473,13 +437,20 @@ const forms = {
|
||||
items.splice(0, 1, [
|
||||
{
|
||||
...fields.default,
|
||||
// type: data.type || 'date',
|
||||
type: 'date',
|
||||
value: null,
|
||||
withDefaultValue: false,
|
||||
disabled: data.type !== 'date',
|
||||
},
|
||||
]);
|
||||
} else if (type === 'uid') {
|
||||
const uidItems = [
|
||||
[{ ...fields.default, disabled: Boolean(data.targetField), type: 'text' }],
|
||||
[fields.divider],
|
||||
[fields.required],
|
||||
];
|
||||
|
||||
items = uidItems;
|
||||
}
|
||||
|
||||
if (!ATTRIBUTES_THAT_DONT_HAVE_MIN_MAX_SETTINGS.includes(type)) {
|
||||
@ -490,11 +461,7 @@ const forms = {
|
||||
name: type === 'number' ? 'max' : 'maxLength',
|
||||
type: 'customCheckboxWithChildren',
|
||||
label: {
|
||||
id: getTrad(
|
||||
`form.attribute.item.maximum${
|
||||
type === 'number' ? '' : 'Length'
|
||||
}`
|
||||
),
|
||||
id: getTrad(`form.attribute.item.maximum${type === 'number' ? '' : 'Length'}`),
|
||||
},
|
||||
|
||||
validations: {},
|
||||
@ -506,11 +473,7 @@ const forms = {
|
||||
name: type === 'number' ? 'min' : 'minLength',
|
||||
type: 'customCheckboxWithChildren',
|
||||
label: {
|
||||
id: getTrad(
|
||||
`form.attribute.item.minimum${
|
||||
type === 'number' ? '' : 'Length'
|
||||
}`
|
||||
),
|
||||
id: getTrad(`form.attribute.item.minimum${type === 'number' ? '' : 'Length'}`),
|
||||
},
|
||||
validations: {},
|
||||
},
|
||||
@ -534,7 +497,7 @@ const forms = {
|
||||
items,
|
||||
};
|
||||
},
|
||||
base(data, type, step) {
|
||||
base(data, type, step, actionType, attributes) {
|
||||
if (type === 'relation') {
|
||||
return {
|
||||
items: [
|
||||
@ -552,9 +515,7 @@ const forms = {
|
||||
if (type === 'component' && step === '1') {
|
||||
const itemsToConcat =
|
||||
data.createComponent === true
|
||||
? [[{ type: 'spacer' }]].concat(
|
||||
componentForm.base('componentToCreate.')
|
||||
)
|
||||
? [[{ type: 'spacer' }]].concat(componentForm.base('componentToCreate.'))
|
||||
: [[{ type: 'spacer' }]];
|
||||
|
||||
return {
|
||||
@ -581,19 +542,13 @@ const forms = {
|
||||
size: 12,
|
||||
options: [
|
||||
{
|
||||
headerId: getTrad(
|
||||
'form.attribute.component.option.repeatable'
|
||||
),
|
||||
descriptionId: getTrad(
|
||||
'form.attribute.component.option.repeatable.description'
|
||||
),
|
||||
headerId: getTrad('form.attribute.component.option.repeatable'),
|
||||
descriptionId: getTrad('form.attribute.component.option.repeatable.description'),
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
headerId: getTrad('form.attribute.component.option.single'),
|
||||
descriptionId: getTrad(
|
||||
'form.attribute.component.option.single.description'
|
||||
),
|
||||
descriptionId: getTrad('form.attribute.component.option.single.description'),
|
||||
value: false,
|
||||
},
|
||||
],
|
||||
@ -615,9 +570,7 @@ const forms = {
|
||||
options: [
|
||||
{
|
||||
headerId: getTrad(
|
||||
`form.attribute.${type}.option.${
|
||||
type === 'text' ? 'short-text' : 'multiple'
|
||||
}`
|
||||
`form.attribute.${type}.option.${type === 'text' ? 'short-text' : 'multiple'}`
|
||||
),
|
||||
descriptionId: getTrad(
|
||||
`form.attribute.${type}.option.${
|
||||
@ -628,9 +581,7 @@ const forms = {
|
||||
},
|
||||
{
|
||||
headerId: getTrad(
|
||||
`form.attribute.${type}.option.${
|
||||
type === 'text' ? 'long-text' : 'single'
|
||||
}`
|
||||
`form.attribute.${type}.option.${type === 'text' ? 'long-text' : 'single'}`
|
||||
),
|
||||
descriptionId: getTrad(
|
||||
`form.attribute.${type}.option.${
|
||||
@ -751,6 +702,35 @@ const forms = {
|
||||
]);
|
||||
}
|
||||
|
||||
if (type === 'uid') {
|
||||
const options = Object.keys(attributes)
|
||||
.filter(key => attributes[key].type === 'string')
|
||||
.map(key => ({ id: key, value: key }));
|
||||
|
||||
items[0].push({
|
||||
label: {
|
||||
id: getTrad('modalForm.attribute.target-field'),
|
||||
},
|
||||
name: 'targetField',
|
||||
type: 'select',
|
||||
options: [{ id: getTrad('none'), value: '' }, ...options].map((option, index) => (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<Fragment key={index}>
|
||||
{index === 0 ? (
|
||||
<FormattedMessage id={option.id}>
|
||||
{msg => <option value={option.value}>{msg}</option>}
|
||||
</FormattedMessage>
|
||||
) : (
|
||||
<option value={option.value}>{option.value}</option>
|
||||
)}
|
||||
</Fragment>
|
||||
)),
|
||||
validations: {
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
items,
|
||||
};
|
||||
@ -814,15 +794,11 @@ const forms = {
|
||||
type: 'booleanBox',
|
||||
size: 12,
|
||||
onChangeCallback: () =>
|
||||
strapi.notification.info(
|
||||
getTrad('contentType.kind.change.warning')
|
||||
),
|
||||
strapi.notification.info(getTrad('contentType.kind.change.warning')),
|
||||
options: [
|
||||
{
|
||||
headerId: getTrad('menu.section.models.name.singular'),
|
||||
descriptionId: getTrad(
|
||||
'form.button.collection-type.description'
|
||||
),
|
||||
descriptionId: getTrad('form.button.collection-type.description'),
|
||||
value: 'collectionType',
|
||||
},
|
||||
{
|
||||
@ -860,12 +836,7 @@ const forms = {
|
||||
},
|
||||
},
|
||||
component: {
|
||||
schema(
|
||||
alreadyTakenAttributes,
|
||||
componentCategory,
|
||||
isEditing = false,
|
||||
compoUid = null
|
||||
) {
|
||||
schema(alreadyTakenAttributes, componentCategory, isEditing = false, compoUid = null) {
|
||||
const takenNames = isEditing
|
||||
? alreadyTakenAttributes.filter(uid => uid !== compoUid)
|
||||
: alreadyTakenAttributes;
|
||||
@ -873,12 +844,7 @@ const forms = {
|
||||
return yup.object().shape({
|
||||
name: yup
|
||||
.string()
|
||||
.unique(
|
||||
errorsTrads.unique,
|
||||
takenNames,
|
||||
createComponentUid,
|
||||
componentCategory
|
||||
)
|
||||
.unique(errorsTrads.unique, takenNames, createComponentUid, componentCategory)
|
||||
.isAllowed(getTrad('error.contentTypeName.reserved-name'))
|
||||
.required(errorsTrads.required),
|
||||
category: yup
|
||||
@ -911,9 +877,7 @@ const forms = {
|
||||
const isCreatingComponent = get(data, 'createComponent', false);
|
||||
|
||||
const itemsToConcat = isCreatingComponent
|
||||
? [[{ type: 'spacer' }]].concat(
|
||||
componentForm.base('componentToCreate.')
|
||||
)
|
||||
? [[{ type: 'spacer' }]].concat(componentForm.base('componentToCreate.'))
|
||||
: [
|
||||
[{ type: 'spacer' }],
|
||||
[
|
||||
|
||||
@ -257,8 +257,9 @@ const ListView = () => {
|
||||
};
|
||||
const goToCMSettingsPage = () => {
|
||||
const endPoint = isInContentTypeView
|
||||
? `/plugins/content-manager/${targetUid}/ctm-configurations/edit-settings/content-types`
|
||||
? `/plugins/content-manager/${contentTypeKind}/${targetUid}/ctm-configurations/edit-settings/content-types`
|
||||
: `/plugins/content-manager/ctm-configurations/edit-settings/components/${targetUid}/`;
|
||||
|
||||
push(endPoint);
|
||||
};
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
"attribute.text": "Text",
|
||||
"attribute.text.description": "Krátký nebo delší text",
|
||||
"attribute.time": "Čas",
|
||||
"attribute.uid": "Uuid",
|
||||
"attribute.uid": "Uid",
|
||||
"attribute.uid.description": "Unikátní identifikátor",
|
||||
"button.attributes.add.another": "Přidat další pole",
|
||||
"button.component.add": "Přidat komponent",
|
||||
|
||||
@ -28,8 +28,9 @@
|
||||
"attribute.text.description": "Small or long text like title or description",
|
||||
"attribute.text": "Text",
|
||||
"attribute.time": "Time",
|
||||
"attribute.timestamp": "Timestamp",
|
||||
"attribute.uid.description": "Unique identifier",
|
||||
"attribute.uid": "Uuid",
|
||||
"attribute.uid": "Uid",
|
||||
"button.attributes.add.another": "Add another field",
|
||||
"button.component.add": "Add a component",
|
||||
"button.component.create": "Create new component",
|
||||
@ -118,6 +119,7 @@
|
||||
"menu.section.models.name.singular": "Collection Type",
|
||||
"menu.section.single-types.name.plural": "Single Types",
|
||||
"menu.section.single-types.name.singular": "Single Type",
|
||||
"modalForm.attribute.target-field": "Attached field",
|
||||
"modalForm.attribute.form.base.name.description": "No space is allowed for the name of the attribute",
|
||||
"modalForm.attribute.form.base.name": "Name",
|
||||
"modalForm.attribute.text.type-selection": "Type",
|
||||
@ -139,6 +141,7 @@
|
||||
"modalForm.sub-header.chooseAttribute.contentType": "Select a field for your collection type",
|
||||
"modelPage.attribute.relationWith": "Relation with",
|
||||
"modelPage.contentHeader.emptyDescription.description": "There is no description",
|
||||
"none": "None",
|
||||
"notification.info.creating.notSaved": "Please save your work before creating a new collection type or component",
|
||||
"notification.info.autoreaload-disable": "The autoReload feature is required to use this plugin. Start your server with `strapi develop`",
|
||||
"plugin.description.long": "Modelize the data structure of your API. Create new fields and relations in just a minute. The files are automatically created and updated in your project.",
|
||||
|
||||
@ -50,7 +50,10 @@
|
||||
"menu.section.models.name.singular": "Collection",
|
||||
"menu.section.single-types.name.plural": "Single Types",
|
||||
"menu.section.single-types.name.singular": "Single Type",
|
||||
"modalForm.attribute.target-field": "Champ associé",
|
||||
"modalForm.attribute.target-field.none": "Aucun",
|
||||
"modalForm.singleType.header-create": "Créer un single type",
|
||||
"none": "Aucun",
|
||||
"button.single-types.create": "Créer un single type",
|
||||
"modelPage.attribute.relationWith": "Relation avec",
|
||||
"modelPage.contentHeader.emptyDescription.description": "Il n'y a pas de description",
|
||||
|
||||
@ -68,7 +68,7 @@
|
||||
"attribute.richtext.description": "Edytor tekstu z możliwością formatowania",
|
||||
"attribute.text.description": "Krótki lub długi tekst jak tytuł lub opis",
|
||||
"attribute.time": "Czas",
|
||||
"attribute.uid": "Uuid",
|
||||
"attribute.uid": "Uid",
|
||||
"attribute.uid.description": "Unikalny identyfikator",
|
||||
"button.attributes.add.another": "Dodaj kolejne pole",
|
||||
"button.component.add": "Dodaj komponent",
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
"attribute.text": "Text",
|
||||
"attribute.text.description": "Простой текст для заголовка или описания",
|
||||
"attribute.time": "Time",
|
||||
"attribute.uid": "Uuid",
|
||||
"attribute.uid": "Uid",
|
||||
"attribute.uid.description": "Уникальный идентификатор",
|
||||
"button.attributes.add.another": "Ещё поле",
|
||||
"button.component.add": "Добавить компонент",
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
"attribute.text": "Text",
|
||||
"attribute.text.description": "Krátky alebo dlhší text",
|
||||
"attribute.time": "Čas",
|
||||
"attribute.uid": "Uuid",
|
||||
"attribute.uid": "Uid",
|
||||
"attribute.uid.description": "Unikátny identifikátor",
|
||||
"button.attributes.add.another": "Pridať ďalšie políčko",
|
||||
"button.component.add": "Pridať komponent",
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
"attribute.text": "文本",
|
||||
"attribute.text.description": "较短或较长的文字,例如标题或说明",
|
||||
"attribute.time": "时间",
|
||||
"attribute.uid": "Uuid",
|
||||
"attribute.uid": "Uid",
|
||||
"attribute.uid.description": "唯一标识符",
|
||||
"button.attributes.add.another": "添加一个新字段",
|
||||
"button.component.add": "添加组件",
|
||||
|
||||
@ -5,6 +5,7 @@ const getAttributeDisplayedType = type => {
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
case 'time':
|
||||
case 'timestamp':
|
||||
displayedType = 'date';
|
||||
break;
|
||||
case 'integer':
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user