Merge branch 'master' into fix/bookshelf-upload-query-findone

This commit is contained in:
Jim LAURIE 2019-02-17 17:03:01 +01:00 committed by GitHub
commit e5c8afe24e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
107 changed files with 427 additions and 1006 deletions

View File

@ -1,27 +1,28 @@
<!-- ⚠️ Your PR title will appear in the changelogs please make it short detailed and understandable for all. -->
<!-- Write a short description of what your PR does and link the concerned issues of your update. -->
<!-- ⚠️ Please link issue(s) you close / fix by using GitHub keywords https://help.github.com/articles/closing-issues-using-keywords/ !-->
#### Description:
<!-- Uncomment the correct contribution type. !-->
**My PR is a:**
#### My PR is a:
- [ ] 💥 Breaking change
- [ ] 🐛 Bug fix #issueNumber
- [ ] 💅 Enhancement
- [ ] 🚀 New feature
**Main update on the:**
#### Main update on the:
- [ ] Admin
- [ ] Documentation
- [ ] Framework
- [ ] Plugin
<!-- Please note that all databases should be tested and confirmed to be working prior to the PR being merged. -->
**Manual testing done on the following databases:**
#### Manual testing done on the following databases:
- [ ] Not applicable
- [ ] MongoDB
- [ ] MySQL
- [ ] Postgres
<!-- Write a short description of what your PR does and link the concerned issues of your update. -->
**Description:**
<!-- ⚠️ Please link issue(s) you close / fix by using GitHub keywords https://help.github.com/articles/closing-issues-using-keywords/ !-->

File diff suppressed because one or more lines are too long

View File

@ -13,7 +13,7 @@ const history = createHistory({
const store = configureStore({}, history);
if (window.Cypress) {
window.__store__ = Object.assign(window.__store__ || {}, { strapiAdmin: store });
window.__store__ = Object.assign(window.__store__ || {}, { store });
}
export { basename, history, store };
export { basename, history, store };

View File

@ -10,6 +10,8 @@ import {
updatePlugin,
} from 'containers/App/actions';
import { showNotification } from 'containers/NotificationProvider/actions';
import injectReducer from './utils/injectReducer';
import injectSaga from './utils/injectSaga';
import { history, store } from './createStore';
import { translationMessages, languages } from './i18n';
import './public-path';
@ -94,4 +96,7 @@ window.strapi = Object.assign(window.strapi || {}, {
currentLanguage: window.localStorage.getItem('strapi-admin-language') || window.navigator.language || window.navigator.userLanguage || 'en',
lockApp,
unlockApp,
});
injectReducer,
injectSaga,
store,
});

View File

