From 1266bbf354c940094972ea6f64e2a025e9a228db Mon Sep 17 00:00:00 2001 From: Praveen Durairaj Date: Thu, 25 Oct 2018 14:57:02 +0530 Subject: [PATCH] add online graphiql to community tools (#716) --- community/tools/graphiql-online/.babelrc | 4 + community/tools/graphiql-online/.bootstraprc | 120 ++ community/tools/graphiql-online/.dockerignore | 1 + community/tools/graphiql-online/.eslintignore | 2 + community/tools/graphiql-online/.eslintrc | 101 + community/tools/graphiql-online/.gitignore | 12 + community/tools/graphiql-online/.npmignore | 5 + community/tools/graphiql-online/Dockerfile | 22 + community/tools/graphiql-online/README.md | 33 + community/tools/graphiql-online/appconfig.js | 9 + .../tools/graphiql-online/bin/server.babel.js | 15 + community/tools/graphiql-online/bin/server.js | 33 + community/tools/graphiql-online/now.json | 4 + community/tools/graphiql-online/package.json | 142 ++ community/tools/graphiql-online/src/client.js | 93 + .../src/components/404/PageNotFound.js | 30 + .../src/components/404/Styles.scss | 42 + .../src/components/ApiExplorer/Actions.js | 240 +++ .../src/components/ApiExplorer/ApiExplorer.js | 52 + .../components/ApiExplorer/ApiExplorer.scss | 808 +++++++ .../ApiExplorer/ApiExplorerGenerator.js | 13 + .../src/components/ApiExplorer/ApiRequest.js | 325 +++ .../ApiExplorer/ApiRequestDetails.js | 28 + .../ApiExplorer/ApiRequestWrapper.js | 63 + .../src/components/ApiExplorer/Discord.svg | 36 + .../src/components/ApiExplorer/Dropdown.svg | 1 + .../components/ApiExplorer/ErrorBoundary.js | 29 + .../src/components/ApiExplorer/GraphiQL.css | 1884 +++++++++++++++++ .../components/ApiExplorer/GraphiQLWrapper.js | 65 + .../src/components/ApiExplorer/Styles.scss | 351 +++ .../src/components/ApiExplorer/Twitter.svg | 19 + .../src/components/ApiExplorer/chevron.svg | 1 + .../src/components/ApiExplorer/state.js | 82 + .../src/components/ApiExplorer/tick.png | Bin 0 -> 156 bytes .../src/components/ApiExplorer/utils.js | 12 + .../src/components/App/Actions.js | 98 + .../graphiql-online/src/components/App/App.js | 75 + .../src/components/App/ErrorBoundary.js | 30 + .../src/components/App/State.js | 12 + .../src/components/App/progress-bar.scss | 79 + .../Common/BreadCrumb/BreadCrumb.js | 14 + .../Common/BreadCrumb/BreadCrumb.scss | 9 + .../src/components/Common/CSManage.scss | 37 + .../src/components/Common/Common.scss | 1018 +++++++++ .../src/components/Common/Spinner/Spinner.js | 24 + .../components/Common/Spinner/Spinner.scss | 121 ++ .../src/components/Login/App.css | 57 + .../src/components/Login/Login.js | 56 + .../src/components/Login/LoginGenerator.js | 12 + .../graphiql-online/src/components/index.js | 6 + community/tools/graphiql-online/src/config.js | 24 + .../tools/graphiql-online/src/helpers/Html.js | 102 + .../src/helpers/getStatusFromRoutes.js | 9 + .../src/helpers/makeRouteHooksSafe.js | 43 + .../tools/graphiql-online/src/reducer.js | 12 + community/tools/graphiql-online/src/routes.js | 22 + community/tools/graphiql-online/src/server.js | 59 + .../src/theme/bootstrap.config.js | 71 + .../src/theme/bootstrap.config.prod.js | 8 + .../src/theme/bootstrap.overrides.scss | 198 ++ .../src/theme/font-awesome.config.js | 18 + .../src/theme/font-awesome.config.less | 7 + .../src/theme/font-awesome.config.prod.js | 8 + .../graphiql-online/src/theme/variables.scss | 27 + .../tools/graphiql-online/static/favicon.ico | Bin 0 -> 1406 bytes .../tools/graphiql-online/static/favicon.png | Bin 0 -> 2251 bytes .../tools/graphiql-online/static/index.html | 53 + .../tools/graphiql-online/static/logo.jpg | Bin 0 -> 6838 bytes .../tools/graphiql-online/webpack/bs3.yml | 116 + .../graphiql-online/webpack/dev.config.js | 186 ++ .../graphiql-online/webpack/prod.config.js | 192 ++ .../webpack/webpack-dev-server.js | 36 + .../webpack/webpack-isomorphic-tools.js | 101 + 73 files changed, 7617 insertions(+) create mode 100644 community/tools/graphiql-online/.babelrc create mode 100644 community/tools/graphiql-online/.bootstraprc create mode 100644 community/tools/graphiql-online/.dockerignore create mode 100644 community/tools/graphiql-online/.eslintignore create mode 100644 community/tools/graphiql-online/.eslintrc create mode 100644 community/tools/graphiql-online/.gitignore create mode 100644 community/tools/graphiql-online/.npmignore create mode 100644 community/tools/graphiql-online/Dockerfile create mode 100644 community/tools/graphiql-online/README.md create mode 100644 community/tools/graphiql-online/appconfig.js create mode 100755 community/tools/graphiql-online/bin/server.babel.js create mode 100644 community/tools/graphiql-online/bin/server.js create mode 100644 community/tools/graphiql-online/now.json create mode 100644 community/tools/graphiql-online/package.json create mode 100755 community/tools/graphiql-online/src/client.js create mode 100644 community/tools/graphiql-online/src/components/404/PageNotFound.js create mode 100644 community/tools/graphiql-online/src/components/404/Styles.scss create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/Actions.js create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/ApiExplorer.js create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/ApiExplorer.scss create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/ApiExplorerGenerator.js create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/ApiRequest.js create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/ApiRequestDetails.js create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/ApiRequestWrapper.js create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/Discord.svg create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/Dropdown.svg create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/ErrorBoundary.js create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/GraphiQL.css create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/GraphiQLWrapper.js create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/Styles.scss create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/Twitter.svg create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/chevron.svg create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/state.js create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/tick.png create mode 100644 community/tools/graphiql-online/src/components/ApiExplorer/utils.js create mode 100644 community/tools/graphiql-online/src/components/App/Actions.js create mode 100644 community/tools/graphiql-online/src/components/App/App.js create mode 100644 community/tools/graphiql-online/src/components/App/ErrorBoundary.js create mode 100644 community/tools/graphiql-online/src/components/App/State.js create mode 100644 community/tools/graphiql-online/src/components/App/progress-bar.scss create mode 100644 community/tools/graphiql-online/src/components/Common/BreadCrumb/BreadCrumb.js create mode 100644 community/tools/graphiql-online/src/components/Common/BreadCrumb/BreadCrumb.scss create mode 100644 community/tools/graphiql-online/src/components/Common/CSManage.scss create mode 100644 community/tools/graphiql-online/src/components/Common/Common.scss create mode 100644 community/tools/graphiql-online/src/components/Common/Spinner/Spinner.js create mode 100644 community/tools/graphiql-online/src/components/Common/Spinner/Spinner.scss create mode 100644 community/tools/graphiql-online/src/components/Login/App.css create mode 100644 community/tools/graphiql-online/src/components/Login/Login.js create mode 100644 community/tools/graphiql-online/src/components/Login/LoginGenerator.js create mode 100644 community/tools/graphiql-online/src/components/index.js create mode 100644 community/tools/graphiql-online/src/config.js create mode 100644 community/tools/graphiql-online/src/helpers/Html.js create mode 100644 community/tools/graphiql-online/src/helpers/getStatusFromRoutes.js create mode 100644 community/tools/graphiql-online/src/helpers/makeRouteHooksSafe.js create mode 100644 community/tools/graphiql-online/src/reducer.js create mode 100644 community/tools/graphiql-online/src/routes.js create mode 100755 community/tools/graphiql-online/src/server.js create mode 100644 community/tools/graphiql-online/src/theme/bootstrap.config.js create mode 100644 community/tools/graphiql-online/src/theme/bootstrap.config.prod.js create mode 100644 community/tools/graphiql-online/src/theme/bootstrap.overrides.scss create mode 100644 community/tools/graphiql-online/src/theme/font-awesome.config.js create mode 100644 community/tools/graphiql-online/src/theme/font-awesome.config.less create mode 100644 community/tools/graphiql-online/src/theme/font-awesome.config.prod.js create mode 100644 community/tools/graphiql-online/src/theme/variables.scss create mode 100644 community/tools/graphiql-online/static/favicon.ico create mode 100644 community/tools/graphiql-online/static/favicon.png create mode 100644 community/tools/graphiql-online/static/index.html create mode 100644 community/tools/graphiql-online/static/logo.jpg create mode 100644 community/tools/graphiql-online/webpack/bs3.yml create mode 100755 community/tools/graphiql-online/webpack/dev.config.js create mode 100755 community/tools/graphiql-online/webpack/prod.config.js create mode 100755 community/tools/graphiql-online/webpack/webpack-dev-server.js create mode 100644 community/tools/graphiql-online/webpack/webpack-isomorphic-tools.js diff --git a/community/tools/graphiql-online/.babelrc b/community/tools/graphiql-online/.babelrc new file mode 100644 index 00000000000..81ee117c3cf --- /dev/null +++ b/community/tools/graphiql-online/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["stage-0", "env", "react"], + "plugins": ["transform-class-properties", "transform-react-remove-prop-types", "istanbul"] +} \ No newline at end of file diff --git a/community/tools/graphiql-online/.bootstraprc b/community/tools/graphiql-online/.bootstraprc new file mode 100644 index 00000000000..1469f7c85be --- /dev/null +++ b/community/tools/graphiql-online/.bootstraprc @@ -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 diff --git a/community/tools/graphiql-online/.dockerignore b/community/tools/graphiql-online/.dockerignore new file mode 100644 index 00000000000..3c3629e647f --- /dev/null +++ b/community/tools/graphiql-online/.dockerignore @@ -0,0 +1 @@ +node_modules diff --git a/community/tools/graphiql-online/.eslintignore b/community/tools/graphiql-online/.eslintignore new file mode 100644 index 00000000000..043ceb51042 --- /dev/null +++ b/community/tools/graphiql-online/.eslintignore @@ -0,0 +1,2 @@ +webpack/* +src/utils.js diff --git a/community/tools/graphiql-online/.eslintrc b/community/tools/graphiql-online/.eslintrc new file mode 100644 index 00000000000..56f86bbb49f --- /dev/null +++ b/community/tools/graphiql-online/.eslintrc @@ -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 + } +} diff --git a/community/tools/graphiql-online/.gitignore b/community/tools/graphiql-online/.gitignore new file mode 100644 index 00000000000..c36cdf8e2fa --- /dev/null +++ b/community/tools/graphiql-online/.gitignore @@ -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/* diff --git a/community/tools/graphiql-online/.npmignore b/community/tools/graphiql-online/.npmignore new file mode 100644 index 00000000000..1008a6dbc3a --- /dev/null +++ b/community/tools/graphiql-online/.npmignore @@ -0,0 +1,5 @@ +* +**/* +!static/dist/main.js +!static/dist/vendor.js +!static/dist/main.css diff --git a/community/tools/graphiql-online/Dockerfile b/community/tools/graphiql-online/Dockerfile new file mode 100644 index 00000000000..98078438746 --- /dev/null +++ b/community/tools/graphiql-online/Dockerfile @@ -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"] diff --git a/community/tools/graphiql-online/README.md b/community/tools/graphiql-online/README.md new file mode 100644 index 00000000000..548bdf93862 --- /dev/null +++ b/community/tools/graphiql-online/README.md @@ -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. diff --git a/community/tools/graphiql-online/appconfig.js b/community/tools/graphiql-online/appconfig.js new file mode 100644 index 00000000000..d84aecccd61 --- /dev/null +++ b/community/tools/graphiql-online/appconfig.js @@ -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', +}; diff --git a/community/tools/graphiql-online/bin/server.babel.js b/community/tools/graphiql-online/bin/server.babel.js new file mode 100755 index 00000000000..e1682870d69 --- /dev/null +++ b/community/tools/graphiql-online/bin/server.babel.js @@ -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); diff --git a/community/tools/graphiql-online/bin/server.js b/community/tools/graphiql-online/bin/server.js new file mode 100644 index 00000000000..c0d70c74b58 --- /dev/null +++ b/community/tools/graphiql-online/bin/server.js @@ -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'); diff --git a/community/tools/graphiql-online/now.json b/community/tools/graphiql-online/now.json new file mode 100644 index 00000000000..36b66f07977 --- /dev/null +++ b/community/tools/graphiql-online/now.json @@ -0,0 +1,4 @@ +{ + "name": "graphqurl-graphiql", + "alias": "hasura-graphiql.now.sh" +} diff --git a/community/tools/graphiql-online/package.json b/community/tools/graphiql-online/package.json new file mode 100644 index 00000000000..6b3beb50a5a --- /dev/null +++ b/community/tools/graphiql-online/package.json @@ -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" + } +} diff --git a/community/tools/graphiql-online/src/client.js b/community/tools/graphiql-online/src/client.js new file mode 100755 index 00000000000..3e591b31602 --- /dev/null +++ b/community/tools/graphiql-online/src/client.js @@ -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 = ( + history)({ basename: '/' })} + routes={getRoutes(store)} + onUpdate={hashLinkScroll} + /> +); + +const dest = document.getElementById('content'); +ReactDOM.render( + + {main} + , + dest +); + +if (process.env.NODE_ENV !== 'production') { + window.React = React; // enable debugger +} diff --git a/community/tools/graphiql-online/src/components/404/PageNotFound.js b/community/tools/graphiql-online/src/components/404/PageNotFound.js new file mode 100644 index 00000000000..bfcb3685046 --- /dev/null +++ b/community/tools/graphiql-online/src/components/404/PageNotFound.js @@ -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 ( +
+ +
+
+
+

404

+ This page doesn't exist. +
+
+
+
+ ); + } +} + +PageNotFound.propTypes = { + dispatch: PropTypes.func.isRequired, +}; + +export default connect()(PageNotFound); diff --git a/community/tools/graphiql-online/src/components/404/Styles.scss b/community/tools/graphiql-online/src/components/404/Styles.scss new file mode 100644 index 00000000000..26791f5a0b8 --- /dev/null +++ b/community/tools/graphiql-online/src/components/404/Styles.scss @@ -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; + } +} diff --git a/community/tools/graphiql-online/src/components/ApiExplorer/Actions.js b/community/tools/graphiql-online/src/components/ApiExplorer/Actions.js new file mode 100644 index 00000000000..a7affbb5789 --- /dev/null +++ b/community/tools/graphiql-online/src/components/ApiExplorer/Actions.js @@ -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, +}; diff --git a/community/tools/graphiql-online/src/components/ApiExplorer/ApiExplorer.js b/community/tools/graphiql-online/src/components/ApiExplorer/ApiExplorer.js new file mode 100644 index 00000000000..e0f307f8892 --- /dev/null +++ b/community/tools/graphiql-online/src/components/ApiExplorer/ApiExplorer.js @@ -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 = ( + + ); + + return ( +
+ +
{requestWrapper}
+
+ ); + } +} + +ApiExplorer.propTypes = { + modalState: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, + route: PropTypes.object.isRequired, + headerFocus: PropTypes.bool.isRequired, +}; + +export default ApiExplorer; diff --git a/community/tools/graphiql-online/src/components/ApiExplorer/ApiExplorer.scss b/community/tools/graphiql-online/src/components/ApiExplorer/ApiExplorer.scss new file mode 100644 index 00000000000..d4caed9c560 --- /dev/null +++ b/community/tools/graphiql-online/src/components/ApiExplorer/ApiExplorer.scss @@ -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; + } + } +} diff --git a/community/tools/graphiql-online/src/components/ApiExplorer/ApiExplorerGenerator.js b/community/tools/graphiql-online/src/components/ApiExplorer/ApiExplorerGenerator.js new file mode 100644 index 00000000000..2378dc58a11 --- /dev/null +++ b/community/tools/graphiql-online/src/components/ApiExplorer/ApiExplorerGenerator.js @@ -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; diff --git a/community/tools/graphiql-online/src/components/ApiExplorer/ApiRequest.js b/community/tools/graphiql-online/src/components/ApiExplorer/ApiRequest.js new file mode 100644 index 00000000000..0a48078ca79 --- /dev/null +++ b/community/tools/graphiql-online/src/components/ApiExplorer/ApiRequest.js @@ -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 ( +