mirror of
https://github.com/strapi/strapi.git
synced 2025-07-23 09:00:19 +00:00
Content manager edit layout and fields links list
This commit is contained in:
parent
c1ffbbfb57
commit
cbb53ac8d4
@ -20,7 +20,7 @@ import { bindActionCreators, compose } from 'redux';
|
|||||||
// Actions required for disabling and enabling the OverlayBlocker
|
// Actions required for disabling and enabling the OverlayBlocker
|
||||||
import {
|
import {
|
||||||
disableGlobalOverlayBlocker,
|
disableGlobalOverlayBlocker,
|
||||||
enableGlobalOverlayBlocker
|
enableGlobalOverlayBlocker,
|
||||||
} from 'actions/overlayBlocker';
|
} from 'actions/overlayBlocker';
|
||||||
import { pluginLoaded, updatePlugin } from 'containers/App/actions';
|
import { pluginLoaded, updatePlugin } from 'containers/App/actions';
|
||||||
import {
|
import {
|
||||||
@ -30,7 +30,7 @@ import {
|
|||||||
makeSelectIsAppLoading,
|
makeSelectIsAppLoading,
|
||||||
makeSelectShowGlobalAppBlocker,
|
makeSelectShowGlobalAppBlocker,
|
||||||
selectHasUserPlugin,
|
selectHasUserPlugin,
|
||||||
selectPlugins
|
selectPlugins,
|
||||||
} from 'containers/App/selectors';
|
} from 'containers/App/selectors';
|
||||||
// Design
|
// Design
|
||||||
import ComingSoonPage from 'containers/ComingSoonPage';
|
import ComingSoonPage from 'containers/ComingSoonPage';
|
||||||
@ -60,7 +60,7 @@ import styles from './styles.scss';
|
|||||||
|
|
||||||
const PLUGINS_TO_BLOCK_PRODUCTION = [
|
const PLUGINS_TO_BLOCK_PRODUCTION = [
|
||||||
'content-type-builder',
|
'content-type-builder',
|
||||||
'settings-manager'
|
'settings-manager',
|
||||||
];
|
];
|
||||||
|
|
||||||
export class AdminPage extends React.Component {
|
export class AdminPage extends React.Component {
|
||||||
@ -71,7 +71,7 @@ export class AdminPage extends React.Component {
|
|||||||
disableGlobalOverlayBlocker: this.props.disableGlobalOverlayBlocker,
|
disableGlobalOverlayBlocker: this.props.disableGlobalOverlayBlocker,
|
||||||
enableGlobalOverlayBlocker: this.props.enableGlobalOverlayBlocker,
|
enableGlobalOverlayBlocker: this.props.enableGlobalOverlayBlocker,
|
||||||
plugins: this.props.plugins,
|
plugins: this.props.plugins,
|
||||||
updatePlugin: this.props.updatePlugin
|
updatePlugin: this.props.updatePlugin,
|
||||||
});
|
});
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -84,7 +84,7 @@ export class AdminPage extends React.Component {
|
|||||||
const {
|
const {
|
||||||
adminPage: { uuid },
|
adminPage: { uuid },
|
||||||
location: { pathname },
|
location: { pathname },
|
||||||
plugins
|
plugins,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (prevProps.location.pathname !== pathname) {
|
if (prevProps.location.pathname !== pathname) {
|
||||||
@ -206,7 +206,7 @@ export class AdminPage extends React.Component {
|
|||||||
showLoading = () => {
|
showLoading = () => {
|
||||||
const {
|
const {
|
||||||
isAppLoading,
|
isAppLoading,
|
||||||
adminPage: { isLoading }
|
adminPage: { isLoading },
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -219,7 +219,7 @@ export class AdminPage extends React.Component {
|
|||||||
retrievePlugins = () => {
|
retrievePlugins = () => {
|
||||||
const {
|
const {
|
||||||
adminPage: { currentEnvironment },
|
adminPage: { currentEnvironment },
|
||||||
plugins
|
plugins,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (currentEnvironment === 'production') {
|
if (currentEnvironment === 'production') {
|
||||||
@ -290,11 +290,11 @@ AdminPage.childContextTypes = {
|
|||||||
disableGlobalOverlayBlocker: PropTypes.func,
|
disableGlobalOverlayBlocker: PropTypes.func,
|
||||||
enableGlobalOverlayBlocker: PropTypes.func,
|
enableGlobalOverlayBlocker: PropTypes.func,
|
||||||
plugins: PropTypes.object,
|
plugins: PropTypes.object,
|
||||||
updatePlugin: PropTypes.func
|
updatePlugin: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
AdminPage.contextTypes = {
|
AdminPage.contextTypes = {
|
||||||
router: PropTypes.object.isRequired
|
router: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
AdminPage.defaultProps = {
|
AdminPage.defaultProps = {
|
||||||
@ -302,7 +302,7 @@ AdminPage.defaultProps = {
|
|||||||
appPlugins: [],
|
appPlugins: [],
|
||||||
hasUserPlugin: true,
|
hasUserPlugin: true,
|
||||||
isAppLoading: true,
|
isAppLoading: true,
|
||||||
overlayBlockerData: {}
|
overlayBlockerData: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
AdminPage.propTypes = {
|
AdminPage.propTypes = {
|
||||||
@ -320,7 +320,7 @@ AdminPage.propTypes = {
|
|||||||
pluginLoaded: PropTypes.func.isRequired,
|
pluginLoaded: PropTypes.func.isRequired,
|
||||||
plugins: PropTypes.object.isRequired,
|
plugins: PropTypes.object.isRequired,
|
||||||
showGlobalAppBlocker: PropTypes.bool.isRequired,
|
showGlobalAppBlocker: PropTypes.bool.isRequired,
|
||||||
updatePlugin: PropTypes.func.isRequired
|
updatePlugin: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
@ -331,7 +331,7 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
hasUserPlugin: selectHasUserPlugin(),
|
hasUserPlugin: selectHasUserPlugin(),
|
||||||
isAppLoading: makeSelectIsAppLoading(),
|
isAppLoading: makeSelectIsAppLoading(),
|
||||||
plugins: selectPlugins(),
|
plugins: selectPlugins(),
|
||||||
showGlobalAppBlocker: makeSelectShowGlobalAppBlocker()
|
showGlobalAppBlocker: makeSelectShowGlobalAppBlocker(),
|
||||||
});
|
});
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
function mapDispatchToProps(dispatch) {
|
||||||
@ -341,7 +341,7 @@ function mapDispatchToProps(dispatch) {
|
|||||||
enableGlobalOverlayBlocker,
|
enableGlobalOverlayBlocker,
|
||||||
getAdminData,
|
getAdminData,
|
||||||
pluginLoaded,
|
pluginLoaded,
|
||||||
updatePlugin
|
updatePlugin,
|
||||||
},
|
},
|
||||||
dispatch
|
dispatch
|
||||||
);
|
);
|
||||||
|
@ -23,12 +23,12 @@ import {
|
|||||||
makeSelectCurrentEnv,
|
makeSelectCurrentEnv,
|
||||||
makeSelectPluginDeleteAction,
|
makeSelectPluginDeleteAction,
|
||||||
makeSelectPlugins,
|
makeSelectPlugins,
|
||||||
makeSelectIsLoading
|
makeSelectIsLoading,
|
||||||
} from './selectors';
|
} from './selectors';
|
||||||
import {
|
import {
|
||||||
getPlugins,
|
getPlugins,
|
||||||
onDeletePluginClick,
|
onDeletePluginClick,
|
||||||
onDeletePluginConfirm
|
onDeletePluginConfirm,
|
||||||
} from './actions';
|
} from './actions';
|
||||||
import reducer from './reducer';
|
import reducer from './reducer';
|
||||||
import saga from './saga';
|
import saga from './saga';
|
||||||
@ -37,7 +37,7 @@ import styles from './styles.scss';
|
|||||||
export class ListPluginsPage extends React.Component {
|
export class ListPluginsPage extends React.Component {
|
||||||
// eslint-disable-line react/prefer-stateless-function
|
// eslint-disable-line react/prefer-stateless-function
|
||||||
getChildContext = () => ({
|
getChildContext = () => ({
|
||||||
currentEnvironment: this.props.currentEnvironment
|
currentEnvironment: this.props.currentEnvironment,
|
||||||
});
|
});
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -64,10 +64,10 @@ export class ListPluginsPage extends React.Component {
|
|||||||
<div className={cn('container-fluid', styles.listPluginsPage)}>
|
<div className={cn('container-fluid', styles.listPluginsPage)}>
|
||||||
<PluginHeader
|
<PluginHeader
|
||||||
title={{
|
title={{
|
||||||
id: 'app.components.ListPluginsPage.title'
|
id: 'app.components.ListPluginsPage.title',
|
||||||
}}
|
}}
|
||||||
description={{
|
description={{
|
||||||
id: 'app.components.ListPluginsPage.description'
|
id: 'app.components.ListPluginsPage.description',
|
||||||
}}
|
}}
|
||||||
actions={[]}
|
actions={[]}
|
||||||
/>
|
/>
|
||||||
@ -85,7 +85,7 @@ export class ListPluginsPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ListPluginsPage.childContextTypes = {
|
ListPluginsPage.childContextTypes = {
|
||||||
currentEnvironment: PropTypes.string.isRequired
|
currentEnvironment: PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
ListPluginsPage.contextTypes = {};
|
ListPluginsPage.contextTypes = {};
|
||||||
@ -98,14 +98,14 @@ ListPluginsPage.propTypes = {
|
|||||||
onDeletePluginClick: PropTypes.func.isRequired,
|
onDeletePluginClick: PropTypes.func.isRequired,
|
||||||
onDeletePluginConfirm: PropTypes.func.isRequired,
|
onDeletePluginConfirm: PropTypes.func.isRequired,
|
||||||
pluginActionSucceeded: PropTypes.bool.isRequired,
|
pluginActionSucceeded: PropTypes.bool.isRequired,
|
||||||
plugins: PropTypes.object.isRequired
|
plugins: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
currentEnvironment: makeSelectCurrentEnv(),
|
currentEnvironment: makeSelectCurrentEnv(),
|
||||||
isLoading: makeSelectIsLoading(),
|
isLoading: makeSelectIsLoading(),
|
||||||
pluginActionSucceeded: makeSelectPluginDeleteAction(),
|
pluginActionSucceeded: makeSelectPluginDeleteAction(),
|
||||||
plugins: makeSelectPlugins()
|
plugins: makeSelectPlugins(),
|
||||||
});
|
});
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
function mapDispatchToProps(dispatch) {
|
||||||
@ -113,15 +113,15 @@ function mapDispatchToProps(dispatch) {
|
|||||||
{
|
{
|
||||||
getPlugins,
|
getPlugins,
|
||||||
onDeletePluginClick,
|
onDeletePluginClick,
|
||||||
onDeletePluginConfirm
|
onDeletePluginConfirm,
|
||||||
},
|
},
|
||||||
dispatch
|
dispatch,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const withConnect = connect(
|
const withConnect = connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps,
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Remove this line if the container doesn't have a route and
|
/* Remove this line if the container doesn't have a route and
|
||||||
@ -137,5 +137,5 @@ const withSaga = injectSaga({ key: 'listPluginsPage', saga });
|
|||||||
export default compose(
|
export default compose(
|
||||||
withReducer,
|
withReducer,
|
||||||
withSaga,
|
withSaga,
|
||||||
withConnect
|
withConnect,
|
||||||
)(ListPluginsPage);
|
)(ListPluginsPage);
|
||||||
|
@ -18,7 +18,7 @@ import { translationMessages } from './i18n';
|
|||||||
|
|
||||||
const LoadableApp = Loadable({
|
const LoadableApp = Loadable({
|
||||||
loader: () => import('containers/App'),
|
loader: () => import('containers/App'),
|
||||||
loading: LoadingIndicatorPage
|
loading: LoadingIndicatorPage,
|
||||||
});
|
});
|
||||||
|
|
||||||
const tryRequireRoot = source => {
|
const tryRequireRoot = source => {
|
||||||
@ -70,7 +70,7 @@ function Comp(props) {
|
|||||||
|
|
||||||
if (window.Cypress) {
|
if (window.Cypress) {
|
||||||
window.__store__ = Object.assign(window.__store__ || {}, {
|
window.__store__ = Object.assign(window.__store__ || {}, {
|
||||||
[pluginId]: store
|
[pluginId]: store,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ strapi.registerPlugin({
|
|||||||
name: pluginPkg.strapi.name,
|
name: pluginPkg.strapi.name,
|
||||||
pluginRequirements,
|
pluginRequirements,
|
||||||
preventComponentRendering: false,
|
preventComponentRendering: false,
|
||||||
translationMessages
|
translationMessages,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Export store
|
// Export store
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
<svg width="13" height="11" xmlns="http://www.w3.org/2000/svg"><g fill="#4B515A" fill-rule="evenodd"><rect x="4" y="8" width="9" height="3" rx="1.5"/><rect y="4" width="9" height="3" rx="1.5"/><rect x="3" width="9" height="3" rx="1.5"/></g></svg>
|
After Width: | Height: | Size: 246 B |
@ -0,0 +1 @@
|
|||||||
|
<svg width="13" height="11" xmlns="http://www.w3.org/2000/svg"><g fill="#007EFF" fill-rule="evenodd"><rect x="4" y="8" width="9" height="3" rx="1.5"/><rect y="4" width="9" height="3" rx="1.5"/><rect x="3" width="9" height="3" rx="1.5"/></g></svg>
|
After Width: | Height: | Size: 246 B |
@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* NavLink
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import { isObject } from 'lodash';
|
||||||
|
import cn from 'classnames';
|
||||||
|
|
||||||
|
import styles from './styles.scss';
|
||||||
|
|
||||||
|
function NavLink(props) {
|
||||||
|
let content = props.children;
|
||||||
|
|
||||||
|
if (typeof props.message === 'string') {
|
||||||
|
content = props.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isObject(props.message) && props.message.id) {
|
||||||
|
content = <FormattedMessage id={props.message.id} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
let icon = <i className={`fa ${props.icon}`} />;
|
||||||
|
|
||||||
|
if (props.icon === 'layout') {
|
||||||
|
icon = <i className={cn(styles.fa, styles.layout)} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link to={props.url} className={cn(styles.navLink)}>
|
||||||
|
{icon}
|
||||||
|
{content}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
NavLink.defaultProps = {
|
||||||
|
children: '',
|
||||||
|
icon: '',
|
||||||
|
message: '',
|
||||||
|
url: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
NavLink.propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
icon: PropTypes.string,
|
||||||
|
message: PropTypes.oneOfType([
|
||||||
|
PropTypes.func,
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.shape({
|
||||||
|
id: PropTypes.string,
|
||||||
|
params: PropTypes.object,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
url: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NavLink;
|
@ -0,0 +1,28 @@
|
|||||||
|
a.navLink {
|
||||||
|
text-decoration: none;
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
span, i {
|
||||||
|
color: #333740;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
i {
|
||||||
|
margin-right: 10px;
|
||||||
|
width: 13px;
|
||||||
|
height: 11px;
|
||||||
|
}
|
||||||
|
.fa.layout {
|
||||||
|
background-image: url('../../assets/icons/icon_layout.svg');
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
span, i {
|
||||||
|
color: #007EFF;
|
||||||
|
}
|
||||||
|
.fa.layout {
|
||||||
|
background-image: url('../../assets/icons/icon_layout_hover.svg');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,16 +2,19 @@ import { map, omit } from 'lodash';
|
|||||||
import request from 'utils/request';
|
import request from 'utils/request';
|
||||||
|
|
||||||
// This method is executed before the load of the plugin
|
// This method is executed before the load of the plugin
|
||||||
const bootstrap = (plugin) => new Promise((resolve, reject) => {
|
const bootstrap = plugin =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
request('/content-manager/models', { method: 'GET' })
|
request('/content-manager/models', { method: 'GET' })
|
||||||
.then(models => {
|
.then(models => {
|
||||||
const menu = [{
|
const menu = [
|
||||||
|
{
|
||||||
name: 'Content Types',
|
name: 'Content Types',
|
||||||
links: map(omit(models.models.models, 'plugins'), (model, key) => ({
|
links: map(omit(models.models.models, 'plugins'), (model, key) => ({
|
||||||
label: model.labelPlural || model.label || key,
|
label: model.labelPlural || model.label || key,
|
||||||
destination: key,
|
destination: key,
|
||||||
})),
|
})),
|
||||||
}];
|
},
|
||||||
|
];
|
||||||
plugin.leftMenuSections = menu;
|
plugin.leftMenuSections = menu;
|
||||||
resolve(plugin);
|
resolve(plugin);
|
||||||
})
|
})
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { bindActionCreators, compose } from 'redux';
|
import { bindActionCreators, compose } from 'redux';
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import { createStructuredSelector } from 'reselect';
|
import { createStructuredSelector } from 'reselect';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import {
|
||||||
@ -19,7 +18,7 @@ import {
|
|||||||
toNumber,
|
toNumber,
|
||||||
toString,
|
toString,
|
||||||
truncate,
|
truncate,
|
||||||
replace
|
replace,
|
||||||
} from 'lodash';
|
} from 'lodash';
|
||||||
import HTML5Backend from 'react-dnd-html5-backend';
|
import HTML5Backend from 'react-dnd-html5-backend';
|
||||||
import { DragDropContext } from 'react-dnd';
|
import { DragDropContext } from 'react-dnd';
|
||||||
@ -32,7 +31,7 @@ import EmptyAttributesBlock from 'components/EmptyAttributesBlock';
|
|||||||
import LoadingIndicator from 'components/LoadingIndicator';
|
import LoadingIndicator from 'components/LoadingIndicator';
|
||||||
import PluginHeader from 'components/PluginHeader';
|
import PluginHeader from 'components/PluginHeader';
|
||||||
import PopUpWarning from 'components/PopUpWarning';
|
import PopUpWarning from 'components/PopUpWarning';
|
||||||
import ListRow from 'components/ListRow';
|
import NavLink from 'components/NavLink';
|
||||||
// Plugin's components
|
// Plugin's components
|
||||||
import CustomDragLayer from 'components/CustomDragLayer';
|
import CustomDragLayer from 'components/CustomDragLayer';
|
||||||
import Edit from 'components/Edit';
|
import Edit from 'components/Edit';
|
||||||
@ -59,13 +58,15 @@ import {
|
|||||||
resetProps,
|
resetProps,
|
||||||
setFileRelations,
|
setFileRelations,
|
||||||
setFormErrors,
|
setFormErrors,
|
||||||
submit
|
submit,
|
||||||
} from './actions';
|
} from './actions';
|
||||||
import reducer from './reducer';
|
import reducer from './reducer';
|
||||||
import saga from './saga';
|
import saga from './saga';
|
||||||
import makeSelectEditPage from './selectors';
|
import makeSelectEditPage from './selectors';
|
||||||
import styles from './styles.scss';
|
import styles from './styles.scss';
|
||||||
|
|
||||||
|
const pluginId = 'content-manager';
|
||||||
|
|
||||||
export class EditPage extends React.Component {
|
export class EditPage extends React.Component {
|
||||||
state = { showWarning: false, showWarningDelete: false };
|
state = { showWarning: false, showWarningDelete: false };
|
||||||
|
|
||||||
@ -87,17 +88,17 @@ export class EditPage extends React.Component {
|
|||||||
includes(this.props.location.search, '?redirectUrl')
|
includes(this.props.location.search, '?redirectUrl')
|
||||||
) {
|
) {
|
||||||
const redirectUrl = this.props.location.search.split(
|
const redirectUrl = this.props.location.search.split(
|
||||||
'?redirectUrl='
|
'?redirectUrl=',
|
||||||
)[1];
|
)[1];
|
||||||
|
|
||||||
this.props.history.push({
|
this.props.history.push({
|
||||||
pathname: redirectUrl.split('?')[0],
|
pathname: redirectUrl.split('?')[0],
|
||||||
search: redirectUrl.split('?')[1]
|
search: redirectUrl.split('?')[1],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.props.history.push({
|
this.props.history.push({
|
||||||
pathname: replace(this.props.location.pathname, '/create', ''),
|
pathname: replace(this.props.location.pathname, '/create', ''),
|
||||||
search: `?source=${this.getSource()}`
|
search: `?source=${this.getSource()}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,7 +123,7 @@ export class EditPage extends React.Component {
|
|||||||
getLayout = () =>
|
getLayout = () =>
|
||||||
bindLayout.call(
|
bindLayout.call(
|
||||||
this,
|
this,
|
||||||
get(this.props.schema, ['layout', this.getModelName()], {})
|
get(this.props.schema, ['layout', this.getModelName()], {}),
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -135,9 +136,9 @@ export class EditPage extends React.Component {
|
|||||||
this.props.editPage.formValidations,
|
this.props.editPage.formValidations,
|
||||||
[
|
[
|
||||||
findIndex(this.props.editPage.formValidations, ['name', name]),
|
findIndex(this.props.editPage.formValidations, ['name', name]),
|
||||||
'validations'
|
'validations',
|
||||||
],
|
],
|
||||||
{}
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
getDisplayedFields = () =>
|
getDisplayedFields = () =>
|
||||||
@ -153,7 +154,7 @@ export class EditPage extends React.Component {
|
|||||||
'models',
|
'models',
|
||||||
'plugins',
|
'plugins',
|
||||||
this.getSource(),
|
this.getSource(),
|
||||||
this.getModelName()
|
this.getModelName(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -179,12 +180,12 @@ export class EditPage extends React.Component {
|
|||||||
* @return {Object}
|
* @return {Object}
|
||||||
*/
|
*/
|
||||||
getSchema = () =>
|
getSchema = () =>
|
||||||
this.getSource() !== 'content-manager'
|
this.getSource() !== pluginId
|
||||||
? get(this.props.schema, [
|
? get(this.props.schema, [
|
||||||
'models',
|
'models',
|
||||||
'plugins',
|
'plugins',
|
||||||
this.getSource(),
|
this.getSource(),
|
||||||
this.getModelName()
|
this.getModelName(),
|
||||||
])
|
])
|
||||||
: get(this.props.schema, ['models', this.getModelName()]);
|
: get(this.props.schema, ['models', this.getModelName()]);
|
||||||
|
|
||||||
@ -195,18 +196,18 @@ export class EditPage extends React.Component {
|
|||||||
const primaryKey = this.getModel().primaryKey;
|
const primaryKey = this.getModel().primaryKey;
|
||||||
const {
|
const {
|
||||||
match: {
|
match: {
|
||||||
params: { id }
|
params: { id },
|
||||||
}
|
},
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const title = get(
|
const title = get(
|
||||||
this.getSchema(),
|
this.getSchema(),
|
||||||
'editDisplay.displayedField',
|
'editDisplay.displayedField',
|
||||||
primaryKey
|
primaryKey,
|
||||||
);
|
);
|
||||||
const valueToDisplay = get(
|
const valueToDisplay = get(
|
||||||
this.props.editPage,
|
this.props.editPage,
|
||||||
['initialRecord', title],
|
['initialRecord', title],
|
||||||
id
|
id,
|
||||||
);
|
);
|
||||||
|
|
||||||
return isEmpty(valueToDisplay)
|
return isEmpty(valueToDisplay)
|
||||||
@ -220,6 +221,25 @@ export class EditPage extends React.Component {
|
|||||||
*/
|
*/
|
||||||
getSource = () => getQueryParameters(this.props.location.search, 'source');
|
getSource = () => getQueryParameters(this.props.location.search, 'source');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get url base to create edit layout link
|
||||||
|
* @type {String} url base
|
||||||
|
*/
|
||||||
|
getContentManagerBaseUrl = () => {
|
||||||
|
let url = `/plugins/${pluginId}/ctm-configurations/edit-settings/`;
|
||||||
|
if (this.getSource() === 'users-permissions') {
|
||||||
|
url = `${url}plugins/${this.getSource()}/`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access url base from injected component to create edit model link
|
||||||
|
* @type {String} url base
|
||||||
|
*/
|
||||||
|
getContentTypeBuilderBaseUrl = () => '/plugins/content-type-builder/models/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize component
|
* Initialize component
|
||||||
*/
|
*/
|
||||||
@ -229,7 +249,7 @@ export class EditPage extends React.Component {
|
|||||||
this.isCreating(),
|
this.isCreating(),
|
||||||
this.getSource(),
|
this.getSource(),
|
||||||
this.getModelAttributes(),
|
this.getModelAttributes(),
|
||||||
this.getDisplayedFields()
|
this.getDisplayedFields(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!this.isCreating()) {
|
if (!this.isCreating()) {
|
||||||
@ -240,7 +260,7 @@ export class EditPage extends React.Component {
|
|||||||
|
|
||||||
// Get all relations made with the upload plugin
|
// Get all relations made with the upload plugin
|
||||||
const fileRelations = Object.keys(
|
const fileRelations = Object.keys(
|
||||||
get(this.getSchema(), 'relations', {})
|
get(this.getSchema(), 'relations', {}),
|
||||||
).reduce((acc, current) => {
|
).reduce((acc, current) => {
|
||||||
const association = get(this.getSchema(), ['relations', current], {});
|
const association = get(this.getSchema(), ['relations', current], {});
|
||||||
|
|
||||||
@ -250,7 +270,7 @@ export class EditPage extends React.Component {
|
|||||||
) {
|
) {
|
||||||
const relation = {
|
const relation = {
|
||||||
name: current,
|
name: current,
|
||||||
multiple: association.nature === 'manyToManyMorph'
|
multiple: association.nature === 'manyToManyMorph',
|
||||||
};
|
};
|
||||||
|
|
||||||
acc.push(relation);
|
acc.push(relation);
|
||||||
@ -265,7 +285,7 @@ export class EditPage extends React.Component {
|
|||||||
handleAddRelationItem = ({ key, value }) => {
|
handleAddRelationItem = ({ key, value }) => {
|
||||||
this.props.addRelationItem({
|
this.props.addRelationItem({
|
||||||
key,
|
key,
|
||||||
value
|
value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -276,19 +296,19 @@ export class EditPage extends React.Component {
|
|||||||
return this.props.changeData({
|
return this.props.changeData({
|
||||||
target: {
|
target: {
|
||||||
name: `record.${target.name}`,
|
name: `record.${target.name}`,
|
||||||
value: defaultValue
|
value: defaultValue,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const errorIndex = findIndex(this.props.editPage.formErrors, [
|
const errorIndex = findIndex(this.props.editPage.formErrors, [
|
||||||
'name',
|
'name',
|
||||||
target.name
|
target.name,
|
||||||
]);
|
]);
|
||||||
const errors = inputValidations(
|
const errors = inputValidations(
|
||||||
target.value,
|
target.value,
|
||||||
this.getAttributeValidations(target.name),
|
this.getAttributeValidations(target.name),
|
||||||
target.type
|
target.type,
|
||||||
);
|
);
|
||||||
const formErrors = cloneDeep(this.props.editPage.formErrors);
|
const formErrors = cloneDeep(this.props.editPage.formErrors);
|
||||||
|
|
||||||
@ -308,7 +328,7 @@ export class EditPage extends React.Component {
|
|||||||
// Check if date
|
// Check if date
|
||||||
if (
|
if (
|
||||||
['float', 'integer', 'biginteger', 'decimal'].indexOf(
|
['float', 'integer', 'biginteger', 'decimal'].indexOf(
|
||||||
get(this.getSchema(), ['fields', e.target.name, 'type'])
|
get(this.getSchema(), ['fields', e.target.name, 'type']),
|
||||||
) !== -1
|
) !== -1
|
||||||
) {
|
) {
|
||||||
value = toNumber(e.target.value);
|
value = toNumber(e.target.value);
|
||||||
@ -316,7 +336,7 @@ export class EditPage extends React.Component {
|
|||||||
|
|
||||||
const target = {
|
const target = {
|
||||||
name: `record.${e.target.name}`,
|
name: `record.${e.target.name}`,
|
||||||
value
|
value,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.props.changeData({ target });
|
this.props.changeData({ target });
|
||||||
@ -336,14 +356,14 @@ export class EditPage extends React.Component {
|
|||||||
|
|
||||||
handleGoBack = () => this.props.history.goBack();
|
handleGoBack = () => this.props.history.goBack();
|
||||||
|
|
||||||
handleRedirect = ({ model, id, source = 'content-manager' }) => {
|
handleRedirect = ({ model, id, source = pluginId }) => {
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
switch (model) {
|
switch (model) {
|
||||||
case 'permission':
|
case 'permission':
|
||||||
case 'role':
|
case 'role':
|
||||||
case 'file':
|
case 'file':
|
||||||
// Exclude special models which are handled by plugins.
|
// Exclude special models which are handled by plugins.
|
||||||
if (source !== 'content-manager') {
|
if (source !== pluginId) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -355,8 +375,8 @@ export class EditPage extends React.Component {
|
|||||||
pathname,
|
pathname,
|
||||||
search: `?source=${source}&redirectURI=${generateRedirectURI({
|
search: `?source=${source}&redirectURI=${generateRedirectURI({
|
||||||
model,
|
model,
|
||||||
search: `?source=${source}`
|
search: `?source=${source}`,
|
||||||
})}`
|
})}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/* eslint-enable */
|
/* eslint-enable */
|
||||||
@ -366,7 +386,7 @@ export class EditPage extends React.Component {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const formErrors = checkFormValidity(
|
const formErrors = checkFormValidity(
|
||||||
this.generateFormFromRecord(),
|
this.generateFormFromRecord(),
|
||||||
this.props.editPage.formValidations
|
this.props.editPage.formValidations,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isEmpty(formErrors)) {
|
if (isEmpty(formErrors)) {
|
||||||
@ -376,24 +396,20 @@ export class EditPage extends React.Component {
|
|||||||
this.props.setFormErrors(formErrors);
|
this.props.setFormErrors(formErrors);
|
||||||
};
|
};
|
||||||
|
|
||||||
hasDisplayedRelations = () => {
|
|
||||||
return this.getDisplayedRelations().length > 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
hasDisplayedDevSection = () => {
|
|
||||||
return process.env.NODE_ENV === 'development';
|
|
||||||
};
|
|
||||||
|
|
||||||
hasDisplayedRightSection = () => {
|
|
||||||
return this.hasDisplayedRelations || this.hasDisplayedDevSection;
|
|
||||||
};
|
|
||||||
|
|
||||||
hasDisplayedFields = () => {
|
hasDisplayedFields = () => {
|
||||||
return get(this.getModel(), ['editDisplay', 'fields'], []).length > 0;
|
return get(this.getModel(), ['editDisplay', 'fields'], []).length > 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
isCreating = () => this.props.match.params.id === 'create';
|
isCreating = () => this.props.match.params.id === 'create';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check environment
|
||||||
|
* @type {boolean} current env is dev
|
||||||
|
*/
|
||||||
|
isDevEnvironment = () => {
|
||||||
|
return process.env.NODE_ENV === 'development';
|
||||||
|
};
|
||||||
|
|
||||||
isRelationComponentNull = () =>
|
isRelationComponentNull = () =>
|
||||||
Object.keys(get(this.getSchema(), 'relations', {})).filter(
|
Object.keys(get(this.getSchema(), 'relations', {})).filter(
|
||||||
relation =>
|
relation =>
|
||||||
@ -401,7 +417,7 @@ export class EditPage extends React.Component {
|
|||||||
(!get(this.getSchema(), ['relations', relation, 'nature'], '')
|
(!get(this.getSchema(), ['relations', relation, 'nature'], '')
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.includes('morph') ||
|
.includes('morph') ||
|
||||||
!get(this.getSchema(), ['relations', relation, relation]))
|
!get(this.getSchema(), ['relations', relation, relation])),
|
||||||
).length === 0;
|
).length === 0;
|
||||||
|
|
||||||
// NOTE: technical debt that needs to be redone
|
// NOTE: technical debt that needs to be redone
|
||||||
@ -412,25 +428,43 @@ export class EditPage extends React.Component {
|
|||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the edit layout link
|
||||||
|
* @type {NavLink}
|
||||||
|
*/
|
||||||
|
layoutLink = () => {
|
||||||
|
// Retrieve URL
|
||||||
|
const url = `${this.getContentManagerBaseUrl()}${this.getModelName()}`;
|
||||||
|
// Link props to display
|
||||||
|
const message = {
|
||||||
|
message: {
|
||||||
|
id: `${pluginId}.containers.Edit.Link.Layout`,
|
||||||
|
},
|
||||||
|
icon: 'layout',
|
||||||
|
};
|
||||||
|
|
||||||
|
return <NavLink {...message} url={url} />;
|
||||||
|
};
|
||||||
|
|
||||||
pluginHeaderActions = () => [
|
pluginHeaderActions = () => [
|
||||||
{
|
{
|
||||||
label: 'content-manager.containers.Edit.reset',
|
label: `${pluginId}.containers.Edit.reset`,
|
||||||
kind: 'secondary',
|
kind: 'secondary',
|
||||||
onClick: this.toggle,
|
onClick: this.toggle,
|
||||||
type: 'button',
|
type: 'button',
|
||||||
disabled: this.showLoaders()
|
disabled: this.showLoaders(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
kind: 'primary',
|
kind: 'primary',
|
||||||
label: 'content-manager.containers.Edit.submit',
|
label: `${pluginId}.containers.Edit.submit`,
|
||||||
onClick: this.handleSubmit,
|
onClick: this.handleSubmit,
|
||||||
type: 'submit',
|
type: 'submit',
|
||||||
loader: this.props.editPage.showLoader,
|
loader: this.props.editPage.showLoader,
|
||||||
style: this.props.editPage.showLoader
|
style: this.props.editPage.showLoader
|
||||||
? { marginRight: '18px', flexGrow: 2 }
|
? { marginRight: '18px', flexGrow: 2 }
|
||||||
: { flexGrow: 2 },
|
: { flexGrow: 2 },
|
||||||
disabled: this.showLoaders()
|
disabled: this.showLoaders(),
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
pluginHeaderSubActions = () => {
|
pluginHeaderSubActions = () => {
|
||||||
@ -443,18 +477,67 @@ export class EditPage extends React.Component {
|
|||||||
kind: 'delete',
|
kind: 'delete',
|
||||||
onClick: this.toggleDelete,
|
onClick: this.toggleDelete,
|
||||||
type: 'button',
|
type: 'button',
|
||||||
disabled: this.showLoaders()
|
disabled: this.showLoaders(),
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return subActions;
|
return subActions;
|
||||||
/* eslint-enable indent */
|
/* eslint-enable indent */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve external links from injected components
|
||||||
|
* @type {Array} List of external links to display
|
||||||
|
*/
|
||||||
|
retrieveLinksContainerComponent = () => {
|
||||||
|
// Should be retrieved from the global props (@soupette)
|
||||||
|
const { plugins } = this.context;
|
||||||
|
const appPlugins = plugins.toJS();
|
||||||
|
const componentToInject = Object.keys(appPlugins).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 = appPlugins[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 (
|
||||||
|
<li key={compo.key}>
|
||||||
|
<Component {...this} {...compo.props} />
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return [...acc, ...compos];
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return componentToInject;
|
||||||
|
};
|
||||||
|
|
||||||
|
shouldDisplayedRelations = () => {
|
||||||
|
return this.getDisplayedRelations().length > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Right section to display if needed
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
shouldDisplayedRightSection = () => {
|
||||||
|
return this.shouldDisplayedRelations() || this.isDevEnvironment();
|
||||||
|
};
|
||||||
|
|
||||||
showLoaders = () => {
|
showLoaders = () => {
|
||||||
const {
|
const {
|
||||||
editPage: { isLoading },
|
editPage: { isLoading },
|
||||||
schema: { layout }
|
schema: { layout },
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -468,72 +551,38 @@ export class EditPage extends React.Component {
|
|||||||
|
|
||||||
toggleDelete = () =>
|
toggleDelete = () =>
|
||||||
this.setState(prevState => ({
|
this.setState(prevState => ({
|
||||||
showWarningDelete: !prevState.showWarningDelete
|
showWarningDelete: !prevState.showWarningDelete,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
layoutLink = () => {
|
/**
|
||||||
const url = this.getContentManagerBaseUrl() + this.getModelName();
|
* Render internal and external links
|
||||||
|
* @type {Array} List of all links to display
|
||||||
|
*/
|
||||||
|
renderNavLinks = () => {
|
||||||
|
// Add ctm link as list item to external links array to return the entire list
|
||||||
|
let ctmLink = <li key={`${pluginId}.link`}>{this.layoutLink()}</li>;
|
||||||
|
|
||||||
return <Link to={url}>Configure the layout</Link>;
|
return [ctmLink, ...this.retrieveLinksContainerComponent()];
|
||||||
};
|
|
||||||
|
|
||||||
getContentManagerBaseUrl = () => {
|
|
||||||
if (this.getModelName() !== 'user') {
|
|
||||||
return '/plugins/content-manager/ctm-configurations/edit-settings/';
|
|
||||||
} else {
|
|
||||||
return '/plugins/content-manager/ctm-configurations/edit-settings/plugins/users-permissions/';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
getContentTypeBuilderBaseUrl = () => {
|
|
||||||
return '/plugins/content-type-builder/models/';
|
|
||||||
};
|
|
||||||
|
|
||||||
retrieveLinksContainerComponent = () => {
|
|
||||||
// Should be retrieved from the global props (@soupette)
|
|
||||||
const { plugins } = this.context;
|
|
||||||
const appPlugins = plugins.toJS();
|
|
||||||
const componentToInject = Object.keys(appPlugins).reduce((acc, current) => {
|
|
||||||
// Retrieve injected compo from plugin
|
|
||||||
// if compo can be injected in left.links area push the compo in the array
|
|
||||||
const currentPlugin = appPlugins[current];
|
|
||||||
const injectedComponents = get(currentPlugin, 'injectedComponents', []);
|
|
||||||
|
|
||||||
const compos = injectedComponents
|
|
||||||
.filter(compo => {
|
|
||||||
return (
|
|
||||||
compo.plugin === 'content-manager.editPage' &&
|
|
||||||
compo.area === 'left.links'
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.map(compo => {
|
|
||||||
const Component = compo.component;
|
|
||||||
|
|
||||||
return <Component {...this} key={compo.key} />;
|
|
||||||
});
|
|
||||||
|
|
||||||
return [...acc, ...compos];
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return componentToInject;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
renderEdit = () => {
|
renderEdit = () => {
|
||||||
const {
|
const {
|
||||||
editPage,
|
editPage,
|
||||||
location: { search }
|
location: { search },
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const source = getQueryParameters(search, 'source');
|
const source = getQueryParameters(search, 'source');
|
||||||
const basePath = '/plugins/content-manager/ctm-configurations';
|
const basePath = `/plugins/${pluginId}/ctm-configurations`;
|
||||||
const pathname =
|
const pathname =
|
||||||
source !== 'content-manager'
|
source !== pluginId
|
||||||
? `${basePath}/plugins/${source}/${this.getModelName()}`
|
? `${basePath}/plugins/${source}/${this.getModelName()}`
|
||||||
: `${basePath}/${this.getModelName()}`;
|
: `${basePath}/${this.getModelName()}`;
|
||||||
|
|
||||||
if (this.showLoaders()) {
|
if (this.showLoaders()) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={!this.hasDisplayedRelations() ? 'col-lg-12' : 'col-lg-9'}
|
className={
|
||||||
|
!this.shouldDisplayedRelations() ? 'col-lg-12' : 'col-lg-9'
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<div className={styles.main_wrapper}>
|
<div className={styles.main_wrapper}>
|
||||||
<LoadingIndicator />
|
<LoadingIndicator />
|
||||||
@ -545,11 +594,13 @@ export class EditPage extends React.Component {
|
|||||||
if (!this.hasDisplayedFields()) {
|
if (!this.hasDisplayedFields()) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={!this.hasDisplayedRelations() ? 'col-lg-12' : 'col-lg-9'}
|
className={
|
||||||
|
!this.shouldDisplayedRelations() ? 'col-lg-12' : 'col-lg-9'
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<EmptyAttributesBlock
|
<EmptyAttributesBlock
|
||||||
description="content-manager.components.EmptyAttributesBlock.description"
|
description={`${pluginId}.components.EmptyAttributesBlock.description`}
|
||||||
label="content-manager.components.EmptyAttributesBlock.button"
|
label={`${pluginId}.components.EmptyAttributesBlock.button`}
|
||||||
onClick={() => this.props.history.push(pathname)}
|
onClick={() => this.props.history.push(pathname)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -558,7 +609,9 @@ export class EditPage extends React.Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={!this.hasDisplayedRightSection() ? 'col-lg-12' : 'col-lg-9'}
|
className={
|
||||||
|
!this.shouldDisplayedRightSection() ? 'col-lg-12' : 'col-lg-9'
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<div className={styles.main_wrapper}>
|
<div className={styles.main_wrapper}>
|
||||||
<Edit
|
<Edit
|
||||||
@ -599,11 +652,10 @@ export class EditPage extends React.Component {
|
|||||||
isOpen={showWarning}
|
isOpen={showWarning}
|
||||||
toggleModal={this.toggle}
|
toggleModal={this.toggle}
|
||||||
content={{
|
content={{
|
||||||
title: 'content-manager.popUpWarning.title',
|
title: `${pluginId}.popUpWarning.title`,
|
||||||
message:
|
message: `${pluginId}.popUpWarning.warning.cancelAllSettings`,
|
||||||
'content-manager.popUpWarning.warning.cancelAllSettings',
|
cancel: `${pluginId}.popUpWarning.button.cancel`,
|
||||||
cancel: 'content-manager.popUpWarning.button.cancel',
|
confirm: `${pluginId}.popUpWarning.button.confirm`,
|
||||||
confirm: 'content-manager.popUpWarning.button.confirm'
|
|
||||||
}}
|
}}
|
||||||
popUpWarningType="danger"
|
popUpWarningType="danger"
|
||||||
onConfirm={this.handleConfirm}
|
onConfirm={this.handleConfirm}
|
||||||
@ -612,20 +664,19 @@ export class EditPage extends React.Component {
|
|||||||
isOpen={showWarningDelete}
|
isOpen={showWarningDelete}
|
||||||
toggleModal={this.toggleDelete}
|
toggleModal={this.toggleDelete}
|
||||||
content={{
|
content={{
|
||||||
title: 'content-manager.popUpWarning.title',
|
title: `${pluginId}.popUpWarning.title`,
|
||||||
message:
|
message: `${pluginId}.popUpWarning.bodyMessage.contentType.delete`,
|
||||||
'content-manager.popUpWarning.bodyMessage.contentType.delete',
|
cancel: `${pluginId}.popUpWarning.button.cancel`,
|
||||||
cancel: 'content-manager.popUpWarning.button.cancel',
|
confirm: `${pluginId}.popUpWarning.button.confirm`,
|
||||||
confirm: 'content-manager.popUpWarning.button.confirm'
|
|
||||||
}}
|
}}
|
||||||
popUpWarningType="danger"
|
popUpWarningType="danger"
|
||||||
onConfirm={this.handleConfirm}
|
onConfirm={this.handleConfirm}
|
||||||
/>
|
/>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
{this.renderEdit()}
|
{this.renderEdit()}
|
||||||
{this.hasDisplayedRightSection() && (
|
{this.shouldDisplayedRightSection() && (
|
||||||
<div className={cn('col-lg-3')}>
|
<div className={cn('col-lg-3')}>
|
||||||
{this.hasDisplayedRelations() && (
|
{this.shouldDisplayedRelations() && (
|
||||||
<div className={styles.sub_wrapper}>
|
<div className={styles.sub_wrapper}>
|
||||||
<EditRelations
|
<EditRelations
|
||||||
changeData={this.props.changeData}
|
changeData={this.props.changeData}
|
||||||
@ -644,12 +695,9 @@ export class EditPage extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{this.hasDisplayedDevSection() && (
|
{this.isDevEnvironment() && (
|
||||||
<div className={styles.links_wrapper}>
|
<div className={styles.links_wrapper}>
|
||||||
<ul>
|
<ul>{this.renderNavLinks()}</ul>
|
||||||
<li>{this.layoutLink()}</li>
|
|
||||||
<li>{this.retrieveLinksContainerComponent()}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -663,11 +711,11 @@ export class EditPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
EditPage.contextTypes = {
|
EditPage.contextTypes = {
|
||||||
plugins: PropTypes.object
|
plugins: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
EditPage.defaultProps = {
|
EditPage.defaultProps = {
|
||||||
schema: {}
|
schema: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
EditPage.propTypes = {
|
EditPage.propTypes = {
|
||||||
@ -688,7 +736,7 @@ EditPage.propTypes = {
|
|||||||
schema: PropTypes.object,
|
schema: PropTypes.object,
|
||||||
setFileRelations: PropTypes.func.isRequired,
|
setFileRelations: PropTypes.func.isRequired,
|
||||||
setFormErrors: PropTypes.func.isRequired,
|
setFormErrors: PropTypes.func.isRequired,
|
||||||
submit: PropTypes.func.isRequired
|
submit: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
function mapDispatchToProps(dispatch) {
|
||||||
@ -706,20 +754,20 @@ function mapDispatchToProps(dispatch) {
|
|||||||
resetProps,
|
resetProps,
|
||||||
setFileRelations,
|
setFileRelations,
|
||||||
setFormErrors,
|
setFormErrors,
|
||||||
submit
|
submit,
|
||||||
},
|
},
|
||||||
dispatch
|
dispatch,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
editPage: makeSelectEditPage(),
|
editPage: makeSelectEditPage(),
|
||||||
schema: makeSelectSchema()
|
schema: makeSelectSchema(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const withConnect = connect(
|
const withConnect = connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps,
|
||||||
);
|
);
|
||||||
|
|
||||||
const withReducer = injectReducer({ key: 'editPage', reducer });
|
const withReducer = injectReducer({ key: 'editPage', reducer });
|
||||||
@ -728,5 +776,5 @@ const withSaga = injectSaga({ key: 'editPage', saga });
|
|||||||
export default compose(
|
export default compose(
|
||||||
withReducer,
|
withReducer,
|
||||||
withSaga,
|
withSaga,
|
||||||
withConnect
|
withConnect,
|
||||||
)(DragDropContext(HTML5Backend)(EditPage));
|
)(DragDropContext(HTML5Backend)(EditPage));
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
.sub_wrapper {
|
.sub_wrapper {
|
||||||
padding: 0 20px 1px;
|
padding: 0 20px 1px;
|
||||||
margin-bottom: 40px;
|
margin-bottom: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.links_wrapper {
|
.links_wrapper {
|
||||||
@ -33,13 +33,5 @@
|
|||||||
&:first-of-type {
|
&:first-of-type {
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
}
|
}
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
p {
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@
|
|||||||
"containers.Edit.returnList": "Return to list",
|
"containers.Edit.returnList": "Return to list",
|
||||||
"containers.Edit.seeDetails": "Details",
|
"containers.Edit.seeDetails": "Details",
|
||||||
"containers.Edit.submit": "Save",
|
"containers.Edit.submit": "Save",
|
||||||
|
"containers.Edit.Link.Layout": "Configure the layout",
|
||||||
|
"containers.Edit.Link.Fields": "Edit the fields",
|
||||||
"containers.Home.introduction": "To edit your entries go to the specific link in the left menu. This plugin doesn't have a proper way to edit settings and it's still under active development.",
|
"containers.Home.introduction": "To edit your entries go to the specific link in the left menu. This plugin doesn't have a proper way to edit settings and it's still under active development.",
|
||||||
"containers.Home.pluginHeaderDescription": "Manage your entries through a powerful and beautiful interface.",
|
"containers.Home.pluginHeaderDescription": "Manage your entries through a powerful and beautiful interface.",
|
||||||
"containers.Home.pluginHeaderTitle": "Content Manager",
|
"containers.Home.pluginHeaderTitle": "Content Manager",
|
||||||
|
@ -35,6 +35,8 @@
|
|||||||
"containers.Edit.returnList": "Retourner à la liste",
|
"containers.Edit.returnList": "Retourner à la liste",
|
||||||
"containers.Edit.seeDetails": "Détails",
|
"containers.Edit.seeDetails": "Détails",
|
||||||
"containers.Edit.submit": "Valider",
|
"containers.Edit.submit": "Valider",
|
||||||
|
"containers.Edit.Link.Layout": "Paramétrer la vue",
|
||||||
|
"containers.Edit.Link.Fields": "Éditer le modèle",
|
||||||
"containers.Home.introduction": "Pour éditer du contenu, choisissez un type de données dans le menu de gauche.",
|
"containers.Home.introduction": "Pour éditer du contenu, choisissez un type de données dans le menu de gauche.",
|
||||||
"containers.Home.pluginHeaderDescription": "Créer et modifier votre type de contenu",
|
"containers.Home.pluginHeaderDescription": "Créer et modifier votre type de contenu",
|
||||||
"containers.Home.pluginHeaderTitle": "Type de contenu",
|
"containers.Home.pluginHeaderTitle": "Type de contenu",
|
||||||
@ -120,4 +122,3 @@
|
|||||||
"success.record.delete": "Supprimé",
|
"success.record.delete": "Supprimé",
|
||||||
"success.record.save": "Sauvegardé"
|
"success.record.save": "Sauvegardé"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,10 +5,11 @@ const {
|
|||||||
getApisKeys,
|
getApisKeys,
|
||||||
getApisUploadRelations,
|
getApisUploadRelations,
|
||||||
getEditDisplayAvailableFieldsPath,
|
getEditDisplayAvailableFieldsPath,
|
||||||
getEditDisplayFieldsPath
|
getEditDisplayFieldsPath,
|
||||||
} = require('./utils/getters');
|
} = require('./utils/getters');
|
||||||
const splitted = str => str.split('.');
|
const splitted = str => str.split('.');
|
||||||
const pickData = (model) => _.pick(model, [
|
const pickData = model =>
|
||||||
|
_.pick(model, [
|
||||||
'info',
|
'info',
|
||||||
'connection',
|
'connection',
|
||||||
'collectionName',
|
'collectionName',
|
||||||
@ -20,7 +21,7 @@ const pickData = (model) => _.pick(model, [
|
|||||||
'options',
|
'options',
|
||||||
'loadedModel',
|
'loadedModel',
|
||||||
'primaryKey',
|
'primaryKey',
|
||||||
'associations'
|
'associations',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
module.exports = async cb => {
|
module.exports = async cb => {
|
||||||
@ -28,7 +29,11 @@ module.exports = async cb => {
|
|||||||
const pluginsLayout = Object.keys(strapi.plugins).reduce((acc, current) => {
|
const pluginsLayout = Object.keys(strapi.plugins).reduce((acc, current) => {
|
||||||
const models = _.get(strapi.plugins, [current, 'config', 'layout'], {});
|
const models = _.get(strapi.plugins, [current, 'config', 'layout'], {});
|
||||||
Object.keys(models).forEach(model => {
|
Object.keys(models).forEach(model => {
|
||||||
const layout = _.get(strapi.plugins, [current, 'config', 'layout', model], {});
|
const layout = _.get(
|
||||||
|
strapi.plugins,
|
||||||
|
[current, 'config', 'layout', model],
|
||||||
|
{}
|
||||||
|
);
|
||||||
acc[model] = layout;
|
acc[model] = layout;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -69,13 +74,14 @@ module.exports = async cb => {
|
|||||||
models: {
|
models: {
|
||||||
plugins: {},
|
plugins: {},
|
||||||
},
|
},
|
||||||
layout: {}
|
layout: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Populate the schema object
|
// Populate the schema object
|
||||||
const buildSchema = (model, name, plugin = false) => {
|
const buildSchema = (model, name, plugin = false) => {
|
||||||
// Model data
|
// Model data
|
||||||
const schemaModel = Object.assign({
|
const schemaModel = Object.assign(
|
||||||
|
{
|
||||||
label: _.upperFirst(name),
|
label: _.upperFirst(name),
|
||||||
labelPlural: _.upperFirst(pluralize(name)),
|
labelPlural: _.upperFirst(pluralize(name)),
|
||||||
orm: model.orm || 'mongoose',
|
orm: model.orm || 'mongoose',
|
||||||
@ -92,13 +98,22 @@ module.exports = async cb => {
|
|||||||
fields: [],
|
fields: [],
|
||||||
relations: [],
|
relations: [],
|
||||||
},
|
},
|
||||||
}, model);
|
},
|
||||||
|
model
|
||||||
|
);
|
||||||
const fieldsToRemove = [];
|
const fieldsToRemove = [];
|
||||||
// Fields (non relation)
|
// Fields (non relation)
|
||||||
const fields = _.mapValues(_.pickBy(model.attributes, attribute =>
|
const fields = _.mapValues(
|
||||||
!attribute.model && !attribute.collection
|
_.pickBy(
|
||||||
), (value, attribute) => {
|
model.attributes,
|
||||||
const fieldClassName = _.get(tempLayout, [name, 'attributes', attribute, 'className'], '');
|
attribute => !attribute.model && !attribute.collection
|
||||||
|
),
|
||||||
|
(value, attribute) => {
|
||||||
|
const fieldClassName = _.get(
|
||||||
|
tempLayout,
|
||||||
|
[name, 'attributes', attribute, 'className'],
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
if (fieldClassName === 'd-none') {
|
if (fieldClassName === 'd-none') {
|
||||||
fieldsToRemove.push(attribute);
|
fieldsToRemove.push(attribute);
|
||||||
@ -110,7 +125,8 @@ module.exports = async cb => {
|
|||||||
type: value.type || 'string',
|
type: value.type || 'string',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Don't display fields that are hidden by default like the resetPasswordToken for the model user
|
// Don't display fields that are hidden by default like the resetPasswordToken for the model user
|
||||||
fieldsToRemove.forEach(field => {
|
fieldsToRemove.forEach(field => {
|
||||||
@ -128,7 +144,11 @@ module.exports = async cb => {
|
|||||||
const attrType = schemaModel.fields[attr].type;
|
const attrType = schemaModel.fields[attr].type;
|
||||||
const sortable = attrType !== 'json' && attrType !== 'array';
|
const sortable = attrType !== 'json' && attrType !== 'array';
|
||||||
|
|
||||||
return Object.assign(schemaModel.fields[attr], { name: attr, sortable, searchable: sortable });
|
return Object.assign(schemaModel.fields[attr], {
|
||||||
|
name: attr,
|
||||||
|
sortable,
|
||||||
|
searchable: sortable,
|
||||||
|
});
|
||||||
})
|
})
|
||||||
// Retrieve only the fourth first items
|
// Retrieve only the fourth first items
|
||||||
.slice(0, 4);
|
.slice(0, 4);
|
||||||
@ -143,13 +163,24 @@ module.exports = async cb => {
|
|||||||
|
|
||||||
// This object will be used to customise the label and description and so on of an input.
|
// This object will be used to customise the label and description and so on of an input.
|
||||||
// TODO: maybe add the customBootstrapClass in it;
|
// TODO: maybe add the customBootstrapClass in it;
|
||||||
schemaModel.editDisplay.availableFields = Object.keys(schemaModel.fields).reduce((acc, current) => {
|
schemaModel.editDisplay.availableFields = Object.keys(
|
||||||
|
schemaModel.fields
|
||||||
|
).reduce((acc, current) => {
|
||||||
acc[current] = Object.assign(
|
acc[current] = Object.assign(
|
||||||
_.pick(_.get(schemaModel, ['fields', current], {}), ['label', 'type', 'description', 'name']),
|
_.pick(_.get(schemaModel, ['fields', current], {}), [
|
||||||
|
'label',
|
||||||
|
'type',
|
||||||
|
'description',
|
||||||
|
'name',
|
||||||
|
]),
|
||||||
{
|
{
|
||||||
editable: ['updatedAt', 'createdAt', 'updated_at', 'created_at'].indexOf(current) === -1,
|
editable:
|
||||||
|
['updatedAt', 'createdAt', 'updated_at', 'created_at'].indexOf(
|
||||||
|
current
|
||||||
|
) === -1,
|
||||||
placeholder: '',
|
placeholder: '',
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
@ -158,12 +189,36 @@ module.exports = async cb => {
|
|||||||
// Model relations
|
// Model relations
|
||||||
schemaModel.relations = model.associations.reduce((acc, current) => {
|
schemaModel.relations = model.associations.reduce((acc, current) => {
|
||||||
const label = _.upperFirst(current.alias);
|
const label = _.upperFirst(current.alias);
|
||||||
const displayedAttribute = current.plugin ? // Value to modified to custom what's displayed in the react-select
|
const displayedAttribute = current.plugin // Value to modified to custom what's displayed in the react-select
|
||||||
_.get(pluginsModel, [current.plugin, 'models', current.model || current.collection, 'info', 'mainField']) ||
|
? _.get(pluginsModel, [
|
||||||
_.findKey(_.get(pluginsModel, [current.plugin, 'models', current.model || current.collection, 'attributes']), { type : 'string'}) ||
|
current.plugin,
|
||||||
'id' :
|
'models',
|
||||||
_.get(models, [current.model || current.collection, 'info', 'mainField']) ||
|
current.model || current.collection,
|
||||||
_.findKey(_.get(models, [current.model || current.collection, 'attributes']), { type : 'string'}) ||
|
'info',
|
||||||
|
'mainField',
|
||||||
|
]) ||
|
||||||
|
_.findKey(
|
||||||
|
_.get(pluginsModel, [
|
||||||
|
current.plugin,
|
||||||
|
'models',
|
||||||
|
current.model || current.collection,
|
||||||
|
'attributes',
|
||||||
|
]),
|
||||||
|
{ type: 'string' }
|
||||||
|
) ||
|
||||||
|
'id'
|
||||||
|
: _.get(models, [
|
||||||
|
current.model || current.collection,
|
||||||
|
'info',
|
||||||
|
'mainField',
|
||||||
|
]) ||
|
||||||
|
_.findKey(
|
||||||
|
_.get(models, [
|
||||||
|
current.model || current.collection,
|
||||||
|
'attributes',
|
||||||
|
]),
|
||||||
|
{ type: 'string' }
|
||||||
|
) ||
|
||||||
'id';
|
'id';
|
||||||
|
|
||||||
acc[current.alias] = {
|
acc[current.alias] = {
|
||||||
@ -175,15 +230,26 @@ module.exports = async cb => {
|
|||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
const relationsArray = Object.keys(schemaModel.relations).filter(relation => {
|
const relationsArray = Object.keys(schemaModel.relations).filter(
|
||||||
const isUploadRelation = _.get(schemaModel, ['relations', relation, 'plugin'], '') === 'upload';
|
relation => {
|
||||||
const isMorphSide = _.get(schemaModel, ['relations', relation, 'nature'], '').toLowerCase().includes('morp') && _.get(schemaModel, ['relations', relation, relation]) !== undefined;
|
const isUploadRelation =
|
||||||
|
_.get(schemaModel, ['relations', relation, 'plugin'], '') ===
|
||||||
|
'upload';
|
||||||
|
const isMorphSide =
|
||||||
|
_.get(schemaModel, ['relations', relation, 'nature'], '')
|
||||||
|
.toLowerCase()
|
||||||
|
.includes('morp') &&
|
||||||
|
_.get(schemaModel, ['relations', relation, relation]) !== undefined;
|
||||||
|
|
||||||
return !isUploadRelation && !isMorphSide;
|
return !isUploadRelation && !isMorphSide;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const uploadRelations = Object.keys(schemaModel.relations).reduce((acc, current) => {
|
const uploadRelations = Object.keys(schemaModel.relations).reduce(
|
||||||
if (_.get(schemaModel, ['relations', current, 'plugin']) === 'upload') {
|
(acc, current) => {
|
||||||
|
if (
|
||||||
|
_.get(schemaModel, ['relations', current, 'plugin']) === 'upload'
|
||||||
|
) {
|
||||||
const model = _.get(schemaModel, ['relations', current]);
|
const model = _.get(schemaModel, ['relations', current]);
|
||||||
|
|
||||||
acc[current] = {
|
acc[current] = {
|
||||||
@ -199,13 +265,20 @@ module.exports = async cb => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
schemaModel.editDisplay.availableFields = _.merge(schemaModel.editDisplay.availableFields, uploadRelations);
|
schemaModel.editDisplay.availableFields = _.merge(
|
||||||
|
schemaModel.editDisplay.availableFields,
|
||||||
|
uploadRelations
|
||||||
|
);
|
||||||
schemaModel.editDisplay.relations = relationsArray;
|
schemaModel.editDisplay.relations = relationsArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
schemaModel.editDisplay.fields = Object.keys(schemaModel.editDisplay.availableFields);
|
schemaModel.editDisplay.fields = Object.keys(
|
||||||
|
schemaModel.editDisplay.availableFields
|
||||||
|
);
|
||||||
|
|
||||||
if (plugin) {
|
if (plugin) {
|
||||||
return _.set(schema.models.plugins, `${plugin}.${name}`, schemaModel);
|
return _.set(schema.models.plugins, `${plugin}.${name}`, schemaModel);
|
||||||
@ -230,7 +303,7 @@ module.exports = async cb => {
|
|||||||
const pluginStore = strapi.store({
|
const pluginStore = strapi.store({
|
||||||
environment: '',
|
environment: '',
|
||||||
type: 'plugin',
|
type: 'plugin',
|
||||||
name: 'content-manager'
|
name: 'content-manager',
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -263,24 +336,42 @@ module.exports = async cb => {
|
|||||||
const schemaApis = getApis(schema.models);
|
const schemaApis = getApis(schema.models);
|
||||||
|
|
||||||
// Array of apis to add
|
// Array of apis to add
|
||||||
const apisToAdd = schemaApis.filter(api => prevSchemaApis.indexOf(api) === -1).map(splitted);
|
const apisToAdd = schemaApis
|
||||||
|
.filter(api => prevSchemaApis.indexOf(api) === -1)
|
||||||
|
.map(splitted);
|
||||||
// Array of apis to remove
|
// Array of apis to remove
|
||||||
const apisToRemove = prevSchemaApis.filter(api => schemaApis.indexOf(api) === -1).map(splitted);
|
const apisToRemove = prevSchemaApis
|
||||||
|
.filter(api => schemaApis.indexOf(api) === -1)
|
||||||
|
.map(splitted);
|
||||||
|
|
||||||
// Retrieve the same apis by name
|
// Retrieve the same apis by name
|
||||||
const sameApis = schemaApis.filter(api => prevSchemaApis.indexOf(api) !== -1).map(splitted);
|
const sameApis = schemaApis
|
||||||
|
.filter(api => prevSchemaApis.indexOf(api) !== -1)
|
||||||
|
.map(splitted);
|
||||||
// Retrieve all the field's path of the current unchanged api name
|
// Retrieve all the field's path of the current unchanged api name
|
||||||
const schemaSameApisKeys = _.flattenDeep(getApisKeys(schema, sameApis));
|
const schemaSameApisKeys = _.flattenDeep(getApisKeys(schema, sameApis));
|
||||||
// Retrieve all the field's path of the previous unchanged api name
|
// Retrieve all the field's path of the previous unchanged api name
|
||||||
const prevSchemaSameApisKeys = _.flattenDeep(getApisKeys(prevSchema, sameApis));
|
const prevSchemaSameApisKeys = _.flattenDeep(
|
||||||
|
getApisKeys(prevSchema, sameApis)
|
||||||
|
);
|
||||||
// Determine for the same api if we need to add some fields
|
// Determine for the same api if we need to add some fields
|
||||||
const sameApisAttrToAdd = schemaSameApisKeys.filter(attr => prevSchemaSameApisKeys.indexOf(attr) === -1).map(splitted);
|
const sameApisAttrToAdd = schemaSameApisKeys
|
||||||
|
.filter(attr => prevSchemaSameApisKeys.indexOf(attr) === -1)
|
||||||
|
.map(splitted);
|
||||||
// Special case for the relations
|
// Special case for the relations
|
||||||
const prevSchemaSameApisUploadRelations = _.flattenDeep(getApisUploadRelations(prevSchema, sameApis));
|
const prevSchemaSameApisUploadRelations = _.flattenDeep(
|
||||||
const schemaSameApisUploadRelations = _.flattenDeep(getApisUploadRelations(schema, sameApis));
|
getApisUploadRelations(prevSchema, sameApis)
|
||||||
const sameApisUploadRelationsToAdd = schemaSameApisUploadRelations.filter(attr => prevSchemaSameApisUploadRelations.indexOf(attr) === -1).map(splitted);
|
);
|
||||||
|
const schemaSameApisUploadRelations = _.flattenDeep(
|
||||||
|
getApisUploadRelations(schema, sameApis)
|
||||||
|
);
|
||||||
|
const sameApisUploadRelationsToAdd = schemaSameApisUploadRelations
|
||||||
|
.filter(attr => prevSchemaSameApisUploadRelations.indexOf(attr) === -1)
|
||||||
|
.map(splitted);
|
||||||
// Determine the fields to remove for the unchanged api name
|
// Determine the fields to remove for the unchanged api name
|
||||||
const sameApisAttrToRemove = prevSchemaSameApisKeys.filter(attr => schemaSameApisKeys.indexOf(attr) === -1).map(splitted);
|
const sameApisAttrToRemove = prevSchemaSameApisKeys
|
||||||
|
.filter(attr => schemaSameApisKeys.indexOf(attr) === -1)
|
||||||
|
.map(splitted);
|
||||||
|
|
||||||
// Remove api
|
// Remove api
|
||||||
apisToRemove.map(apiPath => {
|
apisToRemove.map(apiPath => {
|
||||||
@ -295,7 +386,8 @@ module.exports = async cb => {
|
|||||||
// Check default sort and change it if needed
|
// Check default sort and change it if needed
|
||||||
_.unset(prevSchema.models, attrPath);
|
_.unset(prevSchema.models, attrPath);
|
||||||
// Retrieve the api path in the schema Object
|
// Retrieve the api path in the schema Object
|
||||||
const apiPath = attrPath.length > 3 ? _.take(attrPath, 3) : _.take(attrPath, 1);
|
const apiPath =
|
||||||
|
attrPath.length > 3 ? _.take(attrPath, 3) : _.take(attrPath, 1);
|
||||||
// Retrieve the listDisplay path in the schema Object
|
// Retrieve the listDisplay path in the schema Object
|
||||||
const listDisplayPath = apiPath.concat('listDisplay');
|
const listDisplayPath = apiPath.concat('listDisplay');
|
||||||
const prevListDisplay = _.get(prevSchema.models, listDisplayPath);
|
const prevListDisplay = _.get(prevSchema.models, listDisplayPath);
|
||||||
@ -306,24 +398,36 @@ module.exports = async cb => {
|
|||||||
// If the user has deleted the default sort attribute in the content type builder
|
// If the user has deleted the default sort attribute in the content type builder
|
||||||
// Replace it by new generated one from the current schema
|
// Replace it by new generated one from the current schema
|
||||||
if (_.includes(currentAttr, defaultSort)) {
|
if (_.includes(currentAttr, defaultSort)) {
|
||||||
_.set(prevSchema.models, defaultSortPath, _.get(schema.models, defaultSortPath));
|
_.set(
|
||||||
|
prevSchema.models,
|
||||||
|
defaultSortPath,
|
||||||
|
_.get(schema.models, defaultSortPath)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the displayed fields
|
// Update the displayed fields
|
||||||
const updatedListDisplay = prevListDisplay.filter(obj => obj.name !== currentAttr.join());
|
const updatedListDisplay = prevListDisplay.filter(
|
||||||
|
obj => obj.name !== currentAttr.join()
|
||||||
|
);
|
||||||
|
|
||||||
// Retrieve the model's displayed fields for the `EditPage`
|
// Retrieve the model's displayed fields for the `EditPage`
|
||||||
const fieldsPath = getEditDisplayFieldsPath(attrPath);
|
const fieldsPath = getEditDisplayFieldsPath(attrPath);
|
||||||
// Retrieve the previous settings
|
// Retrieve the previous settings
|
||||||
const prevEditDisplayFields = _.get(prevSchema.models, fieldsPath);
|
const prevEditDisplayFields = _.get(prevSchema.models, fieldsPath);
|
||||||
// Update the fields
|
// Update the fields
|
||||||
const updatedEditDisplayFields = prevEditDisplayFields.filter(field => field !== currentAttr.join());
|
const updatedEditDisplayFields = prevEditDisplayFields.filter(
|
||||||
|
field => field !== currentAttr.join()
|
||||||
|
);
|
||||||
// Set the new layout
|
// Set the new layout
|
||||||
_.set(prevSchema.models, fieldsPath, updatedEditDisplayFields);
|
_.set(prevSchema.models, fieldsPath, updatedEditDisplayFields);
|
||||||
|
|
||||||
if (updatedListDisplay.length === 0) {
|
if (updatedListDisplay.length === 0) {
|
||||||
// Update it with the one from the generated schema
|
// Update it with the one from the generated schema
|
||||||
_.set(prevSchema.models, listDisplayPath, _.get(schema.models, listDisplayPath, []));
|
_.set(
|
||||||
|
prevSchema.models,
|
||||||
|
listDisplayPath,
|
||||||
|
_.get(schema.models, listDisplayPath, [])
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
_.set(prevSchema.models, listDisplayPath, updatedListDisplay);
|
_.set(prevSchema.models, listDisplayPath, updatedListDisplay);
|
||||||
}
|
}
|
||||||
@ -333,7 +437,10 @@ module.exports = async cb => {
|
|||||||
// Here we just need to add the data from the current schema Object
|
// Here we just need to add the data from the current schema Object
|
||||||
apisToAdd.map(apiPath => {
|
apisToAdd.map(apiPath => {
|
||||||
const api = _.get(schema.models, apiPath);
|
const api = _.get(schema.models, apiPath);
|
||||||
const { search, filters, bulkActions, pageEntries, options } = _.get(prevSchema, 'generalSettings');
|
const { search, filters, bulkActions, pageEntries, options } = _.get(
|
||||||
|
prevSchema,
|
||||||
|
'generalSettings'
|
||||||
|
);
|
||||||
|
|
||||||
_.set(api, 'options', options);
|
_.set(api, 'options', options);
|
||||||
_.set(api, 'filters', filters);
|
_.set(api, 'filters', filters);
|
||||||
@ -364,7 +471,13 @@ module.exports = async cb => {
|
|||||||
sameApis.forEach(apiPath => {
|
sameApis.forEach(apiPath => {
|
||||||
// This doesn't keep the prevSettings for the relations, the user will have to reset it.
|
// This doesn't keep the prevSettings for the relations, the user will have to reset it.
|
||||||
// We might have to improve this if we want the order of the relations to be kept
|
// We might have to improve this if we want the order of the relations to be kept
|
||||||
['relations', 'loadedModel', 'associations', 'attributes', ['editDisplay', 'relations']]
|
[
|
||||||
|
'relations',
|
||||||
|
'loadedModel',
|
||||||
|
'associations',
|
||||||
|
'attributes',
|
||||||
|
['editDisplay', 'relations'],
|
||||||
|
]
|
||||||
.map(key => apiPath.concat(key))
|
.map(key => apiPath.concat(key))
|
||||||
.forEach(keyPath => {
|
.forEach(keyPath => {
|
||||||
const newValue = _.get(schema.models, keyPath);
|
const newValue = _.get(schema.models, keyPath);
|
||||||
@ -384,16 +497,23 @@ module.exports = async cb => {
|
|||||||
_.set(prevSchema.models, fieldsPath, currentFields);
|
_.set(prevSchema.models, fieldsPath, currentFields);
|
||||||
});
|
});
|
||||||
|
|
||||||
schemaApis.map((model) => {
|
schemaApis.map(model => {
|
||||||
const isPlugin = model.includes('plugins.');
|
const isPlugin = model.includes('plugins.');
|
||||||
_.set(prevSchema.models[model], 'info', _.get(!isPlugin ? strapi.models[model] : strapi[model], 'info'));
|
_.set(
|
||||||
_.set(prevSchema.models[model], 'options', _.get(!isPlugin ? strapi.models[model] : strapi[model], 'options'));
|
prevSchema.models[model],
|
||||||
|
'info',
|
||||||
|
_.get(!isPlugin ? strapi.models[model] : strapi[model], 'info')
|
||||||
|
);
|
||||||
|
_.set(
|
||||||
|
prevSchema.models[model],
|
||||||
|
'options',
|
||||||
|
_.get(!isPlugin ? strapi.models[model] : strapi[model], 'options')
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
await pluginStore.set({ key: 'schema', value: prevSchema });
|
await pluginStore.set({ key: 'schema', value: prevSchema });
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('error', err);
|
console.log('error', err); // eslint-disable-line no-console
|
||||||
}
|
}
|
||||||
|
|
||||||
cb();
|
cb();
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* EditViewLink
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import NavLink from 'components/NavLink';
|
||||||
|
|
||||||
|
// Create link from content-type-builder to content-manager
|
||||||
|
function EditViewLink(props) {
|
||||||
|
// Retrieve URL from props
|
||||||
|
let url = `${props.getContentTypeBuilderBaseUrl()}${props.getModelName()}`;
|
||||||
|
|
||||||
|
// Add users-permissions to URL for permission, role and user content types
|
||||||
|
if (props.getSource() === 'users-permissions') {
|
||||||
|
url = `${url}&source=${props.getSource()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <NavLink {...props} url={url} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditViewLink.propTypes = {
|
||||||
|
getContentTypeBuilderBaseUrl: PropTypes.func.isRequired,
|
||||||
|
getModelName: PropTypes.func.isRequired,
|
||||||
|
getSource: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditViewLink;
|
@ -1,25 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* ContentManagerEditViewLink
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
|
|
||||||
function ContentManagerEditViewLink(props) {
|
|
||||||
let url = props.getContentTypeBuilderBaseUrl() + props.getModelName();
|
|
||||||
if (
|
|
||||||
props.getModelName() === 'user' ||
|
|
||||||
props.getModelName() === 'role' ||
|
|
||||||
props.getModelName() === 'permission'
|
|
||||||
) {
|
|
||||||
url = url + '&source=users-permissions';
|
|
||||||
}
|
|
||||||
|
|
||||||
return <Link to={url}>Edit the fields</Link>;
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentManagerEditViewLink.propTypes = {};
|
|
||||||
|
|
||||||
export default ContentManagerEditViewLink;
|
|
@ -1,10 +1,16 @@
|
|||||||
import Link from 'components/ContentManagerEditViewLink';
|
import Link from './InjectedComponents/ContentManager/EditViewLink';
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
plugin: 'content-manager.editPage',
|
plugin: 'content-manager.editPage',
|
||||||
area: 'left.links',
|
area: 'right.links',
|
||||||
component: Link,
|
component: Link,
|
||||||
key: 'content-type-builder.link'
|
key: 'content-type-builder.link',
|
||||||
}
|
props: {
|
||||||
|
message: {
|
||||||
|
id: 'content-manager.containers.Edit.Link.Fields',
|
||||||
|
},
|
||||||
|
icon: 'fa-cog',
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user