@ -11,7 +11,7 @@ import getInjectors from './reducerInjectors';
* @param {function} reducer A reducer that will be injected
*
*/
export default ({ key, reducer }) => (WrappedComponent) => {
export default ({ key, reducer, pluginId }) => (WrappedComponent) => {
class ReducerInjector extends React.Component {
static WrappedComponent = WrappedComponent;
static displayName = `withReducer(${(WrappedComponent.displayName || WrappedComponent.name || 'Component')})`;
@ -21,8 +21,9 @@ export default ({ key, reducer }) => (WrappedComponent) => {
componentWillMount() {
const { injectReducer } = this.injectors;
const reducerName = pluginId ? `${pluginId}_${key}` : key;
injectReducer(key, reducer);
injectReducer(reducerName, reducer);
}
injectors = getInjectors(this.context.store);

View File

@ -15,7 +15,7 @@ import getInjectors from './sagaInjectors';
* - constants.ONCE_TILL_UNMOUNTbehaves like 'RESTART_ON_REMOUNT' but never runs it again.
*
*/
export default ({ key, saga, mode }) => (WrappedComponent) => {
export default ({ key, saga, mode, pluginId }) => (WrappedComponent) => {
class InjectSaga extends React.Component {
static WrappedComponent = WrappedComponent;
static displayName = `withSaga(${(WrappedComponent.displayName || WrappedComponent.name || 'Component')})`;
@ -25,14 +25,16 @@ export default ({ key, saga, mode }) => (WrappedComponent) => {
componentWillMount() {
const { injectSaga } = this.injectors;
const sagaName = pluginId ? `${pluginId}_${key}` : key;
injectSaga(key, { saga, mode }, this.props);
injectSaga(sagaName, { saga, mode }, this.props);
}
componentWillUnmount() {
const { ejectSaga } = this.injectors;
const sagaName = pluginId ? `${pluginId}_${key}` : key;
ejectSaga(key);
ejectSaga(sagaName);
}
injectors = getInjectors(this.context.store);

View File

@ -25,6 +25,7 @@
"presetup": "node ./scripts/preSetup.js"
},
"dependencies": {
"intl": "^1.2.5",
"react-ga": "^2.4.1",
"remove-markdown": "^0.2.2",
"shelljs": "^0.7.8"

View File

@ -13,7 +13,7 @@ import { Switch, Route } from 'react-router-dom';
import { bindActionCreators, compose } from 'redux';
// Utils
import { pluginId } from 'app';
import pluginId from 'pluginId';
// Containers
import HomePage from 'containers/HomePage';
@ -21,6 +21,7 @@ import NotFoundPage from 'containers/NotFoundPage';
// When you're done studying the ExamplePage container, remove the following line and delete the ExamplePage container
import ExamplePage from 'containers/ExamplePage';
import reducer from './reducer';
class App extends React.Component {
// When you're done studying the ExamplePage container, remove the following lines and delete the ExamplePage container
@ -44,7 +45,6 @@ class App extends React.Component {
App.contextTypes = {
plugins: PropTypes.object,
router: PropTypes.object.isRequired,
updatePlugin: PropTypes.func,
};
@ -63,7 +63,9 @@ const mapStateToProps = createStructuredSelector({});
// Wrap the component to inject dispatch and state into it
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = strapi.injectReducer({ key: 'global', reducer, pluginId });
export default compose(
withReducer,
withConnect,
)(App);

View File

@ -1,9 +1,10 @@
// import { createSelector } from 'reselect';
// import pluginId from 'pluginId';
/**
* Direct selector to the list state domain
*/
// const selectGlobalDomain = () => state => state.get('global');
// const selectGlobalDomain = () => state => state.get(`${pluginId}-global`);
export {};

View File

@ -4,5 +4,7 @@
*
*/
export const LOAD_DATA = 'ExamplePage/LOAD_DATA';
export const LOADED_DATA = 'ExamplePage/LOADED_DATA';
import pluginId from 'pluginId';
export const LOAD_DATA = `${pluginId}/ExamplePage/LOAD_DATA`;
export const LOADED_DATA = `${pluginId}/ExamplePage/LOADED_DATA`;

View File

@ -10,9 +10,7 @@ import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { injectIntl } from 'react-intl';
import { bindActionCreators, compose } from 'redux';
import injectReducer from 'utils/injectReducer';
import injectSaga from 'utils/injectSaga';
import pluginId from 'pluginId';
import Button from 'components/Button';
@ -90,8 +88,8 @@ const mapStateToProps = createStructuredSelector({
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = injectReducer({ key: 'examplePage', reducer });
const withSaga = injectSaga({ key: 'examplePage', saga });
const withReducer = strapi.injectReducer({ key: 'examplePage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'examplePage', saga, pluginId });
export default compose(
withReducer,

View File

@ -1,9 +1,10 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the examplePage state domain
*/
const selectExamplePageDomain = () => state => state.get('examplePage');
const selectExamplePageDomain = () => state => state.get(`${pluginId}-examplePage`);
/**
* Default selector used by HomePage

View File

@ -4,4 +4,6 @@
*
*/
export const DEFAULT_ACTION = 'HomePage/DEFAULT_ACTION';
import pluginId from 'pluginId';
export const DEFAULT_ACTION = `${pluginId}/HomePage/DEFAULT_ACTION`;

View File

@ -10,9 +10,7 @@ import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { injectIntl } from 'react-intl';
import { bindActionCreators, compose } from 'redux';
import injectReducer from 'utils/injectReducer';
import injectSaga from 'utils/injectSaga';
import pluginId from 'pluginId';
// Selectors
import selectHomePage from './selectors';
@ -55,8 +53,8 @@ const mapStateToProps = createStructuredSelector({
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = injectReducer({ key: 'homePage', reducer });
const withSaga = injectSaga({ key: 'homePage', saga });
const withReducer = strapi.injectReducer({ key: 'homePage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'homePage', saga, pluginId });
export default compose(
withReducer,

View File

@ -1,9 +1,9 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the homePage state domain
*/
const selectHomePageDomain = () => state => state.get('homePage');
const selectHomePageDomain = () => state => state.get(`${pluginId}-homePage`);
/**
* Default selector used by HomePage

View File

@ -0,0 +1,7 @@
const pluginPkg = require('../../package.json');
const pluginId = pluginPkg.name.replace(
/^strapi-plugin-/i,
''
);
module.exports = pluginId;

View File

@ -17,6 +17,7 @@ import { FormattedMessage } from 'react-intl';
import { createStructuredSelector } from 'reselect';
{{/if}}
import { bindActionCreators, compose } from 'redux';
// import pluginId from 'pluginId';
{{#if wantSaga}}
import injectSaga from 'utils/injectSaga';
@ -72,7 +73,7 @@ const withConnect = connect(mapStateToProps, mapDispatchToProps);
/* Remove this line if the container doesn't have a route and
* check the documentation to see how to create the container's store
*/
const withReducer = injectReducer({ key: '{{ camelCase name }}', reducer });
const withReducer = injectReducer({ key: '{{ camelCase name }}', reducer, pluginId });
{{else}}
const withConnect = connect(null, mapDispatchToProps);
{{/if}}
@ -81,7 +82,7 @@ const withConnect = connect(null, mapDispatchToProps);
/* Remove the line below the container doesn't have a route and
* check the documentation to see how to create the container's store
*/
const withSaga = injectSaga({ key: '{{ camelCase name }}', saga });
const withSaga = injectSaga({ key: '{{ camelCase name }}', saga, pluginId });
{{/if}}
export default compose(

View File

@ -1,9 +1,10 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the {{ camelCase name }} state domain
*/
const select{{ properCase name }}Domain = () => (state) => state.get('{{ camelCase name }}');
const select{{ properCase name }}Domain = () => (state) => state.get(`${pluginId}-{{ camelCase name }}`);
/**
* Other specific selectors

View File

@ -11,12 +11,9 @@ import './public-path.js'; // eslint-disable-line import/extensions
import React from 'react';
import Loadable from 'react-loadable';
import { Provider } from 'react-redux';
import LoadingIndicatorPage from 'components/LoadingIndicatorPage';
import configureStore from './store';
import { translationMessages } from './i18n';
const LoadableApp = Loadable({
loader: () => import('containers/App'),
loading: LoadingIndicatorPage,
@ -61,23 +58,16 @@ const apiUrl = `${strapi.backendURL}/${pluginId}`;
const router = strapi.router;
// Create redux store with Strapi admin history
const store = configureStore({}, strapi.router, pluginName);
// const store = configureStore({}, strapi.router, pluginName);
const store = strapi.store;
// Define the plugin root component
function Comp(props) {
return (
<Provider store={store}>
<LoadableApp {...props} />
</Provider>
<LoadableApp {...props} />
);
}
if (window.Cypress) {
window.__store__ = Object.assign(window.__store__ || {}, {
[pluginId]: store,
});
}
// Hot reloadable translation json files
if (module.hot) {
// modules.hot.accept does not accept dynamic dependencies,

View File

@ -1,49 +0,0 @@
/**
* Combine all reducers in this file and export the combined reducers.
* If we were to do this in store.js, reducers wouldn't be hot reloadable.
*/
import { combineReducers } from 'redux-immutable';
import { fromJS } from 'immutable';
import { LOCATION_CHANGE } from 'react-router-redux';
import globalReducer from 'containers/App/reducer'; // eslint-disable-line
/*
* routeReducer
*
* The reducer merges route location changes into our immutable state.
* The change is necessitated by moving to react-router-redux@4
*
*/
// Initial routing state
const routeInitialState = fromJS({
locationBeforeTransitions: null,
});
/**
* Merge route into the global application state
*/
function routeReducer(state = routeInitialState, action) {
switch (action.type) {
/* istanbul ignore next */
case LOCATION_CHANGE:
return state.merge({
locationBeforeTransitions: action.payload,
});
default:
return state;
}
}
/**
* Creates the main reducer with the asynchronously loaded ones
*/
export default function createReducer(asyncReducers) {
return combineReducers({
route: routeReducer,
global: globalReducer,
...asyncReducers,
});
}

View File

@ -1,41 +0,0 @@
// These are the pages you can go to.
// They are all wrapped in the App component, which should contain the navbar etc
// See http://blog.mxstbr.com/2016/01/react-apps-with-pages for more information
// about the code splitting business
import { camelCase, map } from 'lodash';
import { getAsyncInjectors } from 'utils/asyncInjectors';
import routes from 'routes.json'; // eslint-disable-line
// Try to require a node module without throwing an error
const tryRequire = (path) => {
try {
return require(`containers/${path}.js`); // eslint-disable-line global-require
} catch (err) {
return null;
}
};
export default function createRoutes(store) {
// Create reusable async injectors using getAsyncInjectors factory
const { injectReducer, injectSagas } = getAsyncInjectors(store); // eslint-disable-line no-unused-vars
// Inject app sagas
const appSagas = tryRequire('App/sagas');
if (appSagas) injectSagas(appSagas.default);
return map(routes, (route, key) => ({
path: key === '/' ? '' : key,
name: route.name,
getComponent(nextState, cb) {
const reducer = tryRequire(`${route.container}/reducer`); // eslint-disable-line global-require
const sagas = tryRequire(`${route.container}/sagas`); // eslint-disable-line global-require
const component = tryRequire(`${route.container}/index`); // eslint-disable-line global-require
process.nextTick(() => {
if (reducer) injectReducer(camelCase(route.container), reducer.default);
if (sagas) injectSagas(sagas.default);
cb(null, component.default);
});
},
}));
}

View File

@ -1,61 +0,0 @@
/**
* Create the store with dynamic reducers
*/
import { createStore, applyMiddleware, compose } from 'redux';
import { fromJS } from 'immutable';
import { routerMiddleware } from 'react-router-redux';
import createSagaMiddleware from 'redux-saga';
import createReducer from './reducers';
const sagaMiddleware = createSagaMiddleware();
export default function configureStore(initialState = {}, history, name) {
// Create the store with two middlewares
// 1. sagaMiddleware: Makes redux-sagas work
// 2. routerMiddleware: Syncs the location/URL path to the state
const middlewares = [
sagaMiddleware,
routerMiddleware(history),
];
const enhancers = [
applyMiddleware(...middlewares),
];
// If Redux DevTools Extension is installed use it, otherwise use Redux compose
/* eslint-disable no-underscore-dangle */
const composeEnhancers =
process.env.NODE_ENV !== 'production' &&
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
// TODO Try to remove when `react-router-redux` is out of beta, LOCATION_CHANGE should not be fired more than once after hot reloading
// Prevent recomputing reducers for `replaceReducer`
shouldHotReload: false,
name: `Plugin - ${name}`,
})
: compose;
/* eslint-enable */
const store = createStore(
createReducer(),
fromJS(initialState),
composeEnhancers(...enhancers),
);
// Extensions
store.runSaga = sagaMiddleware.run;
store.injectedReducers = {}; // Reducer registry
store.injectedSagas = {}; // Saga registry
// Make reducers hot reloadable, see http://mxs.is/googmo
/* istanbul ignore next */
if (module.hot) {
module.hot.accept('./reducers', () => {
store.replaceReducer(createReducer(store.injectedReducers));
});
}
return store;
}

View File

@ -1,72 +0,0 @@
import { conformsTo, isEmpty, isFunction, isObject, isString } from 'lodash';
import invariant from 'invariant';
import warning from 'warning';
import createReducer from 'reducers';
/**
* Validate the shape of redux store
*/
export function checkStore(store) {
const shape = {
dispatch: isFunction,
subscribe: isFunction,
getState: isFunction,
replaceReducer: isFunction,
runSaga: isFunction,
asyncReducers: isObject,
};
invariant(
conformsTo(store, shape),
'(src/utils...) asyncInjectors: Expected a valid redux store'
);
}
/**
* Inject an asynchronously loaded reducer
*/
export function injectAsyncReducer(store, isValid) {
return function injectReducer(name, asyncReducer) {
if (!isValid) checkStore(store);
invariant(
isString(name) && !isEmpty(name) && isFunction(asyncReducer),
'(src/utils...) injectAsyncReducer: Expected `asyncReducer` to be a reducer function'
);
store.asyncReducers[name] = asyncReducer; // eslint-disable-line no-param-reassign
store.replaceReducer(createReducer(store.asyncReducers));
};
}
/**
* Inject an asynchronously loaded saga
*/
export function injectAsyncSagas(store, isValid) {
return function injectSagas(sagas) {
if (!isValid) checkStore(store);
invariant(
Array.isArray(sagas),
'(src/utils...) injectAsyncSagas: Expected `sagas` to be an array of generator functions'
);
warning(
!isEmpty(sagas),
'(src/utils...) injectAsyncSagas: Received an empty `sagas` array'
);
sagas.map(store.runSaga);
};
}
/**
* Helper for creating injectors
*/
export function getAsyncInjectors(store) {
checkStore(store);
return {
injectReducer: injectAsyncReducer(store, true),
injectSagas: injectAsyncSagas(store, true),
};
}

View File

@ -1,23 +0,0 @@
import conformsTo from 'lodash/conformsTo';
import isFunction from 'lodash/isFunction';
import isObject from 'lodash/isObject';
import invariant from 'invariant';
/**
* Validate the shape of redux store
*/
export default function checkStore(store) {
const shape = {
dispatch: isFunction,
subscribe: isFunction,
getState: isFunction,
replaceReducer: isFunction,
runSaga: isFunction,
injectedReducers: isObject,
injectedSagas: isObject,
};
invariant(
conformsTo(store, shape),
'(app/utils...) injectors: Expected a valid redux store'
);
}

View File

@ -1,36 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import hoistNonReactStatics from 'hoist-non-react-statics';
import getInjectors from './reducerInjectors';
/**
* Dynamically injects a reducer
*
* @param {string} key A key of the reducer
* @param {function} reducer A reducer that will be injected
*
*/
export default ({ key, reducer }) => (WrappedComponent) => {
class ReducerInjector extends React.Component {
static WrappedComponent = WrappedComponent;
static displayName = `withReducer(${(WrappedComponent.displayName || WrappedComponent.name || 'Component')})`;
static contextTypes = {
store: PropTypes.object.isRequired,
};
componentWillMount() {
const { injectReducer } = this.injectors;
injectReducer(key, reducer);
}
injectors = getInjectors(this.context.store);
render() {
return <WrappedComponent {...this.props} />;
}
}
return hoistNonReactStatics(ReducerInjector, WrappedComponent);
};

View File

@ -1,46 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import hoistNonReactStatics from 'hoist-non-react-statics';
import getInjectors from './sagaInjectors';
/**
* Dynamically injects a saga, passes component's props as saga arguments
*
* @param {string} key A key of the saga
* @param {function} saga A root saga that will be injected
* @param {string} [mode] By default (constants.RESTART_ON_REMOUNT) the saga will be started on component mount and
* cancelled with `task.cancel()` on component un-mount for improved performance. Another two options:
* - constants.DAEMONstarts the saga on component mount and never cancels it or starts again,
* - constants.ONCE_TILL_UNMOUNTbehaves like 'RESTART_ON_REMOUNT' but never runs it again.
*
*/
export default ({ key, saga, mode }) => (WrappedComponent) => {
class InjectSaga extends React.Component {
static WrappedComponent = WrappedComponent;
static displayName = `withSaga(${(WrappedComponent.displayName || WrappedComponent.name || 'Component')})`;
static contextTypes = {
store: PropTypes.object.isRequired,
};
componentWillMount() {
const { injectSaga } = this.injectors;
injectSaga(key, { saga, mode }, this.props);
}
componentWillUnmount() {
const { ejectSaga } = this.injectors;
ejectSaga(key);
}
injectors = getInjectors(this.context.store);
render() {
return <WrappedComponent {...this.props} />;
}
}
return hoistNonReactStatics(InjectSaga, WrappedComponent);
};

View File

@ -1,30 +0,0 @@
import invariant from 'invariant';
import { isEmpty, isFunction, isString } from 'lodash';
import createReducer from '../reducers';
import checkStore from './checkStore';
export function injectReducerFactory(store, isValid) {
return function injectReducer(key, reducer) {
if (!isValid) checkStore(store);
invariant(
isString(key) && !isEmpty(key) && isFunction(reducer),
'(app/utils...) injectReducer: Expected `reducer` to be a reducer function'
);
// Check `store.injectedReducers[key] === reducer` for hot reloading when a key is the same but a reducer is different
if (Reflect.has(store.injectedReducers, key) && store.injectedReducers[key] === reducer) return;
store.injectedReducers[key] = reducer; // eslint-disable-line no-param-reassign
store.replaceReducer(createReducer(store.injectedReducers));
};
}
export default function getInjectors(store) {
checkStore(store);
return {
injectReducer: injectReducerFactory(store, true),
};
}

View File

@ -1,86 +0,0 @@
import isEmpty from 'lodash/isEmpty';
import isFunction from 'lodash/isFunction';
import isString from 'lodash/isString';
import invariant from 'invariant';
import conformsTo from 'lodash/conformsTo';
import checkStore from './checkStore';
import {
DAEMON,
ONCE_TILL_UNMOUNT,
RESTART_ON_REMOUNT,
} from './constants';
const allowedModes = [RESTART_ON_REMOUNT, DAEMON, ONCE_TILL_UNMOUNT];
const checkKey = (key) => invariant(
isString(key) && !isEmpty(key),
'(app/utils...) injectSaga: Expected `key` to be a non empty string'
);
const checkDescriptor = (descriptor) => {
const shape = {
saga: isFunction,
mode: (mode) => isString(mode) && allowedModes.includes(mode),
};
invariant(
conformsTo(descriptor, shape),
'(app/utils...) injectSaga: Expected a valid saga descriptor'
);
};
export function injectSagaFactory(store, isValid) {
return function injectSaga(key, descriptor = {}, args) {
if (!isValid) checkStore(store);
const newDescriptor = { ...descriptor, mode: descriptor.mode || RESTART_ON_REMOUNT };
const { saga, mode } = newDescriptor;
checkKey(key);
checkDescriptor(newDescriptor);
let hasSaga = Reflect.has(store.injectedSagas, key);
if (process.env.NODE_ENV !== 'production') {
const oldDescriptor = store.injectedSagas[key];
// enable hot reloading of daemon and once-till-unmount sagas
if (hasSaga && oldDescriptor.saga !== saga) {
oldDescriptor.task.cancel();
hasSaga = false;
}
}
if (!hasSaga || (hasSaga && mode !== DAEMON && mode !== ONCE_TILL_UNMOUNT)) {
store.injectedSagas[key] = { ...newDescriptor, task: store.runSaga(saga, args) }; // eslint-disable-line no-param-reassign
}
};
}
export function ejectSagaFactory(store, isValid) {
return function ejectSaga(key) {
if (!isValid) checkStore(store);
checkKey(key);
if (Reflect.has(store.injectedSagas, key)) {
const descriptor = store.injectedSagas[key];
if (descriptor.mode !== DAEMON) {
descriptor.task.cancel();
// Clean up in production; in development we need `descriptor.saga` for hot reloading
if (process.env.NODE_ENV === 'production') {
// Need some value to be able to detect `ONCE_TILL_UNMOUNT` sagas in `injectSaga`
store.injectedSagas[key] = 'done'; // eslint-disable-line no-param-reassign
}
}
}
};
}
export default function getInjectors(store) {
checkStore(store);
return {
injectSaga: injectSagaFactory(store, true),
ejectSaga: ejectSagaFactory(store, true),
};
}

View File

@ -27,9 +27,6 @@
"lint:admin"
],
"devDependencies": {
"plop": "^2.2.0"
},
"dependencies": {
"add-asset-html-webpack-plugin": "^2.1.2",
"babel-cli": "6.26.0",
"babel-core": "6.26.0",
@ -42,35 +39,25 @@
"babel-plugin-transform-react-constant-elements": "6.23.0",
"babel-plugin-transform-react-inline-elements": "6.22.0",
"babel-plugin-transform-react-remove-prop-types": "0.4.18",
"babel-polyfill": "6.26.0",
"babel-preset-env": "1.6.1",
"babel-preset-react": "6.24.1",
"babel-preset-react-hmre": "1.1.1",
"babel-preset-stage-0": "6.24.1",
"bootstrap": "^4.0.0-alpha.6",
"chalk": "^2.1.0",
"classnames": "^2.2.5",
"copy-webpack-plugin": "^4.3.1",
"cross-env": "^5.0.5",
"css-loader": "^0.28.5",
"cross-env": "^5.0.5",
"exports-loader": "^0.6.4",
"express": "^4.15.4",
"extract-text-webpack-plugin": "^3.0.0",
"express": "^4.15.4",
"file-loader": "^0.11.2",
"history": "^4.6.3",
"html-loader": "^0.5.1",
"html-webpack-plugin": "^2.30.1",
"image-webpack-loader": "^4.3.1",
"immutable": "^3.8.2",
"imports-loader": "^0.7.1",
"intl": "^1.2.5",
"invariant": "2.2.1",
"json-loader": "^0.5.7",
"lodash": "^4.17.5",
"lodash-webpack-plugin": "^0.11.4",
"moment": "^2.16.0",
"node-sass": "^4.5.3",
"null-loader": "^0.1.1",
"plop": "^2.2.0",
"postcss-cssnext": "^2.11.0",
"postcss-focus": "^2.0.0",
"postcss-loader": "^2.0.6",
@ -78,6 +65,27 @@
"postcss-smart-import": "^0.7.5",
"precss": "^2.0.0",
"prettier": "^1.5.3",
"rimraf": "^2.6.1",
"sass-loader": "^6.0.6",
"shelljs": "^0.7.8",
"style-loader": "^0.18.2",
"url-loader": "^1.1.1",
"webpack": "^3.5.5",
"webpack-bundle-analyzer": "^2.9.0",
"webpack-dev-middleware": "^1.12.0",
"webpack-hot-middleware": "^2.18.2"
},
"dependencies": {
"babel-polyfill": "6.26.0",
"bootstrap": "^4.0.0-alpha.6",
"classnames": "^2.2.5",
"history": "^4.6.3",
"immutable": "^3.8.2",
"imports-loader": "^0.7.1",
"invariant": "2.2.1",
"json-loader": "^0.5.7",
"lodash": "^4.17.5",
"moment": "^2.16.0",
"prop-types": "^15.5.10",
"react": "^16.5.2",
"react-copy-to-clipboard": "^5.0.1",
@ -97,16 +105,7 @@
"redux-immutable": "^4.0.0",
"redux-saga": "^0.16.0",
"reselect": "^3.0.1",
"rimraf": "^2.6.1",
"sass-loader": "^6.0.6",
"shelljs": "^0.7.8",
"style-loader": "^0.18.2",
"styled-components": "^3.2.6",
"url-loader": "^1.1.1",
"webpack": "^3.5.5",
"webpack-bundle-analyzer": "^2.9.0",
"webpack-dev-middleware": "^1.12.0",
"webpack-hot-middleware": "^2.18.2",
"whatwg-fetch": "^2.0.3"
}
}

View File

@ -471,7 +471,7 @@ module.exports = function(strapi) {
const type = getType(attribute, attr);
if (type) {
acc.push(`${quote}${attr}${quote} ${type}`);
acc.push(`${quote}${attr}${quote} ${type} ${attribute.required ? 'NOT' : ''} NULL `);
}
return acc;
@ -544,14 +544,12 @@ module.exports = function(strapi) {
}
};
if (!tableExist) {
const createTable = async (table) => {
const defaultAttributeDifinitions = {
mysql: [`id INT AUTO_INCREMENT NOT NULL PRIMARY KEY`],
pg: [`id SERIAL NOT NULL PRIMARY KEY`],
sqlite3: ['id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL']
};
let idAttributeBuilder = defaultAttributeDifinitions[definition.client];
if (definition.primaryKeyType === 'uuid' && definition.client === 'pg') {
idAttributeBuilder = ['id uuid NOT NULL DEFAULT uuid_generate_v4() NOT NULL PRIMARY KEY'];
@ -566,13 +564,16 @@ module.exports = function(strapi) {
${columns}
)
`);
};
if (!tableExist) {
await createTable(table);
// Generate indexes.
await generateIndexes(table, attributes);
await storeTable(table, attributes);
} else {
const columns = Object.keys(attributes);
// Fetch existing column
@ -594,6 +595,14 @@ module.exports = function(strapi) {
// Generate indexes for new attributes.
await generateIndexes(table, columnsToAdd);
let previousAttributes;
try {
previousAttributes = JSON.parse((await StrapiConfigs.forge({key: `db_model_${table}`}).fetch()).toJSON().value);
} catch (err) {
await storeTable(table, attributes);
previousAttributes = JSON.parse((await StrapiConfigs.forge({key: `db_model_${table}`}).fetch()).toJSON().value);
}
// Generate and execute query to add missing column
if (Object.keys(columnsToAdd).length > 0) {
const columns = generateColumns(columnsToAdd, []);
@ -605,31 +614,28 @@ module.exports = function(strapi) {
await Promise.all(queries.map(query => ORM.knex.raw(query)));
}
let previousAttributes;
try {
previousAttributes = JSON.parse((await StrapiConfigs.forge({key: `db_model_${table}`}).fetch()).toJSON().value);
} catch (err) {
await storeTable(table, attributes);
previousAttributes = JSON.parse((await StrapiConfigs.forge({key: `db_model_${table}`}).fetch()).toJSON().value);
}
let sqlite3Change = false;
// Execute query to update column type
await Promise.all(columns.map(attribute =>
new Promise(async (resolve) => {
if (JSON.stringify(previousAttributes[attribute]) === JSON.stringify(attributes[attribute])) {
return resolve();
} else {
sqlite3Change = true;
}
const type = getType(attributes[attribute], attribute);
if (type) {
const changeType = definition.client === 'pg' || definition.client === 'sqlite3'
if (type && definition.client !== 'sqlite3') {
const changeType = definition.client === 'pg'
? `ALTER COLUMN ${quote}${attribute}${quote} TYPE ${type} USING ${quote}${attribute}${quote}::${type}`
: `CHANGE ${quote}${attribute}${quote} ${quote}${attribute}${quote} ${type} `;
const changeRequired = definition.client === 'pg' || definition.client === 'sqlite3'
const changeRequired = definition.client === 'pg'
? `ALTER COLUMN ${quote}${attribute}${quote} ${attributes[attribute].required ? 'SET' : 'DROP'} NOT NULL`
: `CHANGE ${quote}${attribute}${quote} ${quote}${attribute}${quote} ${type} ${attributes[attribute].required ? 'NOT' : ''} NULL`;
await ORM.knex.raw(`ALTER TABLE ${quote}${table}${quote} ${changeType}`);
await ORM.knex.raw(`ALTER TABLE ${quote}${table}${quote} ${changeRequired}`);
}
@ -638,6 +644,28 @@ module.exports = function(strapi) {
})
));
if (sqlite3Change) {
await createTable(`tmp_${table}`);
try {
await ORM.knex.raw(`INSERT INTO ${quote}tmp_${table}${quote}(${Object.keys(attributes).join(' ,')}) SELECT ${Object.keys(attributes).join(' ,')} FROM ${quote}${table}${quote}`);
} catch (err) {
console.log('Warning!');
console.log('We can\'t migrate your data due to the following error.');
console.log();
console.log(err);
console.log();
console.log(`We created a new table "tmp_${table}" with your latest changes.`);
console.log(`We suggest you manually migrate your data from "${table}" to "tmp_${table}" and then to DROP and RENAME the tables.`);
return false;
}
await ORM.knex.raw(`DROP TABLE ${quote}${table}${quote}`);
await ORM.knex.raw(`ALTER TABLE ${quote}tmp_${table}${quote} RENAME TO ${quote}${table}${quote}`);
await generateIndexes(table, attributes);
}
await storeTable(table, attributes);
}
};

View File

@ -46,6 +46,7 @@ class InputJSON extends React.Component {
lineNumbers: true,
matchBrackets: true,
mode: 'application/json',
readOnly: this.props.disabled,
smartIndent: true,
styleSelectedText: true,
tabSize: 2,
@ -186,12 +187,14 @@ class InputJSON extends React.Component {
}
InputJSON.defaultProps = {
disabled: false,
onBlur: () => {},
onChange: () => {},
value: null,
};
InputJSON.propTypes = {
disabled: PropTypes.bool,
name: PropTypes.string.isRequired,
onBlur: PropTypes.func,
onChange: PropTypes.func,

View File

@ -12,8 +12,8 @@ import { createStructuredSelector } from 'reselect';
import PropTypes from 'prop-types';
import { isEmpty, get } from 'lodash';
import { Switch, Route } from 'react-router-dom';
import pluginId from 'pluginId';
import injectSaga from 'utils/injectSaga';
import getQueryParameters from 'utils/getQueryParameters';
import EditPage from 'containers/EditPage';
@ -28,6 +28,7 @@ import {
} from './actions';
import { makeSelectLoading, makeSelectModelEntries, makeSelectSchema } from './selectors';
import reducer from './reducer';
import saga from './sagas';
class App extends React.Component {
@ -93,9 +94,11 @@ const mapStateToProps = createStructuredSelector({
});
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withSaga = injectSaga({ key: 'global', saga });
const withReducer = strapi.injectReducer({ key: 'global', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'global', saga, pluginId });
export default compose(
withReducer,
withSaga,
withConnect,
)(App);

View File

@ -49,7 +49,6 @@ export function* defaultSaga() {
yield take(LOCATION_CHANGE);
yield cancel(loadModelsWatcher);
yield cancel(loadedModelsWatcher);
yield cancel(loadEntriesWatcher);
}

View File

@ -1,9 +1,9 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the list state domain
*/
const selectGlobalDomain = () => state => state.get('global');
const selectGlobalDomain = () => state => state.get(`${pluginId}_global`);
/**
* Other specific selectors

View File

@ -23,6 +23,7 @@ import {
import HTML5Backend from 'react-dnd-html5-backend';
import { DragDropContext } from 'react-dnd';
import cn from 'classnames';
import pluginId from 'pluginId';
// You can find these components in either
// ./node_modules/strapi-helper-plugin/lib/src
// or strapi/packages/strapi-helper-plugin/lib/src
@ -37,8 +38,6 @@ import Edit from 'components/Edit';
import EditRelations from 'components/EditRelations';
// App selectors
import { makeSelectSchema } from 'containers/App/selectors';
import injectReducer from 'utils/injectReducer';
import injectSaga from 'utils/injectSaga';
import getQueryParameters from 'utils/getQueryParameters';
import { bindLayout } from 'utils/bindLayout';
import inputValidations from 'utils/inputsValidations';
@ -601,8 +600,8 @@ const withConnect = connect(
mapDispatchToProps,
);
const withReducer = injectReducer({ key: 'editPage', reducer });
const withSaga = injectSaga({ key: 'editPage', saga });
const withReducer = strapi.injectReducer({ key: 'editPage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'editPage', saga, pluginId });
export default compose(
withReducer,

View File

@ -1,13 +1,13 @@
import { LOCATION_CHANGE } from 'react-router-redux';
// import { LOCATION_CHANGE } from 'react-router-redux';
import { findIndex, get, isArray, isEmpty, includes, isNumber, isString, map } from 'lodash';
import {
all,
call,
cancel,
// cancel,
fork,
put,
select,
take,
// take,
takeLatest,
} from 'redux-saga/effects';
import { makeSelectSchema } from 'containers/App/selectors';
@ -185,13 +185,15 @@ export function* submit() {
}
function* defaultSaga() {
const loadDataWatcher = yield fork(takeLatest, GET_DATA, dataGet);
yield fork(takeLatest, GET_DATA, dataGet);
// TODO fix router (Other PR)
// const loadDataWatcher = yield fork(takeLatest, GET_DATA, dataGet);
yield fork(takeLatest, DELETE_DATA, deleteData);
yield fork(takeLatest, SUBMIT, submit);
yield take(LOCATION_CHANGE);
// yield take(LOCATION_CHANGE);
yield cancel(loadDataWatcher);
// yield cancel(loadDataWatcher);
}
export default defaultSaga;

View File

@ -5,11 +5,12 @@
*/
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the listPage state domain
*/
const selectEditPageDomain = () => state => state.get('editPage');
const selectEditPageDomain = () => state => state.get(`${pluginId}_editPage`);
/**

View File

@ -1,46 +0,0 @@
/*
* Home
*/
import React from 'react';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { FormattedMessage } from 'react-intl';
import PluginHeader from 'components/PluginHeader';
import styles from './styles.scss';
export class Home extends React.Component {
render() {
return (
<div>
<div className={`container-fluid ${styles.containerFluid}`}>
<PluginHeader
title={{
id: 'content-manager.containers.Home.pluginHeaderTitle',
}}
description={{
id: 'content-manager.containers.Home.pluginHeaderDescription',
}}
actions={[]}
/>
<p>
<FormattedMessage id="content-manager.containers.Home.introduction" />
</p>
</div>
</div>
);
}
}
Home.propTypes = {};
export function mapDispatchToProps() {
return {};
}
const mapStateToProps = createStructuredSelector({});
// Wrap the component to inject dispatch and state into it
export default connect(mapStateToProps, mapDispatchToProps)(Home);

View File

@ -1,10 +0,0 @@
{
"pluginHeaderDescription": {
"id": "contentManager.containers.Home.pluginHeaderDescription",
"defaultMessage": "A powerful UI to easily manage your data."
},
"introduction": {
"id": "contentManager.containers.Home.introduction",
"defaultMessage": "To edit your content's entries go to the specific link in the left menu."
}
}

View File

@ -1,17 +0,0 @@
/**
* styles.scss
*
* Home container styles
*/
.containerFluid { /* stylelint-disable */
padding: 18px 30px;
p {
display: block;
margin: 0;
padding-bottom: 14px;
line-height: 18px;
text-align: left;
}
}

View File

@ -13,6 +13,7 @@ import { capitalize, findIndex, get, isUndefined, toInteger, upperFirst } from '
import { ButtonDropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
import { FormattedMessage } from 'react-intl';
import cn from 'classnames';
import pluginId from 'pluginId';
// App selectors
import { makeSelectSchema } from 'containers/App/selectors';
// You can find these components in either
@ -30,8 +31,6 @@ import Search from 'components/Search';
import Table from 'components/Table';
// Utils located in `strapi/packages/strapi-helper-plugin/lib/src/utils`;
import getQueryParameters from 'utils/getQueryParameters';
import injectReducer from 'utils/injectReducer';
import injectSaga from 'utils/injectSaga';
import storeData from 'utils/storeData';
import Div from './Div';
import {
@ -681,7 +680,7 @@ const mapStateToProps = createStructuredSelector({
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = injectReducer({ key: 'listPage', reducer });
const withSaga = injectSaga({ key: 'listPage', saga });
const withReducer = strapi.injectReducer({ key: 'listPage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'listPage', saga, pluginId });
export default compose(withReducer, withSaga, withConnect)(ListPage);

View File

@ -1,13 +1,13 @@
// Dependencies.
import { LOCATION_CHANGE } from 'react-router-redux';
// import { LOCATION_CHANGE } from 'react-router-redux';
import {
all,
call,
cancel,
// cancel,
fork,
put,
select,
take,
// take,
takeLatest,
} from 'redux-saga/effects';
// Utils.
@ -114,13 +114,16 @@ export function* dataDeleteAll({ entriesToDelete, model, source }) {
// All sagas to be loaded
function* defaultSaga() {
const loadDataWatcher = yield fork(takeLatest, GET_DATA, dataGet);
yield fork(takeLatest, GET_DATA, dataGet);
// TODO fix router (Other PR)
// const loadDataWatcher = yield fork(takeLatest, GET_DATA, dataGet);
yield fork(takeLatest, DELETE_DATA, dataDelete);
yield fork(takeLatest, DELETE_SEVERAL_DATA, dataDeleteAll);
yield take(LOCATION_CHANGE);
// yield take(LOCATION_CHANGE);
yield cancel(loadDataWatcher);
// yield cancel(loadDataWatcher);
}
export default defaultSaga;

View File

@ -5,11 +5,12 @@
*/
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the listPage state domain
*/
const selectListPageDomain = () => state => state.get('listPage');
const selectListPageDomain = () => state => state.get(`${pluginId}_listPage`);
/**

View File

@ -14,6 +14,7 @@ import { DragDropContext } from 'react-dnd';
import { FormattedMessage } from 'react-intl';
import { ButtonDropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
import PropTypes from 'prop-types';
import pluginId from 'pluginId';
import {
beginMove,
endMove,
@ -54,9 +55,6 @@ import PluginHeader from 'components/PluginHeader';
import PopUpWarning from 'components/PopUpWarning';
import VariableDraggableAttr from 'components/VariableDraggableAttr';
import injectReducer from 'utils/injectReducer';
import injectSaga from 'utils/injectSaga';
import { onClickEditField, onClickEditListItem, onClickEditRelation } from './actions';
import reducer from './reducer';
import saga from './saga';
@ -1161,8 +1159,8 @@ const withConnect = connect(
mapStateToProps,
mapDispatchToProps,
);
const withReducer = injectReducer({ key: 'settingPage', reducer });
const withSaga = injectSaga({ key: 'settingPage', saga });
const withReducer = strapi.injectReducer({ key: 'settingPage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'settingPage', saga, pluginId });
export default compose(
withReducer,

View File

@ -4,11 +4,12 @@
*/
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the settingPage state domain
*/
const selectSettingPageDomain = () => state => state.get('settingPage');
const selectSettingPageDomain = () => state => state.get(`${pluginId}_settingPage`);
/**
@ -21,4 +22,4 @@ const makeSelectSettingPage = () => createSelector(
);
export default makeSelectSettingPage;
export default makeSelectSettingPage;

View File

@ -10,6 +10,7 @@ import { createStructuredSelector } from 'reselect';
import cn from 'classnames';
import { get, sortBy } from 'lodash';
import PropTypes from 'prop-types';
import pluginId from 'pluginId';
import { onChange, onSubmit, onReset } from 'containers/App/actions';
import { makeSelectModifiedSchema, makeSelectSubmitSuccess } from 'containers/App/selectors';
import Input from 'components/InputsIndex';
@ -17,8 +18,6 @@ import PluginHeader from 'components/PluginHeader';
import PopUpWarning from 'components/PopUpWarning';
import Block from 'components/Block';
import SettingsRow from 'components/SettingsRow';
import injectReducer from 'utils/injectReducer';
import injectSaga from 'utils/injectSaga';
import reducer from './reducer';
import saga from './saga';
import styles from './styles.scss';
@ -211,8 +210,8 @@ const mapStateToProps = createStructuredSelector({
submitSuccess: makeSelectSubmitSuccess(),
});
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = injectReducer({ key: 'settingsPage', reducer });
const withSaga = injectSaga({ key: 'settingsPage', saga });
const withReducer = strapi.injectReducer({ key: 'settingsPage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'settingsPage', saga, pluginId });
export default compose(
withReducer,

View File

@ -4,11 +4,12 @@
*/
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the settingsPage state domain
*/
const selectSettingsPageDomain = () => state => state.get('settingsPage');
const selectSettingsPageDomain = () => state => state.get(`${pluginId}_settingsPage`);
/**
@ -21,4 +22,4 @@ const makeSelectSettingsPage = () => createSelector(
);
export default makeSelectSettingsPage;
export default makeSelectSettingsPage;

View File

@ -0,0 +1,7 @@
const pluginPkg = require('../../package.json');
const pluginId = pluginPkg.name.replace(
/^strapi-plugin-/i,
''
);
module.exports = pluginId;

View File

@ -1,11 +0,0 @@
{
"/": {
"container": "Home"
},
"/:slug": {
"container": "List"
},
"/:slug/:id": {
"container": "Edit"
}
}

View File

@ -67,7 +67,7 @@ describe('Testing Content Manager createPages', function() {
.wait(1000)
.window()
.its('__store__')
.its('content-manager')
.its('store');
});
});
@ -196,11 +196,11 @@ describe('Testing Content Manager createPages', function() {
.wait(2000)
.window()
.its('__store__')
.its('content-manager')
.its('store')
.then(pluginStore => {
const records = pluginStore
.getState()
.getIn(['listPage', 'records', 'tag'])
.getIn(['content-manager_listPage', 'records', 'tag'])
.toJS();
expect(records).to.have.length(0);
@ -411,7 +411,7 @@ describe('Testing Content Manager createPages', function() {
.then(pluginStore => {
const category = pluginStore
.getState()
.getIn(['editPage', 'record', 'category'])
.getIn(['content-manager_editPage', 'record', 'category'])
expect(category).to.equal(null);
});
@ -420,7 +420,7 @@ describe('Testing Content Manager createPages', function() {
.then(pluginStore => {
const category = pluginStore
.getState()
.getIn(['editPage', 'record', 'category', 'name'])
.getIn(['content-manager_editPage', 'record', 'category', 'name'])
expect(category).to.equal('french food');
})
@ -428,7 +428,7 @@ describe('Testing Content Manager createPages', function() {
.then(pluginStore => {
const category = pluginStore
.getState()
.getIn(['editPage', 'record', 'category', 'name'])
.getIn(['content-manager_editPage', 'record', 'category', 'name'])
expect(category).to.equal('french food');
});
@ -440,4 +440,4 @@ describe('Testing Content Manager createPages', function() {
.deleteAllModelData('product', jwt);
});
});
});
});

View File

@ -12,7 +12,7 @@ import { bindActionCreators, compose } from 'redux';
import { createStructuredSelector } from 'reselect';
import { Switch, Route, withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import { pluginId } from 'app';
import pluginId from 'pluginId';
import HomePage from 'containers/HomePage';
import ModelPage from 'containers/ModelPage';
@ -24,12 +24,13 @@ import formReducer from 'containers/Form/reducer';
import { makeSelectShouldRefetchContentType } from 'containers/Form/selectors';
// Utils
import injectSaga from 'utils/injectSaga';
import injectReducer from 'utils/injectReducer';
// import injectSaga from 'utils/injectSaga';
// import injectReducer from 'utils/injectReducer';
import { storeData } from '../../utils/storeData';
import styles from './styles.scss';
import { modelsFetch } from './actions';
import reducer from './reducer';
import saga from './sagas';
/* eslint-disable consistent-return */
@ -92,10 +93,13 @@ const mapStateToProps = createStructuredSelector({
});
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withSaga = injectSaga({ key: 'global', saga });
const withFormReducer = injectReducer({ key: 'form', reducer: formReducer });
const withFormSaga = injectSaga({ key: 'form', saga: formSaga });
const withReducer = strapi.injectReducer({ key: 'global', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'global', saga, pluginId });
const withFormReducer = strapi.injectReducer({ key: 'form', reducer: formReducer, pluginId });
const withFormSaga = strapi.injectSaga({ key: 'form', saga: formSaga, pluginId });
export default compose(
withReducer,
withFormReducer,
withFormSaga,
withSaga,

View File

@ -1,10 +1,11 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the list state domain
*/
const selectGlobalDomain = () => state => state.get('global');
const selectGlobalDomain = () => state => state.get(`${pluginId}_global`);
const makeSelectLoading = () => createSelector(
selectGlobalDomain(),

View File

@ -1,9 +1,10 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the form state domain
*/
const selectFormDomain = () => state => state.get('form');
const selectFormDomain = () => state => state.get(`${pluginId}_form`);
/**
* Other specific selectors

View File

@ -12,6 +12,7 @@ import { size } from 'lodash';
import Helmet from 'react-helmet';
import PropTypes from 'prop-types';
import { router } from 'app';
import pluginId from 'pluginId';
import { makeSelectLoading, makeSelectMenu, makeSelectModels } from 'containers/App/selectors';
import { deleteContentType } from 'containers/App/actions';
@ -23,8 +24,7 @@ import ContentHeader from 'components/ContentHeader';
import EmptyContentTypeView from 'components/EmptyContentTypeView';
import TableList from 'components/TableList';
import injectSaga from 'utils/injectSaga';
import injectReducer from 'utils/injectReducer';
// Utils
import { storeData } from '../../utils/storeData';
import selectHomePage from './selectors';
@ -140,8 +140,8 @@ function mapDispatchToProps(dispatch) {
}
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = injectReducer({ key: 'homePage', reducer });
const withSaga = injectSaga({ key: 'homePage', saga });
const withReducer = strapi.injectReducer({ key: 'homePage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'homePage', saga, pluginId });
export default compose(
withReducer,

View File

@ -1,9 +1,10 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the homePage state domain
*/
const selectHomePageDomain = () => state => state.get('homePage');
const selectHomePageDomain = () => state => state.get(`${pluginId}_homePage`);
/**
* Other specific selectors

View File

@ -13,6 +13,7 @@ import { FormattedMessage } from 'react-intl';
import { NavLink } from 'react-router-dom';
import PropTypes from 'prop-types';
import { router } from 'app';
import pluginId from 'pluginId';
// Global selectors
import { makeSelectMenu } from 'containers/App/selectors';
import { makeSelectContentTypeUpdated } from 'containers/Form/selectors';
@ -23,8 +24,6 @@ import Form from 'containers/Form';
import List from 'components/List';
import PluginLeftMenu from 'components/PluginLeftMenu';
import forms from 'containers/Form/forms.json';
import injectSaga from 'utils/injectSaga';
import injectReducer from 'utils/injectReducer';
import { storeData } from '../../utils/storeData';
import {
cancelChanges,
@ -355,8 +354,8 @@ function mapDispatchToProps(dispatch) {
}
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withSaga = injectSaga({ key: 'modelPage', saga });
const withReducer = injectReducer({ key: 'modelPage', reducer });
const withSaga = strapi.injectSaga({ key: 'modelPage', saga, pluginId });
const withReducer = strapi.injectReducer({ key: 'modelPage', reducer, pluginId });
export default compose(
withReducer,

View File

@ -1,4 +1,4 @@
import { LOCATION_CHANGE } from 'react-router-redux';
// import { LOCATION_CHANGE } from 'react-router-redux';
import {
capitalize,
cloneDeep,
@ -13,7 +13,15 @@ import {
unset,
} from 'lodash';
import pluralize from 'pluralize';
import { takeLatest, call, take, put, fork, cancel, select } from 'redux-saga/effects';
import {
takeLatest,
call,
// take,
put,
fork,
// cancel,
select,
} from 'redux-saga/effects';
import request from 'utils/request';
@ -139,13 +147,18 @@ export function* submitChanges(action) {
}
function* defaultSaga() {
const loadModelWatcher = yield fork(takeLatest, MODEL_FETCH, fetchModel);
const loadSubmitChanges = yield fork(takeLatest, SUBMIT, submitChanges);
yield fork(takeLatest, MODEL_FETCH, fetchModel);
yield fork(takeLatest, SUBMIT, submitChanges);
yield take(LOCATION_CHANGE);
// TODO fix Router (Other PR);
// const loadModelWatcher = yield fork(takeLatest, MODEL_FETCH, fetchModel);
// const loadSubmitChanges = yield fork(takeLatest, SUBMIT, submitChanges);
yield cancel(loadModelWatcher);
yield cancel(loadSubmitChanges);
// yield take(LOCATION_CHANGE);
// yield cancel(loadModelWatcher);
// yield cancel(loadSubmitChanges);
}
export default defaultSaga;

View File

@ -1,9 +1,10 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the modelPage state domain
*/
const selectModelPageDomain = () => state => state.get('modelPage');
const selectModelPageDomain = () => state => state.get(`${pluginId}_modelPage`);
/**
* Other specific selectors

View File

@ -0,0 +1,7 @@
const pluginPkg = require('../../package.json');
const pluginId = pluginPkg.name.replace(
/^strapi-plugin-/i,
''
);
module.exports = pluginId;

View File

@ -1,10 +0,0 @@
{
"/": {
"name": "homePage",
"container": "HomePage"
},
"/models/:modelName": {
"name": "modelPage",
"container": "ModelPage"
}
}

View File

@ -167,11 +167,11 @@ describe('Test CTB', () => {
cy.window()
.its('__store__')
.its('content-manager')
.its('store')
.then(pluginStore => {
const displayedFields = pluginStore
.getState()
.getIn(['global', 'schema', 'models', 'product', 'editDisplay', 'fields'])
.getIn(['content-manager_global', 'schema', 'models', 'product', 'editDisplay', 'fields'])
.toJS();
expect(displayedFields).to.include.members([

View File

@ -1,5 +0,0 @@
/*
*
* App actions
*
*/

View File

@ -1,5 +0,0 @@
/*
*
* App constants
*
*/

View File

@ -6,41 +6,22 @@
*/
import React from 'react';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { Switch, Route } from 'react-router-dom';
import { bindActionCreators, compose } from 'redux';
// Utils
import { pluginId } from 'app';
import pluginId from 'pluginId';
// Containers
import HomePage from 'containers/HomePage';
import NotFoundPage from 'containers/NotFoundPage';
class App extends React.Component {
render() {
return (
<div className={pluginId}>
<Switch>
<Route path={`/plugins/${pluginId}`} component={HomePage} exact />
<Route component={NotFoundPage} />
</Switch>
</div>
);
}
function App() {
return (
<div className={pluginId}>
<Switch>
<Route path={`/plugins/${pluginId}`} component={HomePage} exact />
<Route component={NotFoundPage} />
</Switch>
</div>
);
}
App.propTypes = {};
export function mapDispatchToProps(dispatch) {
return bindActionCreators({}, dispatch);
}
const mapStateToProps = createStructuredSelector({});
// Wrap the component to inject dispatch and state into it
const withConnect = connect(
mapStateToProps,
mapDispatchToProps,
);
export default compose(withConnect)(App);
export default App;

View File

@ -1,18 +0,0 @@
/*
*
* App reducer
*
*/
import { fromJS } from 'immutable';
const initialState = fromJS({});
function appReducer(state = initialState, action) {
switch (action.type) {
default:
return state;
}
}
export default appReducer;

View File

@ -1,9 +0,0 @@
// import { createSelector } from 'reselect';
/**
* Direct selector to the list state domain
*/
// const selectGlobalDomain = () => state => state.get('global');
export {};

View File

@ -12,6 +12,7 @@ import { CopyToClipboard } from 'react-copy-to-clipboard';
import { bindActionCreators, compose } from 'redux';
import { get, isEmpty } from 'lodash';
import cn from 'classnames';
import pluginId from 'pluginId';
// Components
import PluginHeader from 'components/PluginHeader';
import PopUpWarning from 'components/PopUpWarning';
@ -19,11 +20,8 @@ import Block from 'components/Block';
import Row from 'components/Row';
import LoadingIndicatorPage from 'components/LoadingIndicatorPage';
import Input from 'components/InputsIndex';
import { pluginId } from 'app';
// Utils
import auth from 'utils/auth';
import injectReducer from 'utils/injectReducer';
import injectSaga from 'utils/injectSaga';
import openWithNewTab from 'utils/openWithNewTab';
// Actions
import {
@ -245,8 +243,8 @@ const withConnect = connect(
mapStateToProps,
mapDispatchToProps,
);
const withReducer = injectReducer({ key: 'homePage', reducer });
const withSaga = injectSaga({ key: 'homePage', saga });
const withReducer = strapi.injectReducer({ key: 'homePage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'homePage', saga, pluginId });
export default compose(
withReducer,

View File

@ -47,7 +47,7 @@ function* submit() {
}, init);
};
const body = createBody(cloneDeep(form));
console.log({ form, body });
if (body.restrictedAccess && body.password === '') {
return yield put(
setFormErrors({ password: [{ id: 'components.Input.error.validation.required' }] }),

View File

@ -1,9 +1,10 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the homePage state domain
*/
const selectHomePageDomain = () => state => state.get('homePage');
const selectHomePageDomain = () => state => state.get(`${pluginId}_homePage`);
/**
* Default selector used by HomePage
@ -30,4 +31,4 @@ const makeSelectVersionToDelete = () => createSelector(
);
export default selectHomePage;
export { makeSelectForm, makeSelectVersionToDelete, makeSelectPrefix };
export { makeSelectForm, makeSelectVersionToDelete, makeSelectPrefix };

View File

@ -0,0 +1,7 @@
const pluginPkg = require('../../package.json');
const pluginId = pluginPkg.name.replace(
/^strapi-plugin-/i,
''
);
module.exports = pluginId;

View File

@ -7,9 +7,7 @@
import React from 'react';
import { Switch, Route } from 'react-router-dom';
// Utils
import { pluginId } from 'app';
import pluginId from 'pluginId';
// Containers
import ConfigPage from 'containers/ConfigPage';

View File

@ -1,18 +0,0 @@
/*
*
* App reducer
*
*/
import { fromJS } from 'immutable';
const initialState = fromJS({});
function appReducer(state = initialState, action) {
switch (action.type) {
default:
return state;
}
}
export default appReducer;

View File

@ -1,9 +0,0 @@
// import { createSelector } from 'reselect';
/**
* Direct selector to the list state domain
*/
// const selectGlobalDomain = () => state => state.get('global');
export {};

View File

@ -9,6 +9,7 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators, compose } from 'redux';
import { findIndex, get, isEmpty } from 'lodash';
import pluginId from 'pluginId';
// You can find these components in either
// ./node_modules/strapi-helper-plugin/lib/src
@ -20,12 +21,6 @@ import PluginHeader from 'components/PluginHeader';
// Plugin's components
import EditForm from 'components/EditForm';
// You can find these utils in either
// ./node_modules/strapi-helper-plugin/lib/src
// or strapi/packages/strapi-helper-plugin/lib/src
import injectReducer from 'utils/injectReducer';
import injectSaga from 'utils/injectSaga';
import {
getSettings,
onCancel,
@ -180,8 +175,8 @@ const mapStateToProps = selectConfigPage();
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = injectReducer({ key: 'configPage', reducer });
const withSaga = injectSaga({ key: 'configPage', saga });
const withReducer = strapi.injectReducer({ key: 'configPage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'configPage', saga, pluginId });
export default compose(
withReducer,

View File

@ -1,9 +1,10 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the configPage state domain
*/
const selectConfigPageDomain = () => state => state.get('configPage');
const selectConfigPageDomain = () => state => state.get(`${pluginId}_configPage`);
/**
* Default selector used by ConfigPage

View File

@ -0,0 +1,7 @@
const pluginPkg = require('../../package.json');
const pluginId = pluginPkg.name.replace(
/^strapi-plugin-/i,
''
);
module.exports = pluginId;

View File

@ -14,9 +14,7 @@ import 'flag-icon-css/css/flag-icon.css';
import 'react-select/dist/react-select.css';
import { Switch, Route } from 'react-router-dom';
import { isEmpty } from 'lodash';
import { pluginId } from 'app';
import injectSaga from 'utils/injectSaga';
import pluginId from 'pluginId';
import HomePage from 'containers/HomePage';
@ -24,6 +22,7 @@ import { menuFetch, environmentsFetch } from './actions';
import { makeSelectLoading, makeSelectSections } from './selectors';
import styles from './styles.scss';
import reducer from './reducer';
import saga from './sagas';
/* eslint-disable react/require-default-props */
@ -95,9 +94,11 @@ const mapStateToProps = createStructuredSelector({
// Wrap the component to inject dispatch and state into it
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withSaga = injectSaga({ key: 'global', saga });
const withReducer = strapi.injectReducer({ key: 'global', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'global', saga, pluginId });
export default compose(
withReducer,
withSaga,
withConnect,
)(App);

View File

@ -1,10 +1,11 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the list state domain
*/
const selectGlobalDomain = () => state => state.get('global');
const selectGlobalDomain = () => state => state.get(`${pluginId}_global`);
const selectLocationState = () => {
let prevRoutingState;

View File

@ -9,6 +9,7 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators, compose } from 'redux';
import { createStructuredSelector } from 'reselect';
import pluginId from 'pluginId';
import {
endsWith,
@ -45,8 +46,6 @@ import { makeSelectSections, makeSelectEnvironments } from 'containers/App/selec
// utils
import unknowFlag from 'assets/images/unknow_flag.png';
import injectReducer from 'utils/injectReducer';
import injectSaga from 'utils/injectSaga';
import supportedFlags from 'utils/supportedFlags.json';
import { checkFormValidity, getRequiredInputsDb } from '../../utils/inputValidations';
import getFlag, { formatLanguageLocale } from '../../utils/getFlag';
@ -564,8 +563,8 @@ HomePage.propTypes = {
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = injectReducer({ key: 'homePage', reducer });
const withSaga = injectSaga({ key: 'homePage', saga });
const withReducer = strapi.injectReducer({ key: 'homePage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'homePage', saga, pluginId });
export default compose(
withReducer,

View File

@ -1,6 +1,15 @@
import { LOCATION_CHANGE } from 'react-router-redux';
// import { LOCATION_CHANGE } from 'react-router-redux';
import { forEach, set, map, replace } from 'lodash';
import { all, call, take, put, fork, cancel, select, takeLatest } from 'redux-saga/effects';
import {
all,
call,
// take,
put,
fork,
// cancel,
select,
takeLatest,
} from 'redux-saga/effects';
import request from 'utils/request';
// selectors
import { makeSelectModifiedData } from './selectors';
@ -240,28 +249,40 @@ export function* fetchSpecificDatabase(action) {
// Individual exports for testing
export function* defaultSaga() {
const loadConfigWatcher = yield fork(takeLatest, CONFIG_FETCH, fetchConfig);
const loadLanguagesWatcher = yield fork(takeLatest, LANGUAGES_FETCH, fetchLanguages);
const editConfigWatcher = yield fork(takeLatest, EDIT_SETTINGS, settingsEdit);
const postLanguageWatcher = yield fork(takeLatest, NEW_LANGUAGE_POST, postLanguage);
const deleteLanguageWatcher = yield fork(takeLatest, LANGUAGE_DELETE, deleteLanguage);
const loadDatabasesWatcher = yield fork(takeLatest, DATABASES_FETCH, fetchDatabases);
const postDatabaseWatcher = yield fork(takeLatest, NEW_DATABASE_POST, postDatabase);
const deleteDatabaseWatcher = yield fork(takeLatest, DATABASE_DELETE, deleteDatabase);
const fetchSpecificDatabaseWatcher = yield fork(takeLatest, SPECIFIC_DATABASE_FETCH, fetchSpecificDatabase);
const editDatabaseWatcher = yield fork(takeLatest, DATABASE_EDIT, editDatabase);
yield fork(takeLatest, CONFIG_FETCH, fetchConfig);
yield fork(takeLatest, LANGUAGES_FETCH, fetchLanguages);
yield fork(takeLatest, EDIT_SETTINGS, settingsEdit);
yield fork(takeLatest, NEW_LANGUAGE_POST, postLanguage);
yield fork(takeLatest, LANGUAGE_DELETE, deleteLanguage);
yield fork(takeLatest, DATABASES_FETCH, fetchDatabases);
yield fork(takeLatest, NEW_DATABASE_POST, postDatabase);
yield fork(takeLatest, DATABASE_DELETE, deleteDatabase);
yield fork(takeLatest, SPECIFIC_DATABASE_FETCH, fetchSpecificDatabase);
yield fork(takeLatest, DATABASE_EDIT, editDatabase);
yield take(LOCATION_CHANGE);
yield cancel(loadConfigWatcher);
yield cancel(loadLanguagesWatcher);
yield cancel(editConfigWatcher);
yield cancel(postLanguageWatcher);
yield cancel(deleteLanguageWatcher);
yield cancel(loadDatabasesWatcher);
yield cancel(postDatabaseWatcher);
yield cancel(deleteDatabaseWatcher);
yield cancel(fetchSpecificDatabaseWatcher);
yield cancel(editDatabaseWatcher);
// TODO Fix router (Other PR)
// const loadConfigWatcher = yield fork(takeLatest, CONFIG_FETCH, fetchConfig);
// const loadLanguagesWatcher = yield fork(takeLatest, LANGUAGES_FETCH, fetchLanguages);
// const editConfigWatcher = yield fork(takeLatest, EDIT_SETTINGS, settingsEdit);
// const postLanguageWatcher = yield fork(takeLatest, NEW_LANGUAGE_POST, postLanguage);
// const deleteLanguageWatcher = yield fork(takeLatest, LANGUAGE_DELETE, deleteLanguage);
// const loadDatabasesWatcher = yield fork(takeLatest, DATABASES_FETCH, fetchDatabases);
// const postDatabaseWatcher = yield fork(takeLatest, NEW_DATABASE_POST, postDatabase);
// const deleteDatabaseWatcher = yield fork(takeLatest, DATABASE_DELETE, deleteDatabase);
// const fetchSpecificDatabaseWatcher = yield fork(takeLatest, SPECIFIC_DATABASE_FETCH, fetchSpecificDatabase);
// const editDatabaseWatcher = yield fork(takeLatest, DATABASE_EDIT, editDatabase);
// yield take(LOCATION_CHANGE);
// yield cancel(loadConfigWatcher);
// yield cancel(loadLanguagesWatcher);
// yield cancel(editConfigWatcher);
// yield cancel(postLanguageWatcher);
// yield cancel(deleteLanguageWatcher);
// yield cancel(loadDatabasesWatcher);
// yield cancel(postDatabaseWatcher);
// yield cancel(deleteDatabaseWatcher);
// yield cancel(fetchSpecificDatabaseWatcher);
// yield cancel(editDatabaseWatcher);
}
// All sagas to be loaded

View File

@ -1,9 +1,10 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the home state domain
*/
const selectHomePageDomain = () => state => state.get('homePage');
const selectHomePageDomain = () => state => state.get(`${pluginId}_homePage`);
/**
* Other specific selectors

View File

@ -0,0 +1,7 @@
const pluginPkg = require('../../package.json');
const pluginId = pluginPkg.name.replace(
/^strapi-plugin-/i,
''
);
module.exports = pluginId;

View File

@ -1,6 +0,0 @@
{
"(/:slug(/:env))": {
"name": "homePage",
"container": "HomePage"
}
}

View File

@ -8,8 +8,7 @@
import React from 'react';
import { Switch, Route } from 'react-router-dom';
// Utils
import { pluginId } from 'app';
import pluginId from 'pluginId';
// Containers
import ConfigPage from 'containers/ConfigPage';

View File

@ -1,18 +0,0 @@
/*
*
* App reducer
*
*/
import { fromJS } from 'immutable';
const initialState = fromJS({});
function appReducer(state = initialState, action) {
switch (action.type) {
default:
return state;
}
}
export default appReducer;

View File

@ -1,9 +0,0 @@
// import { createSelector } from 'reselect';
/**
* Direct selector to the list state domain
*/
// const selectGlobalDomain = () => state => state.get('global');
export {};

View File

@ -9,6 +9,7 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators, compose } from 'redux';
import { findIndex, get, isEmpty } from 'lodash';
import pluginId from 'pluginId';
// You can find these components in either
// ./node_modules/strapi-helper-plugin/lib/src
@ -20,12 +21,6 @@ import PluginHeader from 'components/PluginHeader';
// Plugin's components
import EditForm from 'components/EditForm';
// You can find these utils in either
// ./node_modules/strapi-helper-plugin/lib/src
// or strapi/packages/strapi-helper-plugin/lib/src
import injectReducer from 'utils/injectReducer';
import injectSaga from 'utils/injectSaga';
import {
getSettings,
onCancel,
@ -180,8 +175,8 @@ const mapStateToProps = selectConfigPage();
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = injectReducer({ key: 'configPage', reducer });
const withSaga = injectSaga({ key: 'configPage', saga });
const withReducer = strapi.injectReducer({ key: 'configPage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'configPage', saga, pluginId });
export default compose(
withReducer,

View File

@ -1,9 +1,10 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the configPage state domain
*/
const selectConfigPageDomain = () => state => state.get('configPage');
const selectConfigPageDomain = () => state => state.get(`${pluginId}_configPage`);
/**
* Default selector used by ConfigPage

View File

@ -11,6 +11,7 @@ import { connect } from 'react-redux';
import { injectIntl } from 'react-intl';
import { bindActionCreators, compose } from 'redux';
import { isEmpty } from 'lodash';
import pluginId from 'pluginId';
// You can find these components in either
// ./node_modules/strapi-helper-plugin/lib/src
@ -28,8 +29,6 @@ import PluginInputFile from 'components/PluginInputFile';
// Utils
import getQueryParameters from 'utils/getQueryParameters';
import injectReducer from 'utils/injectReducer';
import injectSaga from 'utils/injectSaga';
// Actions
import {
@ -221,8 +220,8 @@ const mapStateToProps = selectHomePage();
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = injectReducer({ key: 'homePage', reducer });
const withSaga = injectSaga({ key: 'homePage', saga });
const withReducer = strapi.injectReducer({ key: 'homePage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'homePage', saga, pluginId });
export default compose(
withReducer,

View File

@ -1,7 +1,16 @@
import { LOCATION_CHANGE } from 'react-router-redux';
// import { LOCATION_CHANGE } from 'react-router-redux';
import { Map } from 'immutable';
import { isEmpty } from 'lodash';
import { all, call, fork, put, select, take, takeLatest } from 'redux-saga/effects';
import {
all,
call,
// cancel,
fork,
put,
select,
// take,
takeLatest,
} from 'redux-saga/effects';
import request from 'utils/request';
import {
@ -106,11 +115,13 @@ export function* defaultSaga() {
yield fork(takeLatest, ON_DROP, uploadFiles);
yield fork(takeLatest, ON_SEARCH, search);
const loadDataWatcher = yield fork(takeLatest, GET_DATA, dataGet);
yield fork(takeLatest, GET_DATA, dataGet);
// TODO: Fix router (Other PR)
// const loadDataWatcher = yield fork(takeLatest, GET_DATA, dataGet);
yield take(LOCATION_CHANGE);
// yield take(LOCATION_CHANGE);
yield cancel(loadDataWatcher);
// yield cancel(loadDataWatcher);
}
// All sagas to be loaded

View File

@ -1,9 +1,10 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the homePage state domain
*/
const selectHomePageDomain = () => state => state.get('homePage');
const selectHomePageDomain = () => state => state.get(`${pluginId}_homePage`);
/**
* Default selector used by HomePage

View File

@ -0,0 +1,7 @@
const pluginPkg = require('../../package.json');
const pluginId = pluginPkg.name.replace(
/^strapi-plugin-/i,
''
);
module.exports = pluginId;

View File

@ -1,5 +0,0 @@
/*
*
* App actions
*
*/

View File

@ -1,5 +0,0 @@
/*
*
* App constants
*
*/

View File

@ -7,13 +7,8 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { Switch, Route } from 'react-router-dom';
import { bindActionCreators, compose } from 'redux';
// Utils
import { pluginId } from 'app';
import pluginId from 'pluginId';
// Containers
import AuthPage from 'containers/AuthPage';
@ -59,18 +54,4 @@ App.propTypes = {
location: PropTypes.object.isRequired,
};
export function mapDispatchToProps(dispatch) {
return bindActionCreators(
{},
dispatch,
);
}
const mapStateToProps = createStructuredSelector({});
// Wrap the component to inject dispatch and state into it
const withConnect = connect(mapStateToProps, mapDispatchToProps);
export default compose(
withConnect,
)(App);
export default App;

View File

@ -1,18 +0,0 @@
/*
*
* App reducer
*
*/
import { fromJS } from 'immutable';
const initialState = fromJS({});
function appReducer(state = initialState, action) {
switch (action.type) {
default:
return state;
}
}
export default appReducer;

View File

@ -1,7 +0,0 @@
// import { createSelector } from 'reselect';
/**
* Direct selector to the list state domain
*/
// const selectGlobalDomain = () => state => state.get('global');

View File

@ -12,6 +12,7 @@ import { Link } from 'react-router-dom';
import { FormattedMessage } from 'react-intl';
import { findIndex, get, isBoolean, isEmpty, map, replace } from 'lodash';
import cn from 'classnames';
import pluginId from 'pluginId';
// Logo
import LogoStrapi from 'assets/images/logo_strapi.png';
@ -22,8 +23,6 @@ import Input from 'components/InputsIndex';
// Utils
import auth from 'utils/auth';
import injectSaga from 'utils/injectSaga';
import injectReducer from 'utils/injectReducer';
import {
hideLoginErrorsInput,
@ -328,16 +327,8 @@ function mapDispatchToProps(dispatch) {
}
const withConnect = connect(mapStateToProps, mapDispatchToProps);
/* Remove this line if the container doesn't have a route and
* check the documentation to see how to create the container's store
*/
const withReducer = injectReducer({ key: 'authPage', reducer });
/* Remove the line below the container doesn't have a route and
* check the documentation to see how to create the container's store
*/
const withSaga = injectSaga({ key: 'authPage', saga });
const withReducer = strapi.injectReducer({ key: 'authPage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'authPage', saga, pluginId });
export default compose(
withReducer,

View File

@ -1,9 +1,10 @@
import { createSelector } from 'reselect';
import pluginId from 'pluginId';
/**
* Direct selector to the authPage state domain
*/
const selectAuthPageDomain = () => (state) => state.get('authPage');
const selectAuthPageDomain = () => (state) => state.get(`${pluginId}_authPage`);
/**
* Default selector used by AuthPage

View File

@ -12,6 +12,7 @@ import { bindActionCreators, compose } from 'redux';
import { FormattedMessage } from 'react-intl';
import { findIndex, get, isEmpty, isEqual, size } from 'lodash';
import cn from 'classnames';
import pluginId from 'pluginId';
// Design
import BackHeader from 'components/BackHeader';
@ -23,9 +24,6 @@ import PluginHeader from 'components/PluginHeader';
import Plugins from 'components/Plugins';
import Policies from 'components/Policies';
import injectSaga from 'utils/injectSaga';
import injectReducer from 'utils/injectReducer';
// Actions
import {
addUser,
@ -326,16 +324,8 @@ function mapDispatchToProps(dispatch) {
}
const withConnect = connect(mapStateToProps, mapDispatchToProps);
/* Remove this line if the container doesn't have a route and
* check the documentation to see how to create the container's store
*/
const withReducer = injectReducer({ key: 'editPage', reducer });
/* Remove the line below the container doesn't have a route and
* check the documentation to see how to create the container's store
*/
const withSaga = injectSaga({ key: 'editPage', saga });
const withReducer = strapi.injectReducer({ key: 'editPage', reducer, pluginId });
const withSaga = strapi.injectSaga({ key: 'editPage', saga, pluginId });
export default compose(
withReducer,

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