mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 09:22:43 +03:00
parent
a5890623c4
commit
2777b45335
16492
community/tools/graphiql-online/package-lock.json
generated
Normal file
16492
community/tools/graphiql-online/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -44,8 +44,9 @@
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"deep-equal": "^1.0.1",
|
||||
"graphiql": "^0.11.11",
|
||||
"graphiql-explorer-hasura": "0.0.7",
|
||||
"graphql": "^0.13.2",
|
||||
"hasura-console-graphiql": "0.0.1",
|
||||
"hasura-console-graphiql": "0.0.10",
|
||||
"history": "^3.0.0",
|
||||
"hoist-non-react-statics": "^1.0.3",
|
||||
"invariant": "^2.2.0",
|
||||
|
@ -150,7 +150,6 @@
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.graphiql-container .queryWrap {
|
||||
@ -227,7 +226,7 @@
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
height: 29px;
|
||||
height: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@ -732,6 +731,245 @@ div.CodeMirror-lint-tooltip > * + * {
|
||||
.cm-atom {
|
||||
color: #ca9800;
|
||||
}
|
||||
/* Hasura Analyse modal css */
|
||||
.wd25 {
|
||||
width: 25%;
|
||||
display: inline-block;
|
||||
}
|
||||
.wd75 {
|
||||
width: 75%;
|
||||
display: inline-block;
|
||||
}
|
||||
.wd40 {
|
||||
width: 40%;
|
||||
display: inline-block;
|
||||
}
|
||||
.wd60 {
|
||||
width: 60%;
|
||||
display: inline-block;
|
||||
}
|
||||
.modalWrapper {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 40px;
|
||||
right: 40px;
|
||||
bottom: 40px;
|
||||
border: 1px solid rgb(204, 204, 204);
|
||||
background: rgb(255, 255, 255);
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
}
|
||||
.myOverlayClass {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
background-color: rgba(255, 255, 255, 0.75);
|
||||
z-index: 100;
|
||||
}
|
||||
.modalHeader {
|
||||
background-color: #43495a;
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding: 10px 20px;
|
||||
position: relative;
|
||||
color: #ffc627;
|
||||
}
|
||||
.modalTitle {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.modalClose {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
}
|
||||
.modalClose button {
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #ccc;
|
||||
padding: 0px;
|
||||
height: auto;
|
||||
}
|
||||
.modalClose button:hover {
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
.modalClose button:focus {
|
||||
outline: none;
|
||||
}
|
||||
.modalBody {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
height: calc(100% - 46px);
|
||||
}
|
||||
.topLevelNodesWrapper {
|
||||
border-right: 1px solid #ccc;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.textCenter {
|
||||
text-align: center;
|
||||
}
|
||||
.topLevelNodesWrapper .title {
|
||||
padding: 15px 20px;
|
||||
background-color: #fff3d5;
|
||||
margin-bottom: 20px;
|
||||
color: #767e93;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
.analysisWrapper {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.topLevelNodesWrapper ul {
|
||||
-webkit-padding-start: 0px;
|
||||
padding-inline-start: 0px;
|
||||
-webkit-padding-inline-start: 0px;
|
||||
-moz-padding-inline-start: 0px;
|
||||
-ms-padding-inline-start: 0px;
|
||||
-o-padding-inline-start: 0px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.borderRight {
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
.topLevelNodesWrapper ul li {
|
||||
list-style-type: none;
|
||||
padding: 10px 0;
|
||||
padding-left: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.topLevelNodesWrapper ul li i {
|
||||
margin-right: 5px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.topLevelNodesWrapper ul li.active {
|
||||
color: #fd9540;
|
||||
}
|
||||
.topLevelNodesWrapper ul li:hover {
|
||||
color: #e2701a;
|
||||
}
|
||||
.plansWrapper {
|
||||
height: 50%;
|
||||
position: relative;
|
||||
padding: 0px 20px;
|
||||
}
|
||||
.plansTitle {
|
||||
padding: 10px 0px;
|
||||
color: #767e93;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.copyGenerated {
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
right: 60px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.copyGenerated img,
|
||||
.copyExecution img {
|
||||
width: 20px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.copyGenerated img:hover,
|
||||
.copyExecution img:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
.copyGenerated:focus,
|
||||
.copyExecution:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.codeBlock {
|
||||
/* position: relative;
|
||||
padding: 10px 20px; */
|
||||
background-color: rgb(253, 249, 237);
|
||||
/* margin: 20px;
|
||||
width: 100%; */
|
||||
width: auto;
|
||||
border-radius: 5px;
|
||||
max-height: calc(100% - 60px);
|
||||
overflow: auto;
|
||||
margin-top: 0px;
|
||||
min-height: calc(100% - 60px);
|
||||
}
|
||||
|
||||
.codeBlock pre {
|
||||
display: block;
|
||||
padding: 10px 20px;
|
||||
margin: 0px;
|
||||
font-size: 13px;
|
||||
line-height: unset;
|
||||
word-break: unset;
|
||||
word-wrap: unset;
|
||||
color: #000;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
overflow: unset;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.codeBlock code {
|
||||
color: #000;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.graphiql-container .analyse-button-wrap {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.copyTooltip {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.copyTooltip .tooltiptext {
|
||||
background-color: #555;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 6px;
|
||||
padding: 4px 0px;
|
||||
font-size: 14px;
|
||||
position: absolute;
|
||||
z-index: 1000000000;
|
||||
right: -21px;
|
||||
bottom: 30px;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.3s;
|
||||
transition: opacity 0.3s;
|
||||
display: none;
|
||||
width: 57px;
|
||||
}
|
||||
|
||||
.copyTooltip .tooltiptext::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 24px;
|
||||
right: 22px;
|
||||
margin-left: -5px;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
border-color: #555 transparent transparent transparent;
|
||||
}
|
||||
|
||||
.copyTooltip:hover .tooltiptext {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
display: block;
|
||||
}
|
||||
/* BASICS */
|
||||
|
||||
.CodeMirror {
|
||||
@ -1240,24 +1478,23 @@ span.CodeMirror-selectedtext {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
height: 34px;
|
||||
line-height: 14px;
|
||||
padding: 8px 8px 5px;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.doc-explorer-title {
|
||||
height: 34px;
|
||||
}
|
||||
.graphiql-container .doc-explorer-title,
|
||||
.graphiql-container .history-title {
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
font-weight: bold;
|
||||
overflow-x: initial;
|
||||
padding: 10px 0 10px 10px;
|
||||
overflow-x: hidden;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-user-select: initial;
|
||||
@ -1549,12 +1786,19 @@ span.CodeMirror-selectedtext {
|
||||
.CodeMirror-foldgutter-folded:after {
|
||||
content: '\25B8';
|
||||
}
|
||||
.graphiql-container .history-contents {
|
||||
.graphiql-container .history-contents,
|
||||
.graphiql-container .history-contents input {
|
||||
font-family: 'Consolas', 'Inconsolata', 'Droid Sans Mono', 'Monaco', monospace;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.graphiql-container .history-contents p {
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
font-size: 12px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@ -1564,9 +1808,29 @@ span.CodeMirror-selectedtext {
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.graphiql-container .history-contents p.editable {
|
||||
padding-bottom: 6px;
|
||||
padding-top: 7px;
|
||||
}
|
||||
|
||||
.graphiql-container .history-contents input {
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex-positive: 1;
|
||||
flex-grow: 1;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.graphiql-container .history-contents p:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.graphiql-container .history-contents p span.history-label {
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex-positive: 1;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.CodeMirror-info {
|
||||
background: white;
|
||||
border-radius: 2px;
|
||||
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
||||
import GraphiQL from 'hasura-console-graphiql';
|
||||
import PropTypes from 'prop-types';
|
||||
import ErrorBoundary from './ErrorBoundary';
|
||||
import OneGraphExplorer from './OneGraphExplorer';
|
||||
import { graphQLFetcherFinal, getRemoteQueries } from './Actions';
|
||||
|
||||
import './GraphiQL.css';
|
||||
@ -50,6 +51,12 @@ class GraphiQLWrapper extends Component {
|
||||
} else if (this.state.queries) {
|
||||
graphiqlProps.query = this.state.queries;
|
||||
}
|
||||
const renderGraphiql = props => (
|
||||
<GraphiQL
|
||||
{...graphiqlProps}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<div
|
||||
@ -60,7 +67,12 @@ class GraphiQLWrapper extends Component {
|
||||
styles.graphQLHeight
|
||||
}
|
||||
>
|
||||
<GraphiQL {...graphiqlProps} />
|
||||
<OneGraphExplorer
|
||||
renderGraphiql={renderGraphiql}
|
||||
endpoint={this.props.data.url}
|
||||
headers={this.props.data.headers}
|
||||
query={query}
|
||||
/>
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
|
@ -0,0 +1,49 @@
|
||||
.graphiql-explorer-root {
|
||||
font-size: 12px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: unset;
|
||||
white-space: nowrap;
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
font-family: Consolas, Inconsolata, 'Droid Sans Mono', Monaco, monospace;
|
||||
}
|
||||
|
||||
.graphiql-explorer-abstractfields-label {
|
||||
color: #ca9800;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.graphiql-explorer-abstractargs-label {
|
||||
color: #8b2bb9;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.graphiql-explorer-fieldname {
|
||||
color: rgb(31, 97, 160);
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.graphiql-explorer-node {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.graphiql-explorer-args-wrapper {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.explorerGraphiqlSeparator {
|
||||
height: 100%;
|
||||
right: -5px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 10px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.explorerCursorResize {
|
||||
cursor: col-resize;
|
||||
}
|
||||
|
||||
.gqlexplorer {
|
||||
position: relative;
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
import React from 'react';
|
||||
import { getIntrospectionQuery, buildClientSchema } from 'graphql';
|
||||
import { getHeadersAsJSON } from './utils';
|
||||
import GraphiQLExplorer from 'graphiql-explorer-hasura';
|
||||
import './GraphiQL.css';
|
||||
import './OneGraphExplorer.css';
|
||||
import {
|
||||
makeDefaultArg,
|
||||
getDefaultScalarArgValue,
|
||||
getExplorerWidthFromLocalStorage,
|
||||
setExplorerWidthInLocalStorage,
|
||||
} from './onegraphUtils';
|
||||
|
||||
class OneGraphExplorer extends React.Component {
|
||||
state = {
|
||||
explorerOpen: false,
|
||||
explorerWidth: getExplorerWidthFromLocalStorage(),
|
||||
explorerClientX: null,
|
||||
schema: null,
|
||||
query: this.props.query || '',
|
||||
isResizing: false,
|
||||
headers: [],
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.introspect();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.shouldIntrospect(this.props.headers, this.state.headers)) {
|
||||
this.introspect()
|
||||
}
|
||||
}
|
||||
|
||||
shouldIntrospect(newHeadersArray, oldHeadersArray) {
|
||||
if (this.props.headerFocus) {
|
||||
return false;
|
||||
}
|
||||
const oldHeaders = getHeadersAsJSON(oldHeadersArray);
|
||||
const headers = getHeadersAsJSON(newHeadersArray);
|
||||
if (Object.keys(oldHeaders).length !== Object.keys(headers).length) {
|
||||
return true;
|
||||
}
|
||||
for (var i = Object.keys(headers).length - 1; i >= 0; i--) {
|
||||
const key = Object.keys(headers)[i];
|
||||
const value = headers[key];
|
||||
if (oldHeaders[key] !== value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
introspect() {
|
||||
const { endpoint, headers } = this.props;
|
||||
fetch(endpoint, {
|
||||
method: 'POST',
|
||||
headers: getHeadersAsJSON(headers || []),
|
||||
body: JSON.stringify({
|
||||
query: getIntrospectionQuery(),
|
||||
}),
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
this.setState({
|
||||
schema: buildClientSchema(result.data),
|
||||
headers: JSON.parse(JSON.stringify(headers))
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
this.setState({
|
||||
schema: null,
|
||||
headers: JSON.parse(JSON.stringify(headers))
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
onExplorerResize = e => {
|
||||
const { explorerClientX, explorerWidth } = this.state;
|
||||
if (explorerClientX === null) {
|
||||
this.setState({ explorerClientX: e.clientX });
|
||||
} else {
|
||||
const newExplorerWidth = explorerWidth + e.clientX - explorerClientX;
|
||||
setExplorerWidthInLocalStorage(newExplorerWidth);
|
||||
this.setState({
|
||||
explorerWidth: newExplorerWidth,
|
||||
explorerClientX: e.clientX,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
editQuery = query => {
|
||||
this.setState({ query });
|
||||
};
|
||||
|
||||
toggleExplorer = () => {
|
||||
this.setState(state => ({
|
||||
explorerOpen: !state.explorerOpen,
|
||||
}));
|
||||
};
|
||||
|
||||
handleExplorerResize = e => {
|
||||
e.preventDefault();
|
||||
document.addEventListener('mousemove', this.onExplorerResize);
|
||||
this.setState({
|
||||
isResizing: true,
|
||||
});
|
||||
};
|
||||
|
||||
handleExplorerResizeStop = e => {
|
||||
e.preventDefault();
|
||||
document.removeEventListener('mousemove', this.onExplorerResize);
|
||||
this.setState({
|
||||
isResizing: false,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
schema,
|
||||
explorerOpen,
|
||||
query,
|
||||
explorerWidth,
|
||||
isResizing,
|
||||
} = this.state;
|
||||
const { renderGraphiql } = this.props;
|
||||
return (
|
||||
<div
|
||||
className={`graphiql-container ${
|
||||
isResizing ? 'explorerCursorResize' : ''
|
||||
}`}
|
||||
onMouseUp={this.handleExplorerResizeStop}
|
||||
>
|
||||
<div className="gqlexplorer">
|
||||
{explorerOpen && (
|
||||
<div
|
||||
className="explorerGraphiqlSeparator explorerCursorResize"
|
||||
onMouseDown={this.handleExplorerResize}
|
||||
onMouseUp={this.handleExplorerResizeStop}
|
||||
/>
|
||||
)}
|
||||
<GraphiQLExplorer
|
||||
schema={schema}
|
||||
query={query}
|
||||
onEdit={this.editQuery}
|
||||
explorerIsOpen={explorerOpen}
|
||||
onToggleExplorer={this.toggleExplorer}
|
||||
getDefaultScalarArgValue={getDefaultScalarArgValue}
|
||||
makeDefaultArg={makeDefaultArg}
|
||||
width={explorerWidth}
|
||||
/>
|
||||
</div>
|
||||
{renderGraphiql({
|
||||
query,
|
||||
schema,
|
||||
onEditQuery: this.editQuery,
|
||||
toggleExplorer: this.toggleExplorer,
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default OneGraphExplorer;
|
@ -0,0 +1,21 @@
|
||||
import GraphiQLExplorer from 'graphiql-explorer-hasura';
|
||||
|
||||
export const makeDefaultArg = () => {
|
||||
return false;
|
||||
};
|
||||
|
||||
export const getDefaultScalarArgValue = (parentField, arg, argType) => {
|
||||
return GraphiQLExplorer.defaultValue(argType);
|
||||
};
|
||||
|
||||
export const getExplorerWidthFromLocalStorage = () => {
|
||||
const val = parseInt(
|
||||
window.localStorage.getItem('graphiql:explorerWidth'),
|
||||
10
|
||||
);
|
||||
return isNaN(val) ? 350 : val;
|
||||
};
|
||||
|
||||
export const setExplorerWidthInLocalStorage = width => {
|
||||
localStorage.setItem('graphiql:explorerWidth', width);
|
||||
};
|
@ -37,8 +37,8 @@ class LoginComponent extends React.Component {
|
||||
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)) {
|
||||
const urlRegex= /^(http[s]?:\/\/){0,1}(www\.){0,1}[a-zA-Z0-9\.\-]+\.[a-zA-Z]{2,5}[\.]{0,1}/;
|
||||
if (!urlRegex.test(this.state.graphqlEndpoint)) {
|
||||
alert('Please enter a valid URL');
|
||||
} else {
|
||||
dispatch(updateGraphQLEndpoint(this.state.graphqlEndpoint));
|
||||
|
Loading…
Reference in New Issue
Block a user