diff --git a/docs/3.x.x/en/advanced/customize-admin.md b/docs/3.x.x/en/advanced/customize-admin.md index a819fa90d5..efe380e7b4 100644 --- a/docs/3.x.x/en/advanced/customize-admin.md +++ b/docs/3.x.x/en/advanced/customize-admin.md @@ -62,6 +62,8 @@ The panel will be available through [http://localhost:1337/dashboard](http://loc ### Development mode +Note that to modify the administration panel, your project needs to be created with using the `dev` flag, an example of such would be: `strapi new strapi --dev`. + **#1 — Install its own dependencies** Run `npm install` from the `./admin` folder. @@ -99,14 +101,16 @@ Note: make sure the size of your image is the same as the existing one (434px x ## Build -To build the administration, run the following command from the `./admin` folder: +To build the administration, run the following command from the root directory of your project. ``` -npm run build +npm run setup ``` This will replace the folder's content located at `./admin/admin/build`. Visit http://localhost:1337/admin/ to make sure your updates have been taken in account. +After you have built the admininistration you can now create a new project to develop your API with the changes implemented. **Note:** You should now create a project without `--dev` + *** ## Deployment diff --git a/docs/3.x.x/en/cli/CLI.md b/docs/3.x.x/en/cli/CLI.md index daac90433d..9759038fef 100644 --- a/docs/3.x.x/en/cli/CLI.md +++ b/docs/3.x.x/en/cli/CLI.md @@ -11,7 +11,7 @@ Create a new project ```bash strapi new -options: [--dev|--dbclient= --dbhost= --dbport= --dbname= --dbusername= --dbpassword=] +options: [--dev|--dbclient= --dbhost= --dbport= --dbname= --dbusername= --dbpassword= --dbssl= --dbauth=] ``` - **strapi new <name>**
@@ -20,8 +20,8 @@ options: [--dev|--dbclient= --dbhost= --dbport= --dbna - **strapi new <name> --dev**
Generates a new project called **<name>** and creates symlinks for the `./admin` folder and each plugin inside the `./plugin` folder. It means that the Strapi's development workflow has been set up on the machine earlier. -- **strapi new <name> --dbclient=<dbclient> --dbhost=<dbhost> --dbport=<dbport> --dbname=<dbname> --dbusername=<dbusername> --dbpassword=<dbpassword>**
- Generates a new project called **<name>** and skip the interactive database configuration and initilize with these options. **<dbclient>** can be `mongo`, `postgres`, `mysql`, `sqlite3` or `redis`. **<dbusername>** and **<dbpassword>** are optional. +- **strapi new <name> --dbclient=<dbclient> --dbhost=<dbhost> --dbport=<dbport> --dbname=<dbname> --dbusername=<dbusername> --dbpassword=<dbpassword> --dbssl=<dbssl> --dbauth=<dbauth>**
+ Generates a new project called **<name>** and skip the interactive database configuration and initilize with these options. **<dbclient>** can be `mongo`, `postgres`, `mysql`, `sqlite3` or `redis`. **<dbssl>** and **<dbauth>** are optional. See the [CONTRIBUTING guide](https://github.com/strapi/strapi/blob/master/CONTRIBUTING.md) for more details. diff --git a/packages/strapi-admin/admin/src/components/LeftMenuLinkContainer/index.js b/packages/strapi-admin/admin/src/components/LeftMenuLinkContainer/index.js index 5ea571e596..ce156f2cbe 100755 --- a/packages/strapi-admin/admin/src/components/LeftMenuLinkContainer/index.js +++ b/packages/strapi-admin/admin/src/components/LeftMenuLinkContainer/index.js @@ -69,13 +69,17 @@ function LeftMenuLinkContainer({ layout, plugins }) { // Check if the plugins list is empty or not and display plugins by name const pluginsLinks = !isEmpty(pluginsObject) ? ( map(sortBy(pluginsObject, 'name'), plugin => { - if (plugin.id !== 'email' && plugin.id !== 'content-manager' && plugin.id !== 'settings-manager') { + if (plugin.id !== 'email' && plugin.id !== 'settings-manager') { + const basePath = `/plugins/${get(plugin, 'id')}`; + // NOTE: this should be dynamic + const destination = plugin.id === 'content-manager' ? `${basePath}/ctm-configurations` : basePath; + return ( ); } diff --git a/packages/strapi-admin/admin/src/components/ListPlugins/index.js b/packages/strapi-admin/admin/src/components/ListPlugins/index.js index 6a448a878a..64a6ead46d 100644 --- a/packages/strapi-admin/admin/src/components/ListPlugins/index.js +++ b/packages/strapi-admin/admin/src/components/ListPlugins/index.js @@ -16,7 +16,7 @@ import Row from 'components/Row'; import styles from './styles.scss'; -class ListPlugins extends React.Component { +class ListPlugins extends React.PureComponent { render() { const listSize = size(this.props.plugins); let titleType = listSize === 1 ? 'singular' : 'plural'; diff --git a/packages/strapi-admin/admin/src/components/Row/index.js b/packages/strapi-admin/admin/src/components/Row/index.js index 8ad6128e6c..47b5ef279b 100644 --- a/packages/strapi-admin/admin/src/components/Row/index.js +++ b/packages/strapi-admin/admin/src/components/Row/index.js @@ -8,7 +8,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import cn from 'classnames'; import { FormattedMessage } from 'react-intl'; -import { isEmpty } from 'lodash'; +import { includes, isEmpty } from 'lodash'; // Design import IcoContainer from 'components/IcoContainer'; @@ -17,6 +17,8 @@ import PopUpWarning from 'components/PopUpWarning'; import styles from './styles.scss'; +const PLUGINS_WITH_CONFIG = ['content-manager', 'email', 'upload']; + class Row extends React.Component { state = { showModal: false }; @@ -33,8 +35,10 @@ class Row extends React.Component { render() { // const uploadPath = `/plugins/upload/configurations/${this.context.currentEnvironment}`; - const settingsPath = `/plugins/${this.props.name}/configurations/${this.context.currentEnvironment}`; - const icons = this.props.name === 'upload' || this.props.name === 'email' ? [ + // Make sure to match the ctm config URI instead of content-type view URI + const settingsPath = this.props.name === 'content-manager' ? '/plugins/content-manager/ctm-configurations' : `/plugins/${this.props.name}/configurations/${this.context.currentEnvironment}`; + // const icons = this.props.name === 'upload' || this.props.name === 'email' ? [ + const icons = includes(PLUGINS_WITH_CONFIG, this.props.name) ? [ { icoType: 'cog', onClick: (e) => { diff --git a/packages/strapi-admin/admin/src/containers/LeftMenu/index.js b/packages/strapi-admin/admin/src/containers/LeftMenu/index.js index ba940f7f3d..3303b61d6a 100755 --- a/packages/strapi-admin/admin/src/containers/LeftMenu/index.js +++ b/packages/strapi-admin/admin/src/containers/LeftMenu/index.js @@ -14,16 +14,14 @@ import LeftMenuFooter from 'components/LeftMenuFooter'; import styles from './styles.scss'; -export class LeftMenu extends React.Component { // eslint-disable-line react/prefer-stateless-function - render() { - return ( -
- - - -
- ); - } +function LeftMenu(props) { + return ( +
+ + + +
+ ); } LeftMenu.defaultProps = { diff --git a/packages/strapi-generate-new/lib/before.js b/packages/strapi-generate-new/lib/before.js index b22f2edca6..799af0fc31 100755 --- a/packages/strapi-generate-new/lib/before.js +++ b/packages/strapi-generate-new/lib/before.js @@ -192,7 +192,7 @@ module.exports = (scope, cb) => { ]) .then(answers => { if (hasDatabaseConfig) { - answers = _.omit(scope.database.settings, ['client']); + answers = _.merge((_.omit(scope.database.settings, ['client'])), scope.database.options); } scope.database.settings.host = answers.host; diff --git a/packages/strapi-helper-plugin/lib/src/components/InputToggle/styles.scss b/packages/strapi-helper-plugin/lib/src/components/InputToggle/styles.scss index 15586f9ca7..8c257908a4 100644 --- a/packages/strapi-helper-plugin/lib/src/components/InputToggle/styles.scss +++ b/packages/strapi-helper-plugin/lib/src/components/InputToggle/styles.scss @@ -1,13 +1,25 @@ .gradientOff { background-image: linear-gradient( to bottom right, #F65A1D, #F68E0E ); color: white !important; - box-shadow: inset -1px 1px 3px rgba(0,0,0,0.1); + z-index: 0!important; + + &:active, :hover { + box-shadow: inset -1px 1px 3px rgba(0,0,0,0.1); + background-image: linear-gradient( to bottom right, #F65A1D, #F68E0E ); + color: white !important; + z-index: 0!important; + } } .gradientOn { background-image: linear-gradient( to bottom right, #005EEA, #0097F6); color: white !important; box-shadow: inset 1px 1px 3px rgba(0,0,0,0.1); + &:active, :hover { + background-image: linear-gradient( to bottom right, #005EEA, #0097F6); + color: white !important; + z-index: 0!important; + } } .inputToggleContainer { diff --git a/packages/strapi-helper-plugin/lib/src/components/InputsIndex/index.js b/packages/strapi-helper-plugin/lib/src/components/InputsIndex/index.js index ef8e995a99..8e7cfdf2c6 100644 --- a/packages/strapi-helper-plugin/lib/src/components/InputsIndex/index.js +++ b/packages/strapi-helper-plugin/lib/src/components/InputsIndex/index.js @@ -21,8 +21,6 @@ import InputPasswordWithErrors from 'components/InputPasswordWithErrors'; import InputTextAreaWithErrors from 'components/InputTextAreaWithErrors'; import InputTextWithErrors from 'components/InputTextWithErrors'; import InputToggleWithErrors from 'components/InputToggleWithErrors'; -import WysiwygWithErrors from 'components/WysiwygWithErrors'; -import InputJSONWithErrors from 'components/InputJSONWithErrors'; const DefaultInputError = ({ type }) =>
Your input type: {type} does not exist
; @@ -32,7 +30,6 @@ const inputs = { date: InputDateWithErrors, email: InputEmailWithErrors, file: InputFileWithErrors, - json: InputJSONWithErrors, number: InputNumberWithErrors, password: InputPasswordWithErrors, search: InputSearchWithErrors, @@ -41,7 +38,6 @@ const inputs = { text: InputTextWithErrors, textarea: InputTextAreaWithErrors, toggle: InputToggleWithErrors, - wysiwyg: WysiwygWithErrors, }; function InputsIndex(props) { diff --git a/packages/strapi-helper-plugin/lib/src/components/PopUpWarning/styles.scss b/packages/strapi-helper-plugin/lib/src/components/PopUpWarning/styles.scss index c573bda639..4616bcf0b8 100644 --- a/packages/strapi-helper-plugin/lib/src/components/PopUpWarning/styles.scss +++ b/packages/strapi-helper-plugin/lib/src/components/PopUpWarning/styles.scss @@ -48,6 +48,7 @@ } .modalPosition { + max-width: 37.5rem !important; > div { width: 37.5rem; padding: 0 !important; diff --git a/packages/strapi-helper-plugin/package.json b/packages/strapi-helper-plugin/package.json index cebaccf82e..9b759b157d 100755 --- a/packages/strapi-helper-plugin/package.json +++ b/packages/strapi-helper-plugin/package.json @@ -48,11 +48,9 @@ "bootstrap": "^4.0.0-alpha.6", "chalk": "^2.1.0", "classnames": "^2.2.5", - "codemirror": "^5.38.0", "copy-webpack-plugin": "^4.3.1", "cross-env": "^5.0.5", "css-loader": "^0.28.5", - "draft-js": "^0.10.5", "eslint": "4.4.1", "eslint-config-airbnb": "15.1.0", "eslint-config-airbnb-base": "11.3.1", @@ -108,7 +106,6 @@ "rimraf": "^2.6.1", "sass-loader": "^6.0.6", "shelljs": "^0.7.8", - "showdown": "^1.8.6", "style-loader": "^0.18.2", "styled-components": "^3.2.6", "url-loader": "^0.5.9", diff --git a/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_barred.svg b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_barred.svg new file mode 100755 index 0000000000..2f3c7b9111 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_barred.svg @@ -0,0 +1 @@ +abc \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_bold.svg b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_bold.svg new file mode 100755 index 0000000000..cee3cf4011 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_bold.svg @@ -0,0 +1 @@ +B \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_bullet-list.svg b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_bullet-list.svg new file mode 100755 index 0000000000..6e060c39f5 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_bullet-list.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_code-block.svg b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_code-block.svg new file mode 100755 index 0000000000..a47ca10058 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_code-block.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_italic.svg b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_italic.svg new file mode 100755 index 0000000000..6181979e31 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_italic.svg @@ -0,0 +1 @@ +I \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_link.svg b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_link.svg new file mode 100755 index 0000000000..53b6125367 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_media.svg b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_media.svg new file mode 100755 index 0000000000..d7401730c7 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_media.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_numbered-list.svg b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_numbered-list.svg new file mode 100755 index 0000000000..79c8091f86 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_numbered-list.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_quote-block.svg b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_quote-block.svg new file mode 100755 index 0000000000..62a7990e92 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_quote-block.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_underline.svg b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_underline.svg new file mode 100755 index 0000000000..7a9b8da4e1 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/assets/icons/icon_underline.svg @@ -0,0 +1 @@ +U \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/admin/src/assets/images/icon-cross-blue.svg b/packages/strapi-plugin-content-manager/admin/src/assets/images/icon-cross-blue.svg index 58f0a5d8c7..2c77b183ae 100644 --- a/packages/strapi-plugin-content-manager/admin/src/assets/images/icon-cross-blue.svg +++ b/packages/strapi-plugin-content-manager/admin/src/assets/images/icon-cross-blue.svg @@ -1,18 +1 @@ - - - - Shape - Created with Sketch. - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/admin/src/assets/images/icon-cross.svg b/packages/strapi-plugin-content-manager/admin/src/assets/images/icon-cross.svg index aa113a980d..d627d9bdac 100644 --- a/packages/strapi-plugin-content-manager/admin/src/assets/images/icon-cross.svg +++ b/packages/strapi-plugin-content-manager/admin/src/assets/images/icon-cross.svg @@ -1,14 +1 @@ - - - - Shape - Created with Sketch. - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/admin/src/assets/images/icon-edit-blue.svg b/packages/strapi-plugin-content-manager/admin/src/assets/images/icon-edit-blue.svg new file mode 100644 index 0000000000..0da67b8b3b --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/assets/images/icon-edit-blue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/admin/src/bootstrap.js b/packages/strapi-plugin-content-manager/admin/src/bootstrap.js index dd8585d266..524be693df 100644 --- a/packages/strapi-plugin-content-manager/admin/src/bootstrap.js +++ b/packages/strapi-plugin-content-manager/admin/src/bootstrap.js @@ -1,13 +1,24 @@ -import { generateMenu } from 'containers/App/sagas'; +import { map, omit } from 'lodash'; +import request from 'utils/request'; // This method is executed before the load of the plugin const bootstrap = (plugin) => new Promise((resolve, reject) => { - generateMenu() - .then(menu => { + request('/content-manager/models', { method: 'GET' }) + .then(models => { + const menu = [{ + name: 'Content Types', + links: map(omit(models.models.models, 'plugins'), (model, key) => ({ + label: model.labelPlural || model.label || key, + destination: key, + })), + }]; plugin.leftMenuSections = menu; resolve(plugin); }) - .catch(e => reject(e)); + .catch(e => { + strapi.notification.error('content-manager.error.model.fetch'); + reject(e); + }); }); export default bootstrap; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/Block/index.js b/packages/strapi-plugin-content-manager/admin/src/components/Block/index.js new file mode 100644 index 0000000000..042ede09d0 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/components/Block/index.js @@ -0,0 +1,39 @@ +/** + * + * Block + */ + +import React from 'react'; +import PropTypes from 'prop-types'; +import { FormattedMessage } from 'react-intl'; + +import styles from './styles.scss'; + +const Block = ({ children, description, title }) => ( +
+
+
+ + + {msg =>

{msg}

} +
+
+ {children} +
+
+); + + +Block.defaultProps = { + children: null, + description: 'app.utils.defaultMessage', + title: 'app.utils.defaultMessage', +}; + +Block.propTypes = { + children: PropTypes.any, + description: PropTypes.string, + title: PropTypes.string, +}; + +export default Block; \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/admin/src/components/Block/styles.scss b/packages/strapi-plugin-content-manager/admin/src/components/Block/styles.scss new file mode 100644 index 0000000000..a37d677fea --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/components/Block/styles.scss @@ -0,0 +1,22 @@ +.ctmBlock{ + margin-bottom: 35px; + background: #ffffff; + padding: 22px 28px 18px; + border-radius: 2px; + box-shadow: 0 2px 4px #E3E9F3; + -webkit-font-smoothing: antialiased; +} + +.ctmBlockTitle { + padding-top: 0px; + line-height: 18px; + > span { + font-weight: 600; + color: #333740; + font-size: 18px; + } + > p { + color: #787E8F; + font-size: 13px; + } +} \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/admin/src/components/DraggableAttr/index.js b/packages/strapi-plugin-content-manager/admin/src/components/DraggableAttr/index.js new file mode 100644 index 0000000000..c9cd5ded9a --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/components/DraggableAttr/index.js @@ -0,0 +1,185 @@ +/** + * + * DraggableAttr + */ + +/* eslint-disable react/no-find-dom-node */ +import React from 'react'; +import { findDOMNode } from 'react-dom'; +import { + DragSource, + DropTarget, +} from 'react-dnd'; +import { flow, upperFirst } from 'lodash'; +import PropTypes from 'prop-types'; +import { FormattedMessage } from 'react-intl'; +import cn from 'classnames'; + +import styles from './styles.scss'; + +const draggableAttrSource = { + beginDrag: (props) => { + props.updateSiblingHoverState(); + + return { + id: props.id, + index: props.index, + }; + }, + endDrag: (props) => { + props.updateSiblingHoverState(); + + return {}; + }, +}; + +const draggableAttrTarget = { + hover: (props, monitor, component) => { + const dragIndex = monitor.getItem().index; + const hoverIndex = props.index; + + // Don't replace items with themselves + if (dragIndex === hoverIndex) { + return; + } + + // Determine rectangle on screen + const hoverBoundingRect = findDOMNode(component).getBoundingClientRect(); + + // Get vertical middle + const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; + + // Determine mouse position + const clientOffset = monitor.getClientOffset(); + + // Get pixels to the top + const hoverClientY = clientOffset.y - hoverBoundingRect.top; + + // Only perform the move when the mouse has crossed half of the items height + // When dragging downwards, only move when the cursor is below 50% + // When dragging upwards, only move when the cursor is above 50% + + // Dragging downwards + if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { + return; + } + + // Dragging upwards + if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { + return; + } + + // Time to actually perform the action + props.moveAttr(dragIndex, hoverIndex, props.keys); + + // Note: we're mutating the monitor item here! + // Generally it's better to avoid mutations, + // but it's good here for the sake of performance + // to avoid expensive index searches. + monitor.getItem().index = hoverIndex; + }, +}; + +class DraggableAttr extends React.Component { + state = { isOver: false, dragStart: false }; + + componentDidUpdate(prevProps) { + const { isDraggingSibling } = this.props; + + if (isDraggingSibling !== prevProps.isDraggingSibling && isDraggingSibling) { + this.handleMouseLeave(); + } + } + + handleClickEdit = (e) => { + e.preventDefault(); + e.stopPropagation(); + this.props.onClickEditListItem(this.props.index); + } + + handleMouseEnter = () => { + if (!this.props.isDraggingSibling) { + this.setState({ isOver: true }); + } + }; + + handleMouseLeave = () => this.setState({ isOver: false }); + + handleRemove = (e) => { + e.preventDefault(); + e.stopPropagation(); + this.props.onRemove(this.props.index, this.props.keys); + } + + render() { + const { label, name, isDragging, isEditing, connectDragSource, connectDropTarget } = this.props; + const { isOver, dragStart } = this.state; + const opacity = isDragging ? 0.2 : 1; + const overClass = isOver ? styles.draggableAttrOvered : ''; + const className = dragStart ? styles.dragged : styles.draggableAttr; + + return ( + connectDragSource( + connectDropTarget( +
this.setState({ dragStart: true })} + onDragEnd={() => this.setState({ dragStart: false })} + onMouseEnter={this.handleMouseEnter} + onMouseLeave={this.handleMouseLeave} + onClick={this.handleClickEdit} + style={{ opacity }} + > +