mirror of
https://github.com/usebruno/bruno.git
synced 2025-01-08 23:18:54 +01:00
Feat/highlight path params (#2415)
* fix: Update CodeMirror mode to use combinedmode for SingleLineEditor. This will highlight the pathparams in the QueryUrl. * Refactor: Updated url highlighting. * refactor: Improved the hinting part. * refactor: CodeEditor, MultiLineEditor, and QueryEditor to use defineCombinedCodeMirrorMode for highlighting Bruno variables instead of defineCodeMirrorBrunoVariablesMode * refactor: Updated defineCombinedCodeMirrorMode to defineCodeMirrorCombinedVariablesMode. Now the pathparams at the end of the URL is also highlighted. * refactor: Update CodeMirror mode to use defineCodeMirrorBrunoVariablesMode instead of defineCodeMirrorCombinedVariablesMode. Now the path params in the URL will be highlighted on application open. --------- Co-authored-by: Anoop M D <anoop.md1421@gmail.com>
This commit is contained in:
parent
963b197afc
commit
01e93b5c2b
@ -69,6 +69,7 @@ const QueryUrl = ({ item, collection, handleRun }) => {
|
||||
onChange={(newValue) => onUrlChange(newValue)}
|
||||
onRun={handleRun}
|
||||
collection={collection}
|
||||
item={item}
|
||||
/>
|
||||
<div className="flex items-center h-full mr-2 cursor-pointer" id="send-request" onClick={handleRun}>
|
||||
<div
|
||||
|
@ -24,13 +24,15 @@ class SingleLineEditor extends Component {
|
||||
componentDidMount() {
|
||||
// Initialize CodeMirror as a single line editor
|
||||
/** @type {import("codemirror").Editor} */
|
||||
const variables = getAllVariables(this.props.collection, this.props.item);
|
||||
|
||||
this.editor = CodeMirror(this.editorRef.current, {
|
||||
lineWrapping: false,
|
||||
lineNumbers: false,
|
||||
theme: this.props.theme === 'dark' ? 'monokai' : 'default',
|
||||
mode: 'brunovariables',
|
||||
brunoVarInfo: {
|
||||
variables: getAllVariables(this.props.collection)
|
||||
variables
|
||||
},
|
||||
scrollbarStyle: null,
|
||||
tabindex: 0,
|
||||
@ -82,7 +84,7 @@ class SingleLineEditor extends Component {
|
||||
});
|
||||
if (this.props.autocomplete) {
|
||||
this.editor.on('keyup', (cm, event) => {
|
||||
if (!cm.state.completionActive /*Enables keyboard navigation in autocomplete list*/ && event.keyCode != 13) {
|
||||
if (!cm.state.completionActive /*Enables keyboard navigation in autocomplete list*/ && event.key !== 'Enter') {
|
||||
/*Enter - do not open autocomplete list just after item has been selected in it*/
|
||||
CodeMirror.commands.autocomplete(cm, CodeMirror.hint.anyword, { autocomplete: this.props.autocomplete });
|
||||
}
|
||||
@ -90,7 +92,7 @@ class SingleLineEditor extends Component {
|
||||
}
|
||||
this.editor.setValue(String(this.props.value) || '');
|
||||
this.editor.on('change', this._onEdit);
|
||||
this.addOverlay();
|
||||
this.addOverlay(variables);
|
||||
}
|
||||
|
||||
_onEdit = () => {
|
||||
@ -108,10 +110,10 @@ class SingleLineEditor extends Component {
|
||||
// event loop.
|
||||
this.ignoreChangeEvent = true;
|
||||
|
||||
let variables = getAllVariables(this.props.collection);
|
||||
let variables = getAllVariables(this.props.collection, this.props.item);
|
||||
if (!isEqual(variables, this.variables)) {
|
||||
this.editor.options.brunoVarInfo.variables = variables;
|
||||
this.addOverlay();
|
||||
this.addOverlay(variables);
|
||||
}
|
||||
if (this.props.theme !== prevProps.theme && this.editor) {
|
||||
this.editor.setOption('theme', this.props.theme === 'dark' ? 'monokai' : 'default');
|
||||
@ -127,12 +129,10 @@ class SingleLineEditor extends Component {
|
||||
this.editor.getWrapperElement().remove();
|
||||
}
|
||||
|
||||
addOverlay = () => {
|
||||
let variables = getAllVariables(this.props.collection);
|
||||
addOverlay = (variables) => {
|
||||
this.variables = variables;
|
||||
|
||||
defineCodeMirrorBrunoVariablesMode(variables, 'text/plain');
|
||||
this.editor.setOption('mode', 'brunovariables');
|
||||
this.editor.setOption('mode', 'combinedmode');
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -23,10 +23,23 @@ if (!SERVER_RENDERED) {
|
||||
if (!str || !str.length || typeof str !== 'string') {
|
||||
return;
|
||||
}
|
||||
// str is of format {{variableName}}, extract variableName
|
||||
// we are seeing that from the gql query editor, the token string is of format variableName
|
||||
const variableName = str.replace('{{', '').replace('}}', '').trim();
|
||||
const variableValue = interpolate(get(options.variables, variableName), options.variables);
|
||||
|
||||
// str is of format {{variableName}} or :variableName, extract variableName
|
||||
let variableName;
|
||||
let variableValue;
|
||||
|
||||
if (str.startsWith('{{')) {
|
||||
variableName = str.replace('{{', '').replace('}}', '').trim();
|
||||
variableValue = interpolate(get(options.variables, variableName), options.variables);
|
||||
} else if (str.startsWith(':')) {
|
||||
variableName = str.replace(':', '').trim();
|
||||
variableValue =
|
||||
options.variables && options.variables.pathParams ? options.variables.pathParams[variableName] : undefined;
|
||||
}
|
||||
|
||||
if (variableValue === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const into = document.createElement('div');
|
||||
const descriptionDiv = document.createElement('div');
|
||||
|
@ -657,6 +657,18 @@ export const getEnvironmentVariables = (collection) => {
|
||||
return variables;
|
||||
};
|
||||
|
||||
const getPathParams = (item) => {
|
||||
let pathParams = {};
|
||||
if (item && item.request && item.request.params) {
|
||||
item.request.params.forEach((param) => {
|
||||
if (param.type === 'path' && param.name && param.value) {
|
||||
pathParams[param.name] = param.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
return pathParams;
|
||||
};
|
||||
|
||||
export const getTotalRequestCountInCollection = (collection) => {
|
||||
let count = 0;
|
||||
each(collection.items, (item) => {
|
||||
@ -670,12 +682,16 @@ export const getTotalRequestCountInCollection = (collection) => {
|
||||
return count;
|
||||
};
|
||||
|
||||
export const getAllVariables = (collection) => {
|
||||
export const getAllVariables = (collection, item) => {
|
||||
const environmentVariables = getEnvironmentVariables(collection);
|
||||
const pathParams = getPathParams(item);
|
||||
|
||||
return {
|
||||
...environmentVariables,
|
||||
...collection.collectionVariables,
|
||||
pathParams: {
|
||||
...pathParams
|
||||
},
|
||||
process: {
|
||||
env: {
|
||||
...collection.processEnvVariables
|
||||
|
@ -13,32 +13,61 @@ const pathFoundInVariables = (path, obj) => {
|
||||
};
|
||||
|
||||
export const defineCodeMirrorBrunoVariablesMode = (variables, mode) => {
|
||||
CodeMirror.defineMode('brunovariables', function (config, parserConfig) {
|
||||
let variablesOverlay = {
|
||||
token: function (stream, state) {
|
||||
CodeMirror.defineMode('combinedmode', function (config, parserConfig) {
|
||||
const variablesOverlay = {
|
||||
token: function (stream) {
|
||||
if (stream.match('{{', true)) {
|
||||
let ch;
|
||||
let word = '';
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == '}' && stream.next() == '}') {
|
||||
if (ch === '}' && stream.peek() === '}') {
|
||||
stream.eat('}');
|
||||
let found = pathFoundInVariables(word, variables);
|
||||
if (found) {
|
||||
return 'variable-valid random-' + (Math.random() + 1).toString(36).substring(9);
|
||||
} else {
|
||||
return 'variable-invalid random-' + (Math.random() + 1).toString(36).substring(9);
|
||||
}
|
||||
// Random classname added so adjacent variables are not rendered in the same SPAN by CodeMirror.
|
||||
const found = pathFoundInVariables(word, variables);
|
||||
const status = found ? 'valid' : 'invalid';
|
||||
const randomClass = `random-${(Math.random() + 1).toString(36).substring(9)}`;
|
||||
return `variable-${status} ${randomClass}`;
|
||||
}
|
||||
word += ch;
|
||||
}
|
||||
}
|
||||
while (stream.next() != null && !stream.match('{{', false)) {}
|
||||
stream.skipTo('{{') || stream.skipToEnd();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return CodeMirror.overlayMode(CodeMirror.getMode(config, parserConfig.backdrop || mode), variablesOverlay);
|
||||
const urlPathParamsOverlay = {
|
||||
token: function (stream) {
|
||||
if (stream.match(':', true)) {
|
||||
let ch;
|
||||
let word = '';
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch === '/' || ch === '?' || ch === '&' || ch === '=') {
|
||||
stream.backUp(1);
|
||||
const found = pathFoundInVariables(word, variables?.pathParams);
|
||||
const status = found ? 'valid' : 'invalid';
|
||||
const randomClass = `random-${(Math.random() + 1).toString(36).substring(9)}`;
|
||||
return `variable-${status} ${randomClass}`;
|
||||
}
|
||||
word += ch;
|
||||
}
|
||||
|
||||
// If we've consumed all characters and the word is not empty, it might be a path parameter at the end of the URL.
|
||||
if (word) {
|
||||
const found = pathFoundInVariables(word, variables?.pathParams);
|
||||
const status = found ? 'valid' : 'invalid';
|
||||
const randomClass = `random-${(Math.random() + 1).toString(36).substring(9)}`;
|
||||
return `variable-${status} ${randomClass}`;
|
||||
}
|
||||
}
|
||||
stream.skipTo(':') || stream.skipToEnd();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return CodeMirror.overlayMode(
|
||||
CodeMirror.overlayMode(CodeMirror.getMode(config, parserConfig.backdrop || mode), variablesOverlay),
|
||||
urlPathParamsOverlay
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user