feat: refactor codemirror bruno variables mode

This commit is contained in:
Anoop M D 2023-01-21 01:17:27 +05:30
parent 60c3d41c8e
commit 60fc13c765
12 changed files with 99 additions and 86 deletions

View File

@ -30,7 +30,6 @@ const StyledWrapper = styled.div`
.cm-variable-valid{color: green} .cm-variable-valid{color: green}
.cm-variable-invalid{color: red} .cm-variable-invalid{color: red}
.cm-matchhighlight {background-color: yellow}
`; `;
export default StyledWrapper; export default StyledWrapper;

View File

@ -6,6 +6,9 @@
*/ */
import React from 'react'; import React from 'react';
import isEqual from 'lodash/isEqual';
import { getEnvironmentVariables } from 'utils/collections';
import { defineCodeMirrorBrunoVariablesMode } from 'utils/common/codemirror';
import StyledWrapper from './StyledWrapper'; import StyledWrapper from './StyledWrapper';
let CodeMirror; let CodeMirror;
@ -15,7 +18,7 @@ if (!SERVER_RENDERED) {
CodeMirror = require('codemirror'); CodeMirror = require('codemirror');
} }
export default class QueryEditor extends React.Component { export default class CodeEditor extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -23,6 +26,7 @@ export default class QueryEditor extends React.Component {
// editor is updated, which can later be used to protect the editor from // editor is updated, which can later be used to protect the editor from
// unnecessary updates during the update lifecycle. // unnecessary updates during the update lifecycle.
this.cachedValue = props.value || ''; this.cachedValue = props.value || '';
this.variables = {};
} }
componentDidMount() { componentDidMount() {
@ -31,7 +35,6 @@ export default class QueryEditor extends React.Component {
lineNumbers: true, lineNumbers: true,
lineWrapping: true, lineWrapping: true,
tabSize: 2, tabSize: 2,
highlightSelectionMatches: { showToken: /\w/, annotateScrollbar: true },
mode: this.props.mode || 'application/ld+json', mode: this.props.mode || 'application/ld+json',
keyMap: 'sublime', keyMap: 'sublime',
autoCloseBrackets: true, autoCloseBrackets: true,
@ -93,7 +96,10 @@ export default class QueryEditor extends React.Component {
} }
if(this.editor) { if(this.editor) {
this.addOverlay(); let variables = getEnvironmentVariables(this.props.collection);
if (!isEqual(variables, this.variables)) {
this.addOverlay();
}
} }
if (this.props.theme !== prevProps.theme && this.editor) { if (this.props.theme !== prevProps.theme && this.editor) {
@ -122,37 +128,11 @@ export default class QueryEditor extends React.Component {
} }
addOverlay = () => { addOverlay = () => {
var variables = {
"host": "",
"token": ""
};
const mode = this.props.mode || 'application/ld+json'; const mode = this.props.mode || 'application/ld+json';
let variables = getEnvironmentVariables(this.props.collection);
this.variables = variables;
CodeMirror.defineMode("brunovariables", function(config, parserConfig) { defineCodeMirrorBrunoVariablesMode(variables, mode);
let variablesOverlay = {
token: function(stream, state) {
if (stream.match("{{", true)) {
let ch;
let word = "";
while ((ch = stream.next()) != null) {
if (ch == "}" && stream.next() == "}") {
stream.eat("}");
if (word in variables) {
return "variable-valid";
} else {
return "variable-invalid";
}
}
word += ch;
}
}
while (stream.next() != null && !stream.match("{{", false)) {}
return null;
}
};
return CodeMirror.overlayMode(CodeMirror.getMode(config, parserConfig.backdrop || mode), variablesOverlay);
});
this.editor.setOption('mode', 'brunovariables'); this.editor.setOption('mode', 'brunovariables');
} }

View File

@ -67,6 +67,7 @@ const GraphQLRequestPane = ({ item, collection, leftPaneWidth, onSchemaLoad, tog
switch (tab) { switch (tab) {
case 'query': { case 'query': {
return <QueryEditor return <QueryEditor
collection={collection}
theme={storedTheme} theme={storedTheme}
schema={schema} schema={schema}
width={leftPaneWidth} width={leftPaneWidth}

View File

@ -29,6 +29,9 @@ const StyledWrapper = styled.div`
.cm-s-monokai span.cm-atom{ .cm-s-monokai span.cm-atom{
color: #569cd6 !important; color: #569cd6 !important;
} }
.cm-variable-valid{color: green}
.cm-variable-invalid{color: red}
`; `;
export default StyledWrapper; export default StyledWrapper;

