mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-29 03:13:45 +01:00
feat: added request tab context menu (#2183)
* feat: added close menus on the request tab * feat: added close to the left button * feat: added new request and clone request buttons * chore: fix prettier
This commit is contained in:
parent
8de6b72ab9
commit
1bedfc2046
@ -40,10 +40,15 @@ const Wrapper = styled.div`
|
|||||||
color: ${(props) => props.theme.dropdown.iconColor};
|
color: ${(props) => props.theme.dropdown.iconColor};
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover:not(:disabled) {
|
||||||
background-color: ${(props) => props.theme.dropdown.hoverBg};
|
background-color: ${(props) => props.theme.dropdown.hoverBg};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
&.border-top {
|
&.border-top {
|
||||||
border-top: solid 1px ${(props) => props.theme.dropdown.separator};
|
border-top: solid 1px ${(props) => props.theme.dropdown.separator};
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, useRef, Fragment } from 'react';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import { closeTabs } from 'providers/ReduxStore/slices/tabs';
|
import { closeTabs } from 'providers/ReduxStore/slices/tabs';
|
||||||
import { saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
import { saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
||||||
@ -12,12 +12,18 @@ import ConfirmRequestClose from './ConfirmRequestClose';
|
|||||||
import RequestTabNotFound from './RequestTabNotFound';
|
import RequestTabNotFound from './RequestTabNotFound';
|
||||||
import SpecialTab from './SpecialTab';
|
import SpecialTab from './SpecialTab';
|
||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
|
import Dropdown from 'components/Dropdown';
|
||||||
|
import CloneCollectionItem from 'components/Sidebar/Collections/Collection/CollectionItem/CloneCollectionItem/index';
|
||||||
|
import NewRequest from 'components/Sidebar/NewRequest/index';
|
||||||
|
|
||||||
const RequestTab = ({ tab, collection, folderUid }) => {
|
const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUid }) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { storedTheme } = useTheme();
|
const { storedTheme } = useTheme();
|
||||||
const [showConfirmClose, setShowConfirmClose] = useState(false);
|
const [showConfirmClose, setShowConfirmClose] = useState(false);
|
||||||
|
|
||||||
|
const dropdownTippyRef = useRef();
|
||||||
|
const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
|
||||||
|
|
||||||
const handleCloseClick = (event) => {
|
const handleCloseClick = (event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -28,6 +34,19 @@ const RequestTab = ({ tab, collection, folderUid }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRightClick = (_event) => {
|
||||||
|
const menuDropdown = dropdownTippyRef.current;
|
||||||
|
if (!menuDropdown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (menuDropdown.state.isShown) {
|
||||||
|
menuDropdown.hide();
|
||||||
|
} else {
|
||||||
|
menuDropdown.show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleMouseUp = (e) => {
|
const handleMouseUp = (e) => {
|
||||||
if (e.button === 1) {
|
if (e.button === 1) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@ -143,6 +162,7 @@ const RequestTab = ({ tab, collection, folderUid }) => {
|
|||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
className="flex items-baseline tab-label pl-2"
|
className="flex items-baseline tab-label pl-2"
|
||||||
|
onContextMenu={handleRightClick}
|
||||||
onMouseUp={(e) => {
|
onMouseUp={(e) => {
|
||||||
if (!item.draft) return handleMouseUp(e);
|
if (!item.draft) return handleMouseUp(e);
|
||||||
|
|
||||||
@ -159,6 +179,15 @@ const RequestTab = ({ tab, collection, folderUid }) => {
|
|||||||
<span className="ml-1 tab-name" title={item.name}>
|
<span className="ml-1 tab-name" title={item.name}>
|
||||||
{item.name}
|
{item.name}
|
||||||
</span>
|
</span>
|
||||||
|
<RequestTabMenu
|
||||||
|
onDropdownCreate={onDropdownCreate}
|
||||||
|
tabIndex={tabIndex}
|
||||||
|
collectionRequestTabs={collectionRequestTabs}
|
||||||
|
tabItem={item}
|
||||||
|
collection={collection}
|
||||||
|
dropdownTippyRef={dropdownTippyRef}
|
||||||
|
dispatch={dispatch}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="flex px-2 close-icon-container"
|
className="flex px-2 close-icon-container"
|
||||||
@ -195,4 +224,124 @@ const RequestTab = ({ tab, collection, folderUid }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function RequestTabMenu({ onDropdownCreate, collectionRequestTabs, tabIndex, collection, dropdownTippyRef, dispatch }) {
|
||||||
|
const [showCloneRequestModal, setShowCloneRequestModal] = useState(false);
|
||||||
|
const [showAddNewRequestModal, setShowAddNewRequestModal] = useState(false);
|
||||||
|
|
||||||
|
const totalTabs = collectionRequestTabs.length || 0;
|
||||||
|
const currentTabUid = collectionRequestTabs[tabIndex]?.uid;
|
||||||
|
const currentTabItem = findItemInCollection(collection, currentTabUid);
|
||||||
|
|
||||||
|
const hasLeftTabs = tabIndex !== 0;
|
||||||
|
const hasRightTabs = totalTabs > tabIndex + 1;
|
||||||
|
const hasOtherTabs = totalTabs > 1;
|
||||||
|
|
||||||
|
async function handleCloseTab(event, tabUid) {
|
||||||
|
event.stopPropagation();
|
||||||
|
dropdownTippyRef.current.hide();
|
||||||
|
|
||||||
|
if (!tabUid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const item = findItemInCollection(collection, tabUid);
|
||||||
|
// silently save unsaved changes before closing the tab
|
||||||
|
if (item.draft) {
|
||||||
|
await dispatch(saveRequest(item.uid, collection.uid, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(closeTabs({ tabUids: [tabUid] }));
|
||||||
|
} catch (err) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCloseOtherTabs(event) {
|
||||||
|
dropdownTippyRef.current.hide();
|
||||||
|
|
||||||
|
const otherTabs = collectionRequestTabs.filter((_, index) => index !== tabIndex);
|
||||||
|
otherTabs.forEach((tab) => handleCloseTab(event, tab.uid));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCloseTabsToTheLeft(event) {
|
||||||
|
dropdownTippyRef.current.hide();
|
||||||
|
|
||||||
|
const leftTabs = collectionRequestTabs.filter((_, index) => index < tabIndex);
|
||||||
|
leftTabs.forEach((tab) => handleCloseTab(event, tab.uid));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCloseTabsToTheRight(event) {
|
||||||
|
dropdownTippyRef.current.hide();
|
||||||
|
|
||||||
|
const rightTabs = collectionRequestTabs.filter((_, index) => index > tabIndex);
|
||||||
|
rightTabs.forEach((tab) => handleCloseTab(event, tab.uid));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCloseSavedTabs(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
const savedTabs = collection.items.filter((item) => !item.draft);
|
||||||
|
const savedTabIds = savedTabs.map((item) => item.uid) || [];
|
||||||
|
dispatch(closeTabs({ tabUids: savedTabIds }));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCloseAllTabs(event) {
|
||||||
|
collectionRequestTabs.forEach((tab) => handleCloseTab(event, tab.uid));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
{showAddNewRequestModal && (
|
||||||
|
<NewRequest collection={collection} onClose={() => setShowAddNewRequestModal(false)} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showCloneRequestModal && (
|
||||||
|
<CloneCollectionItem
|
||||||
|
item={currentTabItem}
|
||||||
|
collection={collection}
|
||||||
|
onClose={() => setShowCloneRequestModal(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Dropdown onCreate={onDropdownCreate} icon={<span></span>} placement="bottom-start">
|
||||||
|
<button
|
||||||
|
className="dropdown-item w-full"
|
||||||
|
onClick={() => {
|
||||||
|
dropdownTippyRef.current.hide();
|
||||||
|
setShowAddNewRequestModal(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
New Request
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="dropdown-item w-full"
|
||||||
|
onClick={() => {
|
||||||
|
dropdownTippyRef.current.hide();
|
||||||
|
setShowCloneRequestModal(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Clone Request
|
||||||
|
</button>
|
||||||
|
<button className="dropdown-item w-full" onClick={(e) => handleCloseTab(e, currentTabUid)}>
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
<button disabled={!hasOtherTabs} className="dropdown-item w-full" onClick={handleCloseOtherTabs}>
|
||||||
|
Close Others
|
||||||
|
</button>
|
||||||
|
<button disabled={!hasLeftTabs} className="dropdown-item w-full" onClick={handleCloseTabsToTheLeft}>
|
||||||
|
Close to the Left
|
||||||
|
</button>
|
||||||
|
<button disabled={!hasRightTabs} className="dropdown-item w-full" onClick={handleCloseTabsToTheRight}>
|
||||||
|
Close to the Right
|
||||||
|
</button>
|
||||||
|
<button className="dropdown-item w-full" onClick={handleCloseSavedTabs}>
|
||||||
|
Close Saved
|
||||||
|
</button>
|
||||||
|
<button className="dropdown-item w-full" onClick={handleCloseAllTabs}>
|
||||||
|
Close All
|
||||||
|
</button>
|
||||||
|
</Dropdown>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default RequestTab;
|
export default RequestTab;
|
||||||
|
@ -7,7 +7,6 @@ const Wrapper = styled.div`
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
|
||||||
overflow: scroll;
|
overflow: scroll;
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
|
@ -110,7 +110,14 @@ const RequestTabs = () => {
|
|||||||
role="tab"
|
role="tab"
|
||||||
onClick={() => handleClick(tab)}
|
onClick={() => handleClick(tab)}
|
||||||
>
|
>
|
||||||
<RequestTab key={tab.uid} tab={tab} collection={activeCollection} folderUid={tab.folderUid} />
|
<RequestTab
|
||||||
|
collectionRequestTabs={collectionRequestTabs}
|
||||||
|
tabIndex={index}
|
||||||
|
key={tab.uid}
|
||||||
|
tab={tab}
|
||||||
|
collection={activeCollection}
|
||||||
|
folderUid={tab.folderUid}
|
||||||
|
/>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user