From 3f19b6a6de7a91bfd8549521fec63642c95ddb77 Mon Sep 17 00:00:00 2001 From: Maschga <88616799+Maschga@users.noreply.github.com> Date: Wed, 29 Apr 2026 14:45:48 +0200 Subject: [PATCH] refactor: use single modal instances for loadpoint (#29109) Co-authored-by: Michael Geers --- .../components/ChargingPlans/ChargingPlan.vue | 189 +-------------- .../ChargingPlans/ChargingPlanModal.vue | 226 ++++++++++++++++++ assets/js/components/Loadpoints/Loadpoint.vue | 57 +---- .../Loadpoints/Loadpoints.stories.ts | 4 +- .../js/components/Loadpoints/Loadpoints.vue | 63 ++++- .../components/Loadpoints/SettingsModal.vue | 135 ++++++----- .../components/Tariff/SmartFeedInPriority.vue | 6 +- assets/js/components/Vehicles/Vehicle.vue | 43 ++-- assets/js/types/evcc.ts | 13 + assets/js/uiLoadpoints.ts | 28 ++- tests/boost.spec.ts | 14 +- tests/config-ext-meter.spec.ts | 3 +- tests/demo.spec.ts | 4 +- tests/smart-cost.spec.ts | 9 +- 14 files changed, 451 insertions(+), 343 deletions(-) create mode 100644 assets/js/components/ChargingPlans/ChargingPlanModal.vue diff --git a/assets/js/components/ChargingPlans/ChargingPlan.vue b/assets/js/components/ChargingPlans/ChargingPlan.vue index d268ab4e2..3750c1cc9 100644 --- a/assets/js/components/ChargingPlans/ChargingPlan.vue +++ b/assets/js/components/ChargingPlans/ChargingPlan.vue @@ -28,93 +28,26 @@ - - - - - - diff --git a/assets/js/components/ChargingPlans/ChargingPlanModal.vue b/assets/js/components/ChargingPlans/ChargingPlanModal.vue new file mode 100644 index 000000000..03c5e817b --- /dev/null +++ b/assets/js/components/ChargingPlans/ChargingPlanModal.vue @@ -0,0 +1,226 @@ + + + diff --git a/assets/js/components/Loadpoints/Loadpoint.vue b/assets/js/components/Loadpoints/Loadpoint.vue index 22296a37c..c4db30a5a 100644 --- a/assets/js/components/Loadpoints/Loadpoint.vue +++ b/assets/js/components/Loadpoints/Loadpoint.vue @@ -31,14 +31,6 @@ /> -
@@ -115,11 +109,9 @@ import SettingsButton from "./SettingsButton.vue"; import SettingsModal from "./SettingsModal.vue"; import VehicleIcon from "../VehicleIcon"; import SessionInfo from "./SessionInfo.vue"; -import Modal from "bootstrap/js/dist/modal"; import { defineComponent, type PropType } from "vue"; import type { CHARGE_MODE, - PHASES, PHASE_ACTION, PV_ACTION, CHARGER_STATUS_REASON, @@ -139,7 +131,6 @@ export default defineComponent({ Phases, LabelAndValue, LoadpointSettingsButton: SettingsButton, - LoadpointSettingsModal: SettingsModal, LoadpointSessionInfo: SessionInfo, VehicleIcon, }, @@ -243,7 +234,17 @@ export default defineComponent({ forecast: Object as PropType, lastSmartCostLimit: Number, lastSmartFeedInPriorityLimit: Number, + vehicleKnown: Boolean, + vehicleHasSoc: Boolean, + vehicleNotReachable: Boolean, + socBasedCharging: Boolean, + socBasedPlanning: Boolean, + capacity: Number, + range: Number, + rangePerSoc: Number, + socPerKwh: { type: Number, required: true }, }, + emits: ["open-charging-plan-modal", "open-settings-modal"], data() { return { tickerHandler: null as Timeout, @@ -290,27 +291,10 @@ export default defineComponent({ showChargingIndicator() { return this.charging && this.chargePower > 0; }, - vehicleKnown() { - return !!this.vehicleName; - }, - vehicleHasSoc() { - return this.vehicleKnown && !this.vehicle?.features?.includes("Offline"); - }, - vehicleNotReachable() { - // online vehicle that was not reachable at startup - const features = this.vehicle?.features || []; - return features.includes("Offline") && features.includes("Retryable"); - }, planTimeUnreachable() { // 1 minute tolerance return this.planOverrun > 60; }, - socBasedCharging() { - return this.vehicleHasSoc || this.vehicleSoc > 0; - }, - socBasedPlanning() { - return this.socBasedCharging && this.vehicle?.capacity && this.vehicle?.capacity > 0; - }, pvPossible() { return this.pvConfigured || this.gridConfigured; }, @@ -379,15 +363,6 @@ export default defineComponent({ setLimitEnergy(kWh: number) { api.post(this.apiPath("limitenergy") + "/" + kWh); }, - setMaxCurrent(maxCurrent: number) { - api.post(this.apiPath("maxcurrent") + "/" + maxCurrent); - }, - setMinCurrent(minCurrent: number) { - api.post(this.apiPath("mincurrent") + "/" + minCurrent); - }, - setPhasesConfigured(phases: PHASES) { - api.post(this.apiPath("phases") + "/" + phases); - }, changeVehicle(name: string) { api.post(this.apiPath("vehicle") + `/${name}`); }, @@ -397,9 +372,6 @@ export default defineComponent({ setBatteryBoost(batteryBoost: boolean) { api.post(this.apiPath("batteryboost") + `/${batteryBoost ? "1" : "0"}`); }, - setBatteryBoostLimit(limit: number) { - api.post(this.apiPath("batteryboostlimit") + "/" + limit); - }, fmtPower(value: number) { return this.fmtW(value, POWER_UNIT.AUTO); }, @@ -407,10 +379,7 @@ export default defineComponent({ return this.fmtWh(value, POWER_UNIT.AUTO); }, openSettingsModal() { - const modal = Modal.getOrCreateInstance( - document.getElementById(`loadpointSettingsModal_${this.id}`) as HTMLElement - ); - modal.show(); + this.$emit("open-settings-modal"); }, }, }); diff --git a/assets/js/components/Loadpoints/Loadpoints.stories.ts b/assets/js/components/Loadpoints/Loadpoints.stories.ts index e15a588cf..9d86ffdf0 100644 --- a/assets/js/components/Loadpoints/Loadpoints.stories.ts +++ b/assets/js/components/Loadpoints/Loadpoints.stories.ts @@ -1,6 +1,6 @@ import Loadpoints from "./Loadpoints.vue"; import type { Meta, StoryFn } from "@storybook/vue3"; -import { SMART_COST_TYPE } from "@/types/evcc"; +import { CURRENCY, SMART_COST_TYPE } from "@/types/evcc"; // Create LoadpointCompact structure for the Loadpoints component const createLoadpoint = (opts: any = {}) => { @@ -84,7 +84,7 @@ const baseArgs = { tariffGrid: 0.144, tariffCo2: 252, tariffFeedIn: 0.08, - currency: "EUR", + currency: CURRENCY.EUR, gridConfigured: true, pvConfigured: true, batteryConfigured: true, diff --git a/assets/js/components/Loadpoints/Loadpoints.vue b/assets/js/components/Loadpoints/Loadpoints.vue index f761fa6f6..078896097 100644 --- a/assets/js/components/Loadpoints/Loadpoints.vue +++ b/assets/js/components/Loadpoints/Loadpoints.vue @@ -36,6 +36,10 @@ class="h-100" :class="{ 'loadpoint-unselected': !selected(loadpoint.id) }" @click="goTo(loadpoint.id)" + @open-charging-plan-modal=" + (openArrivalTab) => openChargingPlanModal(loadpoint.id, openArrivalTab) + " + @open-settings-modal="openSettingsModal(loadpoint.id)" /> @@ -58,6 +62,28 @@ +
+ + +
@@ -68,11 +94,21 @@ import "@h2d2/shopicons/es/filled/lightning"; import Loadpoint from "./Loadpoint.vue"; import { defineComponent, type PropType } from "vue"; -import type { UiLoadpoint, SMART_COST_TYPE, Timeout, Vehicle, BATTERY_MODE } from "@/types/evcc"; +import type { + UiLoadpoint, + SMART_COST_TYPE, + Timeout, + Vehicle, + BATTERY_MODE, + Forecast, + CURRENCY, +} from "@/types/evcc"; +import ChargingPlanModal from "../ChargingPlans/ChargingPlanModal.vue"; +import SettingsModal from "../Loadpoints/SettingsModal.vue"; export default defineComponent({ name: "Loadpoints", - components: { Loadpoint }, + components: { Loadpoint, ChargingPlanModal, SettingsModal }, props: { loadpoints: { type: Array as PropType, default: () => [] }, vehicles: { type: Array as PropType }, @@ -82,14 +118,14 @@ export default defineComponent({ tariffGrid: Number, tariffCo2: Number, tariffFeedIn: Number, - currency: String, + currency: String as PropType, selectedId: String, gridConfigured: Boolean, pvConfigured: Boolean, batteryConfigured: Boolean, batterySoc: Number, batteryMode: String as PropType, - forecast: Object, // as PropType, + forecast: Object as PropType, }, emits: ["id-changed"], data() { @@ -188,6 +224,25 @@ export default defineComponent({ } }, 1000); }, + openChargingPlanModal(loadpointId: string, openArrivalTab = false) { + const modal = this.$refs["chargingPlanModal"] as + | InstanceType + | undefined; + + if (openArrivalTab) { + modal?.showArrivalTab(); + } else { + modal?.showDepartureTab(); + } + + modal?.open(loadpointId); + }, + openSettingsModal(loadpointId: string) { + const modal = this.$refs["settingsModal"] as + | InstanceType + | undefined; + modal?.open(loadpointId); + }, }, }); diff --git a/assets/js/components/Loadpoints/SettingsModal.vue b/assets/js/components/Loadpoints/SettingsModal.vue index 34d254b93..e3a11a253 100644 --- a/assets/js/components/Loadpoints/SettingsModal.vue +++ b/assets/js/components/Loadpoints/SettingsModal.vue @@ -1,30 +1,31 @@