feat(#95): runner runs inside a tab of a collection view

This commit is contained in:
Anoop M D 2023-09-28 04:02:20 +05:30
parent 487dd73040
commit c27f090583
13 changed files with 109 additions and 126 deletions

View File

@ -120,8 +120,7 @@ const RequestTabPanel = () => {
return <div className="pb-4 px-4">Collection not found!</div>; return <div className="pb-4 px-4">Collection not found!</div>;
} }
const showRunner = collection.showRunner; if (focusedTab.type === 'collection-runner') {
if (showRunner) {
return <RunnerResults collection={collection} />; return <RunnerResults collection={collection} />;
} }

View File

@ -4,7 +4,6 @@ import { IconFiles, IconRun, IconEye, IconSettings } from '@tabler/icons';
import EnvironmentSelector from 'components/Environments/EnvironmentSelector'; import EnvironmentSelector from 'components/Environments/EnvironmentSelector';
import { addTab } from 'providers/ReduxStore/slices/tabs'; import { addTab } from 'providers/ReduxStore/slices/tabs';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { toggleRunnerView } from 'providers/ReduxStore/slices/collections';
import StyledWrapper from './StyledWrapper'; import StyledWrapper from './StyledWrapper';
const CollectionToolBar = ({ collection }) => { const CollectionToolBar = ({ collection }) => {
@ -12,8 +11,10 @@ const CollectionToolBar = ({ collection }) => {
const handleRun = () => { const handleRun = () => {
dispatch( dispatch(
toggleRunnerView({ addTab({
collectionUid: collection.uid uid: uuid(),
collectionUid: collection.uid,
type: 'collection-runner'
}) })
); );
}; };

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { IconVariable, IconSettings } from '@tabler/icons'; import { IconVariable, IconSettings, IconRun } from '@tabler/icons';
const SpecialTab = ({ handleCloseClick, type }) => { const SpecialTab = ({ handleCloseClick, type }) => {
const getTabInfo = (type) => { const getTabInfo = (type) => {
@ -20,6 +20,14 @@ const SpecialTab = ({ handleCloseClick, type }) => {
</> </>
); );
} }
case 'collection-runner': {
return (
<>
<IconRun size={18} strokeWidth={1.5} className="text-yellow-600" />
<span className="ml-1">Runner</span>
</>
);
}
} }
}; };

View File

