+
{children ? children : (
-
+
)}
);
-};
+});
+
+ResponseClear.displayName = 'ResponseClear';
+
export default ResponseClear;
diff --git a/packages/bruno-app/src/components/ResponsePane/ResponseCopy/index.js b/packages/bruno-app/src/components/ResponsePane/ResponseCopy/index.js
index 3b40b2ff8..9a279e5e5 100644
--- a/packages/bruno-app/src/components/ResponsePane/ResponseCopy/index.js
+++ b/packages/bruno-app/src/components/ResponsePane/ResponseCopy/index.js
@@ -1,7 +1,9 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState, useEffect, forwardRef, useImperativeHandle, useRef } from 'react';
import StyledWrapper from './StyledWrapper';
import toast from 'react-hot-toast';
import { IconCopy, IconCheck } from '@tabler/icons';
+import classnames from 'classnames';
+import ActionIcon from 'ui/ActionIcon/index';
// Hook to get copy response function
export const useResponseCopy = (item) => {
@@ -34,8 +36,16 @@ export const useResponseCopy = (item) => {
return { copyResponse, copied, hasData: !!response.data };
};
-const ResponseCopy = ({ item, children }) => {
+const ResponseCopy = forwardRef(({ item, children }, ref) => {
const { copyResponse, copied, hasData } = useResponseCopy(item);
+ const elementRef = useRef(null);
+
+ const isDisabled = !hasData ? true : false;
+
+ useImperativeHandle(ref, () => ({
+ click: () => elementRef.current?.click(),
+ isDisabled
+ }), [isDisabled]);
const handleKeyDown = (e) => {
if ((e.key === 'Enter' || e.key === ' ') && hasData) {
@@ -51,20 +61,32 @@ const ResponseCopy = ({ item, children }) => {
};
return (
-
+
{children ? children : (
-
+
)}
);
-};
+});
+
+ResponseCopy.displayName = 'ResponseCopy';
export default ResponseCopy;
diff --git a/packages/bruno-app/src/components/ResponsePane/ResponseDownload/index.js b/packages/bruno-app/src/components/ResponsePane/ResponseDownload/index.js
index 8efbd58af..2fa5153ed 100644
--- a/packages/bruno-app/src/components/ResponsePane/ResponseDownload/index.js
+++ b/packages/bruno-app/src/components/ResponsePane/ResponseDownload/index.js
@@ -1,14 +1,21 @@
-import React from 'react';
+import React, { forwardRef, useImperativeHandle, useRef } from 'react';
import StyledWrapper from './StyledWrapper';
import toast from 'react-hot-toast';
import get from 'lodash/get';
import { IconDownload } from '@tabler/icons';
import classnames from 'classnames';
+import ActionIcon from 'ui/ActionIcon/index';
-const ResponseDownload = ({ item, children }) => {
+const ResponseDownload = forwardRef(({ item, children }, ref) => {
const { ipcRenderer } = window;
const response = item.response || {};
- const isDisabled = !response.dataBuffer;
+ const isDisabled = !response.dataBuffer ? true : false;
+ const elementRef = useRef(null);
+
+ useImperativeHandle(ref, () => ({
+ click: () => elementRef.current?.click(),
+ isDisabled
+ }), [isDisabled]);
const saveResponseToFile = () => {
if (isDisabled) {
@@ -25,39 +32,28 @@ const ResponseDownload = ({ item, children }) => {
});
};
- const handleKeyDown = (e) => {
- if (isDisabled) {
- e.preventDefault();
- e.stopPropagation();
- return;
- }
-
- if (e.key === 'Enter' || e.key === ' ') {
- e.preventDefault();
- saveResponseToFile();
- }
- };
-
return (
{children ? children : (
-
+
)}
);
-};
+});
+
+ResponseDownload.displayName = 'ResponseDownload';
+
export default ResponseDownload;
diff --git a/packages/bruno-app/src/components/ResponsePane/ResponseLayoutToggle/index.js b/packages/bruno-app/src/components/ResponsePane/ResponseLayoutToggle/index.js
index 5242d4679..310a49296 100644
--- a/packages/bruno-app/src/components/ResponsePane/ResponseLayoutToggle/index.js
+++ b/packages/bruno-app/src/components/ResponsePane/ResponseLayoutToggle/index.js
@@ -1,8 +1,9 @@
-import React from 'react';
+import React, { forwardRef, useImperativeHandle, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { savePreferences } from 'providers/ReduxStore/slices/app';
import StyledWrapper from './StyledWrapper';
import { IconLayoutColumns, IconLayoutRows } from '@tabler/icons';
+import ActionIcon from 'ui/ActionIcon/index';
export const IconDockToBottom = () => {
return (
@@ -70,40 +71,39 @@ export const useResponseLayoutToggle = () => {
return { orientation, toggleOrientation };
};
-const ResponseLayoutToggle = ({ children }) => {
+const ResponseLayoutToggle = forwardRef(({ children }, ref) => {
const { orientation, toggleOrientation } = useResponseLayoutToggle();
+ const elementRef = useRef(null);
- const handleKeyDown = (e) => {
- if (e.key === 'Enter' || e.key === ' ') {
- e.preventDefault();
- toggleOrientation();
- }
- };
+ useImperativeHandle(ref, () => ({
+ click: () => elementRef.current?.click(),
+ isDisabled: false
+ }), []);
const title = !children ? (orientation === 'horizontal' ? 'Switch to vertical layout' : 'Switch to horizontal layout') : null;
return (
{children ? children : (
-
+
)}
);
-};
+});
+
+ResponseLayoutToggle.displayName = 'ResponseLayoutToggle';
export default ResponseLayoutToggle;
diff --git a/packages/bruno-app/src/components/ResponsePane/ResponseLayoutToggle/index.spec.js b/packages/bruno-app/src/components/ResponsePane/ResponseLayoutToggle/index.spec.js
index 3e49d7618..503076df6 100644
--- a/packages/bruno-app/src/components/ResponsePane/ResponseLayoutToggle/index.spec.js
+++ b/packages/bruno-app/src/components/ResponsePane/ResponseLayoutToggle/index.spec.js
@@ -84,7 +84,7 @@ describe('ResponseLayoutToggle', () => {
describe('Initial Render', () => {
it('should render with horizontal orientation by default', () => {
renderWithProviders(
);
- const button = screen.getByTestId('response-layout-toggle-button');
+ const button = screen.getByTestId('response-layout-toggle-btn');
expect(button).toBeInTheDocument();
expect(button).toHaveAttribute('title', 'Switch to vertical layout');
});
@@ -100,7 +100,7 @@ describe('ResponseLayoutToggle', () => {
}
};
renderWithProviders(
, customState);
- const button = screen.getByTestId('response-layout-toggle-button');
+ const button = screen.getByTestId('response-layout-toggle-btn');
expect(button).toBeInTheDocument();
expect(button).toHaveAttribute('title', 'Switch to horizontal layout');
});
@@ -109,7 +109,7 @@ describe('ResponseLayoutToggle', () => {
describe('Interaction', () => {
it('should switch to vertical layout when clicked in horizontal mode', () => {
const { store } = renderWithProviders(
);
- const button = screen.getByTestId('response-layout-toggle-button');
+ const button = screen.getByTestId('response-layout-toggle-btn');
// Initial state check
expect(button).toHaveAttribute('title', 'Switch to vertical layout');
@@ -145,7 +145,7 @@ describe('ResponseLayoutToggle', () => {
}
};
const { store } = renderWithProviders(
, customState);
- const button = screen.getByTestId('response-layout-toggle-button');
+ const button = screen.getByTestId('response-layout-toggle-btn');
// Initial state check
expect(button).toHaveAttribute('title', 'Switch to horizontal layout');
diff --git a/packages/bruno-app/src/components/ResponsePane/ResponsePaneActions/index.js b/packages/bruno-app/src/components/ResponsePane/ResponsePaneActions/index.js
index 19c773c95..ed905ede0 100644
--- a/packages/bruno-app/src/components/ResponsePane/ResponsePaneActions/index.js
+++ b/packages/bruno-app/src/components/ResponsePane/ResponsePaneActions/index.js
@@ -1,7 +1,7 @@
-import React, { useRef, forwardRef } from 'react';
+import React, { forwardRef, useRef } from 'react';
import styled from 'styled-components';
import { IconDots, IconDownload, IconEraser, IconBookmark, IconCopy, IconLayoutColumns, IconLayoutRows } from '@tabler/icons';
-import Dropdown from 'components/Dropdown';
+import MenuDropdown from 'ui/MenuDropdown';
import ResponseDownload from '../ResponseDownload';
import ResponseBookmark from '../ResponseBookmark';
import ResponseClear from '../ResponseClear';
@@ -39,17 +39,61 @@ MenuIcon.displayName = 'MenuIcon';
const ResponsePaneActions = ({ item, collection, responseSize }) => {
const { orientation } = useResponseLayoutToggle();
- const dropdownTippyRef = useRef();
- const onDropdownCreate = (ref) => {
- dropdownTippyRef.current = ref;
- };
+ // Refs to access child component imperative handles (click, isDisabled)
+ const bookmarkButtonRef = useRef(null);
+ const downloadButtonRef = useRef(null);
+ const clearButtonRef = useRef(null);
+ const copyButtonRef = useRef(null);
+ const layoutToggleButtonRef = useRef(null);
- const closeDropdown = () => {
- if (dropdownTippyRef.current) {
- dropdownTippyRef.current.hide();
+ const menuItems = [
+ {
+ id: 'copy-response',
+ label: 'Copy response',
+ leftSection: IconCopy,
+ get disabled() {
+ return copyButtonRef.current?.isDisabled ?? false;
+ },
+ onClick: () => copyButtonRef.current?.click()
+ },
+ {
+ id: 'save-response',
+ label: 'Save response',
+ leftSection: IconBookmark,
+ get disabled() {
+ return bookmarkButtonRef.current?.isDisabled ?? false;
+ },
+ onClick: () => bookmarkButtonRef.current?.click()
+ },
+ {
+ id: 'download-response',
+ label: 'Download response',
+ leftSection: IconDownload,
+ get disabled() {
+ return downloadButtonRef.current?.isDisabled ?? false;
+ },
+ onClick: () => downloadButtonRef.current?.click()
+ },
+ {
+ id: 'clear-response',
+ label: 'Clear response',
+ leftSection: IconEraser,
+ get disabled() {
+ return clearButtonRef.current?.isDisabled ?? false;
+ },
+ onClick: () => clearButtonRef.current?.click()
+ },
+ {
+ id: 'change-layout',
+ label: 'Change layout',
+ leftSection: orientation === 'vertical' ? IconLayoutColumns : IconLayoutRows,
+ get disabled() {
+ return layoutToggleButtonRef.current?.isDisabled ?? false;
+ },
+ onClick: () => layoutToggleButtonRef.current?.click()
}
- };
+ ];
if (item.type !== 'http-request') {
return null;
@@ -58,65 +102,20 @@ const ResponsePaneActions = ({ item, collection, responseSize }) => {
return (
-
} placement="bottom-end">
-
- {/* Response Copy */}
-
-
-
-
-
- Copy response
-
-
-
- {/* Response Save as Example */}
-
-
-
-
-
- Save response
-
-
-
- {/* Response Download */}
-
-
-
-
-
- Download response
-
-
-
- {/* Response Clear */}
-
-
-
-
-
- Clear response
-
-
-
- {/* Response Layout Toggle */}
-
-
-
- {orientation === 'vertical' ? : }
-
- Change layout
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
diff --git a/packages/bruno-app/src/components/Sidebar/SidebarHeader/CloseWorkspace/index.js b/packages/bruno-app/src/components/Sidebar/CloseWorkspace/index.js
similarity index 100%
rename from packages/bruno-app/src/components/Sidebar/SidebarHeader/CloseWorkspace/index.js
rename to packages/bruno-app/src/components/Sidebar/CloseWorkspace/index.js
diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/ExampleItem/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/ExampleItem/index.js
index bc4e983c5..2f0fb1dfe 100644
--- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/ExampleItem/index.js
+++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/ExampleItem/index.js
@@ -167,7 +167,7 @@ const ExampleItem = ({ example, item, collection }) => {
const handleContextMenu = (e) => {
e.preventDefault();
e.stopPropagation();
- menuDropdownRef.current?.open();
+ menuDropdownRef.current?.show();
};
const itemRowClassName = classnames('flex collection-item-name relative items-center', {
diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/StyledWrapper.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/StyledWrapper.js
index a8901c4a1..c4ed228d0 100644
--- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/StyledWrapper.js
+++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/StyledWrapper.js
@@ -26,6 +26,11 @@ const Wrapper = styled.div`
user-select: none;
position: relative;
+ /* Default: menu icon hidden, shown on hover/focus states (see consolidated rule below) */
+ .collection-item-menu-icon {
+ visibility: hidden;
+ }
+
/* Common styles for drop indicators */
&::before,
&::after {
@@ -50,7 +55,7 @@ const Wrapper = styled.div`
/* Drop target styles */
&.drop-target {
background-color: ${(props) => props.theme.dragAndDrop.hoverBg};
-
+
&::before,
&::after {
opacity: 0;
@@ -94,10 +99,13 @@ const Wrapper = styled.div`
overflow: hidden;
}
+ /* Single source of truth for hover/focus states: background and menu icon visibility */
&:hover,
- &.item-hovered {
+ &.item-hovered,
+ &.item-keyboard-focused {
background: ${(props) => props.theme.sidebar.collection.item.hoverBg};
- .menu-icon {
+ .menu-icon,
+ .collection-item-menu-icon {
visibility: visible;
}
}
diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js
index 2b56afdbb..eb0879b5b 100644
--- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js
+++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js
@@ -27,7 +27,6 @@ import { toggleCollectionItem, addResponseExample } from 'providers/ReduxStore/s
import { insertTaskIntoQueue } from 'providers/ReduxStore/slices/app';
import { uuid } from 'utils/common';
import { copyRequest } from 'providers/ReduxStore/slices/app';
-import MenuDropdown from 'ui/MenuDropdown';
import NewRequest from 'components/Sidebar/NewRequest';
import NewFolder from 'components/Sidebar/NewFolder';
import RenameCollectionItem from './RenameCollectionItem';
@@ -53,6 +52,8 @@ import { calculateDraggedItemNewPathname, getInitialExampleName } from 'utils/co
import { sortByNameThenSequence } from 'utils/common/index';
import CreateExampleModal from 'components/ResponseExample/CreateExampleModal';
import { openDevtoolsAndSwitchToTerminal } from 'utils/terminal';
+import ActionIcon from 'ui/ActionIcon';
+import MenuDropdown from 'ui/MenuDropdown';
const CollectionItem = ({ item, collectionUid, collectionPathname, searchText }) => {
const _isTabForItemActiveSelector = isTabForItemActiveSelector({ itemUid: item.uid });
@@ -285,7 +286,7 @@ const CollectionItem = ({ item, collectionUid, collectionPathname, searchText })
const handleContextMenu = (e) => {
e.preventDefault();
e.stopPropagation();
- menuDropdownRef.current?.open();
+ menuDropdownRef.current?.show();
};
let indents = range(item.depth);
@@ -362,6 +363,16 @@ const CollectionItem = ({ item, collectionUid, collectionPathname, searchText })
onClick: handleShowInFolder
}
);
+ if (!isFolder && isItemARequest(item) && !(item.type === 'http-request' || item.type === 'graphql-request')) {
+ items.push({
+ id: 'run',
+ leftSection: IconPlayerPlay,
+ label: 'Run',
+ onClick: () => {
+ handleRun();
+ }
+ });
+ }
if (!isFolder && (item.type === 'http-request' || item.type === 'graphql-request')) {
items.push({
@@ -633,7 +644,7 @@ const CollectionItem = ({ item, collectionUid, collectionPathname, searchText })
onClick={handleClick}
onDoubleClick={handleDoubleClick}
>
-
+
{isFolder ? (
) : null}
-
+
@@ -663,14 +674,16 @@ const CollectionItem = ({ item, collectionUid, collectionPathname, searchText })
-
diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/StyledWrapper.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/StyledWrapper.js
index b7341d1a6..a845064a0 100644
--- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/StyledWrapper.js
+++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/StyledWrapper.js
@@ -11,44 +11,25 @@ const Wrapper = styled.div`
.rotate-90 {
transform: rotateZ(90deg);
}
+ .collection-actions {
+ visibility: hidden;
+ }
+
+ &:hover,
+ &:focus-within,
+ &.collection-keyboard-focused {
+ .collection-actions {
+ visibility: visible;
+ }
+ }
&.item-hovered {
border-top: ${(props) => props.theme.dragAndDrop.borderStyle} ${(props) => props.theme.dragAndDrop.border};
border-bottom: 2px solid transparent;
- .collection-actions {
- .dropdown {
- div[aria-expanded='false'] {
- visibility: visible;
- }
- }
- }
- }
-
- .collection-actions {
- .dropdown {
- div[aria-expanded='true'] {
- visibility: visible;
- }
- div[aria-expanded='false'] {
- visibility: hidden;
- }
- }
-
- svg {
- height: 22px;
- color: ${(props) => props.theme.sidebar.dropdownIcon.color};
- }
}
&:hover {
background: ${(props) => props.theme.sidebar.collection.item.hoverBg};
- .collection-actions {
- .dropdown {
- div[aria-expanded='false'] {
- visibility: visible;
- }
- }
- }
}
div.tippy-box {
diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js
index 51831c268..cd147e21c 100644
--- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js
+++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js
@@ -1,4 +1,4 @@
-import React, { useState, forwardRef, useRef, useEffect } from 'react';
+import React, { useState, useRef, useEffect } from 'react';
import { getEmptyImage } from 'react-dnd-html5-backend';
import classnames from 'classnames';
import { uuid } from 'utils/common';
@@ -18,11 +18,11 @@ import {
IconFoldDown,
IconX,
IconSettings,
- IconTerminal2
+ IconTerminal2,
+ IconFolder
} from '@tabler/icons';
-import Dropdown from 'components/Dropdown';
import { toggleCollection, collapseFullCollection } from 'providers/ReduxStore/slices/collections';
-import { mountCollection, moveCollectionAndPersist, handleCollectionItemDrop, pasteItem } from 'providers/ReduxStore/slices/collections/actions';
+import { mountCollection, moveCollectionAndPersist, handleCollectionItemDrop, pasteItem, showInFolder } from 'providers/ReduxStore/slices/collections/actions';
import { useDispatch, useSelector } from 'react-redux';
import { hideApiSpecPage, hideHomePage } from 'providers/ReduxStore/slices/app';
import { addTab, makeTabPermanent } from 'providers/ReduxStore/slices/tabs';
@@ -44,6 +44,8 @@ import ShareCollection from 'components/ShareCollection/index';
import { CollectionItemDragPreview } from './CollectionItem/CollectionItemDragPreview/index';
import { sortByNameThenSequence } from 'utils/common/index';
import { openDevtoolsAndSwitchToTerminal } from 'utils/terminal';
+import ActionIcon from 'ui/ActionIcon';
+import MenuDropdown from 'ui/MenuDropdown';
const Collection = ({ collection, searchText }) => {
const [showNewFolderModal, setShowNewFolderModal] = useState(false);
@@ -60,15 +62,7 @@ const Collection = ({ collection, searchText }) => {
const isCollectionFocused = useSelector(isTabForItemActive({ itemUid: collection.uid }));
const { hasCopiedItems } = useSelector((state) => state.app.clipboard);
- const menuDropdownTippyRef = useRef();
- const onMenuDropdownCreate = (ref) => (menuDropdownTippyRef.current = ref);
- const MenuIcon = forwardRef((_props, ref) => {
- return (
-
-
-
- );
- });
+ const menuDropdownRef = useRef(null);
const handleRun = () => {
dispatch(
@@ -140,15 +134,9 @@ const Collection = ({ collection, searchText }) => {
e.preventDefault();
};
- const handleRightClick = (_event) => {
- const _menuDropdown = menuDropdownTippyRef.current;
- if (_menuDropdown) {
- let menuDropdownBehavior = 'show';
- if (_menuDropdown.state.isShown) {
- menuDropdownBehavior = 'hide';
- }
- _menuDropdown[menuDropdownBehavior]();
- }
+ const handleRightClick = (event) => {
+ event.preventDefault();
+ menuDropdownRef.current?.show();
};
const handleCollapseFullCollection = () => {
@@ -165,8 +153,14 @@ const Collection = ({ collection, searchText }) => {
);
};
+ const handleShowInFolder = () => {
+ dispatch(showInFolder(collection.pathname)).catch((error) => {
+ console.error('Error opening the folder', error);
+ toast.error('Error opening the folder');
+ });
+ };
+
const handlePasteItem = () => {
- menuDropdownTippyRef.current.hide();
dispatch(pasteItem(collection.uid, null))
.then(() => {
toast.success('Item pasted successfully');
@@ -276,6 +270,111 @@ const Collection = ({ collection, searchText }) => {
const requestItems = sortItemsBySequence(filter(collection.items, (i) => isItemARequest(i)));
const folderItems = sortByNameThenSequence(filter(collection.items, (i) => isItemAFolder(i)));
+ const menuItems = [
+ {
+ id: 'new-request',
+ leftSection: IconFilePlus,
+ label: 'New Request',
+ onClick: () => {
+ ensureCollectionIsMounted();
+ setShowNewRequestModal(true);
+ }
+ },
+ {
+ id: 'new-folder',
+ leftSection: IconFolderPlus,
+ label: 'New Folder',
+ onClick: () => {
+ ensureCollectionIsMounted();
+ setShowNewFolderModal(true);
+ }
+ },
+ {
+ id: 'run',
+ leftSection: IconPlayerPlay,
+ label: 'Run',
+ onClick: () => {
+ ensureCollectionIsMounted();
+ handleRun();
+ }
+ },
+ {
+ id: 'clone',
+ leftSection: IconCopy,
+ label: 'Clone',
+ testId: 'clone-collection',
+ onClick: () => {
+ setShowCloneCollectionModalOpen(true);
+ }
+ },
+ ...(hasCopiedItems
+ ? [
+ {
+ id: 'paste',
+ leftSection: IconClipboard,
+ label: 'Paste',
+ onClick: handlePasteItem
+ }
+ ]
+ : []),
+ {
+ id: 'rename',
+ leftSection: IconEdit,
+ label: 'Rename',
+ onClick: () => {
+ setShowRenameCollectionModal(true);
+ }
+ },
+ {
+ id: 'share',
+ leftSection: IconShare,
+ label: 'Share',
+ onClick: () => {
+ ensureCollectionIsMounted();
+ setShowShareCollectionModal(true);
+ }
+ },
+ {
+ id: 'collapse',
+ leftSection: IconFoldDown,
+ label: 'Collapse',
+ onClick: handleCollapseFullCollection
+ },
+ {
+ id: 'show-in-folder',
+ leftSection: IconFolder,
+ label: 'Show in File Explorer',
+ onClick: handleShowInFolder
+ },
+ {
+ id: 'divider-1',
+ type: 'divider'
+ },
+ {
+ id: 'settings',
+ leftSection: IconSettings,
+ label: 'Settings',
+ onClick: viewCollectionSettings
+ },
+ {
+ id: 'terminal',
+ leftSection: IconTerminal2,
+ label: 'Open in Terminal',
+ onClick: async () => {
+ const collectionCwd = collection.pathname;
+ await openDevtoolsAndSwitchToTerminal(dispatch, collectionCwd);
+ }
+ },
+ {
+ id: 'remove',
+ leftSection: IconX,
+ label: 'Remove',
+ onClick: () => {
+ setShowRemoveCollectionModal(true);
+ }
+ }
+ ];
+
return (
{showNewRequestModal && setShowNewRequestModal(false)} />}
@@ -311,160 +410,34 @@ const Collection = ({ collection, searchText }) => {
onDoubleClick={handleDoubleClick}
onContextMenu={handleRightClick}
>
-
+
+
+
{isLoading ? : null}
-