diff --git a/packages/strapi-admin/admin/src/components/LeftMenuLink/index.js b/packages/strapi-admin/admin/src/components/LeftMenuLink/index.js index 61a0caf3fb..8f058a8af8 100755 --- a/packages/strapi-admin/admin/src/components/LeftMenuLink/index.js +++ b/packages/strapi-admin/admin/src/components/LeftMenuLink/index.js @@ -24,7 +24,7 @@ class LeftMenuLink extends React.Component { // eslint-disable-line react/prefer className={`${styles.link} ${isLinkActive ? styles.linkActive : ''}`} to={{ pathname: this.props.destination, - search: `?source=${this.props.source}`, + search: `${this.props.source ? '?source=' : ''}${this.props.source}`, }} > diff --git a/packages/strapi-admin/admin/src/containers/AdminPage/index.js b/packages/strapi-admin/admin/src/containers/AdminPage/index.js index 25ff200ef8..ed6580fe52 100644 --- a/packages/strapi-admin/admin/src/containers/AdminPage/index.js +++ b/packages/strapi-admin/admin/src/containers/AdminPage/index.js @@ -25,6 +25,7 @@ import ComingSoonPage from 'containers/ComingSoonPage'; import Content from 'containers/Content'; import Header from 'components/Header/index'; import HomePage from 'containers/HomePage'; +import InstallPluginPage from 'containers/InstallPluginPage'; import LeftMenu from 'containers/LeftMenu'; import ListPluginsPage from 'containers/ListPluginsPage'; import Logout from 'components/Logout'; @@ -111,7 +112,7 @@ export class AdminPage extends React.Component { // eslint-disable-line react/pr - + diff --git a/packages/strapi-admin/admin/src/containers/InstallPluginPage/actions.js b/packages/strapi-admin/admin/src/containers/InstallPluginPage/actions.js new file mode 100644 index 0000000000..3f685b0b3c --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/InstallPluginPage/actions.js @@ -0,0 +1,32 @@ +/* + * + * InstallPluginPage actions + * + */ + +import { + GET_PLUGINS, + GET_PLUGINS_SUCCEEDED, + ON_CHANGE, +} from './constants'; + +export function getPlugins() { + return { + type: GET_PLUGINS, + }; +} + +export function getPluginsSucceeded(availablePlugins) { + return { + type: GET_PLUGINS_SUCCEEDED, + availablePlugins, + }; +} + +export function onChange({ target }) { + return { + type: ON_CHANGE, + keys: target.name.split('.'), + value: target.value, + }; +} diff --git a/packages/strapi-admin/admin/src/containers/InstallPluginPage/constants.js b/packages/strapi-admin/admin/src/containers/InstallPluginPage/constants.js new file mode 100644 index 0000000000..00464a25a7 --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/InstallPluginPage/constants.js @@ -0,0 +1,9 @@ +/* + * + * InstallPluginPage constants + * + */ + +export const GET_PLUGINS = 'StrapiAdmin/InstallPluginPage/GET_PLUGINS'; +export const GET_PLUGINS_SUCCEEDED = 'StrapiAdmin/InstallPluginPage/GET_PLUGINS_SUCCEEDED'; +export const ON_CHANGE = 'StrapiAdmin/InstallPluginPage/ON_CHANGE'; diff --git a/packages/strapi-admin/admin/src/containers/InstallPluginPage/fakeData.json b/packages/strapi-admin/admin/src/containers/InstallPluginPage/fakeData.json new file mode 100644 index 0000000000..d72dd586c9 --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/InstallPluginPage/fakeData.json @@ -0,0 +1,32 @@ +{ + "availablePlugins": [ + { + "description": "content-manager.plugin.description", + "id": "content-manager", + "icon": "plug", + "name": "Content Manager", + "price": 0 + }, + { + "description": "content-type-builder.plugin.description", + "id": "content-type-builder", + "icon": "brush", + "name": "content type builder", + "price": 0 + }, + { + "description": "settings-manager.plugin.description", + "id": "settings-manager", + "icon": "wrench", + "name": "settings manager", + "price": 0 + }, + { + "description": "users-permissions.plugin.description", + "id": "users-permissions", + "icon": "users", + "name": "Auth & Permissions", + "price": 0 + } + ] +} diff --git a/packages/strapi-admin/admin/src/containers/InstallPluginPage/index.js b/packages/strapi-admin/admin/src/containers/InstallPluginPage/index.js new file mode 100644 index 0000000000..f6b217b7b6 --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/InstallPluginPage/index.js @@ -0,0 +1,115 @@ +/** + * + * InstallPluginPage + * + */ + +import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { Helmet } from 'react-helmet'; +import { FormattedMessage } from 'react-intl'; +import { bindActionCreators, compose } from 'redux'; +import cn from 'classnames'; + +// Design +import Input from 'components/Input'; +import PluginHeader from 'components/PluginHeader'; + +import injectSaga from 'utils/injectSaga'; +import injectReducer from 'utils/injectReducer'; + +import { + getPlugins, + onChange, +} from './actions'; + +import makeSelectInstallPluginPage from './selectors'; +import reducer from './reducer'; +import saga from './saga'; + +import styles from './styles.scss'; + +export class InstallPluginPage extends React.Component { // eslint-disable-line react/prefer-stateless-function + componentDidMount() { + // Don't fetch the available plugins if it has already been done + if (!this.props.didFetchPlugins) { + this.props.getPlugins(); + } + } + + render() { + return ( +
+ + {message => ( + + {message} + + + )} + +
+ +
+ +
+
+
+ ); + } +} + +InstallPluginPage.contextTypes = { + plugins: PropTypes.object.isRequired, +}; + +InstallPluginPage.propTypes = { + didFetchPlugins: PropTypes.bool.isRequired, + getPlugins: PropTypes.func.isRequired, + onChange: PropTypes.func.isRequired, + search: PropTypes.string.isRequired, +}; + +const mapStateToProps = makeSelectInstallPluginPage(); + +function mapDispatchToProps(dispatch) { + return bindActionCreators( + { + getPlugins, + onChange, + }, + dispatch, + ); +} + +const withConnect = connect(mapStateToProps, mapDispatchToProps); + +/* Remove this line if the container doesn't have a route and +* check the documentation to see how to create the container's store +*/ +const withReducer = injectReducer({ key: 'installPluginPage', reducer }); + +/* Remove the line below the container doesn't have a route and +* check the documentation to see how to create the container's store +*/ +const withSaga = injectSaga({ key: 'installPluginPage', saga }); + +export default compose( + withReducer, + withSaga, + withConnect, +)(InstallPluginPage); diff --git a/packages/strapi-admin/admin/src/containers/InstallPluginPage/reducer.js b/packages/strapi-admin/admin/src/containers/InstallPluginPage/reducer.js new file mode 100644 index 0000000000..4d7b188139 --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/InstallPluginPage/reducer.js @@ -0,0 +1,32 @@ +/* + * + * InstallPluginPage reducer + * + */ + +import { fromJS, List } from 'immutable'; +import { + GET_PLUGINS_SUCCEEDED, + ON_CHANGE, +} from './constants'; + +const initialState = fromJS({ + availablePlugins: List([]), + didFetchPlugins: false, + search: '', +}); + +function installPluginPageReducer(state = initialState, action) { + switch (action.type) { + case GET_PLUGINS_SUCCEEDED: + return state + .set('didFetchPlugins', true) + .set('plugins', List(action.availablePlugins)); + case ON_CHANGE: + return state.updateIn(action.keys, () => action.value); + default: + return state; + } +} + +export default installPluginPageReducer; diff --git a/packages/strapi-admin/admin/src/containers/InstallPluginPage/saga.js b/packages/strapi-admin/admin/src/containers/InstallPluginPage/saga.js new file mode 100644 index 0000000000..3120c27c9a --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/InstallPluginPage/saga.js @@ -0,0 +1,44 @@ +import { LOCATION_CHANGE } from 'react-router-redux'; +import { + // call, + cancel, + fork, + put, + // select, + take, + takeLatest, +} from 'redux-saga/effects'; + +// import request from 'utils/request'; +import fakeData from './fakeData.json'; + +import { getPluginsSucceeded } from './actions'; +import { GET_PLUGINS } from './constants'; + +export function* pluginsGet() { + try { + const availablePlugins = fakeData.availablePlugins; + const supportUs = { + description: 'app.components.InstallPluginPage.plugin.support-us.description', + id: 'support-us', + icon: '', + name: 'buy a t-shirt', + price: 30, + }; + + yield put(getPluginsSucceeded(availablePlugins.concat([supportUs]))); + } catch(err) { + strapi.notification.error('notification.error'); + } +} + + + +// Individual exports for testing +export default function* defaultSaga() { + const loadPluginsWatcher = yield fork(takeLatest, GET_PLUGINS, pluginsGet); + + yield take(LOCATION_CHANGE); + + yield cancel(loadPluginsWatcher); +} diff --git a/packages/strapi-admin/admin/src/containers/InstallPluginPage/selectors.js b/packages/strapi-admin/admin/src/containers/InstallPluginPage/selectors.js new file mode 100644 index 0000000000..ee9f8fbdae --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/InstallPluginPage/selectors.js @@ -0,0 +1,25 @@ +import { createSelector } from 'reselect'; + +/** + * Direct selector to the installPluginPage state domain + */ +const selectInstallPluginPageDomain = () => (state) => state.get('installPluginPage'); + +/** + * Other specific selectors + */ + + +/** + * Default selector used by InstallPluginPage + */ + +const makeSelectInstallPluginPage = () => createSelector( + selectInstallPluginPageDomain(), + (substate) => substate.toJS() +); + +export default makeSelectInstallPluginPage; +export { + selectInstallPluginPageDomain, +}; diff --git a/packages/strapi-admin/admin/src/containers/InstallPluginPage/styles.scss b/packages/strapi-admin/admin/src/containers/InstallPluginPage/styles.scss new file mode 100644 index 0000000000..65508e7681 --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/InstallPluginPage/styles.scss @@ -0,0 +1,6 @@ +.containerFluid { + padding: 18px 30px !important; + > div:first-child { + max-height: 33px; + } +} diff --git a/packages/strapi-admin/admin/src/translations/en.json b/packages/strapi-admin/admin/src/translations/en.json index 9052732cb8..89edc43eb2 100755 --- a/packages/strapi-admin/admin/src/translations/en.json +++ b/packages/strapi-admin/admin/src/translations/en.json @@ -1,11 +1,20 @@ { "app.components.ComingSoonPage.comingSoon": "Coming soon", "app.components.ComingSoonPage.featuresNotAvailable": "This feature is still under active development.", + "app.components.HomePage.welcome": "Welcome on board!", "app.components.HomePage.description.part1": "We are happy to have you as one of our users!", "app.components.HomePage.description.part2": "You are now a member of our community which will help you building your dreamed app.", "app.components.HomePage.button": "Create your first content type", "app.components.HomePage.feedback": "Feel free to ask questions or give us feedback by using one of the support channels below.", + + "app.components.InstallPluginPage.helmet": "Install plugins", + "app.components.InstallPluginPage.title": "Install new plugins", + "app.components.InstallPluginPage.description": "Extend your app with no efforts", + "app.components.InstallPluginPage.plugin.support-us.description": "Support us by buying the Strapi t-shirt. It will allow us to keep working on the project and try giving the best possible experience!", + "app.components.InstallPluginPage.InputSearch.label": " ", + "app.components.InstallPluginPage.InputSearch.placeholder": "Search a plugin... (ex: authentication)", + "app.components.LeftMenuFooter.poweredBy": "Proudly powered by", "app.components.LeftMenuLinkContainer.configuration": "Configuration", "app.components.LeftMenuLinkContainer.general": "General", @@ -13,8 +22,10 @@ "app.components.LeftMenuLinkContainer.listPlugins": "List plugins", "app.components.LeftMenuLinkContainer.noPluginsInstalled": "No plugins installed yet", "app.components.LeftMenuLinkContainer.plugins": "Plugins", + "app.components.NotFoundPage.description": "Not Found", "app.components.NotFoundPage.back": "Back to homepage", + "app.components.ListPluginsPage.helmet.title": "List plugins", "app.components.ListPluginsPage.title": "Plugins", "app.components.ListPluginsPage.description": "List of the installed plugins in the project.", @@ -23,14 +34,20 @@ "app.components.listPlugins.title.plural": "{number} plugins are installed", "app.components.listPlugins.title.none": "No plugin is installed", "app.components.listPlugins.button": "Add New Plugin", + "components.AutoReloadBlocker.header": "Reload feature is required for this plugin.", "components.AutoReloadBlocker.description": "Open the following file and enable the feature.", + + "components.ErrorBoundary.title": "Something wen't wrong...", + "components.ProductionBlocker.header": "This plugin is only available in development.", "components.ProductionBlocker.description": "For safety we have to disable this plugin in other environments.", + "components.popUpWarning.button.cancel": "Cancel", "components.popUpWarning.button.confirm": "Confirm", "components.popUpWarning.title": "Please confirm", "components.popUpWarning.message": "Are you sure you want to delete this?", + "components.Input.error.validation.email": "This is not an email", "components.Input.error.validation.required": "This value input is required.", "components.Input.error.validation.regex": "The value not match the regex.", @@ -43,8 +60,11 @@ "components.Input.error.attribute.key.taken": "This value already exists", "components.Input.error.attribute.sameKeyAndName": "Can't be equals", "components.Input.error.validation.minSupMax": "Can't be superior", - "components.ErrorBoundary.title": "Something wen't wrong...", + "components.ListRow.empty": "There is no data to be shown.", + + "notification.error": "An error occurred", + "Auth & Permissions": "Auth & Permissions", "Content Manager": "Content Manager", "Content Type Builder": "Content Type Builder", diff --git a/packages/strapi-admin/admin/src/translations/fr.json b/packages/strapi-admin/admin/src/translations/fr.json index 9c1c9492ee..57375581c8 100755 --- a/packages/strapi-admin/admin/src/translations/fr.json +++ b/packages/strapi-admin/admin/src/translations/fr.json @@ -1,11 +1,21 @@ { "app.components.ComingSoonPage.comingSoon": "Bientôt disponible", "app.components.ComingSoonPage.featuresNotAvailable": "Cette fonctionnalité est toujours en cours de développement.", + + "app.components.HomePage.welcome": "Bienvenue à bord!", "app.components.HomePage.description.part1": "Nous somme heureux de vous compter parmi nos utilisateurs", "app.components.HomePage.description.part2": "Vous faites désormais parti de notre communauté qui peut vous aider à développer votre application.", "app.components.HomePage.button": "Créez votre premier type de contenu", "app.components.HomePage.feedback": "N'hésitez pas à utiliser un des channels ci-dessous pour poser vos questions ou nous donner vos retours.", + + "app.components.InstallPluginPage.helmet": "Installez des plugins", + "app.components.InstallPluginPage.title": "Installez des nouveaux plugins", + "app.components.InstallPluginPage.description": "Améliorez votre app sans efforts", + "app.components.InstallPluginPage.plugin.support-us.description": "Soutenez-nous en achetant un Strapi tee shirt. Cela nous aidera a continuer de travailler sur le projet pour vous donner la meilleure expérience possible!", + "app.components.InstallPluginPage.InputSearch.label": " ", + "app.components.InstallPluginPage.InputSearch.placeholder": "Recherchez un plugin... (ex: authentification)", + "app.components.LeftMenuFooter.poweredBy": "Propulsé par", "app.components.LeftMenuLinkContainer.configuration": "Configuration", "app.components.LeftMenuLinkContainer.general": "Général", @@ -13,8 +23,10 @@ "app.components.LeftMenuLinkContainer.listPlugins": "Liste des plugins", "app.components.LeftMenuLinkContainer.noPluginsInstalled": "Aucun plugin installé", "app.components.LeftMenuLinkContainer.plugins": "Plugins", + "app.components.NotFoundPage.description": "Page introuvable", "app.components.NotFoundPage.back": "Retourner à la page d'accueil", + "app.components.ListPluginsPage.helmet.title": "List plugins", "app.components.ListPluginsPage.title": "Plugins", "app.components.ListPluginsPage.description": "Liste des plugins installés dans le projet.", @@ -23,14 +35,20 @@ "app.components.listPlugins.title.plural": "{number} sont disponibles", "app.components.listPlugins.title.none": "Aucun plugin n'est installé", "app.components.listPlugins.button": "Ajouter un Nouveau Plugin", + "components.AutoReloadBlocker.header": "L'autoReload doit être activé pour ce plugin.", "components.AutoReloadBlocker.description": "Ouvrez le fichier suivant pour activer cette fonctionnalité.", + + "components.ErrorBoundary.title": "Une erreur est survenue...", + "components.ProductionBlocker.header": "Ce plugin est disponible uniquement en développement.", "components.ProductionBlocker.description": "Pour des raisons de sécurité il est désactivé dans les autres environnements.", - "comonents.popUpWarning.button.cancel": "Annuler", - "comonents.popUpWarning.button.confirm": "Confirmer", + + "components.popUpWarning.button.cancel": "Annuler", + "components.popUpWarning.button.confirm": "Confirmer", "components.popUpWarning.title": "Merci de confirmer", "components.popUpWarning.message": "Etes-vous sure de vouloir le supprimer?", + "components.Input.error.validation.email": "Le format n'est pas de type email", "components.Input.error.validation.required": "Ce champ est obligatoire.", "components.Input.error.validation.regex": "La valeur ne correspond pas au format attendu.", @@ -43,8 +61,11 @@ "components.Input.error.attribute.key.taken": "Cette valeur existe déjà", "components.Input.error.attribute.sameKeyAndName": "Ne peuvent pas être égaux", "components.Input.error.validation.minSupMax": "Ne peut pas être plus grand", - "components.ErrorBoundary.title": "Une erreur est survenue...", + "components.ListRow.empty": "Il n'y a pas de données à afficher.", + + "notification.error": "Une erreur est survenue", + "Auth & Permissions": "Auth & Permissions", "Content Manager": "Content Manager", "Content Type Builder": "Content Type Builder", diff --git a/packages/strapi-helper-plugin/lib/src/components/Input/index.js b/packages/strapi-helper-plugin/lib/src/components/Input/index.js index 2334b72a12..fc6a5072cf 100644 --- a/packages/strapi-helper-plugin/lib/src/components/Input/index.js +++ b/packages/strapi-helper-plugin/lib/src/components/Input/index.js @@ -483,6 +483,8 @@ class Input extends React.Component { // eslint-disable-line react/prefer-statel return this.renderInputToggle(); case 'email': return this.renderInputEmail(requiredClass, inputDescription, handleBlur); + case 'search': + return this.renderInputSearch(requiredClass, inputDescription, handleBlur) default: } diff --git a/packages/strapi-plugin-users-permissions/config/roles.json b/packages/strapi-plugin-users-permissions/config/roles.json index da10206ce5..0a82683b3a 100644 --- a/packages/strapi-plugin-users-permissions/config/roles.json +++ b/packages/strapi-plugin-users-permissions/config/roles.json @@ -256,138 +256,7 @@ } }, "application": { - "controllers": { - "azeaz": { - "find": { - "enabled": true, - "policy": "" - }, - "findOne": { - "enabled": true, - "policy": "" - }, - "create": { - "enabled": true, - "policy": "" - }, - "update": { - "enabled": true, - "policy": "" - }, - "destroy": { - "enabled": true, - "policy": "" - }, - "identity": { - "enabled": true, - "policy": "" - } - }, - "bite": { - "find": { - "enabled": true, - "policy": "" - }, - "findOne": { - "enabled": true, - "policy": "" - }, - "create": { - "enabled": true, - "policy": "" - }, - "update": { - "enabled": true, - "policy": "" - }, - "destroy": { - "enabled": true, - "policy": "" - }, - "identity": { - "enabled": true, - "policy": "" - } - }, - "erza": { - "find": { - "enabled": true, - "policy": "" - }, - "findOne": { - "enabled": true, - "policy": "" - }, - "create": { - "enabled": true, - "policy": "" - }, - "update": { - "enabled": true, - "policy": "" - }, - "destroy": { - "enabled": true, - "policy": "" - }, - "identity": { - "enabled": true, - "policy": "" - } - }, - "ez": { - "find": { - "enabled": true, - "policy": "" - }, - "findOne": { - "enabled": true, - "policy": "" - }, - "create": { - "enabled": true, - "policy": "" - }, - "update": { - "enabled": true, - "policy": "" - }, - "destroy": { - "enabled": true, - "policy": "" - }, - "identity": { - "enabled": true, - "policy": "" - } - }, - "reaz": { - "find": { - "enabled": true, - "policy": "" - }, - "findOne": { - "enabled": true, - "policy": "" - }, - "create": { - "enabled": true, - "policy": "" - }, - "update": { - "enabled": true, - "policy": "" - }, - "destroy": { - "enabled": true, - "policy": "" - }, - "identity": { - "enabled": true, - "policy": "" - } - } - } + "controllers": {} } } }, @@ -648,138 +517,7 @@ } }, "application": { - "controllers": { - "azeaz": { - "find": { - "enabled": false, - "policy": "" - }, - "findOne": { - "enabled": false, - "policy": "" - }, - "create": { - "enabled": false, - "policy": "" - }, - "update": { - "enabled": false, - "policy": "" - }, - "destroy": { - "enabled": false, - "policy": "" - }, - "identity": { - "enabled": false, - "policy": "" - } - }, - "bite": { - "find": { - "enabled": false, - "policy": "" - }, - "findOne": { - "enabled": false, - "policy": "" - }, - "create": { - "enabled": false, - "policy": "" - }, - "update": { - "enabled": false, - "policy": "" - }, - "destroy": { - "enabled": false, - "policy": "" - }, - "identity": { - "enabled": false, - "policy": "" - } - }, - "erza": { - "find": { - "enabled": false, - "policy": "" - }, - "findOne": { - "enabled": false, - "policy": "" - }, - "create": { - "enabled": false, - "policy": "" - }, - "update": { - "enabled": false, - "policy": "" - }, - "destroy": { - "enabled": false, - "policy": "" - }, - "identity": { - "enabled": false, - "policy": "" - } - }, - "ez": { - "find": { - "enabled": false, - "policy": "" - }, - "findOne": { - "enabled": false, - "policy": "" - }, - "create": { - "enabled": false, - "policy": "" - }, - "update": { - "enabled": false, - "policy": "" - }, - "destroy": { - "enabled": false, - "policy": "" - }, - "identity": { - "enabled": false, - "policy": "" - } - }, - "reaz": { - "find": { - "enabled": false, - "policy": "" - }, - "findOne": { - "enabled": false, - "policy": "" - }, - "create": { - "enabled": false, - "policy": "" - }, - "update": { - "enabled": false, - "policy": "" - }, - "destroy": { - "enabled": false, - "policy": "" - }, - "identity": { - "enabled": false, - "policy": "" - } - } - } + "controllers": {} } } } diff --git a/packages/strapi-plugin-users-permissions/package.json b/packages/strapi-plugin-users-permissions/package.json index 79dfa02697..32422cdce6 100644 --- a/packages/strapi-plugin-users-permissions/package.json +++ b/packages/strapi-plugin-users-permissions/package.json @@ -47,7 +47,7 @@ "license": "MIT", "devDependencies": { "cross-env": "^5.1.1", - "eslint": "^4.12.0", + "eslint": "^4.12.1", "eslint-config-airbnb": "^15.1.0", "eslint-config-airbnb-base": "^11.3.2", "eslint-config-prettier": "^2.9.0", @@ -59,6 +59,6 @@ "plop": "^1.9.0", "prettier": "^1.8.2", "rimraf": "^2.6.2", - "webpack": "^3.8.1" + "webpack": "^3.9.1" } } \ No newline at end of file