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(
|
const handleBoolChange = useCallback(
|
||||||
<K extends keyof FilterState>(key: K, value: string) => {
|
<K extends keyof FilterState>(key: K, value: string | boolean) => {
|
||||||
const typedValue = value === ""
|
const typedValue = value === true || value === "true"
|
||||||
? undefined
|
? true
|
||||||
: JSON.parse(value.toLowerCase());
|
: value === false || value === "false"
|
||||||
|
? false
|
||||||
|
: undefined;
|
||||||
|
|
||||||
setFilterState((prev) => ({
|
setFilterState((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
@@ -386,6 +388,28 @@ export function FilterControl({
|
|||||||
formatEnumLabel(Protobuf.Mesh.HardwareModel[val])}
|
formatEnumLabel(Protobuf.Mesh.HardwareModel[val])}
|
||||||
/>
|
/>
|
||||||
</FilterAccordionItem>
|
</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>
|
</Accordion>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -114,6 +114,18 @@ describe("useFilterNode", () => {
|
|||||||
).toBe(false);
|
).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", () => {
|
it("returns false when current matches defaults", () => {
|
||||||
expect(isFilterDirty(defaultFilterValues)).toBe(false);
|
expect(isFilterDirty(defaultFilterValues)).toBe(false);
|
||||||
});
|
});
|
||||||
@@ -156,5 +168,15 @@ describe("useFilterNode", () => {
|
|||||||
};
|
};
|
||||||
expect(isFilterDirty(modified)).toBe(true);
|
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];
|
voltage: [number, number];
|
||||||
role: Protobuf.Config.Config_DeviceConfig_Role[];
|
role: Protobuf.Config.Config_DeviceConfig_Role[];
|
||||||
hwModel: Protobuf.Mesh.HardwareModel[];
|
hwModel: Protobuf.Mesh.HardwareModel[];
|
||||||
|
showUnheard: boolean | undefined;
|
||||||
|
hopsUnknown: boolean | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const shallowEqualArray = <T>(a: T[], b: T[]): boolean => {
|
const shallowEqualArray = <T>(a: T[], b: T[]): boolean => {
|
||||||
@@ -49,6 +51,8 @@ export function useFilterNode() {
|
|||||||
hwModel: Object.values(Protobuf.Mesh.HardwareModel).filter(
|
hwModel: Object.values(Protobuf.Mesh.HardwareModel).filter(
|
||||||
(v): v is Protobuf.Mesh.HardwareModel => typeof v === "number",
|
(v): v is Protobuf.Mesh.HardwareModel => typeof v === "number",
|
||||||
),
|
),
|
||||||
|
hopsUnknown: undefined,
|
||||||
|
showUnheard: undefined,
|
||||||
}),
|
}),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
@@ -83,6 +87,13 @@ export function useFilterNode() {
|
|||||||
return false;
|
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);
|
const secondsAgo = Date.now() / 1000 - (node.lastHeard ?? 0);
|
||||||
if (
|
if (
|
||||||
secondsAgo < filterState.lastHeard[0] ||
|
secondsAgo < filterState.lastHeard[0] ||
|
||||||
@@ -92,6 +103,13 @@ export function useFilterNode() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(filterState.showUnheard === true && (node.lastHeard ?? 0) !== 0) ||
|
||||||
|
filterState.showUnheard === false && (node.lastHeard ?? 0) === 0
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
typeof filterState.isFavorite !== "undefined" &&
|
typeof filterState.isFavorite !== "undefined" &&
|
||||||
node.isFavorite !== filterState.isFavorite
|
node.isFavorite !== filterState.isFavorite
|
||||||
|
|||||||
@@ -103,6 +103,9 @@
|
|||||||
"filter": {
|
"filter": {
|
||||||
"label": "Filter"
|
"label": "Filter"
|
||||||
},
|
},
|
||||||
|
"advanced": {
|
||||||
|
"label": "Advanced"
|
||||||
|
},
|
||||||
"clearInput": {
|
"clearInput": {
|
||||||
"label": "Clear input"
|
"label": "Clear input"
|
||||||
},
|
},
|
||||||
@@ -152,6 +155,12 @@
|
|||||||
"viaMqtt": {
|
"viaMqtt": {
|
||||||
"label": "Connected via MQTT"
|
"label": "Connected via MQTT"
|
||||||
},
|
},
|
||||||
|
"hopsUnknown": {
|
||||||
|
"label": "Unknown number of hops"
|
||||||
|
},
|
||||||
|
"showUnheard": {
|
||||||
|
"label": "Never heard"
|
||||||
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"label": "Language",
|
"label": "Language",
|
||||||
"changeLanguage": "Change Language"
|
"changeLanguage": "Change Language"
|
||||||
|
|||||||
Reference in New Issue
Block a user