mirror of
https://github.com/strapi/strapi.git
synced 2025-10-13 09:03:25 +00:00
Add GraphQL plugin and inject middleware
This commit is contained in:
parent
15dda2f2cb
commit
4541b6f30b
File diff suppressed because one or more lines are too long
7
packages/strapi-plugin-graphql/.editorconfig
Executable file
7
packages/strapi-plugin-graphql/.editorconfig
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = false
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
103
packages/strapi-plugin-graphql/.gitattributes
vendored
Executable file
103
packages/strapi-plugin-graphql/.gitattributes
vendored
Executable file
@ -0,0 +1,103 @@
|
|||||||
|
# From https://github.com/Danimoth/gitattributes/blob/master/Web.gitattributes
|
||||||
|
|
||||||
|
# Handle line endings automatically for files detected as text
|
||||||
|
# and leave all files detected as binary untouched.
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
#
|
||||||
|
# The above will handle all files NOT found below
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
## These files are text and should be normalized (Convert crlf => lf)
|
||||||
|
#
|
||||||
|
|
||||||
|
# source code
|
||||||
|
*.php text
|
||||||
|
*.css text
|
||||||
|
*.sass text
|
||||||
|
*.scss text
|
||||||
|
*.less text
|
||||||
|
*.styl text
|
||||||
|
*.js text eol=lf
|
||||||
|
*.coffee text
|
||||||
|
*.json text
|
||||||
|
*.htm text
|
||||||
|
*.html text
|
||||||
|
*.xml text
|
||||||
|
*.svg text
|
||||||
|
*.txt text
|
||||||
|
*.ini text
|
||||||
|
*.inc text
|
||||||
|
*.pl text
|
||||||
|
*.rb text
|
||||||
|
*.py text
|
||||||
|
*.scm text
|
||||||
|
*.sql text
|
||||||
|
*.sh text
|
||||||
|
*.bat text
|
||||||
|
|
||||||
|
# templates
|
||||||
|
*.ejs text
|
||||||
|
*.hbt text
|
||||||
|
*.jade text
|
||||||
|
*.haml text
|
||||||
|
*.hbs text
|
||||||
|
*.dot text
|
||||||
|
*.tmpl text
|
||||||
|
*.phtml text
|
||||||
|
|
||||||
|
# git config
|
||||||
|
.gitattributes text
|
||||||
|
.gitignore text
|
||||||
|
.gitconfig text
|
||||||
|
|
||||||
|
# code analysis config
|
||||||
|
.jshintrc text
|
||||||
|
.jscsrc text
|
||||||
|
.jshintignore text
|
||||||
|
.csslintrc text
|
||||||
|
|
||||||
|
# misc config
|
||||||
|
*.yaml text
|
||||||
|
*.yml text
|
||||||
|
.editorconfig text
|
||||||
|
|
||||||
|
# build config
|
||||||
|
*.npmignore text
|
||||||
|
*.bowerrc text
|
||||||
|
|
||||||
|
# Heroku
|
||||||
|
Procfile text
|
||||||
|
.slugignore text
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
*.md text
|
||||||
|
LICENSE text
|
||||||
|
AUTHORS text
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
## These files are binary and should be left untouched
|
||||||
|
#
|
||||||
|
|
||||||
|
# (binary is a macro for -text -diff)
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.gif binary
|
||||||
|
*.ico binary
|
||||||
|
*.mov binary
|
||||||
|
*.mp4 binary
|
||||||
|
*.mp3 binary
|
||||||
|
*.flv binary
|
||||||
|
*.fla binary
|
||||||
|
*.swf binary
|
||||||
|
*.gz binary
|
||||||
|
*.zip binary
|
||||||
|
*.7z binary
|
||||||
|
*.ttf binary
|
||||||
|
*.eot binary
|
||||||
|
*.woff binary
|
||||||
|
*.pyc binary
|
||||||
|
*.pdf binary
|
10
packages/strapi-plugin-graphql/.gitignore
vendored
Normal file
10
packages/strapi-plugin-graphql/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Don't check auto-generated stuff into git
|
||||||
|
coverage
|
||||||
|
node_modules
|
||||||
|
stats.json
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
# Cruft
|
||||||
|
.DS_Store
|
||||||
|
npm-debug.log
|
||||||
|
.idea
|
101
packages/strapi-plugin-graphql/.npmignore
Normal file
101
packages/strapi-plugin-graphql/.npmignore
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
############################
|
||||||
|
# OS X
|
||||||
|
############################
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
Icon
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
._*
|
||||||
|
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Linux
|
||||||
|
############################
|
||||||
|
|
||||||
|
*~
|
||||||
|
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Windows
|
||||||
|
############################
|
||||||
|
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
Desktop.ini
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Packages
|
||||||
|
############################
|
||||||
|
|
||||||
|
*.7z
|
||||||
|
*.csv
|
||||||
|
*.dat
|
||||||
|
*.dmg
|
||||||
|
*.gz
|
||||||
|
*.iso
|
||||||
|
*.jar
|
||||||
|
*.rar
|
||||||
|
*.tar
|
||||||
|
*.zip
|
||||||
|
*.com
|
||||||
|
*.class
|
||||||
|
*.dll
|
||||||
|
*.exe
|
||||||
|
*.o
|
||||||
|
*.seed
|
||||||
|
*.so
|
||||||
|
*.swo
|
||||||
|
*.swp
|
||||||
|
*.swn
|
||||||
|
*.swm
|
||||||
|
*.out
|
||||||
|
*.pid
|
||||||
|
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Logs and databases
|
||||||
|
############################
|
||||||
|
|
||||||
|
*.log
|
||||||
|
*.sql
|
||||||
|
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Misc.
|
||||||
|
############################
|
||||||
|
|
||||||
|
*#
|
||||||
|
ssl
|
||||||
|
.idea
|
||||||
|
nbproject
|
||||||
|
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Node.js
|
||||||
|
############################
|
||||||
|
|
||||||
|
lib-cov
|
||||||
|
lcov.info
|
||||||
|
pids
|
||||||
|
logs
|
||||||
|
results
|
||||||
|
node_modules
|
||||||
|
.node_history
|
||||||
|
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Tests
|
||||||
|
############################
|
||||||
|
|
||||||
|
test
|
||||||
|
testApp
|
||||||
|
coverage
|
1
packages/strapi-plugin-graphql/README.md
Executable file
1
packages/strapi-plugin-graphql/README.md
Executable file
@ -0,0 +1 @@
|
|||||||
|
# Strapi plugin
|
101
packages/strapi-plugin-graphql/admin/.npmignore
Normal file
101
packages/strapi-plugin-graphql/admin/.npmignore
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
############################
|
||||||
|
# OS X
|
||||||
|
############################
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
Icon
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
._*
|
||||||
|
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Linux
|
||||||
|
############################
|
||||||
|
|
||||||
|
*~
|
||||||
|
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Windows
|
||||||
|
############################
|
||||||
|
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
Desktop.ini
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Packages
|
||||||
|
############################
|
||||||
|
|
||||||
|
*.7z
|
||||||
|
*.csv
|
||||||
|
*.dat
|
||||||
|
*.dmg
|
||||||
|
*.gz
|
||||||
|
*.iso
|
||||||
|
*.jar
|
||||||
|
*.rar
|
||||||
|
*.tar
|
||||||
|
*.zip
|
||||||
|
*.com
|
||||||
|
*.class
|
||||||
|
*.dll
|
||||||
|
*.exe
|
||||||
|
*.o
|
||||||
|
*.seed
|
||||||
|
*.so
|
||||||
|
*.swo
|
||||||
|
*.swp
|
||||||
|
*.swn
|
||||||
|
*.swm
|
||||||
|
*.out
|
||||||
|
*.pid
|
||||||
|
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Logs and databases
|
||||||
|
############################
|
||||||
|
|
||||||
|
*.log
|
||||||
|
*.sql
|
||||||
|
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Misc.
|
||||||
|
############################
|
||||||
|
|
||||||
|
*#
|
||||||
|
ssl
|
||||||
|
.idea
|
||||||
|
nbproject
|
||||||
|
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Node.js
|
||||||
|
############################
|
||||||
|
|
||||||
|
lib-cov
|
||||||
|
lcov.info
|
||||||
|
pids
|
||||||
|
logs
|
||||||
|
results
|
||||||
|
node_modules
|
||||||
|
.node_history
|
||||||
|
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Tests
|
||||||
|
############################
|
||||||
|
|
||||||
|
test
|
||||||
|
testApp
|
||||||
|
coverage
|
5
packages/strapi-plugin-graphql/admin/src/containers/App/actions.js
Executable file
5
packages/strapi-plugin-graphql/admin/src/containers/App/actions.js
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* App actions
|
||||||
|
*
|
||||||
|
*/
|
5
packages/strapi-plugin-graphql/admin/src/containers/App/constants.js
Executable file
5
packages/strapi-plugin-graphql/admin/src/containers/App/constants.js
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* App constants
|
||||||
|
*
|
||||||
|
*/
|
69
packages/strapi-plugin-graphql/admin/src/containers/App/index.js
Executable file
69
packages/strapi-plugin-graphql/admin/src/containers/App/index.js
Executable file
@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* This component is the skeleton around the actual pages, and should only
|
||||||
|
* contain code that should be seen on all pages. (e.g. navigation bar)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
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';
|
||||||
|
|
||||||
|
// Containers
|
||||||
|
import HomePage from 'containers/HomePage';
|
||||||
|
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';
|
||||||
|
|
||||||
|
|
||||||
|
class App extends React.Component {
|
||||||
|
// When you're done studying the ExamplePage container, remove the following lines and delete the ExamplePage container
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.history.push(`/plugins/${pluginId}/example`);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className={pluginId}>
|
||||||
|
<Switch>
|
||||||
|
<Route path={`/plugins/${pluginId}`} component={HomePage} exact />
|
||||||
|
{/* When you're done studying the ExamplePage container, remove the following line and delete the ExamplePage container */}
|
||||||
|
<Route path={`/plugins/${pluginId}/example`} component={ExamplePage} exact />
|
||||||
|
<Route component={NotFoundPage} />
|
||||||
|
</Switch>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
App.contextTypes = {
|
||||||
|
plugins: PropTypes.object,
|
||||||
|
router: PropTypes.object.isRequired,
|
||||||
|
updatePlugin: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
App.propTypes = {
|
||||||
|
history: 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);
|
18
packages/strapi-plugin-graphql/admin/src/containers/App/reducer.js
Executable file
18
packages/strapi-plugin-graphql/admin/src/containers/App/reducer.js
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* App reducer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { fromJS } from 'immutable';
|
||||||
|
|
||||||
|
const initialState = fromJS({});
|
||||||
|
|
||||||
|
function appReducer(state = initialState, action) {
|
||||||
|
switch (action.type) {
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default appReducer;
|
9
packages/strapi-plugin-graphql/admin/src/containers/App/selectors.js
Executable file
9
packages/strapi-plugin-graphql/admin/src/containers/App/selectors.js
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
// import { createSelector } from 'reselect';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct selector to the list state domain
|
||||||
|
*/
|
||||||
|
|
||||||
|
// const selectGlobalDomain = () => state => state.get('global');
|
||||||
|
|
||||||
|
export {};
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* ExamplePage actions
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { LOAD_DATA, LOADED_DATA } from './constants';
|
||||||
|
|
||||||
|
export function loadData() {
|
||||||
|
return {
|
||||||
|
type: LOAD_DATA,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loadedData(data) {
|
||||||
|
return {
|
||||||
|
type: LOADED_DATA,
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* ExamplePage constants
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const LOAD_DATA = 'ExamplePage/LOAD_DATA';
|
||||||
|
export const LOADED_DATA = 'ExamplePage/LOADED_DATA';
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* ExamplePage
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
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 Button from 'components/Button';
|
||||||
|
|
||||||
|
import styles from './styles.scss';
|
||||||
|
import { loadData } from './actions';
|
||||||
|
import { makeSelectLoading, makeSelectData } from './selectors';
|
||||||
|
import reducer from './reducer';
|
||||||
|
import saga from './saga';
|
||||||
|
|
||||||
|
export class ExamplePage extends React.Component {
|
||||||
|
generateDataBlock() {
|
||||||
|
if (this.props.data) {
|
||||||
|
const items = this.props.data.map((item, i) => <li key={i}>{item}</li>);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Data:</p>
|
||||||
|
<ul>{items}</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
console.log('Don\'t forget to delete the ExampleContainer when you\'re done studying it');
|
||||||
|
// Generate the data block
|
||||||
|
const dataBlock = this.generateDataBlock();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.examplePage}>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-12">
|
||||||
|
<p>This is an example of a fake API call.</p>
|
||||||
|
<p>Loading: {this.props.loading ? 'yes' : 'no'}.</p>
|
||||||
|
{dataBlock}
|
||||||
|
<Button
|
||||||
|
label={this.props.loading ? 'Loading...' : 'Submit'}
|
||||||
|
disabled={this.props.loading}
|
||||||
|
onClick={this.props.loadData}
|
||||||
|
primary
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExamplePage.contextTypes = {
|
||||||
|
router: PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
|
ExamplePage.propTypes = {
|
||||||
|
data: PropTypes.oneOfType([
|
||||||
|
PropTypes.bool,
|
||||||
|
PropTypes.object,
|
||||||
|
]).isRequired,
|
||||||
|
loadData: PropTypes.func.isRequired,
|
||||||
|
loading: PropTypes.bool.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
function mapDispatchToProps(dispatch) {
|
||||||
|
return bindActionCreators(
|
||||||
|
{
|
||||||
|
loadData,
|
||||||
|
},
|
||||||
|
dispatch,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
loading: makeSelectLoading(),
|
||||||
|
data: makeSelectData(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const withConnect = connect(mapStateToProps, mapDispatchToProps);
|
||||||
|
|
||||||
|
const withReducer = injectReducer({ key: 'examplePage', reducer });
|
||||||
|
const withSaga = injectSaga({ key: 'examplePage', saga });
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withReducer,
|
||||||
|
withSaga,
|
||||||
|
withConnect,
|
||||||
|
)(injectIntl(ExamplePage));
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* ExamplePage reducer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { fromJS } from 'immutable';
|
||||||
|
|
||||||
|
import { LOAD_DATA, LOADED_DATA } from './constants';
|
||||||
|
|
||||||
|
const initialState = fromJS({
|
||||||
|
loading: false,
|
||||||
|
data: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
function examplePageReducer(state = initialState, action) {
|
||||||
|
switch (action.type) {
|
||||||
|
case LOAD_DATA:
|
||||||
|
return state.set('loading', true);
|
||||||
|
case LOADED_DATA:
|
||||||
|
return state.set('loading', false).set('data', fromJS(action.data));
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default examplePageReducer;
|
@ -0,0 +1,31 @@
|
|||||||
|
import { LOCATION_CHANGE } from 'react-router-redux';
|
||||||
|
import { takeLatest, put, fork, take, cancel } from 'redux-saga/effects';
|
||||||
|
|
||||||
|
import { loadedData } from './actions';
|
||||||
|
import { LOAD_DATA } from './constants';
|
||||||
|
|
||||||
|
export function* loadData() {
|
||||||
|
// Fake API request delay
|
||||||
|
yield new Promise(resolve => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve();
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Generate a random array
|
||||||
|
const data = Array(4).fill(0).map(() => Math.floor(Math.random() * 100));
|
||||||
|
|
||||||
|
yield put(loadedData(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Individual exports for testing
|
||||||
|
export function* defaultSaga() {
|
||||||
|
const loadDataWatcher = yield fork(takeLatest, LOAD_DATA, loadData);
|
||||||
|
|
||||||
|
// Suspend execution until location changes
|
||||||
|
yield take(LOCATION_CHANGE);
|
||||||
|
yield cancel(loadDataWatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
// All sagas to be loaded
|
||||||
|
export default defaultSaga;
|
@ -0,0 +1,18 @@
|
|||||||
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct selector to the examplePage state domain
|
||||||
|
*/
|
||||||
|
const selectExamplePageDomain = () => state => state.get('examplePage');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default selector used by HomePage
|
||||||
|
*/
|
||||||
|
|
||||||
|
const makeSelectLoading = () =>
|
||||||
|
createSelector(selectExamplePageDomain(), substate => substate.get('loading'));
|
||||||
|
|
||||||
|
const makeSelectData = () =>
|
||||||
|
createSelector(selectExamplePageDomain(), substate => substate.get('data'));
|
||||||
|
|
||||||
|
export { makeSelectLoading, makeSelectData };
|
@ -0,0 +1,3 @@
|
|||||||
|
.examplePage {
|
||||||
|
|
||||||
|
}
|
13
packages/strapi-plugin-graphql/admin/src/containers/HomePage/actions.js
Executable file
13
packages/strapi-plugin-graphql/admin/src/containers/HomePage/actions.js
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* HomePage actions
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { DEFAULT_ACTION } from './constants';
|
||||||
|
|
||||||
|
export function defaultAction() {
|
||||||
|
return {
|
||||||
|
type: DEFAULT_ACTION,
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* HomePage constants
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const DEFAULT_ACTION = 'HomePage/DEFAULT_ACTION';
|
65
packages/strapi-plugin-graphql/admin/src/containers/HomePage/index.js
Executable file
65
packages/strapi-plugin-graphql/admin/src/containers/HomePage/index.js
Executable file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* HomePage
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
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';
|
||||||
|
|
||||||
|
// Selectors
|
||||||
|
import selectHomePage from './selectors';
|
||||||
|
|
||||||
|
// Styles
|
||||||
|
import styles from './styles.scss';
|
||||||
|
|
||||||
|
import reducer from './reducer';
|
||||||
|
import saga from './saga';
|
||||||
|
|
||||||
|
export class HomePage extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className={styles.homePage}>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HomePage.contextTypes = {
|
||||||
|
router: PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
|
HomePage.propTypes = {
|
||||||
|
// homePage: PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
|
function mapDispatchToProps(dispatch) {
|
||||||
|
return bindActionCreators(
|
||||||
|
{
|
||||||
|
// Your actions here
|
||||||
|
},
|
||||||
|
dispatch,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
homePage: selectHomePage(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const withConnect = connect(mapStateToProps, mapDispatchToProps);
|
||||||
|
|
||||||
|
const withReducer = injectReducer({ key: 'homePage', reducer });
|
||||||
|
const withSaga = injectSaga({ key: 'homePage', saga });
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withReducer,
|
||||||
|
withSaga,
|
||||||
|
withConnect,
|
||||||
|
)(injectIntl(HomePage));
|
22
packages/strapi-plugin-graphql/admin/src/containers/HomePage/reducer.js
Executable file
22
packages/strapi-plugin-graphql/admin/src/containers/HomePage/reducer.js
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* HomePage reducer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { fromJS } from 'immutable';
|
||||||
|
|
||||||
|
import { DEFAULT_ACTION } from './constants';
|
||||||
|
|
||||||
|
const initialState = fromJS({});
|
||||||
|
|
||||||
|
function homePageReducer(state = initialState, action) {
|
||||||
|
switch (action.type) {
|
||||||
|
case DEFAULT_ACTION:
|
||||||
|
return state;
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default homePageReducer;
|
9
packages/strapi-plugin-graphql/admin/src/containers/HomePage/saga.js
Executable file
9
packages/strapi-plugin-graphql/admin/src/containers/HomePage/saga.js
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
// import { LOCATION_CHANGE } from 'react-router-redux';
|
||||||
|
// import { takeLatest, put, fork, take, cancel } from 'redux-saga/effects';
|
||||||
|
|
||||||
|
// Individual exports for testing
|
||||||
|
export function* defaultSaga() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// All sagas to be loaded
|
||||||
|
export default defaultSaga;
|
17
packages/strapi-plugin-graphql/admin/src/containers/HomePage/selectors.js
Executable file
17
packages/strapi-plugin-graphql/admin/src/containers/HomePage/selectors.js
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct selector to the homePage state domain
|
||||||
|
*/
|
||||||
|
const selectHomePageDomain = () => state => state.get('homePage');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default selector used by HomePage
|
||||||
|
*/
|
||||||
|
|
||||||
|
const selectHomePage = () => createSelector(
|
||||||
|
selectHomePageDomain(),
|
||||||
|
(substate) => substate.toJS(),
|
||||||
|
);
|
||||||
|
|
||||||
|
export default selectHomePage;
|
3
packages/strapi-plugin-graphql/admin/src/containers/HomePage/styles.scss
Executable file
3
packages/strapi-plugin-graphql/admin/src/containers/HomePage/styles.scss
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
.homePage {
|
||||||
|
|
||||||
|
}
|
20
packages/strapi-plugin-graphql/admin/src/containers/NotFoundPage/index.js
Executable file
20
packages/strapi-plugin-graphql/admin/src/containers/NotFoundPage/index.js
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* NotFoundPage
|
||||||
|
*
|
||||||
|
* This is the page we show when the user visits a url that doesn't have a route
|
||||||
|
*
|
||||||
|
* NOTE: while this component should technically be a stateless functional
|
||||||
|
* component (SFC), hot reloading does not currently support SFCs. If hot
|
||||||
|
* reloading is not a neccessity for you then you can refactor it and remove
|
||||||
|
* the linting exception.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import NotFound from 'components/NotFound';
|
||||||
|
|
||||||
|
export default class NotFoundPage extends React.Component {
|
||||||
|
render() {
|
||||||
|
return <NotFound {...this.props} />;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
{}
|
1
packages/strapi-plugin-graphql/admin/src/translations/en.json
Executable file
1
packages/strapi-plugin-graphql/admin/src/translations/en.json
Executable file
@ -0,0 +1 @@
|
|||||||
|
{}
|
1
packages/strapi-plugin-graphql/admin/src/translations/fr.json
Executable file
1
packages/strapi-plugin-graphql/admin/src/translations/fr.json
Executable file
@ -0,0 +1 @@
|
|||||||
|
{}
|
@ -0,0 +1 @@
|
|||||||
|
{}
|
@ -0,0 +1 @@
|
|||||||
|
{}
|
@ -0,0 +1 @@
|
|||||||
|
{}
|
3
packages/strapi-plugin-graphql/config/routes.json
Normal file
3
packages/strapi-plugin-graphql/config/routes.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"routes": []
|
||||||
|
}
|
10
packages/strapi-plugin-graphql/controllers/GraphQL.js
Normal file
10
packages/strapi-plugin-graphql/controllers/GraphQL.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GraphQL.js controller
|
||||||
|
*
|
||||||
|
* @description: A set of functions called "actions" of the `GraphQL` plugin.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {};
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"graphql": {
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
}
|
66
packages/strapi-plugin-graphql/middlewares/graphql/index.js
Normal file
66
packages/strapi-plugin-graphql/middlewares/graphql/index.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Public node modules.
|
||||||
|
const { graphqlKoa, graphiqlKoa } = require('apollo-server-koa');
|
||||||
|
const { makeExecutableSchema } = require('graphql-tools');
|
||||||
|
|
||||||
|
const books = [
|
||||||
|
{
|
||||||
|
title: "Harry Potter and the Sorcerer's stone",
|
||||||
|
author: 'J.K. Rowling',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Jurassic Park',
|
||||||
|
author: 'Michael Crichton',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// The GraphQL schema in string form
|
||||||
|
const typeDefs = `
|
||||||
|
type Query { books: [Book] }
|
||||||
|
type Book { title: String, author: String }
|
||||||
|
`;
|
||||||
|
|
||||||
|
// The resolvers
|
||||||
|
const resolvers = {
|
||||||
|
Query: { books: () => books },
|
||||||
|
};
|
||||||
|
|
||||||
|
// Put together a schema
|
||||||
|
const schema = makeExecutableSchema({
|
||||||
|
typeDefs,
|
||||||
|
resolvers,
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = strapi => {
|
||||||
|
return {
|
||||||
|
beforeInitialize: function() {
|
||||||
|
// Try to inject this middleware just after the parser to skip the router processing.
|
||||||
|
const index = strapi.config.middleware.load.after.indexOf('parser');
|
||||||
|
|
||||||
|
if (index !== -1) {
|
||||||
|
strapi.config.middleware.load.after.splice(index + 1, 0, 'graphql');
|
||||||
|
} else {
|
||||||
|
strapi.config.middleware.load.after.push('graphql');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function(cb) {
|
||||||
|
const endpoint = '/graphql';
|
||||||
|
const router = strapi.koaMiddlewares.routerJoi();
|
||||||
|
|
||||||
|
router.post(endpoint, graphqlKoa({ schema }));
|
||||||
|
router.get(endpoint, graphqlKoa({ schema }));
|
||||||
|
|
||||||
|
router.get('/graphiql', graphiqlKoa({ endpointURL: endpoint }));
|
||||||
|
|
||||||
|
strapi.app.use(router.middleware());
|
||||||
|
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
50
packages/strapi-plugin-graphql/package.json
Normal file
50
packages/strapi-plugin-graphql/package.json
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"name": "strapi-plugin-graphql",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "This is the description of the plugin.",
|
||||||
|
"strapi": {
|
||||||
|
"name": "graphql",
|
||||||
|
"icon": "plug",
|
||||||
|
"description": "Description of graphql plugin."
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"analyze:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf stats.json",
|
||||||
|
"preanalyze": "npm run analyze:clean",
|
||||||
|
"analyze": "node ./node_modules/strapi-helper-plugin/lib/internals/scripts/analyze.js",
|
||||||
|
"prebuild": "npm run build:clean && npm run test",
|
||||||
|
"build:dev": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node ./node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress",
|
||||||
|
"build": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production node node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress",
|
||||||
|
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
|
||||||
|
"start": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node ./node_modules/strapi-helper-plugin/lib/server",
|
||||||
|
"generate": "node ./node_modules/plop/plop.js --plopfile node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
|
||||||
|
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --ignore-pattern '/admin/build/' --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
|
||||||
|
"prettier": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
|
||||||
|
"test": "npm run lint",
|
||||||
|
"prepublishOnly": "npm run build"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"apollo-server-koa": "^1.3.3",
|
||||||
|
"graphql": "^0.13.2",
|
||||||
|
"graphql-tools": "^2.23.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"strapi-helper-plugin": "3.0.0-alpha.11.1"
|
||||||
|
},
|
||||||
|
"author": {
|
||||||
|
"name": "A Strapi developer",
|
||||||
|
"email": "",
|
||||||
|
"url": ""
|
||||||
|
},
|
||||||
|
"maintainers": [
|
||||||
|
{
|
||||||
|
"name": "A Strapi developer",
|
||||||
|
"email": "",
|
||||||
|
"url": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 7.0.0",
|
||||||
|
"npm": ">= 3.0.0"
|
||||||
|
},
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
9
packages/strapi-plugin-graphql/services/GraphQL.js
Normal file
9
packages/strapi-plugin-graphql/services/GraphQL.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GraphQL.js service
|
||||||
|
*
|
||||||
|
* @description: A set of functions similar to controller's actions to avoid code duplication.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = {};
|
@ -120,6 +120,10 @@ shell.rm('-f', 'package-lock.json');
|
|||||||
watcher('📦 Linking strapi-plugin-content-type-builder...', 'npm link --no-optional', false);
|
watcher('📦 Linking strapi-plugin-content-type-builder...', 'npm link --no-optional', false);
|
||||||
watcher('🏗 Building...', 'npm run build');
|
watcher('🏗 Building...', 'npm run build');
|
||||||
|
|
||||||
|
shell.cd('../strapi-plugin-graphql');
|
||||||
|
shell.rm('-f', 'package-lock.json');
|
||||||
|
watcher('📦 Linking strapi-plugin-graphql...', 'npm link --no-optional', false);
|
||||||
|
|
||||||
// Log installation duration.
|
// Log installation duration.
|
||||||
const installationEndDate = new Date();
|
const installationEndDate = new Date();
|
||||||
const duration = (installationEndDate.getTime() - installationStartDate.getTime()) / 1000;
|
const duration = (installationEndDate.getTime() - installationStartDate.getTime()) / 1000;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user