Merge branch 'master' into allow-new-input

This commit is contained in:
Jim LAURIE 2018-04-13 15:44:06 +02:00 committed by GitHub
commit 06555cf4d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 103 additions and 36 deletions

View File

@ -139,14 +139,14 @@ In order to do so, you'll need to allow access to other users (identified as 'Gu
To retrieve the list of products, use the `GET /your-content-type` route. To retrieve the list of products, use the `GET /your-content-type` route.
Generated APIs provide a handy way to filter and order queries. In that way, ordering products by price is as easy as `GET http://localhost:1337/product?_order=price:asc`. For more informations, read the [filters documentation](../guides/filters.md) Generated APIs provide a handy way to filter and order queries. In that way, ordering products by price is as easy as `GET http://localhost:1337/product?_sort=price:asc`. For more informations, read the [filters documentation](../guides/filters.md)
Here is an example using jQuery. Here is an example using jQuery.
```js ```js
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
url: 'http://localhost:1337/product?_order=price:asc', // Order by price. url: 'http://localhost:1337/product?_sort=price:asc', // Order by price.
done: function(products) { done: function(products) {
console.log('Well done, here is the list of products: ', products); console.log('Well done, here is the list of products: ', products);
}, },

View File

@ -6,6 +6,7 @@
import React from 'react'; import React from 'react';
import { defineMessages, FormattedMessage } from 'react-intl'; import { defineMessages, FormattedMessage } from 'react-intl';
import { PropTypes } from 'prop-types';
import LocaleToggle from 'containers/LocaleToggle'; import LocaleToggle from 'containers/LocaleToggle';
@ -13,15 +14,19 @@ import styles from './styles.scss';
import messages from './messages.json'; import messages from './messages.json';
defineMessages(messages); defineMessages(messages);
class LeftMenuFooter extends React.Component { // eslint-disable-line react/prefer-stateless-function function LeftMenuFooter({ version }) { // eslint-disable-line react/prefer-stateless-function
render() { return (
return ( <div className={styles.leftMenuFooter}>
<div className={styles.leftMenuFooter}> <FormattedMessage {...messages.poweredBy} />
<FormattedMessage {...messages.poweredBy} /> <a href="http://strapi.io" target="_blank">Strapi</a> <a href="http://strapi.io" target="_blank"> Strapi</a>
<LocaleToggle /> <span>&nbsp;(v{version})</span>
</div> <LocaleToggle />
); </div>
} );
} }
LeftMenuFooter.propTypes = {
version: PropTypes.string.isRequired,
};
export default LeftMenuFooter; export default LeftMenuFooter;

File diff suppressed because one or more lines are too long

View File

@ -8,6 +8,7 @@ import {
GET_GA_STATUS_SUCCEEDED, GET_GA_STATUS_SUCCEEDED,
GET_LAYOUT, GET_LAYOUT,
GET_LAYOUT_SUCCEEDED, GET_LAYOUT_SUCCEEDED,
GET_STRAPI_VERSION_SUCCEEDED,
} from './constants'; } from './constants';
export function getGaStatus() { export function getGaStatus() {
@ -35,3 +36,10 @@ export function getLayoutSucceeded(layout) {
layout, layout,
}; };
} }
export function getStrapiVersionSucceeded(strapiVersion) {
return {
type: GET_STRAPI_VERSION_SUCCEEDED,
strapiVersion,
};
}

View File

@ -8,3 +8,4 @@ export const GET_GA_STATUS = 'app/Admin/GET_GA_STATUS';
export const GET_GA_STATUS_SUCCEEDED = 'app/Admin/GET_GA_STATUS_SUCCEEDED'; export const GET_GA_STATUS_SUCCEEDED = 'app/Admin/GET_GA_STATUS_SUCCEEDED';
export const GET_LAYOUT = 'app/Admin/GET_LAYOUT'; export const GET_LAYOUT = 'app/Admin/GET_LAYOUT';
export const GET_LAYOUT_SUCCEEDED = 'app/Admin/GET_LAYOUT_SUCCEEDED'; export const GET_LAYOUT_SUCCEEDED = 'app/Admin/GET_LAYOUT_SUCCEEDED';
export const GET_STRAPI_VERSION_SUCCEEDED = 'app/Admin/GET_STRAPI_VERSION_SUCCEEDED';