@ -57,7 +57,7 @@ const RequestTab = ({ tab, collection }) => {
return color; return color;
}; };
if (['collection-settings', 'variables'].includes(tab.type)) { if (['collection-settings', 'variables', 'collection-runner'].includes(tab.type)) {
return ( return (
<StyledWrapper className="flex items-center justify-between tab-container px-1"> <StyledWrapper className="flex items-center justify-between tab-container px-1">
<SpecialTab handleCloseClick={handleCloseClick} type={tab.type} /> <SpecialTab handleCloseClick={handleCloseClick} type={tab.type} />

View File

@ -76,8 +76,6 @@ const RequestTabs = () => {
}); });
}; };
const showRunner = activeCollection && activeCollection.showRunner;
// Todo: Must support ephermal requests // Todo: Must support ephermal requests
return ( return (
<StyledWrapper className={getRootClassname()}> <StyledWrapper className={getRootClassname()}>
@ -87,72 +85,70 @@ const RequestTabs = () => {
{collectionRequestTabs && collectionRequestTabs.length ? ( {collectionRequestTabs && collectionRequestTabs.length ? (
<> <>
<CollectionToolBar collection={activeCollection} /> <CollectionToolBar collection={activeCollection} />
{!showRunner ? ( <div className="flex items-center pl-4">
<div className="flex items-center pl-4"> <ul role="tablist">
<ul role="tablist"> {showChevrons ? (
{showChevrons ? ( <li className="select-none short-tab" onClick={leftSlide}>
<li className="select-none short-tab" onClick={leftSlide}>
<div className="flex items-center">
<IconChevronLeft size={18} strokeWidth={1.5} />
</div>
</li>
) : null}
{/* Moved to post mvp */}
{/* <li className="select-none new-tab mr-1" onClick={createNewTab}>
<div className="flex items-center home-icon-container">
<IconHome2 size={18} strokeWidth={1.5}/>
</div>
</li> */}
</ul>
<ul role="tablist" style={{ maxWidth: maxTablistWidth }} ref={tabsRef}>
{collectionRequestTabs && collectionRequestTabs.length
? collectionRequestTabs.map((tab, index) => {
return (
<li
key={tab.uid}
className={getTabClassname(tab, index)}
role="tab"
onClick={() => handleClick(tab)}
>
<RequestTab key={tab.uid} tab={tab} collection={activeCollection} />
</li>
);
})
: null}
</ul>
<ul role="tablist">
{showChevrons ? (
<li className="select-none short-tab" onClick={rightSlide}>
<div className="flex items-center">
<IconChevronRight size={18} strokeWidth={1.5} />
</div>
</li>
) : null}
<li className="select-none short-tab" id="create-new-tab" onClick={createNewTab}>
<div className="flex items-center"> <div className="flex items-center">
<svg <IconChevronLeft size={18} strokeWidth={1.5} />
xmlns="http://www.w3.org/2000/svg"
width="22"
height="22"
fill="currentColor"
viewBox="0 0 16 16"
>
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" />
</svg>
</div> </div>
</li> </li>
{/* Moved to post mvp */} ) : null}
{/* <li className="select-none new-tab choose-request"> {/* Moved to post mvp */}
{/* <li className="select-none new-tab mr-1" onClick={createNewTab}>
<div className="flex items-center home-icon-container">
<IconHome2 size={18} strokeWidth={1.5}/>
</div>
</li> */}
</ul>
<ul role="tablist" style={{ maxWidth: maxTablistWidth }} ref={tabsRef}>
{collectionRequestTabs && collectionRequestTabs.length
? collectionRequestTabs.map((tab, index) => {
return (
<li
key={tab.uid}
className={getTabClassname(tab, index)}
role="tab"
onClick={() => handleClick(tab)}
>
<RequestTab key={tab.uid} tab={tab} collection={activeCollection} />
</li>
);
})
: null}
</ul>
<ul role="tablist">
{showChevrons ? (
<li className="select-none short-tab" onClick={rightSlide}>
<div className="flex items-center"> <div className="flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 16 16"> <IconChevronRight size={18} strokeWidth={1.5} />
<path d="M3 9.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z"/>
</svg>
</div> </div>
</li> */} </li>
</ul> ) : null}
</div> <li className="select-none short-tab" id="create-new-tab" onClick={createNewTab}>
) : null} <div className="flex items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="22"
height="22"
fill="currentColor"
viewBox="0 0 16 16"
>
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" />
</svg>
</div>
</li>
{/* Moved to post mvp */}
{/* <li className="select-none new-tab choose-request">
<div className="flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 16 16">
<path d="M3 9.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z"/>
</svg>
</div>
</li> */}
</ul>
</div>
</> </>
) : null} ) : null}
</StyledWrapper> </StyledWrapper>

View File

@ -3,7 +3,7 @@ import path from 'path';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { get, each, cloneDeep } from 'lodash'; import { get, each, cloneDeep } from 'lodash';
import { runCollectionFolder } from 'providers/ReduxStore/slices/collections/actions'; import { runCollectionFolder } from 'providers/ReduxStore/slices/collections/actions';
import { closeCollectionRunner } from 'providers/ReduxStore/slices/collections'; import { resetCollectionRunner } from 'providers/ReduxStore/slices/collections';
import { findItemInCollection, getTotalRequestCountInCollection } from 'utils/collections'; import { findItemInCollection, getTotalRequestCountInCollection } from 'utils/collections';
import { IconRefresh, IconCircleCheck, IconCircleX, IconCheck, IconX, IconRun } from '@tabler/icons'; import { IconRefresh, IconCircleCheck, IconCircleX, IconCheck, IconX, IconRun } from '@tabler/icons';
import slash from 'utils/common/slash'; import slash from 'utils/common/slash';
@ -69,9 +69,9 @@ export default function RunnerResults({ collection }) {
dispatch(runCollectionFolder(collection.uid, runnerInfo.folderUid, runnerInfo.isRecursive)); dispatch(runCollectionFolder(collection.uid, runnerInfo.folderUid, runnerInfo.isRecursive));
}; };
const closeRunner = () => { const resetRunner = () => {
dispatch( dispatch(
closeCollectionRunner({ resetCollectionRunner({
collectionUid: collection.uid collectionUid: collection.uid
}) })
); );
@ -101,8 +101,8 @@ export default function RunnerResults({ collection }) {
Run Collection Run Collection
</button> </button>
<button className="submit btn btn-sm btn-close mt-6 ml-3" onClick={closeRunner}> <button className="submit btn btn-sm btn-close mt-6 ml-3" onClick={resetRunner}>
Close Reset
</button> </button>
</StyledWrapper> </StyledWrapper>
); );
@ -202,8 +202,8 @@ export default function RunnerResults({ collection }) {
<button type="submit" className="submit btn btn-sm btn-secondary mt-6 ml-3" onClick={runCollection}> <button type="submit" className="submit btn btn-sm btn-secondary mt-6 ml-3" onClick={runCollection}>
Run Collection Run Collection
</button> </button>
<button className="btn btn-sm btn-close mt-6 ml-3" onClick={closeRunner}> <button className="btn btn-sm btn-close mt-6 ml-3" onClick={resetRunner}>
Close Reset
</button> </button>
</div> </div>
) : null} ) : null}

