UNPKG

@platformos/pos-cli

Version:

Manage your platformOS application

1,093 lines (920 loc) 35.1 kB
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } /** * Copyright (c) 2019 GraphQL Contributors. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ import React from 'react'; import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; import { buildClientSchema, GraphQLSchema, parse, print } from 'graphql'; import copyToClipboard from 'copy-to-clipboard'; import { ExecuteButton } from './ExecuteButton'; import { ImagePreview } from './ImagePreview'; import { ToolbarButton } from './ToolbarButton'; import { ToolbarGroup } from './ToolbarGroup'; import { ToolbarMenu, ToolbarMenuItem } from './ToolbarMenu'; import { ToolbarSelect, ToolbarSelectOption } from './ToolbarSelect'; import { QueryEditor } from './QueryEditor'; import { VariableEditor } from './VariableEditor'; import { ResultViewer } from './ResultViewer'; import { DocExplorer } from './DocExplorer'; import { QueryHistory } from './QueryHistory'; import CodeMirrorSizer from '../utility/CodeMirrorSizer'; import StorageAPI from '../utility/StorageAPI'; import getQueryFacts from '../utility/getQueryFacts'; import getSelectedOperationName from '../utility/getSelectedOperationName'; import debounce from '../utility/debounce'; import find from '../utility/find'; import { fillLeafs } from '../utility/fillLeafs'; import { getLeft, getTop } from '../utility/elementPosition'; import { mergeAst } from '../utility/mergeAst'; import { introspectionQuery, introspectionQueryName, introspectionQuerySansSubscriptions } from '../utility/introspectionQueries'; const DEFAULT_DOC_EXPLORER_WIDTH = 350; /** * The top-level React component for GraphiQL, intended to encompass the entire * browser viewport. * * @see https://github.com/graphql/graphiql#usage */ export class GraphiQL extends React.Component { constructor(props) { super(props); // Ensure props are correct _defineProperty(this, "handleClickReference", reference => { this.setState({ docExplorerOpen: true }, () => { this.docExplorerComponent.showDocForReference(reference); }); }); _defineProperty(this, "handleRunQuery", selectedOperationName => { this._editorQueryID++; const queryID = this._editorQueryID; // Use the edited query after autoCompleteLeafs() runs or, // in case autoCompletion fails (the function returns undefined), // the current query from the editor. const editedQuery = this.autoCompleteLeafs() || this.state.query; const variables = this.state.variables; let operationName = this.state.operationName; // If an operation was explicitly provided, different from the current // operation name, then report that it changed. if (selectedOperationName && selectedOperationName !== operationName) { operationName = selectedOperationName; this.handleEditOperationName(operationName); } try { this.setState({ isWaitingForResponse: true, response: null, operationName }); // _fetchQuery may return a subscription. const subscription = this._fetchQuery(editedQuery, variables, operationName, result => { if (queryID === this._editorQueryID) { this.setState({ isWaitingForResponse: false, response: GraphiQL.formatResult(result) }); } }); this.setState({ subscription }); } catch (error) { this.setState({ isWaitingForResponse: false, response: error.message }); } }); _defineProperty(this, "handleStopQuery", () => { const subscription = this.state.subscription; this.setState({ isWaitingForResponse: false, subscription: null }); if (subscription) { subscription.unsubscribe(); } }); _defineProperty(this, "handlePrettifyQuery", () => { const editor = this.getQueryEditor(); const editorContent = editor.getValue(); const prettifiedEditorContent = print(parse(editorContent)); if (prettifiedEditorContent !== editorContent) { editor.setValue(prettifiedEditorContent); } const variableEditor = this.getVariableEditor(); const variableEditorContent = variableEditor.getValue(); try { const prettifiedVariableEditorContent = JSON.stringify(JSON.parse(variableEditorContent), null, 2); if (prettifiedVariableEditorContent !== variableEditorContent) { variableEditor.setValue(prettifiedVariableEditorContent); } } catch { /* Parsing JSON failed, skip prettification */ } }); _defineProperty(this, "handleMergeQuery", () => { const editor = this.getQueryEditor(); const query = editor.getValue(); if (!query) { return; } const ast = parse(query); editor.setValue(print(mergeAst(ast))); }); _defineProperty(this, "handleEditQuery", debounce(100, value => { const queryFacts = this._updateQueryFacts(value, this.state.operationName, this.state.operations, this.state.schema); this.setState({ query: value, ...queryFacts }); if (this.props.onEditQuery) { return this.props.onEditQuery(value); } })); _defineProperty(this, "handleCopyQuery", () => { const editor = this.getQueryEditor(); const query = editor.getValue(); if (!query) { return; } copyToClipboard(query); if (this.props.onCopyQuery) { return this.props.onCopyQuery(query); } }); _defineProperty(this, "_updateQueryFacts", (query, operationName, prevOperations, schema) => { const queryFacts = getQueryFacts(schema, query); if (queryFacts) { // Update operation name should any query names change. const updatedOperationName = getSelectedOperationName(prevOperations, operationName, queryFacts.operations); // Report changing of operationName if it changed. const onEditOperationName = this.props.onEditOperationName; if (onEditOperationName && operationName !== updatedOperationName) { onEditOperationName(updatedOperationName); } return { operationName: updatedOperationName, ...queryFacts }; } }); _defineProperty(this, "handleEditVariables", value => { this.setState({ variables: value }); if (this.props.onEditVariables) { this.props.onEditVariables(value); } }); _defineProperty(this, "handleEditOperationName", operationName => { const onEditOperationName = this.props.onEditOperationName; if (onEditOperationName) { onEditOperationName(operationName); } }); _defineProperty(this, "handleHintInformationRender", elem => { elem.addEventListener('click', this._onClickHintInformation); let onRemoveFn; elem.addEventListener('DOMNodeRemoved', onRemoveFn = () => { elem.removeEventListener('DOMNodeRemoved', onRemoveFn); elem.removeEventListener('click', this._onClickHintInformation); }); }); _defineProperty(this, "handleEditorRunQuery", () => { this._runQueryAtCursor(); }); _defineProperty(this, "_onClickHintInformation", event => { if (event.target.className === 'typeName') { const typeName = event.target.innerHTML; const schema = this.state.schema; if (schema) { const type = schema.getType(typeName); if (type) { this.setState({ docExplorerOpen: true }, () => { this.docExplorerComponent.showDoc(type); }); } } } }); _defineProperty(this, "handleToggleDocs", () => { if (typeof this.props.onToggleDocs === 'function') { this.props.onToggleDocs(!this.state.docExplorerOpen); } this.setState({ docExplorerOpen: !this.state.docExplorerOpen }); }); _defineProperty(this, "handleToggleHistory", () => { if (typeof this.props.onToggleHistory === 'function') { this.props.onToggleHistory(!this.state.historyPaneOpen); } this.setState({ historyPaneOpen: !this.state.historyPaneOpen }); }); _defineProperty(this, "handleSelectHistoryQuery", (query, variables, operationName) => { this.handleEditQuery(query); this.handleEditVariables(variables); this.handleEditOperationName(operationName); }); _defineProperty(this, "handleResizeStart", downEvent => { if (!this._didClickDragBar(downEvent)) { return; } downEvent.preventDefault(); const offset = downEvent.clientX - getLeft(downEvent.target); let onMouseMove = moveEvent => { if (moveEvent.buttons === 0) { return onMouseUp(); } const editorBar = ReactDOM.findDOMNode(this.editorBarComponent); const leftSize = moveEvent.clientX - getLeft(editorBar) - offset; const rightSize = editorBar.clientWidth - leftSize; this.setState({ editorFlex: leftSize / rightSize }); }; let onMouseUp = () => { document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); onMouseMove = null; onMouseUp = null; }; document.addEventListener('mousemove', onMouseMove); document.addEventListener('mouseup', onMouseUp); }); _defineProperty(this, "handleResetResize", () => { this.setState({ editorFlex: 1 }); }); _defineProperty(this, "handleDocsResizeStart", downEvent => { downEvent.preventDefault(); const hadWidth = this.state.docExplorerWidth; const offset = downEvent.clientX - getLeft(downEvent.target); let onMouseMove = moveEvent => { if (moveEvent.buttons === 0) { return onMouseUp(); } const app = ReactDOM.findDOMNode(this); const cursorPos = moveEvent.clientX - getLeft(app) - offset; const docsSize = app.clientWidth - cursorPos; if (docsSize < 100) { this.setState({ docExplorerOpen: false }); } else { this.setState({ docExplorerOpen: true, docExplorerWidth: Math.min(docsSize, 650) }); } }; let onMouseUp = () => { if (!this.state.docExplorerOpen) { this.setState({ docExplorerWidth: hadWidth }); } document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); onMouseMove = null; onMouseUp = null; }; document.addEventListener('mousemove', onMouseMove); document.addEventListener('mouseup', onMouseUp); }); _defineProperty(this, "handleDocsResetResize", () => { this.setState({ docExplorerWidth: DEFAULT_DOC_EXPLORER_WIDTH }); }); _defineProperty(this, "handleVariableResizeStart", downEvent => { downEvent.preventDefault(); let didMove = false; const wasOpen = this.state.variableEditorOpen; const hadHeight = this.state.variableEditorHeight; const offset = downEvent.clientY - getTop(downEvent.target); let onMouseMove = moveEvent => { if (moveEvent.buttons === 0) { return onMouseUp(); } didMove = true; const editorBar = ReactDOM.findDOMNode(this.editorBarComponent); const topSize = moveEvent.clientY - getTop(editorBar) - offset; const bottomSize = editorBar.clientHeight - topSize; if (bottomSize < 60) { this.setState({ variableEditorOpen: false, variableEditorHeight: hadHeight }); } else { this.setState({ variableEditorOpen: true, variableEditorHeight: bottomSize }); } }; let onMouseUp = () => { if (!didMove) { this.setState({ variableEditorOpen: !wasOpen }); } document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); onMouseMove = null; onMouseUp = null; }; document.addEventListener('mousemove', onMouseMove); document.addEventListener('mouseup', onMouseUp); }); if (typeof props.fetcher !== 'function') { throw new TypeError('GraphiQL requires a fetcher function.'); } // Cache the storage instance this._storage = new StorageAPI(props.storage); // Determine the initial query to display. const _query = props.query !== undefined ? props.query : this._storage.get('query') !== null ? this._storage.get('query') : props.defaultQuery !== undefined ? props.defaultQuery : defaultQuery; // Get the initial query facts. const _queryFacts = getQueryFacts(props.schema, _query); // Determine the initial variables to display. const _variables = props.variables !== undefined ? props.variables : this._storage.get('variables'); // Determine the initial operationName to use. const _operationName = props.operationName !== undefined ? props.operationName : getSelectedOperationName(null, this._storage.get('operationName'), _queryFacts && _queryFacts.operations); // prop can be supplied to open docExplorer initially let docExplorerOpen = props.docExplorerOpen || false; // but then local storage state overrides it if (this._storage.get('docExplorerOpen')) { docExplorerOpen = this._storage.get('docExplorerOpen') === 'true'; } // initial variable editor pane open const variableEditorOpen = props.defaultVariableEditorOpen !== undefined ? props.defaultVariableEditorOpen : Boolean(_variables); // Initialize state this.state = { schema: props.schema, query: _query, variables: _variables, operationName: _operationName, docExplorerOpen, response: props.response, editorFlex: Number(this._storage.get('editorFlex')) || 1, variableEditorOpen, variableEditorHeight: Number(this._storage.get('variableEditorHeight')) || 200, historyPaneOpen: this._storage.get('historyPaneOpen') === 'true' || false, docExplorerWidth: Number(this._storage.get('docExplorerWidth')) || DEFAULT_DOC_EXPLORER_WIDTH, isWaitingForResponse: false, subscription: null, ..._queryFacts }; // Ensure only the last executed editor query is rendered. this._editorQueryID = 0; // Subscribe to the browser window closing, treating it as an unmount. if (typeof window === 'object') { window.addEventListener('beforeunload', () => this.componentWillUnmount()); } } componentDidMount() { // Only fetch schema via introspection if a schema has not been // provided, including if `null` was provided. if (this.state.schema === undefined) { this._fetchSchema(); } // Utility for keeping CodeMirror correctly sized. this.codeMirrorSizer = new CodeMirrorSizer(); global.g = this; } componentWillReceiveProps(nextProps) { let nextSchema = this.state.schema; let nextQuery = this.state.query; let nextVariables = this.state.variables; let nextOperationName = this.state.operationName; let nextResponse = this.state.response; if (nextProps.schema !== undefined) { nextSchema = nextProps.schema; } if (nextProps.query !== undefined) { nextQuery = nextProps.query; } if (nextProps.variables !== undefined) { nextVariables = nextProps.variables; } if (nextProps.operationName !== undefined) { nextOperationName = nextProps.operationName; } if (nextProps.response !== undefined) { nextResponse = nextProps.response; } if (nextSchema !== this.state.schema || nextQuery !== this.state.query || nextOperationName !== this.state.operationName) { const updatedQueryAttributes = this._updateQueryFacts(nextQuery, nextOperationName, this.state.operations, nextSchema); if (updatedQueryAttributes !== undefined) { nextOperationName = updatedQueryAttributes.operationName; this.setState(updatedQueryAttributes); } } // If schema is not supplied via props and the fetcher changed, then // remove the schema so fetchSchema() will be called with the new fetcher. if (nextProps.schema === undefined && nextProps.fetcher !== this.props.fetcher) { nextSchema = undefined; } this.setState({ schema: nextSchema, query: nextQuery, variables: nextVariables, operationName: nextOperationName, response: nextResponse }, () => { if (this.state.schema === undefined) { if (this.docExplorerComponent) { this.docExplorerComponent.reset(); } this._fetchSchema(); } }); } componentDidUpdate() { // If this update caused DOM nodes to have changed sizes, update the // corresponding CodeMirror instance sizes to match. this.codeMirrorSizer.updateSizes([this.queryEditorComponent, this.variableEditorComponent, this.resultComponent]); } // When the component is about to unmount, store any persistable state, such // that when the component is remounted, it will use the last used values. componentWillUnmount() { this._storage.set('query', this.state.query); this._storage.set('variables', this.state.variables); this._storage.set('operationName', this.state.operationName); this._storage.set('editorFlex', this.state.editorFlex); this._storage.set('variableEditorHeight', this.state.variableEditorHeight); this._storage.set('docExplorerWidth', this.state.docExplorerWidth); this._storage.set('docExplorerOpen', this.state.docExplorerOpen); this._storage.set('historyPaneOpen', this.state.historyPaneOpen); } render() { const children = React.Children.toArray(this.props.children); const logo = find(children, child => child.type === GraphiQL.Logo) || React.createElement(GraphiQL.Logo, null); const toolbar = find(children, child => child.type === GraphiQL.Toolbar) || React.createElement(GraphiQL.Toolbar, null, React.createElement(ToolbarButton, { onClick: this.handlePrettifyQuery, title: "Prettify Query (Shift-Ctrl-P)", label: "Prettify" }), React.createElement(ToolbarButton, { onClick: this.handleMergeQuery, title: "Merge Query (Shift-Ctrl-M)", label: "Merge" }), React.createElement(ToolbarButton, { onClick: this.handleCopyQuery, title: "Copy Query (Shift-Ctrl-C)", label: "Copy" }), React.createElement(ToolbarButton, { onClick: this.handleToggleHistory, title: "Show History", label: "History" })); const footer = find(children, child => child.type === GraphiQL.Footer); const queryWrapStyle = { WebkitFlex: this.state.editorFlex, flex: this.state.editorFlex }; const docWrapStyle = { display: 'block', width: this.state.docExplorerWidth }; const docExplorerWrapClasses = 'docExplorerWrap' + (this.state.docExplorerWidth < 200 ? ' doc-explorer-narrow' : ''); const historyPaneStyle = { display: this.state.historyPaneOpen ? 'block' : 'none', width: '230px', zIndex: '7' }; const variableOpen = this.state.variableEditorOpen; const variableStyle = { height: variableOpen ? this.state.variableEditorHeight : null }; return React.createElement("div", { className: "graphiql-container" }, React.createElement("div", { className: "historyPaneWrap", style: historyPaneStyle }, React.createElement(QueryHistory, { operationName: this.state.operationName, query: this.state.query, variables: this.state.variables, onSelectQuery: this.handleSelectHistoryQuery, storage: this._storage, queryID: this._editorQueryID }, React.createElement("button", { className: "docExplorerHide", onClick: this.handleToggleHistory, "aria-label": "Close History" }, '\u2715'))), React.createElement("div", { className: "editorWrap" }, React.createElement("div", { className: "topBarWrap" }, React.createElement("div", { className: "topBar" }, logo, React.createElement(ExecuteButton, { isRunning: Boolean(this.state.subscription), onRun: this.handleRunQuery, onStop: this.handleStopQuery, operations: this.state.operations }), toolbar), !this.state.docExplorerOpen && React.createElement("button", { className: "docExplorerShow", onClick: this.handleToggleDocs, "aria-label": "Open Documentation Explorer" }, 'Docs')), React.createElement("div", { ref: n => { this.editorBarComponent = n; }, className: "editorBar", onDoubleClick: this.handleResetResize, onMouseDown: this.handleResizeStart }, React.createElement("div", { className: "queryWrap", style: queryWrapStyle }, React.createElement(QueryEditor, { ref: n => { this.queryEditorComponent = n; }, schema: this.state.schema, value: this.state.query, onEdit: this.handleEditQuery, onHintInformationRender: this.handleHintInformationRender, onClickReference: this.handleClickReference, onCopyQuery: this.handleCopyQuery, onPrettifyQuery: this.handlePrettifyQuery, onMergeQuery: this.handleMergeQuery, onRunQuery: this.handleEditorRunQuery, editorTheme: this.props.editorTheme, readOnly: this.props.readOnly }), React.createElement("section", { className: "variable-editor", style: variableStyle, "aria-label": "Query Variables" }, React.createElement("div", { className: "variable-editor-title", id: "variable-editor-title", style: { cursor: variableOpen ? 'row-resize' : 'n-resize' }, onMouseDown: this.handleVariableResizeStart }, 'Query Variables'), React.createElement(VariableEditor, { ref: n => { this.variableEditorComponent = n; }, value: this.state.variables, variableToType: this.state.variableToType, onEdit: this.handleEditVariables, onHintInformationRender: this.handleHintInformationRender, onPrettifyQuery: this.handlePrettifyQuery, onMergeQuery: this.handleMergeQuery, onRunQuery: this.handleEditorRunQuery, editorTheme: this.props.editorTheme, readOnly: this.props.readOnly }))), React.createElement("div", { className: "resultWrap" }, this.state.isWaitingForResponse && React.createElement("div", { className: "spinner-container" }, React.createElement("div", { className: "spinner" })), React.createElement(ResultViewer, { ref: c => { this.resultComponent = c; }, value: this.state.response, editorTheme: this.props.editorTheme, ResultsTooltip: this.props.ResultsTooltip, ImagePreview: ImagePreview }), footer))), this.state.docExplorerOpen && React.createElement("div", { className: docExplorerWrapClasses, style: docWrapStyle }, React.createElement("div", { className: "docExplorerResizer", onDoubleClick: this.handleDocsResetResize, onMouseDown: this.handleDocsResizeStart }), React.createElement(DocExplorer, { ref: c => { this.docExplorerComponent = c; }, schema: this.state.schema }, React.createElement("button", { className: "docExplorerHide", onClick: this.handleToggleDocs, "aria-label": "Close Documentation Explorer" }, '\u2715')))); } /** * Get the query editor CodeMirror instance. * * @public */ getQueryEditor() { return this.queryEditorComponent.getCodeMirror(); } /** * Get the variable editor CodeMirror instance. * * @public */ getVariableEditor() { return this.variableEditorComponent.getCodeMirror(); } /** * Refresh all CodeMirror instances. * * @public */ refresh() { this.queryEditorComponent.getCodeMirror().refresh(); this.variableEditorComponent.getCodeMirror().refresh(); this.resultComponent.getCodeMirror().refresh(); } /** * Inspect the query, automatically filling in selection sets for non-leaf * fields which do not yet have them. * * @public */ autoCompleteLeafs() { const { insertions, result } = fillLeafs(this.state.schema, this.state.query, this.props.getDefaultFieldNames); if (insertions && insertions.length > 0) { const editor = this.getQueryEditor(); editor.operation(() => { const cursor = editor.getCursor(); const cursorIndex = editor.indexFromPos(cursor); editor.setValue(result); let added = 0; const markers = insertions.map(({ index, string }) => editor.markText(editor.posFromIndex(index + added), editor.posFromIndex(index + (added += string.length)), { className: 'autoInsertedLeaf', clearOnEnter: true, title: 'Automatically added leaf fields' })); setTimeout(() => markers.forEach(marker => marker.clear()), 7000); let newCursorIndex = cursorIndex; insertions.forEach(({ index, string }) => { if (index < cursorIndex) { newCursorIndex += string.length; } }); editor.setCursor(editor.posFromIndex(newCursorIndex)); }); } return result; } // Private methods _fetchSchema() { const fetcher = this.props.fetcher; const fetch = observableToPromise(fetcher({ query: introspectionQuery, operationName: introspectionQueryName })); if (!isPromise(fetch)) { this.setState({ response: 'Fetcher did not return a Promise for introspection.' }); return; } fetch.then(result => { if (result.data) { return result; } // Try the stock introspection query first, falling back on the // sans-subscriptions query for services which do not yet support it. const fetch2 = observableToPromise(fetcher({ query: introspectionQuerySansSubscriptions, operationName: introspectionQueryName })); if (!isPromise(fetch)) { throw new Error('Fetcher did not return a Promise for introspection.'); } return fetch2; }).then(result => { // If a schema was provided while this fetch was underway, then // satisfy the race condition by respecting the already // provided schema. if (this.state.schema !== undefined) { return; } if (result && result.data) { const schema = buildClientSchema(result.data); const queryFacts = getQueryFacts(schema, this.state.query); this.setState({ schema, ...queryFacts }); } else { const responseString = typeof result === 'string' ? result : GraphiQL.formatResult(result); this.setState({ // Set schema to `null` to explicitly indicate that no schema exists. schema: null, response: responseString }); } }).catch(error => { this.setState({ schema: null, response: error ? GraphiQL.formatError(error) : null }); }); } _fetchQuery(query, variables, operationName, cb) { const fetcher = this.props.fetcher; let jsonVariables = null; try { jsonVariables = variables && variables.trim() !== '' ? JSON.parse(variables) : null; } catch (error) { throw new Error(`Variables are invalid JSON: ${error.message}.`); } if (typeof jsonVariables !== 'object') { throw new Error('Variables are not a JSON object.'); } const fetch = fetcher({ query, variables: jsonVariables, operationName }); if (isPromise(fetch)) { // If fetcher returned a Promise, then call the callback when the promise // resolves, otherwise handle the error. fetch.then(cb).catch(error => { this.setState({ isWaitingForResponse: false, response: error ? GraphiQL.formatError(error) : null }); }); } else if (isObservable(fetch)) { // If the fetcher returned an Observable, then subscribe to it, calling // the callback on each next value, and handling both errors and the // completion of the Observable. Returns a Subscription object. const subscription = fetch.subscribe({ next: cb, error: error => { this.setState({ isWaitingForResponse: false, response: error ? GraphiQL.formatError(error) : null, subscription: null }); }, complete: () => { this.setState({ isWaitingForResponse: false, subscription: null }); } }); return subscription; } else { throw new Error('Fetcher did not return Promise or Observable.'); } } _runQueryAtCursor() { if (this.state.subscription) { this.handleStopQuery(); return; } let operationName; const operations = this.state.operations; if (operations) { const editor = this.getQueryEditor(); if (editor.hasFocus()) { const cursor = editor.getCursor(); const cursorIndex = editor.indexFromPos(cursor); // Loop through all operations to see if one contains the cursor. for (let i = 0; i < operations.length; i++) { const operation = operations[i]; if (operation.loc.start <= cursorIndex && operation.loc.end >= cursorIndex) { operationName = operation.name && operation.name.value; break; } } } } this.handleRunQuery(operationName); } _didClickDragBar(event) { // Only for primary unmodified clicks if (event.button !== 0 || event.ctrlKey) { return false; } let target = event.target; // We use codemirror's gutter as the drag bar. if (target.className.indexOf('CodeMirror-gutter') !== 0) { return false; } // Specifically the result window's drag bar. const resultWindow = ReactDOM.findDOMNode(this.resultComponent); while (target) { if (target === resultWindow) { return true; } target = target.parentNode; } return false; } } // Configure the UI by providing this Component as a child of GraphiQL. _defineProperty(GraphiQL, "propTypes", { fetcher: PropTypes.func.isRequired, schema: PropTypes.instanceOf(GraphQLSchema), query: PropTypes.string, variables: PropTypes.string, operationName: PropTypes.string, response: PropTypes.string, storage: PropTypes.shape({ getItem: PropTypes.func, setItem: PropTypes.func, removeItem: PropTypes.func }), defaultQuery: PropTypes.string, defaultVariableEditorOpen: PropTypes.bool, onCopyQuery: PropTypes.func, onEditQuery: PropTypes.func, onEditVariables: PropTypes.func, onEditOperationName: PropTypes.func, onToggleDocs: PropTypes.func, getDefaultFieldNames: PropTypes.func, editorTheme: PropTypes.string, onToggleHistory: PropTypes.func, ResultsTooltip: PropTypes.any, readOnly: PropTypes.bool, docExplorerOpen: PropTypes.bool }); GraphiQL.Logo = function GraphiQLLogo(props) { return React.createElement("div", { className: "title" }, props.children || React.createElement("span", null, 'Graph', React.createElement("em", null, 'i'), 'QL')); }; // Configure the UI by providing this Component as a child of GraphiQL. GraphiQL.Toolbar = function GraphiQLToolbar(props) { return React.createElement("div", { className: "toolbar", role: "toolbar", "aria-label": "Editor Commands" }, props.children); }; // Export main windows/panes to be used separately if desired. GraphiQL.QueryEditor = QueryEditor; GraphiQL.VariableEditor = VariableEditor; GraphiQL.ResultViewer = ResultViewer; // Add a button to the Toolbar. GraphiQL.Button = ToolbarButton; GraphiQL.ToolbarButton = ToolbarButton; // Don't break existing API. // Add a group of buttons to the Toolbar GraphiQL.Group = ToolbarGroup; // Add a menu of items to the Toolbar. GraphiQL.Menu = ToolbarMenu; GraphiQL.MenuItem = ToolbarMenuItem; // Add a select-option input to the Toolbar. GraphiQL.Select = ToolbarSelect; GraphiQL.SelectOption = ToolbarSelectOption; // Configure the UI by providing this Component as a child of GraphiQL. GraphiQL.Footer = function GraphiQLFooter(props) { return React.createElement("div", { className: "footer" }, props.children); }; GraphiQL.formatResult = function (result) { return JSON.stringify(result, null, 2); }; const formatSingleError = error => ({ ...error, // Raise these details even if they're non-enumerable message: error.message, stack: error.stack }); GraphiQL.formatError = function (rawError) { const result = Array.isArray(rawError) ? rawError.map(formatSingleError) : formatSingleError(rawError); return JSON.stringify(result, null, 2); }; const defaultQuery = `# Welcome to GraphiQL # # GraphiQL is an in-browser tool for writing, validating, and # testing GraphQL queries. # # Type queries into this side of the screen, and you will see intelligent # typeaheads aware of the current GraphQL type schema and live syntax and # validation errors highlighted within the text. # # GraphQL queries typically start with a "{" character. Lines that starts # with a # are ignored. # # An example GraphQL query might look like: # # { # field(arg: "value") { # subField # } # } # # Keyboard shortcuts: # # Prettify Query: Shift-Ctrl-P (or press the prettify button above) # # Merge Query: Shift-Ctrl-M (or press the merge button above) # # Run Query: Ctrl-Enter (or press the play button above) # # Auto Complete: Ctrl-Space (or just start typing) # `; // Duck-type promise detection. function isPromise(value) { return typeof value === 'object' && typeof value.then === 'function'; } // Duck-type Observable.take(1).toPromise() function observableToPromise(observable) { if (!isObservable(observable)) { return observable; } return new Promise((resolve, reject) => { const subscription = observable.subscribe(v => { resolve(v); subscription.unsubscribe(); }, reject, () => { reject(new Error('no value resolved')); }); }); } // Duck-type observable detection. function isObservable(value) { return typeof value === 'object' && typeof value.subscribe === 'function'; }