From bfba6bb2fc0e4bb0ede2c60f6eec57f1d39c678a Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Mon, 3 Aug 2026 08:51:14 +0200 Subject: [PATCH] Config UI: fix decimal input in numeric fields (#32458) --- assets/js/components/Config/PropertyField.vue | 4 +- tests/config-decimal-input.spec.ts | 44 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 tests/config-decimal-input.spec.ts diff --git a/assets/js/components/Config/PropertyField.vue b/assets/js/components/Config/PropertyField.vue index bc90bb4b5..43c8f25bb 100644 --- a/assets/js/components/Config/PropertyField.vue +++ b/assets/js/components/Config/PropertyField.vue @@ -252,7 +252,7 @@ export default { }, useLazyBinding() { // avoid conversion loop issues - return this.pricePerKWh; + return this.inputType === "number"; }, icons() { return this.property === "icon"; @@ -386,6 +386,8 @@ export default { return val; }, onFieldChange(e) { + // unparsable input (e.g. locale decimal separator mismatch) + if (e.target.validity?.badInput) return; this.value = this.coerceValue(e.target.value); }, onFieldInput(e) { diff --git a/tests/config-decimal-input.spec.ts b/tests/config-decimal-input.spec.ts new file mode 100644 index 000000000..7974117d4 --- /dev/null +++ b/tests/config-decimal-input.spec.ts @@ -0,0 +1,44 @@ +import { test, expect } from "@playwright/test"; +import { start, stop, baseUrl } from "./evcc"; +import { expectModalVisible } from "./utils"; + +// German browser language (comma as decimal separator), English UI +// macOS Chromium reads --lang, Linux reads LC_ALL/LANG +test.use({ + baseURL: baseUrl(), + launchOptions: { + args: ["--lang=de-DE"], + env: { ...process.env, LC_ALL: "de_DE.UTF-8", LANG: "de_DE.UTF-8" }, + }, + locale: "en-US", +}); + +test.beforeAll(async () => { + await start(); +}); + +test.afterAll(async () => { + await stop(); +}); + +test("decimal input with german separator", async ({ page }) => { + await page.goto("/#/config"); + await page.getByRole("button", { name: "Add solar or battery" }).click(); + const modal = page.getByTestId("meter-modal"); + await expectModalVisible(modal); + await modal.getByRole("button", { name: "Add solar meter" }).click(); + await modal.getByLabel("Manufacturer").selectOption({ label: "SunSpec Inverter" }); + await modal.getByRole("button", { name: "Show advanced settings" }).click(); + + // comma accepted as decimal separator + const timeout = modal.getByLabel("Timeout"); + await timeout.pressSequentially("0,5"); + await expect(timeout).toHaveValue("0.5"); + + // intermediate zeros survive typing + const delay = modal.getByLabel("Delay"); + await delay.pressSequentially("0.004"); + await expect(delay).toHaveValue("0.004"); + await delay.blur(); + await expect(delay).toHaveValue("0.004"); +});