mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-16 04:11:29 +00:00
fix: path-param variable edit popup (#6955)
Co-authored-by: shubh-bruno <shubh-bruno@shubh-bruno.local>
This commit is contained in:
@@ -55,7 +55,8 @@ import {
|
||||
addFolderVar,
|
||||
updateFolderVar,
|
||||
addCollectionVar,
|
||||
updateCollectionVar
|
||||
updateCollectionVar,
|
||||
updatePathParam
|
||||
} from './index';
|
||||
|
||||
import { each } from 'lodash';
|
||||
@@ -2007,7 +2008,23 @@ export const updateVariableInScope = (variableName, newValue, scopeInfo, collect
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
}
|
||||
case 'pathParam': {
|
||||
const { item } = data;
|
||||
const params = item.draft ? get(item, 'draft.request.params', []) : get(item, 'request.params', []);
|
||||
const pathParam = params.find((p) => p.type === 'path' && p.name === variableName);
|
||||
|
||||
if (pathParam) {
|
||||
const updatedParam = { ...pathParam, value: newValue };
|
||||
dispatch(updatePathParam({
|
||||
pathParam: updatedParam,
|
||||
itemUid: item.uid,
|
||||
collectionUid: collection.uid
|
||||
}));
|
||||
}
|
||||
return dispatch(saveRequest(item.uid, collection.uid, true))
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
}
|
||||
default:
|
||||
return reject(new Error(`Unknown scope type: ${type}`));
|
||||
}
|
||||
|
||||
@@ -75,7 +75,8 @@ const getScopeLabel = (scopeType) => {
|
||||
'process.env': 'Process Env',
|
||||
'dynamic': 'Dynamic',
|
||||
'oauth2': 'OAuth2',
|
||||
'undefined': 'Undefined'
|
||||
'undefined': 'Undefined',
|
||||
'pathParam': 'Path Param'
|
||||
};
|
||||
return labels[scopeType] || scopeType;
|
||||
};
|
||||
@@ -209,6 +210,12 @@ export const renderVarInfo = (token, options) => {
|
||||
value: variableValue || '',
|
||||
data: null
|
||||
};
|
||||
} else if (token.string.startsWith('/:')) {
|
||||
scopeInfo = {
|
||||
type: 'pathParam',
|
||||
value: variableValue || '',
|
||||
data: { item }
|
||||
};
|
||||
} else {
|
||||
// Detect variable scope
|
||||
scopeInfo = getVariableScope(variableName, collection, item);
|
||||
@@ -687,88 +694,95 @@ if (!SERVER_RENDERED) {
|
||||
const state = cm.state.brunoVarInfo;
|
||||
const options = state.options;
|
||||
|
||||
// Get the full line text where the hover happened
|
||||
const line = cm.getLine(pos.line);
|
||||
if (!line) return;
|
||||
|
||||
// If the line doesn't even contain both braces, no need to run loops
|
||||
if (!line.includes('{{') || !line.includes('}}')) {
|
||||
return;
|
||||
// ---------- 1) MODE: Double-Brace Variable {{ ... }} ----------
|
||||
// We check this first as it's the most common variable type.
|
||||
if (line.includes('{{') && line.includes('}}')) {
|
||||
// Check if the cursor is roughly between a '{{' to the left and '}}' to the right
|
||||
if (line.lastIndexOf('{{', pos.ch) !== -1 && line.indexOf('}}', pos.ch) !== -1) {
|
||||
let start = pos.ch;
|
||||
let end = pos.ch;
|
||||
|
||||
// Scan LEFT to find the nearest '{{'
|
||||
while (start > 0) {
|
||||
const leftTwo = line.substring(start - 2, start);
|
||||
if (leftTwo === '{{') {
|
||||
start -= 2;
|
||||
break;
|
||||
}
|
||||
// If we hit a '}}' while looking for '{{', the cursor is outside a pair
|
||||
if (leftTwo === '}}') break;
|
||||
start--;
|
||||
}
|
||||
|
||||
// Validate we actually found a '{{'
|
||||
if (start >= 0 && line.substring(start, start + 2) === '{{') {
|
||||
// Scan RIGHT to find the nearest '}}'
|
||||
while (end < line.length) {
|
||||
const rightTwo = line.substring(end, end + 2);
|
||||
if (rightTwo === '}}') {
|
||||
end += 2;
|
||||
break;
|
||||
}
|
||||
// If we hit another '{{' before a closing '}}', the structure is invalid
|
||||
if (rightTwo === '{{') {
|
||||
end = line.length + 1;
|
||||
break;
|
||||
}
|
||||
end++;
|
||||
}
|
||||
|
||||
// Validate the final string and show popup
|
||||
if (end <= line.length && line.substring(end - 2, end) === '}}') {
|
||||
const fullVariableString = line.substring(start, end);
|
||||
const inner = fullVariableString.slice(2, -2).trim();
|
||||
|
||||
if (inner) {
|
||||
const token = { string: fullVariableString, start, end };
|
||||
const brunoVarInfo = renderVarInfo(token, options);
|
||||
if (brunoVarInfo) {
|
||||
showPopup(cm, box, brunoVarInfo);
|
||||
return; // EXIT: We found a variable, don't look for path params
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// lastIndexOf searches backward from the cursor indexOf searches forward
|
||||
if (line.lastIndexOf('{{', pos.ch) === -1 || line.indexOf('}}', pos.ch) === -1) {
|
||||
return;
|
||||
}
|
||||
let start = pos.ch;
|
||||
let end = pos.ch;
|
||||
// ---------- 2) MODE: Path Parameter /:varName ----------
|
||||
// If we didn't return from the brace logic, check if cursor is on a path param
|
||||
const pathParamStart = line.substring(0, pos.ch + 1).lastIndexOf('/:');
|
||||
|
||||
// ---------- Find opening '{{' to the LEFT ----------
|
||||
while (start > 0) {
|
||||
const leftTwo = line.substring(start - 2, start);
|
||||
if (pathParamStart !== -1) {
|
||||
let pathValueEnd = pathParamStart + 2;
|
||||
|
||||
// If we find opening braces, stop
|
||||
if (leftTwo === '{{') {
|
||||
start -= 2;
|
||||
break;
|
||||
// Path params end at the next URL separator (/, ?, &, =) or end of line
|
||||
const separators = ['/', '?', '&', '='];
|
||||
while (pathValueEnd < line.length && !separators.includes(line[pathValueEnd])) {
|
||||
pathValueEnd++;
|
||||
}
|
||||
|
||||
// If we cross a closing braces before finding '{{', we're not inside a variable
|
||||
if (leftTwo === '}}') {
|
||||
return;
|
||||
// Check if cursor is actually inside the detected /:param range
|
||||
if (pos.ch >= pathParamStart && pos.ch < pathValueEnd) {
|
||||
const fullVariableString = line.substring(pathParamStart, pathValueEnd);
|
||||
|
||||
// Ensure it's not just "/:" but has a name (e.g., "/:id")
|
||||
if (fullVariableString.length > 2) {
|
||||
const token = {
|
||||
string: fullVariableString,
|
||||
start: pathParamStart,
|
||||
end: pathValueEnd
|
||||
};
|
||||
const brunoVarInfo = renderVarInfo(token, options);
|
||||
if (brunoVarInfo) {
|
||||
showPopup(cm, box, brunoVarInfo);
|
||||
return; // EXIT: Popup shown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start--;
|
||||
}
|
||||
|
||||
// If we reached the start of the line and didn't match '{{', return
|
||||
if (start < 0 || line.substring(start, start + 2) !== '{{') {
|
||||
return;
|
||||
}
|
||||
|
||||
// ---------- Find closing '}}' to the RIGHT ----------
|
||||
while (end < line.length) {
|
||||
const rightTwo = line.substring(end, end + 2);
|
||||
|
||||
// If we find closing braces, stop
|
||||
if (rightTwo === '}}') {
|
||||
end += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
// If we hit another '{{' before a '}}', then this isn't a valid enclosing pair
|
||||
if (rightTwo === '{{') {
|
||||
return;
|
||||
}
|
||||
|
||||
end++;
|
||||
}
|
||||
// If we reached end-of-line without finding '}}', return
|
||||
if (end > line.length || line.substring(end - 2, end) !== '}}') {
|
||||
return;
|
||||
}
|
||||
|
||||
const fullVariableString = line.substring(start, end);
|
||||
|
||||
// Basic validation to ensure it's a non-empty variable
|
||||
if (!fullVariableString.startsWith('{{') || !fullVariableString.endsWith('}}')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent tooltips for empty variables like {{ }}
|
||||
const inner = fullVariableString.slice(2, -2).trim();
|
||||
if (!inner) return;
|
||||
|
||||
// Build a token object compatible with renderVarInfo
|
||||
const token = {
|
||||
string: fullVariableString,
|
||||
start: start,
|
||||
end: end
|
||||
};
|
||||
|
||||
const brunoVarInfo = renderVarInfo(token, options);
|
||||
if (brunoVarInfo) {
|
||||
showPopup(cm, box, brunoVarInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user