add online graphiql to community tools (#716)
4
community/tools/graphiql-online/.babelrc
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"presets": ["stage-0", "env", "react"],
|
||||
"plugins": ["transform-class-properties", "transform-react-remove-prop-types", "istanbul"]
|
||||
}
|
120
community/tools/graphiql-online/.bootstraprc
Normal file
@ -0,0 +1,120 @@
|
||||
---
|
||||
# Output debugging info
|
||||
# loglevel: debug
|
||||
|
||||
# Major version of Bootstrap: 3 or 4
|
||||
bootstrapVersion: 3
|
||||
|
||||
# If Bootstrap version 3 is used - turn on/off custom icon font path
|
||||
useCustomIconFontPath: false
|
||||
|
||||
# Webpack loaders, order matters
|
||||
styleLoaders:
|
||||
- style
|
||||
- css
|
||||
- sass
|
||||
|
||||
# Extract styles to stand-alone css file
|
||||
# Different settings for different environments can be used,
|
||||
# It depends on value of NODE_ENV environment variable
|
||||
# This param can also be set in webpack config:
|
||||
# entry: 'bootstrap-loader/extractStyles'
|
||||
#extractStyles: false
|
||||
env:
|
||||
development:
|
||||
extractStyles: false
|
||||
production:
|
||||
extractStyles: true
|
||||
|
||||
|
||||
# Customize Bootstrap variables that get imported before the original Bootstrap variables.
|
||||
# Thus, derived Bootstrap variables can depend on values from here.
|
||||
# See the Bootstrap _variables.scss file for examples of derived Bootstrap variables.
|
||||
#
|
||||
|
||||
preBootstrapCustomizations: ./src/theme/variables.scss
|
||||
|
||||
|
||||
# This gets loaded after bootstrap/variables is loaded
|
||||
# Thus, you may customize Bootstrap variables
|
||||
# based on the values established in the Bootstrap _variables.scss file
|
||||
#
|
||||
|
||||
bootstrapCustomizations: ./src/theme/bootstrap.overrides.scss
|
||||
|
||||
|
||||
# Import your custom styles here
|
||||
# Usually this endpoint-file contains list of @imports of your application styles
|
||||
#
|
||||
# appStyles: ./path/to/your/app/styles/endpoint.scss
|
||||
|
||||
|
||||
### Bootstrap styles
|
||||
styles:
|
||||
|
||||
# Mixins
|
||||
mixins: true
|
||||
|
||||
# Reset and dependencies
|
||||
normalize: true
|
||||
print: true
|
||||
glyphicons: true
|
||||
|
||||
# Core CSS
|
||||
scaffolding: true
|
||||
type: true
|
||||
code: true
|
||||
grid: true
|
||||
tables: true
|
||||
forms: true
|
||||
buttons: true
|
||||
|
||||
# Components
|
||||
component-animations: true
|
||||
dropdowns: true
|
||||
button-groups: true
|
||||
input-groups: true
|
||||
navs: true
|
||||
navbar: true
|
||||
breadcrumbs: true
|
||||
pagination: true
|
||||
pager: true
|
||||
labels: true
|
||||
badges: true
|
||||
jumbotron: true
|
||||
thumbnails: true
|
||||
alerts: true
|
||||
progress-bars: true
|
||||
media: true
|
||||
list-group: true
|
||||
panels: true
|
||||
wells: true
|
||||
responsive-embed: true
|
||||
close: true
|
||||
|
||||
# Components w/ JavaScript
|
||||
modals: true
|
||||
tooltip: true
|
||||
popovers: true
|
||||
carousel: true
|
||||
|
||||
# Utility classes
|
||||
utilities: true
|
||||
responsive-utilities: true
|
||||
|
||||
### Bootstrap scripts
|
||||
#scripts: false
|
||||
|
||||
scripts:
|
||||
transition: false
|
||||
alert: false
|
||||
button: true
|
||||
carousel: false
|
||||
collapse: false
|
||||
dropdown: true
|
||||
modal: true
|
||||
tooltip: false
|
||||
popover: false
|
||||
scrollspy: false
|
||||
tab: false
|
||||
affix: false
|
1
community/tools/graphiql-online/.dockerignore
Normal file
@ -0,0 +1 @@
|
||||
node_modules
|
2
community/tools/graphiql-online/.eslintignore
Normal file
@ -0,0 +1,2 @@
|
||||
webpack/*
|
||||
src/utils.js
|
101
community/tools/graphiql-online/.eslintrc
Normal file
@ -0,0 +1,101 @@
|
||||
{ "extends": "eslint-config-airbnb",
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"mocha": true,
|
||||
"cypress/globals": true
|
||||
},
|
||||
"parser": "babel-eslint",
|
||||
"rules": {
|
||||
"allowForLoopAfterthoughts": true,
|
||||
"react/no-multi-comp": 0,
|
||||
"import/default": 0,
|
||||
"import/no-duplicates": 0,
|
||||
"import/named": 0,
|
||||
"import/first": 0,
|
||||
"import/namespace": 0,
|
||||
"import/no-unresolved": 0,
|
||||
"import/no-named-as-default": 2,
|
||||
"import/extensions": 0,
|
||||
"import/no-extraneous-dependencies": 0,
|
||||
"import/prefer-default-export": 0,
|
||||
"comma-dangle": 0,
|
||||
"id-length": [1, {"min": 1, "properties": "never"}],
|
||||
"indent": [2, 2, {"SwitchCase": 1}],
|
||||
"no-console": 0,
|
||||
"arrow-parens": 0,
|
||||
"no-alert": 0,
|
||||
"no-plusplus": 0,
|
||||
"no-unsafe-negation": 0,
|
||||
"no-loop-func": 0,
|
||||
"no-lonely-if": 0,
|
||||
"no-bitwise": 0,
|
||||
"global-require": 0,
|
||||
"no-param-reassign": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-useless-return": 0,
|
||||
"no-restricted-syntax": 0,
|
||||
"no-prototype-builtins": 0,
|
||||
"array-callback-return": 0,
|
||||
"no-useless-concat": 0,
|
||||
"consistent-return": 0,
|
||||
"class-methods-use-this": 0,
|
||||
"arrow-body-style": 0,
|
||||
"prefer-template": 0,
|
||||
"prefer-spread": 0,
|
||||
"object-shorthand": 0,
|
||||
"object-curly-newline": 0,
|
||||
"spaced-comment": 0,
|
||||
"prefer-destructuring": ["error", {"object": false, "array": false}],
|
||||
"prefer-rest-params": 0,
|
||||
"function-paren-newline": 0,
|
||||
"no-case-declarations": 0,
|
||||
"no-restricted-globals": 0,
|
||||
"no-unneeded-ternary": 0,
|
||||
"no-mixed-operators": 0,
|
||||
"no-return-assign": 0,
|
||||
"operator-assignment": 0,
|
||||
"strict": 0,
|
||||
"react/jsx-no-duplicate-props": 0,
|
||||
"react/jsx-filename-extension": 0,
|
||||
"react/jsx-curly-brace-presence": 0,
|
||||
"react/forbid-prop-types": 0,
|
||||
"react/require-default-props": 0,
|
||||
"react/no-unused-prop-types": 0,
|
||||
"react/no-string-refs": 0,
|
||||
"react/no-unused-state": 0,
|
||||
"react/no-array-index-key": 0,
|
||||
"react/jsx-no-bind": 0,
|
||||
"react/prop-types": 0,
|
||||
"react/prefer-stateless-function": 0,
|
||||
"react/no-unescaped-entities": 0,
|
||||
"jsx-a11y/click-events-have-key-events": 0,
|
||||
"jsx-a11y/no-static-element-interactions": 0,
|
||||
"jsx-a11y/no-noninteractive-element-interactions": 0,
|
||||
"jsx-a11y/label-has-for": 0,
|
||||
"jsx-a11y/anchor-is-valid": 0,
|
||||
"jsx-a11y/lang": 0,
|
||||
"jsx-a11y/alt-text": 0,
|
||||
"max-len": 0
|
||||
},
|
||||
"plugins": [
|
||||
"react", "import", "cypress"
|
||||
],
|
||||
|
||||
"settings": {
|
||||
"import/parser": "babel-eslint",
|
||||
"parser": "babel-esling",
|
||||
"import/resolve": {
|
||||
"moduleDirectory": ["node_modules", "src"]
|
||||
}
|
||||
},
|
||||
"globals": {
|
||||
"__DEVELOPMENT__": true,
|
||||
"__CLIENT__": true,
|
||||
"__SERVER__": true,
|
||||
"__DISABLE_SSR__": true,
|
||||
"__DEVTOOLS__": true,
|
||||
"socket": true,
|
||||
"webpackIsomorphicTools": true
|
||||
}
|
||||
}
|
12
community/tools/graphiql-online/.gitignore
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
.env
|
||||
cypress/videos
|
||||
cypress/screenshots
|
||||
.nyc_output
|
||||
node_modules
|
||||
static/dist
|
||||
webpack-assets.json
|
||||
webpack-stats.json
|
||||
npm-debug.log
|
||||
*.swp
|
||||
coverage
|
||||
.idea/*
|
5
community/tools/graphiql-online/.npmignore
Normal file
@ -0,0 +1,5 @@
|
||||
*
|
||||
**/*
|
||||
!static/dist/main.js
|
||||
!static/dist/vendor.js
|
||||
!static/dist/main.css
|
22
community/tools/graphiql-online/Dockerfile
Normal file
@ -0,0 +1,22 @@
|
||||
FROM node:8.9-alpine
|
||||
|
||||
# Create app directory
|
||||
WORKDIR /app
|
||||
|
||||
# Install app dependencies
|
||||
RUN npm config set unsafe-perm true
|
||||
RUN npm -g install serve
|
||||
# A wildcard is used to ensure both package.json AND package-lock.json are copied
|
||||
COPY package*.json ./
|
||||
|
||||
RUN npm install
|
||||
|
||||
# Bundle app source
|
||||
COPY . /app
|
||||
#Build react/vue/angular bundle static files
|
||||
RUN npm run build
|
||||
|
||||
RUN rm -Rf node_modules
|
||||
EXPOSE 8080
|
||||
# serve dist folder on port 8080
|
||||
CMD ["serve", "-s", "static", "-p", "8080"]
|
33
community/tools/graphiql-online/README.md
Normal file
@ -0,0 +1,33 @@
|
||||
## GraphiQL Demo
|
||||
|
||||
This version of GraphiQL is a fork of the original version with a simple header management UI and a fix for subscription.
|
||||
|
||||
## Usage of Environment Variables
|
||||
|
||||
This app uses a few environment variables which are required for development. The production build uses values directly present in index.html serving this app.
|
||||
|
||||
We use [dotenv](https://github.com/motdotla/dotenv) for setting environment variables for development. Create a `.env` file in the root directory (wherever package.json is) and set the following values. Replace accordingly for testing.
|
||||
|
||||
```
|
||||
PORT=3000
|
||||
NODE_ENV=development
|
||||
GRAPHQL_ENDPOINT=http://localhost:8090/v1alpha1/graphql
|
||||
HEADER_STRING='{}'
|
||||
VARIABLE_STRING='{}'
|
||||
QUERY_STRING='query { test_table { id } }'
|
||||
```
|
||||
|
||||
**Note**
|
||||
The .env file should not be in version control.
|
||||
|
||||
## Deployment
|
||||
|
||||
```
|
||||
$ npm run build
|
||||
```
|
||||
|
||||
The static assets will be generated in `static` folder. There is an index.html file referencing the css and js assets inside `dist` folder.
|
||||
|
||||
For a quick Docker based deployment, use `docker build -t graphiql .` && `docker run -d -p 8080:8080 graphiql` for running the production build locally.
|
||||
|
||||
You can also use now.sh for a cloud deployment. Just simply run `now` to deploy this and get a live URL.
|
9
community/tools/graphiql-online/appconfig.js
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
hmrPort: parseInt(process.env.PORT, 10) + 1 || 3001,
|
||||
hmrHost: process.env.HOST || '127.0.0.1',
|
||||
appHost: '0.0.0.0',
|
||||
port: { development: process.env.PORT, production: 8080 },
|
||||
assetsPrefix: '/rstatic',
|
||||
webpackPrefix: '/rstatic/dist/',
|
||||
appPrefix: '/rapp',
|
||||
};
|
15
community/tools/graphiql-online/bin/server.babel.js
Executable file
@ -0,0 +1,15 @@
|
||||
// enable runtime transpilation to use ES6/7 in node
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
const babelrc = fs.readFileSync('.babelrc');
|
||||
let config;
|
||||
|
||||
try {
|
||||
config = JSON.parse(babelrc);
|
||||
} catch (err) {
|
||||
console.error('==> ERROR: Error parsing your .babelrc.');
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
require('babel-core/register')(config);
|
33
community/tools/graphiql-online/bin/server.js
Normal file
@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env node
|
||||
require('./server.babel'); // babel registration (runtime transpilation for node)
|
||||
const path = require('path');
|
||||
|
||||
const rootDir = path.resolve(__dirname, '..');
|
||||
/**
|
||||
* Define isomorphic constants.
|
||||
*/
|
||||
global.__CLIENT__ = false;
|
||||
global.__SERVER__ = true;
|
||||
global.__DISABLE_SSR__ = false; // <----- DISABLES SERVER SIDE RENDERING FOR ERROR DEBUGGING
|
||||
global.__DEVELOPMENT__ = process.env.NODE_ENV !== 'production';
|
||||
|
||||
if (__DEVELOPMENT__) {
|
||||
if (
|
||||
!require('piping')({
|
||||
//Fork the process and supervise the child for hot-reloading code
|
||||
hook: true,
|
||||
ignore: /(\/\.|~$|\.json|\.scss$)/i,
|
||||
})
|
||||
) {
|
||||
return; //The parent process ends, and child process continues from below
|
||||
}
|
||||
}
|
||||
|
||||
const WebpackIsomorphicTools = require('webpack-isomorphic-tools');
|
||||
global.webpackIsomorphicTools = new WebpackIsomorphicTools(
|
||||
require('../webpack/webpack-isomorphic-tools')
|
||||
).server(rootDir, () => {
|
||||
require('../src/server');
|
||||
});
|
||||
|
||||
require('../src/server');
|
4
community/tools/graphiql-online/now.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "graphqurl-graphiql",
|
||||
"alias": "hasura-graphiql.now.sh"
|
||||
}
|
142
community/tools/graphiql-online/package.json
Normal file
@ -0,0 +1,142 @@
|
||||
{
|
||||
"name": "graphqurl-graphiql",
|
||||
"description": "Explore GraphQL APIs with headers",
|
||||
"author": "Hasura (https://github.com/hasura/graphql-engine)",
|
||||
"license": "MIT",
|
||||
"version": "0.1.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/hasura/graphql-engine"
|
||||
},
|
||||
"keywords": [],
|
||||
"scripts": {
|
||||
"start": "concurrently --kill-others \"npm run start-prod\"",
|
||||
"start-prod": "better-npm-run start-prod",
|
||||
"build": "webpack --progress -p --colors --display-error-details --config webpack/prod.config.js",
|
||||
"build-unused": "webpack --verbose --colors --display-error-details --config webpack/prod.config.js --json | webpack-unused -s src",
|
||||
"lint": "eslint -c .eslintrc src api",
|
||||
"start-dev": "better-npm-run start-dev",
|
||||
"watch-client": "better-npm-run watch-client",
|
||||
"dev": "concurrently --kill-others \"npm run watch-client\" \"npm run start-dev\" ",
|
||||
"cypress": "cypress open",
|
||||
"test": "cypress run --spec 'cypress/integration/test_complete.js' --config baseUrl=$CYPRESS_BASE_URL",
|
||||
"deploy": "now --docker --public && now alias && now alias hasura-graphiql.now.sh graphiql-online.com"
|
||||
},
|
||||
"betterScripts": {
|
||||
"start-prod": {
|
||||
"command": "node ./bin/server.js",
|
||||
"env": {
|
||||
"NODE_PATH": "./src",
|
||||
"NODE_ENV": "production",
|
||||
"PORT": 8080
|
||||
}
|
||||
},
|
||||
"start-dev": {
|
||||
"command": "node -r dotenv/config ./bin/server.js"
|
||||
},
|
||||
"watch-client": {
|
||||
"command": "node -r dotenv/config webpack/webpack-dev-server.js"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"apollo-link": "^1.2.2",
|
||||
"apollo-link-ws": "^1.0.8",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"deep-equal": "^1.0.1",
|
||||
"graphiql": "^0.11.11",
|
||||
"graphql": "^0.13.2",
|
||||
"hasura-console-graphiql": "0.0.1",
|
||||
"history": "^3.0.0",
|
||||
"hoist-non-react-statics": "^1.0.3",
|
||||
"invariant": "^2.2.0",
|
||||
"isomorphic-fetch": "^2.2.1",
|
||||
"less": "^3.7.1",
|
||||
"lru-memoize": "^1.0.0",
|
||||
"map-props": "^1.0.0",
|
||||
"multireducer": "^1.0.2",
|
||||
"piping": "^0.3.0",
|
||||
"prettier": "^1.13.0",
|
||||
"pretty-error": "^1.2.0",
|
||||
"prop-types": "^15.6.0",
|
||||
"query-string": "^6.1.0",
|
||||
"react": "^16.4.0",
|
||||
"react-dom": "^16.4.0",
|
||||
"react-helmet": "^5.2.0",
|
||||
"react-hot-loader": "^4.2.0",
|
||||
"react-progress-bar-plus": "^1.3.1",
|
||||
"react-redux": "^5.0.6",
|
||||
"react-router": "^3.2.0",
|
||||
"react-router-redux": "^4.0.8",
|
||||
"redux": "^4.0.0",
|
||||
"redux-logger": "^3.0.6",
|
||||
"redux-thunk": "^2.2.0",
|
||||
"subscriptions-transport-ws": "^0.9.12",
|
||||
"valid-url": "^1.0.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-eslint": "^8.2.3",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-plugin-istanbul": "^4.1.6",
|
||||
"babel-plugin-react-transform": "~3.0.0",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.10",
|
||||
"babel-plugin-typecheck": "^2.0.0",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"babel-preset-stage-0": "^6.24.1",
|
||||
"babel-runtime": "~6.26.0",
|
||||
"better-npm-run": "^0.1.0",
|
||||
"bootstrap-loader": "^2.2.0",
|
||||
"bootstrap-sass": "^3.3.7",
|
||||
"clean-webpack-plugin": "^0.1.17",
|
||||
"concurrently": "^3.5.0",
|
||||
"css-loader": "^0.28.11",
|
||||
"dotenv": "^5.0.1",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-airbnb": "16.1.0",
|
||||
"eslint-loader": "^1.0.0",
|
||||
"eslint-plugin-chai-friendly": "^0.4.1",
|
||||
"eslint-plugin-cypress": "^2.0.1",
|
||||
"eslint-plugin-import": "^2.12.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.0.3",
|
||||
"eslint-plugin-react": "^7.9.1",
|
||||
"express": "^4.13.3",
|
||||
"express-session": "^1.12.1",
|
||||
"extract-text-webpack-plugin": "^3.0.2",
|
||||
"file-loader": "^1.1.11",
|
||||
"font-awesome": "^4.7.0",
|
||||
"font-awesome-webpack": "0.0.4",
|
||||
"husky": "^0.14.3",
|
||||
"ignore-loader": "^0.1.2",
|
||||
"jquery": "^3.3.1",
|
||||
"json-loader": "^0.5.4",
|
||||
"less-loader": "^4.1.0",
|
||||
"lint-staged": "^6.1.1",
|
||||
"mini-css-extract-plugin": "^0.4.0",
|
||||
"node-sass": "^4.9.2",
|
||||
"nyc": "^12.0.2",
|
||||
"optimize-css-assets-webpack-plugin": "^4.0.2",
|
||||
"react-a11y": "^0.2.6",
|
||||
"react-addons-test-utils": "^15.0.3",
|
||||
"react-transform-hmr": "1.0.4",
|
||||
"redux-devtools": "^3.4.1",
|
||||
"redux-devtools-dock-monitor": "^1.1.2",
|
||||
"redux-devtools-log-monitor": "^1.3.0",
|
||||
"resolve-url-loader": "^2.3.0",
|
||||
"sass-loader": "^7.0.1",
|
||||
"sinon": "^1.17.7",
|
||||
"style-loader": "^0.20.3",
|
||||
"timekeeper": "1.0.0",
|
||||
"uglifyjs-webpack-plugin": "^1.2.7",
|
||||
"unused-files-webpack-plugin": "^3.4.0",
|
||||
"url-loader": "^1.0.1",
|
||||
"webpack": "^4.14.0",
|
||||
"webpack-cli": "^3.0.8",
|
||||
"webpack-dev-middleware": "^3.1.3",
|
||||
"webpack-hot-middleware": "^2.22.2",
|
||||
"webpack-isomorphic-tools": "^3.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.9.1"
|
||||
}
|
||||
}
|
93
community/tools/graphiql-online/src/client.js
Executable file
@ -0,0 +1,93 @@
|
||||
/**
|
||||
* THIS IS THE ENTRY POINT FOR THE CLIENT, JUST LIKE server.js IS THE ENTRY POINT FOR THE SERVER.
|
||||
*/
|
||||
// import 'babel-polyfill';
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { createLogger } from 'redux-logger';
|
||||
import thunk from 'redux-thunk';
|
||||
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { Router, browserHistory } from 'react-router';
|
||||
import { routerMiddleware, syncHistoryWithStore } from 'react-router-redux';
|
||||
import { compose, createStore, applyMiddleware } from 'redux';
|
||||
import { useBasename } from 'history';
|
||||
|
||||
import getRoutes from './routes';
|
||||
|
||||
import reducer from './reducer';
|
||||
|
||||
// Create the store
|
||||
let _finalCreateStore;
|
||||
|
||||
if (__DEVELOPMENT__) {
|
||||
_finalCreateStore = compose(
|
||||
applyMiddleware(thunk, routerMiddleware(browserHistory), createLogger()),
|
||||
require('redux-devtools').persistState(
|
||||
window.location.href.match(/[?&]debug_session=([^&]+)\b/)
|
||||
)
|
||||
)(createStore);
|
||||
} else {
|
||||
_finalCreateStore = compose(
|
||||
applyMiddleware(thunk, routerMiddleware(browserHistory))
|
||||
)(createStore);
|
||||
}
|
||||
|
||||
const hashLinkScroll = () => {
|
||||
const { hash } = window.location;
|
||||
if (hash !== '') {
|
||||
// Push onto callback queue so it runs after the DOM is updated,
|
||||
// this is required when navigating from a different page so that
|
||||
// the element is rendered on the page before trying to getElementById.
|
||||
setTimeout(() => {
|
||||
const id = hash.replace('#', '');
|
||||
const element = document.getElementById(id);
|
||||
if (element) {
|
||||
element.scrollIntoView();
|
||||
}
|
||||
}, 0);
|
||||
} else {
|
||||
// This is a hack to solve the issue with scroll retention during page change.
|
||||
setTimeout(() => {
|
||||
const element = document.getElementsByTagName('body');
|
||||
if (element && element.length > 0) {
|
||||
element[0].scrollIntoView();
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
const store = _finalCreateStore(reducer);
|
||||
const history = syncHistoryWithStore(browserHistory, store);
|
||||
|
||||
/* ****************************************************************** */
|
||||
|
||||
// Enable hot reloading
|
||||
if (__DEVELOPMENT__ && module.hot) {
|
||||
module.hot.accept('./reducer', () => {
|
||||
store.replaceReducer(require('./reducer'));
|
||||
});
|
||||
}
|
||||
|
||||
// Main routes and rendering
|
||||
const main = (
|
||||
<Router
|
||||
history={useBasename(() => history)({ basename: '/' })}
|
||||
routes={getRoutes(store)}
|
||||
onUpdate={hashLinkScroll}
|
||||
/>
|
||||
);
|
||||
|
||||
const dest = document.getElementById('content');
|
||||
ReactDOM.render(
|
||||
<Provider store={store} key="provider">
|
||||
{main}
|
||||
</Provider>,
|
||||
dest
|
||||
);
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
window.React = React; // enable debugger
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Helmet from 'react-helmet';
|
||||
|
||||
class PageNotFound extends Component {
|
||||
render() {
|
||||
const styles = require('./Styles.scss');
|
||||
return (
|
||||
<div className={styles.viewcontainer}>
|
||||
<Helmet title="404 - Page Not Found" />
|
||||
<div className={'container ' + styles.centerContent}>
|
||||
<div className={'row ' + styles.message}>
|
||||
<div className="col-xs-8">
|
||||
<h1>404</h1>
|
||||
This page doesn't exist.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
PageNotFound.propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default connect()(PageNotFound);
|
@ -0,0 +1,42 @@
|
||||
.container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.viewcontainer {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
display: table;
|
||||
|
||||
.centerContent{
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
|
||||
.message {
|
||||
padding: 50px 20%;
|
||||
}
|
||||
.message h1 {
|
||||
font-size: 54px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.message p {
|
||||
margin-left: 15px;
|
||||
}
|
||||
.message p > a {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
background: #eee;
|
||||
h2 {
|
||||
margin: 0;
|
||||
padding: 26px;
|
||||
float: left;
|
||||
line-height: 26px;
|
||||
}
|
||||
.nav {
|
||||
padding: 20px;
|
||||
float: left;
|
||||
}
|
||||
}
|
@ -0,0 +1,240 @@
|
||||
import defaultState from './state';
|
||||
// import fetch from 'isomorphic-fetch';
|
||||
|
||||
import { SubscriptionClient } from 'subscriptions-transport-ws';
|
||||
import { WebSocketLink } from 'apollo-link-ws';
|
||||
import { parse } from 'graphql';
|
||||
import { execute } from 'apollo-link';
|
||||
import { push } from 'react-router-redux';
|
||||
|
||||
const REQUEST_HEADER_CHANGED = 'ApiExplorer/REQUEST_HEADER_CHANGED';
|
||||
const REQUEST_HEADER_ADDED = 'ApiExplorer/REQUEST_HEADER_ADDED';
|
||||
const REQUEST_HEADER_REMOVED = 'ApiExplorer/REQUEST_HEADER_REMOVED';
|
||||
|
||||
const FOCUS_ROLE_HEADER = 'ApiExplorer/FOCUS_ROLE_HEADER';
|
||||
const UNFOCUS_ROLE_HEADER = 'ApiExplorer/UNFOCUS_ROLE_HEADER';
|
||||
const GRAPHQL_ENDPOINT_CHANGED = 'ApiExplorer/GRAPHQL_ENDPOINT_CHANGED';
|
||||
|
||||
import { getHeadersAsJSON } from './utils';
|
||||
|
||||
const focusHeaderTextbox = () => ({ type: FOCUS_ROLE_HEADER });
|
||||
const unfocusTypingHeader = () => ({ type: UNFOCUS_ROLE_HEADER });
|
||||
|
||||
const updateGraphQLEndpoint = (endpoint) => {
|
||||
return (dispatch) => {
|
||||
dispatch({ type: GRAPHQL_ENDPOINT_CHANGED, data: endpoint });
|
||||
// set local storage
|
||||
window.localStorage.setItem('ONLINE_GRAPHIQL_ENDPOINT', endpoint);
|
||||
dispatch(push('/graphiql'));
|
||||
};
|
||||
};
|
||||
|
||||
const createWsClient = (url, headers) => {
|
||||
const gqlUrl = new URL(url);
|
||||
let websocketProtocol = 'ws';
|
||||
if (gqlUrl.protocol === 'https:') {
|
||||
websocketProtocol = 'wss';
|
||||
}
|
||||
const headersFinal = getHeadersAsJSON(headers);
|
||||
const graphqlUrl = `${websocketProtocol}://${url.split('//')[1]}`;
|
||||
const client = new SubscriptionClient(graphqlUrl, {
|
||||
connectionParams: {
|
||||
headers: {
|
||||
...headersFinal,
|
||||
},
|
||||
},
|
||||
reconnect: true,
|
||||
});
|
||||
return client;
|
||||
};
|
||||
|
||||
const graphqlSubscriber = (graphQLParams, url, headers) => {
|
||||
const link = new WebSocketLink(createWsClient(url, headers));
|
||||
try {
|
||||
const fetcher = operation => {
|
||||
operation.query = parse(operation.query);
|
||||
return execute(link, operation);
|
||||
};
|
||||
return fetcher(graphQLParams);
|
||||
} catch (e) {
|
||||
return e.json();
|
||||
}
|
||||
};
|
||||
|
||||
const isSubscription = graphQlParams => {
|
||||
const queryDoc = parse(graphQlParams.query);
|
||||
for (const definition of queryDoc.definitions) {
|
||||
if (definition.kind === 'OperationDefinition') {
|
||||
const operation = definition.operation;
|
||||
if (operation === 'subscription') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const graphQLFetcherFinal = (graphQLParams, url, headers) => {
|
||||
if (isSubscription(graphQLParams)) {
|
||||
return graphqlSubscriber(graphQLParams, url, headers);
|
||||
}
|
||||
return fetch(url, {
|
||||
method: 'POST',
|
||||
headers: getHeadersAsJSON(headers),
|
||||
body: JSON.stringify(graphQLParams),
|
||||
}).then(response => response.json());
|
||||
};
|
||||
|
||||
const changeRequestHeader = (index, key, newValue, isDisabled) => ({
|
||||
type: REQUEST_HEADER_CHANGED,
|
||||
data: {
|
||||
index: index,
|
||||
keyName: key,
|
||||
newValue: newValue,
|
||||
isDisabled: isDisabled,
|
||||
},
|
||||
});
|
||||
|
||||
const addRequestHeader = (key, value) => ({
|
||||
type: REQUEST_HEADER_ADDED,
|
||||
data: {
|
||||
key: key,
|
||||
value: value,
|
||||
},
|
||||
});
|
||||
|
||||
const removeRequestHeader = index => {
|
||||
return {
|
||||
type: REQUEST_HEADER_REMOVED,
|
||||
data: index,
|
||||
};
|
||||
};
|
||||
|
||||
// This method adds the new header and moves the empty header to the bottom of the list
|
||||
const getHeadersAfterAddingNewHeader = (headers, newHeader) => {
|
||||
const nonEmptyHeaders = headers.filter(header => {
|
||||
return !header.isNewHeader;
|
||||
});
|
||||
nonEmptyHeaders.push(newHeader);
|
||||
nonEmptyHeaders.push({
|
||||
key: '',
|
||||
value: '',
|
||||
isActive: false,
|
||||
isNewHeader: true,
|
||||
});
|
||||
return nonEmptyHeaders;
|
||||
};
|
||||
|
||||
// This method adds a new empty header if no empty header is present
|
||||
const getChangedHeaders = (headers, changedHeaderDetails) => {
|
||||
const newHeaders = Object.assign([], headers);
|
||||
if (newHeaders[changedHeaderDetails.index].isNewHeader) {
|
||||
newHeaders[changedHeaderDetails.index].isNewHeader = false;
|
||||
newHeaders[changedHeaderDetails.index].isActive = true;
|
||||
newHeaders[changedHeaderDetails.index].isDisabled = false;
|
||||
}
|
||||
if (changedHeaderDetails.keyName === 'isActive') {
|
||||
newHeaders[changedHeaderDetails.index].isActive = !newHeaders[
|
||||
changedHeaderDetails.index
|
||||
].isActive;
|
||||
} else {
|
||||
newHeaders[changedHeaderDetails.index][changedHeaderDetails.keyName] =
|
||||
changedHeaderDetails.newValue;
|
||||
}
|
||||
if (changedHeaderDetails.isDisabled === true) {
|
||||
newHeaders[changedHeaderDetails.index].isDisabled = true;
|
||||
} else {
|
||||
newHeaders[changedHeaderDetails.index].isDisabled = false;
|
||||
}
|
||||
const nonEmptyHeaders = newHeaders.filter(header => {
|
||||
return !header.isNewHeader;
|
||||
});
|
||||
nonEmptyHeaders.push({
|
||||
key: '',
|
||||
value: '',
|
||||
isActive: false,
|
||||
isNewHeader: true,
|
||||
isDisabled: false,
|
||||
});
|
||||
return nonEmptyHeaders;
|
||||
};
|
||||
|
||||
const apiExplorerReducer = (state = defaultState, action) => {
|
||||
switch (action.type) {
|
||||
case REQUEST_HEADER_CHANGED:
|
||||
return {
|
||||
...state,
|
||||
displayedApi: {
|
||||
...state.displayedApi,
|
||||
request: {
|
||||
...state.displayedApi.request,
|
||||
headers: getChangedHeaders(
|
||||
state.displayedApi.request.headers,
|
||||
action.data
|
||||
),
|
||||
},
|
||||
},
|
||||
};
|
||||
case REQUEST_HEADER_ADDED:
|
||||
return {
|
||||
...state,
|
||||
displayedApi: {
|
||||
...state.displayedApi,
|
||||
request: {
|
||||
...state.displayedApi.request,
|
||||
headers: getHeadersAfterAddingNewHeader(
|
||||
state.displayedApi.request.headers,
|
||||
{
|
||||
key: action.data.key,
|
||||
value: action.data.value,
|
||||
isActive: true,
|
||||
isNewHeader: false,
|
||||
}
|
||||
),
|
||||
},
|
||||
},
|
||||
};
|
||||
case REQUEST_HEADER_REMOVED:
|
||||
return {
|
||||
...state,
|
||||
displayedApi: {
|
||||
...state.displayedApi,
|
||||
request: {
|
||||
...state.displayedApi.request,
|
||||
headers: state.displayedApi.request.headers.filter((header, i) => {
|
||||
return !(i === action.data);
|
||||
}),
|
||||
},
|
||||
},
|
||||
};
|
||||
case UNFOCUS_ROLE_HEADER:
|
||||
return {
|
||||
...state,
|
||||
headerFocus: false,
|
||||
};
|
||||
case FOCUS_ROLE_HEADER:
|
||||
return {
|
||||
...state,
|
||||
headerFocus: true,
|
||||
};
|
||||
case GRAPHQL_ENDPOINT_CHANGED:
|
||||
return {
|
||||
...state,
|
||||
graphqlEndpoint: action.data,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default apiExplorerReducer;
|
||||
|
||||
export {
|
||||
changeRequestHeader,
|
||||
addRequestHeader,
|
||||
removeRequestHeader,
|
||||
graphQLFetcherFinal,
|
||||
focusHeaderTextbox,
|
||||
unfocusTypingHeader,
|
||||
updateGraphQLEndpoint,
|
||||
};
|
@ -0,0 +1,52 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ApiRequestWrapper from './ApiRequestWrapper';
|
||||
import Helmet from 'react-helmet';
|
||||
import { push } from 'react-router-redux';
|
||||
|
||||
class ApiExplorer extends Component {
|
||||
componentWillMount() {
|
||||
const localStorageUrl = window.localStorage.getItem('ONLINE_GRAPHIQL_ENDPOINT');
|
||||
if (!this.props.graphqlEndpoint && localStorageUrl === null) {
|
||||
this.props.dispatch(push('/'));
|
||||
}
|
||||
}
|
||||
render() {
|
||||
const localStorageUrl = window.localStorage.getItem('ONLINE_GRAPHIQL_ENDPOINT');
|
||||
const styles = require('./ApiExplorer.scss');
|
||||
const wrapperClass = styles.apiExplorerWrapper;
|
||||
const requestStyles = '';
|
||||
const wdClass = '';
|
||||
const requestWrapper = (
|
||||
<ApiRequestWrapper
|
||||
credentials={this.props.credentials}
|
||||
explorerData={this.props.explorerData}
|
||||
details={this.props.displayedApi.details}
|
||||
request={this.props.displayedApi.request}
|
||||
requestStyles={requestStyles}
|
||||
dispatch={this.props.dispatch}
|
||||
wdStyles={wdClass}
|
||||
route={this.props.route}
|
||||
dataHeaders={this.props.dataHeaders}
|
||||
headerFocus={this.props.headerFocus}
|
||||
graphqlEndpoint={localStorageUrl}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={'container-fluid ' + styles.padd_remove}>
|
||||
<Helmet title="GraphiQL" />
|
||||
<div className={wrapperClass}>{requestWrapper}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ApiExplorer.propTypes = {
|
||||
modalState: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
route: PropTypes.object.isRequired,
|
||||
headerFocus: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default ApiExplorer;
|
@ -0,0 +1,808 @@
|
||||
@import "../Common/Common.scss";
|
||||
.display_inl {
|
||||
display: inline-block;
|
||||
}
|
||||
.width_80 {
|
||||
width: 80%;
|
||||
}
|
||||
.responseHeader
|
||||
{
|
||||
color: #788095;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
}
|
||||
.admin_token_align {
|
||||
vertical-align: middle;
|
||||
margin-left: 2px;
|
||||
}
|
||||
.marginBottom
|
||||
{
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.apiExplorerMini {
|
||||
width: 80%;
|
||||
}
|
||||
.wrapperOnBoarding {
|
||||
// width: 80% !important;
|
||||
}
|
||||
.panelGreyed {
|
||||
opacity: 0.1;
|
||||
}
|
||||
.requestGreyed {
|
||||
opacity: 0.1;
|
||||
}
|
||||
.panelInFocus {
|
||||
|
||||
}
|
||||
.requestInFocus {
|
||||
|
||||
}
|
||||
.cursorNotAllowed {
|
||||
cursor: not-allowed;
|
||||
button {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
.apiExplorerWrapper
|
||||
{
|
||||
display: flex;
|
||||
height: $mainContainerHeight;
|
||||
.ApiRequestWrapperVH
|
||||
{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.apiCollectionWrapper
|
||||
{
|
||||
background-color: #fff;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
// Changed it from overfllow-y: scroll
|
||||
.apiCollectionTabWrapper
|
||||
{
|
||||
.apiCollectionTab
|
||||
{
|
||||
-webkit-padding-start: 0px;
|
||||
-webkit-margin-before: 0;
|
||||
-webkit-margin-after: 0;
|
||||
-moz-padding-start: 0px;
|
||||
-moz-margin-before: 0;
|
||||
-moz-margin-after: 0;
|
||||
border-bottom: 1px solid #D8D8D8;
|
||||
position: absolute;
|
||||
width: 20%;
|
||||
min-width: 240px;
|
||||
background-color: #fff;
|
||||
z-index: 10;
|
||||
.apiCollectionTabList
|
||||
{
|
||||
list-style-type: none;
|
||||
display: inline-block;
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
padding: 10px 11px;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
color: #D8D8D8;
|
||||
cursor: pointer;
|
||||
}
|
||||
.activeApiCollectionTab
|
||||
{
|
||||
border-bottom: 3px solid #ffca27;
|
||||
color: #6B6B6B;
|
||||
}
|
||||
.apiCollectionTabList:focus
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
.apiCollectionClearHistory
|
||||
{
|
||||
padding: 0 15px;
|
||||
margin: 0;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
/*
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
transform: translateX(-88%);
|
||||
*/
|
||||
.apiCollectionClearHistoryButton
|
||||
{
|
||||
/*
|
||||
float: right;
|
||||
margin: 10px 0;
|
||||
cursor: pointer;
|
||||
*/
|
||||
margin: 10px 0;
|
||||
cursor: pointer;
|
||||
position: fixed;
|
||||
bottom: 15px;
|
||||
text-align: center;
|
||||
width: 20%;
|
||||
margin-left: -15px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
z-index: 1;
|
||||
i {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.apiPaddTop
|
||||
{
|
||||
padding-top: 46px !important;
|
||||
}
|
||||
.apiCollectionTabListDetails
|
||||
{
|
||||
padding: 0 15px;
|
||||
margin: 10px 0;
|
||||
// padding-top: 46px;
|
||||
.apiCollectionTabListHead
|
||||
{
|
||||
padding-left: 15px;
|
||||
padding-bottom: 10px;
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
.serviceBaseDomain {
|
||||
color: #bbb;
|
||||
}
|
||||
}
|
||||
.add_ellipsis {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
.apiCollectionGetPost
|
||||
{
|
||||
.apiCollectionGetWrapper
|
||||
{
|
||||
padding: 5px 0;
|
||||
cursor: pointer;
|
||||
.apiCollectionGet
|
||||
{
|
||||
text-align: left;
|
||||
color: #70CD00;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
padding-left: 15px;
|
||||
}
|
||||
.apiCollectionGetDetailsWrapper
|
||||
{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.apiCollectionGetDetails
|
||||
{
|
||||
word-wrap: break-word;
|
||||
padding-right: 10px !important
|
||||
}
|
||||
.apiCollectionPostDetails
|
||||
{
|
||||
word-wrap: break-word;
|
||||
padding-right: 10px !important
|
||||
}
|
||||
.apiRightArrowWrapper
|
||||
{
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
.activeApiCollectionGetWrapperIcon
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.activeApiCollectionGetWrapper
|
||||
{
|
||||
background-color: #FFF3D5;
|
||||
border-radius: 4px;
|
||||
.activeApiCollectionGetWrapperIcon
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.apiCollectionPostWrapper
|
||||
{
|
||||
padding: 5px 0;
|
||||
cursor: pointer;
|
||||
.apiCollectionPost
|
||||
{
|
||||
text-align: left;
|
||||
color: #FD9540;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
padding-left: 15px;
|
||||
}
|
||||
.apiCollectionGetDetailsWrapper
|
||||
{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.apiCollectionGetDetails
|
||||
{
|
||||
word-wrap: break-word;
|
||||
padding-right: 10px !important
|
||||
}
|
||||
.apiCollectionPostDetails
|
||||
{
|
||||
word-wrap: break-word;
|
||||
padding-right: 10px !important
|
||||
}
|
||||
.apiRightArrowWrapper
|
||||
{
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.activeApiCollectionGetWrapperIcon
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.activeApiCollectionGetWrapper
|
||||
{
|
||||
background-color: #FFF3D5;
|
||||
border-radius: 4px;
|
||||
.activeApiCollectionGetWrapperIcon
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.apiContentPadd {
|
||||
padding-top: 20px;
|
||||
border-color: rgba(23, 42, 58, .1);
|
||||
border-width: 2px;
|
||||
border-bottom-style: solid;
|
||||
padding-bottom: 10px;
|
||||
width: 100%;
|
||||
float: left;
|
||||
}
|
||||
.closeHeader {
|
||||
cursor: pointer;
|
||||
padding-top: 8px;
|
||||
font-size: 16px;
|
||||
float: right;
|
||||
display: inline-block;
|
||||
}
|
||||
.showAccessKey{
|
||||
cursor: pointer;
|
||||
padding-top: 8px;
|
||||
padding-right: 8px;
|
||||
font-size: 16px;
|
||||
float: left;
|
||||
display: inline-block;
|
||||
}
|
||||
.apiRequestWrapper
|
||||
{
|
||||
.file_upload_wrapper {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
display: inline-block;
|
||||
padding: 20px;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
margin-bottom: 15px;
|
||||
input[type="file"] {
|
||||
display: inline-block;
|
||||
width: 162px;
|
||||
}
|
||||
}
|
||||
.apiRequestheader
|
||||
{
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
padding-bottom: 10px;
|
||||
color: #000;
|
||||
}
|
||||
.apiHasura {
|
||||
font-size: 14px;
|
||||
text-align: right;
|
||||
i {
|
||||
color: #757575;;
|
||||
font-size: 22px;
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 15px;
|
||||
}
|
||||
i:hover {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
.built {
|
||||
text-align: right;
|
||||
font-size: 14px;
|
||||
position: absolute;
|
||||
right: 40px;
|
||||
top: 16px;
|
||||
i {
|
||||
color: #f93c18;
|
||||
}
|
||||
}
|
||||
.changeEndpoint {
|
||||
padding: 10px 10px !important;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.apiRequestContent
|
||||
{
|
||||
font-size: 14px;
|
||||
float: left;
|
||||
font-weight: bold;
|
||||
a
|
||||
{
|
||||
color: #FEC53D;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover
|
||||
{
|
||||
color: #FEC53D;
|
||||
text-decoration: underline;
|
||||
}
|
||||
code
|
||||
{
|
||||
background-color: transparent;
|
||||
border: 1px solid #767E93;
|
||||
padding: 1px 4px !important;
|
||||
color: #767E93;
|
||||
}
|
||||
}
|
||||
.apiPostRequestWrapper
|
||||
{
|
||||
// padding: 20px 0;
|
||||
// padding-top: 20px;
|
||||
padding-top: 20px;
|
||||
background-color: #f8fafb;
|
||||
.inputGroupWrapper
|
||||
{
|
||||
-webkit-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
|
||||
-moz-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
|
||||
border-radius: 5px;
|
||||
.inputGroupBtn
|
||||
{
|
||||
button
|
||||
{
|
||||
width: 100px;
|
||||
border: 0;
|
||||
padding: 10px 12px;
|
||||
background-color: #F9F9F9;
|
||||
color: #FD9540;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
.caret
|
||||
{
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.inputGroupInput
|
||||
{
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
padding: 10px 12px;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.sendBtn
|
||||
{
|
||||
button
|
||||
{
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
height: 39px;
|
||||
color: #606060;
|
||||
font-weight: bold;
|
||||
border-radius: 5px;
|
||||
background-color: #FEC53D;
|
||||
border: 1px solid #FEC53D;
|
||||
/*
|
||||
background-color: #FFCA27;
|
||||
border: 1px solid #FFCA27;
|
||||
*/
|
||||
&:hover {
|
||||
background-color: #F2B130;
|
||||
}
|
||||
}
|
||||
/*
|
||||
button:hover
|
||||
{
|
||||
border: 1px solid #F2B130;
|
||||
background-color: #F2B130;
|
||||
}
|
||||
*/
|
||||
}
|
||||
.generateBtn
|
||||
{
|
||||
button
|
||||
{
|
||||
width: 100%;
|
||||
background-color: transparent;
|
||||
text-align: center;
|
||||
height: 39px;
|
||||
border: 1px solid #606060;
|
||||
color: #606060;
|
||||
font-weight: bold;
|
||||
border-radius: 5px;
|
||||
}
|
||||
button:hover
|
||||
{
|
||||
border: 1px solid #606060;
|
||||
background-color: #efefef;
|
||||
}
|
||||
}
|
||||
}
|
||||
.responseWrapper
|
||||
{
|
||||
clear: both;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.responseHeader
|
||||
{
|
||||
color: #788095;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
.viewDetails
|
||||
{
|
||||
padding-left: 10px;
|
||||
font-weight: normal;
|
||||
color: #FFCA27;
|
||||
}
|
||||
.addAdminToken
|
||||
{
|
||||
text-align: right;
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
.addAdminToken
|
||||
{
|
||||
text-align: right;
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.apiResponseWrapper
|
||||
{
|
||||
.apiResponseheaderWrapper
|
||||
{
|
||||
border-bottom: 1px solid #ccc;
|
||||
margin-bottom: 20px;
|
||||
.apiResponseheader
|
||||
{
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
padding-bottom: 10px;
|
||||
// color: #000;
|
||||
color: #788095
|
||||
}
|
||||
.statusDetails
|
||||
{
|
||||
display: inline-block;
|
||||
float: right;
|
||||
padding-left: 20px;
|
||||
.statusView
|
||||
{
|
||||
padding-left: 5px;
|
||||
font-weight: normal;
|
||||
color: #FFCA27;
|
||||
}
|
||||
}
|
||||
}
|
||||
.helpTextWrapper
|
||||
{
|
||||
padding: 15px;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
clear: both;
|
||||
margin-bottom: 20px;
|
||||
i
|
||||
{
|
||||
padding-right: 10px;
|
||||
}
|
||||
pre
|
||||
{
|
||||
margin-top: 10px;
|
||||
border-radius: 0;
|
||||
}
|
||||
.copyBtn
|
||||
{
|
||||
padding: 9px;
|
||||
}
|
||||
}
|
||||
.suggestionTextColor {
|
||||
color: #111;
|
||||
background-color: #ffd760;
|
||||
border-color: #ffd760;
|
||||
}
|
||||
.noResponseWrapper
|
||||
{
|
||||
width: 100%;
|
||||
min-height: 200px;
|
||||
background-color: #fff;
|
||||
-webkit-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
|
||||
-moz-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
|
||||
clear: both;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
.noResponseContainer
|
||||
{
|
||||
width: 325px;
|
||||
.noResponseHeader
|
||||
{
|
||||
font-size: 18px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.barWrapper
|
||||
{
|
||||
padding-top: 15px;
|
||||
text-align: center;
|
||||
.bigBar
|
||||
{
|
||||
width: 56%;
|
||||
margin-right: 7px;
|
||||
height: 20px;
|
||||
background-color: #EEEEEE;
|
||||
display: inline-block;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.mediumBar
|
||||
{
|
||||
width: 23%;
|
||||
margin-right: 7px;
|
||||
height: 20px;
|
||||
background-color: #FFCA27;
|
||||
display: inline-block;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.smallBar
|
||||
{
|
||||
width: 13%;
|
||||
margin-right: 7px;
|
||||
height: 20px;
|
||||
background-color: #EEEEEE;
|
||||
display: inline-block;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.responseHeader
|
||||
{
|
||||
padding-top: 15px;
|
||||
color: #788095;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
clear: both;
|
||||
.viewDetails
|
||||
{
|
||||
padding-left: 10px;
|
||||
font-weight: normal;
|
||||
color: #FFCA27;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Common
|
||||
.responseTable
|
||||
{
|
||||
padding-top: 15px;
|
||||
.tableBorder
|
||||
{
|
||||
background-color: #fff;
|
||||
border: 1px solid #E3E5E5;
|
||||
thead
|
||||
{
|
||||
tr
|
||||
{
|
||||
th
|
||||
{
|
||||
border-bottom: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
tbody
|
||||
{
|
||||
tr
|
||||
{
|
||||
td
|
||||
{
|
||||
border-top: 0;
|
||||
// padding: 5px;
|
||||
padding: 0px 5px;
|
||||
min-width: 50px;
|
||||
.responseTableInput
|
||||
{
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
// padding: 0;
|
||||
}
|
||||
}
|
||||
.headerPadd {
|
||||
padding: 15px !important;
|
||||
}
|
||||
.borderTop
|
||||
{
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
.tableTdLeft
|
||||
{
|
||||
padding-left: 5%;
|
||||
}
|
||||
.tableEnterKey
|
||||
{
|
||||
// padding: 10px 0;
|
||||
padding: 0px 5px;
|
||||
padding-left: 4.5%;
|
||||
}
|
||||
.tableLastTd
|
||||
{
|
||||
padding-left: 5px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.headerHeading {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
.queryBuilderWrapper
|
||||
{
|
||||
padding-bottom: 20px;
|
||||
.queryBuilderTab
|
||||
{
|
||||
ul
|
||||
{
|
||||
border: 1px solid #E7E7E7;
|
||||
-webkit-padding-start: 0px;
|
||||
-moz-padding-start: 0px;
|
||||
display: inline-block;
|
||||
li
|
||||
{
|
||||
list-style-type: none;
|
||||
display: inline-block;
|
||||
padding: 12px 20px;
|
||||
width: 150px;
|
||||
text-align: center;
|
||||
color: #788094;
|
||||
cursor: pointer;
|
||||
background-color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
li:focus
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
.activeQueryBuilderTab
|
||||
{
|
||||
background-color: #FFF050;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.AceEditorWrapper
|
||||
{
|
||||
-webkit-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
|
||||
-moz-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
|
||||
/*
|
||||
margin-top: 15px;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 20px;
|
||||
*/
|
||||
}
|
||||
|
||||
.queryBuilderLayout {
|
||||
background-color: #fff;
|
||||
// padding: 15px;
|
||||
}
|
||||
.queryBuilderLayoutSub {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.qbTabHeading {
|
||||
font-weight: bold;
|
||||
padding-top: 15px;
|
||||
padding-left: 20px;
|
||||
padding-bottom: 15px;
|
||||
i {
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.common_checkbox
|
||||
{
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
.common_checkbox_label
|
||||
{
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin: 0px;
|
||||
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
.common_checkbox_label
|
||||
{
|
||||
margin-bottom: 0px !important;
|
||||
padding-top: 5px;
|
||||
}
|
||||
.common_checkbox + .common_checkbox_label:before
|
||||
{
|
||||
content: '';
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
padding-top: 2px;
|
||||
margin-right: 2px;
|
||||
text-align: center;
|
||||
border-radius:4px;
|
||||
cursor:pointer;
|
||||
}
|
||||
label
|
||||
{
|
||||
font-weight: normal;
|
||||
}
|
||||
.common_checkbox:checked + .common_checkbox_label:before
|
||||
{
|
||||
content: url('./tick.png');
|
||||
background: #FFCA27;
|
||||
color: #fff;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.authPanelSubHeadings {
|
||||
font-size: 16px;
|
||||
font-weight: italic;
|
||||
padding-left: 15px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.apiResponseTab {
|
||||
padding-top: 20px;
|
||||
.apiResponseTabUl {
|
||||
display: inline-block;
|
||||
-webkit-padding-start: 0px;
|
||||
-webkit-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.1);
|
||||
-moz-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.1);
|
||||
.apiResponseTabList {
|
||||
display: inline-block;
|
||||
padding: 15px 25px;
|
||||
list-style-type: none;
|
||||
background-color: #fff;
|
||||
font-weight: 600;
|
||||
color: #6B6B6B;
|
||||
cursor: pointer;
|
||||
}
|
||||
.apiResponseTabList:focus {
|
||||
outline: none;
|
||||
}
|
||||
.activeApiResponseTab {
|
||||
background-color: #FFF3D5
|
||||
}
|
||||
}
|
||||
.apiResponseTabPanel {
|
||||
.AceEditorWrapper {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
import ApiExplorer from './ApiExplorer';
|
||||
|
||||
const generatedApiExplorer = connect => {
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
...state.apiexplorer,
|
||||
credentials: {},
|
||||
};
|
||||
};
|
||||
return connect(mapStateToProps)(ApiExplorer);
|
||||
};
|
||||
|
||||
export default generatedApiExplorer;
|
@ -0,0 +1,325 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { push } from 'react-router-redux';
|
||||
|
||||
import {
|
||||
changeRequestParams,
|
||||
addRequestHeader,
|
||||
changeRequestHeader,
|
||||
removeRequestHeader,
|
||||
updateFileObject,
|
||||
focusHeaderTextbox,
|
||||
unfocusTypingHeader,
|
||||
} from './Actions';
|
||||
|
||||
import GraphiQLWrapper from './GraphiQLWrapper';
|
||||
|
||||
const styles = require('./ApiExplorer.scss');
|
||||
|
||||
class ApiRequest extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
this.state.accessKeyVisible = false;
|
||||
this.state.bodyAllowedMethods = ['POST'];
|
||||
this.state.tabIndex = 0;
|
||||
}
|
||||
|
||||
onRequestParamsChanged = newValue => {
|
||||
this.props.dispatch(changeRequestParams(newValue));
|
||||
};
|
||||
|
||||
onHeaderValueChanged(e) {
|
||||
const index = parseInt(e.target.getAttribute('data-header-id'), 10);
|
||||
const key = e.target.getAttribute('data-element-name');
|
||||
const newValue = e.target.value;
|
||||
this.props.dispatch(changeRequestHeader(index, key, newValue, false));
|
||||
}
|
||||
|
||||
onDeleteHeaderClicked(e) {
|
||||
const index = parseInt(e.target.getAttribute('data-header-id'), 10);
|
||||
this.props.dispatch(removeRequestHeader(index));
|
||||
}
|
||||
|
||||
onNewHeaderKeyChanged(e) {
|
||||
this.handleTypingTimeouts();
|
||||
this.props.dispatch(addRequestHeader(e.target.value, ''));
|
||||
}
|
||||
|
||||
onNewHeaderValueChanged(e) {
|
||||
this.handleTypingTimeouts();
|
||||
this.props.dispatch(addRequestHeader('', e.target.value));
|
||||
}
|
||||
|
||||
onKeyUpAtNewHeaderField(e) {
|
||||
if (e.keyCode === 13) {
|
||||
this.props.dispatch(
|
||||
addRequestHeader(this.state.newHeader.key, this.state.newHeader.value)
|
||||
);
|
||||
}
|
||||
}
|
||||
getUrlBar() {
|
||||
return (
|
||||
<div
|
||||
id="stickyHeader"
|
||||
className={
|
||||
styles.apiPostRequestWrapper +
|
||||
' ' +
|
||||
styles.wd100 +
|
||||
' ' +
|
||||
styles.stickyHeader
|
||||
}
|
||||
>
|
||||
<div className={'col-xs-11 ' + styles.padd_remove}>
|
||||
<div
|
||||
className={
|
||||
'input-group ' +
|
||||
styles.inputGroupWrapper
|
||||
}
|
||||
>
|
||||
<div
|
||||
className={
|
||||
'input-group-btn ' +
|
||||
styles.inputGroupBtn
|
||||
}
|
||||
>
|
||||
<button type="button" className={'btn btn-default'}>
|
||||
POST
|
||||
</button>
|
||||
</div>
|
||||
<input
|
||||
defaultValue={this.props.url}
|
||||
readOnly
|
||||
type="text"
|
||||
className={
|
||||
styles.inputGroupInput +
|
||||
' form-control '
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={'col-xs-1 ' + styles.padd_remove}>
|
||||
<button onClick={this.changeEndpoint.bind(this)} className={styles.changeEndpoint + ' btn btn-sm btn-small btn-info'}>
|
||||
Change Endpoint
|
||||
</button>
|
||||
</div>
|
||||
<div className={styles.stickySeparator} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
getHeaderTitleView() {
|
||||
return (
|
||||
<div className={styles.responseWrapper}>
|
||||
<div className={'col-xs-12 ' + styles.padd_remove}>
|
||||
<div className={styles.responseHeader}>Request Headers</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
getHeaderRows() {
|
||||
const rows = this.props.headers.map((header, i) => {
|
||||
return (
|
||||
<tr key={i}>
|
||||
{header.isNewHeader ? null : (
|
||||
<td>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="sponsored"
|
||||
className={styles.common_checkbox + ' common_checkbox'}
|
||||
id={i + 1}
|
||||
checked={header.isActive}
|
||||
data-header-id={i}
|
||||
onChange={this.onHeaderValueChanged.bind(this)}
|
||||
data-element-name="isActive"
|
||||
/>
|
||||
<label
|
||||
htmlFor={i + 1}
|
||||
className={
|
||||
styles.common_checkbox_label + ' common_checkbox_label'
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
)}
|
||||
<td
|
||||
colSpan={header.isNewHeader ? '2' : '1'}
|
||||
className={
|
||||
header.isNewHeader
|
||||
? styles.border_right +
|
||||
' ' +
|
||||
styles.tableTdLeft +
|
||||
' ' +
|
||||
styles.borderTop +
|
||||
' ' +
|
||||
styles.tableEnterKey
|
||||
: styles.border_right
|
||||
}
|
||||
>
|
||||
<input
|
||||
className={'form-control ' + styles.responseTableInput}
|
||||
value={header.key}
|
||||
disabled={header.isDisabled === true ? true : false}
|
||||
data-header-id={i}
|
||||
placeholder="Enter Key"
|
||||
data-element-name="key"
|
||||
onChange={this.onHeaderValueChanged.bind(this)}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
type="text"
|
||||
data-test={`header-key-${i}`}
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
colSpan={header.isNewHeader ? '2' : '1'}
|
||||
className={
|
||||
header.isNewHeader
|
||||
? styles.borderTop +
|
||||
' ' +
|
||||
styles.tableEnterKey +
|
||||
' ' +
|
||||
styles.tableLastTd
|
||||
: ''
|
||||
}
|
||||
>
|
||||
<input
|
||||
className={'form-control ' + styles.responseTableInput}
|
||||
value={header.value}
|
||||
disabled={header.isDisabled === true ? true : false}
|
||||
data-header-id={i}
|
||||
placeholder="Enter Value"
|
||||
data-element-name="value"
|
||||
onChange={this.onHeaderValueChanged.bind(this)}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
data-test={`header-value-${i}`}
|
||||
type={
|
||||
header.key === 'X-Hasura-Access-Key' &&
|
||||
!this.state.accessKeyVisible
|
||||
? 'password'
|
||||
: 'text'
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
{header.isNewHeader ? null : (
|
||||
<td>
|
||||
{header.key === 'X-Hasura-Access-Key' ? (
|
||||
<i
|
||||
className={styles.showAccessKey + ' fa fa-eye'}
|
||||
data-header-id={i}
|
||||
aria-hidden="true"
|
||||
onClick={this.onShowAccessKeyClicked.bind(this)}
|
||||
/>
|
||||
) : null}
|
||||
<i
|
||||
className={styles.closeHeader + ' fa fa-times'}
|
||||
data-header-id={i}
|
||||
aria-hidden="true"
|
||||
onClick={this.onDeleteHeaderClicked.bind(this)}
|
||||
/>
|
||||
</td>
|
||||
)}
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
return rows;
|
||||
}
|
||||
|
||||
getHeaderTableView() {
|
||||
return (
|
||||
<div className={styles.responseTable}>
|
||||
<table className={'table ' + styles.tableBorder}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th className={styles.wd4 + ' ' + styles.headerHeading} />
|
||||
<th
|
||||
className={
|
||||
styles.wd48 +
|
||||
' ' +
|
||||
styles.border_right +
|
||||
' ' +
|
||||
styles.headerHeading
|
||||
}
|
||||
>
|
||||
Key
|
||||
</th>
|
||||
<th className={styles.wd48 + ' ' + styles.headerHeading}>
|
||||
Value
|
||||
</th>
|
||||
<th className={styles.wd4 + ' ' + styles.headerHeading} />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>{this.getHeaderRows()}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
getHeaderBody() {
|
||||
return (
|
||||
<div className={styles.responseHeader + ' ' + styles.marginBottom}>
|
||||
Request Body
|
||||
</div>
|
||||
);
|
||||
}
|
||||
getValidBody() {
|
||||
switch (this.props.bodyType) {
|
||||
case 'graphql':
|
||||
return (
|
||||
<GraphiQLWrapper
|
||||
data={this.props}
|
||||
dispatch={this.props.dispatch}
|
||||
headerFocus={this.props.headerFocus}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
changeEndpoint() {
|
||||
this.props.dispatch(push('/'));
|
||||
}
|
||||
|
||||
handleFocus = () => {
|
||||
this.props.dispatch(focusHeaderTextbox());
|
||||
};
|
||||
|
||||
handleBlur = () => {
|
||||
this.props.dispatch(unfocusTypingHeader());
|
||||
};
|
||||
|
||||
handleFileChange(e) {
|
||||
if (e.target.files.length > 0) {
|
||||
this.props.dispatch(updateFileObject(e.target.files[0]));
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={styles.apiRequestWrapper}>
|
||||
{this.getUrlBar()}
|
||||
<hr />
|
||||
{this.getHeaderTitleView()}
|
||||
{this.getHeaderTableView()}
|
||||
{this.getValidBody()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ApiRequest.propTypes = {
|
||||
method: PropTypes.string.isRequired,
|
||||
url: PropTypes.string.isRequired,
|
||||
headers: PropTypes.array,
|
||||
params: PropTypes.string,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
explorerData: PropTypes.object.isRequired,
|
||||
credentials: PropTypes.object.isRequired,
|
||||
bodyType: PropTypes.string.isRequired,
|
||||
route: PropTypes.object.isRequired,
|
||||
numberOfTables: PropTypes.number.isRequired,
|
||||
headerFocus: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default ApiRequest;
|
@ -0,0 +1,28 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class ApiRequestDetails extends Component {
|
||||
render() {
|
||||
const styles = require('./ApiExplorer.scss');
|
||||
return (
|
||||
<div className={styles.apiRequestWrapper + ' ' + styles.apiContentPadd}>
|
||||
<div className={styles.apiRequestContent}>{this.props.description}</div>
|
||||
<div className={styles.built}>
|
||||
Built with <i className="fa fa-heart" /> by <a href={'http://hasura.io/'} target={'_blank'}>Hasura</a>
|
||||
</div>
|
||||
<div className={styles.apiHasura}>
|
||||
<a href="https://github.com/hasura/graphql-engine/tree/master/community/tools/graphiql-online" target={'_blank'}>
|
||||
<i className="fa fa-github" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ApiRequestDetails.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
description: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default ApiRequestDetails;
|
@ -0,0 +1,63 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ApiRequest from './ApiRequest';
|
||||
import ApiRequestDetails from './ApiRequestDetails';
|
||||
|
||||
class ApiRequestWrapper extends Component {
|
||||
render() {
|
||||
const styles = require('./ApiExplorer.scss');
|
||||
return (
|
||||
<div
|
||||
id="apiRequestBlock"
|
||||
className={
|
||||
this.props.wdStyles +
|
||||
' ' +
|
||||
styles.padd_left +
|
||||
' ' +
|
||||
styles.padd_right +
|
||||
' ' +
|
||||
styles.ApiRequestWrapperVH +
|
||||
' ' +
|
||||
this.props.requestStyles
|
||||
}
|
||||
>
|
||||
<ApiRequestDetails
|
||||
title={this.props.details.title}
|
||||
description={this.props.details.description}
|
||||
/>
|
||||
<ApiRequest
|
||||
bodyType={
|
||||
this.props.request.bodyType ? this.props.request.bodyType : ''
|
||||
}
|
||||
credentials={this.props.credentials}
|
||||
method={this.props.request.method}
|
||||
url={this.props.graphqlEndpoint}
|
||||
headers={this.props.request.headers}
|
||||
params={this.props.request.params}
|
||||
explorerData={this.props.explorerData}
|
||||
dispatch={this.props.dispatch}
|
||||
dataHeaders={this.props.dataHeaders}
|
||||
numberOfTables={this.props.numberOfTables}
|
||||
headerFocus={this.props.headerFocus}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ApiRequestWrapper.propTypes = {
|
||||
details: PropTypes.object.isRequired,
|
||||
request: PropTypes.object.isRequired,
|
||||
explorerData: PropTypes.object.isRequired,
|
||||
credentials: PropTypes.object.isRequired,
|
||||
bodyType: PropTypes.string,
|
||||
showHelpBulb: PropTypes.bool,
|
||||
requestStyles: PropTypes.string,
|
||||
wdStyles: PropTypes.string,
|
||||
dispatch: PropTypes.func,
|
||||
numberOfTables: PropTypes.number,
|
||||
headerFocus: PropTypes.bool.isRequired,
|
||||
graphqlEndpoint: PropTypes.string,
|
||||
};
|
||||
|
||||
export default ApiRequestWrapper;
|
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="-216 218 66 66" style="enable-background:new -216 218 66 66;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#97A9FF;}
|
||||
.st1{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g id="Layer_1">
|
||||
<title>Discord</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<g id="Page-1">
|
||||
<g id="Hasura_Jun29-Update" transform="translate(-1157.000000, -872.000000)">
|
||||
<g id="Group-6" transform="translate(1066.000000, 872.000000)">
|
||||
<g id="Discord" transform="translate(91.000000, 0.000000)">
|
||||
<g>
|
||||
<g id="Twitter-Copy">
|
||||
<path id="back" class="st0" d="M-216,251c0-18.2,14.8-33,33-33s33,14.8,33,33s-14.8,33-33,33S-216,269.2-216,251z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Layer_2">
|
||||
<g>
|
||||
<path class="st1" d="M-172.5,266.6l-2.5-2.9c4.8-1.3,6.7-4.6,6.7-4.6c-6.1,5.7-22.6,6-29.1,0c0,0,1.6,3,6.5,4.6l-2.7,2.9
|
||||
c-8.2-0.1-11.3-5.6-11.3-5.6c0-12.1,5.4-21.8,5.4-21.8c5.5-3.9,10.5-3.9,10.5-3.9l0.4,0.5c-6.8,1.9-9.7,4.9-9.7,4.9
|
||||
c7.9-5.4,24.3-4.9,30.7,0c0.1-0.1-3.9-3.3-10-4.9l0.6-0.5c0,0,5,0,10.5,3.9c0,0,5.4,9.7,5.4,21.8
|
||||
C-161.2,261-164.3,266.5-172.5,266.6z"/>
|
||||
<ellipse class="st0" cx="-190" cy="253.5" rx="3.9" ry="4.1"/>
|
||||
<ellipse class="st0" cx="-176.5" cy="253.5" rx="3.9" ry="4.1"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="8" viewBox="0 0 13 8"><path fill="none" stroke="#4D4D4D" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.6" opacity=".7" transform="rotate(90 5 6.5)" d="M0 10L5 5 0 0"/></svg>
|
After Width: | Height: | Size: 249 B |
@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class ErrorBoundary extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { hasError: false, info: null };
|
||||
}
|
||||
|
||||
componentDidCatch(error, info) {
|
||||
this.setState({ hasError: true, info: info });
|
||||
// most likely a localstorage issue
|
||||
window.localStorage.clear();
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
// You can render any custom fallback UI
|
||||
return <div>{this.props.children}</div>;
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorBoundary.propTypes = {
|
||||
children: PropTypes.element,
|
||||
};
|
||||
|
||||
export default ErrorBoundary;
|
@ -0,0 +1,65 @@
|
||||
import React, { Component } from 'react';
|
||||
import GraphiQL from 'hasura-console-graphiql';
|
||||
import PropTypes from 'prop-types';
|
||||
import ErrorBoundary from './ErrorBoundary';
|
||||
import { graphQLFetcherFinal } from './Actions';
|
||||
|
||||
import './GraphiQL.css';
|
||||
|
||||
class GraphiQLWrapper extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
schema: null,
|
||||
error: false,
|
||||
onBoardingEnabled: false,
|
||||
};
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !nextProps.headerFocus;
|
||||
}
|
||||
|
||||
render() {
|
||||
const styles = require('../Common/Common.scss');
|
||||
const { variables, query } = window.__env;
|
||||
const graphQLFetcher = graphQLParams => {
|
||||
return graphQLFetcherFinal(
|
||||
graphQLParams,
|
||||
this.props.data.url,
|
||||
this.props.data.headers
|
||||
);
|
||||
};
|
||||
const graphiqlProps = {
|
||||
fetcher: graphQLFetcher,
|
||||
};
|
||||
if (query || Object.keys(variables).length !== 0) {
|
||||
graphiqlProps.query = query;
|
||||
if (variables !== 'undefined') {
|
||||
graphiqlProps.variables = JSON.stringify(variables, null, 2);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<div
|
||||
className={
|
||||
'react-container-graphql ' +
|
||||
styles.wd100 +
|
||||
' ' +
|
||||
styles.graphQLHeight
|
||||
}
|
||||
>
|
||||
<GraphiQL {...graphiqlProps} />
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
GraphiQLWrapper.propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
data: PropTypes.object.isRequired,
|
||||
headerFocus: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default GraphiQLWrapper;
|
@ -0,0 +1,351 @@
|
||||
@import url('https://fonts.googleapis.com/css?family=Raleway:300,400,600');
|
||||
@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,600');
|
||||
body
|
||||
{
|
||||
font-size: 16px;
|
||||
font-family: 'Open Sans'
|
||||
}
|
||||
.wd100
|
||||
{
|
||||
width: 100%;
|
||||
float: left;
|
||||
}
|
||||
.displayFlex
|
||||
{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.boxShadow
|
||||
{
|
||||
-webkit-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.3);
|
||||
-moz-box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.commonBtn
|
||||
{
|
||||
text-align: center;
|
||||
padding: 25px 0;
|
||||
clear: both;
|
||||
button
|
||||
{
|
||||
border-radius: 25px;
|
||||
background-color: #4767a1;
|
||||
padding: 15px 30px;
|
||||
border: 0;
|
||||
color: #fff;
|
||||
font-family: 'Raleway';
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
button:hover
|
||||
{
|
||||
background-color: #3b5f93;
|
||||
}
|
||||
button:focus
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
.lightGrayBgColor
|
||||
{
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
.blueBgColor
|
||||
{
|
||||
background-color: #303b4e;
|
||||
}
|
||||
.pageHeader
|
||||
{
|
||||
font-family: 'Raleway';
|
||||
font-weight: 600;
|
||||
font-size: 44px;
|
||||
color: #4D4D4D;
|
||||
}
|
||||
.pageSubHeader
|
||||
{
|
||||
font-family: 'Raleway';
|
||||
font-weight: 600;
|
||||
font-size: 28px;
|
||||
text-align: center;
|
||||
color: #102261;
|
||||
}
|
||||
.pageDescription
|
||||
{
|
||||
text-align: center;
|
||||
color: #565656;
|
||||
padding-bottom: 15px;
|
||||
font-size: 16px;
|
||||
line-height: 1.7;
|
||||
font-family: 'Open Sans';
|
||||
a
|
||||
{
|
||||
color: #f93c18;
|
||||
}
|
||||
a:hover
|
||||
{
|
||||
color: #e0270e;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
.pageDescriptionSmall
|
||||
{
|
||||
text-align: center;
|
||||
color: #f93c18;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
padding-bottom: 10px;
|
||||
font-family: 'Open Sans';
|
||||
a
|
||||
{
|
||||
color: #f93c18;
|
||||
i
|
||||
{
|
||||
color: #f93c18;
|
||||
}
|
||||
}
|
||||
a:hover
|
||||
{
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
.noPadd
|
||||
{
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
.commonSectionWrapper
|
||||
{
|
||||
padding: 75px 0;
|
||||
}
|
||||
|
||||
.powerfulGraphQLWrapper
|
||||
{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.pageSubHeader
|
||||
{
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
.pageSubHeader, .pageDescription
|
||||
{
|
||||
text-align: left;
|
||||
padding-right: 50px;
|
||||
}
|
||||
.powerfulGraphQLImg
|
||||
{
|
||||
text-align: right;
|
||||
img
|
||||
{
|
||||
width: 95%;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
.easyStepsWrapper
|
||||
{
|
||||
.pageSubHeader
|
||||
{
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
.stepsListWrapper
|
||||
{
|
||||
.stepsList
|
||||
{
|
||||
.stepsIcon
|
||||
{
|
||||
text-align: center;
|
||||
padding-bottom: 20px;
|
||||
img
|
||||
{
|
||||
max-height: 60px;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.pageDescription
|
||||
{
|
||||
padding: 0 5px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.easyStepsImg
|
||||
{
|
||||
background-color: #3edad7;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
padding: 30px;
|
||||
width: 90%;
|
||||
margin: 0 0 0 auto;
|
||||
img
|
||||
{
|
||||
width: 65px;
|
||||
display: inline-block;
|
||||
}
|
||||
.pageDescription
|
||||
{
|
||||
padding-top: 20px;
|
||||
color: #fff;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
font-family: 'Raleway';
|
||||
}
|
||||
}
|
||||
}
|
||||
.footerWrapper
|
||||
{
|
||||
padding: 20px 0px;
|
||||
.socialWrapper
|
||||
{
|
||||
text-align: center;
|
||||
.socialIcon
|
||||
{
|
||||
display: inline-block;
|
||||
padding: 0px 10px;
|
||||
img
|
||||
{
|
||||
width: 50px;
|
||||
display: inline-block;
|
||||
opacity: 0.7;
|
||||
}
|
||||
img:hover
|
||||
{
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.pageDescription
|
||||
{
|
||||
color: #fff;
|
||||
i
|
||||
{
|
||||
color: #f93c18;
|
||||
}
|
||||
a
|
||||
{
|
||||
color: #fff;
|
||||
}
|
||||
a:hover
|
||||
{
|
||||
color: #f93c18;
|
||||
}
|
||||
}
|
||||
.pageDescriptionSmall
|
||||
{
|
||||
padding-top: 20px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px)
|
||||
{
|
||||
.pageHeader
|
||||
{
|
||||
font-size: 30px;
|
||||
text-align: center;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
.pageSubHeader
|
||||
{
|
||||
font-size: 22px !important;
|
||||
text-align: center;
|
||||
}
|
||||
.pageDescription
|
||||
{
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
}
|
||||
.pageDescriptionSmall
|
||||
{
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
}
|
||||
.commonSectionWrapper
|
||||
{
|
||||
padding: 30px 0;
|
||||
}
|
||||
.displayFlex
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
.powerfulGraphQLWrapper
|
||||
{
|
||||
display: block;
|
||||
.pageSubHeader, .pageDescription
|
||||
{
|
||||
text-align: center;
|
||||
padding-right: 0;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
.powerfulGraphQLImg
|
||||
{
|
||||
text-align: center;
|
||||
padding-top: 20px;
|
||||
img
|
||||
{
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.easyStepsWrapper
|
||||
{
|
||||
.stepsListWrapper
|
||||
{
|
||||
.stepsList
|
||||
{
|
||||
padding-bottom: 0px;
|
||||
.stepsIcon
|
||||
{
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.easyStepsImg
|
||||
{
|
||||
width: 95%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
.footerWrapper
|
||||
{
|
||||
.pageDescriptionSmall
|
||||
{
|
||||
padding: 0px 10px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (min-width: 768px) and (max-width: 991px)
|
||||
{
|
||||
.commonSectionWrapper
|
||||
{
|
||||
padding: 30px 0;
|
||||
}
|
||||
.pageHeader
|
||||
{
|
||||
font-size: 35px;
|
||||
text-align: center;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
.easyStepsWrapper
|
||||
{
|
||||
.stepsListWrapper
|
||||
{
|
||||
.stepsList
|
||||
{
|
||||
padding-bottom: 30px;
|
||||
.stepsIcon
|
||||
{
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.easyStepsImg
|
||||
{
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="66px" height="66px" viewBox="0 0 66 66" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 49.3 (51167) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Twitter</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Hasura_Jun29-Update" transform="translate(-1066.000000, -872.000000)">
|
||||
<g id="Group-6" transform="translate(1066.000000, 872.000000)">
|
||||
<g id="Twitter">
|
||||
<g>
|
||||
<path d="M0,33 C0,14.7746024 14.7746024,0 33,0 C51.2253976,0 66,14.7746024 66,33 C66,51.2253976 51.2253976,66 33,66 C14.7746024,66 0,51.2253976 0,33 Z" id="back" fill="#55ACEE"></path>
|
||||
<path d="M32.5362646,26.7393379 L32.6058642,27.8966431 L31.4458703,27.7549322 C27.2234923,27.2117073 23.5347116,25.3694664 20.4027279,22.2754464 L18.8715359,20.7402457 L18.477138,21.8739324 C17.6419423,24.401109 18.1755395,27.0699965 19.9155304,28.8650005 C20.8435256,29.8569763 20.6347267,29.9986872 19.033935,29.4082253 C18.477138,29.2192775 17.9899405,29.0775667 17.9435407,29.1484221 C17.7811416,29.3137514 18.3379387,31.4630325 18.7787364,32.3132975 C19.3819332,33.4942212 20.6115268,34.6515264 21.9571198,35.3364621 L23.0939139,35.879687 L21.7483209,35.9033055 C20.4491277,35.9033055 20.4027279,35.9269239 20.5419272,36.4229119 C21.0059248,37.9581126 22.8387152,39.5877873 24.8803045,40.2963415 L26.318697,40.7923294 L25.0659036,41.5481205 C23.2099133,42.6345703 21.0291246,43.2486506 18.848336,43.2958876 C17.8043415,43.319506 16.9459459,43.4139799 16.9459459,43.4848353 C16.9459459,43.7210201 19.7763312,45.0436546 21.4235226,45.563261 C26.3650968,47.0984617 32.2346662,46.4371445 36.6426431,43.815494 C39.7746268,41.9496346 42.9066105,38.2415343 44.3682028,34.6515264 C45.1569987,32.7384301 45.9457946,29.242896 45.9457946,27.5659844 C45.9457946,26.4795347 46.0153942,26.3378238 47.3145874,25.0388078 C48.0801834,24.2830167 48.7993797,23.4563701 48.938579,23.2201854 C49.1705778,22.7714344 49.1473779,22.7714344 47.9641841,23.1729484 C45.9921943,23.8815026 45.7137958,23.7870287 46.6881907,22.7241974 C47.407387,21.9684063 48.2657825,20.5985348 48.2657825,20.1970208 C48.2657825,20.1261654 47.9177843,20.2442577 47.5233864,20.456824 C47.1057885,20.6930087 46.1777934,21.0472858 45.481797,21.2598521 L44.2290035,21.6613661 L43.0922095,20.8819565 C42.4658128,20.456824 41.5842174,19.9844545 41.1202198,19.8427437 C39.937026,19.5120851 38.1274354,19.559322 37.060241,19.9372176 C34.1602561,21.0000489 32.3274657,23.7397918 32.5362646,26.7393379 Z" id="Shape" fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.8 KiB |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="7" height="14" viewBox="0 0 7 14"><path fill="#788095" d="M.535.5L6.465 7l-5.93 6.5z"/></svg>
|
After Width: | Height: | Size: 140 B |
@ -0,0 +1,82 @@
|
||||
const existingHeaders = window.__env.headers;
|
||||
|
||||
const defaultHeader = [
|
||||
{
|
||||
key: 'Content-Type',
|
||||
value: 'application/json',
|
||||
isActive: true,
|
||||
isNewHeader: false,
|
||||
isDisabled: true,
|
||||
},
|
||||
];
|
||||
|
||||
if (existingHeaders) {
|
||||
Object.keys(existingHeaders).forEach((key) => {
|
||||
defaultHeader.push({
|
||||
key,
|
||||
value: existingHeaders[key],
|
||||
isActive: true,
|
||||
isNewHeader: false,
|
||||
})
|
||||
});
|
||||
}
|
||||
defaultHeader.push({
|
||||
key: '',
|
||||
value: '',
|
||||
isActive: false,
|
||||
isNewHeader: true,
|
||||
});
|
||||
|
||||
const getUrl = path => {
|
||||
return `${window.__env.graphqlEndpoint}`;
|
||||
};
|
||||
|
||||
const dataApisContent = [];
|
||||
// check project version
|
||||
dataApisContent.push({
|
||||
id: 'DataApi-3',
|
||||
details: {
|
||||
title: '',
|
||||
description:
|
||||
'Explore GraphQL APIs with headers',
|
||||
category: 'data',
|
||||
},
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: getUrl('/v1alpha1/graphql'),
|
||||
headers: defaultHeader,
|
||||
bodyType: 'graphql',
|
||||
params: JSON.stringify({}, null, 4),
|
||||
},
|
||||
});
|
||||
|
||||
const dataApis = {
|
||||
title: 'Data',
|
||||
content: dataApisContent,
|
||||
};
|
||||
|
||||
const explorerData = {
|
||||
sendingRequest: false,
|
||||
enableResponseSection: false,
|
||||
response: {},
|
||||
fileObj: null,
|
||||
};
|
||||
|
||||
const defaultApi = dataApis.content[0];
|
||||
|
||||
const defaultState = {
|
||||
currentTab: 0,
|
||||
displayedApi: defaultApi,
|
||||
modalState: {
|
||||
isOpen: false,
|
||||
isCopied: false,
|
||||
},
|
||||
explorerData,
|
||||
authApiExpanded: 'Username-password Login',
|
||||
headerFocus: false,
|
||||
graphqlEndpoint: ''
|
||||
};
|
||||
|
||||
export default defaultState;
|
||||
|
||||
export { defaultApi, defaultHeader };
|
After Width: | Height: | Size: 156 B |
@ -0,0 +1,12 @@
|
||||
const getHeadersAsJSON = headers => {
|
||||
const headerJSON = {};
|
||||
const nonEmptyHeaders = headers.filter(header => {
|
||||
return (header.key || header.value) && header.isActive;
|
||||
});
|
||||
nonEmptyHeaders.forEach(header => {
|
||||
headerJSON[header.key] = header.value;
|
||||
});
|
||||
return headerJSON;
|
||||
};
|
||||
|
||||
export { getHeadersAsJSON };
|
@ -0,0 +1,98 @@
|
||||
import defaultState from './State';
|
||||
|
||||
const LOAD_REQUEST = 'App/ONGOING_REQUEST';
|
||||
const DONE_REQUEST = 'App/DONE_REQUEST';
|
||||
const FAILED_REQUEST = 'App/FAILED_REQUEST';
|
||||
const ERROR_REQUEST = 'App/ERROR_REQUEST';
|
||||
const CONNECTION_FAILED = 'App/CONNECTION_FAILED';
|
||||
const CLOSE_MODAL = 'App/CLOSE_MODAL';
|
||||
const NOTIF_EXPANDED = 'App/NOTIF_EXPANDED';
|
||||
const NOTIF_MSG = 'App/NOTIF_MSG';
|
||||
|
||||
const notifExpand = isExpanded => ({ type: NOTIF_EXPANDED, data: isExpanded });
|
||||
const notifMsg = finalMsg => ({ type: NOTIF_MSG, data: finalMsg });
|
||||
|
||||
const progressBarReducer = (state = defaultState, action) => {
|
||||
switch (action.type) {
|
||||
case LOAD_REQUEST:
|
||||
return {
|
||||
...state,
|
||||
ongoingRequest: true,
|
||||
percent: 10,
|
||||
requestSuccess: null,
|
||||
requestError: null,
|
||||
connectionFailed: false,
|
||||
};
|
||||
|
||||
case DONE_REQUEST:
|
||||
return {
|
||||
...state,
|
||||
percent: 100,
|
||||
ongoingRequest: false,
|
||||
requestSuccess: true,
|
||||
requestError: null,
|
||||
connectionFailed: false,
|
||||
};
|
||||
|
||||
case FAILED_REQUEST:
|
||||
return {
|
||||
...state,
|
||||
percent: 100,
|
||||
ongoingRequest: false,
|
||||
requestSuccess: null,
|
||||
requestError: true,
|
||||
connectionFailed: false,
|
||||
};
|
||||
|
||||
case ERROR_REQUEST:
|
||||
return {
|
||||
...state,
|
||||
modalOpen: true,
|
||||
error: action.data,
|
||||
reqURL: action.url,
|
||||
reqData: action.params,
|
||||
statusCode: action.statusCode,
|
||||
connectionFailed: false,
|
||||
};
|
||||
case CONNECTION_FAILED:
|
||||
return {
|
||||
...state,
|
||||
modalOpen: true,
|
||||
error: true,
|
||||
connectionFailed: true,
|
||||
};
|
||||
|
||||
case CLOSE_MODAL:
|
||||
return {
|
||||
...state,
|
||||
modalOpen: false,
|
||||
};
|
||||
|
||||
case NOTIF_EXPANDED:
|
||||
return {
|
||||
...state,
|
||||
isNotifExpanded: action.data,
|
||||
};
|
||||
case NOTIF_MSG:
|
||||
return {
|
||||
...state,
|
||||
notifMsg: action.data,
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default progressBarReducer;
|
||||
export {
|
||||
LOAD_REQUEST,
|
||||
DONE_REQUEST,
|
||||
FAILED_REQUEST,
|
||||
ERROR_REQUEST,
|
||||
CLOSE_MODAL,
|
||||
CONNECTION_FAILED,
|
||||
NOTIF_EXPANDED,
|
||||
notifExpand,
|
||||
notifMsg,
|
||||
};
|
75
community/tools/graphiql-online/src/components/App/App.js
Normal file
@ -0,0 +1,75 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import ProgressBar from 'react-progress-bar-plus';
|
||||
import './progress-bar.scss';
|
||||
import { NOTIF_EXPANDED } from './Actions';
|
||||
import ErrorBoundary from './ErrorBoundary';
|
||||
|
||||
class App extends Component {
|
||||
componentDidMount() {
|
||||
// Hide the loader once the react component is ready.
|
||||
// NOTE: This will execute only onces (since this is parent component for all other component).
|
||||
const className = document.getElementById('content').className;
|
||||
document.getElementById('content').className = className + ' show';
|
||||
document.getElementById('loading').style.display = 'none';
|
||||
}
|
||||
|
||||
onModalClose = () => {
|
||||
this.props.dispatch({ type: NOTIF_EXPANDED, data: false });
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
ongoingRequest,
|
||||
percent,
|
||||
intervalTime,
|
||||
children,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<div>
|
||||
{ongoingRequest && (
|
||||
<ProgressBar
|
||||
percent={percent}
|
||||
autoIncrement={true} // eslint-disable-line react/jsx-boolean-value
|
||||
intervalTime={intervalTime}
|
||||
spinner={false}
|
||||
/>
|
||||
)}
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
App.propTypes = {
|
||||
reqURL: PropTypes.string,
|
||||
reqData: PropTypes.object,
|
||||
statusCode: PropTypes.number,
|
||||
|
||||
modalOpen: PropTypes.bool,
|
||||
error: PropTypes.object,
|
||||
ongoingRequest: PropTypes.bool,
|
||||
requestError: PropTypes.bool,
|
||||
connectionFailed: PropTypes.bool,
|
||||
|
||||
intervalTime: PropTypes.number,
|
||||
percent: PropTypes.number,
|
||||
|
||||
children: PropTypes.element,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
|
||||
isNotifExpanded: PropTypes.bool,
|
||||
notifMsg: PropTypes.string,
|
||||
};
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
...state.progressBar,
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(App);
|
@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class ErrorBoundary extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { hasError: false, info: null };
|
||||
}
|
||||
|
||||
componentDidCatch(error, info) {
|
||||
// Display fallback UI
|
||||
this.setState({ hasError: true, info: info });
|
||||
// You can also log the error to an error reporting service
|
||||
// logErrorToMyService(error, info);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
// You can render any custom fallback UI
|
||||
return <div>Something went wrong</div>;
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorBoundary.propTypes = {
|
||||
children: PropTypes.element,
|
||||
};
|
||||
|
||||
export default ErrorBoundary;
|
12
community/tools/graphiql-online/src/components/App/State.js
Normal file
@ -0,0 +1,12 @@
|
||||
const defaultState = {
|
||||
percent: 0,
|
||||
intervalTime: 200,
|
||||
ongoingRequest: false,
|
||||
requestSuccess: null,
|
||||
requestError: null,
|
||||
modalOpen: false,
|
||||
error: null,
|
||||
isNotifExpanded: false,
|
||||
notifMsg: null,
|
||||
};
|
||||
export default defaultState;
|
@ -0,0 +1,79 @@
|
||||
.alertDanger
|
||||
{
|
||||
position: sticky;
|
||||
position: -webkit-sticky;
|
||||
position: -moz-sticky;
|
||||
position: -o-sticky;
|
||||
position: -ms-sticky;
|
||||
top: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
.notifModalDialog {
|
||||
width: 800px;
|
||||
margin: 30px auto;
|
||||
right: 100px;
|
||||
top: -15px;
|
||||
}
|
||||
:global {
|
||||
@keyframes react-progress-spinner {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.react-progress-bar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: all 400ms;
|
||||
z-index: 9999;
|
||||
&.react-progress-bar-on-top {
|
||||
height: 100%;
|
||||
}
|
||||
&.react-progress-bar-hide {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
z-index: -10;
|
||||
}
|
||||
}
|
||||
|
||||
.react-progress-bar-percent {
|
||||
height: 2px;
|
||||
background: #e8694d;
|
||||
box-shadow: 0 2px 5px #d3291c, 0 2px 5px #d3291c;
|
||||
transition: all 200ms ease;
|
||||
}
|
||||
|
||||
.react-progress-bar-spinner {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 15px;
|
||||
}
|
||||
|
||||
.react-progress-bar-spinner-left {
|
||||
left: 15px;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
.react-progress-bar-spinner-right {
|
||||
left: auto;
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
.react-progress-bar-spinner-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
box-sizing: border-box;
|
||||
border: solid 2px transparent;
|
||||
border-top-color: #d3291c;
|
||||
border-left-color: #d3291c;
|
||||
border-radius: 50%;
|
||||
animation: react-progress-spinner 400ms linear infinite;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
class BreadCrumb extends Component {
|
||||
render() {
|
||||
const styles = require('./BreadCrumb.scss');
|
||||
return <div className={styles.breadcrumbWrapper}>{this.props.data}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
BreadCrumb.propTypes = {
|
||||
data: React.PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default BreadCrumb;
|
@ -0,0 +1,9 @@
|
||||
@import "../Common.scss";
|
||||
|
||||
.breadcrumbWrapper {
|
||||
padding: 20px 0px;
|
||||
padding-bottom: 0px;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: #767E93;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
@import "./Common.scss";
|
||||
button.control {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.subTopic {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.readyIcon {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.failIcon {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.eventContainer {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.logContainer {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
table td.longOne {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.endpoint {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.floatRight {
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
}
|
1018
community/tools/graphiql-online/src/components/Common/Common.scss
Normal file
@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
|
||||
const Spinner = () => {
|
||||
const styles = require('./Spinner.scss');
|
||||
|
||||
return (
|
||||
<div className={styles.sk_circle}>
|
||||
<div className={styles.sk_circle1 + ' ' + styles.sk_child} />
|
||||
<div className={styles.sk_circle2 + ' ' + styles.sk_child} />
|
||||
<div className={styles.sk_circle3 + ' ' + styles.sk_child} />
|
||||
<div className={styles.sk_circle4 + ' ' + styles.sk_child} />
|
||||
<div className={styles.sk_circle5 + ' ' + styles.sk_child} />
|
||||
<div className={styles.sk_circle6 + ' ' + styles.sk_child} />
|
||||
<div className={styles.sk_circle7 + ' ' + styles.sk_child} />
|
||||
<div className={styles.sk_circle8 + ' ' + styles.sk_child} />
|
||||
<div className={styles.sk_circle9 + ' ' + styles.sk_child} />
|
||||
<div className={styles.sk_circle10 + ' ' + styles.sk_child} />
|
||||
<div className={styles.sk_circle11 + ' ' + styles.sk_child} />
|
||||
<div className={styles.sk_circle12 + ' ' + styles.sk_child} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Spinner;
|
@ -0,0 +1,121 @@
|
||||
.sk_circle {
|
||||
margin: 100px auto;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
position: relative;
|
||||
}
|
||||
.sk_circle .sk_child {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.sk_circle .sk_child:before {
|
||||
content: '';
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
width: 15%;
|
||||
height: 15%;
|
||||
background-color: #333;
|
||||
border-radius: 100%;
|
||||
-webkit-animation: sk_circleBounceDelay 1.2s infinite ease-in-out both;
|
||||
animation: sk_circleBounceDelay 1.2s infinite ease-in-out both;
|
||||
}
|
||||
.sk_circle .sk_circle2 {
|
||||
-webkit-transform: rotate(30deg);
|
||||
-ms-transform: rotate(30deg);
|
||||
transform: rotate(30deg); }
|
||||
.sk_circle .sk_circle3 {
|
||||
-webkit-transform: rotate(60deg);
|
||||
-ms-transform: rotate(60deg);
|
||||
transform: rotate(60deg); }
|
||||
.sk_circle .sk_circle4 {
|
||||
-webkit-transform: rotate(90deg);
|
||||
-ms-transform: rotate(90deg);
|
||||
transform: rotate(90deg); }
|
||||
.sk_circle .sk_circle5 {
|
||||
-webkit-transform: rotate(120deg);
|
||||
-ms-transform: rotate(120deg);
|
||||
transform: rotate(120deg); }
|
||||
.sk_circle .sk_circle6 {
|
||||
-webkit-transform: rotate(150deg);
|
||||
-ms-transform: rotate(150deg);
|
||||
transform: rotate(150deg); }
|
||||
.sk_circle .sk_circle7 {
|
||||
-webkit-transform: rotate(180deg);
|
||||
-ms-transform: rotate(180deg);
|
||||
transform: rotate(180deg); }
|
||||
.sk_circle .sk_circle8 {
|
||||
-webkit-transform: rotate(210deg);
|
||||
-ms-transform: rotate(210deg);
|
||||
transform: rotate(210deg); }
|
||||
.sk_circle .sk_circle9 {
|
||||
-webkit-transform: rotate(240deg);
|
||||
-ms-transform: rotate(240deg);
|
||||
transform: rotate(240deg); }
|
||||
.sk_circle .sk_circle10 {
|
||||
-webkit-transform: rotate(270deg);
|
||||
-ms-transform: rotate(270deg);
|
||||
transform: rotate(270deg); }
|
||||
.sk_circle .sk_circle11 {
|
||||
-webkit-transform: rotate(300deg);
|
||||
-ms-transform: rotate(300deg);
|
||||
transform: rotate(300deg); }
|
||||
.sk_circle .sk_circle12 {
|
||||
-webkit-transform: rotate(330deg);
|
||||
-ms-transform: rotate(330deg);
|
||||
transform: rotate(330deg); }
|
||||
.sk_circle .sk_circle2:before {
|
||||
-webkit-animation-delay: -1.1s;
|
||||
animation-delay: -1.1s; }
|
||||
.sk_circle .sk_circle3:before {
|
||||
-webkit-animation-delay: -1s;
|
||||
animation-delay: -1s; }
|
||||
.sk_circle .sk_circle4:before {
|
||||
-webkit-animation-delay: -0.9s;
|
||||
animation-delay: -0.9s; }
|
||||
.sk_circle .sk_circle5:before {
|
||||
-webkit-animation-delay: -0.8s;
|
||||
animation-delay: -0.8s; }
|
||||
.sk_circle .sk_circle6:before {
|
||||
-webkit-animation-delay: -0.7s;
|
||||
animation-delay: -0.7s; }
|
||||
.sk_circle .sk_circle7:before {
|
||||
-webkit-animation-delay: -0.6s;
|
||||
animation-delay: -0.6s; }
|
||||
.sk_circle .sk_circle8:before {
|
||||
-webkit-animation-delay: -0.5s;
|
||||
animation-delay: -0.5s; }
|
||||
.sk_circle .sk_circle9:before {
|
||||
-webkit-animation-delay: -0.4s;
|
||||
animation-delay: -0.4s; }
|
||||
.sk_circle .sk_circle10:before {
|
||||
-webkit-animation-delay: -0.3s;
|
||||
animation-delay: -0.3s; }
|
||||
.sk_circle .sk_circle11:before {
|
||||
-webkit-animation-delay: -0.2s;
|
||||
animation-delay: -0.2s; }
|
||||
.sk_circle .sk_circle12:before {
|
||||
-webkit-animation-delay: -0.1s;
|
||||
animation-delay: -0.1s; }
|
||||
|
||||
@-webkit-keyframes sk_circleBounceDelay {
|
||||
0%, 80%, 100% {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
} 40% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sk_circleBounceDelay {
|
||||
0%, 80%, 100% {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
} 40% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
57
community/tools/graphiql-online/src/components/Login/App.css
Normal file
@ -0,0 +1,57 @@
|
||||
@import url('https://fonts.googleapis.com/css?family=Raleway:400,600');
|
||||
@import url('https://fonts.googleapis.com/css?family=Open+Sans:300,400');
|
||||
body
|
||||
{
|
||||
font-family: 'Open Sans';
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
}
|
||||
.login {
|
||||
text-align: center;
|
||||
}
|
||||
.loginTextbox {
|
||||
font-size: 16px;
|
||||
height: 43px;
|
||||
width: 74%;
|
||||
margin-right: 1%;
|
||||
font-weight: 300;
|
||||
border: 1px solid #ececec;
|
||||
border-radius: 5px;
|
||||
padding: 0;
|
||||
padding-left: 10px;
|
||||
display: inline-block;
|
||||
|
||||
}
|
||||
.loginButton {
|
||||
height: 45px;
|
||||
width: 10%;
|
||||
display: inline-block;
|
||||
border-radius: 5px;
|
||||
background-color: 'green' !important;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
margin-right: 1%;
|
||||
}
|
||||
.loginButton:hover
|
||||
{
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
.loginHeading {
|
||||
text-align: center;
|
||||
font-family: 'Raleway';
|
||||
margin-top: 0;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
.loginWrapper
|
||||
{
|
||||
width: 600px;
|
||||
padding: 30px;
|
||||
margin: 0 auto;
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
border: 1px solid #ececec;
|
||||
border-radius: 5px;
|
||||
background-color: #f6f6f6;
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import './App.css';
|
||||
import { updateGraphQLEndpoint } from '../ApiExplorer/Actions';
|
||||
|
||||
class LoginComponent extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = { graphqlEndpoint: '' };
|
||||
}
|
||||
setGraphQLEndpoint(e) {
|
||||
this.setState({ ...this.state, graphqlEndpoint: e.target.value });
|
||||
}
|
||||
render() {
|
||||
const { dispatch } = this.props;
|
||||
return (
|
||||
<div className="loginWrapper">
|
||||
<h2 className="loginHeading"> Online GraphiQL </h2>
|
||||
<div className="login">
|
||||
<div>
|
||||
<form>
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
className="loginTextbox"
|
||||
placeholder="Enter GraphQL Endpoint URL"
|
||||
onChange={this.setGraphQLEndpoint.bind(this)}
|
||||
/>
|
||||
<button
|
||||
className="loginButton"
|
||||
type="submit"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
const emailRegex = /^(http[s]?:\/\/){0,1}(www\.){0,1}[a-zA-Z0-9\.\-]+\.[a-zA-Z]{2,5}[\.]{0,1}/;
|
||||
if (!emailRegex.test(this.state.graphqlEndpoint)) {
|
||||
alert('Please enter a valid URL');
|
||||
} else {
|
||||
dispatch(updateGraphQLEndpoint(this.state.graphqlEndpoint));
|
||||
}
|
||||
}}
|
||||
>
|
||||
<i className={'fa fa-sign-in'} />
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LoginComponent.propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default LoginComponent;
|
@ -0,0 +1,12 @@
|
||||
import LoginComponent from './Login';
|
||||
|
||||
const generatedLoginComponent = connect => {
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
...state.apiexplorer,
|
||||
};
|
||||
};
|
||||
return connect(mapStateToProps)(LoginComponent);
|
||||
};
|
||||
|
||||
export default generatedLoginComponent;
|
6
community/tools/graphiql-online/src/components/index.js
Normal file
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Export component modules
|
||||
*/
|
||||
|
||||
export App from './App/App';
|
||||
export PageNotFound from './404/PageNotFound';
|
24
community/tools/graphiql-online/src/config.js
Normal file
@ -0,0 +1,24 @@
|
||||
/* @flow */
|
||||
const appConfig = require('../appconfig');
|
||||
|
||||
const host = appConfig.appHost;
|
||||
const port = appConfig.port[process.env.NODE_ENV || 'development'];
|
||||
|
||||
// require('babel-polyfill');
|
||||
|
||||
const environment = {
|
||||
development: {
|
||||
isProduction: false,
|
||||
},
|
||||
production: {
|
||||
isProduction: true,
|
||||
},
|
||||
}[process.env.NODE_ENV || 'development'];
|
||||
|
||||
module.exports = Object.assign(
|
||||
{
|
||||
host: host,
|
||||
port: port,
|
||||
},
|
||||
environment
|
||||
);
|
102
community/tools/graphiql-online/src/helpers/Html.js
Normal file
@ -0,0 +1,102 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Helmet from 'react-helmet';
|
||||
/**
|
||||
* Wrapper component containing HTML metadata and boilerplate tags.
|
||||
* Used in server-side code only to wrap the string output of the
|
||||
* rendered route component.
|
||||
*
|
||||
* The only thing this component doesn't (and can't) include is the
|
||||
* HTML doctype declaration, which is added to the rendered output
|
||||
* by the server.js file.
|
||||
*/
|
||||
export default class Html extends Component {
|
||||
static propTypes = {
|
||||
assets: PropTypes.object,
|
||||
component: PropTypes.node,
|
||||
baseDomain: PropTypes.string,
|
||||
};
|
||||
|
||||
render() {
|
||||
const { assets } = this.props;
|
||||
const head = Helmet.rewind();
|
||||
|
||||
return (
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<link rel="icon" type="image/png" href="/rstatic/favicon.png" />
|
||||
|
||||
{Object.keys(assets.styles).map((style, key) => (
|
||||
<link
|
||||
href={assets.styles[style]}
|
||||
key={key}
|
||||
media="screen, projection"
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
charSet="UTF-8"
|
||||
/>
|
||||
))}
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
||||
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
|
||||
crossOrigin="anonymous"
|
||||
/>
|
||||
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `window.__env={
|
||||
graphqlEndpoint: '${process.env.GRAPHQL_ENDPOINT}',
|
||||
query: '${process.env.QUERY_STRING}',
|
||||
headers: '${process.env.HEADER_STRING}',
|
||||
variables: '${process.env.VARIABLE_STRING}'
|
||||
};`,
|
||||
}}
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<style
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
.content {
|
||||
display: 'none';
|
||||
opacity: 0;
|
||||
transition: opacity .20s linear;
|
||||
}
|
||||
.content.show {
|
||||
display: 'block';
|
||||
opacity: 1;
|
||||
transition: opacity .20s linear;
|
||||
}
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
id="loading"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `<div class="page-loading" style="
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: sans-serif;
|
||||
justify-content: center;
|
||||
">
|
||||
<span class="" style="
|
||||
font-size: 2em;
|
||||
margin-top: -3em;
|
||||
color: #848484;
|
||||
">
|
||||
Loading...
|
||||
</span>
|
||||
</div>`,
|
||||
}}
|
||||
/>
|
||||
|
||||
<div id="content" className="content" />
|
||||
<script src={assets.javascript.main} charSet="UTF-8" />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Return the status code from the last matched route with a status property.
|
||||
*
|
||||
* @param matchedRoutes
|
||||
* @returns {Number|null}
|
||||
*/
|
||||
export default matchedRoutes => {
|
||||
return matchedRoutes.reduce((prev, cur) => cur.status || prev, null);
|
||||
};
|
@ -0,0 +1,43 @@
|
||||
import { createRoutes } from 'react-router/lib/RouteUtils';
|
||||
|
||||
// Wrap the hooks so they don't fire if they're called before
|
||||
// the store is initialised. This only happens when doing the first
|
||||
// client render of a route that has an onEnter hook
|
||||
function makeHooksSafe(routes, store) {
|
||||
if (Array.isArray(routes)) {
|
||||
return routes.map(route => makeHooksSafe(route, store));
|
||||
}
|
||||
|
||||
const onEnter = routes.onEnter;
|
||||
|
||||
if (onEnter) {
|
||||
routes.onEnter = function safeOnEnter(...args) {
|
||||
try {
|
||||
store.getState();
|
||||
} catch (err) {
|
||||
if (onEnter.length === 3) {
|
||||
args[2]();
|
||||
}
|
||||
|
||||
// There's no store yet so ignore the hook
|
||||
return;
|
||||
}
|
||||
|
||||
onEnter.apply(null, args);
|
||||
};
|
||||
}
|
||||
|
||||
if (routes.childRoutes) {
|
||||
makeHooksSafe(routes.childRoutes, store);
|
||||
}
|
||||
|
||||
if (routes.indexRoute) {
|
||||
makeHooksSafe(routes.indexRoute, store);
|
||||
}
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
export default function makeRouteHooksSafe(_getRoutes) {
|
||||
return store => makeHooksSafe(createRoutes(_getRoutes(store)), store);
|
||||
}
|
12
community/tools/graphiql-online/src/reducer.js
Normal file
@ -0,0 +1,12 @@
|
||||
import { combineReducers } from 'redux';
|
||||
import { routerReducer } from 'react-router-redux';
|
||||
import apiExplorerReducer from 'components/ApiExplorer/Actions';
|
||||
import progressBarReducer from 'components/App/Actions';
|
||||
|
||||
const reducer = combineReducers({
|
||||
progressBar: progressBarReducer,
|
||||
apiexplorer: apiExplorerReducer,
|
||||
routing: routerReducer,
|
||||
});
|
||||
|
||||
export default reducer;
|
22
community/tools/graphiql-online/src/routes.js
Normal file
@ -0,0 +1,22 @@
|
||||
import React from 'react';
|
||||
import { Route, IndexRoute } from 'react-router';
|
||||
import { connect } from 'react-redux';
|
||||
import { App, PageNotFound } from 'components';
|
||||
import generatedApiExplorer from './components/ApiExplorer/ApiExplorerGenerator';
|
||||
import generatedLoginComponent from './components/Login/LoginGenerator';
|
||||
|
||||
const routes = () => {
|
||||
// loads schema
|
||||
return (
|
||||
<Route path="/" component={App}>
|
||||
<Route path="">
|
||||
<IndexRoute component={generatedLoginComponent(connect)} />
|
||||
</Route>
|
||||
<Route path="/graphiql" component={generatedApiExplorer(connect)} />
|
||||
<Route path="404" component={PageNotFound} status="404" />
|
||||
<Route path="*" component={PageNotFound} status="404" />
|
||||
</Route>
|
||||
);
|
||||
};
|
||||
|
||||
export default routes;
|
59
community/tools/graphiql-online/src/server.js
Executable file
@ -0,0 +1,59 @@
|
||||
import Express from 'express';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/server';
|
||||
import config from './config';
|
||||
// import favicon from 'serve-favicon';
|
||||
import path from 'path';
|
||||
import Html from './helpers/Html';
|
||||
import http from 'http';
|
||||
|
||||
global.__DISABLE_SSR__ = true;
|
||||
|
||||
// Express middleware
|
||||
const app = new Express();
|
||||
const server = new http.Server(app);
|
||||
|
||||
/* Constants */
|
||||
/* Routes and middleware */
|
||||
// app.use(favicon(path.join(__dirname, '..', 'static', 'favicon.ico')));
|
||||
app.use('/rstatic', Express.static(path.join(__dirname, '..', 'static')));
|
||||
|
||||
app.use((req, res) => {
|
||||
if (__DEVELOPMENT__) {
|
||||
// Do not cache webpack stats: the script file would change since
|
||||
// hot module replacement is enabled in the development env
|
||||
webpackIsomorphicTools.refresh();
|
||||
}
|
||||
|
||||
// Initialize the store here
|
||||
function hydrateOnClient() {
|
||||
res.send(
|
||||
'<!doctype html>\n' +
|
||||
ReactDOM.renderToString(
|
||||
<Html assets={webpackIsomorphicTools.assets()} />
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (__DISABLE_SSR__) {
|
||||
hydrateOnClient();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (config.port) {
|
||||
server.listen(config.port, config.host, err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
console.info(
|
||||
'==> 💻 Open http://%s:%s in a browser to view the app.',
|
||||
config.host,
|
||||
config.port
|
||||
);
|
||||
});
|
||||
} else {
|
||||
console.error(
|
||||
'==> ERROR: No PORT environment variable has been specified'
|
||||
);
|
||||
}
|
71
community/tools/graphiql-online/src/theme/bootstrap.config.js
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Bootstrap configuration for bootstrap-sass-loader
|
||||
*
|
||||
* Scripts are disabled to not load jQuery.
|
||||
* If you depend on Bootstrap scripts consider react-bootstrap instead.
|
||||
* https://github.com/react-bootstrap/react-bootstrap
|
||||
*
|
||||
* In order to keep the bundle size low in production
|
||||
* disable components you don't use.
|
||||
*
|
||||
*/
|
||||
module.exports = {
|
||||
preBootstrapCustomizations: './src/theme/variables.scss',
|
||||
mainSass: './src/theme/bootstrap.overrides.scss',
|
||||
verbose: false,
|
||||
debug: false,
|
||||
scripts: {
|
||||
transition: false,
|
||||
alert: false,
|
||||
button: true,
|
||||
carousel: false,
|
||||
collapse: false,
|
||||
dropdown: true,
|
||||
modal: true,
|
||||
tooltip: false,
|
||||
popover: false,
|
||||
scrollspy: false,
|
||||
tab: false,
|
||||
affix: false,
|
||||
},
|
||||
styles: {
|
||||
mixins: true,
|
||||
normalize: true,
|
||||
print: true,
|
||||
glyphicons: true,
|
||||
scaffolding: true,
|
||||
type: true,
|
||||
code: true,
|
||||
grid: true,
|
||||
tables: true,
|
||||
forms: true,
|
||||
buttons: true,
|
||||
'component-animations': true,
|
||||
dropdowns: true,
|
||||
'button-groups': true,
|
||||
'input-groups': true,
|
||||
navs: true,
|
||||
navbar: true,
|
||||
breadcrumbs: true,
|
||||
pagination: true,
|
||||
pager: true,
|
||||
labels: true,
|
||||
badges: true,
|
||||
jumbotron: true,
|
||||
thumbnails: true,
|
||||
alerts: true,
|
||||
'progress-bars': true,
|
||||
media: true,
|
||||
'list-group': true,
|
||||
panels: true,
|
||||
wells: true,
|
||||
'responsive-embed': true,
|
||||
close: true,
|
||||
modals: true,
|
||||
tooltip: true,
|
||||
popovers: true,
|
||||
carousel: false,
|
||||
utilities: true,
|
||||
'responsive-utilities': true,
|
||||
},
|
||||
};
|
8
community/tools/graphiql-online/src/theme/bootstrap.config.prod.js
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
const bootstrapConfig = require('./bootstrap.config.js');
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||
|
||||
bootstrapConfig.styleLoaders = ExtractTextPlugin.extract({
|
||||
fallback: 'style-loader',
|
||||
use: ['css-loader', 'sass-loader'],
|
||||
});
|
||||
module.exports = bootstrapConfig;
|
198
community/tools/graphiql-online/src/theme/bootstrap.overrides.scss
vendored
Normal file
@ -0,0 +1,198 @@
|
||||
/**
|
||||
* Override Bootstrap styles that you can't modify via variables here.
|
||||
*
|
||||
*/
|
||||
input[type="radio"], input[type="checkbox"]
|
||||
{
|
||||
margin: 0 5px 0px 0px;
|
||||
}
|
||||
label
|
||||
{
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.navbar-brand {
|
||||
position: relative;
|
||||
padding-left: 50px;
|
||||
}
|
||||
|
||||
.graphiql-container .topBar {
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-nav > .active > a,
|
||||
.navbar-default .navbar-nav > .active > a:hover,
|
||||
.navbar-default .navbar-nav > .active > a:focus {
|
||||
color: #33e0ff;
|
||||
background-color: transparent;
|
||||
}
|
||||
.control-label
|
||||
{
|
||||
padding-top: 0;
|
||||
}
|
||||
form {
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
.form-control:focus {
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0px rgba(102, 175, 233, 0.6);
|
||||
}
|
||||
|
||||
.form-control {
|
||||
// border-radius: 0;
|
||||
height: auto;
|
||||
}
|
||||
select.form-control
|
||||
{
|
||||
border-radius: 0;
|
||||
-webkit-border-radius: 0px;
|
||||
}
|
||||
.btn {
|
||||
// border-radius: 0;
|
||||
outline: none;
|
||||
}
|
||||
.btn:active, .btn.active
|
||||
{
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.btn:focus, .btn.focus, .btn:active:focus, .btn:active.focus, .btn.active:focus, .btn.active.focus
|
||||
{
|
||||
outline: none !important;
|
||||
}
|
||||
.btn:focus
|
||||
{
|
||||
outline: none !important;
|
||||
}
|
||||
.alert {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.btn-warning {
|
||||
background-color: #FEC53D !important;
|
||||
border-color: #FEC53D !important;
|
||||
color: #000 !important;
|
||||
padding: 5px 10px !important;
|
||||
font-size: 12px !important;
|
||||
line-height: 1.5 !important;
|
||||
}
|
||||
.btn-warning:hover {
|
||||
color: #000;
|
||||
background-color: #ec971f;
|
||||
border-color: #d58512;
|
||||
}
|
||||
// Generate Code modal
|
||||
.padd_remove
|
||||
{
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
.generateCodeWrapper
|
||||
{
|
||||
width: 65% !important;
|
||||
.modal-content
|
||||
{
|
||||
.modal-header
|
||||
{
|
||||
background-color: #F8FAFB;
|
||||
color: #222 ;
|
||||
padding: 20px;
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom: 0;
|
||||
border-bottom: 1px solid #ccc;
|
||||
h4
|
||||
{
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
button
|
||||
{
|
||||
text-shadow: none;
|
||||
color: #C4C6C6;
|
||||
opacity: 1;
|
||||
span
|
||||
{
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
.modal-body
|
||||
{
|
||||
padding: 25px;
|
||||
.generateBodyWrapper
|
||||
{
|
||||
.generateButtonWrapper
|
||||
{
|
||||
width: 100%;
|
||||
float: left;
|
||||
padding-bottom: 20px;
|
||||
.generateSelect
|
||||
{
|
||||
button
|
||||
{
|
||||
width: auto;
|
||||
padding: 10px 35px;
|
||||
padding-left: 10px;
|
||||
background-color: #F9F9F9;
|
||||
color: #606060;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
border: 1px solid #ccc;
|
||||
position: relative;
|
||||
.dropCaret
|
||||
{
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.generateCopyButton
|
||||
{
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
button {
|
||||
background-color: #FEC53D;
|
||||
border-radius: 5px;
|
||||
color: #606060;
|
||||
border: 1px solid #FEC53D;
|
||||
padding: 5px 10px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
&:hover {
|
||||
background-color: #F2B130;
|
||||
}
|
||||
}
|
||||
}
|
||||
.generateCopyButtonDisabled
|
||||
{
|
||||
text-align: right;
|
||||
button
|
||||
{
|
||||
border-radius: 5px;
|
||||
border: 1px solid #606060;
|
||||
height: 39px;
|
||||
padding: 5px 15px;
|
||||
font-size: 15px;
|
||||
background-color: #FFF;
|
||||
text-align: center;
|
||||
color: #606060;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.ace_editor
|
||||
{
|
||||
min-height: 150px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.ace-github
|
||||
{
|
||||
min-height: 150px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Configuration file for font-awesome-webpack
|
||||
*
|
||||
* In order to keep the bundle size low in production,
|
||||
* disable components you don't use.
|
||||
*
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
styles: {
|
||||
mixins: true,
|
||||
core: true,
|
||||
icons: true,
|
||||
larger: true,
|
||||
path: true,
|
||||
animated: true,
|
||||
},
|
||||
};
|
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Configuration file for font-awesome-webpack
|
||||
*
|
||||
*/
|
||||
|
||||
// Example:
|
||||
// @fa-border-color: #ddd;
|
@ -0,0 +1,8 @@
|
||||
const fontAwesomeConfig = require('./font-awesome.config.js');
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||
|
||||
fontAwesomeConfig.styleLoader = ExtractTextPlugin.extract({
|
||||
fallback: 'style-loader',
|
||||
use: 'css-loader!less-loader',
|
||||
});
|
||||
module.exports = fontAwesomeConfig;
|
27
community/tools/graphiql-online/src/theme/variables.scss
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Define scss variables here.
|
||||
*
|
||||
* Available options for Bootstrap:
|
||||
* http://getbootstrap.com/customize/
|
||||
*
|
||||
*/
|
||||
|
||||
// Custom Colors
|
||||
$cyan: #33e0ff;
|
||||
$humility: #777;
|
||||
|
||||
// Bootstrap Variables
|
||||
$brand-primary: darken(#428bca, 6.5%);
|
||||
$brand-secondary: #e25139;
|
||||
$brand-success: #5cb85c;
|
||||
$brand-warning: #f0ad4e;
|
||||
$brand-danger: #d9534f;
|
||||
$brand-info: #5bc0de;
|
||||
|
||||
$text-color: #333;
|
||||
|
||||
$font-size-base: 14px;
|
||||
$font-family-sans-serif: "Helvetica Neue", Helvetica, sans-serif;
|
||||
|
||||
$table-bg-hover: #EBF7DE !default;
|
||||
$table-bg-active: $table-bg-hover !default;
|
BIN
community/tools/graphiql-online/static/favicon.ico
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
community/tools/graphiql-online/static/favicon.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
53
community/tools/graphiql-online/static/index.html
Normal file
@ -0,0 +1,53 @@
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<link rel="icon" type="image/png" href="./favicon.png" />
|
||||
<script>
|
||||
window.__env = {
|
||||
graphqlEndpoint: '',
|
||||
headers: '',
|
||||
variables: '',
|
||||
query: ''
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<style>
|
||||
.mainContent {
|
||||
display: 'none';
|
||||
opacity: 0;
|
||||
transition: opacity .20s linear;
|
||||
}
|
||||
.mainContent.show {
|
||||
display: 'block';
|
||||
opacity: 1;
|
||||
transition: opacity .20s linear;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="loading">
|
||||
<div class="page-loading" style="
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: sans-serif;
|
||||
justify-content: center;
|
||||
">
|
||||
<span class="" style="
|
||||
font-size: 2em;
|
||||
margin-top: -3em;
|
||||
color: #848484;
|
||||
">
|
||||
Loading...
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content" class="mainContent"></div>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"/>
|
||||
|
||||
<link rel="stylesheet" href="/dist/main.css" charset="UTF-8"/>
|
||||
<script src="/dist/vendor.js" charset="UTF-8"></script>
|
||||
<script src="/dist/main.js" charset="UTF-8"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
BIN
community/tools/graphiql-online/static/logo.jpg
Normal file
After Width: | Height: | Size: 6.7 KiB |
116
community/tools/graphiql-online/webpack/bs3.yml
Normal file
@ -0,0 +1,116 @@
|
||||
---
|
||||
# Output debugging info
|
||||
# loglevel: debug
|
||||
|
||||
# Major version of Bootstrap: 3 or 4
|
||||
bootstrapVersion: 3
|
||||
|
||||
# If Bootstrap version 3 is used - turn on/off custom icon font path
|
||||
useCustomIconFontPath: false
|
||||
|
||||
# Webpack loaders, order matters
|
||||
styleLoaders:
|
||||
- style-loader
|
||||
- css-loader
|
||||
- sass-loader
|
||||
|
||||
# Extract styles to stand-alone css file
|
||||
# Different settings for different environments can be used,
|
||||
# It depends on value of NODE_ENV environment variable
|
||||
# This param can also be set in webpack config:
|
||||
# entry: 'bootstrap-loader/extractStyles'
|
||||
extractStyles: true
|
||||
# env:
|
||||
# development:
|
||||
# extractStyles: false
|
||||
# production:
|
||||
# extractStyles: true
|
||||
|
||||
# Customize Bootstrap variables that get imported before the original Bootstrap variables.
|
||||
# Thus original Bootstrap variables can depend on values from here. All the bootstrap
|
||||
# variables are configured with !default, and thus, if you define the variable here, then
|
||||
# that value is used, rather than the default. However, many bootstrap variables are derived
|
||||
# from other bootstrap variables, and thus, you want to set this up before we load the
|
||||
# official bootstrap versions.
|
||||
# For example, _variables.scss contains:
|
||||
# $input-color: $gray !default;
|
||||
# This means you can define $input-color before we load _variables.scss
|
||||
|
||||
#preBootstrapCustomizations: ./src/theme/variables.scss
|
||||
|
||||
# This gets loaded after bootstrap/variables is loaded and before bootstrap is loaded.
|
||||
# A good example of this is when you want to override a bootstrap variable to be based
|
||||
# on the default value of bootstrap. This is pretty specialized case. Thus, you normally
|
||||
# just override bootrap variables in preBootstrapCustomizations so that derived
|
||||
# variables will use your definition.
|
||||
#
|
||||
# For example, in _variables.scss:
|
||||
# $input-height: (($font-size-base * $line-height) + ($input-padding-y * 2) + ($border-width * 2)) !default;
|
||||
# This means that you could define this yourself in preBootstrapCustomizations. Or you can do
|
||||
# this in bootstrapCustomizations to make the input height 10% bigger than the default calculation.
|
||||
# Thus you can leverage the default calculations.
|
||||
# $input-height: $input-height * 1.10;
|
||||
|
||||
# bootstrapCustomizations: ./app/styles/bootstrap/customizations.scss
|
||||
|
||||
# Import your custom styles here. You have access to all the bootstrap variables. If you require
|
||||
# your sass files separately, you will not have access to the bootstrap variables, mixins, clases, etc.
|
||||
# Usually this endpoint-file contains list of @imports of your application styles.
|
||||
|
||||
#appStyles: ./src/theme/bootstrap.overrides.scss
|
||||
|
||||
### Bootstrap styles
|
||||
styles:
|
||||
|
||||
# Mixins
|
||||
mixins: true
|
||||
|
||||
# Reset and dependencies
|
||||
normalize: true
|
||||
print: true
|
||||
glyphicons: true
|
||||
|
||||
# Core CSS
|
||||
scaffolding: true
|
||||
type: true
|
||||
code: true
|
||||
grid: true
|
||||
tables: true
|
||||
forms: true
|
||||
buttons: true
|
||||
|
||||
# Components
|
||||
component-animations: true
|
||||
dropdowns: true
|
||||
button-groups: true
|
||||
input-groups: true
|
||||
navs: true
|
||||
navbar: true
|
||||
breadcrumbs: true
|
||||
pagination: true
|
||||
pager: true
|
||||
labels: true
|
||||
badges: true
|
||||
jumbotron: true
|
||||
thumbnails: true
|
||||
alerts: true
|
||||
progress-bars: true
|
||||
media: true
|
||||
list-group: true
|
||||
panels: true
|
||||
wells: true
|
||||
responsive-embed: true
|
||||
close: true
|
||||
|
||||
# Components w/ JavaScript
|
||||
modals: true
|
||||
tooltip: true
|
||||
popovers: true
|
||||
carousel: true
|
||||
|
||||
# Utility classes
|
||||
utilities: true
|
||||
responsive-utilities: true
|
||||
|
||||
### Bootstrap scripts
|
||||
scripts: false
|
186
community/tools/graphiql-online/webpack/dev.config.js
Executable file
@ -0,0 +1,186 @@
|
||||
// require('babel-polyfill');
|
||||
|
||||
// Webpack config for development
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const assetsPath = path.resolve(__dirname, '../static/dist');
|
||||
const appconfig = require('../appconfig');
|
||||
const host = appconfig.hmrHost;
|
||||
const port = appconfig.hmrPort;
|
||||
|
||||
const autoprefixer = require('autoprefixer');
|
||||
|
||||
const WebpackIsomorphicToolsPlugin = require('webpack-isomorphic-tools/plugin');
|
||||
const webpackIsomorphicToolsPlugin = new WebpackIsomorphicToolsPlugin(
|
||||
require('./webpack-isomorphic-tools')
|
||||
);
|
||||
|
||||
// const { UnusedFilesWebpackPlugin } = require('unused-files-webpack-plugin');
|
||||
|
||||
const babelrc = fs.readFileSync('./.babelrc');
|
||||
let babelrcObject = {};
|
||||
|
||||
try {
|
||||
babelrcObject = JSON.parse(babelrc);
|
||||
} catch (err) {
|
||||
console.error('==> ERROR: Error parsing your .babelrc.');
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
const babelrcObjectDevelopment =
|
||||
(babelrcObject.env && babelrcObject.env.development) || {};
|
||||
const babelLoaderQuery = Object.assign(
|
||||
{},
|
||||
babelrcObject,
|
||||
babelrcObjectDevelopment
|
||||
);
|
||||
delete babelLoaderQuery.env;
|
||||
|
||||
babelLoaderQuery.plugins = babelLoaderQuery.plugins || [];
|
||||
if (babelLoaderQuery.plugins.indexOf('react-transform') < 0) {
|
||||
babelLoaderQuery.plugins.push('react-transform');
|
||||
}
|
||||
|
||||
babelLoaderQuery.extra = babelLoaderQuery.extra || {};
|
||||
if (!babelLoaderQuery.extra['react-transform']) {
|
||||
babelLoaderQuery.extra['react-transform'] = {};
|
||||
}
|
||||
if (!babelLoaderQuery.extra['react-transform'].transforms) {
|
||||
babelLoaderQuery.extra['react-transform'].transforms = [];
|
||||
}
|
||||
babelLoaderQuery.extra['react-transform'].transforms.push({
|
||||
transform: 'react-transform-hmr',
|
||||
imports: ['react'],
|
||||
locals: ['module'],
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
mode: 'development',
|
||||
devtool: 'inline-source-map',
|
||||
context: path.resolve(__dirname, '..'),
|
||||
entry: {
|
||||
main: [
|
||||
'webpack-hot-middleware/client?path=http://' +
|
||||
host +
|
||||
':' +
|
||||
port +
|
||||
'/__webpack_hmr',
|
||||
'bootstrap-loader?extractStyles',
|
||||
'font-awesome-webpack!./src/theme/font-awesome.config.js',
|
||||
'./src/client.js',
|
||||
],
|
||||
},
|
||||
output: {
|
||||
path: assetsPath,
|
||||
filename: '[name]-[hash].js',
|
||||
chunkFilename: '[name]-[chunkhash].js',
|
||||
publicPath: 'http://' + host + ':' + port + appconfig.webpackPrefix,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.mjs$/,
|
||||
include: /node_modules/,
|
||||
type: 'javascript/auto',
|
||||
},
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
exclude: /node_modules/,
|
||||
use: 'babel-loader',
|
||||
},
|
||||
{
|
||||
test: /\.flow$/,
|
||||
loader: 'ignore-loader',
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
importLoaders: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
'css-loader?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]',
|
||||
'sass-loader?outputStyle=expanded&sourceMap',
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: { limit: 10000, mimetype: 'application/font-woff' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: { limit: 10000, mimetype: 'application/font-woff' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: { limit: 10000, mimetype: 'application/octet-stream' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: [{ loader: 'file-loader' }],
|
||||
},
|
||||
{
|
||||
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: { limit: 10000, mimetype: 'image/svg+xml' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: webpackIsomorphicToolsPlugin.regular_expression('images'),
|
||||
use: [{ loader: 'url-loader', options: { limit: 10240 } }],
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
modules: ['src', 'node_modules'],
|
||||
extensions: ['.json', '.js', '.jsx', '.mjs'],
|
||||
},
|
||||
plugins: [
|
||||
// hot reload
|
||||
// new UnusedFilesWebpackPlugin({}),
|
||||
new webpack.ProvidePlugin({
|
||||
$: 'jquery',
|
||||
jQuery: 'jquery',
|
||||
}),
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
postcss: [autoprefixer],
|
||||
}),
|
||||
new webpack.IgnorePlugin(/webpack-stats\.json$/),
|
||||
new webpack.DefinePlugin({
|
||||
__CLIENT__: true,
|
||||
__SERVER__: false,
|
||||
__DEVELOPMENT__: true,
|
||||
__DEVTOOLS__: true, // <-------- DISABLE redux-devtools HERE
|
||||
}),
|
||||
webpackIsomorphicToolsPlugin.development(),
|
||||
],
|
||||
};
|
192
community/tools/graphiql-online/webpack/prod.config.js
Executable file
@ -0,0 +1,192 @@
|
||||
// Webpack config for creating the production bundle.
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const CleanPlugin = require('clean-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const appconfig = require('../appconfig');
|
||||
|
||||
const relativeAssetsPath = '../static/dist';
|
||||
const assetsPath = path.join(__dirname, relativeAssetsPath);
|
||||
|
||||
const WebpackIsomorphicToolsPlugin = require('webpack-isomorphic-tools/plugin');
|
||||
const webpackIsomorphicToolsPlugin = new WebpackIsomorphicToolsPlugin(
|
||||
require('./webpack-isomorphic-tools')
|
||||
);
|
||||
|
||||
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
|
||||
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||
|
||||
const cleanOptions = {
|
||||
root: process.cwd(),
|
||||
verbose: true,
|
||||
dry: false,
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
mode: 'production',
|
||||
context: path.resolve(__dirname, '..'),
|
||||
entry: {
|
||||
main: ['bootstrap-loader?extractStyles', './src/client.js'],
|
||||
},
|
||||
output: {
|
||||
path: assetsPath,
|
||||
filename: '[name].js',
|
||||
chunkFilename: '[name].js',
|
||||
publicPath: appconfig.webpackPrefix,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.mjs$/,
|
||||
include: /node_modules/,
|
||||
type: 'javascript/auto',
|
||||
},
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
exclude: /node_modules/,
|
||||
use: 'babel-loader',
|
||||
},
|
||||
{
|
||||
test: /\.flow$/,
|
||||
loader: 'ignore-loader',
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
importLoaders: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
'css-loader?modules&importLoaders=2&sourceMap=false',
|
||||
'sass-loader?outputStyle=expanded&sourceMap=false&sourceMapContents=false',
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: { limit: 10000, mimetype: 'application/font-woff' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: { limit: 10000, mimetype: 'application/font-woff' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: { limit: 10000, mimetype: 'application/octet-stream' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: [{ loader: 'file-loader' }],
|
||||
},
|
||||
{
|
||||
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: { limit: 10000, mimetype: 'image/svg+xml' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: webpackIsomorphicToolsPlugin.regular_expression('images'),
|
||||
use: [{ loader: 'url-loader', options: { limit: 10240 } }],
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
modules: ['src', 'node_modules'],
|
||||
extensions: ['.json', '.js', '.jsx', '.mjs'],
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
runtimeChunk: {
|
||||
name: 'vendor',
|
||||
},
|
||||
minimizer: [
|
||||
new UglifyJSPlugin({
|
||||
uglifyOptions: {
|
||||
ecma: 8,
|
||||
warnings: false,
|
||||
compress: false,
|
||||
mangle: true,
|
||||
output: {
|
||||
comments: false,
|
||||
beautify: false,
|
||||
},
|
||||
toplevel: false,
|
||||
nameCache: null,
|
||||
ie8: false,
|
||||
keep_classnames: undefined,
|
||||
keep_fnames: false,
|
||||
safari10: false,
|
||||
},
|
||||
}),
|
||||
new OptimizeCssAssetsPlugin({
|
||||
assetNameRegExp: /\.css$/,
|
||||
}),
|
||||
],
|
||||
splitChunks: {
|
||||
cacheGroups: {
|
||||
commons: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: 'vendor',
|
||||
chunks: 'initial',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
new CleanPlugin(['./static/dist/*.*'], cleanOptions),
|
||||
|
||||
new webpack.ProvidePlugin({
|
||||
$: 'jquery',
|
||||
jQuery: 'jquery',
|
||||
}),
|
||||
new MiniCssExtractPlugin({
|
||||
// Options similar to the same options in webpackOptions.output
|
||||
// both options are optional
|
||||
filename: 'main.css',
|
||||
chunkFilename: 'main.css',
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
__CLIENT__: true,
|
||||
__SERVER__: false,
|
||||
__DEVELOPMENT__: false,
|
||||
__DEVTOOLS__: false,
|
||||
}),
|
||||
|
||||
// ignore dev config
|
||||
new webpack.IgnorePlugin(/\.\/dev/, /\/config$/),
|
||||
|
||||
// set global consts
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
// Useful to reduce the size of client-side libraries, e.g. react
|
||||
NODE_ENV: JSON.stringify('production'),
|
||||
},
|
||||
}),
|
||||
],
|
||||
};
|
36
community/tools/graphiql-online/webpack/webpack-dev-server.js
Executable file
@ -0,0 +1,36 @@
|
||||
const Express = require('express');
|
||||
const webpack = require('webpack');
|
||||
|
||||
const webpackConfig = require('./dev.config');
|
||||
const compiler = webpack(webpackConfig);
|
||||
const appconfig = require('../appconfig');
|
||||
|
||||
const host = appconfig.hmrHost;
|
||||
const port = appconfig.hmrPort;
|
||||
|
||||
const serverOptions = {
|
||||
contentBase: 'http://' + host + ':' + port,
|
||||
logLevel: 'silent',
|
||||
hot: true,
|
||||
inline: true,
|
||||
lazy: false,
|
||||
publicPath: webpackConfig.output.publicPath,
|
||||
headers: { 'Access-Control-Allow-Origin': '*' },
|
||||
stats: { colors: true },
|
||||
};
|
||||
|
||||
const app = new Express();
|
||||
|
||||
app.use(require('webpack-dev-middleware')(compiler, serverOptions));
|
||||
app.use(require('webpack-hot-middleware')(compiler));
|
||||
|
||||
app.listen(port, function onAppListening(err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
} else {
|
||||
console.info(
|
||||
'==> 🚧 Webpack development server listening on port %s',
|
||||
port
|
||||
);
|
||||
}
|
||||
});
|
@ -0,0 +1,101 @@
|
||||
var WebpackIsomorphicToolsPlugin = require('webpack-isomorphic-tools/plugin');
|
||||
|
||||
// see this link for more info on what all of this means
|
||||
// https://github.com/halt-hammerzeit/webpack-isomorphic-tools
|
||||
module.exports = {
|
||||
// when adding "js" extension to asset types
|
||||
// and then enabling debug mode, it may cause a weird error:
|
||||
//
|
||||
// [0] npm run start-prod exited with code 1
|
||||
// Sending SIGTERM to other processes..
|
||||
//
|
||||
// debug: true,
|
||||
|
||||
assets: {
|
||||
images: {
|
||||
extensions: ['jpeg', 'jpg', 'png', 'gif'],
|
||||
parser: WebpackIsomorphicToolsPlugin.url_loader_parser,
|
||||
},
|
||||
fonts: {
|
||||
extensions: ['woff', 'woff2', 'ttf', 'eot'],
|
||||
parser: WebpackIsomorphicToolsPlugin.url_loader_parser,
|
||||
},
|
||||
svg: {
|
||||
extension: 'svg',
|
||||
parser: WebpackIsomorphicToolsPlugin.url_loader_parser,
|
||||
},
|
||||
// this whole "bootstrap" asset type is only used once in development mode.
|
||||
// the only place it's used is the Html.js file
|
||||
// where a <style/> tag is created with the contents of the
|
||||
// './src/theme/bootstrap.config.js' file.
|
||||
// (the aforementioned <style/> tag can reduce the white flash
|
||||
// when refreshing page in development mode)
|
||||
//
|
||||
// hooking into 'js' extension require()s isn't the best solution
|
||||
// and I'm leaving this comment here in case anyone finds a better idea.
|
||||
//bootstrap: {
|
||||
// extension: 'js',
|
||||
// include: ['./src/theme/bootstrap.config.js'],
|
||||
// filter: function(module, regex, options, log) {
|
||||
// function is_bootstrap_style(name) {
|
||||
// return name.indexOf('./src/theme/bootstrap.config.js') >= 0;
|
||||
// }
|
||||
// if (options.development) {
|
||||
// return is_bootstrap_style(module.name) && WebpackIsomorphicToolsPlugin.style_loader_filter(module, regex, options, log);
|
||||
// }
|
||||
// // no need for it in production mode
|
||||
// },
|
||||
// // in development mode there's webpack "style-loader",
|
||||
// // so the module.name is not equal to module.name
|
||||
// path: WebpackIsomorphicToolsPlugin.style_loader_path_extractor,
|
||||
// parser: WebpackIsomorphicToolsPlugin.css_loader_parser
|
||||
//},
|
||||
|
||||
style_modules: {
|
||||
extensions: ['scss'],
|
||||
filter: (module, regex, options, log) => {
|
||||
if (options.development) {
|
||||
// in development mode there's webpack "style-loader",
|
||||
// so the module.name is not equal to module.name
|
||||
return WebpackIsomorphicToolsPlugin.style_loader_filter(
|
||||
module,
|
||||
regex,
|
||||
options,
|
||||
log
|
||||
);
|
||||
} else {
|
||||
// in production mode there's no webpack "style-loader",
|
||||
// so the module.name will be equal to the asset path
|
||||
return regex.test(module.name);
|
||||
}
|
||||
},
|
||||
path: (module, options, log) => {
|
||||
if (options.development) {
|
||||
// in development mode there's webpack "style-loader",
|
||||
// so the module.name is not equal to module.name
|
||||
return WebpackIsomorphicToolsPlugin.style_loader_path_extractor(
|
||||
module,
|
||||
options,
|
||||
log
|
||||
);
|
||||
} else {
|
||||
// in production mode there's no webpack "style-loader",
|
||||
// so the module.name will be equal to the asset path
|
||||
return module.name;
|
||||
}
|
||||
},
|
||||
parser: (module, options, log) => {
|
||||
if (options.development) {
|
||||
return WebpackIsomorphicToolsPlugin.css_modules_loader_parser(
|
||||
module,
|
||||
options,
|
||||
log
|
||||
);
|
||||
} else {
|
||||
// in production mode there's Extract Text Loader which extracts CSS text away
|
||||
return module.source;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|