@@ -265,10 +288,17 @@ function mapDispatchToProps(dispatch) {
);
}
-const withConnect = connect(mapStateToProps, mapDispatchToProps);
+const withConnect = connect(
+ mapStateToProps,
+ mapDispatchToProps,
+);
const withReducer = injectReducer({ key: 'homePage', reducer });
const withSaga = injectSaga({ key: 'homePage', saga });
// export default connect(mapDispatchToProps)(HomePage);
-export default compose(withReducer, withSaga, withConnect)(HomePage);
+export default compose(
+ withReducer,
+ withSaga,
+ withConnect,
+)(HomePage);
diff --git a/packages/strapi-admin/admin/src/containers/HomePage/saga.js b/packages/strapi-admin/admin/src/containers/HomePage/saga.js
index 881ecb72e3..90fd9ea455 100644
--- a/packages/strapi-admin/admin/src/containers/HomePage/saga.js
+++ b/packages/strapi-admin/admin/src/containers/HomePage/saga.js
@@ -1,14 +1,7 @@
import 'whatwg-fetch';
import { dropRight, take } from 'lodash';
import removeMd from 'remove-markdown';
-import {
- all,
- call,
- fork,
- put,
- select,
- takeLatest,
-} from 'redux-saga/effects';
+import { all, call, fork, put, select, takeLatest } from 'redux-saga/effects';
import request from 'utils/request';
import { getArticlesSucceeded, submitSucceeded } from './actions';
import { GET_ARTICLES, SUBMIT } from './constants';
@@ -19,7 +12,11 @@ function* getArticles() {
const articles = yield call(fetchArticles);
const posts = articles.posts.reduce((acc, curr) => {
// Limit to 200 characters and remove last word.
- const content = dropRight(take(removeMd(curr.markdown), 250).join('').split(' ')).join(' ');
+ const content = dropRight(
+ take(removeMd(curr.markdown), 250)
+ .join('')
+ .split(' '),
+ ).join(' ');
acc.push({
title: curr.title,
@@ -31,17 +28,19 @@ function* getArticles() {
}, []);
yield put(getArticlesSucceeded(posts));
- } catch(err) {
+ } catch (err) {
// Silent
}
}
-
function* submit() {
try {
const body = yield select(makeSelectBody());
- yield call(request, 'https://analytics.strapi.io/register', { method: 'POST', body });
- } catch(err) {
+ yield call(request, 'https://analytics.strapi.io/register', {
+ method: 'POST',
+ body,
+ });
+ } catch (err) {
// silent
} finally {
strapi.notification.success('HomePage.notification.newsLetter.success');
@@ -56,11 +55,12 @@ function* defaultSaga() {
]);
}
-
function fetchArticles() {
- return fetch('https://blog.strapi.io/ghost/api/v0.1/posts/?client_id=ghost-frontend&client_secret=1f260788b4ec&limit=2', {})
- .then(resp => {
- return resp.json ? resp.json() : resp;
- });
+ return fetch(
+ 'https://blog.strapi.io/ghost/api/v0.1/posts/?client_id=ghost-frontend&client_secret=1f260788b4ec&limit=2',
+ {},
+ ).then(resp => {
+ return resp.json ? resp.json() : resp;
+ });
}
export default defaultSaga;
diff --git a/packages/strapi-admin/admin/src/containers/Onboarding/actions.js b/packages/strapi-admin/admin/src/containers/Onboarding/actions.js
new file mode 100644
index 0000000000..869700caff
--- /dev/null
+++ b/packages/strapi-admin/admin/src/containers/Onboarding/actions.js
@@ -0,0 +1,43 @@
+/*
+ *
+ * Onboarding actions
+ *
+ */
+
+import { GET_VIDEOS, GET_VIDEOS_SUCCEEDED, ON_CLICK, SET_VIDEOS_DURATION, UPDATE_VIDEO_START_TIME } from './constants';
+
+export function getVideos() {
+ return {
+ type: GET_VIDEOS,
+ };
+}
+
+export function getVideosSucceeded(videos) {
+ return {
+ type: GET_VIDEOS_SUCCEEDED,
+ videos,
+ };
+}
+
+export function onClick(e) {
+ return {
+ type: ON_CLICK,
+ index: parseInt(e.currentTarget.id, 10),
+ };
+}
+
+export function setVideoDuration(index, duration) {
+ return {
+ type: SET_VIDEOS_DURATION,
+ index: parseInt(index, 10),
+ duration: parseFloat(duration, 10),
+ };
+}
+
+export function updateVideoStartTime(index, startTime) {
+ return {
+ type: UPDATE_VIDEO_START_TIME,
+ index: parseInt(index, 10),
+ startTime: parseFloat(startTime, 10),
+ };
+}
diff --git a/packages/strapi-admin/admin/src/containers/Onboarding/constants.js b/packages/strapi-admin/admin/src/containers/Onboarding/constants.js
new file mode 100644
index 0000000000..7e3a0fe6c5
--- /dev/null
+++ b/packages/strapi-admin/admin/src/containers/Onboarding/constants.js
@@ -0,0 +1,12 @@
+/*
+ *
+ * Onboarding constants
+ *
+ */
+
+export const GET_VIDEOS = 'StrapiAdmin/Onboarding/GET_VIDEOS';
+export const GET_VIDEOS_SUCCEEDED =
+ 'StrapiAdmin/Onboarding/GET_VIDEOS_SUCCEEDED';
+ export const ON_CLICK = 'StrapiAdmin/Onboarding/ON_CLICK';
+ export const SET_VIDEOS_DURATION = 'StrapiAdmin/Onboarding/SET_VIDEOS_DURATION';
+ export const UPDATE_VIDEO_START_TIME = 'StrapiAdmin/Onboarding/UPDATE_VIDEO_START_TIME';
diff --git a/packages/strapi-admin/admin/src/containers/Onboarding/index.js b/packages/strapi-admin/admin/src/containers/Onboarding/index.js
new file mode 100644
index 0000000000..438edffcdb
--- /dev/null
+++ b/packages/strapi-admin/admin/src/containers/Onboarding/index.js
@@ -0,0 +1,133 @@
+/**
+ *
+ * Onboarding
+ *
+ */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import cn from 'classnames';
+import { connect } from 'react-redux';
+import { bindActionCreators, compose } from 'redux';
+import { getVideos, onClick, setVideoDuration, updateVideoStartTime } from './actions';
+
+import injectSaga from 'utils/injectSaga';
+import injectReducer from 'utils/injectReducer';
+import makeSelectOnboarding from './selectors';
+import reducer from './reducer';
+import saga from './saga';
+
+import OnboardingVideo from 'components/OnboardingVideo';
+
+import styles from './styles.scss';
+
+export class Onboarding extends React.Component {
+ state = { showVideos: false };
+
+ componentWillMount() {
+ this.setState({ showVideos: true });
+ this.props.getVideos();
+ }
+
+ toggleVideos = () => {
+ // Display videos card
+ this.setState(prevState => ({ showVideos: !prevState.showVideos }));
+
+ // EmitEvent
+ const { showVideos } = this.state;
+ const eventName = showVideos ? 'didOpenGetStartedVideoContainer' : 'didCloseGetStartedVideoContainer';
+ this.context.emitEvent(eventName);
+ };
+
+ updateLocalStorage = (index, current) => {
+ // Update store
+ this.props.updateVideoStartTime(index, current);
+
+ // Update localStorage
+ let videosTime = JSON.parse(localStorage.getItem('videos'));
+ videosTime.fill(0);
+ videosTime[index] = current;
+ localStorage.setItem('videos', JSON.stringify(videosTime));
+ };
+
+ // eslint-disable-line react/prefer-stateless-function
+ render() {
+ const { videos, onClick, setVideoDuration } = this.props;
+
+ return (
+
+
+
+
Get started video
+
25% completed
+
+
+
+ {videos.map((video, i) => {
+ return (
+
+ );
+ })}
+
+
+
+
+
+
+
+ );
+ }
+}
+Onboarding.contextTypes = {
+ emitEvent: PropTypes.func,
+};
+
+Onboarding.propTypes = {
+ getVideos: PropTypes.func.isRequired,
+};
+
+const mapStateToProps = makeSelectOnboarding();
+
+function mapDispatchToProps(dispatch) {
+ return bindActionCreators({ getVideos, onClick, setVideoDuration, updateVideoStartTime }, 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: 'onboarding', 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: 'onboarding', saga });
+
+export default compose(
+ withReducer,
+ withSaga,
+ withConnect,
+)(Onboarding);
diff --git a/packages/strapi-admin/admin/src/containers/Onboarding/reducer.js b/packages/strapi-admin/admin/src/containers/Onboarding/reducer.js
new file mode 100644
index 0000000000..92b9509aab
--- /dev/null
+++ b/packages/strapi-admin/admin/src/containers/Onboarding/reducer.js
@@ -0,0 +1,47 @@
+/*
+ *
+ * Onboarding reducer
+ *
+ */
+
+import { fromJS } from 'immutable';
+import { GET_VIDEOS_SUCCEEDED, ON_CLICK, SET_VIDEOS_DURATION, UPDATE_VIDEO_START_TIME } from './constants';
+
+const initialState = fromJS({
+ videos: fromJS([]),
+});
+
+function onboardingReducer(state = initialState, action) {
+ switch (action.type) {
+ case GET_VIDEOS_SUCCEEDED:
+ return state.update('videos', () => fromJS(action.videos));
+ case ON_CLICK:
+ return state.updateIn(['videos'], list => {
+ return list.reduce((acc, current, index) => {
+
+ if (index === action.index) {
+ return acc.updateIn([index, 'isOpen'], v => !v);
+ }
+
+ return acc.updateIn([index, 'isOpen'], () => false);
+ }, list);
+ });
+ case SET_VIDEOS_DURATION:
+ return state.updateIn(['videos', action.index, 'duration'], () => action.duration);
+ case UPDATE_VIDEO_START_TIME:
+ return state.updateIn(['videos'], list => {
+ return list.reduce((acc, current, index) => {
+
+ if (index === action.index) {
+ return acc.updateIn([index, 'startTime'], () => action.startTime);
+ }
+
+ return acc.updateIn([index, 'startTime'], () => 0);
+ }, list);
+ });
+ default:
+ return state;
+ }
+}
+
+export default onboardingReducer;
diff --git a/packages/strapi-admin/admin/src/containers/Onboarding/saga.js b/packages/strapi-admin/admin/src/containers/Onboarding/saga.js
new file mode 100644
index 0000000000..e1eb49a052
--- /dev/null
+++ b/packages/strapi-admin/admin/src/containers/Onboarding/saga.js
@@ -0,0 +1,50 @@
+import { GET_VIDEOS } from './constants';
+import { getVideosSucceeded } from './actions';
+import request from 'utils/request';
+
+import { all, call, fork, takeLatest, put } from 'redux-saga/effects';
+
+function* getVideos() {
+ try {
+ const videos = yield call(request, 'https://strapi.io/videos', {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ },
+ false,
+ true,
+ { noAuth: true },
+ );
+
+ let currTimes = Array.apply(null, Array(videos.length)).map(Number.prototype.valueOf,0);
+
+ // Retrieve start time if enable in localStorage
+ if (localStorage.getItem('videos')) {
+ currTimes.splice(0, currTimes.length, ...JSON.parse(localStorage.getItem('videos')));
+ } else {
+ localStorage.setItem('videos', JSON.stringify(currTimes));
+ }
+
+ yield put(
+ getVideosSucceeded(
+ videos.map((video, index) => {
+ video.isOpen = false;
+ video.duration = null;
+ video.startTime = currTimes[index];
+
+ return video;
+ }),
+ ),
+ );
+ } catch (err) {
+ console.log('err');
+ console.log({ err });
+ }
+}
+
+function* defaultSaga() {
+ yield all([fork(takeLatest, GET_VIDEOS, getVideos)]);
+}
+
+export default defaultSaga;
diff --git a/packages/strapi-admin/admin/src/containers/Onboarding/selectors.js b/packages/strapi-admin/admin/src/containers/Onboarding/selectors.js
new file mode 100644
index 0000000000..2f5dd23c08
--- /dev/null
+++ b/packages/strapi-admin/admin/src/containers/Onboarding/selectors.js
@@ -0,0 +1,25 @@
+import { createSelector } from 'reselect';
+
+/**
+ * Direct selector to the onboarding state domain
+ */
+const selectOnboardingDomain = () => (state) => state.get('onboarding');
+
+/**
+ * Other specific selectors
+ */
+
+
+/**
+ * Default selector used by Onboarding
+ */
+
+const makeSelectOnboarding = () => createSelector(
+ selectOnboardingDomain(),
+ (substate) => substate.toJS()
+);
+
+export default makeSelectOnboarding;
+export {
+ selectOnboardingDomain,
+};
diff --git a/packages/strapi-admin/admin/src/containers/Onboarding/styles.scss b/packages/strapi-admin/admin/src/containers/Onboarding/styles.scss
new file mode 100644
index 0000000000..cd57c0c77e
--- /dev/null
+++ b/packages/strapi-admin/admin/src/containers/Onboarding/styles.scss
@@ -0,0 +1,77 @@
+.videosWrapper {
+ position: fixed;
+ right: 15px;
+ bottom: 15px;
+ button,
+ button:focus,
+ a {
+ cursor: pointer;
+ outline: 0;
+ }
+ p {
+ margin-bottom: 0;
+ }
+ .videosHeader {
+ padding: 15px 15px 0 15px;
+ p {
+ font-family: Lato-Bold;
+ font-size: 11px;
+ text-transform: uppercase;
+ display: inline-block;
+ width: 50%;
+ vertical-align: top;
+ color: #5c5f66;
+ &:last-of-type {
+ text-align: right;
+ color: #5a9e06;
+ }
+ }
+ }
+ .videosContent {
+ background-color: white;
+ margin-bottom: 10px;
+ margin-right: 15px;
+ box-shadow: 0 2px 4px 0 #e3e9f3;
+ border-radius: 3px;
+ transition: all 0.3s linear;
+ &.shown {
+ visibility: visible;
+ opacity: 1;
+ }
+ &.hide {
+ opacity: 0;
+ visibility: hidden;
+ }
+
+ ul {
+ list-style: none;
+ padding: 10px 0;
+ }
+ }
+ .openBtn {
+ width: 38px;
+ height: 38px;
+ float: right;
+ button {
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ color: white;
+ background: #0e7de7;
+ -webkit-box-shadow: 0px 2px 4px 0px rgba(227, 233, 243, 1);
+ -moz-box-shadow: 0px 2px 4px 0px rgba(227, 233, 243, 1);
+ box-shadow: 0px 2px 4px 0px rgba(227, 233, 243, 1);
+ i:last-of-type {
+ display: none;
+ }
+ &.active {
+ i:first-of-type {
+ display: none;
+ }
+ i:last-of-type {
+ display: block;
+ }
+ }
+ }
+ }
+}
diff --git a/packages/strapi-admin/admin/src/containers/Onboarding/tests/actions.test.js b/packages/strapi-admin/admin/src/containers/Onboarding/tests/actions.test.js
new file mode 100644
index 0000000000..336c014b91
--- /dev/null
+++ b/packages/strapi-admin/admin/src/containers/Onboarding/tests/actions.test.js
@@ -0,0 +1,18 @@
+
+import {
+ defaultAction,
+} from '../actions';
+import {
+ DEFAULT_ACTION,
+} from '../constants';
+
+describe('Onboarding actions', () => {
+ describe('Default Action', () => {
+ it('has a type of DEFAULT_ACTION', () => {
+ const expected = {
+ type: DEFAULT_ACTION,
+ };
+ expect(defaultAction()).toEqual(expected);
+ });
+ });
+});
diff --git a/packages/strapi-admin/admin/src/containers/Onboarding/tests/index.test.js b/packages/strapi-admin/admin/src/containers/Onboarding/tests/index.test.js
new file mode 100644
index 0000000000..74a5139bcc
--- /dev/null
+++ b/packages/strapi-admin/admin/src/containers/Onboarding/tests/index.test.js
@@ -0,0 +1,10 @@
+// import React from 'react';
+// import { shallow } from 'enzyme';
+
+// import { Onboarding } from '../index';
+
+describe('
', () => {
+ it('Expect to have unit tests specified', () => {
+ expect(true).toEqual(false);
+ });
+});
diff --git a/packages/strapi-admin/admin/src/containers/Onboarding/tests/reducer.test.js b/packages/strapi-admin/admin/src/containers/Onboarding/tests/reducer.test.js
new file mode 100644
index 0000000000..4c16235c3a
--- /dev/null
+++ b/packages/strapi-admin/admin/src/containers/Onboarding/tests/reducer.test.js
@@ -0,0 +1,9 @@
+
+import { fromJS } from 'immutable';
+import onboardingReducer from '../reducer';
+
+describe('onboardingReducer', () => {
+ it('returns the initial state', () => {
+ expect(onboardingReducer(undefined, {})).toEqual(fromJS({}));
+ });
+});
diff --git a/packages/strapi-admin/admin/src/containers/Onboarding/tests/saga.test.js b/packages/strapi-admin/admin/src/containers/Onboarding/tests/saga.test.js
new file mode 100644
index 0000000000..9047074182
--- /dev/null
+++ b/packages/strapi-admin/admin/src/containers/Onboarding/tests/saga.test.js
@@ -0,0 +1,15 @@
+/**
+ * Test sagas
+ */
+
+/* eslint-disable redux-saga/yield-effects */
+// import { take, call, put, select } from 'redux-saga/effects';
+// import { defaultSaga } from '../saga';
+
+// const generator = defaultSaga();
+
+describe('defaultSaga Saga', () => {
+ it('Expect to have unit tests specified', () => {
+ expect(true).toEqual(false);
+ });
+});
diff --git a/packages/strapi-admin/admin/src/containers/Onboarding/tests/selectors.test.js b/packages/strapi-admin/admin/src/containers/Onboarding/tests/selectors.test.js
new file mode 100644
index 0000000000..999875df75
--- /dev/null
+++ b/packages/strapi-admin/admin/src/containers/Onboarding/tests/selectors.test.js
@@ -0,0 +1,10 @@
+// import { fromJS } from 'immutable';
+// import { makeSelectOnboardingDomain } from '../selectors';
+
+// const selector = makeSelectOnboardingDomain();
+
+describe('makeSelectOnboardingDomain', () => {
+ it('Expect to have unit tests specified', () => {
+ expect(true).toEqual(false);
+ });
+});
diff --git a/packages/strapi-admin/package.json b/packages/strapi-admin/package.json
index cf271d1c57..d78b7fade0 100644
--- a/packages/strapi-admin/package.json
+++ b/packages/strapi-admin/package.json
@@ -26,9 +26,13 @@
},
"dependencies": {
"intl": "^1.2.5",
+ "react": "^16.8.1",
+ "react-dom": "^16.8.1",
"react-ga": "^2.4.1",
+ "redux": "^4.0.1",
"remove-markdown": "^0.2.2",
- "shelljs": "^0.7.8"
+ "shelljs": "^0.7.8",
+ "video-react": "^0.13.2"
},
"devDependencies": {
"cross-env": "^5.0.5",
diff --git a/packages/strapi-helper-plugin/lib/server/middlewares/frontendMiddleware.js b/packages/strapi-helper-plugin/lib/server/middlewares/frontendMiddleware.js
index 19b6228af6..3d9db23d93 100644
--- a/packages/strapi-helper-plugin/lib/server/middlewares/frontendMiddleware.js
+++ b/packages/strapi-helper-plugin/lib/server/middlewares/frontendMiddleware.js
@@ -47,7 +47,7 @@ const addDevMiddlewares = (app, webpackConfig) => {
/**
* Front-end middleware
*/
-module.exports = (app) => {
+module.exports = app => {
const webpackConfig = require('../../internals/webpack/webpack.dev.babel');
// const webpackConfig = require(path.resolve(process.cwd(), 'node_modules', 'strapi-helper-plugin', 'internals', 'webpack', 'webpack.dev.babel'));
diff --git a/packages/strapi-helper-plugin/lib/src/utils/auth.js b/packages/strapi-helper-plugin/lib/src/utils/auth.js
index e2316c2cb0..9212f9d7bf 100644
--- a/packages/strapi-helper-plugin/lib/src/utils/auth.js
+++ b/packages/strapi-helper-plugin/lib/src/utils/auth.js
@@ -73,7 +73,6 @@ const auth = {
return null;
},
-
setToken(value = '', isLocalStorage = false, tokenKey = TOKEN_KEY) {
return auth.set(value, tokenKey, isLocalStorage);
},
diff --git a/packages/strapi-helper-plugin/lib/src/utils/request.js b/packages/strapi-helper-plugin/lib/src/utils/request.js
index a83b1606e5..8e25d72e6e 100644
--- a/packages/strapi-helper-plugin/lib/src/utils/request.js
+++ b/packages/strapi-helper-plugin/lib/src/utils/request.js
@@ -9,6 +9,7 @@ import auth from 'utils/auth';
* @return {object} The parsed JSON from the request
*/
function parseJSON(response) {
+ // return response;
return response.json ? response.json() : response;
}
@@ -41,21 +42,22 @@ function checkTokenValidity(response) {
method: 'GET',
headers: {
'Content-Type': 'application/json',
- 'Authorization': `Bearer ${auth.getToken()}`,
+ Authorization: `Bearer ${auth.getToken()}`,
},
};
if (auth.getToken()) {
- return fetch(`${strapi.backendURL}/user/me`, options)
- .then(() => {
- if (response.status === 401) {
- window.location = `${strapi.remoteURL}/plugins/users-permissions/auth/login`;
+ return fetch(`${strapi.backendURL}/user/me`, options).then(() => {
+ if (response.status === 401) {
+ window.location = `${
+ strapi.remoteURL
+ }/plugins/users-permissions/auth/login`;
- auth.clearAppStorage();
- }
+ auth.clearAppStorage();
+ }
- return checkStatus(response, false);
- });
+ return checkStatus(response, false);
+ });
}
}
@@ -72,12 +74,12 @@ function formatQueryParams(params) {
}
/**
-* Server restart watcher
-* @param response
-* @returns {object} the response data
-*/
+ * Server restart watcher
+ * @param response
+ * @returns {object} the response data
+ */
function serverRestartWatcher(response) {
- return new Promise((resolve) => {
+ return new Promise(resolve => {
fetch(`${strapi.backendURL}/_health`, {
method: 'HEAD',
mode: 'no-cors',
@@ -93,8 +95,7 @@ function serverRestartWatcher(response) {
})
.catch(() => {
setTimeout(() => {
- return serverRestartWatcher(response)
- .then(resolve);
+ return serverRestartWatcher(response).then(resolve);
}, 100);
});
});
@@ -108,22 +109,38 @@ function serverRestartWatcher(response) {
*
* @return {object} The response data
*/
-export default function request(url, options = {}, shouldWatchServerRestart = false, stringify = true ) {
+export default function request(...args) {
+ let [url, options = {}, shouldWatchServerRestart, stringify = true, ...rest] = args;
+ let noAuth;
+
+ try {
+ [{ noAuth }] = rest;
+ } catch(err) {
+ noAuth = false;
+ }
+
// Set headers
if (!options.headers) {
- options.headers = Object.assign({
- 'Content-Type': 'application/json',
- }, options.headers, {
- 'X-Forwarded-Host': 'strapi',
- });
+ options.headers = Object.assign(
+ {
+ 'Content-Type': 'application/json',
+ },
+ options.headers,
+ {
+ 'X-Forwarded-Host': 'strapi',
+ },
+ );
}
const token = auth.getToken();
- if (token) {
- options.headers = Object.assign({
- 'Authorization': `Bearer ${token}`,
- }, options.headers);
+ if (token && !noAuth) {
+ options.headers = Object.assign(
+ {
+ Authorization: `Bearer ${token}`,
+ },
+ options.headers,
+ );
}
// Add parameters to url
@@ -142,7 +159,7 @@ export default function request(url, options = {}, shouldWatchServerRestart = fa
return fetch(url, options)
.then(checkStatus)
.then(parseJSON)
- .then((response) => {
+ .then(response => {
if (shouldWatchServerRestart) {
// Display the global OverlayBlocker
strapi.lockApp(shouldWatchServerRestart);
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/AttributeRow/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/AttributeRow/index.js
index ac8030a6fd..2c9e3fe057 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/components/AttributeRow/index.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/components/AttributeRow/index.js
@@ -56,6 +56,7 @@ class AttributeRow extends React.Component {
handleEdit = () => this.props.onEditAttribute(this.props.row.name);
handleDelete = () => {
+ this.context.emitEvent('willDeleteFieldOfContentType');
this.props.onDelete(this.props.row.name);
this.setState({ showWarning: false });
};
@@ -136,6 +137,10 @@ class AttributeRow extends React.Component {
}
}
+AttributeRow.contextTypes = {
+ emitEvent: PropTypes.func,
+};
+
AttributeRow.propTypes = {
onDelete: PropTypes.func.isRequired,
onEditAttribute: PropTypes.func.isRequired,
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ContentHeader/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ContentHeader/index.js
index 06f882e914..ee7226f484 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/components/ContentHeader/index.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ContentHeader/index.js
@@ -17,6 +17,9 @@ import styles from './styles.scss';
/* eslint-disable jsx-a11y/click-events-have-key-events */
class ContentHeader extends React.Component { // eslint-disable-line react/prefer-stateless-function
handleEdit = () => {
+ // Send event.
+ this.context.emitEvent('willEditNameOfContentType');
+ // Open modal.
router.push(this.props.editPath);
}
@@ -41,6 +44,7 @@ class ContentHeader extends React.Component { // eslint-disable-line react/prefe
renderContentHeader = () => {
const description = isEmpty(this.props.description) ? '' :
;
const buttons = this.props.addButtons ? this.renderButtonContainer() : '';
+
return (
@@ -74,6 +78,10 @@ class ContentHeader extends React.Component { // eslint-disable-line react/prefe
}
}
+ContentHeader.contextTypes = {
+ emitEvent: PropTypes.func
+};
+
ContentHeader.propTypes = {
addButtons: PropTypes.bool,
buttonsContent: PropTypes.array,
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/PopUpHeaderNavLink/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/PopUpHeaderNavLink/index.js
index c90fd23db0..b421bbfd65 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/components/PopUpHeaderNavLink/index.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/components/PopUpHeaderNavLink/index.js
@@ -15,6 +15,12 @@ import styles from './styles.scss';
class PopUpHeaderNavLink extends React.Component { // eslint-disable-line react/prefer-stateless-function
handleGoTo = () => {
+ if (this.props.routePath.indexOf('#create::contentType') !== -1 && this.props.name === 'advancedSettings') {
+ this.context.emitEvent('didSelectContentTypeSettings');
+ } else if (this.props.routePath.indexOf('#create') !== -1 && this.props.routePath.indexOf('::attribute') !== -1 && this.props.name === 'advancedSettings') {
+ this.context.emitEvent('didSelectContentTypeFieldSettings');
+ }
+
router.push(replace(this.props.routePath, this.props.nameToReplace, this.props.name));
}
@@ -29,6 +35,10 @@ class PopUpHeaderNavLink extends React.Component { // eslint-disable-line react/
}
}
+PopUpHeaderNavLink.contextTypes = {
+ emitEvent: PropTypes.func
+};
+
PopUpHeaderNavLink.propTypes = {
message: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/index.js
index 4d61e66ddd..d39ecda29d 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/index.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/index.js
@@ -373,6 +373,7 @@ export class Form extends React.Component { // eslint-disable-line react/prefer-
}
goToAttributeTypeView = (attributeType) => {
+ this.context.emitEvent('didSelectContentTypeFieldType', { type: attributeType });
const settings = attributeType === 'relation' ? 'defineRelation' : 'baseSettings';
router.push(`${this.props.routePath}#create${this.props.modelName}::attribute${attributeType}::${settings}`);
}
@@ -461,6 +462,12 @@ export class Form extends React.Component { // eslint-disable-line react/prefer-
let dataSucces = null;
let cbFail;
+ if (redirectToChoose) {
+ this.context.emitEvent('willAddMoreFieldToContentType');
+ } else if (this.props.hash.indexOf('#edit') !== -1 && this.props.hash.indexOf('::attribute') !== -1) {
+ this.context.emitEvent('willEditFieldOfContentType');
+ }
+
switch (true) {
case includes(hashArray[0], '#edit'): {
// Check if the user is editing the attribute
@@ -682,6 +689,7 @@ export class Form extends React.Component { // eslint-disable-line react/prefer-
}
Form.contextTypes = {
+ emitEvent: PropTypes.func,
plugins: PropTypes.object,
updatePlugin: PropTypes.func,
};
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/sagas.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/sagas.js
index 4870e3655e..d07a1af61c 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/sagas.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/sagas.js
@@ -39,6 +39,8 @@ export function* editContentType(action) {
const response = yield call(request, requestUrl, opts, true);
if (response.ok) {
+ action.context.emitEvent('didEditNameOfContentType');
+
yield put(contentTypeActionSucceeded());
yield put(unsetButtonLoading());
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/HomePage/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/HomePage/index.js
index 021524f6b3..9594014bc7 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/containers/HomePage/index.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/HomePage/index.js
@@ -46,6 +46,9 @@ export class HomePage extends React.Component { // eslint-disable-line react/pre
if (storeData.getIsModelTemporary()) {
strapi.notification.info('content-type-builder.notification.info.contentType.creating.notSaved');
} else {
+ // Send event.
+ this.context.emitEvent('willCreateContentType');
+ // Open CT modal.
this.toggleModal();
}
}
@@ -108,6 +111,7 @@ export class HomePage extends React.Component { // eslint-disable-line react/pre
}
HomePage.contextTypes = {
+ emitEvent: PropTypes.func,
plugins: PropTypes.object,
updatePlugin: PropTypes.func,
};
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/index.js
index f2beeff899..1d4e989bb6 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/index.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/index.js
@@ -315,6 +315,7 @@ export class ModelPage extends React.Component { // eslint-disable-line react/pr
}
ModelPage.contextTypes = {
+ emitEvent: PropTypes.func,
plugins: PropTypes.object,
updatePlugin: PropTypes.func,
};
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/sagas.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/sagas.js
index 3f2021a130..9c4b9a2bb6 100644
--- a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/sagas.js
+++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/sagas.js
@@ -107,15 +107,22 @@ export function* submitChanges(action) {
set(body, 'plugin', pluginModel);
}
+ const { emitEvent } = action.context;
const method = modelName === body.name ? 'POST' : 'PUT';
const baseUrl = '/content-type-builder/models/';
const requestUrl = method === 'POST' ? baseUrl : `${baseUrl}${body.name}`;
const opts = { method, body };
+
+ // Send event.
+ yield put(emitEvent('willSaveContentType'));
+
+ // Send request to save the content type.
const response = yield call(request, requestUrl, opts, true);
if (response.ok) {
if (method === 'POST') {
storeData.clearAppStorage();
+ yield put(emitEvent('didSaveContentType'));
yield put(temporaryContentTypePosted(size(get(body, 'attributes'))));
yield put(postContentTypeSucceeded());
diff --git a/packages/strapi-plugin-content-type-builder/controllers/ContentTypeBuilder.js b/packages/strapi-plugin-content-type-builder/controllers/ContentTypeBuilder.js
index 6b1f4f41e2..fcab7c36eb 100644
--- a/packages/strapi-plugin-content-type-builder/controllers/ContentTypeBuilder.js
+++ b/packages/strapi-plugin-content-type-builder/controllers/ContentTypeBuilder.js
@@ -80,6 +80,8 @@ module.exports = {
if (_.isEmpty(strapi.api)) {
strapi.emit('didCreateFirstContentType');
+ } else {
+ strapi.emit('didCreateContentType');
}
ctx.send({ ok: true });