Issues: add tariff and messenger devices, sorting (#28072)

This commit is contained in:
Michael Geers 2026-03-10 12:40:45 +01:00 • committed by GitHub
parent e5240a138c
commit b77358183a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 52 additions and 18 deletions

View file

@ -2,20 +2,32 @@ import { describe, it, expect } from "vitest";
import { formatJson } from "./format";
describe("formatJson", () => {
it("formats basic object", () => {
it("formats basic object with sorted keys", () => {
const obj = { foo: "bar", baz: 123 };
const result = formatJson(obj);
expect(result).toBe(`{
"foo": "bar",
"baz": 123
"baz": 123,
"foo": "bar"
}`);
});
it("sorts id and name first", () => {
const obj = { zebra: 1, name: "test", id: 42, alpha: 2 };
const result = formatJson(obj);
expect(result).toBe(`{
"id": 42,
"name": "test",
"alpha": 2,
"zebra": 1
}`);
});
it("expands arrays with expand keys", () => {
const obj = {
items: ["foo", "bar"],
other: ["baz", "qux"],
items: ["foo", "bar"],
};
const result = formatJson(obj, ["items"]);
@ -30,8 +42,8 @@ describe("formatJson", () => {
it("expands objects with expand keys", () => {
const obj = {
config: { alpha: 1, beta: 2 },
other: { gamma: 3 },
config: { beta: 2, alpha: 1 },
};
const result = formatJson(obj, ["config"]);
@ -44,19 +56,19 @@ describe("formatJson", () => {
}`);
});
it("keeps nested objects in arrays single-lined", () => {
it("keeps nested objects in arrays single-lined with sorted keys", () => {
const obj = {
items: [
{ foo: "bar", baz: 123 },
{ qux: "test", num: 456 },
{ qux: "test", id: 1, num: 456 },
],
};
const result = formatJson(obj, ["items"]);
expect(result).toBe(`{
"items": [
{"foo":"bar","baz":123},
{"qux":"test","num":456}
{"baz":123,"foo":"bar"},
{"id":1,"num":456,"qux":"test"}
]
}`);
});

View file

@ -1,3 +1,15 @@
function sortedEntries(obj: object): [string, any][] {
const firstKeys = ["id", "name"];
return Object.entries(obj).sort(([a], [b]) => {
const ai = firstKeys.indexOf(a);
const bi = firstKeys.indexOf(b);
if (ai >= 0 || bi >= 0) {
return (ai >= 0 ? ai : Infinity) - (bi >= 0 ? bi : Infinity);
}
return a.localeCompare(b);
});
}
export function formatJson(obj: any, expandKeys: string[] = []): string {
if (!obj || typeof obj !== "object") {
return JSON.stringify(obj, null, 2);
@ -5,7 +17,7 @@ export function formatJson(obj: any, expandKeys: string[] = []): string {
const lines: string[] = [];
for (const [key, value] of Object.entries(obj)) {
for (const [key, value] of sortedEntries(obj)) {
let valueStr: string;
// Check if this key should be expanded (only if not empty)
@ -19,14 +31,17 @@ export function formatJson(obj: any, expandKeys: string[] = []): string {
valueStr = "[]";
} else {
const arrayItems = value.map((item) => {
const itemStr = JSON.stringify(item);
const itemStr =
item && typeof item === "object" && !Array.isArray(item)
? JSON.stringify(Object.fromEntries(sortedEntries(item)))
: JSON.stringify(item);
return ` ${itemStr.replace(/\\n/g, "\n")}`;
});
valueStr = `[\n${arrayItems.join(",\n")}\n ]`;
}
} else {
// Object expansion
const objEntries = Object.entries(value);
const objEntries = sortedEntries(value);
if (objEntries.length === 0) {
// Keep empty objects compact
valueStr = "{}";

View file

@ -330,14 +330,13 @@ import type { State } from "@/types/evcc";
// Keys that should be expanded (1-level expansion for arrays and objects)
const EXPAND_KEYS = [
"battery",
"charger",
"forecast",
"loadpoints",
"pv",
"vehicles",
"statistics",
"charger",
"site",
"messenger",
"meter",
"pv",
"tariff",
"vehicle",
];
@ -494,7 +493,9 @@ export default defineComponent({
const deviceEndpoints = [
"config/loadpoints",
"config/devices/charger",
"config/devices/messenger",
"config/devices/meter",
"config/devices/tariff",
"config/devices/vehicle",
];
@ -505,7 +506,9 @@ export default defineComponent({
"config/eebus",
"config/hems",
"config/messaging",
"config/messagingEvents",
"config/tariffs",
"config/tariff",
];
const configs: any = {};
@ -515,7 +518,11 @@ export default defineComponent({
// Add private=false for device endpoints to hide private data in bug reports
const response = await api.get(endpoint, { params: { private: false } });
if (response.data && Object.keys(response.data).length > 0) {
const key = endpoint.replace("config/", "").replace("devices/", "");
let key = endpoint.replace("config/", "").replace("devices/", "");
// avoid collision with config/devices/tariff
if (key === "tariff" && !deviceEndpoints.includes(endpoint)) {
key = "tariffRefs";
}
let data = response.data;
// Filter out entries without id property for device endpoints