diff --git a/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js b/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js index e77b8d3a4..08449e871 100644 --- a/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js +++ b/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js @@ -5,6 +5,7 @@ import { requestUrlChanged, updateRequestMethod } from 'providers/ReduxStore/sli import HttpMethodSelector from './HttpMethodSelector'; import { useTheme } from 'providers/Theme'; import SendIcon from 'components/Icons/Send'; +import SingleLineEditor from 'components/SingleLineEditor'; import StyledWrapper from './StyledWrapper'; const QueryUrl = ({ item, collection, handleRun }) => { @@ -39,15 +40,10 @@ const QueryUrl = ({ item, collection, handleRun }) => {
- onUrlChange(event.target.value)} + onUrlChange(newValue)} + collection={collection} />
diff --git a/packages/bruno-app/src/components/SingleLineEditor/StyledWrapper.js b/packages/bruno-app/src/components/SingleLineEditor/StyledWrapper.js new file mode 100644 index 000000000..fc84d7f51 --- /dev/null +++ b/packages/bruno-app/src/components/SingleLineEditor/StyledWrapper.js @@ -0,0 +1,33 @@ +import styled from 'styled-components'; + +const StyledWrapper = styled.div` + width: 100%; + height: 30px; + overflow-y: hidden; + + .CodeMirror { + background: transparent; + height: 30px; + font-size: 14px; + line-height: 30px; + + .CodeMirror-lines { + padding: 0; + } + + .CodeMirror-cursor { + height: 20px !important; + margin-top: 5px !important; + } + + pre { + font-family: Inter, sans-serif !important; + } + } + + .cm-variable-valid{color: green} + .cm-variable-invalid{color: red} + .cm-matchhighlight {background-color: yellow} +`; + +export default StyledWrapper; diff --git a/packages/bruno-app/src/components/SingleLineEditor/index.js b/packages/bruno-app/src/components/SingleLineEditor/index.js new file mode 100644 index 000000000..495519cd3 --- /dev/null +++ b/packages/bruno-app/src/components/SingleLineEditor/index.js @@ -0,0 +1,103 @@ +import React, { Component } from 'react'; +import CodeMirror from 'codemirror'; +import each from 'lodash/each'; +import isEqual from 'lodash/isEqual'; +import { findEnvironmentInCollection } from 'utils/collections'; +import StyledWrapper from './StyledWrapper'; + +class SingleLineEditor extends Component { + constructor(props) { + super(props); + this.editorRef = React.createRef(); + this.variables = {}; + } + componentDidMount() { + // Initialize CodeMirror as a single line editor + this.editor = CodeMirror(this.editorRef.current, { + lineWrapping: false, + lineNumbers: false, + autofocus: true, + mode: "brunovariables", + extraKeys: { + "Enter": () => {}, + "Ctrl-Enter": () => {}, + "Cmd-Enter": () => {}, + "Alt-Enter": () => {}, + "Shift-Enter": () => {} + }, + }); + this.editor.setValue(this.props.value) + + this.editor.on('change', (cm) => { + this.props.onChange(cm.getValue()); + }); + this.addOverlay(); + } + + componentDidUpdate(prevProps) { + let variables = this.getEnvironmentVariables(); + if (!isEqual(variables, this.variables)) { + this.addOverlay(); + } + } + + componentWillUnmount() { + 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 = () => { + let variables = this.getEnvironmentVariables(); + this.variables = variables; + + 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 || "text/plain"), variablesOverlay); + }); + + this.editor.setOption('mode', 'brunovariables'); + } + + render() { + return ( + + ); + } +} +export default SingleLineEditor; diff --git a/packages/bruno-app/src/pageComponents/Index/index.js b/packages/bruno-app/src/pageComponents/Index/index.js index b96341f4f..015cfadc8 100644 --- a/packages/bruno-app/src/pageComponents/Index/index.js +++ b/packages/bruno-app/src/pageComponents/Index/index.js @@ -6,7 +6,6 @@ import RequestTabPanel from 'components/RequestTabPanel'; import Sidebar from 'components/Sidebar'; import { useSelector } from 'react-redux'; import StyledWrapper from './StyledWrapper'; -import 'codemirror/lib/codemirror.css'; import 'codemirror/theme/material.css'; import 'codemirror/theme/monokai.css';