From 6852cc6631813d7e51144ad1e0c0f9b68f5885b8 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Wed, 1 Feb 2023 06:07:43 +0530 Subject: [PATCH] feat: refactored logic around query param parsing --- packages/bruno-app/package.json | 1 + .../RequestPane/QueryEditor/index.js | 2 +- .../SingleLineEditor/StyledWrapper.js | 7 ++- .../src/components/SingleLineEditor/index.js | 29 +++++++++++-- packages/bruno-app/src/utils/url/index.js | 28 ++++++------ .../bruno-app/src/utils/url/index.spec.js | 43 +++++++++++++++++++ 6 files changed, 92 insertions(+), 18 deletions(-) create mode 100644 packages/bruno-app/src/utils/url/index.spec.js diff --git a/packages/bruno-app/package.json b/packages/bruno-app/package.json index 36b1a165b..5080f9d46 100644 --- a/packages/bruno-app/package.json +++ b/packages/bruno-app/package.json @@ -7,6 +7,7 @@ "build": "next build && next export", "start": "next start", "lint": "next lint", + "test": "jest", "prettier": "prettier --write \"./src/**/*.{js,jsx,json,ts,tsx}\"" }, "dependencies": { diff --git a/packages/bruno-app/src/components/RequestPane/QueryEditor/index.js b/packages/bruno-app/src/components/RequestPane/QueryEditor/index.js index 8cdf90b22..667c61e86 100644 --- a/packages/bruno-app/src/components/RequestPane/QueryEditor/index.js +++ b/packages/bruno-app/src/components/RequestPane/QueryEditor/index.js @@ -160,12 +160,12 @@ export default class QueryEditor extends React.Component { if (this.props.theme !== prevProps.theme && this.editor) { this.editor.setOption('theme', this.props.theme === 'dark' ? 'monokai' : 'default'); } - this.ignoreChangeEvent = false; let variables = getEnvironmentVariables(this.props.collection); if (!isEqual(variables, this.variables)) { this.editor.options.brunoVarInfo.variables = variables; this.addOverlay(); } + this.ignoreChangeEvent = false; } componentWillUnmount() { diff --git a/packages/bruno-app/src/components/SingleLineEditor/StyledWrapper.js b/packages/bruno-app/src/components/SingleLineEditor/StyledWrapper.js index 4155c64d7..ecea2d333 100644 --- a/packages/bruno-app/src/components/SingleLineEditor/StyledWrapper.js +++ b/packages/bruno-app/src/components/SingleLineEditor/StyledWrapper.js @@ -1,13 +1,14 @@ import styled from 'styled-components'; const StyledWrapper = styled.div` + width: 100%; height: 30px; overflow-y: hidden; overflow-x: hidden; .CodeMirror { background: transparent; - height: 30px; + height: 34px; font-size: 14px; line-height: 30px; overflow: hidden; @@ -16,6 +17,10 @@ const StyledWrapper = styled.div` display: none !important; } + .CodeMirror-scroll { + overflow: hidden !important; + } + .CodeMirror-hscrollbar { display: none !important; } diff --git a/packages/bruno-app/src/components/SingleLineEditor/index.js b/packages/bruno-app/src/components/SingleLineEditor/index.js index 700751b86..4c7b6c748 100644 --- a/packages/bruno-app/src/components/SingleLineEditor/index.js +++ b/packages/bruno-app/src/components/SingleLineEditor/index.js @@ -14,6 +14,10 @@ if (!SERVER_RENDERED) { class SingleLineEditor extends Component { constructor(props) { super(props); + // Keep a cached version of the value, this cache will be updated when the + // editor is updated, which can later be used to protect the editor from + // unnecessary updates during the update lifecycle. + this.cachedValue = props.value || ''; this.editorRef = React.createRef(); this.variables = {}; } @@ -68,14 +72,26 @@ class SingleLineEditor extends Component { 'Tab': () => {} }, }); - this.editor.setValue(this.props.value); - this.editor.on('change', (cm) => { - this.props.onChange(cm.getValue()); - }); + this.editor.setValue(this.props.value || ''); + this.editor.on('change', this._onEdit); this.addOverlay(); } + _onEdit = () => { + if (!this.ignoreChangeEvent && this.editor) { + this.cachedValue = this.editor.getValue(); + if (this.props.onChange) { + this.props.onChange(this.cachedValue); + } + } + }; + componentDidUpdate(prevProps) { + // Ensure the changes caused by this update are not interpretted as + // user-input changes which could otherwise result in an infinite + // event loop. + this.ignoreChangeEvent = true; + let variables = getEnvironmentVariables(this.props.collection); if (!isEqual(variables, this.variables)) { this.editor.options.brunoVarInfo.variables = variables; @@ -84,6 +100,11 @@ class SingleLineEditor extends Component { if (this.props.theme !== prevProps.theme && this.editor) { this.editor.setOption('theme', this.props.theme === 'dark' ? 'monokai' : 'default'); } + if (this.props.value !== prevProps.value && this.props.value !== this.cachedValue && this.editor) { + this.cachedValue = this.props.value; + this.editor.setValue(this.props.value); + } + this.ignoreChangeEvent = false; } componentWillUnmount() { diff --git a/packages/bruno-app/src/utils/url/index.js b/packages/bruno-app/src/utils/url/index.js index 63b6b4fc9..d8166f52c 100644 --- a/packages/bruno-app/src/utils/url/index.js +++ b/packages/bruno-app/src/utils/url/index.js @@ -1,25 +1,29 @@ import isEmpty from 'lodash/isEmpty'; import trim from 'lodash/trim'; import each from 'lodash/each'; -import splitOnFirst from 'split-on-first'; +import filter from 'lodash/filter'; + +const hasLength = (str) => { + if(!str || !str.length) { + return false; + } + + str = str.trim(); + + return str.length > 0; +}; export const parseQueryParams = (query) => { if (!query || !query.length) { return []; } - let params = query.split('&'); - let result = []; + let params = query.split('&').map(param => { + let [name, value = ''] = param.split('='); + return { name, value }; + }); - for (let i = 0; i < params.length; i++) { - let pair = splitOnFirst(params[i], '='); - result.push({ - name: pair[0], - value: pair[1] - }); - } - - return result; + return filter(params, (p) => hasLength(p.name)); }; export const stringifyQueryParams = (params) => { diff --git a/packages/bruno-app/src/utils/url/index.spec.js b/packages/bruno-app/src/utils/url/index.spec.js new file mode 100644 index 000000000..5dda69e4b --- /dev/null +++ b/packages/bruno-app/src/utils/url/index.spec.js @@ -0,0 +1,43 @@ +import { parseQueryParams } from './index'; + +describe('Url Utils - parseQueryParams', () => { + it('should parse query - case 1', () => { + const params = parseQueryParams(""); + expect(params).toEqual([]); + }); + + it('should parse query - case 2', () => { + const params = parseQueryParams("a"); + expect(params).toEqual([{name: 'a', value: ''}]); + }); + + it('should parse query - case 3', () => { + const params = parseQueryParams("a="); + expect(params).toEqual([{name: 'a', value: ''}]); + }); + + it('should parse query - case 4', () => { + const params = parseQueryParams("a=1"); + expect(params).toEqual([{name: 'a', value: '1'}]); + }); + + it('should parse query - case 5', () => { + const params = parseQueryParams("a=1&"); + expect(params).toEqual([{name: 'a', value: '1'}]); + }); + + it('should parse query - case 6', () => { + const params = parseQueryParams("a=1&b"); + expect(params).toEqual([{name: 'a', value: '1'}, {name: 'b', value: ''}]); + }); + + it('should parse query - case 7', () => { + const params = parseQueryParams("a=1&b="); + expect(params).toEqual([{name: 'a', value: '1'}, {name: 'b', value: ''}]); + }); + + it('should parse query - case 8', () => { + const params = parseQueryParams("a=1&b=2"); + expect(params).toEqual([{name: 'a', value: '1'}, {name: 'b', value: '2'}]); + }); +});