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:
commit
9414ae23df
2 changed files with 107 additions and 65 deletions
|
|
@ -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 ? (
|
||||||
|
|
|
||||||
|
|
@ -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,11 +31,45 @@ 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="relative mt-2 flex items-center mb-2 mx-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="search"
|
||||||
|
id="search"
|
||||||
|
placeholder="Search nodes"
|
||||||
|
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"
|
||||||
|
onChange={(e) => {
|
||||||
|
handleSearchInput(e.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-y-0 right-0 flex py-1.5 pr-3 items-center">
|
||||||
|
<MagnifyingGlassIcon className="h-5 w-5 dark:text-white"></MagnifyingGlassIcon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="mt-1 w-full">
|
<div className="mt-1 w-full">
|
||||||
{Object.keys(data)
|
{Object.keys(dataFilter)
|
||||||
.sort()
|
.sort()
|
||||||
.map((d: keyof APIObjectType, i) => (
|
.map((d: keyof APIObjectType, i) =>
|
||||||
|
Object.keys(dataFilter[d]).length > 0 ? (
|
||||||
<DisclosureComponent
|
<DisclosureComponent
|
||||||
key={i}
|
key={i}
|
||||||
button={{
|
button={{
|
||||||
|
|
@ -37,7 +78,7 @@ export default function ExtraSidebar() {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="p-2 flex flex-col gap-2">
|
<div className="p-2 flex flex-col gap-2">
|
||||||
{Object.keys(data[d])
|
{Object.keys(dataFilter[d])
|
||||||
.sort()
|
.sort()
|
||||||
.map((t: string, k) => (
|
.map((t: string, k) => (
|
||||||
<TooltipReact
|
<TooltipReact
|
||||||
|
|
@ -52,7 +93,8 @@ export default function ExtraSidebar() {
|
||||||
draggable
|
draggable
|
||||||
className={" cursor-grab border-l-8 rounded-l-md"}
|
className={" cursor-grab border-l-8 rounded-l-md"}
|
||||||
style={{
|
style={{
|
||||||
borderLeftColor: nodeColors[d] ?? nodeColors.unknown,
|
borderLeftColor:
|
||||||
|
nodeColors[d] ?? nodeColors.unknown,
|
||||||
}}
|
}}
|
||||||
onDragStart={(event) =>
|
onDragStart={(event) =>
|
||||||
onDragStart(event, {
|
onDragStart(event, {
|
||||||
|
|
@ -78,12 +120,13 @@ export default function ExtraSidebar() {
|
||||||
</div>
|
</div>
|
||||||
</TooltipReact>
|
</TooltipReact>
|
||||||
))}
|
))}
|
||||||
{Object.keys(data[d]).length === 0 && (
|
|
||||||
<div className="text-gray-400 text-center">Coming soon</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</DisclosureComponent>
|
</DisclosureComponent>
|
||||||
))}
|
) : (
|
||||||
|
<div key={i}></div>
|
||||||
|
)
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue