diff --git a/Web App/web/src/views/Charging.vue b/Web App/web/src/views/Charging.vue index 2dd9811..6a65141 100644 --- a/Web App/web/src/views/Charging.vue +++ b/Web App/web/src/views/Charging.vue @@ -57,6 +57,41 @@ const sessionMetrics = computed(() => // --- Real OCPP control (Anker Solix), gated by the per-user control mode --- // The demo session card above is presentational; this card drives a real charger // via the control endpoints when the user has picked Own/Proxy CSMS in Settings. +// --- Folding the cards --- +// +// The column runs long once the readings are in it, so every card folds away. +// Which ones are folded is kept in localStorage rather than on the profile, the +// same way the provider panel keeps its own: it is a per-device reading habit, +// not an account setting, and it should survive leaving the tab. Keyed by card, +// so a fold outlives switching charger. +const COLLAPSED_KEY = "dv_charging_collapsed"; + +const collapsed = ref(readCollapsed()); + +function readCollapsed() { + try { + const raw = JSON.parse(localStorage.getItem(COLLAPSED_KEY) || "[]"); + return Array.isArray(raw) ? raw.filter((id) => typeof id === "string") : []; + } catch { + return []; // unreadable (hand-edited, or written by an older version) + } +} + +function isOpen(id) { + return !collapsed.value.includes(id); +} + +function toggleCard(id) { + collapsed.value = isOpen(id) + ? [...collapsed.value, id] + : collapsed.value.filter((k) => k !== id); + try { + localStorage.setItem(COLLAPSED_KEY, JSON.stringify(collapsed.value)); + } catch { + // A full or blocked store just means the choice lasts this visit only. + } +} + const ctlMode = ref("off"); const ctlSerial = ref(localStorage.getItem("dv_ctl_serial") || ""); const ctl = ref(null); // { connected, status, controlMode, ... } @@ -728,12 +763,27 @@ onMounted(async () => {
{{ t("charging.control.title") }}
+ + +{{ t("charging.modbus.title") }}
+ + +{{ t("charging.modbus.alarmsHint") }}
{{ t("charging.info.title") }}
+{{ t("charging.stations.noControlHint") }}
+