mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 17:26:42 +00:00
Fix/dhcp config network sort (#25799)
* Add ip sort method to compare helper * Add ip sort functionality to dhcp config panel datatable * Add type ip to DataTableColumnData * Change ip sorting to padStart method for better readablity * Rename ip compare method to clarify ipv4 * Enhance IP compare method to include ipv6 * Add compare IP test
This commit is contained in:
parent
e9272b9a27
commit
f47336392c
@ -1,4 +1,5 @@
|
|||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
|
import { isIPAddress } from "./is_ip_address";
|
||||||
|
|
||||||
const collator = memoizeOne(
|
const collator = memoizeOne(
|
||||||
(language: string | undefined) => new Intl.Collator(language)
|
(language: string | undefined) => new Intl.Collator(language)
|
||||||
@ -33,6 +34,19 @@ export const stringCompare = (
|
|||||||
return fallbackStringCompare(a, b);
|
return fallbackStringCompare(a, b);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ipCompare = (a: string, b: string) => {
|
||||||
|
const aIsIpV4 = isIPAddress(a);
|
||||||
|
const bIsIpV4 = isIPAddress(b);
|
||||||
|
|
||||||
|
if (aIsIpV4 && bIsIpV4) {
|
||||||
|
return ipv4Compare(a, b);
|
||||||
|
}
|
||||||
|
if (!aIsIpV4 && !bIsIpV4) {
|
||||||
|
return ipV6Compare(a, b);
|
||||||
|
}
|
||||||
|
return aIsIpV4 ? -1 : 1;
|
||||||
|
};
|
||||||
|
|
||||||
export const caseInsensitiveStringCompare = (
|
export const caseInsensitiveStringCompare = (
|
||||||
a: string,
|
a: string,
|
||||||
b: string,
|
b: string,
|
||||||
@ -64,3 +78,42 @@ export const orderCompare = (order: string[]) => (a: string, b: string) => {
|
|||||||
|
|
||||||
return idxA - idxB;
|
return idxA - idxB;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function ipv4Compare(a: string, b: string) {
|
||||||
|
const num1 = Number(
|
||||||
|
a
|
||||||
|
.split(".")
|
||||||
|
.map((num) => num.padStart(3, "0"))
|
||||||
|
.join("")
|
||||||
|
);
|
||||||
|
const num2 = Number(
|
||||||
|
b
|
||||||
|
.split(".")
|
||||||
|
.map((num) => num.padStart(3, "0"))
|
||||||
|
.join("")
|
||||||
|
);
|
||||||
|
return num1 - num2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ipV6Compare(a: string, b: string) {
|
||||||
|
const ipv6a = normalizeIPv6(a)
|
||||||
|
.split(":")
|
||||||
|
.map((part) => part.padStart(4, "0"))
|
||||||
|
.join("");
|
||||||
|
const ipv6b = normalizeIPv6(b)
|
||||||
|
.split(":")
|
||||||
|
.map((part) => part.padStart(4, "0"))
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
return ipv6a.localeCompare(ipv6b);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeIPv6(ip) {
|
||||||
|
const parts = ip.split("::");
|
||||||
|
const head = parts[0].split(":");
|
||||||
|
const tail = parts[1] ? parts[1].split(":") : [];
|
||||||
|
const totalParts = 8;
|
||||||
|
const missing = totalParts - (head.length + tail.length);
|
||||||
|
const zeros = new Array(missing).fill("0");
|
||||||
|
return [...head, ...zeros, ...tail].join(":");
|
||||||
|
}
|
||||||
|
@ -72,6 +72,7 @@ export interface DataTableColumnData<T = any> extends DataTableSortColumnData {
|
|||||||
label?: TemplateResult | string;
|
label?: TemplateResult | string;
|
||||||
type?:
|
type?:
|
||||||
| "numeric"
|
| "numeric"
|
||||||
|
| "ip"
|
||||||
| "icon"
|
| "icon"
|
||||||
| "icon-button"
|
| "icon-button"
|
||||||
| "overflow"
|
| "overflow"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { expose } from "comlink";
|
import { expose } from "comlink";
|
||||||
import { stringCompare } from "../../common/string/compare";
|
import { stringCompare, ipCompare } from "../../common/string/compare";
|
||||||
import { stripDiacritics } from "../../common/string/strip-diacritics";
|
import { stripDiacritics } from "../../common/string/strip-diacritics";
|
||||||
import type {
|
import type {
|
||||||
ClonedDataTableColumnData,
|
ClonedDataTableColumnData,
|
||||||
@ -57,6 +57,8 @@ const sortData = (
|
|||||||
if (column.type === "numeric") {
|
if (column.type === "numeric") {
|
||||||
valA = isNaN(valA) ? undefined : Number(valA);
|
valA = isNaN(valA) ? undefined : Number(valA);
|
||||||
valB = isNaN(valB) ? undefined : Number(valB);
|
valB = isNaN(valB) ? undefined : Number(valB);
|
||||||
|
} else if (column.type === "ip") {
|
||||||
|
return sort * ipCompare(valA, valB);
|
||||||
} else if (typeof valA === "string" && typeof valB === "string") {
|
} else if (typeof valA === "string" && typeof valB === "string") {
|
||||||
return sort * stringCompare(valA, valB, language);
|
return sort * stringCompare(valA, valB, language);
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@ export class DHCPConfigPanel extends SubscribeMixin(LitElement) {
|
|||||||
title: localize("ui.panel.config.dhcp.ip_address"),
|
title: localize("ui.panel.config.dhcp.ip_address"),
|
||||||
filterable: true,
|
filterable: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
|
type: "ip",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
34
test/common/string/compare_ip.test.ts
Normal file
34
test/common/string/compare_ip.test.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { assert, describe, it } from "vitest";
|
||||||
|
import { ipCompare } from "../../../src/common/string/compare";
|
||||||
|
import { isIPAddress } from "../../../src/common/string/is_ip_address";
|
||||||
|
|
||||||
|
describe("compareIpAdresses", () => {
|
||||||
|
const ipAddresses: string[] = [
|
||||||
|
"192.168.1.1",
|
||||||
|
"10.0.0.1",
|
||||||
|
"fe80::85d:e82c:9446:7995",
|
||||||
|
"192.168.0.1",
|
||||||
|
"fe80::85d:e82c:9446:7994",
|
||||||
|
"::ffff:192.168.1.1",
|
||||||
|
"1050:0000:0000:0000:0005:0600:300c:326b",
|
||||||
|
];
|
||||||
|
const expected: string[] = [
|
||||||
|
"10.0.0.1",
|
||||||
|
"192.168.0.1",
|
||||||
|
"192.168.1.1",
|
||||||
|
"::ffff:192.168.1.1",
|
||||||
|
"1050:0000:0000:0000:0005:0600:300c:326b",
|
||||||
|
"fe80::85d:e82c:9446:7994",
|
||||||
|
"fe80::85d:e82c:9446:7995",
|
||||||
|
];
|
||||||
|
|
||||||
|
const sorted = [...ipAddresses].sort(ipCompare);
|
||||||
|
|
||||||
|
it("Detects ipv4 addresses", () => {
|
||||||
|
assert.isTrue(isIPAddress("192.168.0.1"));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Compares ipv4 and ipv6 addresses", () => {
|
||||||
|
assert.deepEqual(sorted, expected);
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user