From fc93faff064be9a4ca185316f38a5c68cc7df708 Mon Sep 17 00:00:00 2001 From: Anusree Subash Date: Sat, 1 Oct 2022 18:17:33 +0530 Subject: [PATCH] feat: search collections, resolves #1 --- .../Collection/CollectionItem/index.js | 31 ++++++++++++++++--- .../Sidebar/Collections/Collection/index.js | 25 ++++++++++++--- .../components/Sidebar/Collections/index.js | 5 +-- renderer/components/Sidebar/index.js | 4 ++- renderer/utils/collections/search.js | 21 +++++++++++++ 5 files changed, 75 insertions(+), 11 deletions(-) create mode 100644 renderer/utils/collections/search.js diff --git a/renderer/components/Sidebar/Collections/Collection/CollectionItem/index.js b/renderer/components/Sidebar/Collections/Collection/CollectionItem/index.js index f9b67f259..2b6ce2291 100644 --- a/renderer/components/Sidebar/Collections/Collection/CollectionItem/index.js +++ b/renderer/components/Sidebar/Collections/Collection/CollectionItem/index.js @@ -1,4 +1,4 @@ -import React, { useState, useRef, forwardRef } from 'react'; +import React, { useState, useRef, forwardRef, useEffect } from 'react'; import range from 'lodash/range'; import classnames from 'classnames'; import { IconChevronRight, IconDots } from '@tabler/icons'; @@ -12,10 +12,11 @@ import RequestMethod from './RequestMethod'; import RenameCollectionItem from './RenameCollectionItem'; import DeleteCollectionItem from './DeleteCollectionItem'; import { isItemARequest, isItemAFolder, itemIsOpenedInTabs } from 'utils/tabs'; +import { doesRequestMatchSearchText, doesFolderHaveItemsMatchSearchText } from 'utils/collections/search'; import StyledWrapper from './StyledWrapper'; -const CollectionItem = ({item, collection}) => { +const CollectionItem = ({item, collection, searchText}) => { const tabs = useSelector((state) => state.tabs.tabs); const activeTabUid = useSelector((state) => state.tabs.activeTabUid); const isDragging = useSelector((state) => state.app.isDragging); @@ -25,6 +26,15 @@ const CollectionItem = ({item, collection}) => { const [deleteItemModalOpen, setDeleteItemModalOpen] = useState(false); const [newRequestModalOpen, setNewRequestModalOpen] = useState(false); const [newFolderModalOpen, setNewFolderModalOpen] = useState(false); + const [itemIsCollapsed, setItemisCollapsed] = useState(item.collapsed); + + useEffect(() => { + if (searchText && searchText.length) { + setItemisCollapsed(false); + } else { + setItemisCollapsed(item.collapsed); + } + }, [searchText, item]); const dropdownTippyRef = useRef(); const MenuIcon = forwardRef((props, ref) => { @@ -36,7 +46,7 @@ const CollectionItem = ({item, collection}) => { }); const iconClassName = classnames({ - 'rotate-90': item.collapsed + 'rotate-90': !itemIsCollapsed }); const itemRowClassName = classnames('flex collection-item-name items-center', { @@ -71,6 +81,18 @@ const CollectionItem = ({item, collection}) => { 'is-dragging': isDragging }); + if(searchText && searchText.length) { + if(isItemARequest(item)) { + if(!doesRequestMatchSearchText(item, searchText)) { + return null; + } + } else { + if (!doesFolderHaveItemsMatchSearchText(item, searchText)) { + return null; + }; + } + } + return ( {renameItemModalOpen && setRenameItemModalOpen(false)}/>} @@ -148,13 +170,14 @@ const CollectionItem = ({item, collection}) => { - {item.collapsed ? ( + {!itemIsCollapsed ? (
{item.items && item.items.length ? item.items.map((i) => { return }) : null}
diff --git a/renderer/components/Sidebar/Collections/Collection/index.js b/renderer/components/Sidebar/Collections/Collection/index.js index 0e3e8d237..fa010efa6 100644 --- a/renderer/components/Sidebar/Collections/Collection/index.js +++ b/renderer/components/Sidebar/Collections/Collection/index.js @@ -1,4 +1,4 @@ -import React, { useState, forwardRef, useRef } from 'react'; +import React, { useState, forwardRef, useRef, useEffect } from 'react'; import classnames from 'classnames'; import { IconChevronRight, IconDots } from '@tabler/icons'; import Dropdown from 'components/Dropdown'; @@ -7,14 +7,24 @@ import { useDispatch } from 'react-redux'; import NewRequest from 'components/Sidebar/NewRequest'; import NewFolder from 'components/Sidebar/NewFolder'; import CollectionItem from './CollectionItem'; +import { doesCollectionHaveItemsMatchingSearchText } from 'utils/collections/search'; import StyledWrapper from './StyledWrapper'; -const Collection = ({collection}) => { +const Collection = ({collection, searchText}) => { const [showNewFolderModal, setShowNewFolderModal] = useState(false); const [showNewRequestModal, setShowNewRequestModal] = useState(false); + const [collectionIsCollapsed, setCollectionIsCollapsed] = useState(collection.collapsed); const dispatch = useDispatch(); + useEffect(() => { + if (searchText && searchText.length) { + setCollectionIsCollapsed(false); + } else { + setCollectionIsCollapsed(collection.collapsed); + } + }, [searchText, collection]); + const menuDropdownTippyRef = useRef(); const onMenuDropdownCreate = (ref) => menuDropdownTippyRef.current = ref; const MenuIcon = forwardRef((props, ref) => { @@ -26,13 +36,19 @@ const Collection = ({collection}) => { }); const iconClassName = classnames({ - 'rotate-90': !collection.collapsed + 'rotate-90': !collectionIsCollapsed }); const handleClick = (event) => { dispatch(collectionClicked(collection.uid)); }; + if(searchText && searchText.length) { + if(!doesCollectionHaveItemsMatchingSearchText(collection, searchText)) { + return null; + } + } + return ( {showNewRequestModal && setShowNewRequestModal(false)}/>} @@ -71,13 +87,14 @@ const Collection = ({collection}) => {
- {!collection.collapsed ? ( + {!collectionIsCollapsed ? (
{collection.items && collection.items.length ? collection.items.map((i) => { return }) : null}
diff --git a/renderer/components/Sidebar/Collections/index.js b/renderer/components/Sidebar/Collections/index.js index 951a0e809..f7fb72d17 100644 --- a/renderer/components/Sidebar/Collections/index.js +++ b/renderer/components/Sidebar/Collections/index.js @@ -1,14 +1,15 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import Collection from './Collection'; -const Collections = () => { +const Collections = ({searchText}) => { const collections = useSelector((state) => state.collections.collections); return (
{collections && collections.length ? collections.map((c) => { return diff --git a/renderer/components/Sidebar/index.js b/renderer/components/Sidebar/index.js index cbc3f68d8..2293167ab 100644 --- a/renderer/components/Sidebar/index.js +++ b/renderer/components/Sidebar/index.js @@ -18,6 +18,7 @@ const Sidebar = () => { const dispatch = useDispatch(); const [dragging, setDragging] = useState(false); + const [searchText, setSearchText] = useState(''); const handleMouseMove = (e) => { if(dragging) { @@ -86,10 +87,11 @@ const Sidebar = () => { autoComplete="off" autoCorrect="off" autoCapitalize="off" spellCheck="false" className="block w-full pl-7 py-1 sm:text-sm" placeholder="search" + onChange={(e) => setSearchText(e.target.value.toLowerCase())} />
- +
diff --git a/renderer/utils/collections/search.js b/renderer/utils/collections/search.js new file mode 100644 index 000000000..84e6ee303 --- /dev/null +++ b/renderer/utils/collections/search.js @@ -0,0 +1,21 @@ +import { flattenItems, isItemARequest } from "./index"; +import filter from 'lodash/filter'; +import find from 'lodash/find'; + +export const doesRequestMatchSearchText = (request, searchText) => { + return request.name.toLowerCase().includes(searchText.toLowerCase()); +}; + +export const doesFolderHaveItemsMatchSearchText = (item, searchText) => { + let flattenedItems = flattenItems(item.items); + let requestItems = filter(flattenedItems, (item) => isItemARequest(item)); + + return find(requestItems, (request) => doesRequestMatchSearchText(request, searchText)); +}; + +export const doesCollectionHaveItemsMatchingSearchText = (collection, searchText) => { + let flattenedItems = flattenItems(collection.items); + let requestItems = filter(flattenedItems, (item) => isItemARequest(item)); + + return find(requestItems, (request) => doesRequestMatchSearchText(request, searchText)); +} \ No newline at end of file