Browse Source

add simple peer search

pull/157/head
osirisfrik 2 years ago
parent
commit
e76d6dab5f
  1. 46
      src/components/generic/Search.tsx
  2. 18
      src/core/utils/getDeepField.ts
  3. 12
      src/pages/Messages.tsx
  4. 19
      src/pages/Peers.tsx

46
src/components/generic/Search.tsx

@ -0,0 +1,46 @@
import { SearchIcon } from "lucide-react";
import { Input } from "@components/UI/Input";
import { getDeepField } from "@app/core/utils/getDeepField";
export interface SearchProps<T extends object = object> {
data: T[];
filterBy: string;
onFilter: (results: T[]) => void;
}
export function Search<T extends object = object>({
data,
filterBy,
onFilter,
}: SearchProps<T>): JSX.Element {
let timeout: number | string | NodeJS.Timeout;
const onInputChange = (query: string) => {
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
const regex = new RegExp(query, "gi");
const results = data.filter((item) => {
const value = getDeepField(item, filterBy);
return value && regex.test(`${value}`);
});
onFilter(results);
}, 250);
};
return (
<>
<Input
placeholder="Search"
action={{
icon: SearchIcon,
onClick: () => false,
}}
onChange={(e) => onInputChange(e.target.value)}
/>
</>
);
}

18
src/core/utils/getDeepField.ts

@ -0,0 +1,18 @@
export function getDeepField<O extends object = object, D = any>(
object: O,
path: string,
defaultValue?: D,
): D | undefined {
const keys = path.split(".");
let value: any = object;
for (const key of keys) {
if (!Object.hasOwn(value, key)) {
return defaultValue;
}
value = value[key];
}
return value ?? defaultValue;
}

12
src/pages/Messages.tsx

@ -1,8 +1,10 @@
import type { NodeInfo } from "@buf/meshtastic_protobufs.bufbuild_es/meshtastic/mesh_pb";
import { ChannelChat } from "@components/PageComponents/Messages/ChannelChat.js";
import { PageLayout } from "@components/PageLayout.js";
import { Sidebar } from "@components/Sidebar.js";
import { SidebarSection } from "@components/UI/Sidebar/SidebarSection.js";
import { SidebarButton } from "@components/UI/Sidebar/sidebarButton.js";
import { Search } from "@app/components/generic/Search.js";
import { useDevice } from "@core/stores/deviceStore.js";
import { Hashicon } from "@emeraldpay/hashicon-react";
import { Protobuf, Types } from "@meshtastic/js";
@ -25,6 +27,9 @@ export const MessagesPage = (): JSX.Element => {
(ch) => ch.role !== Protobuf.Channel.Channel_Role.DISABLED,
);
const currentChannel = channels.get(activeChat);
const [searchNodes, setSearchNodes] = useState<NodeInfo[]>(filteredNodes);
const onSearchFilter = (result: NodeInfo[]) => setSearchNodes(result);
return (
<>
@ -50,7 +55,12 @@ export const MessagesPage = (): JSX.Element => {
))}
</SidebarSection>
<SidebarSection label="Peers">
{filteredNodes.map((node) => (
<Search<NodeInfo>
data={filteredNodes}
filterBy="user.longName"
onFilter={onSearchFilter}
/>
{searchNodes.map((node) => (
<SidebarButton
key={node.num}
label={node.user?.longName ?? "Unknown"}

19
src/pages/Peers.tsx

@ -2,10 +2,14 @@ import { Sidebar } from "@components/Sidebar.js";
import { Mono } from "@components/generic/Mono.js";
import { Table } from "@components/generic/Table/index.js";
import { TimeAgo } from "@components/generic/Table/tmp/TimeAgo.js";
import { SidebarSection } from '@components/UI/Sidebar/SidebarSection.js';
import { Search } from '@app/components/generic/Search'
import { useDevice } from "@core/stores/deviceStore.js";
import { Hashicon } from "@emeraldpay/hashicon-react";
import { Protobuf } from "@meshtastic/js";
import { base16 } from "rfc4648";
import { NodeInfo } from '@buf/meshtastic_protobufs.bufbuild_es/meshtastic/mesh_pb';
import { useState } from 'react';
export const PeersPage = (): JSX.Element => {
const { nodes, hardware } = useDevice();
@ -13,10 +17,21 @@ export const PeersPage = (): JSX.Element => {
const filteredNodes = Array.from(nodes.values()).filter(
(n) => n.num !== hardware.myNodeNum,
);
const [searchNodes, setSearchNodes] = useState<NodeInfo[]>(filteredNodes)
const onFilter = (results: NodeInfo[]) => setSearchNodes(results);
return (
<>
<Sidebar />
<Sidebar>
<SidebarSection label="Peers">
<Search<NodeInfo>
data={filteredNodes}
filterBy="user.longName"
onFilter={onFilter}
/>
</SidebarSection>
</Sidebar>
<div className="w-full overflow-y-auto">
<Table
headings={[
@ -27,7 +42,7 @@ export const PeersPage = (): JSX.Element => {
{ title: "Last Heard", type: "normal", sortable: true },
{ title: "SNR", type: "normal", sortable: true },
]}
rows={filteredNodes.map((node) => [
rows={searchNodes.map((node) => [
<Hashicon size={24} value={node.num.toString()} />,
<h1>
{node.user?.longName ??

Loading…
Cancel
Save