View File

@ -1,9 +1,10 @@
import React from 'react'; import React from 'react';
import get from 'lodash/get'; import get from 'lodash/get';
import { uuid } from 'utils/common';
import Modal from 'components/Modal'; import Modal from 'components/Modal';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { addTab } from 'providers/ReduxStore/slices/tabs';
import { runCollectionFolder } from 'providers/ReduxStore/slices/collections/actions'; import { runCollectionFolder } from 'providers/ReduxStore/slices/collections/actions';
import { showRunnerView } from 'providers/ReduxStore/slices/collections';
import { flattenItems } from 'utils/collections'; import { flattenItems } from 'utils/collections';
import StyledWrapper from './StyledWrapper'; import StyledWrapper from './StyledWrapper';
@ -12,8 +13,10 @@ const RunCollectionItem = ({ collection, item, onClose }) => {
const onSubmit = (recursive) => { const onSubmit = (recursive) => {
dispatch( dispatch(
showRunnerView({ addTab({
collectionUid: collection.uid uid: uuid(),
collectionUid: collection.uid,
type: 'collection-runner'
}) })
); );
dispatch(runCollectionFolder(collection.uid, item ? item.uid : null, recursive)); dispatch(runCollectionFolder(collection.uid, item ? item.uid : null, recursive));

View File

@ -6,7 +6,7 @@ import { useDrag, useDrop } from 'react-dnd';
import { IconChevronRight, IconDots } from '@tabler/icons'; import { IconChevronRight, IconDots } from '@tabler/icons';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { addTab, focusTab } from 'providers/ReduxStore/slices/tabs'; import { addTab, focusTab } from 'providers/ReduxStore/slices/tabs';
import { collectionFolderClicked, hideRunnerView } from 'providers/ReduxStore/slices/collections'; import { collectionFolderClicked } from 'providers/ReduxStore/slices/collections';
import { moveItem } from 'providers/ReduxStore/slices/collections/actions'; import { moveItem } from 'providers/ReduxStore/slices/collections/actions';
import Dropdown from 'components/Dropdown'; import Dropdown from 'components/Dropdown';
import NewRequest from 'components/Sidebar/NewRequest'; import NewRequest from 'components/Sidebar/NewRequest';
@ -86,11 +86,6 @@ const CollectionItem = ({ item, collection, searchText }) => {
}); });
const handleClick = (event) => { const handleClick = (event) => {
dispatch(
hideRunnerView({
collectionUid: collection.uid
})
);
if (isItemARequest(item)) { if (isItemARequest(item)) {
if (itemIsOpenedInTabs(item, tabs)) { if (itemIsOpenedInTabs(item, tabs)) {
dispatch( dispatch(

View File

@ -1,5 +1,6 @@
import React, { useState, forwardRef, useRef, useEffect } from 'react'; import React, { useState, forwardRef, useRef, useEffect } from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
import { uuid } from 'utils/common';
import filter from 'lodash/filter'; import filter from 'lodash/filter';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';
import { useDrop } from 'react-dnd'; import { useDrop } from 'react-dnd';
@ -8,12 +9,12 @@ import Dropdown from 'components/Dropdown';
import { collectionClicked } from 'providers/ReduxStore/slices/collections'; import { collectionClicked } from 'providers/ReduxStore/slices/collections';
import { moveItemToRootOfCollection } from 'providers/ReduxStore/slices/collections/actions'; import { moveItemToRootOfCollection } from 'providers/ReduxStore/slices/collections/actions';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { addTab } from 'providers/ReduxStore/slices/tabs';
import NewRequest from 'components/Sidebar/NewRequest'; import NewRequest from 'components/Sidebar/NewRequest';
import NewFolder from 'components/Sidebar/NewFolder'; import NewFolder from 'components/Sidebar/NewFolder';
import CollectionItem from './CollectionItem'; import CollectionItem from './CollectionItem';
import RemoveCollection from './RemoveCollection'; import RemoveCollection from './RemoveCollection';
import CollectionProperties from './CollectionProperties'; import CollectionProperties from './CollectionProperties';
import RunCollectionItem from './CollectionItem/RunCollectionItem';
import { doesCollectionHaveItemsMatchingSearchText } from 'utils/collections/search'; import { doesCollectionHaveItemsMatchingSearchText } from 'utils/collections/search';
import { isItemAFolder, isItemARequest, transformCollectionToSaveToIdb } from 'utils/collections'; import { isItemAFolder, isItemARequest, transformCollectionToSaveToIdb } from 'utils/collections';
import exportCollection from 'utils/collections/export'; import exportCollection from 'utils/collections/export';
@ -26,7 +27,6 @@ const Collection = ({ collection, searchText }) => {
const [showNewRequestModal, setShowNewRequestModal] = useState(false); const [showNewRequestModal, setShowNewRequestModal] = useState(false);
const [showRenameCollectionModal, setShowRenameCollectionModal] = useState(false); const [showRenameCollectionModal, setShowRenameCollectionModal] = useState(false);
const [showRemoveCollectionModal, setShowRemoveCollectionModal] = useState(false); const [showRemoveCollectionModal, setShowRemoveCollectionModal] = useState(false);
const [showRunCollectionModal, setShowRunCollectionModal] = useState(false);
const [collectionPropertiesModal, setCollectionPropertiesModal] = useState(false); const [collectionPropertiesModal, setCollectionPropertiesModal] = useState(false);
const [collectionIsCollapsed, setCollectionIsCollapsed] = useState(collection.collapsed); const [collectionIsCollapsed, setCollectionIsCollapsed] = useState(collection.collapsed);
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -41,6 +41,16 @@ const Collection = ({ collection, searchText }) => {
); );
}); });
const handleRun = () => {
dispatch(
addTab({
uid: uuid(),
collectionUid: collection.uid,
type: 'collection-runner'
})
);
};
useEffect(() => { useEffect(() => {
if (searchText && searchText.length) { if (searchText && searchText.length) {
setCollectionIsCollapsed(false); setCollectionIsCollapsed(false);
@ -105,9 +115,6 @@ const Collection = ({ collection, searchText }) => {
{showRemoveCollectionModal && ( {showRemoveCollectionModal && (
<RemoveCollection collection={collection} onClose={() => setShowRemoveCollectionModal(false)} /> <RemoveCollection collection={collection} onClose={() => setShowRemoveCollectionModal(false)} />
)} )}
{showRunCollectionModal && (
<RunCollectionItem collection={collection} onClose={() => setShowRunCollectionModal(false)} />
)}
{collectionPropertiesModal && ( {collectionPropertiesModal && (
<CollectionProperties collection={collection} onClose={() => setCollectionPropertiesModal(false)} /> <CollectionProperties collection={collection} onClose={() => setCollectionPropertiesModal(false)} />
)} )}
@ -147,7 +154,7 @@ const Collection = ({ collection, searchText }) => {
className="dropdown-item" className="dropdown-item"
onClick={(e) => { onClick={(e) => {
menuDropdownTippyRef.current.hide(); menuDropdownTippyRef.current.hide();
setShowRunCollectionModal(true); handleRun();
}} }}
> >
Run Run

View File

@ -769,7 +769,6 @@ export const openCollectionEvent = (uid, pathname, brunoConfig) => (dispatch, ge
name: brunoConfig.name, name: brunoConfig.name,
pathname: pathname, pathname: pathname,
items: [], items: [],
showRunner: false,
collectionVariables: {}, collectionVariables: {},
brunoConfig: brunoConfig brunoConfig: brunoConfig
}; };

View File

@ -1016,30 +1016,6 @@ export const collectionsSlice = createSlice({
collection.name = newName; collection.name = newName;
} }
}, },
toggleRunnerView: (state, action) => {
const { collectionUid } = action.payload;
const collection = findCollectionByUid(state.collections, collectionUid);
if (collection) {
collection.showRunner = !collection.showRunner;
}
},
showRunnerView: (state, action) => {
const { collectionUid } = action.payload;
const collection = findCollectionByUid(state.collections, collectionUid);
if (collection) {
collection.showRunner = true;
}
},
hideRunnerView: (state, action) => {
const { collectionUid } = action.payload;
const collection = findCollectionByUid(state.collections, collectionUid);
if (collection) {
collection.showRunner = false;
}
},
resetRunResults: (state, action) => { resetRunResults: (state, action) => {
const { collectionUid } = action.payload; const { collectionUid } = action.payload;
const collection = findCollectionByUid(state.collections, collectionUid); const collection = findCollectionByUid(state.collections, collectionUid);
@ -1149,13 +1125,12 @@ export const collectionsSlice = createSlice({
} }
} }
}, },
closeCollectionRunner: (state, action) => { resetCollectionRunner: (state, action) => {
const { collectionUid } = action.payload; const { collectionUid } = action.payload;
const collection = findCollectionByUid(state.collections, collectionUid); const collection = findCollectionByUid(state.collections, collectionUid);
if (collection) { if (collection) {
collection.runnerResult = null; collection.runnerResult = null;
collection.showRunner = false;
} }
} }
} }
@ -1216,13 +1191,10 @@ export const {
collectionUnlinkDirectoryEvent, collectionUnlinkDirectoryEvent,
collectionAddEnvFileEvent, collectionAddEnvFileEvent,
collectionRenamedEvent, collectionRenamedEvent,
toggleRunnerView,
showRunnerView,
hideRunnerView,
resetRunResults, resetRunResults,
runRequestEvent, runRequestEvent,
runFolderEvent, runFolderEvent,
closeCollectionRunner resetCollectionRunner
} = collectionsSlice.actions; } = collectionsSlice.actions;
export default collectionsSlice.reducer; export default collectionsSlice.reducer;

View File

@ -10,6 +10,10 @@ const initialState = {
activeTabUid: null activeTabUid: null
}; };
const tabTypeAlreadyExists = (tabs, collectionUid, type) => {
return find(tabs, (tab) => tab.collectionUid === collectionUid && tab.type === type);
};
export const tabsSlice = createSlice({ export const tabsSlice = createSlice({
name: 'tabs', name: 'tabs',
initialState, initialState,
@ -20,8 +24,8 @@ export const tabsSlice = createSlice({
return; return;
} }
if (action.payload.type === 'variables') { if (['variables', 'collection-settings', 'collection-runner'].includes(action.payload.type)) {
const tab = find(state.tabs, (t) => t.collectionUid === action.payload.collectionUid && t.type === 'variables'); const tab = tabTypeAlreadyExists(state.tabs, action.payload.collectionUid, action.payload.type);
if (tab) { if (tab) {
state.activeTabUid = tab.uid; state.activeTabUid = tab.uid;
return; return;

View File

@ -124,7 +124,6 @@ const collectionSchema = Yup.object({
.nullable(), .nullable(),
environments: environmentsSchema, environments: environmentsSchema,
pathname: Yup.string().nullable(), pathname: Yup.string().nullable(),
showRunner: Yup.boolean(),
runnerResult: Yup.object({ runnerResult: Yup.object({
items: Yup.array() items: Yup.array()
}), }),