mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-24 17:03:47 +01:00
* feat: update settings collection tab name * refact: special tab name in its own helper * feat: add ctrl tab * chore: add jest config for module name mapping * feat: add path to ctrlTab --------- Co-authored-by: Anoop M D <anoop.md1421@gmail.com>
This commit is contained in:
parent
93080de2a8
commit
fd92df7bf9
15
packages/bruno-app/jest.config.js
Normal file
15
packages/bruno-app/jest.config.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/** @type {import('jest').Config} */
|
||||||
|
const config = {
|
||||||
|
moduleNameMapper: {
|
||||||
|
'^assets/(.*)$': '<rootDir>/src/assets/$1',
|
||||||
|
'^components/(.*)$': '<rootDir>/src/components/$1',
|
||||||
|
'^hooks/(.*)$': '<rootDir>/src/hooks/$1',
|
||||||
|
'^themes/(.*)$': '<rootDir>/src/themes/$1',
|
||||||
|
'^api/(.*)$': '<rootDir>/src/api/$1',
|
||||||
|
'^pageComponents/(.*)$': '<rootDir>/src/pageComponents/$1',
|
||||||
|
'^providers/(.*)$': '<rootDir>/src/providers/$1',
|
||||||
|
'^utils/(.*)$': '<rootDir>/src/utils/$1'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = config;
|
@ -0,0 +1,12 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const Wrapper = styled.dialog`
|
||||||
|
background-color: ${(props) => props.theme.ctrlTabPopup.bg};
|
||||||
|
color: ${(props) => props.theme.ctrlTabPopup.text};
|
||||||
|
button:focus {
|
||||||
|
outline: none;
|
||||||
|
background-color: ${(props) => props.theme.ctrlTabPopup.highlightBg};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default Wrapper;
|
81
packages/bruno-app/src/components/CtrlTabPopup/index.js
Normal file
81
packages/bruno-app/src/components/CtrlTabPopup/index.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { findItemInCollection, findCollectionByUid } from 'utils/collections';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import StyledWrapper from './StyledWrapper';
|
||||||
|
import reverse from 'lodash/reverse';
|
||||||
|
import { getSpecialTabName, isSpecialTab, isItemAFolder } from 'utils/tabs';
|
||||||
|
import { selectCtrlTabAction } from 'providers/ReduxStore/slices/tabs';
|
||||||
|
|
||||||
|
export const tabStackToPopupTabs = (collections, ctrlTabStack) => {
|
||||||
|
if (!collections) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrlTabStack
|
||||||
|
.map((tab) => {
|
||||||
|
const collection = findCollectionByUid(collections, tab.collectionUid);
|
||||||
|
return { collection, tab: findItemInCollection(collection, tab.uid) ?? tab };
|
||||||
|
})
|
||||||
|
.map(({ collection, tab }) => ({
|
||||||
|
tabName: isSpecialTab(tab) ? getSpecialTabName(tab.type) : tab.name,
|
||||||
|
path: getItemPath(collection, tab),
|
||||||
|
uid: tab.uid
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getItemPath = (collection, item) => {
|
||||||
|
if (isSpecialTab(item)) {
|
||||||
|
return collection.name;
|
||||||
|
}
|
||||||
|
if (collection.items.find((i) => i.uid === item.uid)) {
|
||||||
|
return collection.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
collection.name + '/' + collection.items.map((i) => (isItemAFolder(i) ? getItemPath(i, item) : null)).find(Boolean)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// required in cases where we remove a tab from the stack but the user is still holding ctrl
|
||||||
|
const tabStackToUniqueId = (ctrlTabStack) => ctrlTabStack.map((tab) => tab.uid).join('-');
|
||||||
|
|
||||||
|
export default function CtrlTabPopup() {
|
||||||
|
const ctrlTabIndex = useSelector((state) => state.tabs.ctrlTabIndex);
|
||||||
|
const ctrlTabStack = useSelector((state) => state.tabs.ctrlTabStack);
|
||||||
|
const collections = useSelector((state) => state.collections.collections);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
if (ctrlTabIndex === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const popupTabs = tabStackToPopupTabs(collections, ctrlTabStack);
|
||||||
|
|
||||||
|
const currentTabbedTab = popupTabs.at(ctrlTabIndex);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="absolute flex justify-center top-1 w-full">
|
||||||
|
<StyledWrapper
|
||||||
|
key={'dialog' + ctrlTabIndex + tabStackToUniqueId(ctrlTabStack)}
|
||||||
|
className="flex flex-col rounded isolate z-10 p-1 overflow-y-auto max-h-80 w-96"
|
||||||
|
>
|
||||||
|
{reverse(popupTabs).map((popupTab) => (
|
||||||
|
<button
|
||||||
|
key={popupTab.uid}
|
||||||
|
autoFocus={currentTabbedTab === popupTab}
|
||||||
|
onClick={() => dispatch(selectCtrlTabAction(popupTab.uid))}
|
||||||
|
type="button"
|
||||||
|
className={classnames('py-0.5 px-5 rounded text-left truncate', {
|
||||||
|
'is-active': currentTabbedTab === popupTab
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<strong className="font-medium">{popupTab.tabName}</strong>
|
||||||
|
{' '}
|
||||||
|
<span className="text-xs font-extralight">{popupTab.path}</span>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</StyledWrapper>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
59
packages/bruno-app/src/components/CtrlTabPopup/index.spec.js
Normal file
59
packages/bruno-app/src/components/CtrlTabPopup/index.spec.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { tabStackToPopupTabs } from './index';
|
||||||
|
|
||||||
|
describe('CtrlTabPopup', () => {
|
||||||
|
describe('tabStackToPopupTabs', () => {
|
||||||
|
it('should return an empty array if collections is falsy', () => {
|
||||||
|
const collections = null;
|
||||||
|
const ctrlTabStack = [];
|
||||||
|
|
||||||
|
const result = tabStackToPopupTabs(collections, ctrlTabStack);
|
||||||
|
|
||||||
|
expect(result).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an array of popup tabs', () => {
|
||||||
|
const collections = [
|
||||||
|
{
|
||||||
|
name: 'Collection 1',
|
||||||
|
uid: 'collection1',
|
||||||
|
items: [{ name: 'Request 1', uid: 'aaa', type: 'http-request', collectionUid: 'collection1' }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Collection 2',
|
||||||
|
uid: 'collection2',
|
||||||
|
items: [
|
||||||
|
{ name: 'Request 2', uid: 'ccc', type: 'http-request', collectionUid: 'collection2' },
|
||||||
|
{
|
||||||
|
name: 'Folder 1',
|
||||||
|
type: 'folder',
|
||||||
|
items: [
|
||||||
|
{ name: 'Request 3', uid: 'ddd', type: 'http-request', collectionUid: 'collection2' },
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'Folder 2',
|
||||||
|
type: 'folder',
|
||||||
|
items: [{ name: 'Request 4', uid: 'eee', type: 'http-request', collectionUid: 'collection2' }]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const ctrlTabStack = [
|
||||||
|
{ collectionUid: 'collection1', uid: 'aaa', type: 'http-request' },
|
||||||
|
{ collectionUid: 'collection2', uid: 'ddd', type: 'http-request' },
|
||||||
|
{ collectionUid: 'collection2', uid: 'eee', type: 'http-request' },
|
||||||
|
{ collectionUid: 'collection2', uid: 'yyy', type: 'collection-settings' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = tabStackToPopupTabs(collections, ctrlTabStack);
|
||||||
|
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ tabName: 'Request 1', path: 'Collection 1', uid: 'aaa' },
|
||||||
|
{ tabName: 'Request 3', path: 'Collection 2/Folder 1', uid: 'ddd' },
|
||||||
|
{ tabName: 'Request 4', path: 'Collection 2/Folder 1/Folder 2', uid: 'eee' },
|
||||||
|
{ tabName: 'Settings', path: 'Collection 2', uid: 'yyy' }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -9,6 +9,7 @@ import StyledWrapper from './StyledWrapper';
|
|||||||
import 'codemirror/theme/material.css';
|
import 'codemirror/theme/material.css';
|
||||||
import 'codemirror/theme/monokai.css';
|
import 'codemirror/theme/monokai.css';
|
||||||
import 'codemirror/addon/scroll/simplescrollbars.css';
|
import 'codemirror/addon/scroll/simplescrollbars.css';
|
||||||
|
import CtrlTabPopup from 'components/CtrlTabPopup';
|
||||||
|
|
||||||
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
|
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
|
||||||
if (!SERVER_RENDERED) {
|
if (!SERVER_RENDERED) {
|
||||||
@ -60,6 +61,7 @@ export default function Main() {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<StyledWrapper className={className}>
|
<StyledWrapper className={className}>
|
||||||
|
<CtrlTabPopup />
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<section className="flex flex-grow flex-col overflow-auto">
|
<section className="flex flex-grow flex-col overflow-auto">
|
||||||
{showHomePage ? (
|
{showHomePage ? (
|
||||||
|
@ -9,7 +9,7 @@ import NetworkError from 'components/ResponsePane/NetworkError';
|
|||||||
import NewRequest from 'components/Sidebar/NewRequest';
|
import NewRequest from 'components/Sidebar/NewRequest';
|
||||||
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
||||||
import { findCollectionByUid, findItemInCollection } from 'utils/collections';
|
import { findCollectionByUid, findItemInCollection } from 'utils/collections';
|
||||||
import { closeTabs, switchTab } from 'providers/ReduxStore/slices/tabs';
|
import { CTRL_TAB_ACTIONS, closeTabs, switchTab } from 'providers/ReduxStore/slices/tabs';
|
||||||
|
|
||||||
export const HotkeysContext = React.createContext();
|
export const HotkeysContext = React.createContext();
|
||||||
|
|
||||||
@ -154,6 +154,48 @@ export const HotkeysProvider = (props) => {
|
|||||||
};
|
};
|
||||||
}, [activeTabUid]);
|
}, [activeTabUid]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const shortcuts = ['mod+tab'];
|
||||||
|
const shiftedShortcuts = ['shift+mod+tab'];
|
||||||
|
|
||||||
|
const bindCtrlTabShortcut = () => {
|
||||||
|
Mousetrap.bind(shortcuts, () => {
|
||||||
|
dispatch(ctrlTab(CTRL_TAB_ACTIONS.ENTER));
|
||||||
|
Mousetrap.unbind(shortcuts);
|
||||||
|
|
||||||
|
Mousetrap.bind(shortcuts, () => {
|
||||||
|
dispatch(ctrlTab(CTRL_TAB_ACTIONS.PLUS));
|
||||||
|
return false; // this stops the event bubbling
|
||||||
|
});
|
||||||
|
Mousetrap.bind(shiftedShortcuts, () => {
|
||||||
|
dispatch(ctrlTab(CTRL_TAB_ACTIONS.MINUS));
|
||||||
|
return false; // this stops the event bubbling
|
||||||
|
});
|
||||||
|
|
||||||
|
Mousetrap.bind(
|
||||||
|
['mod'],
|
||||||
|
() => {
|
||||||
|
dispatch(ctrlTab(CTRL_TAB_ACTIONS.SWITCH));
|
||||||
|
Mousetrap.unbind(['mod'], 'keyup');
|
||||||
|
Mousetrap.unbind(shortcuts);
|
||||||
|
Mousetrap.unbind(shiftedShortcuts);
|
||||||
|
|
||||||
|
bindCtrlTabShortcut();
|
||||||
|
return false; // this stops the event bubbling
|
||||||
|
},
|
||||||
|
'keyup'
|
||||||
|
);
|
||||||
|
|
||||||
|
return false; // this stops the event bubbling
|
||||||
|
});
|
||||||
|
};
|
||||||
|
bindCtrlTabShortcut();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
Mousetrap.unbind(shortcuts);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Switch to the previous tab
|
// Switch to the previous tab
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Mousetrap.bind(['command+pageup', 'ctrl+pageup'], (e) => {
|
Mousetrap.bind(['command+pageup', 'ctrl+pageup'], (e) => {
|
||||||
|
@ -7,13 +7,48 @@ import last from 'lodash/last';
|
|||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
tabs: [],
|
tabs: [],
|
||||||
activeTabUid: null
|
activeTabUid: null,
|
||||||
|
ctrlTabStack: [],
|
||||||
|
ctrlTabIndex: null
|
||||||
};
|
};
|
||||||
|
|
||||||
const tabTypeAlreadyExists = (tabs, collectionUid, type) => {
|
const tabTypeAlreadyExists = (tabs, collectionUid, type) => {
|
||||||
return find(tabs, (tab) => tab.collectionUid === collectionUid && tab.type === type);
|
return find(tabs, (tab) => tab.collectionUid === collectionUid && tab.type === type);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const uidToTab = (state, uid) => find(state.tabs, (tab) => tab.uid === uid);
|
||||||
|
|
||||||
|
const focusTabWithStack = (state, uid) => {
|
||||||
|
if (state.activeTabUid === uid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (state.activeTabUid) {
|
||||||
|
const previousTab = uidToTab(state, state.activeTabUid);
|
||||||
|
const currentTab = uidToTab(state, uid);
|
||||||
|
state.ctrlTabStack = [
|
||||||
|
...filter(state.ctrlTabStack, (tab) => tab.uid !== state.activeTabUid && tab.uid !== uid),
|
||||||
|
...(previousTab ? [previousTab] : []), // if previousTab is undefined, it means the tab was closed while focused
|
||||||
|
currentTab
|
||||||
|
];
|
||||||
|
}
|
||||||
|
state.activeTabUid = uid;
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeClosedTabs = (state, filterFunction) => {
|
||||||
|
state.tabs = filter(state.tabs, filterFunction);
|
||||||
|
state.ctrlTabStack = filter(state.ctrlTabStack, filterFunction);
|
||||||
|
if (state.ctrlTabStack.length < 2) {
|
||||||
|
state.ctrlTabIndex = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CTRL_TAB_ACTIONS = Object.freeze({
|
||||||
|
ENTER: 'enter',
|
||||||
|
PLUS: 'plus',
|
||||||
|
MINUS: 'minus',
|
||||||
|
SWITCH: 'switch'
|
||||||
|
});
|
||||||
|
|
||||||
export const tabsSlice = createSlice({
|
export const tabsSlice = createSlice({
|
||||||
name: 'tabs',
|
name: 'tabs',
|
||||||
initialState,
|
initialState,
|
||||||
@ -29,7 +64,7 @@ export const tabsSlice = createSlice({
|
|||||||
) {
|
) {
|
||||||
const tab = tabTypeAlreadyExists(state.tabs, action.payload.collectionUid, action.payload.type);
|
const tab = tabTypeAlreadyExists(state.tabs, action.payload.collectionUid, action.payload.type);
|
||||||
if (tab) {
|
if (tab) {
|
||||||
state.activeTabUid = tab.uid;
|
focusTabWithStack(state, tab.uid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,10 +78,38 @@ export const tabsSlice = createSlice({
|
|||||||
type: action.payload.type || 'request',
|
type: action.payload.type || 'request',
|
||||||
...(action.payload.uid ? { folderUid: action.payload.uid } : {})
|
...(action.payload.uid ? { folderUid: action.payload.uid } : {})
|
||||||
});
|
});
|
||||||
state.activeTabUid = action.payload.uid;
|
focusTabWithStack(state, action.payload.uid);
|
||||||
},
|
},
|
||||||
focusTab: (state, action) => {
|
focusTab: (state, action) => {
|
||||||
state.activeTabUid = action.payload.uid;
|
focusTabWithStack(state, action.payload.uid);
|
||||||
|
},
|
||||||
|
focusCtrlTab: (state, action) => {
|
||||||
|
focusTabWithStack(state, action.payload.uid);
|
||||||
|
state.ctrlTabIndex = null;
|
||||||
|
},
|
||||||
|
ctrlTab: (state, action) => {
|
||||||
|
if (state.ctrlTabStack.length < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (action.payload) {
|
||||||
|
case CTRL_TAB_ACTIONS.ENTER:
|
||||||
|
state.ctrlTabIndex = -2;
|
||||||
|
return;
|
||||||
|
case CTRL_TAB_ACTIONS.PLUS:
|
||||||
|
state.ctrlTabIndex = (state.ctrlTabIndex - 1) % state.ctrlTabStack.length;
|
||||||
|
return;
|
||||||
|
case CTRL_TAB_ACTIONS.MINUS:
|
||||||
|
state.ctrlTabIndex = (state.ctrlTabIndex + 1) % state.ctrlTabStack.length;
|
||||||
|
return;
|
||||||
|
case CTRL_TAB_ACTIONS.SWITCH:
|
||||||
|
if (state.ctrlTabIndex === null) {
|
||||||
|
// if already switched (eg, from click), do nothing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
focusTabWithStack(state, state.ctrlTabStack.at(state.ctrlTabIndex).uid);
|
||||||
|
state.ctrlTabIndex = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
switchTab: (state, action) => {
|
switchTab: (state, action) => {
|
||||||
if (!state.tabs || !state.tabs.length) {
|
if (!state.tabs || !state.tabs.length) {
|
||||||
@ -94,7 +157,7 @@ export const tabsSlice = createSlice({
|
|||||||
const tabUids = action.payload.tabUids || [];
|
const tabUids = action.payload.tabUids || [];
|
||||||
|
|
||||||
// remove the tabs from the state
|
// remove the tabs from the state
|
||||||
state.tabs = filter(state.tabs, (t) => !tabUids.includes(t.uid));
|
removeClosedTabs(state, (t) => !tabUids.includes(t.uid));
|
||||||
|
|
||||||
if (activeTab && state.tabs.length) {
|
if (activeTab && state.tabs.length) {
|
||||||
const { collectionUid } = activeTab;
|
const { collectionUid } = activeTab;
|
||||||
@ -109,9 +172,9 @@ export const tabsSlice = createSlice({
|
|||||||
// if there are sibling tabs, set the active tab to the last sibling tab
|
// if there are sibling tabs, set the active tab to the last sibling tab
|
||||||
// otherwise, set the active tab to the last tab in the list
|
// otherwise, set the active tab to the last tab in the list
|
||||||
if (siblingTabs && siblingTabs.length) {
|
if (siblingTabs && siblingTabs.length) {
|
||||||
state.activeTabUid = last(siblingTabs).uid;
|
focusTabWithStack(state, last(siblingTabs).uid);
|
||||||
} else {
|
} else {
|
||||||
state.activeTabUid = last(state.tabs).uid;
|
focusTabWithStack(state, last(state.tabs).uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,15 +185,24 @@ export const tabsSlice = createSlice({
|
|||||||
},
|
},
|
||||||
closeAllCollectionTabs: (state, action) => {
|
closeAllCollectionTabs: (state, action) => {
|
||||||
const collectionUid = action.payload.collectionUid;
|
const collectionUid = action.payload.collectionUid;
|
||||||
state.tabs = filter(state.tabs, (t) => t.collectionUid !== collectionUid);
|
removeClosedTabs(state, (t) => t.collectionUid !== collectionUid);
|
||||||
state.activeTabUid = null;
|
state.activeTabUid = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const selectCtrlTabAction = (uid) => (dispatch) => {
|
||||||
|
dispatch(
|
||||||
|
tabsSlice.actions.focusCtrlTab({
|
||||||
|
uid
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
addTab,
|
addTab,
|
||||||
focusTab,
|
focusTab,
|
||||||
|
ctrlTab,
|
||||||
switchTab,
|
switchTab,
|
||||||
updateRequestPaneTabWidth,
|
updateRequestPaneTabWidth,
|
||||||
updateRequestPaneTab,
|
updateRequestPaneTab,
|
||||||
|
@ -174,7 +174,11 @@ const darkTheme = {
|
|||||||
opacity: 0.2
|
opacity: 0.2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
ctrlTabPopup: {
|
||||||
|
bg: '#1f2937',
|
||||||
|
text: '#ccc',
|
||||||
|
highlightBg: '#374151'
|
||||||
|
},
|
||||||
button: {
|
button: {
|
||||||
secondary: {
|
secondary: {
|
||||||
color: 'rgb(204, 204, 204)',
|
color: 'rgb(204, 204, 204)',
|
||||||
|
@ -178,7 +178,11 @@ const lightTheme = {
|
|||||||
opacity: 0.4
|
opacity: 0.4
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
ctrlTabPopup: {
|
||||||
|
bg: '#fff8f7',
|
||||||
|
text: 'rgb(52, 52, 52)',
|
||||||
|
highlightBg: '#ffb63154'
|
||||||
|
},
|
||||||
button: {
|
button: {
|
||||||
secondary: {
|
secondary: {
|
||||||
color: '#212529',
|
color: '#212529',
|
||||||
|
@ -11,3 +11,24 @@ export const isItemAFolder = (item) => {
|
|||||||
export const itemIsOpenedInTabs = (item, tabs) => {
|
export const itemIsOpenedInTabs = (item, tabs) => {
|
||||||
return find(tabs, (t) => t.uid === item.uid);
|
return find(tabs, (t) => t.uid === item.uid);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isSpecialTab = ({ type }) => {
|
||||||
|
if (!type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ['variables', 'collection-settings', 'collection-runner'].includes(type);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getSpecialTabName = (type) => {
|
||||||
|
switch (type) {
|
||||||
|
case 'variables':
|
||||||
|
return 'Variables';
|
||||||
|
case 'collection-settings':
|
||||||
|
return 'Settings';
|
||||||
|
case 'collection-runner':
|
||||||
|
return 'Runner';
|
||||||
|
default:
|
||||||
|
console.error('Unknown special tab type', type);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user