mirror of
https://github.com/usebruno/bruno.git
synced 2026-07-01 16:44:16 +00:00
* feat: add stop request button in api url bar * docs: add farsi translation * fix: handle escaped forward slashes by fast-json-format library upgrade * refactor: change ui to use one from Websockets * chore: cleanup * fix: lint issues * Replace IconPlayerStop with IconSquareRoundedX * update json request and response formatting logic * chore: format changes * chore: remove un-needed diffs * chore: sanitize * bugfix(#5939): curl import fails for custom content-types * chore: remove un-needed diffs * chore: enhance response handling for streaming * fix: disable requestid check for tests and assertions to be updated after streaming result * chore: housekeeping * fix: streamline loading and cancel request icon logic * chore: formatting * fix: multiple co-pilot changes * fix: handle in folders * feat: add WaitGroup utility for managing concurrent tasks * refactor: remove WaitGroup utility and clean up network IPC logic * refactor: remove unused setTimeout import and clean up post script execution * refactor: clean up post-response script execution logic * undiff * re-align * refactor: streamline post-response script execution - Cleaned up formatting and improved readability of the post-response script execution logic. - Consolidated parameters in function calls for consistency. * fix: keep original dataBuffer for saving response --------- Co-authored-by: adarshajit <adarshajit@gmail.com> Co-authored-by: sajadoncode <sajadoncode@gmail.com> Co-authored-by: lohit-bruno <lohit@usebruno.com> Co-authored-by: Bijin A B <bijin@usebruno.com> Co-authored-by: Pragadesh-45 <temporaryg7904@gmail.com> Co-authored-by: Anoop M D <anoop@usebruno.com> Co-authored-by: Anoop M D <anoop.md1421@gmail.com> Co-authored-by: Dawid Góra <dawidgora@icloud.com>
186 lines
6.1 KiB
JavaScript
186 lines
6.1 KiB
JavaScript
import React, { useState, useEffect, useRef, useMemo } from 'react';
|
|
import get from 'lodash/get';
|
|
import { useDispatch } from 'react-redux';
|
|
import { requestUrlChanged, updateRequestMethod } from 'providers/ReduxStore/slices/collections';
|
|
import { cancelRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
|
import HttpMethodSelector from './HttpMethodSelector';
|
|
import { useTheme } from 'providers/Theme';
|
|
import { IconDeviceFloppy, IconArrowRight, IconCode, IconSquareRoundedX } from '@tabler/icons';
|
|
import SingleLineEditor from 'components/SingleLineEditor';
|
|
import { isMacOS } from 'utils/common/platform';
|
|
import { hasRequestChanges } from 'utils/collections';
|
|
import StyledWrapper from './StyledWrapper';
|
|
import GenerateCodeItem from 'components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/index';
|
|
import toast from 'react-hot-toast';
|
|
|
|
const QueryUrl = ({ item, collection, handleRun }) => {
|
|
const { theme, storedTheme } = useTheme();
|
|
const dispatch = useDispatch();
|
|
const method = item.draft ? get(item, 'draft.request.method') : get(item, 'request.method');
|
|
const url = item.draft ? get(item, 'draft.request.url', '') : get(item, 'request.url', '');
|
|
const isMac = isMacOS();
|
|
const saveShortcut = isMac ? 'Cmd + S' : 'Ctrl + S';
|
|
const editorRef = useRef(null);
|
|
const isGrpc = item.type === 'grpc-request';
|
|
const isLoading = ['queued', 'sending'].includes(item.requestState);
|
|
|
|
const [methodSelectorWidth, setMethodSelectorWidth] = useState(90);
|
|
const [generateCodeItemModalOpen, setGenerateCodeItemModalOpen] = useState(false);
|
|
const hasChanges = useMemo(() => hasRequestChanges(item), [item]);
|
|
|
|
useEffect(() => {
|
|
const el = document.querySelector('.method-selector-container');
|
|
setMethodSelectorWidth(el.offsetWidth);
|
|
}, [method]);
|
|
|
|
const onSave = (finalValue) => {
|
|
dispatch(saveRequest(item.uid, collection.uid));
|
|
};
|
|
|
|
const onUrlChange = (value) => {
|
|
if (!editorRef.current?.editor) return;
|
|
const editor = editorRef.current.editor;
|
|
const cursor = editor.getCursor();
|
|
|
|
const finalUrl = value?.trim() ?? value;
|
|
|
|
dispatch(
|
|
requestUrlChanged({
|
|
itemUid: item.uid,
|
|
collectionUid: collection.uid,
|
|
url: finalUrl
|
|
})
|
|
);
|
|
|
|
// Restore cursor position only if URL was trimmed
|
|
if (finalUrl !== value) {
|
|
setTimeout(() => {
|
|
if (editor) {
|
|
editor.setCursor(cursor);
|
|
}
|
|
}, 0);
|
|
}
|
|
};
|
|
|
|
const onMethodSelect = (verb) => {
|
|
dispatch(
|
|
updateRequestMethod({
|
|
method: verb,
|
|
itemUid: item.uid,
|
|
collectionUid: collection.uid
|
|
})
|
|
);
|
|
};
|
|
|
|
const handleGenerateCode = (e) => {
|
|
e.stopPropagation();
|
|
if (item?.request?.url !== '' || (item.draft?.request?.url !== undefined && item.draft?.request?.url !== '')) {
|
|
setGenerateCodeItemModalOpen(true);
|
|
} else {
|
|
toast.error('URL is required');
|
|
}
|
|
};
|
|
|
|
const handleCancelRequest = () => {
|
|
dispatch(cancelRequest(item.cancelTokenUid, item, collection));
|
|
};
|
|
|
|
return (
|
|
<StyledWrapper className="flex items-center">
|
|
<div className="flex flex-1 items-center h-full method-selector-container">
|
|
{isGrpc ? (
|
|
<div className="flex items-center justify-center h-full w-16">
|
|
<span className="text-xs text-indigo-500 font-bold">gRPC</span>
|
|
</div>
|
|
|
|
) : (
|
|
<HttpMethodSelector method={method} onMethodSelect={onMethodSelect} />
|
|
)}
|
|
</div>
|
|
<div
|
|
id="request-url"
|
|
className="flex items-center flex-grow input-container h-full"
|
|
style={{
|
|
color: 'yellow',
|
|
width: `calc(100% - ${methodSelectorWidth}px)`,
|
|
maxWidth: `calc(100% - ${methodSelectorWidth}px)`
|
|
}}
|
|
>
|
|
<SingleLineEditor
|
|
ref={editorRef}
|
|
value={url}
|
|
onSave={(finalValue) => onSave(finalValue)}
|
|
theme={storedTheme}
|
|
onChange={(newValue) => onUrlChange(newValue)}
|
|
onRun={handleRun}
|
|
collection={collection}
|
|
highlightPathParams={true}
|
|
item={item}
|
|
/>
|
|
<div className="flex items-center h-full mr-2 cursor-pointer" id="send-request" onClick={handleRun}>
|
|
<div
|
|
title="Generate Code"
|
|
className="infotip mr-3"
|
|
onClick={(e) => {
|
|
handleGenerateCode(e);
|
|
}}
|
|
>
|
|
<IconCode
|
|
color={theme.requestTabs.icon.color}
|
|
strokeWidth={1.5}
|
|
size={22}
|
|
className={'cursor-pointer'}
|
|
/>
|
|
<span className="infotiptext text-xs">
|
|
Generate Code
|
|
</span>
|
|
</div>
|
|
<div
|
|
title="Save Request"
|
|
className="infotip mr-3"
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
if (!hasChanges) return;
|
|
onSave();
|
|
}}
|
|
>
|
|
<IconDeviceFloppy
|
|
color={hasChanges ? theme.colors.text.yellow : theme.requestTabs.icon.color}
|
|
strokeWidth={1.5}
|
|
size={22}
|
|
className={`${hasChanges ? 'cursor-pointer' : 'cursor-default'}`}
|
|
/>
|
|
<span className="infotiptext text-xs">
|
|
Save <span className="shortcut">({saveShortcut})</span>
|
|
</span>
|
|
</div>
|
|
|
|
{
|
|
isLoading || item.response?.stream?.running ? (
|
|
<IconSquareRoundedX
|
|
color={theme.requestTabPanel.url.icon}
|
|
strokeWidth={1.5}
|
|
size={22}
|
|
data-testid="cancel-request-icon"
|
|
onClick={handleCancelRequest}
|
|
/>
|
|
) : (
|
|
<IconArrowRight
|
|
color={theme.requestTabPanel.url.icon}
|
|
strokeWidth={1.5}
|
|
size={22}
|
|
data-testid="send-arrow-icon"
|
|
/>
|
|
)
|
|
}
|
|
</div>
|
|
</div>
|
|
{generateCodeItemModalOpen && (
|
|
<GenerateCodeItem collectionUid={collection.uid} item={item} onClose={() => setGenerateCodeItemModalOpen(false)} />
|
|
)}
|
|
</StyledWrapper>
|
|
);
|
|
};
|
|
|
|
export default QueryUrl;
|