Add advanced filters (#655)
* Add advanced filters * Review edits --------- Co-authored-by: philon- <philon-@users.noreply.github.com>
This commit is contained in:
co-authored by
philon-
parent
a5339af0dd
commit
7adbe01723
@@ -190,10 +190,12 @@ export function FilterControl({
|
||||
);
|
||||
|
||||
const handleBoolChange = useCallback(
|
||||
<K extends keyof FilterState>(key: K, value: string) => {
|
||||
const typedValue = value === ""
|
||||
? undefined
|
||||
: JSON.parse(value.toLowerCase());
|
||||
<K extends keyof FilterState>(key: K, value: string | boolean) => {
|
||||
const typedValue = value === true || value === "true"
|
||||
? true
|
||||
: value === false || value === "false"
|
||||
? false
|
||||
: undefined;
|
||||
|
||||
setFilterState((prev) => ({
|
||||
...prev,
|
||||
@@ -386,6 +388,28 @@ export function FilterControl({
|
||||
formatEnumLabel(Protobuf.Mesh.HardwareModel[val])}
|
||||
/>
|
||||
</FilterAccordionItem>
|
||||
<FilterAccordionItem label={t("advanced.label")}>
|
||||
<FilterToggle
|
||||
label={t("hopsUnknown.label")}
|
||||
filterKey="hopsUnknown"
|
||||
alternativeLabels={[
|
||||
t("hide.label"),
|
||||
t("showOnly.label"),
|
||||
]}
|
||||
filterState={filterState}
|
||||
onChange={handleBoolChange}
|
||||
/>
|
||||
<FilterToggle
|
||||
label={t("showUnheard.label")}
|
||||
filterKey="showUnheard"
|
||||
alternativeLabels={[
|
||||
t("hide.label"),
|
||||
t("showOnly.label"),
|
||||
]}
|
||||
filterState={filterState}
|
||||
onChange={handleBoolChange}
|
||||
/>
|
||||
</FilterAccordionItem>
|
||||
</Accordion>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -114,6 +114,18 @@ describe("useFilterNode", () => {
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("filters by hopsUnknown", () => {
|
||||
expect(nodeFilter(node, { hopsUnknown: true })).toBe(false);
|
||||
expect(nodeFilter(node, { hopsUnknown: false })).toBe(true);
|
||||
expect(nodeFilter(node, { hopsUnknown: undefined })).toBe(true);
|
||||
});
|
||||
|
||||
it("filters by showUnheard", () => {
|
||||
expect(nodeFilter(node, { showUnheard: true })).toBe(false);
|
||||
expect(nodeFilter(node, { showUnheard: false })).toBe(true);
|
||||
expect(nodeFilter(node, { showUnheard: undefined })).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false when current matches defaults", () => {
|
||||
expect(isFilterDirty(defaultFilterValues)).toBe(false);
|
||||
});
|
||||
@@ -156,5 +168,15 @@ describe("useFilterNode", () => {
|
||||
};
|
||||
expect(isFilterDirty(modified)).toBe(true);
|
||||
});
|
||||
|
||||
it("detects dirty boolean field (hopsUnknown)", () => {
|
||||
const modified = { ...defaultFilterValues, hopsUnknown: true };
|
||||
expect(isFilterDirty(modified)).toBe(true);
|
||||
});
|
||||
|
||||
it("detects dirty boolean field (showUnheard)", () => {
|
||||
const modified = { ...defaultFilterValues, showUnheard: true };
|
||||
expect(isFilterDirty(modified)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,6 +15,8 @@ export type FilterState = {
|
||||
voltage: [number, number];
|
||||
role: Protobuf.Config.Config_DeviceConfig_Role[];
|
||||
hwModel: Protobuf.Mesh.HardwareModel[];
|
||||
showUnheard: boolean | undefined;
|
||||
hopsUnknown: boolean | undefined;
|
||||
};
|
||||
|
||||
const shallowEqualArray = <T>(a: T[], b: T[]): boolean => {
|
||||
@@ -49,6 +51,8 @@ export function useFilterNode() {
|
||||
hwModel: Object.values(Protobuf.Mesh.HardwareModel).filter(
|
||||
(v): v is Protobuf.Mesh.HardwareModel => typeof v === "number",
|
||||
),
|
||||
hopsUnknown: undefined,
|
||||
showUnheard: undefined,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
@@ -83,6 +87,13 @@ export function useFilterNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
(filterState.hopsUnknown === true && node.hopsAway !== undefined) ||
|
||||
filterState.hopsUnknown === false && node.hopsAway === undefined
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const secondsAgo = Date.now() / 1000 - (node.lastHeard ?? 0);
|
||||
if (
|
||||
secondsAgo < filterState.lastHeard[0] ||
|
||||
@@ -92,6 +103,13 @@ export function useFilterNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
(filterState.showUnheard === true && (node.lastHeard ?? 0) !== 0) ||
|
||||
filterState.showUnheard === false && (node.lastHeard ?? 0) === 0
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof filterState.isFavorite !== "undefined" &&
|
||||
node.isFavorite !== filterState.isFavorite
|
||||
|
||||
@@ -103,6 +103,9 @@
|
||||
"filter": {
|
||||
"label": "Filter"
|
||||
},
|
||||
"advanced": {
|
||||
"label": "Advanced"
|
||||
},
|
||||
"clearInput": {
|
||||
"label": "Clear input"
|
||||
},
|
||||
@@ -152,6 +155,12 @@
|
||||
"viaMqtt": {
|
||||
"label": "Connected via MQTT"
|
||||
},
|
||||
"hopsUnknown": {
|
||||
"label": "Unknown number of hops"
|
||||
},
|
||||
"showUnheard": {
|
||||
"label": "Never heard"
|
||||
},
|
||||
"language": {
|
||||
"label": "Language",
|
||||
"changeLanguage": "Change Language"
|
||||
|
||||
Reference in New Issue
Block a user