Make fatal banner dismissible (#29692)

This commit is contained in:
Michael Geers 2026-05-06 13:16:57 +02:00 • committed by GitHub
parent 42b5cb2b49
commit fd80b71475
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 48 additions and 15 deletions

View file

@ -38,26 +38,41 @@
</div>
<div
v-else-if="showError"
class="d-flex align-items-center container px-0 px-sm-4 justify-content-center flex-wrap gap-2"
class="d-flex align-items-center container px-0 px-sm-4 flex-wrap gap-2"
data-testid="fatal-error"
>
<shopicon-regular-car1
size="m"
class="fatal-icon flex-grow-0 flex-shrink-0 d-none d-sm-block"
></shopicon-regular-car1>
<div class="mx-3 mt-1">
<div>
<strong>
{{ $t("offline.configurationError") }}
</strong>
</div>
<div class="d-flex flex-column gap-1">
<div v-for="fatalText in fatalTexts" :key="fatalText" class="text-break">
{{ fatalText }}
<div class="d-flex align-items-center gap-4">
<shopicon-regular-car1
size="m"
class="fatal-icon flex-shrink-0 d-none d-sm-block"
></shopicon-regular-car1>
<div class="mt-1">
<div>
<strong>
{{ $t("offline.configurationError") }}
</strong>
</div>
<div class="d-flex flex-column gap-1">
<div
v-for="fatalText in fatalTexts"
:key="fatalText"
class="text-break"
>
{{ fatalText }}
</div>
</div>
</div>
</div>
<RestartButton class="ms-auto" error @restart="restart" />
<div class="ms-auto d-flex align-items-center gap-3">
<button
type="button"
class="btn btn-link btn-sm text-reset p-0"
@click="dismiss"
>
{{ $t("config.general.dismiss") }}
</button>
<RestartButton error @restart="restart" />
</div>
</div>
</div>
</div>
@ -69,6 +84,7 @@ import "@h2d2/shopicons/es/regular/car1";
import CloudOffline from "../MaterialIcon/CloudOffline.vue";
import RestartButton from "./RestartButton.vue";
import restart, { performRestart, restartComplete } from "@/restart";
import deepEqual from "@/utils/deepEqual";
import type { FatalError } from "@/types/evcc";
export default defineComponent({
@ -129,11 +145,19 @@ export default defineComponent({
this.dismissed = false;
}
},
fatal(next, prev) {
if (!deepEqual(next, prev)) {
this.dismissed = false;
}
},
},
methods: {
restart() {
performRestart();
},
dismiss() {
this.dismissed = true;
},
},
});
</script>

View file

@ -240,6 +240,7 @@
"customHelp": "Erstelle ein benutzerdefiniertes Gerät mit evcc's Plugin-System.",
"customOption": "Benutzerdefiniertes Gerät",
"delete": "Löschen",
"dismiss": "Ausblenden",
"docsLink": "Siehe Dokumentation.",
"dragHandle": "Verschieben",
"dragItem": "Verschiebbar: {title}",

View file

@ -240,6 +240,7 @@
"customHelp": "Create a user-defined device using evcc's plugin system.",
"customOption": "User-defined device",
"delete": "Delete",
"dismiss": "Dismiss",
"docsLink": "See documentation.",
"dragHandle": "Drag handle",
"dragItem": "Draggable: {title}",

View file

@ -35,6 +35,13 @@ test.describe("fatal config handling", async () => {
// remove meter
await expect(page.getByTestId("fatal-error")).toBeVisible();
// dismiss hides the banner; reload restores it while the error persists
await page.getByRole("button", { name: "Dismiss" }).click();
await expect(page.getByTestId("fatal-error")).not.toBeVisible();
await page.reload();
await expect(page.getByTestId("fatal-error")).toBeVisible();
await expect(page.getByTestId("pv")).toBeVisible();
await page.getByTestId("pv").getByRole("button", { name: "edit" }).click();
await expectModalVisible(meterModal);