Merge pull request 'UI: Added Machine List Search Bar' (#209) from Qubasa-Qubasa-main into main
All checks were successful
checks-impure / test (push) Successful in 3s
checks / test (push) Successful in 3s

This commit is contained in:
clan-bot 2023-08-29 16:24:45 +00:00
commit a6c6310115
7 changed files with 657 additions and 554 deletions

View File

@ -0,0 +1,17 @@
import { useState, useEffect } from "react";
export function useDebounce(value: any, delay: number) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}

View File

@ -67,15 +67,15 @@ export function EnhancedTableToolbar(
</Grid2>
{/*Toolbar Grid */}
<Grid2 key="Toolbar" xs={12}>
<Toolbar
sx={{
pl: { sm: 2 },
pr: { xs: 1, sm: 1 },
}}
>
{props.children}
</Toolbar>
<Grid2
key="Toolbar"
xs={12}
container
justifyContent="center"
alignItems="center"
sx={{ pl: { sm: 2 }, pr: { xs: 1, sm: 1 }, pt: { xs: 1, sm: 3 } }}
>
{props.children}
</Grid2>
</Grid2>
);

View File

@ -59,7 +59,7 @@ export function NodeRow(props: {
//const labelId = `enhanced-table-checkbox-${index}`;
// Speed optimization. We compare string pointers here instead of the string content.
const isSelected = selected == row.name;
const isSelected = selected == row.id;
const handleClick = (event: React.MouseEvent<unknown>, name: string) => {
if (isSelected) {
@ -93,7 +93,7 @@ export function NodeRow(props: {
<TableCell
component="th"
scope="row"
onClick={(event) => handleClick(event, row.name)}
onClick={(event) => handleClick(event, row.id)}
>
<Stack>
<Typography component="div" align="left" variant="body1">

View File

@ -15,6 +15,7 @@ import { EnhancedTableToolbar } from "./enhancedTableToolbar";
import { StickySpeedDial } from "./stickySpeedDial";
import { NodeTableContainer } from "./nodeTableContainer";
import { SearchBar } from "./searchBar";
import Grid2 from "@mui/material/Unstable_Grid2/Grid2";
export interface NodeTableProps {
tableData: TableData[];
@ -29,7 +30,7 @@ export function NodeTable(props: NodeTableProps) {
const [selected, setSelected] = useState<string | undefined>(undefined);
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(5);
const [search, setSearch] = useState<string>("");
const [filteredList, setFilteredList] = useState<TableData[]>(tableData);
const handleChangePage = (event: unknown, newPage: number) => {
setPage(newPage);
@ -45,10 +46,15 @@ export function NodeTable(props: NodeTableProps) {
<Paper sx={{ width: "100%", mb: 2 }}>
<StickySpeedDial selected={selected} />
<EnhancedTableToolbar tableData={tableData}>
<SearchBar search={search} setSearch={setSearch} />
<Grid2 xs={12}>
<SearchBar
tableData={tableData}
setFilteredList={setFilteredList}
/>
</Grid2>
</EnhancedTableToolbar>
<NodeTableContainer
tableData={tableData}
tableData={filteredList}
page={page}
rowsPerPage={rowsPerPage}
dense={false}
@ -60,7 +66,7 @@ export function NodeTable(props: NodeTableProps) {
rowsPerPageOptions={[5, 10, 25]}
labelRowsPerPage={is_xs ? "Rows" : "Rows per page:"}
component="div"
count={tableData.length}
count={filteredList.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}

View File

@ -1,29 +1,107 @@
"use client";
import { ChangeEvent, SetStateAction, Dispatch } from "react";
import {
SetStateAction,
Dispatch,
useState,
useEffect,
useRef,
useMemo,
} from "react";
import IconButton from "@mui/material/IconButton";
import Tooltip from "@mui/material/Tooltip";
import SearchIcon from "@mui/icons-material/Search";
import { useDebounce } from "../hooks/useDebounce";
import { TableData } from "@/data/nodeData";
import {
Autocomplete,
Box,
Container,
InputAdornment,
Stack,
TextField,
} from "@mui/material";
export interface SearchBarProps {
search: string;
setSearch: Dispatch<SetStateAction<string>>;
tableData: TableData[];
setFilteredList: Dispatch<SetStateAction<TableData[]>>;
}
export function SearchBar(props: SearchBarProps) {
const { search, setSearch } = props;
const handleSearch = (event: ChangeEvent<HTMLInputElement>) => {
setSearch(event.target.value);
let { tableData, setFilteredList } = props;
const [search, setSearch] = useState<string>("");
const debouncedSearch = useDebounce(search, 250);
// Define a function to handle the Esc key press
const handleEsc = (event: any) => {
if (event.key === "Escape") {
setSearch("");
setFilteredList(tableData);
}
};
useEffect(() => {
if (debouncedSearch) {
const filtered: TableData[] = tableData.filter((row) => {
return row.name.toLowerCase().includes(debouncedSearch.toLowerCase());
});
setFilteredList(filtered);
}
}, [debouncedSearch]);
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.value === "") {
setFilteredList(tableData);
}
setSearch(e.target.value);
};
const suggestions = useMemo(
() => tableData.map((row) => row.name),
[tableData],
);
return (
<label htmlFor="search">
<Tooltip title="Filter list">
<IconButton>
<SearchIcon />
</IconButton>
</Tooltip>
<input id="search" type="text" value={search} onChange={handleSearch} />
</label>
<Autocomplete
freeSolo
options={suggestions}
onChange={(event, value) => {
// do something with the selected value
if (value === null) {
setSearch("");
setFilteredList(tableData);
} else {
setSearch(value);
}
}}
renderInput={(params) => (
<TextField
{...params}
fullWidth
label="Search"
variant="outlined"
value={search}
onKeyDown={handleEsc}
onChange={handleInputChange}
autoComplete="nickname"
InputProps={{
...params.InputProps,
endAdornment: (
<InputAdornment position="end">
<IconButton>
<SearchIcon />
</IconButton>
</InputAdornment>
),
}}
>
{/* {suggestions.map((item, index) => (
<option key={index} onClick={() => handleSelect(item)}>
{item}
</option>
))} */}
</TextField>
)}
/>
);
}

View File

@ -31,6 +31,8 @@ function createData(
};
}
var nameNumber = 0;
// A function to generate random names
function getRandomName(): string {
let names = [
@ -55,7 +57,7 @@ function getRandomName(): string {
"Zoe",
];
let index = Math.floor(Math.random() * names.length);
return names[index];
return names[index] + nameNumber++;
}
// A function to generate random IPv6 addresses

File diff suppressed because it is too large Load Diff