From 7f772bad7320f3fedce3725f758406d8e6ebe59d Mon Sep 17 00:00:00 2001 From: Maschga <88616799+Maschga@users.noreply.github.com> Date: Tue, 17 Feb 2026 12:26:03 +0100 Subject: [PATCH] Config UI: make messengers configurable (#26946) Co-authored-by: andig Co-authored-by: andig Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> Co-authored-by: Michael Geers --- api/api.go | 5 + api/globalconfig/types.go | 65 +++--- assets/css/app.css | 23 ++ .../components/ChargingPlans/PlanStrategy.vue | 34 +-- assets/js/components/Config/DeviceCard.vue | 74 +------ .../components/Config/DeviceCardEditIcon.vue | 84 ++++++++ .../components/Config/DeviceModal/Actions.vue | 2 +- .../Config/DeviceModal/DeviceInfoButton.vue | 35 +++ .../Config/DeviceModal/DeviceModalBase.vue | 5 + assets/js/components/Config/JsonModal.vue | 13 +- assets/js/components/Config/Markdown.vue | 4 +- .../components/Config/Messaging/EventItem.vue | 134 ++++++++++++ .../Config/Messaging/MessagingLegacyModal.vue | 34 +++ .../Config/Messaging/MessagingModal.vue | 172 +++++++++++++++ .../Config/Messaging/MessengerModal.vue | 74 +++++++ .../js/components/Config/Messaging/utils.ts | 3 + .../js/components/Config/MessagingModal.vue | 26 --- assets/js/components/Config/PropertyField.vue | 31 ++- assets/js/components/Config/TestResult.vue | 11 +- assets/js/components/Config/VehicleModal.vue | 1 + .../Config/defaultYaml/messenger.yaml | 7 + assets/js/components/Helper/GenericModal.vue | 19 +- assets/js/types/evcc.ts | 25 ++- assets/js/views/Config.vue | 73 +++++-- charger/template.go | 4 +- cmd/root.go | 11 +- cmd/setup.go | 204 ++++++++++-------- core/keys/global.go | 1 + core/loadpoint.go | 12 +- core/loadpoint_test.go | 8 +- core/site.go | 6 +- i18n/de.json | 63 +++++- i18n/en.json | 65 +++++- {push => messenger}/config.go | 12 +- {push => messenger}/hub.go | 22 +- push/push.go => messenger/messenger.go | 4 +- {push => messenger}/ntfy.go | 5 +- {push => messenger}/pushover.go | 5 +- {push => messenger}/shoutrrr.go | 6 +- {push => messenger}/telegram.go | 5 +- messenger/template.go | 21 ++ messenger/template_test.go | 24 +++ meter/template.go | 4 +- server/http.go | 13 +- server/http_config_device_handler.go | 22 ++ tariff/template.go | 4 +- templates/definition/embed.go | 2 +- templates/definition/messenger/email.yaml | 39 ++++ templates/definition/messenger/ntfy.yaml | 63 ++++++ templates/definition/messenger/pushover.yaml | 52 +++++ templates/definition/messenger/shoutrrr.yaml | 19 ++ templates/definition/messenger/telegram.yaml | 39 ++++ tests/config-messaging.evcc.yaml | 5 + tests/config-messaging.spec.ts | 180 ++++++++++++++-- tests/messaging-legacy.sql | 11 + util/config/instance.go | 6 + util/templates/class.go | 1 + util/templates/class_enumer.go | 12 +- util/templates/init.go | 2 +- vehicle/template.go | 4 +- 60 files changed, 1547 insertions(+), 363 deletions(-) create mode 100644 assets/js/components/Config/DeviceCardEditIcon.vue create mode 100644 assets/js/components/Config/DeviceModal/DeviceInfoButton.vue create mode 100644 assets/js/components/Config/Messaging/EventItem.vue create mode 100644 assets/js/components/Config/Messaging/MessagingLegacyModal.vue create mode 100644 assets/js/components/Config/Messaging/MessagingModal.vue create mode 100644 assets/js/components/Config/Messaging/MessengerModal.vue create mode 100644 assets/js/components/Config/Messaging/utils.ts delete mode 100644 assets/js/components/Config/MessagingModal.vue create mode 100644 assets/js/components/Config/defaultYaml/messenger.yaml rename {push => messenger}/config.go (73%) rename {push => messenger}/hub.go (88%) rename push/push.go => messenger/messenger.go (97%) rename {push => messenger}/ntfy.go (93%) rename {push => messenger}/pushover.go (91%) rename {push => messenger}/shoutrrr.go (87%) rename {push => messenger}/telegram.go (95%) create mode 100644 messenger/template.go create mode 100644 messenger/template_test.go create mode 100644 templates/definition/messenger/email.yaml create mode 100644 templates/definition/messenger/ntfy.yaml create mode 100644 templates/definition/messenger/pushover.yaml create mode 100644 templates/definition/messenger/shoutrrr.yaml create mode 100644 templates/definition/messenger/telegram.yaml create mode 100644 tests/config-messaging.evcc.yaml create mode 100644 tests/messaging-legacy.sql diff --git a/api/api.go b/api/api.go index cb3680ac1..d92a7e65b 100644 --- a/api/api.go +++ b/api/api.go @@ -291,3 +291,8 @@ type Circuit interface { type Redactor interface { Redacted() any } + +// Messenger implements message sending +type Messenger interface { + Send(title, msg string) +} diff --git a/api/globalconfig/types.go b/api/globalconfig/types.go index 036670214..ab7fda8a8 100644 --- a/api/globalconfig/types.go +++ b/api/globalconfig/types.go @@ -34,34 +34,35 @@ const ( ) type All struct { - Network Network - Ocpp ocpp.Config - Log string - SponsorToken string - Plant string // telemetry plant id - Telemetry bool - Mcp bool - Metrics bool - Profile bool - Levels map[string]string - Interval time.Duration - Database DB - Mqtt Mqtt - ModbusProxy []ModbusProxy - Javascript []Javascript - Go []Go - Influx Influx - EEBus eebus.Config - HEMS Hems - SHM shm.Config - Messaging Messaging - Meters []config.Named - Chargers []config.Named - Vehicles []config.Named - Tariffs Tariffs - Site map[string]any - Loadpoints []config.Named - Circuits []config.Named + Network Network + Ocpp ocpp.Config + Log string + SponsorToken string + Plant string // telemetry plant id + Telemetry bool + Mcp bool + Metrics bool + Profile bool + Levels map[string]string + Interval time.Duration + Database DB + Mqtt Mqtt + ModbusProxy []ModbusProxy + Javascript []Javascript + Go []Go + Influx Influx + EEBus eebus.Config + HEMS Hems + SHM shm.Config + Messaging Messaging + MessagingEvents MessagingEvents + Meters []config.Named + Chargers []config.Named + Vehicles []config.Named + Tariffs Tariffs + Site map[string]any + Loadpoints []config.Named + Circuits []config.Named } type Javascript struct { @@ -146,13 +147,17 @@ type DB struct { } type Messaging struct { - Events map[string]MessagingEventTemplate + Events MessagingEvents Services []config.Typed } +type MessagingEvents = map[string]MessagingEventTemplate + // MessagingEventTemplate is the push message configuration for an event type MessagingEventTemplate struct { - Title, Msg string + Title string `json:"title"` + Msg string `json:"msg"` + Disabled bool `json:"disabled"` } func (c Messaging) IsConfigured() bool { diff --git a/assets/css/app.css b/assets/css/app.css index 67befbf26..9a586c4e0 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -773,3 +773,26 @@ input::-webkit-date-and-time-value { .tabular { font-variant-numeric: tabular-nums; } + +/* Collapsible wrapper pattern with choreographed animation */ +.collapsible-wrapper { + display: grid; + grid-template-rows: 0fr; + transition: grid-template-rows var(--evcc-transition-fast) ease 0.2s; +} + +.collapsible-wrapper.open { + grid-template-rows: 1fr; + transition: grid-template-rows var(--evcc-transition-fast) ease; +} + +.collapsible-content { + overflow: hidden; + opacity: 0; + transition: opacity 0.2s ease; +} + +.collapsible-wrapper.open .collapsible-content { + opacity: 1; + transition: opacity var(--evcc-transition-fast) ease 0.2s; +} diff --git a/assets/js/components/ChargingPlans/PlanStrategy.vue b/assets/js/components/ChargingPlans/PlanStrategy.vue index 0c1f5918a..a8014a76b 100644 --- a/assets/js/components/ChargingPlans/PlanStrategy.vue +++ b/assets/js/components/ChargingPlans/PlanStrategy.vue @@ -1,6 +1,6 @@ @@ -129,15 +80,8 @@ export default { .icon:empty { display: none; } -.edit-button { - /* transparent button, right align icon */ - margin-right: -0.5rem; -} .divide { margin-left: -1.5rem; margin-right: -1.5rem; } -button:disabled { - pointer-events: auto; -} diff --git a/assets/js/components/Config/DeviceCardEditIcon.vue b/assets/js/components/Config/DeviceCardEditIcon.vue new file mode 100644 index 000000000..bcca7ab14 --- /dev/null +++ b/assets/js/components/Config/DeviceCardEditIcon.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/assets/js/components/Config/DeviceModal/Actions.vue b/assets/js/components/Config/DeviceModal/Actions.vue index 3ee0ca369..57e877a89 100644 --- a/assets/js/components/Config/DeviceModal/Actions.vue +++ b/assets/js/components/Config/DeviceModal/Actions.vue @@ -7,7 +7,7 @@ @test="$emit('test')" /> -
+
+ +
+ + + + + diff --git a/assets/js/components/Config/DeviceModal/DeviceModalBase.vue b/assets/js/components/Config/DeviceModal/DeviceModalBase.vue index 9d617f5db..4651ae2dc 100644 --- a/assets/js/components/Config/DeviceModal/DeviceModalBase.vue +++ b/assets/js/components/Config/DeviceModal/DeviceModalBase.vue @@ -10,6 +10,9 @@ @close="handleClose" @visibilitychange="handleVisibilityChange" > +
@@ -167,6 +170,7 @@ + + diff --git a/assets/js/components/Config/Messaging/MessagingLegacyModal.vue b/assets/js/components/Config/Messaging/MessagingLegacyModal.vue new file mode 100644 index 000000000..4fccb7818 --- /dev/null +++ b/assets/js/components/Config/Messaging/MessagingLegacyModal.vue @@ -0,0 +1,34 @@ + + + diff --git a/assets/js/components/Config/Messaging/MessagingModal.vue b/assets/js/components/Config/Messaging/MessagingModal.vue new file mode 100644 index 000000000..815c0d8b6 --- /dev/null +++ b/assets/js/components/Config/Messaging/MessagingModal.vue @@ -0,0 +1,172 @@ + + + diff --git a/assets/js/components/Config/Messaging/MessengerModal.vue b/assets/js/components/Config/Messaging/MessengerModal.vue new file mode 100644 index 000000000..641060c4a --- /dev/null +++ b/assets/js/components/Config/Messaging/MessengerModal.vue @@ -0,0 +1,74 @@ + + + diff --git a/assets/js/components/Config/Messaging/utils.ts b/assets/js/components/Config/Messaging/utils.ts new file mode 100644 index 000000000..9996d36f8 --- /dev/null +++ b/assets/js/components/Config/Messaging/utils.ts @@ -0,0 +1,3 @@ +export function capitalize(str: string): string { + return str.charAt(0).toUpperCase() + str.slice(1); +} diff --git a/assets/js/components/Config/MessagingModal.vue b/assets/js/components/Config/MessagingModal.vue deleted file mode 100644 index 69dcaa7f6..000000000 --- a/assets/js/components/Config/MessagingModal.vue +++ /dev/null @@ -1,26 +0,0 @@ - - - diff --git a/assets/js/components/Config/PropertyField.vue b/assets/js/components/Config/PropertyField.vue index abaa81940..7398c52ae 100644 --- a/assets/js/components/Config/PropertyField.vue +++ b/assets/js/components/Config/PropertyField.vue @@ -13,6 +13,7 @@ :class="selectMode ? 'btn-check' : 'd-none'" :name="property" :value="key" + :disabled="disabled" @click="toggleSelectMode" />