Adding search functionality to ExtraSideBarComponent (#411)

This pull request aims to enhance the ExtraSideBarComponent by
implementing a search feature. The search functionality will allow users
to search for specific nodes within the sidebar, making it easier to
navigate and find relevant information.

Modified ExtraSideBarComponent to include a search input field.
Implemented search logic to filter nodes based on user input.
Added a search results display section to show the filtered nodes.
Integrated search functionality with the existing node navigation.
Updated relevant tests to ensure proper functionality and coverage.
Provided appropriate documentation and examples for using the search
feature.
This commit is contained in:
anovazzi1 2023-05-31 01:05:37 -03:00 • committed by GitHub
commit 9414ae23df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 107 additions and 65 deletions

View file

@ -1,6 +1,6 @@
import { Disclosure } from "@headlessui/react"; import { Disclosure } from "@headlessui/react";
import { ChevronLeftIcon } from "@heroicons/react/24/outline"; import { ChevronLeftIcon } from "@heroicons/react/24/outline";
import { useContext } from "react"; import { useContext, useState } from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { classNames } from "../../utils"; import { classNames } from "../../utils";
import { locationContext } from "../../contexts/locationContext"; import { locationContext } from "../../contexts/locationContext";
@ -13,6 +13,7 @@ export default function ExtraSidebar() {
extraNavigation, extraNavigation,
extraComponent, extraComponent,
} = useContext(locationContext); } = useContext(locationContext);
return ( return (
<> <>
<aside <aside
@ -21,10 +22,8 @@ export default function ExtraSidebar() {
} flex-shrink-0 flex overflow-hidden flex-col border-r dark:border-r-gray-700 transition-all duration-500`} } flex-shrink-0 flex overflow-hidden flex-col border-r dark:border-r-gray-700 transition-all duration-500`}
> >
<div className="w-52 dark:bg-gray-800 border dark:border-gray-700 overflow-y-auto scrollbar-hide h-full flex flex-col items-start"> <div className="w-52 dark:bg-gray-800 border dark:border-gray-700 overflow-y-auto scrollbar-hide h-full flex flex-col items-start">
<div className="flex pt-1 px-4 justify-between align-middle w-full"> <div className="flex px-4 justify-between align-middle w-full">
<span className="text-gray-900 dark:text-white py-[2px] font-medium "> <span className="text-gray-900 dark:text-white py-[2px] font-medium "></span>
{extraNavigation.title}
</span>
</div> </div>
<div className="flex flex-grow flex-col w-full"> <div className="flex flex-grow flex-col w-full">
{extraNavigation.options ? ( {extraNavigation.options ? (

View file

@ -1,13 +1,20 @@
import { Bars2Icon } from "@heroicons/react/24/outline"; import { Bars2Icon } from "@heroicons/react/24/outline";
import DisclosureComponent from "../DisclosureComponent"; import DisclosureComponent from "../DisclosureComponent";
import { nodeColors, nodeIcons, nodeNames } from "../../../../utils"; import {
import { useContext, useEffect, useState } from "react"; classNames,
nodeColors,
nodeIcons,
nodeNames,
} from "../../../../utils";
import { useContext, useEffect, useState, useRef } from "react";
import { typesContext } from "../../../../contexts/typesContext"; import { typesContext } from "../../../../contexts/typesContext";
import { APIClassType, APIObjectType } from "../../../../types/api"; import { APIClassType, APIObjectType } from "../../../../types/api";
import TooltipReact from "../../../../components/ReactTooltipComponent"; import TooltipReact from "../../../../components/ReactTooltipComponent";
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
export default function ExtraSidebar() { export default function ExtraSidebar() {
const { data } = useContext(typesContext); const { data } = useContext(typesContext);
const [dataFilter, setFilterData] = useState(data);
function onDragStart( function onDragStart(
event: React.DragEvent<any>, event: React.DragEvent<any>,
@ -24,66 +31,102 @@ export default function ExtraSidebar() {
event.dataTransfer.setData("json", JSON.stringify(data)); event.dataTransfer.setData("json", JSON.stringify(data));
} }
function handleSearchInput(e: string) {
setFilterData((_) => {
let ret = {};
Object.keys(data).forEach((d: keyof APIObjectType, i) => {
ret[d] = {};
let keys = Object.keys(data[d]).filter((nd) =>
nd.toLowerCase().includes(e.toLowerCase())
);
keys.forEach((element) => {
ret[d][element] = data[d][element];
});
});
return ret;
});
}
return ( return (
<div className="mt-1 w-full"> <>
{Object.keys(data) <div className="relative mt-2 flex items-center mb-2 mx-2">
.sort() <input
.map((d: keyof APIObjectType, i) => ( type="text"
<DisclosureComponent name="search"
key={i} id="search"
button={{ placeholder="Search nodes"
title: nodeNames[d] ?? nodeNames.unknown, className="dark:text-white focus:outline-none block w-full rounded-md py-1.5 ps-3 pr-9 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 sm:text-sm sm:leading-6 dark:ring-0 dark:bg-[#2d3747] dark:focus:outline-none"
Icon: nodeIcons[d] ?? nodeIcons.unknown, onChange={(e) => {
}} handleSearchInput(e.target.value);
> }}
<div className="p-2 flex flex-col gap-2"> />
{Object.keys(data[d]) <div className="absolute inset-y-0 right-0 flex py-1.5 pr-3 items-center">
.sort() <MagnifyingGlassIcon className="h-5 w-5 dark:text-white"></MagnifyingGlassIcon>
.map((t: string, k) => ( </div>
<TooltipReact </div>
selector={t}
htmlContent={t} <div className="mt-1 w-full">
position="right" {Object.keys(dataFilter)
delayShow={1500} .sort()
key={k} .map((d: keyof APIObjectType, i) =>
> Object.keys(dataFilter[d]).length > 0 ? (
<div key={k} data-tooltip-id={t}> <DisclosureComponent
<div key={i}
draggable button={{
className={" cursor-grab border-l-8 rounded-l-md"} title: nodeNames[d] ?? nodeNames.unknown,
style={{ Icon: nodeIcons[d] ?? nodeIcons.unknown,
borderLeftColor: nodeColors[d] ?? nodeColors.unknown, }}
}} >
onDragStart={(event) => <div className="p-2 flex flex-col gap-2">
onDragStart(event, { {Object.keys(dataFilter[d])
type: t, .sort()
node: data[d][t], .map((t: string, k) => (
}) <TooltipReact
} selector={t}
onDragEnd={() => { htmlContent={t}
document.body.removeChild( position="right"
document.getElementsByClassName( delayShow={1500}
"cursor-grabbing" key={k}
)[0]
);
}}
> >
<div className="flex w-full justify-between text-sm px-3 py-1 bg-white dark:bg-gray-800 items-center border-dashed border-gray-400 dark:border-gray-600 border-l-0 rounded-md rounded-l-none border"> <div key={k} data-tooltip-id={t}>
<span className="text-black dark:text-white w-36 pr-1 truncate text-xs"> <div
{t} draggable
</span> className={" cursor-grab border-l-8 rounded-l-md"}
<Bars2Icon className="w-4 h-6 text-gray-400 dark:text-gray-600" /> style={{
borderLeftColor:
nodeColors[d] ?? nodeColors.unknown,
}}
onDragStart={(event) =>
onDragStart(event, {
type: t,
node: data[d][t],
})
}
onDragEnd={() => {
document.body.removeChild(
document.getElementsByClassName(
"cursor-grabbing"
)[0]
);
}}
>
<div className="flex w-full justify-between text-sm px-3 py-1 bg-white dark:bg-gray-800 items-center border-dashed border-gray-400 dark:border-gray-600 border-l-0 rounded-md rounded-l-none border">
<span className="text-black dark:text-white w-36 pr-1 truncate text-xs">
{t}
</span>
<Bars2Icon className="w-4 h-6 text-gray-400 dark:text-gray-600" />
</div>
</div>
</div> </div>
</div> </TooltipReact>
</div> ))}
</TooltipReact> </div>
))} </DisclosureComponent>
{Object.keys(data[d]).length === 0 && ( ) : (
<div className="text-gray-400 text-center">Coming soon</div> <div key={i}></div>
)} )
</div> )}
</DisclosureComponent> </div>
))} </>
</div>
); );
} }