View File

@ -137,13 +137,19 @@ export class AdminPage extends React.Component { // eslint-disable-line react/pr
showLeftMenu = () => !includes(this.props.location.pathname, 'users-permissions/auth/'); showLeftMenu = () => !includes(this.props.location.pathname, 'users-permissions/auth/');
render() { render() {
const leftMenu = this.showLeftMenu() ? <LeftMenu plugins={this.props.plugins} layout={this.props.adminPage.layout} /> : ''; const { adminPage } = this.props;
const header = this.showLeftMenu() ? <Header /> : ''; const header = this.showLeftMenu() ? <Header /> : '';
const style = this.showLeftMenu() ? {} : { width: '100%' }; const style = this.showLeftMenu() ? {} : { width: '100%' };
return ( return (
<div className={styles.adminPage}> <div className={styles.adminPage}>
{leftMenu} {this.showLeftMenu() && (
<LeftMenu
plugins={this.props.plugins}
layout={adminPage.layout}
version={adminPage.strapiVersion}
/>
)}
{ auth.getToken() && this.props.hasUserPlugin && this.isUrlProtected(this.props) ? ( { auth.getToken() && this.props.hasUserPlugin && this.isUrlProtected(this.props) ? (
<Logout /> <Logout />
) : ''} ) : ''}

View File

@ -6,11 +6,16 @@
import { fromJS, Map } from 'immutable'; import { fromJS, Map } from 'immutable';
import { GET_GA_STATUS_SUCCEEDED, GET_LAYOUT_SUCCEEDED } from './constants'; import {
GET_GA_STATUS_SUCCEEDED,
GET_LAYOUT_SUCCEEDED,
GET_STRAPI_VERSION_SUCCEEDED,
} from './constants';
const initialState = fromJS({ const initialState = fromJS({
allowGa: true, allowGa: true,
layout: Map({}), layout: Map({}),
strapiVersion: '3',
}); });
function adminPageReducer(state = initialState, action) { function adminPageReducer(state = initialState, action) {
@ -19,6 +24,8 @@ function adminPageReducer(state = initialState, action) {
return state.update('allowGa', () => action.allowGa); return state.update('allowGa', () => action.allowGa);
case GET_LAYOUT_SUCCEEDED: case GET_LAYOUT_SUCCEEDED:
return state.update('layout', () => Map(action.layout)); return state.update('layout', () => Map(action.layout));
case GET_STRAPI_VERSION_SUCCEEDED:
return state.update('strapiVersion', () => action.strapiVersion);
default: default:
return state; return state;
} }

View File

@ -1,13 +1,23 @@
import { take } from 'lodash';
import { fork, call, put, takeLatest } from 'redux-saga/effects'; import { fork, call, put, takeLatest } from 'redux-saga/effects';
import request from 'utils/request'; import request from 'utils/request';
import { getGaStatusSucceeded, getLayoutSucceeded } from './actions'; import {
getGaStatusSucceeded,
getLayoutSucceeded,
getStrapiVersionSucceeded,
} from './actions';
import { GET_GA_STATUS, GET_LAYOUT } from './constants'; import { GET_GA_STATUS, GET_LAYOUT } from './constants';
function* getGaStatus() { function* getGaStatus() {
try { try {
const response = yield call(request, '/admin/gaConfig', { method: 'GET' }); const [allowGa, strapiVersion] = yield [
yield put(getGaStatusSucceeded(response.allowGa)); call(request, '/admin/gaConfig', { method: 'GET' }),
call(request, '/admin/strapiVersion', { method: 'GET' }),
];
yield put(getGaStatusSucceeded(allowGa));
const version = take(`${strapiVersion.strapiVersion.split('.')[0]}${strapiVersion.strapiVersion.split('alpha')[1]}`, 4).join('');
yield put(getStrapiVersionSucceeded(version));
} catch(err) { } catch(err) {
strapi.notification.error('notification.error'); strapi.notification.error('notification.error');
} }

View File

@ -18,16 +18,21 @@ export class LeftMenu extends React.Component { // eslint-disable-line react/pre
render() { render() {
return ( return (
<div className={styles.leftMenu}> <div className={styles.leftMenu}>
<LeftMenuHeader></LeftMenuHeader> <LeftMenuHeader />
<LeftMenuLinkContainer {...this.props}></LeftMenuLinkContainer> <LeftMenuLinkContainer {...this.props} />
<LeftMenuFooter plugins={this.props.plugins}></LeftMenuFooter> <LeftMenuFooter plugins={this.props.plugins} version={this.props.version} />
</div> </div>
); );
} }
} }
LeftMenu.defaultProps = {
version: '3',
};
LeftMenu.propTypes = { LeftMenu.propTypes = {
plugins: PropTypes.object.isRequired, plugins: PropTypes.object.isRequired,
version: PropTypes.string,
}; };
function mapDispatchToProps(dispatch) { function mapDispatchToProps(dispatch) {

View File

@ -20,6 +20,12 @@
"handler": "Admin.getGaConfig", "handler": "Admin.getGaConfig",
"policies": [] "policies": []
}, },
{
"method": "GET",
"path": "/strapiVersion",
"handler": "Admin.getStrapiVersion",
"policies": []
},
{ {
"method": "GET", "method": "GET",
"path": "/layout", "path": "/layout",

View File

@ -17,6 +17,15 @@ module.exports = {
} }
}, },
getStrapiVersion: async ctx => {
try {
const strapiVersion = _.get(strapi.config, 'info.strapi', null);
return ctx.send({ strapiVersion });
} catch(err) {
return ctx.badRequest(null, [{ messages: [{ id: 'The version is not available' }] }]);
}
},
getGaConfig: async ctx => { getGaConfig: async ctx => {
try { try {
const allowGa = _.get(strapi.config, 'info.customs.allowGa', true); const allowGa = _.get(strapi.config, 'info.customs.allowGa', true);

View File

@ -132,6 +132,9 @@ module.exports = (options) => ({
require.resolve('babel-plugin-transform-react-remove-prop-types'), require.resolve('babel-plugin-transform-react-remove-prop-types'),
require.resolve('babel-plugin-transform-react-constant-elements'), require.resolve('babel-plugin-transform-react-constant-elements'),
require.resolve('babel-plugin-transform-react-inline-elements'), require.resolve('babel-plugin-transform-react-inline-elements'),
require.resolve('babel-plugin-transform-es2015-destructuring'),
require.resolve('babel-plugin-transform-es2015-parameters'),
require.resolve('babel-plugin-transform-object-rest-spread'),
], ],
}, },
test: { test: {

View File

@ -34,6 +34,9 @@
"babel-eslint": "^7.2.3", "babel-eslint": "^7.2.3",
"babel-loader": "^7.1.1", "babel-loader": "^7.1.1",
"babel-plugin-istanbul": "^4.1.5", "babel-plugin-istanbul": "^4.1.5",
"babel-plugin-transform-es2015-destructuring": "^6.23.0",
"babel-plugin-transform-es2015-parameters": "^6.24.1",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-react-constant-elements": "^6.23.0", "babel-plugin-transform-react-constant-elements": "^6.23.0",
"babel-plugin-transform-react-inline-elements": "^6.22.0", "babel-plugin-transform-react-inline-elements": "^6.22.0",
"babel-plugin-transform-react-remove-prop-types": "^0.4.8", "babel-plugin-transform-react-remove-prop-types": "^0.4.8",

View File

@ -30,8 +30,9 @@ function EditRelations(props) {
{(message) => <h3>{message}</h3>} {(message) => <h3>{message}</h3>}
</FormattedMessage> </FormattedMessage>
{map(filterRelationsUpload(props.schema.relations), (relation, key) => { {map(filterRelationsUpload(props.schema.relations), (relation, key) => {
if (relation.nature.toLowerCase().includes('morph') && relation[key]) return '';
const Select = ['oneWay', 'oneToOne', 'manyToOne'].includes(relation.nature) && relation.dominant ? SelectOne : SelectMany; const Select = ['oneWay', 'oneToOne', 'manyToOne', 'oneToManyMorph', 'oneToOneMorph'].includes(relation.nature) && relation.dominant ? SelectOne : SelectMany;
return ( return (
<Select <Select

View File

@ -223,7 +223,8 @@ export class EditPage extends React.Component {
isRelationComponentNull = () => ( isRelationComponentNull = () => (
Object.keys(get(this.getSchema(), 'relations', {})).filter(relation => ( Object.keys(get(this.getSchema(), 'relations', {})).filter(relation => (
get(this.getSchema(), ['relations', relation, 'plugin']) !== 'upload' get(this.getSchema(), ['relations', relation, 'plugin']) !== 'upload' &&
(!get(this.getSchema(), ['relations', relation, 'nature'], '').toLowerCase().includes('morph') || !get(this.getSchema(), ['relations', relation, relation]))
)).length === 0 )).length === 0
) )

View File

@ -14,13 +14,14 @@ module.exports = {
.count()); .count());
}, },
findOne: async function (params, populate) { findOne: async function (params, populate, raw = true) {
return this const query = this
.findOne({ .findOne({
[this.primaryKey]: params[this.primaryKey] || params.id [this.primaryKey]: params[this.primaryKey] || params.id
}) })
.populate(populate || this.associations.map(x => x.alias).join(' ')) .populate(populate || this.associations.map(x => x.alias).join(' '));
.lean();
return raw ? query.lean() : query;
}, },
create: async function (params) { create: async function (params) {
@ -300,18 +301,18 @@ module.exports = {
However the upload doesn't need this method. It only uses the `removeRelationMorph`. However the upload doesn't need this method. It only uses the `removeRelationMorph`.
*/ */
const entry = await module.exports.findOne.call(this, params, []); const entry = (await module.exports.findOne.call(this, params, [], false)).toJSON();
const value = entry[params.alias] || []; const value = [];
// Retrieve association. // Retrieve association.
const association = this.associations.find(association => association.via === params.alias)[0]; const association = this.associations.find(association => association.alias === params.alias);
if (!association) { if (!association) {
throw Error(`Impossible to create relationship with ${params.ref} (${params.refId})`); throw Error(`Impossible to create relationship with ${params.ref} (${params.refId})`);
} }
// Resolve if the association is already existing. // Resolve if the association is already existing.
const isExisting = entry[params.alias].find(obj => { const isExisting = value.find(obj => {
if (obj.kind === params.ref && obj.ref.toString() === params.refId.toString() && obj.field === params.field) { if (obj.kind === params.ref && obj.ref.toString() === params.refId.toString() && obj.field === params.field) {
return true; return true;
} }
@ -326,9 +327,10 @@ module.exports = {
// Push new relation to the association array. // Push new relation to the association array.
value.push({ value.push({
ref: params.refId, ref: params.ref,
refId: params.refId,
kind: params.ref, kind: params.ref,
field: association.filter field: params.field
}); });
entry[params.alias] = value; entry[params.alias] = value;

View File

@ -59,7 +59,7 @@ module.exports = {
}); });
// Then, request plugin upload. // Then, request plugin upload.
if (strapi.plugins.upload) { if (strapi.plugins.upload && !_.isEmpty(values.files)) {
// Upload new files and attach them to this entity. // Upload new files and attach them to this entity.
await strapi.plugins.upload.services.upload.uploadToEntity({ await strapi.plugins.upload.services.upload.uploadToEntity({
id: entry.id || entry._id, id: entry.id || entry._id,