From 90e7ac313ff1cf90112027083e619768e8bbaded Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Wed, 11 Feb 2026 09:14:16 +0100 Subject: [PATCH] Config UI: refactor modal handling, add deep linking (#27344) --- assets/js/components/Auth/PasswordModal.vue | 4 + .../components/Config/BackupRestoreModal.vue | 1 + assets/js/components/Config/ChargerModal.vue | 26 +- assets/js/components/Config/CircuitsModal.vue | 3 +- assets/js/components/Config/ControlModal.vue | 1 + .../Config/DeviceModal/DeviceModalBase.vue | 19 +- assets/js/components/Config/EebusModal.vue | 3 +- .../components/Config/ExperimentalModal.vue | 1 + assets/js/components/Config/GeneralConfig.vue | 50 +-- .../components/Config/GeneralConfigEntry.vue | 20 +- assets/js/components/Config/HemsModal.vue | 3 +- assets/js/components/Config/InfluxModal.vue | 3 +- assets/js/components/Config/JsonModal.vue | 11 +- .../js/components/Config/LoadpointModal.vue | 72 ++-- .../js/components/Config/MessagingModal.vue | 3 +- assets/js/components/Config/MeterModal.vue | 82 +++-- .../js/components/Config/ModbusProxyModal.vue | 3 +- assets/js/components/Config/MqttModal.vue | 3 +- assets/js/components/Config/NetworkModal.vue | 3 +- assets/js/components/Config/OcppModal.vue | 7 +- assets/js/components/Config/ShmModal.vue | 3 +- assets/js/components/Config/SponsorModal.vue | 3 +- assets/js/components/Config/TariffsModal.vue | 3 +- .../js/components/Config/TelemetryModal.vue | 1 + assets/js/components/Config/TitleModal.vue | 3 +- assets/js/components/Config/VehicleModal.vue | 7 +- assets/js/components/Config/YamlModal.vue | 12 +- assets/js/components/Helper/GenericModal.vue | 42 +-- assets/js/configModal.test.ts | 75 ++++ assets/js/configModal.ts | 302 ++++++++++++++++ assets/js/router.test.ts | 51 +++ assets/js/router.ts | 22 ++ assets/js/views/Config.vue | 321 ++++-------------- tests/config-deeplink.spec.ts | 65 ++++ tests/config-loadpoint.spec.ts | 10 + tests/config-messaging.spec.ts | 2 +- 36 files changed, 785 insertions(+), 455 deletions(-) create mode 100644 assets/js/configModal.test.ts create mode 100644 assets/js/configModal.ts create mode 100644 assets/js/router.test.ts create mode 100644 tests/config-deeplink.spec.ts diff --git a/assets/js/components/Auth/PasswordModal.vue b/assets/js/components/Auth/PasswordModal.vue index 9a6f2b1b3..45657128f 100644 --- a/assets/js/components/Auth/PasswordModal.vue +++ b/assets/js/components/Auth/PasswordModal.vue @@ -4,6 +4,7 @@ ref="modal" :title="title" :data-testid="dataTestId" + :config-modal-name="configModalName" :uncloseable="isUncloseable" @open="open" @closed="closed" @@ -114,6 +115,9 @@ export default defineComponent({ modalId() { return this.updateMode ? "passwordUpdateModal" : "passwordSetupModal"; }, + configModalName() { + return this.updateMode ? "passwordupdate" : undefined; + }, dataTestId() { return this.updateMode ? "password-update-modal" : "password-setup-modal"; }, diff --git a/assets/js/components/Config/BackupRestoreModal.vue b/assets/js/components/Config/BackupRestoreModal.vue index a4a07150f..88c2105e4 100644 --- a/assets/js/components/Config/BackupRestoreModal.vue +++ b/assets/js/components/Config/BackupRestoreModal.vue @@ -2,6 +2,7 @@
@@ -86,7 +85,7 @@ import { defineComponent, type PropType } from "vue"; import FormRow from "./FormRow.vue"; import DeviceModalBase from "./DeviceModal/DeviceModalBase.vue"; import { ConfigType } from "@/types/evcc"; -import type { ModalFade } from "../Helper/GenericModal.vue"; +import { getModal } from "@/configModal"; import { type DeviceValues, type Template, @@ -123,16 +122,13 @@ export default defineComponent({ DeviceModalBase, }, props: { - id: Number, - loadpointType: { type: String as PropType, default: null }, - fade: String as PropType, ocpp: { type: Object as PropType, default: () => ({ config: { port: 0 }, status: { stations: [] } }), }, isSponsor: Boolean, }, - emits: ["added", "updated", "removed", "close"], + emits: ["changed", "close"], data() { return { initialValues, @@ -143,6 +139,12 @@ export default defineComponent({ }; }, computed: { + id(): number | undefined { + return getModal("charger")?.id; + }, + loadpointType(): LoadpointType | null { + return (getModal("charger")?.type as LoadpointType) || null; + }, modalTitle(): string { if (this.isNew) { return this.$t(`config.charger.titleAdd.${this.loadpointType}`); @@ -319,6 +321,10 @@ export default defineComponent({ this.ocppNextStepConfirmed = true; } }, + async emitChanged(action: "added" | "updated" | "removed", name?: string) { + const result = { action, name }; + this.$emit("changed", result); + }, reset() { this.ocppNextStepConfirmed = false; this.currentTemplate = null; diff --git a/assets/js/components/Config/CircuitsModal.vue b/assets/js/components/Config/CircuitsModal.vue index 4ee03411b..4a06ac44f 100644 --- a/assets/js/components/Config/CircuitsModal.vue +++ b/assets/js/components/Config/CircuitsModal.vue @@ -1,13 +1,12 @@