From 54a1b0cc0baba657a0672cc22f026b2ef12c474c Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Apr 2026 08:23:58 +0000 Subject: [PATCH] Sessions UI: Add odometer (mileage) column in table view (#29263) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: andig <184815+andig@users.noreply.github.com> Co-authored-by: naltatis <152287+naltatis@users.noreply.github.com> Co-authored-by: Michael Geers --- .../js/components/Sessions/SessionTable.vue | 21 +++++++++++++++---- i18n/de.json | 1 + i18n/en.json | 1 + tests/sessions.spec.ts | 15 +++++++++++++ tests/sessions.sql | 4 ++-- 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/assets/js/components/Sessions/SessionTable.vue b/assets/js/components/Sessions/SessionTable.vue index 1aff0a2ed..ce4a4fbe3 100644 --- a/assets/js/components/Sessions/SessionTable.vue +++ b/assets/js/components/Sessions/SessionTable.vue @@ -119,9 +119,10 @@ :key="column.name" :data-testid="`sessions-foot-${column.name}`" scope="col" - class="align-top text-end" + class="align-top text-end tabular" > - {{ column.format(column.total || 0) }} + + {{ column.format(column.total || 0) }} @@ -133,7 +134,7 @@ data-testid="sessions-entry" @click="showDetails(session.id)" > - + {{ fmtFullDateTime(new Date(session.created), true) }} @@ -146,7 +147,11 @@
{{ session.loadpoint }}
{{ session.vehicle }}
- + - {{ column.format(column.value(session) || 0) }} @@ -162,6 +167,7 @@ import CustomSelect from "../Helper/CustomSelect.vue"; import formatter, { POWER_UNIT } from "@/mixins/formatter"; import breakpoint from "@/mixins/breakpoint.ts"; import settings from "@/settings.ts"; +import { distanceUnit, distanceValue } from "@/units"; import type { CURRENCY } from "@/types/evcc"; import type { Session, Column } from "./types"; @@ -244,6 +250,13 @@ export default defineComponent({ value: (session) => session.chargeDuration, format: (value) => this.fmtDurationNs(value, false, "h"), }, + { + name: "odometer", + unit: distanceUnit(), + total: null, + value: (session) => session.odometer || null, + format: (value) => this.fmtNumber(distanceValue(value), 0), + }, { name: "avgPower", unit: "kW", diff --git a/i18n/de.json b/i18n/de.json index aec63eea6..93c705a90 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -1445,6 +1445,7 @@ }, "loadpoint": "Ladepunkt", "noData": "Noch keine Ladevorgänge in diesem Monat.", + "odometer": "Kilometerstand", "overview": "Übersicht", "period": { "month": "Monat", diff --git a/i18n/en.json b/i18n/en.json index 8d852e51c..4aa510dae 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1445,6 +1445,7 @@ }, "loadpoint": "Charging point", "noData": "No charging sessions this month.", + "odometer": "Mileage", "overview": "Overview", "period": { "month": "Month", diff --git a/tests/sessions.spec.ts b/tests/sessions.spec.ts index dc7aa7b05..4e4efe7dd 100644 --- a/tests/sessions.spec.ts +++ b/tests/sessions.spec.ts @@ -245,10 +245,24 @@ test.describe("columns desktop", async () => { await page.goto("/#/sessions?year=2023&month=3"); await expect(page.getByTestId("sessions-head-co2")).toBeVisible(); }); + test("select odometer column if it has values", async ({ page }) => { + await page.goto("/#/sessions?year=2023&month=3"); + await expect( + page.getByTestId("sessions-head-co2").locator("option[value=odometer]") + ).toHaveCount(1); + await page.getByTestId("sessions-head-co2").getByRole("combobox").selectOption("odometer"); + await expect(page.getByTestId("sessions-head-odometer")).toBeVisible(); + await expect(page.getByTestId("sessions-entry").nth(0)).toContainText("12,345"); + await expect(page.getByTestId("sessions-foot-odometer")).toHaveText(""); + }); test("hide co2 column if it doesnt have values", async ({ page }) => { await page.goto("/#/sessions?year=2023&month=5"); await expect(page.getByTestId("sessions-head-co2")).toHaveCount(0); }); + test("hide odometer column if it doesnt have values", async ({ page }) => { + await page.goto("/#/sessions?year=2023&month=5"); + await expect(page.getByTestId("sessions-head-odometer")).toHaveCount(0); + }); }); const date = new Date(); @@ -335,6 +349,7 @@ test.describe("session details", async () => { await expect(modal.getByTestId("session-details-price")).toContainText("2.00 € 20.0 ct/kWh"); await expect(modal.getByTestId("session-details-co2")).toContainText("3 kg"); await expect(modal.getByTestId("session-details-co2")).toContainText("300 g/kWh"); + await expect(modal.getByTestId("session-details-odometer")).toContainText("12,345 km"); }); test("edit session (session 5)", async ({ page }) => { diff --git a/tests/sessions.sql b/tests/sessions.sql index bc2bbf164..72c789ec4 100644 --- a/tests/sessions.sql +++ b/tests/sessions.sql @@ -18,8 +18,8 @@ CREATE TABLE `sessions` ( PRIMARY KEY (`id`) ); -INSERT INTO `sessions` VALUES (1,'2023-03-01 08:00:00.0+02:00','2023-05-02 12:00:00.0+02:00','Carport',NULL,'blauer e-Golf',NULL,NULL,10,NULL,100,2,0.2,300,3600000000000); +INSERT INTO `sessions` VALUES (1,'2023-03-01 08:00:00.0+02:00','2023-05-02 12:00:00.0+02:00','Carport',NULL,'blauer e-Golf',NULL,NULL,10,12345,100,2,0.2,300,3600000000000); INSERT INTO `sessions` VALUES (2,'2023-05-02 08:00:00.0+02:00','2023-05-02 12:00:00.0+02:00','Carport',NULL,'blauer e-Golf',NULL,NULL,10,NULL,100,2,0.2,NULL,1800000000000); INSERT INTO `sessions` VALUES (3,'2023-05-02 08:00:00.0+02:00','2023-05-02 12:00:00.0+02:00','Carport',NULL,'blauer e-Golf',NULL,NULL,2.5,NULL,88.21,0.75,0.3,NULL,NULL); INSERT INTO `sessions` VALUES (4,'2023-05-03 16:00:00.0+02:00','2023-05-03 20:00:00.0+02:00','Carport',NULL,'weißes Model 3',NULL,NULL,2.5,NULL,50,0.25,0.1,NULL,NULL); -INSERT INTO `sessions` VALUES (5,'2023-05-04 22:00:00.0+02:00','2023-05-05 06:00:00.0+02:00','Garage',NULL,'weißes Model 3',NULL,NULL,5,NULL,0,2.5,0.5,null,3600000000000); \ No newline at end of file +INSERT INTO `sessions` VALUES (5,'2023-05-04 22:00:00.0+02:00','2023-05-05 06:00:00.0+02:00','Garage',NULL,'weißes Model 3',NULL,NULL,5,NULL,0,2.5,0.5,null,3600000000000);