Config UI: streamline loadpoint creation and unify wording (#31658)
This commit is contained in:
parent
999bed78c5
commit
b900237a8b
15 changed files with 246 additions and 91 deletions
31
assets/js/components/Config/CreateFlowStatus.vue
Normal file
31
assets/js/components/Config/CreateFlowStatus.vue
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<template>
|
||||
<div v-if="inProgress" class="d-flex align-items-start gap-3 py-2">
|
||||
<div class="spinner-border flex-shrink-0 text-gray" role="status" aria-hidden="true"></div>
|
||||
<p class="mb-0 pt-1 text-gray">{{ creatingText }}</p>
|
||||
</div>
|
||||
<div v-else class="d-flex flex-column gap-4">
|
||||
<div class="d-flex align-items-start gap-3">
|
||||
<SuccessCheck class="flex-shrink-0" />
|
||||
<p class="mb-0 pt-2">{{ successText }}</p>
|
||||
</div>
|
||||
<div class="d-flex align-items-center justify-content-between gap-3">
|
||||
<slot name="actions" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import SuccessCheck from "../Helper/SuccessCheck.vue";
|
||||
|
||||
// Reusable creating -> created status for device creation flows.
|
||||
export default defineComponent({
|
||||
name: "CreateFlowStatus",
|
||||
components: { SuccessCheck },
|
||||
props: {
|
||||
inProgress: Boolean,
|
||||
creatingText: String,
|
||||
successText: String,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
@ -9,7 +9,22 @@
|
|||
@close="onClose"
|
||||
@dismiss="onDismiss"
|
||||
>
|
||||
<div v-if="!loadpointType" class="d-flex flex-column gap-4">
|
||||
<CreateFlowStatus
|
||||
v-if="autoCreate"
|
||||
:in-progress="autoCreateInProgress"
|
||||
:creating-text="$t(`config.loadpoint.creating.${loadpointType}`)"
|
||||
:success-text="$t('config.loadpoint.created', { name: values.title })"
|
||||
>
|
||||
<template #actions>
|
||||
<a href="#" @click.prevent="autoCreate = false">
|
||||
{{ $t("config.loadpoint.advancedConfig") }}
|
||||
</a>
|
||||
<button type="button" class="btn btn-primary" @click="finish">
|
||||
{{ $t("config.general.close") }}
|
||||
</button>
|
||||
</template>
|
||||
</CreateFlowStatus>
|
||||
<div v-else-if="!loadpointType" class="d-flex flex-column gap-4">
|
||||
<NewDeviceButton
|
||||
v-for="t in typeChoices"
|
||||
:key="t"
|
||||
|
|
@ -90,13 +105,7 @@
|
|||
</div>
|
||||
|
||||
<div v-if="values.charger || !isNew">
|
||||
<p v-if="isNew && !showAllSettings" class="mt-4 mb-0 text-muted">
|
||||
{{ $t("config.loadpoint.defaultsHint") }}
|
||||
<a href="#" @click.prevent="showAllSettings = true">
|
||||
{{ $t("config.loadpoint.defaultsHintLink") }} </a
|
||||
>.
|
||||
</p>
|
||||
<div class="collapsible-wrapper" :class="{ open: !isNew || showAllSettings }">
|
||||
<div class="collapsible-wrapper" :class="{ open: !isNew }">
|
||||
<div class="collapsible-content">
|
||||
<h6 class="mt-4">{{ $t("config.loadpoint.chargingTitle") }}</h6>
|
||||
|
||||
|
|
@ -625,10 +634,12 @@ import api from "@/api";
|
|||
import GenericModal from "../Helper/GenericModal.vue";
|
||||
import deepClone from "@/utils/deepClone";
|
||||
import deepEqual from "@/utils/deepEqual";
|
||||
import sleep from "@/utils/sleep";
|
||||
import formatter, { POWER_UNIT } from "@/mixins/formatter";
|
||||
import DeviceRefBox from "./DeviceRefBox.vue";
|
||||
import NewDeviceButton from "./NewDeviceButton.vue";
|
||||
import InvalidReferenceAlert from "./InvalidReferenceAlert.vue";
|
||||
import CreateFlowStatus from "./CreateFlowStatus.vue";
|
||||
import { handleError, customChargerName, createDeviceUtils } from "./DeviceModal";
|
||||
import { getModal, openModal, replaceModal, closeModal } from "@/configModal";
|
||||
import {
|
||||
|
|
@ -688,6 +699,7 @@ export default {
|
|||
DeviceRefBox,
|
||||
NewDeviceButton,
|
||||
InvalidReferenceAlert,
|
||||
CreateFlowStatus,
|
||||
},
|
||||
mixins: [formatter],
|
||||
props: {
|
||||
|
|
@ -706,12 +718,12 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
isModalVisible: false,
|
||||
showAllSettings: false,
|
||||
saving: false,
|
||||
values: deepClone(defaultValues) as ConfigLoadpoint,
|
||||
chargerPower: "11kw",
|
||||
solarMode: "default",
|
||||
created: false,
|
||||
autoCreate: false,
|
||||
autoCreateInProgress: false,
|
||||
tab: "solar",
|
||||
powerUnit: POWER_UNIT,
|
||||
};
|
||||
|
|
@ -724,7 +736,10 @@ export default {
|
|||
return getModal("loadpoint")?.type as LoadpointType | undefined;
|
||||
},
|
||||
modalTitle() {
|
||||
if (this.isNew) {
|
||||
if (this.autoCreate && !this.autoCreateInProgress) {
|
||||
return this.$t(`config.loadpoint.createdTitle.${this.loadpointType}`);
|
||||
}
|
||||
if (this.isNew || this.autoCreate) {
|
||||
return this.$t(`config.loadpoint.titleAdd.${this.loadpointType || "unknown"}`);
|
||||
}
|
||||
return this.$t(`config.loadpoint.titleEdit.${this.loadpointType || "unknown"}`);
|
||||
|
|
@ -751,24 +766,24 @@ export default {
|
|||
},
|
||||
chargerStatus() {
|
||||
if (!this.chargerValues || !this.values.charger) {
|
||||
return {};
|
||||
return null;
|
||||
}
|
||||
return this.chargerValues[this.values.charger] || {};
|
||||
return this.chargerValues[this.values.charger] || null;
|
||||
},
|
||||
chargerSupports1p3p() {
|
||||
return this.chargerStatus.phases1p3p?.value || false;
|
||||
return this.chargerStatus?.phases1p3p?.value || false;
|
||||
},
|
||||
chargerIsSinglePhase() {
|
||||
return this.chargerStatus.singlePhase?.value || false;
|
||||
return this.chargerStatus?.singlePhase?.value || false;
|
||||
},
|
||||
chargerIsIntegratedDevice() {
|
||||
return this.chargerStatus.integratedDevice?.value || false;
|
||||
return this.chargerStatus?.integratedDevice?.value || false;
|
||||
},
|
||||
chargerIsSwitchDevice() {
|
||||
return this.chargerStatus.switchDevice?.value || false;
|
||||
return this.chargerStatus?.switchDevice?.value || false;
|
||||
},
|
||||
chargerIsHeating() {
|
||||
return this.chargerStatus.heating?.value === true;
|
||||
return this.chargerStatus?.heating?.value === true;
|
||||
},
|
||||
meterTitle() {
|
||||
const name = this.values.meter;
|
||||
|
|
@ -857,6 +872,12 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
id(newId) {
|
||||
// replaceModal swaps the id in place (after create) without a remount
|
||||
if (this.isModalVisible && newId !== undefined && this.values?.id !== newId) {
|
||||
this.loadConfiguration();
|
||||
}
|
||||
},
|
||||
chargerPower(value) {
|
||||
if (value === "11kw") {
|
||||
this.values.minCurrent = 6;
|
||||
|
|
@ -881,8 +902,8 @@ export default {
|
|||
methods: {
|
||||
reset() {
|
||||
this.values = deepClone(defaultValues);
|
||||
this.created = false;
|
||||
this.showAllSettings = false;
|
||||
this.autoCreate = false;
|
||||
this.autoCreateInProgress = false;
|
||||
this.updatePhases();
|
||||
},
|
||||
async loadConfiguration() {
|
||||
|
|
@ -922,18 +943,30 @@ export default {
|
|||
}
|
||||
},
|
||||
async create() {
|
||||
this.saving = true;
|
||||
this.autoCreate = true;
|
||||
this.autoCreateInProgress = true;
|
||||
await sleep(1000); // ux pause
|
||||
try {
|
||||
await api.post("config/loadpoints", this.values);
|
||||
this.created = true;
|
||||
this.emitChanged("added");
|
||||
// the created response has no id to compare against on next open, so
|
||||
// reset explicitly instead of relying on the isModalVisible watcher
|
||||
this.reset();
|
||||
for (let i = 0; !this.chargerStatus && i < 100; i++) {
|
||||
await sleep(50);
|
||||
}
|
||||
const res = await api.post("config/loadpoints", this.values);
|
||||
this.$emit("changed", { action: "added" });
|
||||
// edit mode of the newly loadpoint
|
||||
replaceModal("loadpoint", {
|
||||
id: res.data?.id,
|
||||
type: this.loadpointType || undefined,
|
||||
});
|
||||
this.autoCreateInProgress = false;
|
||||
} catch (e) {
|
||||
this.autoCreate = false;
|
||||
this.autoCreateInProgress = false;
|
||||
handleError(e, "create failed");
|
||||
}
|
||||
this.saving = false;
|
||||
},
|
||||
async finish() {
|
||||
await closeModal({ action: "added" });
|
||||
this.reset();
|
||||
},
|
||||
onOpen() {
|
||||
this.isModalVisible = true;
|
||||
|
|
@ -942,12 +975,17 @@ export default {
|
|||
this.isModalVisible = false;
|
||||
},
|
||||
async onDismiss() {
|
||||
if (!this.values.id && !this.created) {
|
||||
// closeModal already cleared the route id, so check values.id, not isNew
|
||||
if (!this.values.id && !this.autoCreate) {
|
||||
await this.cleanupDevice("charger", this.values.charger, this.chargers);
|
||||
await this.cleanupDevice("meter", this.values.meter, this.meters);
|
||||
this.$emit("dismissed");
|
||||
this.reset();
|
||||
return;
|
||||
}
|
||||
// keep values so reopening the same loadpoint stays populated
|
||||
this.autoCreate = false;
|
||||
this.autoCreateInProgress = false;
|
||||
},
|
||||
async cleanupDevice(type: DeviceType, name: string, list: { name: string; id: number }[]) {
|
||||
const id = list.find((d) => d.name === name)?.id;
|
||||
|
|
@ -965,7 +1003,11 @@ export default {
|
|||
type: this.loadpointType || undefined,
|
||||
});
|
||||
if (result.action === "added" && result.name) {
|
||||
const instantCreate = this.isNew && !this.values.charger;
|
||||
this.values.charger = result.name;
|
||||
if (instantCreate) {
|
||||
await this.create();
|
||||
}
|
||||
} else if (result.action === "removed") {
|
||||
this.values.charger = "";
|
||||
}
|
||||
|
|
|
|||
38
assets/js/components/Helper/SuccessCheck.vue
Normal file
38
assets/js/components/Helper/SuccessCheck.vue
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<template>
|
||||
<span class="successCheck">
|
||||
<shopicon-regular-checkmark></shopicon-regular-checkmark>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import "@h2d2/shopicons/es/regular/checkmark";
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "SuccessCheck",
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.successCheck {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
border-radius: 50%;
|
||||
background: var(--evcc-green);
|
||||
color: var(--evcc-darkest-green);
|
||||
animation: successCheckIn var(--evcc-transition-fast, 250ms) ease-in both;
|
||||
}
|
||||
@keyframes successCheckIn {
|
||||
from {
|
||||
transform: scale(0.5);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
34
i18n/de.json
34
i18n/de.json
|
|
@ -143,16 +143,16 @@
|
|||
"template": "Hersteller",
|
||||
"titleAdd": {
|
||||
"charging": "Wallbox hinzufügen",
|
||||
"heating": "Heizung hinzufügen"
|
||||
"heating": "Heizgerät hinzufügen"
|
||||
},
|
||||
"titleEdit": {
|
||||
"charging": "Wallbox bearbeiten",
|
||||
"heating": "Heizung bearbeiten"
|
||||
"heating": "Heizgerät bearbeiten"
|
||||
},
|
||||
"type": {
|
||||
"custom": {
|
||||
"charging": "Benutzerdefinierte Wallbox",
|
||||
"heating": "Benutzerdefinierte Heizung"
|
||||
"heating": "Benutzerdefiniertes Heizgerät"
|
||||
},
|
||||
"heatpump": "Benutzerdefinierte Wärmepumpe",
|
||||
"sgready": "Benutzerdefinierte Wärmepumpe (sg-ready über Plugins)",
|
||||
|
|
@ -396,17 +396,18 @@
|
|||
"loadpoint": {
|
||||
"addCharger": {
|
||||
"charging": "Wallbox hinzufügen",
|
||||
"heating": "Heizung hinzufügen"
|
||||
"heating": "Heizgerät hinzufügen"
|
||||
},
|
||||
"addMeter": "Zusätzlichen Energiezähler hinzufügen",
|
||||
"advancedConfig": "Erweiterte Konfiguration",
|
||||
"cancel": "Abbrechen",
|
||||
"chargerError": {
|
||||
"charging": "Wallbox muss konfiguriert sein.",
|
||||
"heating": "Heizung muss konfiguriert sein."
|
||||
"heating": "Heizgerät muss konfiguriert sein."
|
||||
},
|
||||
"chargerLabel": {
|
||||
"charging": "Wallbox",
|
||||
"heating": "Heizung"
|
||||
"heating": "Heizgerät"
|
||||
},
|
||||
"chargerPower11kw": "11 kW",
|
||||
"chargerPower11kwHelp": "Verwendet einen Strombereich von 6 bis 16 A.",
|
||||
|
|
@ -420,14 +421,21 @@
|
|||
"circuitInvalid": "Stromkreis existiert nicht",
|
||||
"circuitLabel": "Stromkreis",
|
||||
"circuitUnassigned": "nicht zugewiesen",
|
||||
"created": "„{name}“ wurde angelegt und verwendet sinnvolle Standardwerte.",
|
||||
"createdTitle": {
|
||||
"charging": "Ladepunkt erstellt",
|
||||
"heating": "Heizung erstellt"
|
||||
},
|
||||
"creating": {
|
||||
"charging": "Wallbox gespeichert. Ladepunkt wird erstellt …",
|
||||
"heating": "Heizgerät gespeichert. Heizung wird erstellt …"
|
||||
},
|
||||
"defaultModeHelp": {
|
||||
"charging": "Lademodus beim Anschließen des Fahrzeugs.",
|
||||
"heating": "Wird beim Systemstart gesetzt."
|
||||
},
|
||||
"defaultModeHelpKeep": "Zuletzt ausgewählter Modus wird beibehalten.",
|
||||
"defaultModeLabel": "Standard-Modus",
|
||||
"defaultsHint": "Standardmodus, PV-Überschussverhalten und elektrische Details verwenden sinnvolle Standardwerte.",
|
||||
"defaultsHintLink": "Einstellungen anpassen",
|
||||
"delete": "Löschen",
|
||||
"electricalSubtitle": "Im Zweifelsfall Elektriker fragen.",
|
||||
"electricalTitle": "Elektrik",
|
||||
|
|
@ -444,7 +452,7 @@
|
|||
"noVehicles": "Keine Fahrzeuge konfiguriert.",
|
||||
"option": {
|
||||
"charging": "Ladepunkt hinzufügen",
|
||||
"heating": "Heizungsgerät hinzufügen"
|
||||
"heating": "Heizung hinzufügen"
|
||||
},
|
||||
"phases1p": "1-phasig",
|
||||
"phases3p": "3-phasig",
|
||||
|
|
@ -485,12 +493,12 @@
|
|||
"titleAdd": {
|
||||
"charging": "Ladepunkt hinzufügen",
|
||||
"heating": "Heizung hinzufügen",
|
||||
"unknown": "Wallbox oder Heizung hinzufügen"
|
||||
"unknown": "Ladepunkt oder Heizung hinzufügen"
|
||||
},
|
||||
"titleEdit": {
|
||||
"charging": "Ladepunkt bearbeiten",
|
||||
"heating": "Heizung bearbeiten",
|
||||
"unknown": "Wallbox oder Heizung bearbeiten"
|
||||
"unknown": "Ladepunkt oder Heizung bearbeiten"
|
||||
},
|
||||
"titleExample": {
|
||||
"charging": "Garage, Carport, etc.",
|
||||
|
|
@ -508,7 +516,7 @@
|
|||
"addAdditional": "Zusätzlichen Zähler hinzufügen",
|
||||
"addConsumer": "Verbraucher hinzufügen",
|
||||
"addGrid": "Netzzähler hinzufügen",
|
||||
"addLoadpoint": "Wallbox oder Heizung hinzufügen",
|
||||
"addLoadpoint": "Ladepunkt oder Heizung hinzufügen",
|
||||
"addPvBattery": "PV oder Speicher hinzufügen",
|
||||
"addTariffs": "Tarife hinzufügen",
|
||||
"addVehicle": "Fahrzeug hinzufügen",
|
||||
|
|
@ -801,7 +809,7 @@
|
|||
"general": "Allgemein",
|
||||
"grid": "Netzanschluss",
|
||||
"integrations": "Integrationen",
|
||||
"loadpoints": "Laden & Heizen",
|
||||
"loadpoints": "Ladepunkte & Heizungen",
|
||||
"meter": "PV & Batterie",
|
||||
"services": "Dienste",
|
||||
"system": "System",
|
||||
|
|
|
|||
38
i18n/en.json
38
i18n/en.json
|
|
@ -143,16 +143,16 @@
|
|||
"template": "Manufacturer",
|
||||
"titleAdd": {
|
||||
"charging": "Add Charger",
|
||||
"heating": "Add Heater"
|
||||
"heating": "Add Heating Device"
|
||||
},
|
||||
"titleEdit": {
|
||||
"charging": "Edit Charger",
|
||||
"heating": "Edit Heater"
|
||||
"heating": "Edit Heating Device"
|
||||
},
|
||||
"type": {
|
||||
"custom": {
|
||||
"charging": "User-defined charger",
|
||||
"heating": "User-defined heater"
|
||||
"heating": "User-defined heating device"
|
||||
},
|
||||
"heatpump": "User-defined heat pump",
|
||||
"sgready": "User-defined heat pump (sg-ready via plugins)",
|
||||
|
|
@ -396,17 +396,18 @@
|
|||
"loadpoint": {
|
||||
"addCharger": {
|
||||
"charging": "Add charger",
|
||||
"heating": "Add heater"
|
||||
"heating": "Add heating device"
|
||||
},
|
||||
"addMeter": "Add dedicated energy meter",
|
||||
"advancedConfig": "Advanced configuration",
|
||||
"cancel": "Cancel",
|
||||
"chargerError": {
|
||||
"charging": "Configuring a charger is required.",
|
||||
"heating": "Configuring a heater is required."
|
||||
"heating": "Configuring a heating device is required."
|
||||
},
|
||||
"chargerLabel": {
|
||||
"charging": "Charger",
|
||||
"heating": "Heater"
|
||||
"heating": "Heating device"
|
||||
},
|
||||
"chargerPower11kw": "11 kW",
|
||||
"chargerPower11kwHelp": "Will use a current range of 6 to 16 A.",
|
||||
|
|
@ -420,14 +421,21 @@
|
|||
"circuitInvalid": "Circuit does not exist",
|
||||
"circuitLabel": "Circuit",
|
||||
"circuitUnassigned": "unassigned",
|
||||
"created": "“{name}” was created and uses sensible defaults.",
|
||||
"createdTitle": {
|
||||
"charging": "Charging point created",
|
||||
"heating": "Heater created"
|
||||
},
|
||||
"creating": {
|
||||
"charging": "Charger saved. Creating charging point …",
|
||||
"heating": "Heating device saved. Creating heater …"
|
||||
},
|
||||
"defaultModeHelp": {
|
||||
"charging": "Charging mode when connecting the vehicle.",
|
||||
"heating": "Is set when on system start."
|
||||
},
|
||||
"defaultModeHelpKeep": "Keeps the last selected mode.",
|
||||
"defaultModeLabel": "Default mode",
|
||||
"defaultsHint": "Default mode, solar behaviour and electrical details use sensible defaults.",
|
||||
"defaultsHintLink": "Adjust settings",
|
||||
"delete": "Delete",
|
||||
"electricalSubtitle": "When in doubt, ask your electrician.",
|
||||
"electricalTitle": "Electrics",
|
||||
|
|
@ -444,7 +452,7 @@
|
|||
"noVehicles": "No vehicles are configured.",
|
||||
"option": {
|
||||
"charging": "Add charging point",
|
||||
"heating": "Add heating device"
|
||||
"heating": "Add heater"
|
||||
},
|
||||
"phases1p": "1-phase",
|
||||
"phases3p": "3-phase",
|
||||
|
|
@ -484,13 +492,13 @@
|
|||
"thresholdEnableLabel": "Enable grid power",
|
||||
"titleAdd": {
|
||||
"charging": "Add Charging Point",
|
||||
"heating": "Add Heating Device",
|
||||
"unknown": "Add Charger or Heater"
|
||||
"heating": "Add Heater",
|
||||
"unknown": "Add Charging Point or Heater"
|
||||
},
|
||||
"titleEdit": {
|
||||
"charging": "Edit Charging Point",
|
||||
"heating": "Edit Heating Device",
|
||||
"unknown": "Edit Charger or Heater"
|
||||
"heating": "Edit Heater",
|
||||
"unknown": "Edit Charging Point or Heater"
|
||||
},
|
||||
"titleExample": {
|
||||
"charging": "Garage, Carport, etc.",
|
||||
|
|
@ -508,7 +516,7 @@
|
|||
"addAdditional": "Add additional meter",
|
||||
"addConsumer": "Add consumer",
|
||||
"addGrid": "Add grid meter",
|
||||
"addLoadpoint": "Add charger or heater",
|
||||
"addLoadpoint": "Add charging point or heater",
|
||||
"addPvBattery": "Add solar or battery",
|
||||
"addTariffs": "Add tariffs",
|
||||
"addVehicle": "Add vehicle",
|
||||
|
|
@ -801,7 +809,7 @@
|
|||
"general": "General",
|
||||
"grid": "Grid",
|
||||
"integrations": "Integrations",
|
||||
"loadpoints": "Charging & Heating",
|
||||
"loadpoints": "Charging points & Heaters",
|
||||
"meter": "Solar & Battery",
|
||||
"services": "Services",
|
||||
"system": "System",
|
||||
|
|
|
|||
|
|
@ -189,7 +189,9 @@ func newLoadpointHandler() http.HandlerFunc {
|
|||
|
||||
setConfigDirty()
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
jsonWrite(w, struct {
|
||||
ID int `json:"id"`
|
||||
}{ID: conf.ID})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
expectModalVisible,
|
||||
newLoadpoint,
|
||||
addDemoCharger,
|
||||
finishLoadpoint,
|
||||
ChargerStatus,
|
||||
} from "./utils";
|
||||
test.use({ baseURL: baseUrl() });
|
||||
|
|
@ -120,9 +121,7 @@ test.describe("boost", async () => {
|
|||
await page.goto("/#/config");
|
||||
await newLoadpoint(page, "New Charger");
|
||||
await addDemoCharger(page, undefined, ChargerStatus.Connected);
|
||||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
await finishLoadpoint(page);
|
||||
|
||||
// restart evcc to apply new loadpoint
|
||||
await restart(CONFIG_BATTERY);
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ test.describe("circuit", async () => {
|
|||
|
||||
// add loadpoint and charger
|
||||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await page.getByRole("button", { name: "Add charger or heater" }).click();
|
||||
await page.getByRole("button", { name: "Add charging point or heater" }).click();
|
||||
await expectModalVisible(lpModal);
|
||||
await lpModal.getByRole("button", { name: "Add charging point" }).click();
|
||||
await lpModal.getByLabel("Title").fill("Carport");
|
||||
|
|
@ -69,6 +69,7 @@ test.describe("circuit", async () => {
|
|||
await expectModalVisible(lpModal);
|
||||
|
||||
// no load management, no circuits
|
||||
await lpModal.getByRole("link", { name: "Advanced configuration" }).click();
|
||||
await expect(lpModal.getByLabel("Circuit")).not.toBeVisible();
|
||||
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ test.describe("fatal config handling", async () => {
|
|||
await addDemoCharger(page);
|
||||
|
||||
// add shelly meter
|
||||
await lpModal.getByRole("link", { name: "Advanced configuration" }).click();
|
||||
await lpModal.getByRole("button", { name: "Add dedicated energy meter" }).click();
|
||||
const meterModal = page.getByTestId("meter-modal");
|
||||
await expectModalVisible(meterModal);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ test.describe("invalid references", async () => {
|
|||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await newLoadpoint(page, "Test Carport");
|
||||
await addDemoCharger(page);
|
||||
await lpModal.getByRole("link", { name: "Advanced configuration" }).click();
|
||||
|
||||
// Wait for circuit field to be available and assign to circuit main
|
||||
await expect(lpModal.getByLabel("Circuit")).toBeVisible();
|
||||
|
|
@ -118,6 +119,7 @@ test.describe("invalid references", async () => {
|
|||
// Create loadpoint with demo charger and assign vehicle
|
||||
await newLoadpoint(page, "Garage");
|
||||
await addDemoCharger(page);
|
||||
await lpModal.getByRole("link", { name: "Advanced configuration" }).click();
|
||||
await expect(lpModal.getByLabel("Default vehicle")).toBeVisible();
|
||||
await lpModal.getByLabel("Default vehicle").selectOption("Legacy Vehicle");
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
addDemoMeter,
|
||||
addVehicle,
|
||||
newLoadpoint,
|
||||
finishLoadpoint,
|
||||
} from "./utils";
|
||||
|
||||
const CONFIG_ONE_LP = "config-one-lp.evcc.yaml";
|
||||
|
|
@ -43,6 +44,12 @@ test.describe("charging loadpoint", async () => {
|
|||
await chargerModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(chargerModal);
|
||||
await expectModalVisible(lpModal);
|
||||
|
||||
// instant-create success screen
|
||||
await expect(lpModal.getByRole("heading", { name: "Charging point created" })).toBeVisible();
|
||||
await expect(lpModal).toContainText("“Solar Carport” was created and uses sensible defaults.");
|
||||
|
||||
await lpModal.getByRole("link", { name: "Advanced configuration" }).click();
|
||||
await expect(lpModal.getByLabel("Title")).toHaveValue("Solar Carport");
|
||||
// verify defaults
|
||||
await expect(lpModal.getByLabel("Default mode")).toHaveValue("");
|
||||
|
|
@ -146,8 +153,7 @@ test.describe("charging loadpoint", async () => {
|
|||
// add loadpoint via UI
|
||||
await newLoadpoint(page, "Garage");
|
||||
await addDemoCharger(page);
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
await finishLoadpoint(page);
|
||||
|
||||
// two loadpoints
|
||||
await expect(page.getByTestId("loadpoint")).toHaveCount(2);
|
||||
|
|
@ -203,8 +209,7 @@ test.describe("charging loadpoint", async () => {
|
|||
await chargerModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(chargerModal);
|
||||
await expectModalVisible(lpModal);
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
await finishLoadpoint(page);
|
||||
await expect(page.getByTestId("loadpoint")).toHaveCount(1);
|
||||
await expect(page.getByTestId("loadpoint")).toContainText("11.0 kW");
|
||||
|
||||
|
|
@ -221,8 +226,7 @@ test.describe("charging loadpoint", async () => {
|
|||
await chargerModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(chargerModal);
|
||||
await expectModalVisible(lpModal);
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
await finishLoadpoint(page);
|
||||
|
||||
// two loadpoints, each with its own distinct charger
|
||||
await expect(page.getByTestId("loadpoint")).toHaveCount(2);
|
||||
|
|
@ -251,6 +255,7 @@ test.describe("charging loadpoint", async () => {
|
|||
// add loadpoint > no vehicle option
|
||||
await newLoadpoint(page, LP_1);
|
||||
await addDemoCharger(page);
|
||||
await lpModal.getByRole("link", { name: "Advanced configuration" }).click();
|
||||
await expect(lpModal.getByLabel("Default vehicle")).not.toBeVisible();
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
|
|
@ -278,6 +283,7 @@ test.describe("charging loadpoint", async () => {
|
|||
// add second loadpoint
|
||||
await newLoadpoint(page, LP_2);
|
||||
await addDemoCharger(page);
|
||||
await lpModal.getByRole("link", { name: "Advanced configuration" }).click();
|
||||
await lpModal.getByLabel("Default vehicle").selectOption(VEHICLE_2);
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
|
|
@ -313,6 +319,7 @@ test.describe("charging loadpoint", async () => {
|
|||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await newLoadpoint(page, "Carport");
|
||||
await addDemoCharger(page);
|
||||
await lpModal.getByRole("link", { name: "Advanced configuration" }).click();
|
||||
await lpModal.getByLabel("Default mode").selectOption("---");
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
|
|
@ -356,10 +363,14 @@ test.describe("charging loadpoint", async () => {
|
|||
await addDemoCharger(page);
|
||||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await expectModalVisible(lpModal);
|
||||
await lpModal.getByRole("link", { name: "Advanced configuration" }).click();
|
||||
await lpModal.getByLabel("Default vehicle").selectOption("Porsche");
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
|
||||
await restart();
|
||||
await page.reload();
|
||||
|
||||
// delete vehicle
|
||||
await page.getByTestId("vehicle").nth(0).getByRole("button", { name: "edit" }).click();
|
||||
const vehicleModal = page.getByTestId("vehicle-modal");
|
||||
|
|
@ -385,8 +396,7 @@ test.describe("charging loadpoint", async () => {
|
|||
await newLoadpoint(page, "Garage");
|
||||
await addDemoCharger(page);
|
||||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
await finishLoadpoint(page);
|
||||
|
||||
// delete charger
|
||||
await page.getByTestId("loadpoint").getByRole("button", { name: "edit" }).click();
|
||||
|
|
@ -397,7 +407,9 @@ test.describe("charging loadpoint", async () => {
|
|||
await chargerModal.getByRole("button", { name: "Delete" }).click();
|
||||
await expectModalHidden(chargerModal);
|
||||
await expectModalVisible(lpModal);
|
||||
await expect(lpModal.getByRole("heading", { name: "Edit Charger or Heater" })).toBeVisible();
|
||||
await expect(
|
||||
lpModal.getByRole("heading", { name: "Edit Charging Point or Heater" })
|
||||
).toBeVisible();
|
||||
|
||||
// close modal before restarting
|
||||
await lpModal.getByRole("button", { name: "Close" }).click();
|
||||
|
|
@ -426,6 +438,8 @@ test.describe("charging loadpoint", async () => {
|
|||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
await restart();
|
||||
await page.reload();
|
||||
await expect(page.getByTestId("loadpoint")).toContainText("11.0 kW");
|
||||
|
||||
// delete charger
|
||||
|
|
@ -504,6 +518,7 @@ power:
|
|||
await expectModalVisible(lpModal);
|
||||
|
||||
// add user-defined meter
|
||||
await lpModal.getByRole("link", { name: "Advanced configuration" }).click();
|
||||
await lpModal.getByRole("button", { name: "Add dedicated energy meter" }).click();
|
||||
const meterModal = page.getByTestId("meter-modal");
|
||||
await expectModalVisible(meterModal);
|
||||
|
|
@ -585,6 +600,7 @@ power:
|
|||
await expectModalHidden(chargerModal);
|
||||
await expectModalVisible(lpModal);
|
||||
|
||||
await lpModal.getByRole("link", { name: "Advanced configuration" }).click();
|
||||
const modeSelect = lpModal.getByLabel("Default mode");
|
||||
await expect(modeSelect.getByRole("option", { name: "Solar", exact: true })).toHaveCount(1);
|
||||
await expect(modeSelect.getByRole("option", { name: "Min+Solar" })).toHaveCount(0);
|
||||
|
|
@ -611,10 +627,8 @@ test.describe("heating loadpoint", async () => {
|
|||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await addDemoCharger(page, LoadpointType.Heating);
|
||||
|
||||
// check heading
|
||||
await expect(lpModal.getByRole("heading", { name: "Add Heating Device" })).toBeVisible();
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
await expect(lpModal.getByRole("heading", { name: "Heater created" })).toBeVisible();
|
||||
await finishLoadpoint(page);
|
||||
|
||||
// restart edit
|
||||
await restart();
|
||||
|
|
@ -624,7 +638,7 @@ test.describe("heating loadpoint", async () => {
|
|||
await expect(lpEntry).toContainText("Wärmepumpe");
|
||||
await lpEntry.getByRole("button", { name: "edit" }).click();
|
||||
await expectModalVisible(lpModal);
|
||||
await expect(lpModal.getByRole("heading", { name: "Edit Heating Device" })).toBeVisible();
|
||||
await expect(lpModal.getByRole("heading", { name: "Edit Heater" })).toBeVisible();
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
|
||||
|
|
@ -650,12 +664,12 @@ test.describe("heating loadpoint", async () => {
|
|||
// add loadpoint
|
||||
await newLoadpoint(page, "Wärmepumpe", LoadpointType.Heating);
|
||||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await lpModal.getByRole("button", { name: "Add heater" }).click();
|
||||
await lpModal.getByRole("button", { name: "Add heating device" }).click();
|
||||
|
||||
// add user-defined heat pump
|
||||
const modal = page.getByTestId("charger-modal");
|
||||
await expectModalVisible(modal);
|
||||
await modal.getByLabel("Manufacturer").selectOption("User-defined heater");
|
||||
await modal.getByLabel("Manufacturer").selectOption("User-defined heating device");
|
||||
await modal.getByLabel("Manufacturer").selectOption("User-defined heat pump");
|
||||
await modal
|
||||
.getByLabel("Manufacturer")
|
||||
|
|
@ -706,8 +720,7 @@ temp:
|
|||
await expectModalVisible(lpModal);
|
||||
|
||||
// create
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
await finishLoadpoint(page);
|
||||
|
||||
await expect(page.getByTestId("loadpoint")).toHaveCount(1);
|
||||
const lpEntry = page.getByTestId("loadpoint").first();
|
||||
|
|
@ -724,8 +737,7 @@ temp:
|
|||
await newLoadpoint(page, "Wärmepumpe", LoadpointType.Heating);
|
||||
await addDemoCharger(page, LoadpointType.Heating);
|
||||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
await finishLoadpoint(page);
|
||||
|
||||
// delete heater
|
||||
await page.getByTestId("loadpoint").getByRole("button", { name: "edit" }).click();
|
||||
|
|
@ -736,9 +748,11 @@ temp:
|
|||
await chargerModal.getByRole("button", { name: "Delete" }).click();
|
||||
await expectModalHidden(chargerModal);
|
||||
await expectModalVisible(lpModal);
|
||||
await expect(lpModal.getByRole("heading", { name: "Edit Charger or Heater" })).toBeVisible();
|
||||
await expect(
|
||||
lpModal.getByRole("heading", { name: "Edit Charging Point or Heater" })
|
||||
).toBeVisible();
|
||||
await expect(lpModal.getByRole("button", { name: "Add charging point" })).toBeVisible();
|
||||
await expect(lpModal.getByRole("button", { name: "Add heating device" })).toBeVisible();
|
||||
await expect(lpModal.getByRole("button", { name: "Add heater" })).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ test.describe("ocpp", () => {
|
|||
await page.goto("/#/config");
|
||||
|
||||
// Open loadpoint modal and select charging point type
|
||||
await page.getByRole("button", { name: "Add charger or heater" }).click();
|
||||
await page.getByRole("button", { name: "Add charging point or heater" }).click();
|
||||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await expectModalVisible(lpModal);
|
||||
await lpModal.getByRole("button", { name: "Charging point" }).click();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { test, expect } from "@playwright/test";
|
||||
import { start, stop, restart, baseUrl } from "./evcc";
|
||||
import { expectModalHidden, expectModalVisible } from "./utils";
|
||||
import { expectModalHidden, expectModalVisible, finishLoadpoint } from "./utils";
|
||||
|
||||
test.use({ baseURL: baseUrl() });
|
||||
|
||||
|
|
@ -49,8 +49,7 @@ test.describe("onboarding", async () => {
|
|||
await chargerModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(chargerModal);
|
||||
await expectModalVisible(lpModal);
|
||||
await lpModal.getByRole("button", { name: "Save" }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
await finishLoadpoint(page);
|
||||
|
||||
await restart();
|
||||
|
||||
|
|
|
|||
|
|
@ -385,6 +385,7 @@ limit:
|
|||
await addDemoCharger(page);
|
||||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await expectModalVisible(lpModal);
|
||||
await lpModal.getByRole("link", { name: "Advanced configuration" }).click();
|
||||
const circuitOptions = lpModal.getByLabel("Circuit").getByRole("option");
|
||||
await expect(circuitOptions).toHaveText(["---", "House [main]"]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ export async function addDemoCharger(
|
|||
): Promise<void> {
|
||||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await lpModal
|
||||
.getByRole("button", { name: type === LoadpointType.Heating ? "Add heater" : "Add charger" })
|
||||
.getByRole("button", {
|
||||
name: type === LoadpointType.Heating ? "Add heating device" : "Add charger",
|
||||
})
|
||||
.click();
|
||||
|
||||
const modal = page.getByTestId("charger-modal");
|
||||
|
|
@ -69,6 +71,7 @@ export async function addDemoCharger(
|
|||
|
||||
export async function addDemoMeter(page: Page, power = "0"): Promise<void> {
|
||||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await lpModal.getByRole("link", { name: "Advanced configuration" }).click();
|
||||
await lpModal.getByRole("button", { name: "Add dedicated energy meter" }).click();
|
||||
|
||||
const modal = page.getByTestId("meter-modal");
|
||||
|
|
@ -96,16 +99,22 @@ export async function newLoadpoint(
|
|||
type: LoadpointType = LoadpointType.Charging
|
||||
): Promise<void> {
|
||||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await page.getByRole("button", { name: "Add charger or heater" }).click();
|
||||
await page.getByRole("button", { name: "Add charging point or heater" }).click();
|
||||
await expectModalVisible(lpModal);
|
||||
await lpModal
|
||||
.getByRole("button", {
|
||||
name: type === LoadpointType.Heating ? "Add heating device" : "Add charging point",
|
||||
name: type === LoadpointType.Heating ? "Add heater" : "Add charging point",
|
||||
})
|
||||
.click();
|
||||
await lpModal.getByLabel("Title").fill(title);
|
||||
}
|
||||
|
||||
export async function finishLoadpoint(page: Page): Promise<void> {
|
||||
const lpModal = page.getByTestId("loadpoint-modal");
|
||||
await lpModal.getByText("Close", { exact: true }).click();
|
||||
await expectModalHidden(lpModal);
|
||||
}
|
||||
|
||||
export async function dragElement(
|
||||
page: Page,
|
||||
sourceElement: Locator,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue