import React, { useState, useRef, forwardRef, useEffect } from 'react'; import range from 'lodash/range'; import filter from 'lodash/filter'; import classnames from 'classnames'; import { useDrag, useDrop } from 'react-dnd'; import { IconChevronRight, IconDots } from '@tabler/icons'; import { useSelector, useDispatch } from 'react-redux'; import { addTab, focusTab } from 'providers/ReduxStore/slices/tabs'; import { collectionFolderClicked } from 'providers/ReduxStore/slices/collections'; import { moveItem } from 'providers/ReduxStore/slices/collections/actions'; import Dropdown from 'components/Dropdown'; import NewRequest from 'components/Sidebar/NewRequest'; import NewFolder from 'components/Sidebar/NewFolder'; import RequestMethod from './RequestMethod'; import RenameCollectionItem from './RenameCollectionItem'; import CloneCollectionItem from './CloneCollectionItem'; import DeleteCollectionItem from './DeleteCollectionItem'; import RunCollectionItem from './RunCollectionItem'; import GenerateCodeItem from './GenerateCodeItem'; import { isItemARequest, isItemAFolder, itemIsOpenedInTabs } from 'utils/tabs'; import { doesRequestMatchSearchText, doesFolderHaveItemsMatchSearchText } from 'utils/collections/search'; import { getDefaultRequestPaneTab } from 'utils/collections'; import { hideHomePage } from 'providers/ReduxStore/slices/app'; import toast from 'react-hot-toast'; import StyledWrapper from './StyledWrapper'; const CollectionItem = ({ item, collection, searchText }) => { const tabs = useSelector((state) => state.tabs.tabs); const activeTabUid = useSelector((state) => state.tabs.activeTabUid); const isSidebarDragging = useSelector((state) => state.app.isDragging); const dispatch = useDispatch(); const [renameItemModalOpen, setRenameItemModalOpen] = useState(false); const [cloneItemModalOpen, setCloneItemModalOpen] = useState(false); const [deleteItemModalOpen, setDeleteItemModalOpen] = useState(false); const [generateCodeItemModalOpen, setGenerateCodeItemModalOpen] = useState(false); const [newRequestModalOpen, setNewRequestModalOpen] = useState(false); const [newFolderModalOpen, setNewFolderModalOpen] = useState(false); const [runCollectionModalOpen, setRunCollectionModalOpen] = useState(false); const [itemIsCollapsed, setItemisCollapsed] = useState(item.collapsed); const [{ isDragging }, drag] = useDrag({ type: `COLLECTION_ITEM_${collection.uid}`, item: item, collect: (monitor) => ({ isDragging: monitor.isDragging() }) }); const [{ isOver }, drop] = useDrop({ accept: `COLLECTION_ITEM_${collection.uid}`, drop: (draggedItem) => { if (draggedItem.uid !== item.uid) { dispatch(moveItem(collection.uid, draggedItem.uid, item.uid)); } }, canDrop: (draggedItem) => { return draggedItem.uid !== item.uid; }, collect: (monitor) => ({ isOver: monitor.isOver() }) }); useEffect(() => { if (searchText && searchText.length) { setItemisCollapsed(false); } else { setItemisCollapsed(item.collapsed); } }, [searchText, item]); const dropdownTippyRef = useRef(); const MenuIcon = forwardRef((props, ref) => { return (
); }); const iconClassName = classnames({ 'rotate-90': !itemIsCollapsed }); const itemRowClassName = classnames('flex collection-item-name items-center', { 'item-focused-in-tab': item.uid == activeTabUid }); const handleClick = (event) => { switch (event.button) { case 0: // left click if (isItemARequest(item)) { dispatch(hideHomePage()); if (itemIsOpenedInTabs(item, tabs)) { dispatch( focusTab({ uid: item.uid }) ); return; } dispatch( addTab({ uid: item.uid, collectionUid: collection.uid, requestPaneTab: getDefaultRequestPaneTab(item) }) ); return; } dispatch( collectionFolderClicked({ itemUid: item.uid, collectionUid: collection.uid }) ); return; case 2: // right click const _menuDropdown = dropdownTippyRef.current; if (_menuDropdown) { let menuDropdownBehavior = 'show'; if (_menuDropdown.state.isShown) { menuDropdownBehavior = 'hide'; } _menuDropdown[menuDropdownBehavior](); } return; } }; const handleDoubleClick = (event) => { setRenameItemModalOpen(true); }; let indents = range(item.depth); const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref); const isFolder = isItemAFolder(item); const className = classnames('flex flex-col w-full', { 'is-sidebar-dragging': isSidebarDragging }); if (searchText && searchText.length) { if (isItemARequest(item)) { if (!doesRequestMatchSearchText(item, searchText)) { return null; } } else { if (!doesFolderHaveItemsMatchSearchText(item, searchText)) { return null; } } } // we need to sort request items by seq property const sortRequestItems = (items = []) => { return items.sort((a, b) => a.seq - b.seq); }; // we need to sort folder items by name alphabetically const sortFolderItems = (items = []) => { return items.sort((a, b) => a.name.localeCompare(b.name)); }; const handleGenerateCode = (e) => { e.stopPropagation(); dropdownTippyRef.current.hide(); if (item.request.url !== '' || (item.draft?.request.url !== undefined && item.draft?.request.url !== '')) { setGenerateCodeItemModalOpen(true); } else { toast.error('URL is required'); } }; const requestItems = sortRequestItems(filter(item.items, (i) => isItemARequest(i))); const folderItems = sortFolderItems(filter(item.items, (i) => isItemAFolder(i))); return ( {renameItemModalOpen && ( setRenameItemModalOpen(false)} /> )} {cloneItemModalOpen && ( setCloneItemModalOpen(false)} /> )} {deleteItemModalOpen && ( setDeleteItemModalOpen(false)} /> )} {newRequestModalOpen && ( setNewRequestModalOpen(false)} /> )} {newFolderModalOpen && ( setNewFolderModalOpen(false)} /> )} {runCollectionModalOpen && ( setRunCollectionModalOpen(false)} /> )} {generateCodeItemModalOpen && ( setGenerateCodeItemModalOpen(false)} /> )}
drag(drop(node))}>
{indents && indents.length ? indents.map((i) => { return (
 {/* Indent */}
); }) : null}
{isFolder ? ( ) : null}
{item.name}
} placement="bottom-start"> {isFolder && ( <>
{ dropdownTippyRef.current.hide(); setNewRequestModalOpen(true); }} > New Request
{ dropdownTippyRef.current.hide(); setNewFolderModalOpen(true); }} > New Folder
{ dropdownTippyRef.current.hide(); setRunCollectionModalOpen(true); }} > Run
)}
{ dropdownTippyRef.current.hide(); setRenameItemModalOpen(true); }} > Rename
{!isFolder && (
{ dropdownTippyRef.current.hide(); setCloneItemModalOpen(true); }} > Clone
)} {!isFolder && item.type === 'http-request' && (
{ handleGenerateCode(e); }} > Generate Code
)}
{ dropdownTippyRef.current.hide(); setDeleteItemModalOpen(true); }} > Delete
{!itemIsCollapsed ? (
{folderItems && folderItems.length ? folderItems.map((i) => { return ; }) : null} {requestItems && requestItems.length ? requestItems.map((i) => { return ; }) : null}
) : null}
); }; export default CollectionItem;