UI: configure settings via URL params (#31244)

This commit is contained in:
Michael Geers 2026-06-26 18:46:54 +02:00 • committed by GitHub
parent 64a7600b78
commit b0a3564d26
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 90 additions and 7 deletions

View file

@ -6,6 +6,7 @@ import App from "./views/App.vue";
import setupRouter from "./router.ts";
import setupI18n from "./i18n.ts";
import { watchThemeChanges } from "./theme.ts";
import { applyUrlSettings } from "./urlSettings.ts";
import { appDetection, sendToApp } from "./utils/native";
import store from "./store";
import type { Notification } from "./types/evcc";
@ -74,6 +75,8 @@ const app = createApp(
})
);
applyUrlSettings();
const i18n = setupI18n();
const head = createHead();

View file

@ -94,10 +94,7 @@ import { getThemePreference, setThemePreference } from "@/theme.ts";
import { getUnits, setUnits, is12hFormat, set12hFormat } from "@/units";
import { isApp } from "@/utils/native";
import { defineComponent, type PropType } from "vue";
import { LENGTH_UNIT, THEME, type UiLoadpoint } from "@/types/evcc";
const TIME_12H = "12";
const TIME_24H = "24";
import { LENGTH_UNIT, THEME, TIME_FORMAT, type UiLoadpoint } from "@/types/evcc";
export default defineComponent({
name: "UserInterfaceSettings",
@ -110,11 +107,11 @@ export default defineComponent({
theme: getThemePreference(),
language: getLocalePreference() || "",
unit: getUnits(),
timeFormat: is12hFormat() ? TIME_12H : TIME_24H,
timeFormat: is12hFormat() ? TIME_FORMAT.H12 : TIME_FORMAT.H24,
fullscreenActive: false,
THEMES: Object.values(THEME),
UNITS: Object.values(LENGTH_UNIT),
TIME_FORMATS: [TIME_24H, TIME_12H],
TIME_FORMATS: [TIME_FORMAT.H24, TIME_FORMAT.H12],
};
},
computed: {
@ -139,7 +136,7 @@ export default defineComponent({
setUnits(value);
},
timeFormat(value) {
set12hFormat(value === TIME_12H);
set12hFormat(value === TIME_FORMAT.H12);
},
theme(value) {
setThemePreference(value);

View file

@ -289,6 +289,11 @@ export enum LENGTH_UNIT {
MILES = "mi",
}
export enum TIME_FORMAT {
H12 = "12",
H24 = "24",
}
export interface Loadpoint {
name: string;
batteryBoost: boolean;

41
assets/js/urlSettings.ts Normal file
View file

@ -0,0 +1,41 @@
import settings from "./settings";
import { LOCALES } from "./i18n";
import { LENGTH_UNIT, THEME, TIME_FORMAT } from "./types/evcc";
export function applyUrlSettings() {
const url = new URL(window.location.href);
const params = url.searchParams;
let touched = false;
const theme = params.get("theme");
if (theme && Object.values(THEME).includes(theme as THEME)) {
settings.theme = theme as THEME;
touched = true;
}
const lang = params.get("lang");
if (lang === "auto") {
settings.locale = null;
touched = true;
} else if (lang && lang in LOCALES) {
settings.locale = lang as keyof typeof LOCALES;
touched = true;
}
const unit = params.get("unit");
if (unit && Object.values(LENGTH_UNIT).includes(unit as LENGTH_UNIT)) {
settings.unit = unit as LENGTH_UNIT;
touched = true;
}
const format = params.get("format");
if (format && Object.values(TIME_FORMAT).includes(format as TIME_FORMAT)) {
settings.is12hFormat = format === TIME_FORMAT.H12;
touched = true;
}
if (touched) {
["theme", "lang", "unit", "format"].forEach((k) => params.delete(k));
window.history.replaceState(window.history.state, "", url.pathname + url.search + url.hash);
}
}

View file

@ -0,0 +1,37 @@
import { test, expect } from "@playwright/test";
import { start, stop, baseUrl } from "./evcc";
test.use({ baseURL: baseUrl() });
test.beforeAll(async () => {
await start();
});
test.afterAll(async () => {
await stop();
});
test.describe("ui settings via url", async () => {
test("apply, persist and strip valid params", async ({ page }) => {
await page.goto("/?theme=dark&lang=de&unit=mi&format=12");
await expect(page.locator("html")).toHaveAttribute("data-bs-theme", "dark");
await expect(page.locator("html")).toHaveAttribute("lang", "de");
const stored = await page.evaluate(() => ({
theme: localStorage["settings_theme"],
locale: localStorage["settings_locale"],
unit: localStorage["settings_unit"],
format: localStorage["settings_12h_format"],
}));
expect(stored).toEqual({ theme: "dark", locale: "de", unit: "mi", format: "true" });
// params removed from address bar
expect(new URL(page.url()).search).toBe("");
});
test("ignore invalid value and keep it in url", async ({ page }) => {
await page.goto("/?theme=bogus");
await expect(page.locator("html")).not.toHaveAttribute("data-bs-theme", "bogus");
expect(new URL(page.url()).searchParams.get("theme")).toBe("bogus");
});
});