2019-07-11 15:33:49 +02:00
|
|
|
import React, { memo, useEffect, useState, useReducer } from 'react';
|
2019-07-11 11:35:18 +02:00
|
|
|
import PropTypes from 'prop-types';
|
2019-08-01 16:51:20 +02:00
|
|
|
import { cloneDeep, get } from 'lodash';
|
2019-07-11 11:35:18 +02:00
|
|
|
import {
|
2019-07-11 15:33:49 +02:00
|
|
|
BackHeader,
|
2019-07-11 11:35:18 +02:00
|
|
|
getQueryParameters,
|
|
|
|
|
LoadingIndicatorPage,
|
2019-07-11 16:53:00 +02:00
|
|
|
LiLink,
|
2019-07-11 11:35:18 +02:00
|
|
|
PluginHeader,
|
2019-07-11 15:33:49 +02:00
|
|
|
PopUpWarning,
|
2019-07-11 11:35:18 +02:00
|
|
|
request,
|
|
|
|
|
templateObject,
|
|
|
|
|
} from 'strapi-helper-plugin';
|
|
|
|
|
import pluginId from '../../pluginId';
|
2019-07-17 17:39:43 +02:00
|
|
|
import { EditViewProvider } from '../../contexts/EditView';
|
2019-07-11 11:35:18 +02:00
|
|
|
import Container from '../../components/Container';
|
2019-07-17 17:39:43 +02:00
|
|
|
import Group from '../../components/Group';
|
|
|
|
|
import Inputs from '../../components/Inputs';
|
|
|
|
|
import SelectWrapper from '../../components/SelectWrapper';
|
2019-07-16 15:19:28 +02:00
|
|
|
import init, { setDefaultForm } from './init';
|
2019-07-11 11:35:18 +02:00
|
|
|
import reducer, { initialState } from './reducer';
|
2019-07-17 17:39:43 +02:00
|
|
|
import { LinkWrapper, MainWrapper, SubWrapper } from './components';
|
2019-07-30 17:25:18 +02:00
|
|
|
import createYupSchema from './utils/schema';
|
|
|
|
|
import {
|
2019-07-30 16:18:11 +02:00
|
|
|
getMediaAttributes,
|
|
|
|
|
cleanData,
|
2019-08-01 16:51:20 +02:00
|
|
|
mapDataKeysToFilesToUpload,
|
2019-07-30 17:25:18 +02:00
|
|
|
} from './utils/formatData';
|
2019-07-11 11:35:18 +02:00
|
|
|
|
|
|
|
|
const getRequestUrl = path => `/${pluginId}/explorer/${path}`;
|
|
|
|
|
|
|
|
|
|
function EditView({
|
2019-07-11 16:53:00 +02:00
|
|
|
currentEnvironment,
|
|
|
|
|
emitEvent,
|
2019-07-11 11:35:18 +02:00
|
|
|
layouts,
|
2019-07-16 18:53:41 +02:00
|
|
|
location: { pathname, search },
|
2019-07-11 15:33:49 +02:00
|
|
|
history: { push },
|
2019-07-11 11:35:18 +02:00
|
|
|
match: {
|
|
|
|
|
params: { slug, id },
|
|
|
|
|
},
|
2019-07-11 16:53:00 +02:00
|
|
|
plugins,
|
2019-07-11 11:35:18 +02:00
|
|
|
}) {
|
2019-07-12 15:39:18 +02:00
|
|
|
const layout = get(layouts, [slug], {});
|
|
|
|
|
const isCreatingEntry = id === 'create';
|
2019-07-12 18:38:29 +02:00
|
|
|
const attributes = get(layout, ['schema', 'attributes'], {});
|
2019-07-30 17:25:18 +02:00
|
|
|
const submitAbortController = new AbortController();
|
|
|
|
|
const submitSignal = submitAbortController.signal;
|
2019-07-12 18:38:29 +02:00
|
|
|
const groups = Object.keys(attributes).reduce((acc, current) => {
|
2019-07-16 15:19:28 +02:00
|
|
|
const { group, repeatable, type, min } = get(attributes, [current], {
|
2019-07-12 18:38:29 +02:00
|
|
|
group: '',
|
|
|
|
|
type: '',
|
|
|
|
|
repeatable,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (type === 'group') {
|
2019-07-16 15:19:28 +02:00
|
|
|
acc.push({ key: current, group, repeatable, isOpen: !repeatable, min });
|
2019-07-12 18:38:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
}, []);
|
|
|
|
|
const groupLayoutsToGet = groups
|
|
|
|
|
.filter(
|
|
|
|
|
(current, index) =>
|
|
|
|
|
groups.findIndex(el => el.group === current.group) === index
|
|
|
|
|
)
|
|
|
|
|
.map(({ group }) => group);
|
2019-07-12 15:39:18 +02:00
|
|
|
|
2019-07-11 15:33:49 +02:00
|
|
|
const [showWarningCancel, setWarningCancel] = useState(false);
|
|
|
|
|
const [showWarningDelete, setWarningDelete] = useState(false);
|
|
|
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
2019-07-11 11:35:18 +02:00
|
|
|
const [reducerState, dispatch] = useReducer(reducer, initialState, () =>
|
2019-07-12 15:39:18 +02:00
|
|
|
init(initialState, layout, isCreatingEntry)
|
2019-07-11 11:35:18 +02:00
|
|
|
);
|
2019-07-17 17:39:43 +02:00
|
|
|
|
2019-07-12 15:39:18 +02:00
|
|
|
const state = reducerState.toJS();
|
2019-07-12 18:38:29 +02:00
|
|
|
const {
|
2019-07-18 16:53:12 +02:00
|
|
|
didCheckErrors,
|
|
|
|
|
errors,
|
2019-07-12 18:38:29 +02:00
|
|
|
groupLayoutsData,
|
|
|
|
|
initialData,
|
|
|
|
|
modifiedData,
|
|
|
|
|
isLoading,
|
|
|
|
|
isLoadingForLayouts,
|
|
|
|
|
} = state;
|
2019-07-11 15:33:49 +02:00
|
|
|
|
2019-07-11 11:35:18 +02:00
|
|
|
const source = getQueryParameters(search, 'source');
|
2019-07-12 18:38:29 +02:00
|
|
|
const shouldShowLoader =
|
|
|
|
|
isLoadingForLayouts || (!isCreatingEntry && isLoading);
|
2019-07-11 11:35:18 +02:00
|
|
|
|
|
|
|
|
useEffect(() => {
|
2019-07-18 14:34:25 +02:00
|
|
|
// Cancel requests
|
|
|
|
|
const abortControllerFetchData = new AbortController();
|
|
|
|
|
const abortControllerLayouts = new AbortController();
|
|
|
|
|
const signalFetchData = abortControllerFetchData.signal;
|
|
|
|
|
const signalFetchLayouts = abortControllerLayouts.signal;
|
|
|
|
|
|
2019-07-12 18:38:29 +02:00
|
|
|
const fetchGroupLayouts = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const data = await Promise.all(
|
|
|
|
|
groupLayoutsToGet.map(uid =>
|
2019-07-24 11:10:29 +02:00
|
|
|
request(`/${pluginId}/groups/${uid}`, {
|
2019-07-18 14:34:25 +02:00
|
|
|
method: 'GET',
|
|
|
|
|
signal: signalFetchLayouts,
|
|
|
|
|
})
|
2019-07-12 18:38:29 +02:00
|
|
|
)
|
|
|
|
|
);
|
2019-07-24 11:10:29 +02:00
|
|
|
|
2019-07-12 18:38:29 +02:00
|
|
|
const groupLayouts = data.reduce((acc, current) => {
|
2019-07-24 18:24:23 +02:00
|
|
|
acc[current.data.uid] = current.data;
|
2019-07-12 18:38:29 +02:00
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
2019-07-16 15:19:28 +02:00
|
|
|
// Retrieve all the default values for the repeatables and init the form
|
|
|
|
|
const defaultGroupValues = groups.reduce((acc, current) => {
|
|
|
|
|
const defaultForm = setDefaultForm(
|
|
|
|
|
get(groupLayouts, [current.group, 'schema', 'attributes'], {})
|
|
|
|
|
);
|
|
|
|
|
const arr = [];
|
|
|
|
|
|
|
|
|
|
if (current.min && current.repeatable === true) {
|
|
|
|
|
for (let i = 0; i < current.min; i++) {
|
|
|
|
|
arr.push({ ...defaultForm, _temp__id: i });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
acc[current.key] = {
|
|
|
|
|
toSet: arr,
|
|
|
|
|
defaultRepeatable: defaultForm,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (current.repeatable === false) {
|
|
|
|
|
acc[current.key] = {
|
|
|
|
|
toSet: defaultForm,
|
|
|
|
|
defaultRepeatable: defaultForm,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
2019-07-12 18:38:29 +02:00
|
|
|
dispatch({
|
|
|
|
|
type: 'GET_GROUP_LAYOUTS_SUCCEEDED',
|
|
|
|
|
groupLayouts,
|
2019-07-16 15:19:28 +02:00
|
|
|
defaultGroupValues,
|
|
|
|
|
isCreatingEntry,
|
2019-07-12 18:38:29 +02:00
|
|
|
});
|
|
|
|
|
} catch (err) {
|
|
|
|
|
// TODO ADD A TRAD
|
2019-07-18 14:34:25 +02:00
|
|
|
|
|
|
|
|
if (err.code !== 20) {
|
|
|
|
|
strapi.notification.error('notification.error');
|
|
|
|
|
}
|
2019-07-12 18:38:29 +02:00
|
|
|
}
|
|
|
|
|
};
|
2019-07-18 18:14:29 +02:00
|
|
|
const fetchData = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const data = await request(getRequestUrl(`${slug}/${id}`), {
|
|
|
|
|
method: 'GET',
|
|
|
|
|
params: { source },
|
|
|
|
|
signal: signalFetchData,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'GET_DATA_SUCCEEDED',
|
|
|
|
|
data,
|
|
|
|
|
});
|
|
|
|
|
fetchGroupLayouts();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
if (err.code !== 20) {
|
|
|
|
|
strapi.notification.error(`${pluginId}.error.record.fetch`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2019-07-12 18:38:29 +02:00
|
|
|
|
2019-07-11 11:35:18 +02:00
|
|
|
if (!isCreatingEntry) {
|
|
|
|
|
fetchData();
|
2019-07-17 18:22:33 +02:00
|
|
|
} else {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'INIT',
|
|
|
|
|
data: setDefaultForm(get(layout, ['schema', 'attributes'])),
|
|
|
|
|
});
|
2019-07-18 18:14:29 +02:00
|
|
|
fetchGroupLayouts();
|
2019-07-11 11:35:18 +02:00
|
|
|
}
|
2019-07-17 18:22:33 +02:00
|
|
|
|
2019-07-18 14:34:25 +02:00
|
|
|
return () => {
|
|
|
|
|
abortControllerFetchData.abort();
|
|
|
|
|
abortControllerLayouts.abort();
|
2019-07-30 17:25:18 +02:00
|
|
|
submitAbortController.abort();
|
2019-07-18 14:34:25 +02:00
|
|
|
};
|
|
|
|
|
|
2019-07-12 18:38:29 +02:00
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
2019-07-17 18:22:33 +02:00
|
|
|
}, [id, isCreatingEntry, slug, source, pathname]);
|
2019-07-11 11:35:18 +02:00
|
|
|
|
|
|
|
|
if (shouldShowLoader) {
|
|
|
|
|
return <LoadingIndicatorPage />;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-11 15:33:49 +02:00
|
|
|
const toggleWarningCancel = () => setWarningCancel(prevState => !prevState);
|
|
|
|
|
const toggleWarningDelete = () => setWarningDelete(prevState => !prevState);
|
2019-07-16 18:53:41 +02:00
|
|
|
const redirectURL = search
|
|
|
|
|
.split('redirectUrl=')
|
|
|
|
|
.filter((_, index) => index !== 0)
|
|
|
|
|
.join('');
|
|
|
|
|
|
2019-07-11 15:33:49 +02:00
|
|
|
const redirectToPreviousPage = () => push(redirectURL);
|
|
|
|
|
const handleConfirmDelete = async () => {
|
|
|
|
|
toggleWarningDelete();
|
|
|
|
|
setIsSubmitting(true);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await request(getRequestUrl(`${slug}/${id}`), {
|
|
|
|
|
method: 'DELETE',
|
|
|
|
|
params: { source },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
strapi.notification.success(`${pluginId}.success.record.delete`);
|
|
|
|
|
redirectToPreviousPage();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
setIsSubmitting(false);
|
|
|
|
|
strapi.notification.error(`${pluginId}.error.record.delete`);
|
|
|
|
|
}
|
|
|
|
|
};
|
2019-07-18 16:53:12 +02:00
|
|
|
|
2019-07-11 15:33:49 +02:00
|
|
|
const displayedFieldNameInHeader = get(
|
|
|
|
|
layout,
|
|
|
|
|
['settings', 'mainField'],
|
|
|
|
|
'id'
|
|
|
|
|
);
|
2019-07-11 11:35:18 +02:00
|
|
|
const pluginHeaderTitle = isCreatingEntry
|
|
|
|
|
? { id: `${pluginId}.containers.Edit.pluginHeader.title.new` }
|
|
|
|
|
: templateObject({ mainField: displayedFieldNameInHeader }, initialData)
|
|
|
|
|
.mainField;
|
2019-07-16 18:53:41 +02:00
|
|
|
const displayedRelations = get(layout, ['layouts', 'editRelations'], []);
|
|
|
|
|
const hasRelations = displayedRelations.length > 0;
|
2019-07-12 14:15:56 +02:00
|
|
|
const fields = get(layout, ['layouts', 'edit'], []);
|
2019-07-11 16:53:00 +02:00
|
|
|
/**
|
|
|
|
|
* Retrieve external links from injected components
|
|
|
|
|
* @type {Array} List of external links to display
|
|
|
|
|
*/
|
|
|
|
|
const retrieveLinksContainerComponent = () => {
|
|
|
|
|
const componentToInject = Object.keys(plugins).reduce((acc, current) => {
|
|
|
|
|
// Retrieve injected compos from plugin
|
|
|
|
|
// if compo can be injected in left.links area push the compo in the array
|
|
|
|
|
const currentPlugin = plugins[current];
|
|
|
|
|
const injectedComponents = get(currentPlugin, 'injectedComponents', []);
|
|
|
|
|
|
|
|
|
|
const compos = injectedComponents
|
|
|
|
|
.filter(compo => {
|
|
|
|
|
return (
|
|
|
|
|
compo.plugin === `${pluginId}.editPage` &&
|
|
|
|
|
compo.area === 'right.links'
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
.map(compo => {
|
|
|
|
|
const Component = compo.component;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Component
|
|
|
|
|
currentEnvironment={currentEnvironment}
|
|
|
|
|
getModelName={() => slug}
|
|
|
|
|
getSource={() => source}
|
|
|
|
|
getContentTypeBuilderBaseUrl={() =>
|
|
|
|
|
'/plugins/content-type-builder/models/'
|
|
|
|
|
}
|
|
|
|
|
{...compo.props}
|
|
|
|
|
key={compo.key}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
emitEvent('willEditContentTypeFromEditView');
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return [...acc, ...compos];
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
return componentToInject;
|
|
|
|
|
};
|
2019-07-15 14:41:43 +02:00
|
|
|
|
2019-07-18 16:53:12 +02:00
|
|
|
const handleSubmit = async e => {
|
|
|
|
|
e.preventDefault();
|
2019-07-19 09:32:36 +02:00
|
|
|
const schema = createYupSchema(layout, { groups: groupLayoutsData });
|
2019-07-18 16:53:12 +02:00
|
|
|
|
|
|
|
|
try {
|
2019-07-30 17:41:14 +02:00
|
|
|
// Validate the form using yup
|
2019-07-18 16:53:12 +02:00
|
|
|
await schema.validate(modifiedData, { abortEarly: false });
|
2019-07-30 17:41:14 +02:00
|
|
|
// Set the loading state in the plugin header
|
2019-07-30 17:25:18 +02:00
|
|
|
setIsSubmitting(true);
|
2019-07-30 17:41:14 +02:00
|
|
|
emitEvent('willSaveEntry');
|
|
|
|
|
// Create an object containing all the paths of the media fields
|
2019-07-30 16:18:11 +02:00
|
|
|
const filesMap = getMediaAttributes(layout, groupLayoutsData);
|
2019-08-01 16:51:20 +02:00
|
|
|
// Create an object that maps the keys with the related files to upload
|
|
|
|
|
const filesToUpload = mapDataKeysToFilesToUpload(filesMap, modifiedData);
|
2019-07-30 16:18:11 +02:00
|
|
|
|
2019-08-01 16:51:20 +02:00
|
|
|
const cleanedData = cleanData(
|
|
|
|
|
cloneDeep(modifiedData),
|
|
|
|
|
layout,
|
|
|
|
|
groupLayoutsData
|
|
|
|
|
);
|
2019-07-30 16:18:11 +02:00
|
|
|
|
2019-08-01 16:51:20 +02:00
|
|
|
const formData = new FormData();
|
2019-07-30 16:18:11 +02:00
|
|
|
|
2019-08-01 16:51:20 +02:00
|
|
|
formData.append('data', JSON.stringify(cleanedData));
|
2019-07-30 16:18:11 +02:00
|
|
|
|
2019-08-01 16:51:20 +02:00
|
|
|
Object.keys(filesToUpload).forEach(key => {
|
|
|
|
|
const files = filesToUpload[key];
|
2019-07-30 16:18:11 +02:00
|
|
|
|
2019-08-01 16:51:20 +02:00
|
|
|
files.forEach(file => {
|
|
|
|
|
formData.append(`files.${key}`, file);
|
|
|
|
|
});
|
|
|
|
|
});
|
2019-07-30 16:18:11 +02:00
|
|
|
|
|
|
|
|
// Change the request helper default headers so we can pass a FormData
|
|
|
|
|
const headers = { 'X-Forwarded-Host': 'strapi' };
|
|
|
|
|
const method = isCreatingEntry ? 'POST' : 'PUT';
|
|
|
|
|
const endPoint = isCreatingEntry ? slug : `${slug}/${id}`;
|
|
|
|
|
|
2019-07-30 17:41:14 +02:00
|
|
|
try {
|
|
|
|
|
// Time to actually send the data
|
2019-08-01 16:51:20 +02:00
|
|
|
await request(
|
|
|
|
|
getRequestUrl(endPoint),
|
|
|
|
|
{
|
|
|
|
|
method,
|
|
|
|
|
headers,
|
|
|
|
|
params: { source },
|
|
|
|
|
body: formData,
|
|
|
|
|
signal: submitSignal,
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
false
|
|
|
|
|
);
|
2019-07-30 17:41:14 +02:00
|
|
|
emitEvent('didSaveEntry');
|
|
|
|
|
redirectToPreviousPage();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.log('send data error', err);
|
|
|
|
|
emitEvent('didNotSaveEntry', { error: err });
|
|
|
|
|
// TODO handle errors from the API
|
|
|
|
|
strapi.notification.error(
|
|
|
|
|
`${pluginId}.containers.EditView.notification.errors`
|
|
|
|
|
);
|
|
|
|
|
}
|
2019-07-18 16:53:12 +02:00
|
|
|
} catch (err) {
|
2019-07-30 17:25:18 +02:00
|
|
|
setIsSubmitting(false);
|
2019-07-30 16:18:11 +02:00
|
|
|
console.log({ err });
|
2019-07-18 16:53:12 +02:00
|
|
|
const errors = get(err, 'inner', []).reduce((acc, curr) => {
|
|
|
|
|
acc[
|
|
|
|
|
curr.path
|
|
|
|
|
.split('[')
|
|
|
|
|
.join('.')
|
|
|
|
|
.split(']')
|
|
|
|
|
.join('')
|
|
|
|
|
] = [{ id: curr.message }];
|
|
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'SET_ERRORS',
|
|
|
|
|
errors,
|
|
|
|
|
});
|
|
|
|
|
|
2019-07-19 09:32:36 +02:00
|
|
|
strapi.notification.error(
|
|
|
|
|
`${pluginId}.containers.EditView.notification.errors`
|
|
|
|
|
);
|
2019-07-18 16:53:12 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2019-07-11 11:35:18 +02:00
|
|
|
return (
|
2019-07-17 17:39:43 +02:00
|
|
|
<EditViewProvider
|
|
|
|
|
addRelation={({ target: { name, value } }) => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'ADD_RELATION',
|
|
|
|
|
keys: name.split('.'),
|
|
|
|
|
value,
|
|
|
|
|
});
|
|
|
|
|
}}
|
2019-07-18 16:53:12 +02:00
|
|
|
didCheckErrors={didCheckErrors}
|
|
|
|
|
errors={errors}
|
2019-07-17 17:39:43 +02:00
|
|
|
moveRelation={(dragIndex, overIndex, name) => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'MOVE_FIELD',
|
|
|
|
|
dragIndex,
|
|
|
|
|
overIndex,
|
|
|
|
|
keys: name.split('.'),
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
onChange={({ target: { name, value } }) => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'ON_CHANGE',
|
|
|
|
|
keys: name.split('.'),
|
|
|
|
|
value,
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
onRemove={keys => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'REMOVE_RELATION',
|
|
|
|
|
keys,
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
pathname={pathname}
|
|
|
|
|
search={search}
|
|
|
|
|
>
|
2019-07-11 15:33:49 +02:00
|
|
|
<BackHeader onClick={() => redirectToPreviousPage()} />
|
|
|
|
|
<Container className="container-fluid">
|
|
|
|
|
<form onSubmit={handleSubmit}>
|
|
|
|
|
<PluginHeader
|
|
|
|
|
actions={[
|
|
|
|
|
{
|
|
|
|
|
label: `${pluginId}.containers.Edit.reset`,
|
|
|
|
|
kind: 'secondary',
|
|
|
|
|
onClick: () => {
|
|
|
|
|
toggleWarningCancel();
|
|
|
|
|
},
|
|
|
|
|
type: 'button',
|
|
|
|
|
disabled: isSubmitting, // TODO STATE WHEN SUBMITING
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
kind: 'primary',
|
|
|
|
|
label: `${pluginId}.containers.Edit.submit`,
|
|
|
|
|
type: 'submit',
|
|
|
|
|
loader: isSubmitting,
|
|
|
|
|
style: isSubmitting
|
|
|
|
|
? { marginRight: '18px', flexGrow: 2 }
|
|
|
|
|
: { flexGrow: 2 },
|
|
|
|
|
disabled: isSubmitting, // TODO STATE WHEN SUBMITING
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
subActions={
|
|
|
|
|
isCreatingEntry
|
|
|
|
|
? []
|
|
|
|
|
: [
|
|
|
|
|
{
|
|
|
|
|
label: 'app.utils.delete',
|
|
|
|
|
kind: 'delete',
|
|
|
|
|
onClick: () => {
|
|
|
|
|
toggleWarningDelete();
|
|
|
|
|
},
|
|
|
|
|
type: 'button',
|
|
|
|
|
disabled: isSubmitting, // TODO STATE WHEN SUBMITING
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
title={pluginHeaderTitle}
|
|
|
|
|
/>
|
2019-07-11 16:53:00 +02:00
|
|
|
<div className="row">
|
2019-07-24 18:24:23 +02:00
|
|
|
<div className="col-md-12 col-lg-9">
|
2019-07-12 14:15:56 +02:00
|
|
|
<MainWrapper>
|
|
|
|
|
{fields.map((fieldsRow, key) => {
|
2019-07-12 18:38:29 +02:00
|
|
|
const [{ name }] = fieldsRow;
|
|
|
|
|
const group = get(layout, ['schema', 'attributes', name], {});
|
2019-07-24 10:16:44 +02:00
|
|
|
const groupMetas = get(
|
|
|
|
|
layout,
|
|
|
|
|
['metadatas', name, 'edit'],
|
|
|
|
|
{}
|
|
|
|
|
);
|
2019-07-13 10:04:25 +02:00
|
|
|
const groupValue = get(
|
|
|
|
|
modifiedData,
|
|
|
|
|
[name],
|
|
|
|
|
group.repeatable ? [] : {}
|
|
|
|
|
);
|
2019-07-12 18:38:29 +02:00
|
|
|
|
|
|
|
|
if (fieldsRow.length === 1 && group.type === 'group') {
|
2019-08-09 13:23:39 +02:00
|
|
|
const groupErrorKeys = Object.keys(errors)
|
|
|
|
|
.filter(errorKey => errorKey.includes(name))
|
|
|
|
|
.map(errorKey =>
|
|
|
|
|
errorKey
|
|
|
|
|
.split('.')
|
|
|
|
|
.slice(0, 2)
|
|
|
|
|
.join('.')
|
|
|
|
|
);
|
|
|
|
|
|
2019-07-12 18:38:29 +02:00
|
|
|
return (
|
|
|
|
|
<Group
|
|
|
|
|
{...group}
|
2019-07-24 10:16:44 +02:00
|
|
|
{...groupMetas}
|
2019-07-15 13:00:31 +02:00
|
|
|
addField={keys => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'ADD_FIELD_TO_GROUP',
|
|
|
|
|
keys: keys.split('.'),
|
|
|
|
|
});
|
|
|
|
|
}}
|
2019-08-09 13:23:39 +02:00
|
|
|
groupErrorKeys={groupErrorKeys}
|
2019-07-13 10:04:25 +02:00
|
|
|
groupValue={groupValue}
|
|
|
|
|
key={key}
|
2019-08-01 16:51:20 +02:00
|
|
|
isRepeatable={group.repeatable || false}
|
2019-07-13 10:04:25 +02:00
|
|
|
name={name}
|
2019-07-15 14:41:43 +02:00
|
|
|
modifiedData={modifiedData}
|
2019-07-15 17:29:13 +02:00
|
|
|
moveGroupField={(dragIndex, overIndex, name) => {
|
|
|
|
|
dispatch({
|
2019-07-17 15:35:19 +02:00
|
|
|
type: 'MOVE_FIELD',
|
2019-07-15 17:29:13 +02:00
|
|
|
dragIndex,
|
|
|
|
|
overIndex,
|
|
|
|
|
keys: name.split('.'),
|
|
|
|
|
});
|
|
|
|
|
}}
|
2019-07-13 10:04:25 +02:00
|
|
|
onChange={({ target: { name, value } }) => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'ON_CHANGE',
|
|
|
|
|
keys: name.split('.'),
|
|
|
|
|
value,
|
|
|
|
|
});
|
|
|
|
|
}}
|
2019-07-15 14:41:43 +02:00
|
|
|
layout={get(groupLayoutsData, group.group, {})}
|
2019-07-17 16:14:00 +02:00
|
|
|
pathname={pathname}
|
2019-07-16 16:06:46 +02:00
|
|
|
removeField={(keys, shouldAddEmptyField) => {
|
2019-07-15 13:00:31 +02:00
|
|
|
dispatch({
|
|
|
|
|
type: 'ON_REMOVE_FIELD',
|
|
|
|
|
keys: keys.split('.'),
|
2019-07-16 16:06:46 +02:00
|
|
|
shouldAddEmptyField,
|
2019-07-15 13:00:31 +02:00
|
|
|
});
|
|
|
|
|
}}
|
2019-07-12 18:38:29 +02:00
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
2019-07-12 14:15:56 +02:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div key={key} className="row">
|
2019-07-17 12:06:19 +02:00
|
|
|
{fieldsRow.map(({ name }, index) => {
|
2019-07-12 14:15:56 +02:00
|
|
|
return (
|
2019-07-12 15:39:18 +02:00
|
|
|
<Inputs
|
2019-07-17 12:06:19 +02:00
|
|
|
autoFocus={key === 0 && index === 0}
|
2019-07-18 16:53:12 +02:00
|
|
|
didCheckErrors={didCheckErrors}
|
|
|
|
|
errors={errors}
|
2019-07-12 15:39:18 +02:00
|
|
|
key={name}
|
2019-07-15 14:41:43 +02:00
|
|
|
keys={name}
|
|
|
|
|
layout={layout}
|
|
|
|
|
modifiedData={modifiedData}
|
2019-07-12 15:39:18 +02:00
|
|
|
name={name}
|
2019-07-12 15:44:23 +02:00
|
|
|
onChange={({ target: { name, value } }) => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'ON_CHANGE',
|
|
|
|
|
keys: name.split('.'),
|
|
|
|
|
value,
|
|
|
|
|
});
|
|
|
|
|
}}
|
2019-07-12 15:39:18 +02:00
|
|
|
/>
|
2019-07-12 14:15:56 +02:00
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</MainWrapper>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="col-md-12 col-lg-3">
|
|
|
|
|
{hasRelations && (
|
|
|
|
|
<SubWrapper
|
2019-07-29 17:11:53 +02:00
|
|
|
style={{ padding: '0 20px 1px', marginBottom: '26px' }}
|
2019-07-12 14:15:56 +02:00
|
|
|
>
|
2019-07-22 11:41:27 +02:00
|
|
|
<div style={{ paddingTop: '22px' }}>
|
2019-07-16 18:53:41 +02:00
|
|
|
{displayedRelations.map(relationName => {
|
|
|
|
|
const relation = get(
|
|
|
|
|
layout,
|
|
|
|
|
['schema', 'attributes', relationName],
|
|
|
|
|
{}
|
|
|
|
|
);
|
|
|
|
|
const relationMetas = get(
|
|
|
|
|
layout,
|
2019-07-24 10:16:44 +02:00
|
|
|
['metadatas', relationName, 'edit'],
|
2019-07-16 18:53:41 +02:00
|
|
|
{}
|
|
|
|
|
);
|
|
|
|
|
const value = get(modifiedData, [relationName], null);
|
|
|
|
|
|
|
|
|
|
return (
|
2019-07-17 12:06:19 +02:00
|
|
|
<SelectWrapper
|
2019-07-16 18:53:41 +02:00
|
|
|
{...relation}
|
|
|
|
|
{...relationMetas}
|
2019-07-17 12:06:19 +02:00
|
|
|
key={relationName}
|
2019-07-16 18:53:41 +02:00
|
|
|
name={relationName}
|
2019-07-24 10:16:44 +02:00
|
|
|
relationsType={relation.relationType}
|
2019-07-16 18:53:41 +02:00
|
|
|
value={value}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
})}
|
2019-07-15 13:00:31 +02:00
|
|
|
</div>
|
2019-07-12 14:15:56 +02:00
|
|
|
</SubWrapper>
|
|
|
|
|
)}
|
2019-07-11 16:53:00 +02:00
|
|
|
<LinkWrapper>
|
|
|
|
|
<ul>
|
|
|
|
|
<LiLink
|
|
|
|
|
message={{
|
|
|
|
|
id: `${pluginId}.containers.Edit.Link.Layout`,
|
|
|
|
|
}}
|
|
|
|
|
icon="layout"
|
|
|
|
|
key={`${pluginId}.link`}
|
2019-07-31 16:29:04 +02:00
|
|
|
url={`/plugins/${pluginId}/ctm-configurations/models/${slug}/edit-settings${
|
|
|
|
|
source !== pluginId ? `?source=${source}` : ''
|
|
|
|
|
}`}
|
2019-07-11 16:53:00 +02:00
|
|
|
onClick={() => {
|
|
|
|
|
emitEvent('willEditContentTypeLayoutFromEditView');
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
{retrieveLinksContainerComponent()}
|
|
|
|
|
</ul>
|
|
|
|
|
</LinkWrapper>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2019-07-11 15:33:49 +02:00
|
|
|
</form>
|
|
|
|
|
<PopUpWarning
|
|
|
|
|
isOpen={showWarningCancel}
|
|
|
|
|
toggleModal={toggleWarningCancel}
|
|
|
|
|
content={{
|
|
|
|
|
title: `${pluginId}.popUpWarning.title`,
|
|
|
|
|
message: `${pluginId}.popUpWarning.warning.cancelAllSettings`,
|
|
|
|
|
cancel: `${pluginId}.popUpWarning.button.cancel`,
|
|
|
|
|
confirm: `${pluginId}.popUpWarning.button.confirm`,
|
|
|
|
|
}}
|
|
|
|
|
popUpWarningType="danger"
|
|
|
|
|
onConfirm={() => {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: 'RESET_FORM',
|
|
|
|
|
});
|
|
|
|
|
toggleWarningCancel();
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
<PopUpWarning
|
|
|
|
|
isOpen={showWarningDelete}
|
|
|
|
|
toggleModal={toggleWarningDelete}
|
|
|
|
|
content={{
|
|
|
|
|
title: `${pluginId}.popUpWarning.title`,
|
|
|
|
|
message: `${pluginId}.popUpWarning.bodyMessage.contentType.delete`,
|
|
|
|
|
cancel: `${pluginId}.popUpWarning.button.cancel`,
|
|
|
|
|
confirm: `${pluginId}.popUpWarning.button.confirm`,
|
|
|
|
|
}}
|
|
|
|
|
popUpWarningType="danger"
|
|
|
|
|
onConfirm={handleConfirmDelete}
|
2019-07-11 11:35:18 +02:00
|
|
|
/>
|
2019-07-11 15:33:49 +02:00
|
|
|
</Container>
|
2019-07-17 17:39:43 +02:00
|
|
|
</EditViewProvider>
|
2019-07-11 11:35:18 +02:00
|
|
|
);
|
2019-07-10 09:31:26 +02:00
|
|
|
}
|
|
|
|
|
|
2019-07-11 11:35:18 +02:00
|
|
|
EditView.propTypes = {
|
2019-07-11 16:53:00 +02:00
|
|
|
currentEnvironment: PropTypes.string.isRequired,
|
|
|
|
|
emitEvent: PropTypes.func.isRequired,
|
2019-07-11 15:33:49 +02:00
|
|
|
history: PropTypes.shape({
|
|
|
|
|
push: PropTypes.func.isRequired,
|
|
|
|
|
}),
|
2019-07-11 11:35:18 +02:00
|
|
|
layouts: PropTypes.object,
|
|
|
|
|
location: PropTypes.shape({
|
2019-07-19 17:42:47 +02:00
|
|
|
pathname: PropTypes.string,
|
2019-07-11 11:35:18 +02:00
|
|
|
search: PropTypes.string,
|
|
|
|
|
}),
|
|
|
|
|
match: PropTypes.shape({
|
|
|
|
|
params: PropTypes.shape({
|
|
|
|
|
id: PropTypes.string.isRequired,
|
|
|
|
|
slug: PropTypes.string.isRequired,
|
|
|
|
|
}),
|
|
|
|
|
}),
|
2019-07-11 16:53:00 +02:00
|
|
|
plugins: PropTypes.object,
|
2019-07-11 11:35:18 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default memo(EditView);
|