View File

@ -6,7 +6,10 @@
*/ */
import React from 'react'; import React from 'react';
import isEqual from 'lodash/isEqual';
import MD from 'markdown-it'; import MD from 'markdown-it';
import { getEnvironmentVariables } from 'utils/collections';
import { defineCodeMirrorBrunoVariablesMode } from 'utils/common/codemirror';
import StyledWrapper from './StyledWrapper'; import StyledWrapper from './StyledWrapper';
import onHasCompletion from './onHasCompletion'; import onHasCompletion from './onHasCompletion';
@ -29,6 +32,7 @@ export default class QueryEditor extends React.Component {
// editor is updated, which can later be used to protect the editor from // editor is updated, which can later be used to protect the editor from
// unnecessary updates during the update lifecycle. // unnecessary updates during the update lifecycle.
this.cachedValue = props.value || ''; this.cachedValue = props.value || '';
this.variables = {};
} }
componentDidMount() { componentDidMount() {
@ -129,6 +133,7 @@ export default class QueryEditor extends React.Component {
editor.on('hasCompletion', this._onHasCompletion); editor.on('hasCompletion', this._onHasCompletion);
editor.on('beforeChange', this._onBeforeChange); editor.on('beforeChange', this._onBeforeChange);
} }
this.addOverlay();
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
@ -152,6 +157,10 @@ export default class QueryEditor extends React.Component {
this.editor.setOption('theme', this.props.theme === 'dark' ? 'monokai' : 'default'); this.editor.setOption('theme', this.props.theme === 'dark' ? 'monokai' : 'default');
} }
this.ignoreChangeEvent = false; this.ignoreChangeEvent = false;
let variables = getEnvironmentVariables(this.props.collection);
if (!isEqual(variables, this.variables)) {
this.addOverlay();
}
} }
componentWillUnmount() { componentWillUnmount() {
@ -163,6 +172,15 @@ export default class QueryEditor extends React.Component {
} }
} }
addOverlay = () => {
let variables = getEnvironmentVariables(this.props.collection);
this.variables = variables;
console.log(variables);
defineCodeMirrorBrunoVariablesMode(variables, "text/plain");
this.editor.setOption('mode', 'brunovariables');
}
render() { render() {
return ( return (
<StyledWrapper <StyledWrapper

View File

@ -45,7 +45,7 @@ const RequestBody = ({ item, collection }) => {
return ( return (
<StyledWrapper className="w-full"> <StyledWrapper className="w-full">
<CodeEditor theme={storedTheme} value={bodyContent[bodyMode] || ''} onEdit={onEdit} onRun={onRun} onSave={onSave} mode={codeMirrorMode[bodyMode]} /> <CodeEditor collection={collection} theme={storedTheme} value={bodyContent[bodyMode] || ''} onEdit={onEdit} onRun={onRun} onSave={onSave} mode={codeMirrorMode[bodyMode]} />
</StyledWrapper> </StyledWrapper>
); );
} }

View File

@ -17,7 +17,7 @@ const QueryResult = ({ item, collection, value, width }) => {
return ( return (
<StyledWrapper className="px-3 w-full" style={{ maxWidth: width }}> <StyledWrapper className="px-3 w-full" style={{ maxWidth: width }}>
<div className="h-full"> <div className="h-full">
<CodeEditor theme={storedTheme} onRun={onRun} value={value || ''} readOnly /> <CodeEditor collection={collection} theme={storedTheme} onRun={onRun} value={value || ''} readOnly />
</div> </div>
</StyledWrapper> </StyledWrapper>
); );

View File

@ -27,7 +27,6 @@ const StyledWrapper = styled.div`
.cm-variable-valid{color: green} .cm-variable-valid{color: green}
.cm-variable-invalid{color: red} .cm-variable-invalid{color: red}
.cm-matchhighlight {background-color: yellow}
`; `;
export default StyledWrapper; export default StyledWrapper;

View File

@ -1,10 +1,16 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import CodeMirror from 'codemirror';
import each from 'lodash/each';
import isEqual from 'lodash/isEqual'; import isEqual from 'lodash/isEqual';
import { findEnvironmentInCollection } from 'utils/collections'; import { getEnvironmentVariables } from 'utils/collections';
import { defineCodeMirrorBrunoVariablesMode } from 'utils/common/codemirror';
import StyledWrapper from './StyledWrapper'; import StyledWrapper from './StyledWrapper';
let CodeMirror;
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
if (!SERVER_RENDERED) {
CodeMirror = require('codemirror');
}
class SingleLineEditor extends Component { class SingleLineEditor extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -35,7 +41,7 @@ class SingleLineEditor extends Component {
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
let variables = this.getEnvironmentVariables(); let variables = getEnvironmentVariables(this.props.collection);
if (!isEqual(variables, this.variables)) { if (!isEqual(variables, this.variables)) {
this.addOverlay(); this.addOverlay();
} }
@ -45,52 +51,11 @@ class SingleLineEditor extends Component {
this.editor.getWrapperElement().remove(); this.editor.getWrapperElement().remove();
} }
getEnvironmentVariables = () => {
let variables = {};
const collection = this.props.collection;
if (collection) {
const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
if (environment) {
each(environment.variables, (variable) => {
if(variable.name && variable.value && variable.enabled) {
variables[variable.name] = variable.value;
}
});
}
}
return variables;
}
addOverlay = () => { addOverlay = () => {
let variables = this.getEnvironmentVariables(); let variables = getEnvironmentVariables(this.props.collection);
this.variables = variables; this.variables = variables;
CodeMirror.defineMode("brunovariables", function(config, parserConfig) { defineCodeMirrorBrunoVariablesMode(variables, "text/plain");
let variablesOverlay = {
token: function(stream, state) {
if (stream.match("{{", true)) {
let ch;
let word = "";
while ((ch = stream.next()) != null) {
if (ch == "}" && stream.next() == "}") {
stream.eat("}");
if (word in variables) {
return "variable-valid";
} else {
return "variable-invalid";
}
}
word += ch;
}
}
while (stream.next() != null && !stream.match("{{", false)) {}
return null;
}
};
return CodeMirror.overlayMode(CodeMirror.getMode(config, parserConfig.backdrop || "text/plain"), variablesOverlay);
});
this.editor.setOption('mode', 'brunovariables'); this.editor.setOption('mode', 'brunovariables');
} }

View File

@ -18,15 +18,12 @@ if (!SERVER_RENDERED) {
require('codemirror/addon/fold/foldgutter'); require('codemirror/addon/fold/foldgutter');
require('codemirror/addon/mode/overlay'); require('codemirror/addon/mode/overlay');
require('codemirror/addon/hint/show-hint'); require('codemirror/addon/hint/show-hint');
require('codemirror/addon/scroll/annotatescrollbar');
require('codemirror/keymap/sublime'); require('codemirror/keymap/sublime');
require('codemirror/addon/comment/comment'); require('codemirror/addon/comment/comment');
require('codemirror/addon/edit/closebrackets'); require('codemirror/addon/edit/closebrackets');
require('codemirror/addon/search/search'); require('codemirror/addon/search/search');
require('codemirror/addon/search/searchcursor'); require('codemirror/addon/search/searchcursor');
require('codemirror/addon/search/jump-to-line'); require('codemirror/addon/search/jump-to-line');
require('codemirror/addon/search/matchesonscrollbar');
require('codemirror/addon/search/match-highlighter');
require('codemirror/addon/dialog/dialog'); require('codemirror/addon/dialog/dialog');
require('codemirror-graphql/hint'); require('codemirror-graphql/hint');

View File

@ -549,3 +549,19 @@ export const getDefaultRequestPaneTab = (item) => {
return 'query'; return 'query';
} }
}; };
export const getEnvironmentVariables = (collection) => {
let variables = {};
if (collection) {
const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
if (environment) {
each(environment.variables, (variable) => {
if(variable.name && variable.value && variable.enabled) {
variables[variable.name] = variable.value;
}
});
}
}
return variables;
}

View File

@ -0,0 +1,35 @@
let CodeMirror;
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
if (!SERVER_RENDERED) {
CodeMirror = require('codemirror');
}
export const defineCodeMirrorBrunoVariablesMode = (variables, mode) => {
CodeMirror.defineMode("brunovariables", function(config, parserConfig) {
let variablesOverlay = {
token: function(stream, state) {
if (stream.match("{{", true)) {
let ch;
let word = "";
while ((ch = stream.next()) != null) {
if (ch == "}" && stream.next() == "}") {
stream.eat("}");
if (word in variables) {
return "variable-valid";
} else {
return "variable-invalid";
}
}
word += ch;
}
}
while (stream.next() != null && !stream.match("{{", false)) {}
return null;
}
};
return CodeMirror.overlayMode(CodeMirror.getMode(config, parserConfig.backdrop || mode), variablesOverlay);
});
};