mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-21 15:33:11 +01:00
feat: search collections, resolves #1
This commit is contained in:
parent
c7cced5868
commit
fc93faff06
@ -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 (
|
||||
<StyledWrapper className={className}>
|
||||
{renameItemModalOpen && <RenameCollectionItem item={item} collection={collection} onClose={() => setRenameItemModalOpen(false)}/>}
|
||||
@ -148,13 +170,14 @@ const CollectionItem = ({item, collection}) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{item.collapsed ? (
|
||||
{!itemIsCollapsed ? (
|
||||
<div>
|
||||
{item.items && item.items.length ? item.items.map((i) => {
|
||||
return <CollectionItem
|
||||
key={i.uid}
|
||||
item={i}
|
||||
collection={collection}
|
||||
searchText={searchText}
|
||||
/>
|
||||
}) : null}
|
||||
</div>
|
||||
|
@ -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 (
|
||||
<StyledWrapper className="flex flex-col">
|
||||
{showNewRequestModal && <NewRequest collection={collection} onClose={() => setShowNewRequestModal(false)}/>}
|
||||
@ -71,13 +87,14 @@ const Collection = ({collection}) => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{!collection.collapsed ? (
|
||||
{!collectionIsCollapsed ? (
|
||||
<div>
|
||||
{collection.items && collection.items.length ? collection.items.map((i) => {
|
||||
return <CollectionItem
|
||||
key={i.uid}
|
||||
item={i}
|
||||
collection={collection}
|
||||
searchText={searchText}
|
||||
/>
|
||||
}) : null}
|
||||
</div>
|
||||
|
@ -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 (
|
||||
<div className="mt-4 flex flex-col">
|
||||
{collections && collections.length ? collections.map((c) => {
|
||||
return <Collection
|
||||
searchText={searchText}
|
||||
collection={c}
|
||||
key={c.uid}
|
||||
/>
|
||||
|
@ -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())}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Collections />
|
||||
<Collections searchText={searchText}/>
|
||||
</div>
|
||||
<div className="flex px-1 py-2 items-center cursor-pointer text-gray-500 select-none">
|
||||
<div className="flex items-center ml-1 text-xs ">
|
||||
|
21
renderer/utils/collections/search.js
Normal file
21
renderer/utils/collections/search.js
Normal file
@ -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));
|
||||
}
|
Loading…
Reference in New Issue
Block a user