Resolve conflicts and disallow to edit and remove default roles

This commit is contained in:
Aurelsicoko 2018-01-24 11:52:09 +01:00
commit cf1cb7050b
110 changed files with 1275 additions and 686 deletions

View File

@ -17,7 +17,7 @@ before_install:
- rm -rf node_modules/
install:
- npm run setup
- npm run setup --debug
script:
- npm run doc

View File

@ -41,7 +41,7 @@ This is the production-ready version of Strapi (v1). You should also consider th
npm install strapi -g
```
Read the [Getting started](http://strapi.io/documentation/getting-started/quick-start.html) page to create your first project using Strapi.
Read the [Getting started](https://strapi.io/getting-started) page to create your first project using Strapi.
## Features
@ -56,7 +56,7 @@ Read the [Getting started](http://strapi.io/documentation/getting-started/quick-
## Philosophy ?
> At [Strapi](http://strapi.io), everything we do we believe in changing the status quo of web development. Our products are simple to use, user friendly and production-ready.
> At [Strapi](https://strapi.io), everything we do we believe in changing the status quo of web development. Our products are simple to use, user friendly and production-ready.
Web and mobile applications needed a powerful, simple to use and production-ready API-driven solution. That's why we created Strapi, an open-source Content Management Framework (CMF) for exposing your content (data, media) accross multi-devices.
@ -78,8 +78,12 @@ For general help using Strapi, please refer to [the official Strapi documentatio
### Professional support
[Strapi Solutions](http://strapi.io), the company behind Strapi, provides a full range of solutions to get better results, faster. We're always looking for the next challenge: coaching, consulting, training, customization, etc. [Drop us an email](mailto:support@strapi.io) to see how we can help you.
[Strapi Solutions](https://strapi.io), the company behind Strapi, provides a full range of solutions to get better results, faster. We're always looking for the next challenge: coaching, consulting, training, customization, etc. [Drop us an email](mailto:support@strapi.io) to see how we can help you.
### Migration
Follow our [migration guides](https://strapi.io/documentation/migration/migration-guide.html) on the website to keep your Strapi projects updated.
## License
[MIT License](LICENSE.md) Copyright (c) 2015-2018 [Strapi Solutions](http://strapi.io/).
[MIT License](LICENSE.md) Copyright (c) 2015-2018 [Strapi Solutions](https://strapi.io/).

View File

@ -12,10 +12,10 @@ The most advanced open-source Content Management Framework to build powerful API
{% endcenter %}
## v3@alpha.7 is available!
## v3@alpha.8 is available!
We've been working on a major update for Strapi during the past months, rewriting the core framework and the dashboard.
This documentation is only related to Strapi v3@alpha.7 ([v1 documentation is still available](http://strapi.io/documentation/1.x.x)).
This documentation is only related to Strapi v3@alpha.8 ([v1 documentation is still available](http://strapi.io/documentation/1.x.x)).
**[Get Started](getting-started/installation.md)**<br />
Learn how to install Strapi and start developing your API.
@ -36,4 +36,3 @@ Understand how to develop your own plugin.
Learn about Strapi's API, the `strapi` object that is available in your backend.
**[Migration guide](migration/migration-guide.md)**<br />
Migrate from v1 to v3@alpha.7.

View File

@ -16,7 +16,7 @@
* [Table of contents](concepts/concepts.md)
### Guides
* [Authentification](guides/authentification.md)
* [Authentication](guides/authentication.md)
* [Configurations](configurations/configurations.md)
* [Controllers](guides/controllers.md)
* [Deployment](guides/deployment.md)
@ -53,3 +53,4 @@
### Migration
* [Migrating from v1 to v3](migration/migration-guide.md)
* [Migrating from 3.0.0-alpha.7.4 to 3.0.0-alpha.8](migration/migration-guide-alpha-7-4-to-alpha-8.md)

View File

@ -176,7 +176,7 @@ The `gzip` middleware will be loaded after the `p3p` middleware. All the others
],
"order": [],
"after": [
"parser"
"parser",
"router"
]
}
@ -216,7 +216,7 @@ We assume that we set the `./config/middleware.json` file like this:
"gzip"
],
"after": [
"parser"
"parser",
"router"
]
}

View File

@ -11,7 +11,7 @@ $.ajax({
type: 'POST',
url: 'http://localhost:1337/auth/local/register',
data: {
username: 'Strapi user'
username: 'Strapi user',
email: 'user@strapi.io',
password: 'strapiPassword'
},
@ -30,7 +30,7 @@ $.ajax({
This route lets you log your users in by getting an authentication token.
#### Usage
#### Local
- The `identifier` param can either be an email or a username.
@ -53,6 +53,32 @@ $.ajax({
});
```
## Providers
Thanks to [Grant](https://github.com/simov/grant) and [Purest](https://github.com/simov/purest), you can easily use OAuth and OAuth2
providers to enable authentication in your application. By default,
Strapi comes with four providers:
- Facebook
- Google
- Github
- Linkedin2 (Oauth2 Provider for Linkedin)
To use the providers authentication, set your credentials in
`./plugins/users-permissions/config/environments/development/grant.json`.
Redirect your user to: `GET /connect/:provider`. eg: `GET /connect/facebook`
After his approval, he will be redirected to `/auth/:provider/callback`. The `jwt` and `user` data will be available in the body response.
Response payload:
```js
{
"user": {},
"jwt": ""
}
```
## Use your token to be identified as a user.
By default, each API request is identified as `guest` role (see permissions of `guest`'s role in your admin dashboard). To make a request as a user, you have to set the `Authorization` token in your request headers. You receive a 401 error if you are not authorized to make this request or if your authorization header is not correct.
@ -91,7 +117,7 @@ $.ajax({
type: 'POST',
url: 'http://localhost:1337/auth/forgot-password',
data: {
email: 'user@strapi.io'
email: 'user@strapi.io',
url: 'http://mon-site.com/rest-password'
},
done: function() {
@ -118,8 +144,8 @@ $.ajax({
type: 'POST',
url: 'http://localhost:1337/auth/reset-password',
data: {
code: 'privateCode'
password: 'myNewPassword'
code: 'privateCode',
password: 'myNewPassword',
passwordConfirmation: 'myNewPassword'
},
done: function() {

View File

@ -48,14 +48,14 @@ You need to define the english and french translation for this key.
**Path —** `./config/locales/en_US.json`.
```json
{
"Hello %s": "Hello %s"
"Hello %s": "Hello %s"
}
```
**Path —** `./config/locales/fr_FR.json`.
```json
{
"Hello %s": "Bonjour %s"
"Hello %s": "Bonjour %s"
}
```

View File

@ -137,8 +137,8 @@ For example "color=blue&size=small":
```js
{
color: 'blue',
size: 'small'
color: 'blue',
size: 'small'
}
```
@ -163,8 +163,8 @@ ctx.set('ETag', '123');
// cache is ok
if (ctx.fresh) {
ctx.status = 304;
return;
ctx.status = 304;
return;
}
// cache is stale
@ -238,7 +238,7 @@ only images are sent to a given route:
if (ctx.is('image/*')) {
// process
} else {
ctx.throw(415, 'images only!');
ctx.throw(415, 'images only!');
}
```
@ -300,10 +300,10 @@ or use a switch:
```js
switch (ctx.accepts('json', 'html', 'text')) {
case 'json': break;
case 'html': break;
case 'text': break;
default: ctx.throw(406, 'json, html, or text only');
case 'json': break;
case 'html': break;
case 'text': break;
default: ctx.throw(406, 'json, html, or text only');
}
```

View File

@ -155,7 +155,7 @@ Here's an example of stream error handling without automatically destroying the
const PassThrough = require('stream').PassThrough;
app.use(async ctx => {
ctx.body = someHTTPStream.on('error', ctx.onerror).pipe(PassThrough());
ctx.body = someHTTPStream.on('error', ctx.onerror).pipe(PassThrough());
});
```
@ -192,8 +192,8 @@ Set several response header `fields` with an object:
```js
ctx.set({
'Etag': '1234',
'Last-Modified': date
'Etag': '1234',
'Last-Modified': date
});
```
@ -247,7 +247,7 @@ let body = ctx.body;
if (!body || body.pipe) return;
if (Buffer.isBuffer(body)) body = body.toString();
ctx.body = minify(body);
ctx.body = minify(body);
});
```
@ -468,7 +468,7 @@ Here's an example of stream error handling without automatically destroying the
const PassThrough = require('stream').PassThrough;
app.use(async ctx => {
ctx.body = someHTTPStream.on('error', ctx.onerror).pipe(PassThrough());
ctx.body = someHTTPStream.on('error', ctx.onerror).pipe(PassThrough());
});
```
@ -505,8 +505,8 @@ Set several response header `fields` with an object:
```js
ctx.set({
'Etag': '1234',
'Last-Modified': date
'Etag': '1234',
'Last-Modified': date
});
```
@ -560,7 +560,7 @@ let body = ctx.body;
if (!body || body.pipe) return;
if (Buffer.isBuffer(body)) body = body.toString();
ctx.body = minify(body);
ctx.body = minify(body);
});
```
@ -693,9 +693,9 @@ Generates the following response payload:
```json
{
"statusCode": 400,
"error": "Bad Request",
"message": "invalid query"
"statusCode": 400,
"error": "Bad Request",
"message": "invalid query"
}
```
@ -723,9 +723,9 @@ Generates the following response:
```json
"payload": {
"statusCode": 401,
"error": "Unauthorized",
"message": "invalid password"
"statusCode": 401,
"error": "Unauthorized",
"message": "invalid password"
},
"headers" {}
```
@ -738,12 +738,12 @@ Generates the following response:
```json
"payload": {
"statusCode": 401,
"error": "Unauthorized",
"message": "invalid password",
"attributes": {
"error": "invalid password"
}
"statusCode": 401,
"error": "Unauthorized",
"message": "invalid password",
"attributes": {
"error": "invalid password"
}
},
"headers" {
"WWW-Authenticate": "sample error=\"invalid password\""
@ -758,9 +758,9 @@ Generates the following response:
```json
"payload": {
"statusCode": 401,
"error": "Unauthorized",
"attributes": "VGhpcyBpcyBhIHRlc3QgdG9rZW4="
"statusCode": 401,
"error": "Unauthorized",
"attributes": "VGhpcyBpcyBhIHRlc3QgdG9rZW4="
},
"headers" {
"WWW-Authenticate": "Negotiate VGhpcyBpcyBhIHRlc3QgdG9rZW4="
@ -775,15 +775,15 @@ Generates the following response:
```json
"payload": {
"statusCode": 401,
"error": "Unauthorized",
"message": "invalid password",
"attributes": {
"error": "invalid password",
"ttl": 0,
"cache": "",
"foo": "bar"
}
"statusCode": 401,
"error": "Unauthorized",
"message": "invalid password",
"attributes": {
"error": "invalid password",
"ttl": 0,
"cache": "",
"foo": "bar"
}
},
"headers" {
"WWW-Authenticate": "sample ttl=\"0\", cache=\"\", foo=\"bar\", error=\"invalid password\""
@ -804,9 +804,9 @@ Generates the following response payload:
```json
{
"statusCode": 402,
"error": "Payment Required",
"message": "bandwidth used"
"statusCode": 402,
"error": "Payment Required",
"message": "bandwidth used"
}
```
@ -824,9 +824,9 @@ Generates the following response payload:
```json
{
"statusCode": 403,
"error": "Forbidden",
"message": "try again some time"
"statusCode": 403,
"error": "Forbidden",
"message": "try again some time"
}
```
@ -844,9 +844,9 @@ Generates the following response payload:
```json
{
"statusCode": 404,
"error": "Not Found",
"message": "missing"
"statusCode": 404,
"error": "Not Found",
"message": "missing"
}
```
@ -865,9 +865,9 @@ Generates the following response payload:
```json
{
"statusCode": 405,
"error": "Method Not Allowed",
"message": "that method is not allowed"
"statusCode": 405,
"error": "Method Not Allowed",
"message": "that method is not allowed"
}
```
@ -885,9 +885,9 @@ Generates the following response payload:
```json
{
"statusCode": 406,
"error": "Not Acceptable",
"message": "unacceptable"
"statusCode": 406,
"error": "Not Acceptable",
"message": "unacceptable"
}
```
@ -905,9 +905,9 @@ Generates the following response payload:
```json
{
"statusCode": 407,
"error": "Proxy Authentication Required",
"message": "auth missing"
"statusCode": 407,
"error": "Proxy Authentication Required",
"message": "auth missing"
}
```
@ -925,9 +925,9 @@ Generates the following response payload:
```json
{
"statusCode": 408,
"error": "Request Time-out",
"message": "timed out"
"statusCode": 408,
"error": "Request Time-out",
"message": "timed out"
}
```
@ -945,9 +945,9 @@ Generates the following response payload:
```json
{
"statusCode": 409,
"error": "Conflict",
"message": "there was a conflict"
"statusCode": 409,
"error": "Conflict",
"message": "there was a conflict"
}
```
@ -965,9 +965,9 @@ Generates the following response payload:
```json
{
"statusCode": 410,
"error": "Gone",
"message": "it is gone"
"statusCode": 410,
"error": "Gone",
"message": "it is gone"
}
```
@ -985,9 +985,9 @@ Generates the following response payload:
```json
{
"statusCode": 411,
"error": "Length Required",
"message": "length needed"
"statusCode": 411,
"error": "Length Required",
"message": "length needed"
}
```
@ -1005,8 +1005,8 @@ Generates the following response payload:
```json
{
"statusCode": 412,
"error": "Precondition Failed"
"statusCode": 412,
"error": "Precondition Failed"
}
```
@ -1024,9 +1024,9 @@ Generates the following response payload:
```json
{
"statusCode": 413,
"error": "Request Entity Too Large",
"message": "too big"
"statusCode": 413,
"error": "Request Entity Too Large",
"message": "too big"
}
```
@ -1044,9 +1044,9 @@ Generates the following response payload:
```json
{
"statusCode": 414,
"error": "Request-URI Too Large",
"message": "uri is too long"
"statusCode": 414,
"error": "Request-URI Too Large",
"message": "uri is too long"
}
```
@ -1064,9 +1064,9 @@ Generates the following response payload:
```json
{
"statusCode": 415,
"error": "Unsupported Media Type",
"message": "that media is not supported"
"statusCode": 415,
"error": "Unsupported Media Type",
"message": "that media is not supported"
}
```
@ -1084,8 +1084,8 @@ Generates the following response payload:
```json
{
"statusCode": 416,
"error": "Requested Range Not Satisfiable"
"statusCode": 416,
"error": "Requested Range Not Satisfiable"
}
```
@ -1103,9 +1103,9 @@ Generates the following response payload:
```json
{
"statusCode": 417,
"error": "Expectation Failed",
"message": "expected this to work"
"statusCode": 417,
"error": "Expectation Failed",
"message": "expected this to work"
}
```
@ -1123,9 +1123,9 @@ Generates the following response payload:
```json
{
"statusCode": 418,
"error": "I'm a Teapot",
"message": "Sorry, no coffee..."
"statusCode": 418,
"error": "I'm a Teapot",
"message": "Sorry, no coffee..."
}
```
@ -1143,9 +1143,9 @@ Generates the following response payload:
```json
{
"statusCode": 422,
"error": "Unprocessable Entity",
"message": "your data is bad and you should feel bad"
"statusCode": 422,
"error": "Unprocessable Entity",
"message": "your data is bad and you should feel bad"
}
```
@ -1163,9 +1163,9 @@ Generates the following response payload:
```json
{
"statusCode": 423,
"error": "Locked",
"message": "this resource has been locked"
"statusCode": 423,
"error": "Locked",
"message": "this resource has been locked"
}
```
@ -1183,9 +1183,9 @@ Generates the following response payload:
```json
{
"statusCode": 428,
"error": "Precondition Required",
"message": "you must supply an If-Match header"
"statusCode": 428,
"error": "Precondition Required",
"message": "you must supply an If-Match header"
}
```
@ -1203,9 +1203,9 @@ Generates the following response payload:
```json
{
"statusCode": 429,
"error": "Too Many Requests",
"message": "you have exceeded your request limit"
"statusCode": 429,
"error": "Too Many Requests",
"message": "you have exceeded your request limit"
}
```
@ -1223,9 +1223,9 @@ Generates the following response payload:
```json
{
"statusCode": 451,
"error": "Unavailable For Legal Reasons",
"message": "you are not permitted to view this resource for legal reasons"
"statusCode": 451,
"error": "Unavailable For Legal Reasons",
"message": "you are not permitted to view this resource for legal reasons"
}
```
@ -1247,9 +1247,9 @@ Generates the following response payload:
```json
{
"statusCode": 500,
"error": "Internal Server Error",
"message": "An internal server error occurred"
"statusCode": 500,
"error": "Internal Server Error",
"message": "An internal server error occurred"
}
```
@ -1267,9 +1267,9 @@ Generates the following response payload:
```json
{
"statusCode": 501,
"error": "Not Implemented",
"message": "method not implemented"
"statusCode": 501,
"error": "Not Implemented",
"message": "method not implemented"
}
```
@ -1287,9 +1287,9 @@ Generates the following response payload:
```json
{
"statusCode": 502,
"error": "Bad Gateway",
"message": "that is a bad gateway"
"statusCode": 502,
"error": "Bad Gateway",
"message": "that is a bad gateway"
}
```
@ -1307,9 +1307,9 @@ Generates the following response payload:
```json
{
"statusCode": 503,
"error": "Service Unavailable",
"message": "unavailable"
"statusCode": 503,
"error": "Service Unavailable",
"message": "unavailable"
}
```
@ -1327,7 +1327,7 @@ Generates the following response payload:
```json
{
"statusCode": 504,
"error": "Gateway Time-out"
"statusCode": 504,
"error": "Gateway Time-out"
}
```

View File

@ -0,0 +1,57 @@
# Migrating from 3.0.0-alpha.7.3 to 3.0.0-alpha.8
**Here are the major changes:**
- Fix deployment process
- Setup database connection on project creation
- Helper for table creation for SQL database
> Feel free to [join us on Slack](http://slack.strapi.io) and ask questions about the migration process.
## Getting started
Install Strapi `alpha.8` globally on your computer. To do so run `npm install strapi@3.0.0-alpha.8 -g`.
When it's done, generate a new empty project `strapi new myNewProject` (don't pay attention to the database configuration).
## Configurations
You will have to update just 1 file: `package.json`
- Edit the scripts section: (only the `setup` line has changed)
```json
{
"scripts": {
"setup": "cd admin && npm run setup",
"start": "node server.js",
"strapi": "node_modules/strapi/bin/strapi.js",
"lint": "node_modules/.bin/eslint api/**/*.js config/**/*.js plugins/**/*.js",
"postinstall": "node node_modules/strapi/lib/utils/post-install.js"
}
}
```
- Edit the Strapi's dependencies version: (move Strapi's dependencies to `3.0.0-alpha.8` version)
```json
{
"dependencies": {
"lodash": "4.x.x",
"strapi": "3.0.0-alpha.8",
"strapi-mongoose": "3.0.0-alpha.8"
}
}
```
## Update the Admin
Delete your old admin folder and replace by the new one.
## Update the Plugins
Copy these 3 files `/plugins/users-permissions/config/jwt.json`, `/plugins/users-permissions/config/roles.json` and `/plugins/users-permissions/models/User.settings.json` **from your old project** and paste them in the corresponding ones in your new project. It is important to save these files.
Then, delete your old `plugins` folder and replace it by the new one.
That's all, you have now upgraded to Strapi `alpha.8`.

View File

@ -330,7 +330,7 @@ export default FooPage;
## OverlayBlocker
The OverlayBlocker is a React component that is very useful to block user interactions when the strapi server is restarting in order to avoid front-end errors.
The OverlayBlocker is a React component that is very useful to block user interactions when the strapi server is restarting in order to avoid front-end errors. This component is automatically displayed when the server needs to restart. You need to disable it in order to override the current design (once disabled it won't show on the other plugins so it's really important to enable it back when the component is unmounting).
### Usage
@ -341,7 +341,7 @@ The OverlayBlocker is a React component that is very useful to block user intera
### Example
In this example we'll have a button that when clicked it will display the OverlayBlocker for 5 seconds thus 'freezes' the admin so the user can't navigate (it simulates a very long server restart).
In this example we'll have a button that when clicked will display the OverlayBlocker for 5 seconds thus 'freezes' the admin so the user can't navigate (it simulates a very long server restart).
**Path -** `./plugins/my-plugin/admin/src/containers/FooPage/constants.js`.
```js
@ -373,6 +373,12 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators, compose } from 'redux';
// Actions required for disabling and enabling the OverlayBlocker
import {
disableGlobalOverlayBlocker,
enableGlobalOverlayBlocker,
} from 'actions/overlayBlocker';
// Design
import Button from 'components/Button';
import OverlayBlocker from 'components/OverlayBlocker';
@ -395,6 +401,16 @@ import makeSelectFooPage from './selectors';
export class FooPage extends React.Component {
componentDidMount() {
// Disable the AdminPage OverlayBlocker in order to give it a custom design (children)
this.props.disableGlobalOverlayBlocker();
}
componentWillUnmount() {
// Enable the AdminPage OverlayBlocker so it is displayed when the server is restarting in the other plugins
this.props.enableGlobalOverlayBlocker();
}
render() {
return (
<div>
@ -410,6 +426,8 @@ export class FooPage extends React.Component {
}
FooPage.propTypes = {
disableGlobalOverlayBlocker: PropTypes.func.isRequired,
enableGlobalOverlayBlocker: PropTypes.func.isRequired,
onButtonClick: PropTypes.func.isRequired,
showOverlayBlocker: PropTypes.bool.isRequired,
};
@ -419,6 +437,8 @@ const mapStateToProps = makeSelectFooPage();
function mapDispatchToProps(dispatch) {
return bindActionCreators(
{
disableGlobalOverlayBlocker,
enableGlobalOverlayBlocker,
onButtonClick,
},
dispatch,

View File

@ -2,6 +2,63 @@
Strapi provides helpers so you don't have to develop again and again the same generic functions.
## Auth
`auth.js` lets you get, set and delete data in either the browser's `localStorage` or `sessionStorage`.
### Methods
| Name | Description |
| ---- | ----------- |
| clear(key) | Remove the data in either `localStorage` or `sessionStorage` |
| clearAppStorage() | Remove all data from both storage |
| clearToken() | Remove the user's `jwt Token` in the appropriate browser's storage |
| clearUserInfo() | Remove the user's info from storage |
| get(key) | Get the item in the browser's storage |
| getToken() | Get the user's `jwtToken` |
| getUserInfo() | Get the user's infos |
| set(value, key, isLocalStorage) | Set an item in the `sessionStorage`. If `true` is passed as the 3rd parameter it sets the value in the `localStorage` |
| setToken(value, isLocalStorage) | Set the user's `jwtToken` in the `sessionStorage`. If `true` is passed as the 2nd parameter it sets the value in the `localStorage` |
| setUserInfo(value, isLocalStorage) | Set the user's info in the `sessionStorage`. If `true` is passed as the 2nd parameter it sets the value in the `localStorage` |
```js
import auth from 'utils/auth';
// ...
//
auth.setToken('12345', true); // This will set 1234 in the browser's localStorage associated with the key: jwtToken
```
## Colors
This function allows to darken a color.
### Usage
```js
import { darken } from 'utils/colors';
const linkColor = darken('#f5f5f5', 1.5); // Will darken #F5F5F5 by 1.5% which gives #f2f2f2.
```
## Get URL Query Parameters
The helpers allows to retrieve the query parameters in the URL.
### Example
```js
import getQueryParameters from 'utils/getQueryParameters';
const URL = '/create?source=users-permissions';
const source = getQueryParameters(URL, 'source');
console.log(source); // users-permissions
```
## Request helper
A request helper is available to handle all requests inside a plugin.
@ -368,7 +425,6 @@ function* defaultSaga() {
export default defaultSaga;
```
***
***
### Example with server autoReload watcher

View File

@ -1,6 +1,6 @@
{
"private": true,
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"devDependencies": {
"assert": "~1.3.0",
"babel-eslint": "^6.1.2",

View File

@ -8,3 +8,4 @@ package-lock.json
.DS_Store
npm-debug.log
.idea
manifest.json

View File

@ -1,7 +1,6 @@
# Don't check auto-generated stuff into git
coverage
node_modules
build
plugins.json
stats.json
package-lock.json

View File

@ -23,7 +23,14 @@ import LanguageProvider from 'containers/LanguageProvider';
import App from 'containers/App';
import { showNotification } from 'containers/NotificationProvider/actions';
import { pluginLoaded, updatePlugin, unsetHasUserPlugin } from 'containers/App/actions';
import {
freezeApp,
pluginLoaded,
unfreezeApp,
unsetHasUserPlugin,
updatePlugin,
} from 'containers/App/actions';
import auth from 'utils/auth';
import configureStore from './store';
import { translationMessages, languages } from './i18n';
@ -175,6 +182,13 @@ const displayNotification = (message, status) => {
store.dispatch(showNotification(message, status));
};
const lockApp = () => {
store.dispatch(freezeApp());
};
const unlockApp = () => {
store.dispatch(unfreezeApp());
};
/**
* Public Strapi object exposed to the `window` object
@ -208,6 +222,8 @@ window.strapi = Object.assign(window.strapi || {}, {
router: history,
languages,
currentLanguage: window.localStorage.getItem('strapi-admin-language') || window.navigator.language || window.navigator.userLanguage || 'en',
lockApp,
unlockApp,
});
const dispatch = store.dispatch;

View File

@ -5,12 +5,25 @@
.icoContainer {
width: 70px;
height: 36px;
position: relative;
margin: auto 0;
line-height: 36px;
text-align: center;
border: 1px solid rgba(28,93,231,0.1);
border-radius: 3px;
font-size: 20px;
> img {
max-width: 100%;
max-height: 100%;
width: auto;
height: auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
}
.pluginContent {

File diff suppressed because one or more lines are too long

View File

@ -17,7 +17,13 @@ import { Switch, Route } from 'react-router-dom';
import { get, includes, isFunction, map, omit } from 'lodash';
import { pluginLoaded, updatePlugin } from 'containers/App/actions';
import { selectHasUserPlugin, selectPlugins } from 'containers/App/selectors';
import {
makeSelectBlockApp,
makeSelectShowGlobalAppBlocker,
selectHasUserPlugin,
selectPlugins,
} from 'containers/App/selectors';
import { hideNotification } from 'containers/NotificationProvider/actions';
// Design
@ -30,6 +36,7 @@ import LeftMenu from 'containers/LeftMenu';
import ListPluginsPage from 'containers/ListPluginsPage';
import Logout from 'components/Logout';
import NotFoundPage from 'containers/NotFoundPage';
import OverlayBlocker from 'components/OverlayBlocker';
import PluginPage from 'containers/PluginPage';
import auth from 'utils/auth';
@ -130,6 +137,7 @@ export class AdminPage extends React.Component { // eslint-disable-line react/pr
</Switch>
</Content>
</div>
<OverlayBlocker isOpen={this.props.blockApp && this.props.showGlobalAppBlocker} />
</div>
);
}
@ -149,17 +157,21 @@ AdminPage.defaultProps = {
};
AdminPage.propTypes = {
blockApp: PropTypes.bool.isRequired,
hasUserPlugin: PropTypes.bool,
history: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
pluginLoaded: PropTypes.func.isRequired,
plugins: PropTypes.object.isRequired,
showGlobalAppBlocker: PropTypes.bool.isRequired,
updatePlugin: PropTypes.func.isRequired,
};
const mapStateToProps = createStructuredSelector({
blockApp: makeSelectBlockApp(),
hasUserPlugin: selectHasUserPlugin(),
plugins: selectPlugins(),
showGlobalAppBlocker: makeSelectShowGlobalAppBlocker(),
});
function mapDispatchToProps(dispatch) {

View File

@ -5,13 +5,21 @@
*/
import {
FREEZE_APP,
LOAD_PLUGIN,
UPDATE_PLUGIN,
PLUGIN_LOADED,
PLUGIN_DELETED,
PLUGIN_LOADED,
UNFREEZE_APP,
UNSET_HAS_USERS_PLUGIN,
UPDATE_PLUGIN,
} from './constants';
export function freezeApp() {
return {
type: FREEZE_APP,
};
}
export function loadPlugin(newPlugin) {
return {
type: LOAD_PLUGIN,
@ -19,22 +27,6 @@ export function loadPlugin(newPlugin) {
};
}
export function updatePlugin(pluginId, updatedKey, updatedValue) {
return {
type: UPDATE_PLUGIN,
pluginId,
updatedKey,
updatedValue,
};
}
export function pluginLoaded(newPlugin) {
return {
type: PLUGIN_LOADED,
plugin: newPlugin,
};
}
export function pluginDeleted(plugin) {
return {
type: PLUGIN_DELETED,
@ -42,8 +34,30 @@ export function pluginDeleted(plugin) {
};
}
export function pluginLoaded(newPlugin) {
return {
type: PLUGIN_LOADED,
plugin: newPlugin,
};
}
export function unfreezeApp() {
return {
type: UNFREEZE_APP,
};
}
export function unsetHasUserPlugin() {
return {
type: UNSET_HAS_USERS_PLUGIN,
};
}
export function updatePlugin(pluginId, updatedKey, updatedValue) {
return {
type: UPDATE_PLUGIN,
pluginId,
updatedKey,
updatedValue,
};
}

View File

@ -4,8 +4,10 @@
*
*/
export const UNSET_HAS_USERS_PLUGIN = 'app/App/UNSET_HAS_USERS_PLUGIN';
export const FREEZE_APP = 'app/App/FREEZE_APP';
export const LOAD_PLUGIN = 'app/App/LOAD_PLUGIN';
export const UPDATE_PLUGIN = 'app/App/UPDATE_PLUGIN';
export const PLUGIN_LOADED = 'app/App/PLUGIN_LOADED';
export const PLUGIN_DELETED = 'app/App/PLUGIN_DELETED';
export const UNFREEZE_APP = 'app/App/UNFREEZE_APP';
export const UNSET_HAS_USERS_PLUGIN = 'app/App/UNSET_HAS_USERS_PLUGIN';
export const UPDATE_PLUGIN = 'app/App/UPDATE_PLUGIN';

View File

@ -1,24 +1,43 @@
import { fromJS } from 'immutable';
// Shared constants
import {
UPDATE_PLUGIN,
DISABLE_GLOBAL_OVERLAY_BLOCKER,
ENABLE_GLOBAL_OVERLAY_BLOCKER,
} from 'constants/overlayBlocker';
import { fromJS } from 'immutable';
import {
FREEZE_APP,
PLUGIN_DELETED,
PLUGIN_LOADED,
UNFREEZE_APP,
UNSET_HAS_USERS_PLUGIN,
UPDATE_PLUGIN,
} from './constants';
const initialState = fromJS({
plugins: {},
blockApp: false,
hasUserPlugin: true,
plugins: {},
showGlobalAppBlocker: true,
});
function appReducer(state = initialState, action) {
switch (action.type) {
case DISABLE_GLOBAL_OVERLAY_BLOCKER:
return state.set('showGlobalAppBlocker', false);
case ENABLE_GLOBAL_OVERLAY_BLOCKER:
return state.set('showGlobalAppBlocker', true);
case FREEZE_APP:
return state.set('blockApp', true);
case PLUGIN_LOADED:
return state.setIn(['plugins', action.plugin.id], fromJS(action.plugin));
case UPDATE_PLUGIN:
return state.setIn(['plugins', action.pluginId, action.updatedKey], fromJS(action.updatedValue));
case PLUGIN_DELETED:
return state.deleteIn(['plugins', action.plugin]);
case UNFREEZE_APP:
return state.set('blockApp', false);
case UNSET_HAS_USERS_PLUGIN:
return state.set('hasUserPlugin', false);
default:

View File

@ -19,8 +19,20 @@ const selectHasUserPlugin = () => createSelector(
(appState) => appState.get('hasUserPlugin'),
);
const makeSelectShowGlobalAppBlocker = () => createSelector(
selectApp(),
(appState) => appState.get('showGlobalAppBlocker'),
);
const makeSelectBlockApp = () => createSelector(
selectApp(),
(appState) => appState.get('blockApp'),
);
export {
selectApp,
selectHasUserPlugin,
selectPlugins,
makeSelectBlockApp,
makeSelectShowGlobalAppBlocker,
};

View File

@ -13,6 +13,11 @@ import { bindActionCreators, compose } from 'redux';
import cn from 'classnames';
import { get, isUndefined, map } from 'lodash';
import {
disableGlobalOverlayBlocker,
enableGlobalOverlayBlocker,
} from 'actions/overlayBlocker';
// Design
// import Input from 'components/Input';
import DownloadInfo from 'components/DownloadInfo';
@ -43,12 +48,20 @@ export class InstallPluginPage extends React.Component { // eslint-disable-line
);
componentDidMount() {
// Disable the AdminPage OverlayBlocker in order to give it a custom design (children)
this.props.disableGlobalOverlayBlocker();
// Don't fetch the available plugins if it has already been done
if (!this.props.didFetchPlugins) {
this.props.getPlugins();
}
}
componentWillUnmount() {
// Enable the AdminPage OverlayBlocker so it is displayed when the server is restarting
this.props.enableGlobalOverlayBlocker();
}
render() {
return (
<div>
@ -118,7 +131,9 @@ InstallPluginPage.propTypes = {
availablePlugins: PropTypes.array.isRequired,
blockApp: PropTypes.bool.isRequired,
didFetchPlugins: PropTypes.bool.isRequired,
disableGlobalOverlayBlocker: PropTypes.func.isRequired,
downloadPlugin: PropTypes.func.isRequired,
enableGlobalOverlayBlocker: PropTypes.func.isRequired,
getPlugins: PropTypes.func.isRequired,
history: PropTypes.object.isRequired,
// onChange: PropTypes.func.isRequired,
@ -130,7 +145,9 @@ const mapStateToProps = makeSelectInstallPluginPage();
function mapDispatchToProps(dispatch) {
return bindActionCreators(
{
disableGlobalOverlayBlocker,
downloadPlugin,
enableGlobalOverlayBlocker,
getPlugins,
onChange,
},

View File

@ -37,7 +37,7 @@ export class PluginPage extends React.Component { // eslint-disable-line react/p
}
return (
<ErrorBoundary key={plugin.id}>
<ErrorBoundary key={plugin.id}>
<Elem {...this.props} {...blockerComponentProps} />
</ErrorBoundary>
);

View File

@ -60,6 +60,9 @@
"components.ErrorBoundary.title": "Something wen't wrong...",
"components.OverlayBlocker.title": "Waiting for restart...",
"components.OverlayBlocker.description": "You're using a feature that needs the server to restart. Please wait until the server is up.",
"components.ProductionBlocker.header": "This plugin is only available in development.",
"components.ProductionBlocker.description": "For safety we have to disable this plugin in other environments.",

View File

@ -58,6 +58,9 @@
"components.AutoReloadBlocker.header": "L'autoReload doit être activé pour ce plugin.",
"components.AutoReloadBlocker.description": "Ouvrez le fichier suivant pour activer cette fonctionnalité.",
"components.OverlayBlocker.title": "Le serveur est en train de redémarrer",
"components.OverlayBlocker.description": "Vous utilisez une fonctionnalité qui nécessite le redémarrage du server. Merci d'attendre que celui-ci ait redémarré.",
"components.ErrorBoundary.title": "Une erreur est survenue...",
"components.ProductionBlocker.header": "Ce plugin est disponible uniquement en développement.",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-admin",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Strapi Admin",
"repository": {
"type": "git",
@ -16,10 +16,9 @@
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
"start": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development PORT=4000 IS_ADMIN=true node ./node_modules/strapi-helper-plugin/lib/server",
"generate": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/plop --plopfile ./node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path ./admin/.gitignore --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"pretest": "npm run lint",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path ./admin/.gitignore --ignore-pattern build --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"prettier": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
"test": "echo Tests are not implemented.",
"test": "npm run lint",
"prepublishOnly": "npm run build",
"setup": "node ./scripts/setup.js"
},
@ -28,8 +27,8 @@
},
"devDependencies": {
"sanitize.css": "^4.1.0",
"strapi-helper-plugin": "3.0.0-alpha.7.3",
"strapi-utils": "3.0.0-alpha.7.3"
"strapi-helper-plugin": "3.0.0-alpha.8.3",
"strapi-utils": "3.0.0-alpha.8.3"
},
"author": {
"name": "Strapi",

View File

@ -61,12 +61,20 @@ if (process.env.npm_config_plugins === 'true') {
shell.exec(`cd ${path.resolve(plugins, plugin)} && npm install`, {
silent
});
shell.exec(`cd ${path.resolve(plugins, plugin, 'node_modules', 'strapi-helper-plugin')} && npm install`, {
silent
});
if (isDevelopmentMode) {
shell.exec(`cd ${path.resolve(plugins, plugin)} && npm link strapi-helper-plugin`, {
silent
});
} else {
shell.exec(`cd ${path.resolve(plugins, plugin, 'node_modules', 'strapi-helper-plugin')} && npm install`, {
silent
});
}
shell.echo('🏗 Building...');
const build = shell.exec(`cd ${path.resolve(plugins, plugin)} && APP_PATH=${appPath} npm run build`, {
const build = shell.exec(`cd ${path.resolve(plugins, plugin)} && APP_PATH=${appPath} npm run build`, {
silent
});

View File

@ -1,6 +1,6 @@
{
"name": "strapi-bookshelf",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Bookshelf hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [
@ -19,8 +19,8 @@
"bookshelf": "^0.10.3",
"lodash": "^4.17.4",
"pluralize": "^6.0.0",
"strapi-knex": "3.0.0-alpha.7.3",
"strapi-utils": "3.0.0-alpha.7.3"
"strapi-knex": "3.0.0-alpha.8.3",
"strapi-utils": "3.0.0-alpha.8.3"
},
"strapi": {
"isHook": true,
@ -55,4 +55,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-ejs",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "EJS hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [
@ -46,4 +46,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-admin",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Generate the default admin panel for a Strapi application.",
"homepage": "http://strapi.io",
"keywords": [
@ -15,7 +15,7 @@
"dependencies": {
"fs-extra": "^4.0.1",
"lodash": "^4.17.4",
"strapi-admin": "3.0.0-alpha.7.3"
"strapi-admin": "3.0.0-alpha.8.3"
},
"author": {
"email": "hi@strapi.io",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-api",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Generate an API for a Strapi application.",
"homepage": "http://strapi.io",
"keywords": [
@ -43,4 +43,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-controller",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Generate a controller for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [
@ -43,4 +43,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-model",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Generate a model for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [
@ -43,4 +43,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,6 @@
{
"session": {
"enabled": false,
"enabled": true,
"client": "cookie",
"key": "strapi.sid",
"prefix": "strapi:sess:",

View File

@ -8,8 +8,8 @@
"host": "${process.env.DATABASE_HOST || 'localhost'}",
"port": "${process.env.DATABASE_PORT || 27017}",
"database": "${process.env.DATABASE_NAME || 'production'}",
"username": "",
"password": ""
"username": "${process.env.DATABASE_USERNAME || ''}",
"password": "${process.env.DATABASE_PASSWORD || ''}"
},
"options": {}
}

View File

@ -13,6 +13,7 @@ const execSync = require('child_process').execSync;
const _ = require('lodash');
const fs = require('fs-extra');
const inquirer = require('inquirer');
const shell = require('shelljs');
// Logger.
const logger = require('strapi-utils').logger;
@ -186,14 +187,14 @@ module.exports = (scope, cb) => {
});
}),
new Promise(resolve => {
let cmd = `npm install --prefix ${scope.rootPath} ${scope.client.connector}@alpha`;
let cmd = `npm install --prefix "${scope.rootPath}" ${scope.client.connector}@alpha`;
if (scope.client.module) {
cmd += ` ${scope.client.module}`;
}
exec(cmd, () => {
if (scope.client.module) {
const lock = require(`${scope.rootPath}/node_modules/${scope.client.module}/package.json`);
const lock = require(path.join(`${scope.rootPath}`,`/node_modules/`,`${scope.client.module}/package.json`));
scope.client.version = lock.version;
}
@ -205,12 +206,10 @@ module.exports = (scope, cb) => {
Promise.all(asyncFn)
.then(() => {
try {
require(path.resolve(`${scope.rootPath}/node_modules/${scope.client.connector}/lib/utils/connectivity.js`))(scope, cb.success, connectionValidation);
require(path.join(`${scope.rootPath}`,`/node_modules/`,`${scope.client.connector}/lib/utils/connectivity.js`))(scope, cb.success, connectionValidation);
} catch(err) {
execSync(`rm -r ${scope.rootPath}`);
shell.rm('-r', scope.rootPath);
logger.info('Copying the dashboard...');
cb.success();
}
});

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-new",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Generate a new Strapi application.",
"homepage": "http://strapi.io",
"keywords": [
@ -18,7 +18,7 @@
"get-installed-path": "^3.0.1",
"inquirer": "^4.0.2",
"lodash": "^4.17.4",
"strapi-utils": "3.0.0-alpha.7.3",
"strapi-utils": "3.0.0-alpha.8.3",
"uuid": "^3.1.0"
},
"scripts": {
@ -48,4 +48,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -35,10 +35,9 @@ module.exports = scope => {
'build:clean': 'node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build',
'start': 'node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node ./node_modules/strapi-helper-plugin/lib/server',
'generate': 'node ./node_modules/plop/plop.js --plopfile node_modules/strapi-helper-plugin/lib/internals/generators/index.js',
'lint': 'node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin',
'pretest': 'npm run lint',
'lint': 'node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --ignore-pattern \'/admin/build/\' --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin',
'prettier': 'node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write "{admin,__{tests,mocks}__}/**/*.js"',
'test': 'echo Tests are not implemented.',
'test': 'npm run lint',
'prepublishOnly': 'npm run build'
},
'dependencies': {},

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-plugin",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Generate an plugin for a Strapi application.",
"homepage": "http://strapi.io",
"keywords": [
@ -44,4 +44,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,5 @@
# Don't check auto-generated stuff into git
coverage
build
node_modules
stats.json
package-lock.json

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-policy",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Generate a policy for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [
@ -43,4 +43,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-service",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Generate a service for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [
@ -43,4 +43,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Master of ceremonies for the Strapi generators.",
"homepage": "http://strapi.io",
"keywords": [
@ -17,7 +17,7 @@
"fs-extra": "^4.0.0",
"lodash": "^4.17.4",
"reportback": "^2.0.1",
"strapi-utils": "3.0.0-alpha.7.3"
"strapi-utils": "3.0.0-alpha.8.3"
},
"author": {
"name": "Strapi team",

View File

@ -20,11 +20,11 @@ const appPath = (() => {
})();
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
const adminPath = (() => {
if (isSetup) {
return isAdmin ? path.resolve(appPath, 'strapi-admin') : path.resolve(process.env.PWD);
if (isAdmin && isSetup) {
return path.resolve(appPath, 'strapi-admin');
}
return path.resolve(appPath, 'admin');
return path.resolve(process.env.PWD);
})();
if (!isSetup) {

View File

@ -15,6 +15,7 @@ const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPl
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const isAdmin = process.env.IS_ADMIN === 'true';
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
const appPath = (() => {
if (process.env.APP_PATH) {
return process.env.APP_PATH;
@ -22,7 +23,13 @@ const appPath = (() => {
return isAdmin ? path.resolve(process.env.PWD, '..') : path.resolve(process.env.PWD, '..', '..');
})();
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
const rootAdminpath = (() => {
if (isSetup) {
return isAdmin ? path.resolve(appPath, 'strapi-admin') : path.resolve(appPath, 'packages', 'strapi-admin');
}
return path.resolve(appPath, 'admin');
})();
// Load plugins into the same build in development mode.
const plugins = {
@ -117,30 +124,14 @@ module.exports = require('./webpack.base.babel')({
],
alias: {
moment: 'moment/moment.js',
'babel-polyfill': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'babel-polyfill'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'babel-polyfill'),
'lodash': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'lodash'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'lodash'),
'immutable': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'immutable'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'immutable'),
'react-intl': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-intl'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-intl'),
'react': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react'),
'react-dom': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-dom'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-dom'),
'react-transition-group': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-transition-group'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-transition-group'),
'reactstrap': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'reactstrap'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'reactstrap')
'babel-polyfill': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'babel-polyfill'),
'lodash': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'lodash'),
'immutable': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'immutable'),
'react-intl': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-intl'),
'react': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react'),
'react-dom': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-dom'),
'react-transition-group': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-transition-group'),
'reactstrap': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'reactstrap')
},
// Emit a source map for easier debugging

View File

@ -21,6 +21,14 @@ const appPath = (() => {
})();
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
const rootAdminpath = (() => {
if (isSetup) {
return isAdmin ? path.resolve(appPath, 'strapi-admin') : path.resolve(appPath, 'packages', 'strapi-admin');
}
return path.resolve(appPath, 'admin');
})();
module.exports = {
context: appPath,
entry: {
@ -29,9 +37,7 @@ module.exports = {
devtool: 'cheap-module-source-map',
output: {
filename: '[name].dll.js',
path: isSetup ?
path.join(__dirname, 'dist'):
path.join(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'lib', 'internals', 'webpack', 'dist'),
path: path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'lib', 'internals', 'webpack', 'dist'),
// The name of the global variable which the library's
// require() function will be assigned to
@ -40,9 +46,7 @@ module.exports = {
plugins: [
new webpack.DllPlugin({
name: '[name]_lib',
path: isSetup ?
path.join(__dirname, 'manifest.json'):
path.join(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'lib', 'internals', 'webpack', 'manifest.json'),
path: path.resolve(rootAdminpath, 'admin', 'src', 'config', 'manifest.json'),
})
],
resolve: {
@ -54,30 +58,14 @@ module.exports = {
],
alias: {
moment: 'moment/moment.js',
'babel-polyfill': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'babel-polyfill'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'babel-polyfill'),
'lodash': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'lodash'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'lodash'),
'immutable': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'immutable'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'immutable'),
'react-intl': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-intl'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-intl'),
'react': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react'),
'react-dom': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-dom'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-dom'),
'react-transition-group': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-transition-group'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-transition-group'),
'reactstrap': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'reactstrap'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'reactstrap')
'babel-polyfill': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'babel-polyfill'),
'lodash': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'lodash'),
'immutable': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'immutable'),
'react-intl': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-intl'),
'react': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react'),
'react-dom': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-dom'),
'react-transition-group': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-transition-group'),
'reactstrap': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'reactstrap')
},
symlinks: false,
extensions: [

View File

@ -35,12 +35,16 @@ const adminPath = (() => {
return path.resolve(appPath, 'admin');
})();
const rootAdminpath = (() => {
if (isSetup) {
return isAdmin ? path.resolve(appPath, 'strapi-admin') : path.resolve(appPath, 'packages', 'strapi-admin');
}
return path.resolve(appPath, 'admin');
})();
const plugins = [
new webpack.DllReferencePlugin({
manifest: require(isSetup ?
path.join(__dirname, 'manifest.json'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'lib', 'internals', 'webpack', 'manifest.json')
),
manifest: require(path.resolve(rootAdminpath, 'admin', 'src', 'config', 'manifest.json'))
}),
// Minify and optimize the JavaScript
new webpack.optimize.UglifyJsPlugin({
@ -79,13 +83,6 @@ if (isAdmin && !isSetup) {
} catch (e) {
throw new Error(`Impossible to access to ${serverConfig}`);
}
// Note: Travis failed with it.
plugins.push(new CopyWebpackPlugin([{
from: 'config/plugins.json',
context: path.resolve(adminPath, 'admin', 'src'),
to: 'config/plugins.json'
}]));
}
// Build the `index.html file`
@ -112,6 +109,11 @@ if (isAdmin) {
plugins.push(new AddAssetHtmlPlugin({
filepath: path.resolve(__dirname, 'dist/*.dll.js')
}));
plugins.push(new CopyWebpackPlugin([{
from: 'config/plugins.json',
context: path.resolve(adminPath, 'admin', 'src'),
to: 'config/plugins.json'
}]));
}
const main = (() => {
@ -167,30 +169,14 @@ module.exports = base({
alias: {
moment: 'moment/moment.js',
'babel-polyfill': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'babel-polyfill'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'babel-polyfill'),
'lodash': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'lodash'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'lodash'),
'immutable': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'immutable'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'immutable'),
'react-intl': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-intl'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-intl'),
'react': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react'),
'react-dom': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-dom'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-dom'),
'react-transition-group': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-transition-group'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-transition-group'),
'reactstrap': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'reactstrap'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'reactstrap')
'babel-polyfill': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'babel-polyfill'),
'lodash': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'lodash'),
'immutable': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'immutable'),
'react-intl': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-intl'),
'react': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react'),
'react-dom': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-dom'),
'react-transition-group': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-transition-group'),
'reactstrap': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'reactstrap')
},
devtool: 'cheap-module-source-map',

View File

@ -24,6 +24,7 @@ module.exports = {
// Some libraries don't like being run through babel.
// If they gripe, put them here.
noParse: [
/build/,
/node_modules(\\|\/)sinon/,
/node_modules(\\|\/)acorn/,
],

View File

@ -0,0 +1,23 @@
/*
*
* Shared OverlayBlocker actions
*
*/
import {
DISABLE_GLOBAL_OVERLAY_BLOCKER,
ENABLE_GLOBAL_OVERLAY_BLOCKER,
} from '../constants/overlayBlocker';
export function disableGlobalOverlayBlocker() {
return {
type: DISABLE_GLOBAL_OVERLAY_BLOCKER,
};
}
export function enableGlobalOverlayBlocker() {
return {
type: ENABLE_GLOBAL_OVERLAY_BLOCKER,
};
}

View File

@ -4,7 +4,7 @@
height: 6rem;
width: 6.5rem;
line-height: 6rem;
z-index: 999999;
z-index: 999;
text-align: center;
background-color: #FFFFFF;
color: #81848A;

View File

@ -7,6 +7,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import cn from 'classnames';
import styles from './styles.scss';
@ -22,11 +24,32 @@ class OverlayBlocker extends React.Component {
}
render() {
const content = this.props.children ? (
this.props.children
) : (
<div className={styles.container}>
<div className={styles.icoContainer}>
<i className="fa fa-refresh" />
</div>
<div>
<h4>
<FormattedMessage id="components.OverlayBlocker.title" />
</h4>
<p>
<FormattedMessage id="components.OverlayBlocker.description" />
</p>
<div className={styles.buttonContainer}>
<a className={cn(styles.primary, 'btn')} href="https://strapi.io/documentation/configurations/configurations.html#server" target="_blank">Read the documentation</a>
</div>
</div>
</div>
);
if (this.props.isOpen) {
return ReactDOM.createPortal(
<div className={styles.overlay}>
<div>
{this.props.children}
{content}
</div>
</div>,
this.overlayContainer

View File

@ -1,3 +1,35 @@
.container {
display: flex;
justify-content: center;
> div {
padding-top: 2.5rem;
> h4 {
font-size: 24px;
font-weight: 700;
line-height: 24px;
margin-bottom: 0;
}
> p {
margin-top: -1px;
font-size: 14px;
color: #919BAE;
}
}
}
.icoContainer {
padding-top: 0 !important;
font-size: 4.2rem;
color: #323740;
margin-right: 20px;
line-height: 9.3rem;
> i {
-webkit-animation:spin 4s linear infinite;
-moz-animation:spin 4s linear infinite;
animation:spin 4s linear infinite;
}
}
.overlay {
position: fixed;
top: 0;
@ -5,12 +37,86 @@
bottom: 0;
left: 0;
z-index: 1040;
background-color: rgba(0, 0, 0, 0.5);
&:before {
position: fixed;
content: '';
top: 6rem;
right: 0;
bottom: 0;
left: 0;
background: linear-gradient(rgba(0,0,0, 15) 0%, rgba(0,0,0,0) 100%);
opacity: 0.5;
}
&:after {
content:'';
position: fixed;
top: 6rem;
right: 0;
bottom: 0;
left: 24rem;
background: linear-gradient(#FBFBFB 20%, rgba(0, 0, 100, 0) 100%);
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.1);
box-shadow: inset 0 1px 2px 0 rgba(40, 42, 49, 0.16);
}
> div {
position: fixed;
top: 17.5rem;
top: 11.5rem;
left: 50%;
margin-left: -24rem;
margin-left: -17.5rem;
z-index: 1100;
}
}
.buttonContainer {
padding-top: 3.9rem;
> a {
height: 30px;
font-size: 13px;
}
}
.primary {
min-width: 15rem;
padding-top: 4px;
padding-left: 1.6rem;
padding-right: 1.6rem;
border-radius: 0.3rem;
border: none;
background: linear-gradient(315deg, #0097F6 0%, #005EEA 100%);
color: white;
font-family: Lato;
font-weight: 600;
-webkit-font-smoothing: antialiased;
cursor: pointer;
> i {
margin-right: 1.3rem;
font-weight: 600;
padding-top: 1px;
}
&:before {
content: '\f02d';
font-family: 'FontAwesome';
font-weight: 600;
font-size: 1.3rem;
margin-right: 13px;
}
&:active {
box-shadow: inset 1px 1px 3px rgba(0,0,0,.15);
}
&:focus {
outline: 0;
}
&:hover {
color: white;
}
}
@-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }

View File

@ -0,0 +1,8 @@
/*
*
* Shared OverlayBlocker constants
*
*/
export const DISABLE_GLOBAL_OVERLAY_BLOCKER = 'strapiHelperPlugin/OverlayBlocker/DISABLE_GLOBAL_OVERLAY_BLOCKER';
export const ENABLE_GLOBAL_OVERLAY_BLOCKER = 'strapiHelperPlugin/OverlayBlocker/ENABLE_GLOBAL_OVERLAY_BLOCKER';

View File

@ -1,5 +1,6 @@
import 'whatwg-fetch';
import auth from 'utils/auth';
/**
* Parses the JSON returned by a network request
*
@ -86,6 +87,8 @@ function serverRestartWatcher(response) {
}
})
.then(() => {
// Hide the global OverlayBlocker
strapi.unlockApp();
resolve(response);
})
.catch(err => {
@ -141,6 +144,8 @@ export default function request(url, options = {}, shouldWatchServerRestart = fa
.then(parseJSON)
.then((response) => {
if (shouldWatchServerRestart) {
// Display the global OverlayBlocker
strapi.lockApp();
return serverRestartWatcher(response);
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-helper-plugin",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Helper for Strapi plugins development",
"engines": {
"node": ">= 8.0.0",
@ -21,9 +21,8 @@
"license": "MIT",
"scripts": {
"lint": "cross-env IS_HELPER=true ./node_modules/eslint/bin/eslint.js --ignore-path .gitignore --config ./lib/internals/eslint/eslint-config.js .",
"pretest": "npm run lint",
"prettier": "prettier --single-quote --trailing-comma es5 --write \"{lib,__{tests,mocks}__}/**/*.js\"",
"test": "echo Tests are not implemented."
"test": "npm run lint"
},
"pre-commit": [
"lint:admin"

View File

@ -1,6 +1,6 @@
{
"name": "strapi-knex",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Knex hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-middleware-views",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Views hook to enable server-side rendering for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -43,11 +43,14 @@ module.exports = function (strapi) {
const { host, port, username, password, database } = _.defaults(connection.settings, strapi.config.hook.settings.mongoose);
// Connect to mongo database
if (_.isEmpty(username) || _.isEmpty(password)) {
instance.connect(`mongodb://${host}:${port}/${database}`);
} else {
instance.connect(`mongodb://${username}:${password}@${host}:${port}/${database}`);
const connectOptions = {}
if (!_.isEmpty(username)) {
connectOptions.user = username
if (!_.isEmpty(password)) {
connectOptions.pass = password
}
}
instance.connect(`mongodb://${host}:${port}/${database}`, connectOptions);
// Handle error
instance.connection.on('error', error => {

View File

@ -9,8 +9,16 @@ const logger = require('strapi-utils').logger;
module.exports = (scope, success, error) => {
const Mongoose = require(path.resolve(`${scope.rootPath}/node_modules/mongoose`));
Mongoose.connect(`mongodb://${ (scope.database.settings.username && scope.database.settings.password) ? `${scope.database.settings.username}:${scope.database.settings.password}@` : '' }${scope.database.settings.host}:${scope.database.settings.port}/${scope.database.settings.database}`, function (err) {
const { username, password } = scope.database.settings
const connectOptions = {}
if (username) {
connectOptions.user = username
if (password) {
connectOptions.pass = password
}
}
Mongoose.connect(`mongodb://${scope.database.settings.host}:${scope.database.settings.port}/${scope.database.settings.database}`, connectOptions, function (err) {
if (err) {
logger.warn('Database connection has failed! Make sure your database is running.');
return error();

View File

@ -1,6 +1,6 @@
{
"name": "strapi-mongoose",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Mongoose hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [
@ -19,7 +19,7 @@
"mongoose": "^5.0.0-rc1",
"mongoose-float": "^1.0.2",
"pluralize": "^6.0.0",
"strapi-utils": "3.0.0-alpha.7.3"
"strapi-utils": "3.0.0-alpha.8.3"
},
"strapi": {
"isHook": true

View File

@ -1,6 +1,5 @@
# Don't check auto-generated stuff into git
coverage
build
node_modules
stats.json
package-lock.json

View File

@ -1,28 +1,7 @@
{
"name": "strapi-plugin-content-manager",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "A powerful UI to easily manage your data.",
"engines": {
"node": ">= 8.0.0",
"npm": ">= 5.3.0"
},
"author": {
"email": "hi@strapi.io",
"name": "Strapi team",
"url": "http://strapi.io"
},
"maintainers": [
{
"name": "Strapi team",
"email": "hi@strapi.io",
"url": "http://strapi.io"
}
],
"repository": {
"type": "git",
"url": "git://github.com/strapi/strapi.git"
},
"license": "MIT",
"strapi": {
"name": "Content Manager",
"icon": "plug",
@ -38,14 +17,34 @@
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
"start": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development PLUGIN=true node ./node_modules/strapi-helper-plugin/lib/server",
"generate": "node ./node_modules/plop/plop.js --plopfile ./node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"pretest": "npm run lint",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --ignore-pattern '/admin/build/' --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"prettier": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
"test": "echo Tests are not implemented.",
"test": "npm run lint",
"prepublishOnly": "npm run build"
},
"devDependencies": {
"react-select": "^1.0.0-rc.5",
"strapi-helper-plugin": "3.0.0-alpha.7.3"
}
}
"strapi-helper-plugin": "3.0.0-alpha.8.3"
},
"author": {
"name": "Strapi team",
"email": "hi@strapi.io",
"url": "http://strapi.io"
},
"maintainers": [
{
"name": "Strapi team",
"email": "hi@strapi.io",
"url": "http://strapi.io"
}
],
"repository": {
"type": "git",
"url": "git://github.com/strapi/strapi.git"
},
"engines": {
"node": ">= 8.0.0",
"npm": ">= 3.0.0"
},
"license": "MIT"
}

View File

@ -1,6 +1,5 @@
# Dont check auto-generated stuff into git
coverage
build
node_modules
stats.json

View File

@ -45,7 +45,11 @@ class TableList extends React.Component { // eslint-disable-line react/prefer-st
</div>
</li>
{map(this.props.rowItems, (rowItem, key) => (
<TableListRow key={key} rowItem={rowItem} onDelete={this.props.onHandleDelete} />
<TableListRow
key={key}
onDelete={this.props.onHandleDelete}
rowItem={rowItem}
/>
))}
</ul>
</div>

View File

@ -20,6 +20,7 @@ import NotFoundPage from 'containers/NotFoundPage';
import formSaga from 'containers/Form/sagas';
import formReducer from 'containers/Form/reducer';
// Other containers actions
import { makeSelectShouldRefetchContentType } from 'containers/Form/selectors';
// Utils

View File

@ -7,15 +7,13 @@ export function* deleteContentType(action) {
try {
if (action.sendRequest) {
const requestUrl = `/content-type-builder/models/${action.itemToDelete}`;
const response = yield call(request, requestUrl, { method: 'DELETE' }, true);
yield call(request, requestUrl, { method: 'DELETE' });
if (action.updateLeftMenu) {
if (response.ok && action.updateLeftMenu) {
action.updatePlugin('content-manager', 'leftMenuSections', action.leftMenuContentTypes);
strapi.notification.success('content-type-builder.notification.success.contentTypeDeleted');
}
strapi.notification.success('content-type-builder.notification.success.contentTypeDeleted');
}
} catch(error) {
strapi.notification.error('content-type-builder.notification.error.message');
}

View File

@ -41,6 +41,6 @@ const selectLocationState = () => {
export {
selectLocationState,
makeSelectLoading,
makeSelectModels,
makeSelectMenu,
makeSelectModels,
};

View File

@ -254,6 +254,7 @@ export class Form extends React.Component { // eslint-disable-line react/prefer-
this.props.contentTypeCreate(contentType);
}
this.setState({ showModal: false });
return this.props.contentTypeEdit(this.context);
}

View File

@ -69,8 +69,8 @@ export class HomePage extends React.Component { // eslint-disable-line react/pre
title={title}
buttonLabel={'content-type-builder.button.contentType.add'}
onButtonClick={this.handleButtonClick}
rowItems={this.props.models}
onHandleDelete={this.handleDelete}
rowItems={this.props.models}
/>
);
}

View File

@ -76,8 +76,6 @@ export class ModelPage extends React.Component { // eslint-disable-line react/pr
if (this.props.updatedContentType !== nextProps.updatedContentType) {
if (this.state.contentTypeTemporary && storeData.getContentType()) {
this.props.modelFetchSucceeded({ model: storeData.getContentType() });
} else {
this.fetchModel(nextProps);
}
}
@ -86,24 +84,24 @@ export class ModelPage extends React.Component { // eslint-disable-line react/pr
}
}
componentWillUpdate(nextProps) {
if (!isEmpty(nextProps.menu)) {
const allowedPaths = nextProps.menu.reduce((acc, current) => {
const models = current.items.reduce((acc, current) => {
acc.push(current.name);
return acc;
}, []);
return acc.concat(models);
}, []);
const shouldRedirect = allowedPaths.filter(el => el === this.props.match.params.modelName.split('&')[0]).length === 0;
if (shouldRedirect) {
this.props.history.push('/404');
}
}
}
// componentWillUpdate(nextProps) {
// if (!isEmpty(nextProps.menu)) {
// const allowedPaths = nextProps.menu.reduce((acc, current) => {
// const models = current.items.reduce((acc, current) => {
// acc.push(current.name);
//
// return acc;
// }, []);
// return acc.concat(models);
// }, []);
//
// const shouldRedirect = allowedPaths.filter(el => el === this.props.match.params.modelName.split('&')[0]).length === 0;
//
// if (shouldRedirect) {
// this.props.history.push('/404');
// }
// }
// }
componentDidUpdate(prevProps) {
if (prevProps.match.params.modelName !== this.props.match.params.modelName) {
@ -347,7 +345,7 @@ ModelPage.propTypes = {
cancelChanges: PropTypes.func.isRequired,
checkIfTableExists: PropTypes.func.isRequired,
deleteAttribute: PropTypes.func.isRequired,
history: PropTypes.object.isRequired,
// history: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
match: PropTypes.object.isRequired,
menu: PropTypes.array.isRequired,

View File

@ -140,7 +140,6 @@ export function* submitChanges(action) {
}
yield put(submitActionSucceeded());
yield put(resetShowButtonsProps());
// Remove loader
yield put(unsetButtonLoader());

View File

@ -3,7 +3,7 @@ import request from 'utils/request';
const shouldRenderCompo = (plugin) => new Promise((resolve, reject) => {
request(`${strapi.backendURL}/content-type-builder/autoReload`)
.then(response => {
plugin.preventComponentRendering = !response.autoReload;
plugin.preventComponentRendering = !response.autoReload.enabled;
plugin.blockerComponentProps = {
blockerComponentTitle: 'components.AutoReloadBlocker.header',
blockerComponentDescription: 'components.AutoReloadBlocker.description',

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-content-type-builder",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Strapi plugin to create content type (API).",
"strapi": {
"name": "Content Type Builder",
@ -17,19 +17,18 @@
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
"start": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node ./node_modules/strapi-helper-plugin/lib/server",
"generate": "node ./node_modules/plop/plop.js --plopfile node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"pretest": "npm run lint",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --ignore-pattern '/admin/build/' --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"prettier": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
"test": "echo Tests are not implemented.",
"test": "npm run lint",
"prepublishOnly": "npm run build"
},
"dependencies": {
"pluralize": "^7.0.0",
"strapi-generate": "3.0.0-alpha.7.3",
"strapi-generate-api": "3.0.0-alpha.7.3"
"strapi-generate": "3.0.0-alpha.8.3",
"strapi-generate-api": "3.0.0-alpha.8.3"
},
"devDependencies": {
"strapi-helper-plugin": "3.0.0-alpha.7.3"
"strapi-helper-plugin": "3.0.0-alpha.8.3"
},
"author": {
"name": "Strapi team",
@ -43,6 +42,10 @@
"url": "http://strapi.io"
}
],
"repository": {
"type": "git",
"url": "git://github.com/strapi/strapi.git"
},
"engines": {
"node": ">= 8.0.0",
"npm": ">= 3.0.0"

View File

@ -1,6 +1,5 @@
# Don't check auto-generated stuff into git
coverage
build
node_modules
stats.json

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-email",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "This is the description of the plugin.",
"strapi": {
"name": "Email",
@ -8,42 +8,45 @@
"description": "email.plugin.description"
},
"scripts": {
"analyze:clean": "node node_modules/strapi-helper-plugin/node_modules/.bin/rimraf stats.json",
"analyze:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf stats.json",
"preanalyze": "npm run analyze:clean",
"analyze": "node node_modules/strapi-helper-plugin/lib/internals/scripts/analyze.js",
"analyze": "node ./node_modules/strapi-helper-plugin/lib/internals/scripts/analyze.js",
"prebuild": "npm run build:clean && npm run test",
"build:dev": "node node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress",
"build": "node node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production node node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress",
"build:clean": "node node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
"start": "node node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node node_modules/strapi-helper-plugin/lib/server",
"generate": "node node_modules/plop/plop.js --plopfile node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
"lint": "node node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --config node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"pretest": "npm run lint",
"prettier": "node node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
"test": "echo Tests are not implemented.",
"build:dev": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node ./node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress",
"build": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production node node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress",
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
"start": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node ./node_modules/strapi-helper-plugin/lib/server",
"generate": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/plop --plopfile ./node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --ignore-pattern '/admin/build/' --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"prettier": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
"test": "npm run lint",
"prepublishOnly": "npm run build"
},
"dependencies": {
"sendmail": "^1.2.0"
},
"devDependencies": {
"strapi-helper-plugin": "3.0.0-alpha.7.3"
"strapi-helper-plugin": "3.0.0-alpha.8.3"
},
"author": {
"name": "A Strapi developer",
"email": "",
"url": ""
"name": "Strapi team",
"email": "hi@strapi.io",
"url": "http://strapi.io"
},
"maintainers": [
{
"name": "A Strapi developer",
"email": "",
"url": ""
"name": "Strapi team",
"email": "hi@strapi.io",
"url": "http://strapi.io"
}
],
"repository": {
"type": "git",
"url": "git://github.com/strapi/strapi.git"
},
"engines": {
"node": ">= 7.0.0",
"npm": ">= 3.0.0"
},
"license": "MIT"
}
}

View File

@ -5,26 +5,12 @@
*/
import {
MENU_FETCH,
ENVIRONMENTS_FETCH,
MENU_FETCH_SUCCEEDED,
ENVIRONMENTS_FETCH_SUCCEEDED,
MENU_FETCH_SUCCEEDED,
MENU_FETCH,
} from './constants';
export function menuFetch() {
return {
type: MENU_FETCH,
};
}
export function fetchMenuSucceeded(menu) {
return {
type: MENU_FETCH_SUCCEEDED,
menu,
};
}
export function environmentsFetch() {
return {
type: ENVIRONMENTS_FETCH,
@ -37,3 +23,16 @@ export function environmentsFetchSucceeded(environments) {
environments,
};
}
export function fetchMenuSucceeded(menu) {
return {
type: MENU_FETCH_SUCCEEDED,
menu,
};
}
export function menuFetch() {
return {
type: MENU_FETCH,
};
}

View File

@ -4,7 +4,7 @@
*
*/
export const MENU_FETCH = 'SettingsManager/App/MENU_FETCH';
export const ENVIRONMENTS_FETCH = 'SettingsManager/App/ENVIRONMENTS_FETCH';
export const MENU_FETCH_SUCCEEDED = 'SettingsManager/App/MENU_FETCH_SUCCEEDED';
export const ENVIRONMENTS_FETCH_SUCCEEDED = 'SettingsManager/App/ENVIRONMENTS_FETCH_SUCCEEDED';
export const MENU_FETCH = 'SettingsManager/App/MENU_FETCH';
export const MENU_FETCH_SUCCEEDED = 'SettingsManager/App/MENU_FETCH_SUCCEEDED';

View File

@ -6,24 +6,23 @@
import { fromJS, List } from 'immutable';
import {
MENU_FETCH_SUCCEEDED,
ENVIRONMENTS_FETCH_SUCCEEDED,
MENU_FETCH_SUCCEEDED,
} from './constants';
/* eslint-disable new-cap */
const initialState = fromJS({
sections: List(), // eslint-disable-line new-cap
environments: List(),
sections: List([]),
environments: List([]),
loading: true,
});
function appReducer(state = initialState, action) {
switch (action.type) {
case MENU_FETCH_SUCCEEDED:
return state.set('sections', List(action.menu.sections)).set('loading', false);
case ENVIRONMENTS_FETCH_SUCCEEDED:
return state
.set('environments', List(action.environments.environments));
case MENU_FETCH_SUCCEEDED:
return state.set('sections', List(action.menu.sections)).set('loading', false);
default:
return state;
}

View File

@ -37,5 +37,10 @@ const makeSelectLoading = () => createSelector(
(globalSate) => globalSate.get('loading'),
);
export { selectLocationState, makeSelectSections, makeSelectEnvironments, makeSelectLoading };
export {
makeSelectEnvironments,
makeSelectLoading,
makeSelectSections,
selectLocationState,
};
export default selectGlobalDomain;

View File

@ -1,5 +1,4 @@
import { LOCATION_CHANGE } from 'react-router-redux';
import { forEach, set, map, replace } from 'lodash';
import { call, take, put, fork, cancel, select, takeLatest } from 'redux-saga/effects';
import request from 'utils/request';
@ -86,7 +85,6 @@ export function* deleteLanguage(action) {
method: 'DELETE',
};
const requestUrl = `/settings-manager/configurations/languages/${action.languageToDelete}`;
const resp = yield call(request, requestUrl, opts, true);
if (resp.ok) {
@ -152,7 +150,6 @@ export function* fetchLanguages() {
export function* postLanguage() {
try {
const newLanguage = yield select(makeSelectModifiedData());
const body = {
name: newLanguage['language.defaultLocale'],
};
@ -161,12 +158,11 @@ export function* postLanguage() {
method: 'POST',
};
const requestUrl = '/settings-manager/configurations/languages';
const resp = yield call(request, requestUrl, opts, true);
if (resp.ok) {
strapi.notification.success('settings-manager.strapi.notification.success.languageAdd');
yield put(languageActionSucceeded());
strapi.notification.success('settings-manager.strapi.notification.success.languageAdd');
}
} catch(error) {
yield put(languageActionError());
@ -187,7 +183,6 @@ export function* postDatabase(action) {
body,
};
const requestUrl = `/settings-manager/configurations/databases/${action.endPoint}`;
const resp = yield call(request, requestUrl, opts, true);
if (resp.ok) {
@ -203,7 +198,6 @@ export function* postDatabase(action) {
});
yield put(databaseActionError(formErrors));
strapi.notification.error('settings-manager.strapi.notification.error');
}
}
@ -221,13 +215,13 @@ export function* settingsEdit(action) {
const resp = yield call(request, requestUrl, opts, true);
if (resp.ok) {
strapi.notification.success('settings-manager.strapi.notification.success.settingsEdit');
yield put(editSettingsSucceeded());
yield put(unsetLoader());
strapi.notification.success('settings-manager.strapi.notification.success.settingsEdit');
}
} catch(error) {
strapi.notification.error('settings-manager.strapi.notification.error');
yield put(unsetLoader());
strapi.notification.error('settings-manager.strapi.notification.error');
}
}
@ -237,7 +231,6 @@ export function* fetchSpecificDatabase(action) {
method: 'GET',
};
const requestUrl = `/settings-manager/configurations/databases/${action.databaseName}/${action.endPoint}`;
const data = yield call(request, requestUrl, opts);
yield put(specificDatabaseFetchSucceeded(data));

View File

@ -1,126 +0,0 @@
import 'whatwg-fetch';
import { startsWith } from 'lodash';
import auth from 'utils/auth';
/**
* Parses the JSON returned by a network request
*
* @param {object} response A response from a network request
*
* @return {object} The parsed JSON from the request
*/
function parseJSON(response) {
return response.json();
}
/**
* Checks if a network request came back fine, and throws an error if not
*
* @param {object} response A response from a network request
*
* @return {object|undefined} Returns either the response, or throws an error
*/
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
}
return parseJSON(response).then(responseFormatted => {
const error = new Error(response.statusText);
error.response = response;
error.response.payload = responseFormatted;
throw error;
});
}
/**
* Format query params
*
* @param params
* @returns {string}
*/
function formatQueryParams(params) {
return Object.keys(params)
.map(k => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`)
.join('&');
}
/**
* Server restart watcher
* @param response
* @returns {object} the response data
*/
function serverRestartWatcher(response) {
return new Promise((resolve) => {
fetch(`${strapi.backendURL}/_health`, {
method: 'HEAD',
mode: 'no-cors',
headers: {
'Content-Type': 'application/json',
'Keep-Alive': false,
},
})
.then(() => {
resolve(response);
})
.catch(() => {
setTimeout(() => {
return serverRestartWatcher(response)
.then(resolve);
}, 100);
});
});
}
/**
* Requests a URL, returning a promise
*
* @param {string} url The URL we want to request
* @param {object} [options] The options we want to pass to "fetch"
*
* @return {object} The response data
*/
export default function request(url, options, shouldWatchServerRestart = false) {
const optionsObj = options || {};
// Set headers
optionsObj.headers = {
'Content-Type': 'application/json',
'X-Forwarded-Host': 'strapi',
};
const token = auth.getToken();
if (token) {
optionsObj.headers = Object.assign({
'Authorization': `Bearer ${token}`,
}, optionsObj.headers);
}
// Add parameters to url
let urlFormatted = startsWith(url, '/')
? `${strapi.backendURL}${url}`
: url;
if (optionsObj && optionsObj.params) {
const params = formatQueryParams(optionsObj.params);
urlFormatted = `${url}?${params}`;
}
// Stringify body object
if (optionsObj && optionsObj.body) {
optionsObj.body = JSON.stringify(optionsObj.body);
}
return fetch(urlFormatted, optionsObj)
.then(checkStatus)
.then(parseJSON)
.then((response) => {
if (shouldWatchServerRestart) {
return serverRestartWatcher(response);
}
return response;
});
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-settings-manager",
"version": "3.0.0-alpha.7.3",
"version": "3.0.0-alpha.8.3",
"description": "Strapi plugin to manage settings.",
"strapi": {
"name": "Settings Manager",
@ -17,16 +17,15 @@
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
"start": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node ./node_modules/strapi-helper-plugin/lib/server",
"generate": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/plop --plopfile ./node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"pretest": "npm run lint",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --ignore-pattern '/admin/build/' --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"prettier": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
"test": "echo Tests are not implemented.",
"test": "npm run lint",
"prepublishOnly": "npm run build"
},
"devDependencies": {
"flag-icon-css": "^2.8.0",
"react-select": "^1.0.0-rc.5",
"strapi-helper-plugin": "3.0.0-alpha.7.3"
"strapi-helper-plugin": "3.0.0-alpha.8.3"
},
"author": {
"name": "Strapi team",
@ -40,9 +39,13 @@
"url": "http://strapi.io"
}
],
"repository": {
"type": "git",
"url": "git://github.com/strapi/strapi.git"
},
"engines": {
"node": ">= 8.0.0",
"npm": ">= 3.0.0"
},
"license": "MIT"
}
}

View File

@ -5,6 +5,7 @@ node_modules
stats.json
roles.json
jwt.json
grant.json
# Cruft
.DS_Store

View File

@ -48,7 +48,7 @@ const generateListTitle = (data, settingType) => {
}
};
function List({ data, deleteActionSucceeded, deleteData, noButton, onButtonClick, settingType }) {
function List({ data, deleteData, noButton, onButtonClick, settingType }) {
return (
<div className={styles.list}>
<div className={styles.flex}>
@ -69,7 +69,6 @@ function List({ data, deleteActionSucceeded, deleteData, noButton, onButtonClick
<ul className={noButton ? styles.listPadded : ''}>
{map(data, item => (
<ListRow
deleteActionSucceeded={deleteActionSucceeded}
deleteData={deleteData}
item={item}
key={item.name}
@ -89,7 +88,6 @@ List.defaultProps = {
List.propTypes = {
data: PropTypes.array.isRequired,
deleteActionSucceeded: PropTypes.bool.isRequired,
deleteData: PropTypes.func.isRequired,
noButton: PropTypes.bool,
onButtonClick: PropTypes.func,

View File

@ -19,12 +19,6 @@ import styles from './styles.scss';
class ListRow extends React.Component { // eslint-disable-line react/prefer-stateless-function
state = { showModalDelete: false };
componentWillReceiveProps(nextProps) {
if (nextProps.deleteActionSucceeded !== this.props.deleteActionSucceeded) {
this.setState({ showModalDelete: false });
}
}
// Roles that can't be deleted && modified
// Don't delete this line
protectedRoleIDs = ['root'];
@ -46,11 +40,11 @@ class ListRow extends React.Component { // eslint-disable-line react/prefer-stat
switch (this.props.settingType) {
case 'roles':
if (includes(this.protectedRoleIDs, get(this.props.item, 'id').toString())) {
if (includes(this.protectedRoleIDs, get(this.props.item, 'type').toString())) {
icons = [];
}
if (includes(this.undeletableIDs, get(this.props.item, 'id').toString())) {
if (includes(this.undeletableIDs, get(this.props.item, 'type').toString())) {
icons = [{ icoType: 'pencil', onClick: this.handleClick }];
}
@ -135,7 +129,7 @@ class ListRow extends React.Component { // eslint-disable-line react/prefer-stat
handleClick = () => {
switch (this.props.settingType) {
case 'roles': {
if (!includes(this.protectedRoleIDs, get(this.props.item, 'id').toString())) {
if (!includes(this.protectedRoleIDs, get(this.props.item, 'type').toString())) {
return router.push(`${router.location.pathname}/edit/${this.props.item.id}`);
}
return;
@ -148,7 +142,10 @@ class ListRow extends React.Component { // eslint-disable-line react/prefer-stat
}
}
handleDelete = () => this.props.deleteData(this.props.item, this.props.settingType);
handleDelete = () => {
this.props.deleteData(this.props.item, this.props.settingType);
this.setState({ showModalDelete: false });
}
render() {
return (
@ -176,7 +173,6 @@ ListRow.defaultProps = {
};
ListRow.propTypes = {
deleteActionSucceeded: PropTypes.bool.isRequired,
deleteData: PropTypes.func.isRequired,
item: PropTypes.object,
settingType: PropTypes.string,

View File

@ -117,7 +117,7 @@ Plugin.propTypes = {
plugin: PropTypes.shape({
description: PropTypes.string,
information: PropTypes.shape({
logo: PropTypes.string.isRequired,
logo: PropTypes.string,
}),
}),
pluginSelected: PropTypes.string.isRequired,

View File

@ -5,5 +5,3 @@
*/
// const selectGlobalDomain = () => state => state.get('global');
export {};

View File

@ -8,6 +8,7 @@ import {
take,
takeLatest,
} from 'redux-saga/effects';
import request from 'utils/request';
import {
@ -98,7 +99,7 @@ export function* submit() {
};
const requestURL = actionType === 'POST' ? '/users-permissions/roles' : `/users-permissions/roles/${roleId}`;
const response = yield call(request, requestURL, opts);
const response = yield call(request, requestURL, opts, true);
if (response.ok) {
yield put(submitSucceeded());

View File

@ -116,7 +116,6 @@ export class HomePage extends React.Component {
<EditForm onChange={this.props.onChange} values={this.props.modifiedData} /> : (
<List
data={this.props.data}
deleteActionSucceeded={this.props.deleteActionSucceeded}
deleteData={this.props.deleteData}
noButton={noButtonList}
onButtonClick={this.handleButtonClick}
@ -161,7 +160,6 @@ HomePage.defaultProps = {};
HomePage.propTypes = {
data: PropTypes.array.isRequired,
deleteActionSucceeded: PropTypes.bool.isRequired,
deleteData: PropTypes.func.isRequired,
fetchData: PropTypes.func.isRequired,
history: PropTypes.object.isRequired,

View File

@ -17,7 +17,6 @@ import {
const initialState = fromJS({
data: List([]),
dataToDelete: Map({}),
deleteActionSucceeded: false,
deleteEndPoint: '',
initialData: Map({}),
modifiedData: Map({}),
@ -34,8 +33,7 @@ function homePageReducer(state = initialState, action) {
return state
.update('data', list => list.splice(action.indexDataToDelete, 1))
.set('deleteEndPoint', '')
.set('dataToDelete', Map({}))
.set('deleteActionSucceeded', !state.get('deleteActionSucceeded'));
.set('dataToDelete', Map({}));
case FETCH_DATA_SUCCEEDED:
return state.set('data', List(action.data));
case ON_CHANGE:

View File

@ -1,6 +1,7 @@
import { LOCATION_CHANGE } from 'react-router-redux';
import { findIndex } from 'lodash';
import { takeLatest, put, fork, take, cancel, select, call } from 'redux-saga/effects';
import request from 'utils/request';
import {
@ -8,6 +9,7 @@ import {
fetchDataSucceeded,
setForm,
} from './actions';
import {
DELETE_DATA,
FETCH_DATA,
@ -32,8 +34,7 @@ export function* dataDelete() {
if (indexDataToDelete !== -1) {
const id = dataToDelete.id;
const requestURL = `/users-permissions/${endPointAPI}/${id}`;
// TODO watchServerRestart
const response = yield call(request, requestURL, { method: 'DELETE' });
const response = yield call(request, requestURL, { method: 'DELETE' }, true);
if (response.ok) {
yield put(deleteDataSucceeded(indexDataToDelete));

View File

@ -28,6 +28,47 @@ module.exports = cb => {
}
}
if (!_.get(strapi.plugins['users-permissions'], 'config.grant')) {
try {
const grant = {
facebook: {
key: '',
secret: '',
callback: '/auth/facebook/callback',
scope: ['email']
},
google: {
key: '',
secret: '',
callback: '/auth/google/callback',
scope: ['email']
},
github: {
key: '',
secret: '',
redirect_uri: '/auth/google/callback',
scope: [
'user',
'user:email'
]
},
twitter: {
key: '',
secret: '',
callback: '/auth/twitter/callback'
}
};
fs.writeFileSync(path.join(strapi.config.appPath, 'plugins', 'users-permissions', 'config', 'grant.json'), JSON.stringify({
grant
}, null, 2), 'utf8');
_.set(strapi.plugins['users-permissions'], 'config.grant', grant);
} catch(err) {
strapi.log.error(err);
}
}
strapi.plugins['users-permissions'].services.userspermissions.syncSchema(() => {
strapi.plugins['users-permissions'].services.userspermissions.initialize(cb);
});

View File

@ -25,7 +25,7 @@ module.exports = async (ctx, next) => {
if (!role) {
role = await strapi.query('role', 'users-permissions').findOne({ type: 'guest' }, []);
}
const route = ctx.request.route;
const permission = await strapi.query('permission', 'users-permissions').findOne({
role: role._id || role.id,

View File

@ -116,6 +116,15 @@
"prefix": ""
}
},
{
"method": "GET",
"path": "/auth/:provider/callback",
"handler": "Auth.callback",
"config": {
"policies": [],
"prefix": ""
}
},
{
"method": "POST",
"path": "/auth/forgot-password",

View File

@ -8,12 +8,12 @@
const _ = require('lodash');
const crypto = require('crypto');
const emailRegExp = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
module.exports = {
callback: async (ctx) => {
const provider = ctx.params.provider || 'local';
const params = ctx.request.body;
const access_token = ctx.query.access_token;
if (provider === 'local') {
// The identifier is required.
@ -29,11 +29,11 @@ module.exports = {
const query = {};
// Check if the provided identifier is an email or not.
const isEmail = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(params.identifier);
const isEmail = emailRegExp.test(params.identifier);
// Set the identifier to the appropriate query field.
if (isEmail) {
query.email = params.identifier;
query.email = params.identifier.toLowerCase();
} else {
query.username = params.identifier;
}
@ -66,9 +66,12 @@ module.exports = {
}
} else {
// Connect the user thanks to the third-party provider.
const user = await strapi.api.user.services.grant.connect(provider, access_token);
const user = await strapi.plugins['users-permissions'].services.providers.connect(provider, ctx.query);
ctx.redirect(strapi.config.frontendUrl || strapi.config.url + '?jwt=' + strapi.api.user.services.jwt.issue(user) + '&user=' + JSON.stringify(user));
ctx.send({
jwt: strapi.plugins['users-permissions'].services.jwt.issue(user),
user: _.omit(user.toJSON ? user.toJSON() : user, ['password', 'resetPasswordToken'])
});
}
},
@ -175,6 +178,13 @@ module.exports = {
return ctx.badRequest(null, ctx.request.admin ? [{ messages: [{ id: 'Auth.form.error.role.notFound' }] }] : 'Impossible to find the root role.');
}
// Check if the provided identifier is an email or not.
const isEmail = emailRegExp.test(params.identifier);
if (isEmail) {
params.identifier = params.identifier.toLowerCase();
}
params.role = role._id || role.id;
params.password = await strapi.plugins['users-permissions'].services.user.hashPassword(params);

View File

@ -20,10 +20,14 @@ module.exports = {
return ctx.badRequest(null, [{ messages: [{ id: 'Cannot be empty' }] }]);
}
strapi.reload.isWatching = false;
try {
await strapi.plugins['users-permissions'].services.userspermissions.createRole(ctx.request.body);
ctx.send({ ok: true });
strapi.reload();
} catch(err) {
ctx.badRequest(null, [{ messages: [{ id: 'An error occured' }] }]);
}

View File

@ -0,0 +1,5 @@
{
"provider": {
"enabled": true
}
}

View File

@ -0,0 +1,32 @@
'use strict';
/**
* Module dependencies
*/
// Public node modules.
const _ = require('lodash');
const Grant = require('grant-koa');
module.exports = strapi => {
return {
beforeInitialize: function() {
strapi.config.middleware.load.after.push('provider');
},
initialize: function(cb) {
_.defaultsDeep(strapi.plugins['users-permissions'].config.grant, {
server: {
protocol: 'http',
host: 'localhost:1337'
}
});
const grant = new Grant(strapi.plugins['users-permissions'].config.grant);
strapi.app.use(strapi.koaMiddlewares.compose(grant.middleware));
cb();
}
};
};

Some files were not shown because too many files have changed in this diff Show More