Execute oxfmt (#1166)
Ran pnpm oxfmt . This should get the web repo aligned so that we can better enforce oxfmt going forward.
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
export const Blur = () => {
|
||||
return (
|
||||
<div className="fixed inset-0 backdrop-blur-md backdrop-brightness-press" aria-hidden="true" />
|
||||
<div
|
||||
className="fixed inset-0 backdrop-blur-md backdrop-brightness-press"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -50,7 +50,10 @@ interface FilterToggleProps<K extends keyof FilterState> {
|
||||
onChange: (key: K, value: string) => void;
|
||||
}
|
||||
|
||||
export const FilterAccordionItem = ({ label, children }: FilterAccordionItemProps) => {
|
||||
export const FilterAccordionItem = ({
|
||||
label,
|
||||
children,
|
||||
}: FilterAccordionItemProps) => {
|
||||
return (
|
||||
<AccordionItem value={label}>
|
||||
<AccordionHeader>
|
||||
@@ -62,7 +65,9 @@ export const FilterAccordionItem = ({ label, children }: FilterAccordionItemProp
|
||||
{label}
|
||||
</AccordionTrigger>
|
||||
</AccordionHeader>
|
||||
<AccordionContent className={cn("px-1 pb-4 pt-2 space-y-3 dark:border-slate-700")}>
|
||||
<AccordionContent
|
||||
className={cn("px-1 pb-4 pt-2 space-y-3 dark:border-slate-700")}
|
||||
>
|
||||
{children}
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
@@ -127,7 +132,8 @@ export const FilterMulti = <K extends EnumArrayKeys<FilterState>>({
|
||||
}: FilterMultiProps<K>) => {
|
||||
const selected = getNumberArray(filterState, filterKey);
|
||||
|
||||
const allSelected = options.length > 0 && options.every((opt) => selected.includes(opt));
|
||||
const allSelected =
|
||||
options.length > 0 && options.every((opt) => selected.includes(opt));
|
||||
|
||||
const toggleAll = () => {
|
||||
setFilterState((prev) => ({
|
||||
@@ -141,7 +147,9 @@ export const FilterMulti = <K extends EnumArrayKeys<FilterState>>({
|
||||
const current = getNumberArray(prev, filterKey);
|
||||
return {
|
||||
...prev,
|
||||
[filterKey]: checked ? [...current, val] : current.filter((v) => v !== val),
|
||||
[filterKey]: checked
|
||||
? [...current, val]
|
||||
: current.filter((v) => v !== val),
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -189,7 +197,11 @@ export const FilterToggle = <K extends keyof FilterState>({
|
||||
aria-label={label}
|
||||
id={label}
|
||||
onValueChange={(value) => onChange(filterKey, value)}
|
||||
value={typeof filterState[filterKey] === "undefined" ? "" : String(filterState[filterKey])}
|
||||
value={
|
||||
typeof filterState[filterKey] === "undefined"
|
||||
? ""
|
||||
: String(filterState[filterKey])
|
||||
}
|
||||
>
|
||||
<ToggleGroupItem
|
||||
value="false"
|
||||
|
||||
@@ -8,7 +8,11 @@ import type { FilterState } from "@components/generic/Filter/useFilterNode.ts";
|
||||
import { TimeAgo } from "@components/generic/TimeAgo.tsx";
|
||||
import { Accordion } from "@components/UI/Accordion.tsx";
|
||||
import { Input } from "@components/UI/Input.tsx";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@components/UI/Popover.tsx";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@components/UI/Popover.tsx";
|
||||
import { cn } from "@core/utils/cn.ts";
|
||||
import { debounce } from "@core/utils/debounce.ts";
|
||||
import { Protobuf } from "@meshtastic/sdk";
|
||||
@@ -155,7 +159,10 @@ export function FilterControl({
|
||||
);
|
||||
|
||||
const handleBoolChange = useCallback(
|
||||
<K extends keyof FilterState>(key: K, value: string | boolean | undefined) => {
|
||||
<K extends keyof FilterState>(
|
||||
key: K,
|
||||
value: string | boolean | undefined,
|
||||
) => {
|
||||
let typedValue: boolean | undefined;
|
||||
if (value === true || value === "true") {
|
||||
typedValue = true;
|
||||
@@ -179,7 +186,10 @@ export function FilterControl({
|
||||
[],
|
||||
);
|
||||
|
||||
const formatEnumLabel = useCallback((label: string): string => label.replace(/_/g, " "), []);
|
||||
const formatEnumLabel = useCallback(
|
||||
(label: string): string => label.replace(/_/g, " "),
|
||||
[],
|
||||
);
|
||||
|
||||
const roleOptions = useMemo(
|
||||
() =>
|
||||
@@ -190,7 +200,9 @@ export function FilterControl({
|
||||
);
|
||||
const hwModelOptions = useMemo(
|
||||
() =>
|
||||
Object.values(Protobuf.Mesh.HardwareModel).filter((v): v is number => typeof v === "number"),
|
||||
Object.values(Protobuf.Mesh.HardwareModel).filter(
|
||||
(v): v is number => typeof v === "number",
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
@@ -214,10 +226,17 @@ export function FilterControl({
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
{...parameters?.popoverContentProps}
|
||||
className={cn("dark:text-slate-300", parameters?.popoverContentProps?.className)}
|
||||
className={cn(
|
||||
"dark:text-slate-300",
|
||||
parameters?.popoverContentProps?.className,
|
||||
)}
|
||||
>
|
||||
<form className="space-y-4">
|
||||
<Accordion type="single" defaultValue={t("general.label")} collapsible>
|
||||
<Accordion
|
||||
type="single"
|
||||
defaultValue={t("general.label")}
|
||||
collapsible
|
||||
>
|
||||
<FilterAccordionItem label={t("general.label")}>
|
||||
{(parameters?.showTextSearch ?? true) && (
|
||||
<div className="flex flex-col space-y-1 pb-2">
|
||||
@@ -347,7 +366,9 @@ export function FilterControl({
|
||||
setFilterState={setFilterState}
|
||||
options={roleOptions}
|
||||
getLabel={(val) =>
|
||||
formatEnumLabel(Protobuf.Config.Config_DeviceConfig_Role[val] ?? "UNSET")
|
||||
formatEnumLabel(
|
||||
Protobuf.Config.Config_DeviceConfig_Role[val] ?? "UNSET",
|
||||
)
|
||||
}
|
||||
/>
|
||||
</FilterAccordionItem>
|
||||
@@ -358,7 +379,9 @@ export function FilterControl({
|
||||
filterState={filterState}
|
||||
setFilterState={setFilterState}
|
||||
options={hwModelOptions}
|
||||
getLabel={(val) => formatEnumLabel(Protobuf.Mesh.HardwareModel[val] ?? "UNKNOWN")}
|
||||
getLabel={(val) =>
|
||||
formatEnumLabel(Protobuf.Mesh.HardwareModel[val] ?? "UNKNOWN")
|
||||
}
|
||||
/>
|
||||
</FilterAccordionItem>
|
||||
<FilterAccordionItem label={t("advanced.label")}>
|
||||
|
||||
@@ -111,7 +111,9 @@ describe("useFilterNode", () => {
|
||||
hwModel: [Protobuf.Mesh.HardwareModel.TLORA_T3_S3],
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(nodeFilter(node, { hwModel: [Protobuf.Mesh.HardwareModel.HELTEC_V3] })).toBe(false);
|
||||
expect(
|
||||
nodeFilter(node, { hwModel: [Protobuf.Mesh.HardwareModel.HELTEC_V3] }),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("filters by hopsUnknown", () => {
|
||||
@@ -188,8 +190,12 @@ describe("useFilterNode", () => {
|
||||
lastHeard: [lastHeardMin, lastHeardMax],
|
||||
} = defaultFilterValues;
|
||||
const veryOld = { ...node, lastHeard: lastHeardMax + 1 }; // older than slider max
|
||||
expect(nodeFilter(veryOld, { lastHeard: [lastHeardMin, lastHeardMax] })).toBe(true); // open upper
|
||||
expect(nodeFilter(veryOld, { lastHeard: [lastHeardMin, lastHeardMax - 1] })).toBe(false); // now bounded
|
||||
expect(
|
||||
nodeFilter(veryOld, { lastHeard: [lastHeardMin, lastHeardMax] }),
|
||||
).toBe(true); // open upper
|
||||
expect(
|
||||
nodeFilter(veryOld, { lastHeard: [lastHeardMin, lastHeardMax - 1] }),
|
||||
).toBe(false); // now bounded
|
||||
});
|
||||
|
||||
it("snr: max at default means no upper bound", () => {
|
||||
@@ -222,7 +228,9 @@ describe("useFilterNode", () => {
|
||||
},
|
||||
} satisfies Protobuf.Mesh.NodeInfo;
|
||||
expect(nodeFilter(hiV, { voltage: [voltageMin, voltageMax] })).toBe(true); // open upper
|
||||
expect(nodeFilter(hiV, { voltage: [voltageMin, voltageMax - 0.01] })).toBe(false); // bounded
|
||||
expect(
|
||||
nodeFilter(hiV, { voltage: [voltageMin, voltageMax - 0.01] }),
|
||||
).toBe(false); // bounded
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,7 +45,8 @@ export function useFilterNode() {
|
||||
batteryLevel: [0, 101],
|
||||
voltage: [0, 5],
|
||||
role: Object.values(Protobuf.Config.Config_DeviceConfig_Role).filter(
|
||||
(v): v is Protobuf.Config.Config_DeviceConfig_Role => typeof v === "number",
|
||||
(v): v is Protobuf.Config.Config_DeviceConfig_Role =>
|
||||
typeof v === "number",
|
||||
),
|
||||
hwModel: Object.values(Protobuf.Mesh.HardwareModel).filter(
|
||||
(v): v is Protobuf.Mesh.HardwareModel => typeof v === "number",
|
||||
@@ -57,7 +58,10 @@ export function useFilterNode() {
|
||||
);
|
||||
|
||||
const nodeFilter = useCallback(
|
||||
(node: Protobuf.Mesh.NodeInfo, filterOverrides?: Partial<FilterState>): boolean => {
|
||||
(
|
||||
node: Protobuf.Mesh.NodeInfo,
|
||||
filterOverrides?: Partial<FilterState>,
|
||||
): boolean => {
|
||||
const filterState: FilterState = {
|
||||
...defaultFilterValues,
|
||||
...filterOverrides,
|
||||
@@ -83,7 +87,10 @@ export function useFilterNode() {
|
||||
const hops = node.hopsAway ?? 7;
|
||||
if (
|
||||
(node.hopsAway === undefined &&
|
||||
!shallowEqualArray(filterState.hopsAway, defaultFilterValues.hopsAway)) || // If hops are unknown, hide node if state is not default
|
||||
!shallowEqualArray(
|
||||
filterState.hopsAway,
|
||||
defaultFilterValues.hopsAway,
|
||||
)) || // If hops are unknown, hide node if state is not default
|
||||
hops < filterState.hopsAway[0] ||
|
||||
hops > filterState.hopsAway[1]
|
||||
) {
|
||||
@@ -100,7 +107,10 @@ export function useFilterNode() {
|
||||
const secondsAgo = Math.max(0, Date.now() / 1000 - (node.lastHeard ?? 0));
|
||||
if (
|
||||
(node.lastHeard === 0 &&
|
||||
!shallowEqualArray(filterState.lastHeard, defaultFilterValues.lastHeard)) || // If lastHeard is unknown (0), hide node if state is not default
|
||||
!shallowEqualArray(
|
||||
filterState.lastHeard,
|
||||
defaultFilterValues.lastHeard,
|
||||
)) || // If lastHeard is unknown (0), hide node if state is not default
|
||||
secondsAgo < filterState.lastHeard[0] ||
|
||||
(secondsAgo > filterState.lastHeard[1] &&
|
||||
filterState.lastHeard[1] !== defaultFilterValues.lastHeard[1])
|
||||
@@ -122,15 +132,21 @@ export function useFilterNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof filterState.viaMqtt !== "undefined" && node.viaMqtt !== filterState.viaMqtt) {
|
||||
if (
|
||||
typeof filterState.viaMqtt !== "undefined" &&
|
||||
node.viaMqtt !== filterState.viaMqtt
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const snr = node.snr ?? -20;
|
||||
if (
|
||||
(node.snr === undefined && !shallowEqualArray(filterState.snr, defaultFilterValues.snr)) ||
|
||||
(snr < filterState.snr[0] && filterState.snr[0] !== defaultFilterValues.snr[0]) ||
|
||||
(snr > filterState.snr[1] && filterState.snr[1] !== defaultFilterValues.snr[1])
|
||||
(node.snr === undefined &&
|
||||
!shallowEqualArray(filterState.snr, defaultFilterValues.snr)) ||
|
||||
(snr < filterState.snr[0] &&
|
||||
filterState.snr[0] !== defaultFilterValues.snr[0]) ||
|
||||
(snr > filterState.snr[1] &&
|
||||
filterState.snr[1] !== defaultFilterValues.snr[1])
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@@ -151,7 +167,10 @@ export function useFilterNode() {
|
||||
const airUtilTx = node.deviceMetrics?.airUtilTx ?? 0;
|
||||
if (
|
||||
(node.deviceMetrics?.airUtilTx === undefined &&
|
||||
!shallowEqualArray(filterState.airUtilTx, defaultFilterValues.airUtilTx)) ||
|
||||
!shallowEqualArray(
|
||||
filterState.airUtilTx,
|
||||
defaultFilterValues.airUtilTx,
|
||||
)) ||
|
||||
airUtilTx < filterState.airUtilTx[0] ||
|
||||
airUtilTx > filterState.airUtilTx[1]
|
||||
) {
|
||||
@@ -161,7 +180,10 @@ export function useFilterNode() {
|
||||
const batt = node.deviceMetrics?.batteryLevel ?? 101;
|
||||
if (
|
||||
(node.deviceMetrics?.batteryLevel === undefined &&
|
||||
!shallowEqualArray(filterState.batteryLevel, defaultFilterValues.batteryLevel)) ||
|
||||
!shallowEqualArray(
|
||||
filterState.batteryLevel,
|
||||
defaultFilterValues.batteryLevel,
|
||||
)) ||
|
||||
batt < filterState.batteryLevel[0] ||
|
||||
batt > filterState.batteryLevel[1]
|
||||
) {
|
||||
@@ -171,7 +193,10 @@ export function useFilterNode() {
|
||||
const voltage = Math.abs(node.deviceMetrics?.voltage ?? 0);
|
||||
if (
|
||||
(node.deviceMetrics?.voltage === undefined &&
|
||||
!shallowEqualArray(filterState.voltage, defaultFilterValues.voltage)) ||
|
||||
!shallowEqualArray(
|
||||
filterState.voltage,
|
||||
defaultFilterValues.voltage,
|
||||
)) ||
|
||||
voltage < filterState.voltage[0] ||
|
||||
(voltage > filterState.voltage[1] &&
|
||||
filterState.voltage[1] !== defaultFilterValues.voltage[1])
|
||||
@@ -193,7 +218,10 @@ export function useFilterNode() {
|
||||
node.user?.hwModel ?? Protobuf.Mesh.HardwareModel.UNSET;
|
||||
if (
|
||||
(node.user?.hwModel === undefined &&
|
||||
!shallowEqualArray(filterState.hwModel, defaultFilterValues.hwModel)) ||
|
||||
!shallowEqualArray(
|
||||
filterState.hwModel,
|
||||
defaultFilterValues.hwModel,
|
||||
)) ||
|
||||
!filterState.hwModel.includes(hwModel)
|
||||
) {
|
||||
return false;
|
||||
|
||||
@@ -6,7 +6,10 @@ interface MonoProps extends React.HTMLAttributes<HTMLSpanElement> {
|
||||
}
|
||||
export const Mono = ({ children, className, ...rest }: MonoProps) => {
|
||||
return (
|
||||
<span className={cn("font-mono text-sm text-text-secondary", className)} {...rest}>
|
||||
<span
|
||||
className={cn("font-mono text-sm text-text-secondary", className)}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { Mono } from "@components/generic/Mono.tsx";
|
||||
import { type DataRow, type Heading, Table } from "@components/generic/Table/index.tsx";
|
||||
import {
|
||||
type DataRow,
|
||||
type Heading,
|
||||
Table,
|
||||
} from "@components/generic/Table/index.tsx";
|
||||
import { TimeAgo } from "@components/generic/TimeAgo.tsx";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import { describe, expect, it } from "vitest";
|
||||
@@ -102,8 +106,8 @@ describe("Generic Table", () => {
|
||||
expect(columnHeaders).toHaveLength(3);
|
||||
|
||||
const getRenderedOrder = () =>
|
||||
[...renderedTable.querySelectorAll("[data-testid='short-name']")].map((el) =>
|
||||
el.textContent?.trim(),
|
||||
[...renderedTable.querySelectorAll("[data-testid='short-name']")].map(
|
||||
(el) => el.textContent?.trim(),
|
||||
);
|
||||
|
||||
// Default sort: "Last Heard" desc. TST2 is favorite, so it's first.
|
||||
|
||||
@@ -97,7 +97,8 @@ export const Table = ({ headings, rows }: TableProps) => {
|
||||
scope="col"
|
||||
className={cn(
|
||||
"py-2 pr-3 text-left",
|
||||
heading.sortable && "cursor-pointer hover:brightness-hover active:brightness-press",
|
||||
heading.sortable &&
|
||||
"cursor-pointer hover:brightness-hover active:brightness-press",
|
||||
)}
|
||||
onClick={() => heading.sortable && handleSort(heading.title)}
|
||||
onKeyUp={(e) => {
|
||||
|
||||
Reference in New Issue
Block a user