diff --git a/assets/css/app.css b/assets/css/app.css
index 4bf4818f7..3511d755b 100644
--- a/assets/css/app.css
+++ b/assets/css/app.css
@@ -78,6 +78,7 @@
--evcc-accent2: var(--evcc-dark-green);
--evcc-accent3: var(--evcc-darker-green);
--bs-primary: var(--evcc-dark-green);
+ --bs-border-color-translucent: rgba(255, 255, 255, 0.175);
}
html {
diff --git a/assets/js/components/Energyflow/Energyflow.vue b/assets/js/components/Energyflow/Energyflow.vue
index b5317d08e..c4bac2732 100644
--- a/assets/js/components/Energyflow/Energyflow.vue
+++ b/assets/js/components/Energyflow/Energyflow.vue
@@ -2,6 +2,7 @@
@@ -78,6 +79,7 @@
:details="batterySoc"
:detailsFmt="batteryFmt"
detailsClickable
+ data-testid="energyflow-entry-batterydischarge"
@details-clicked="openBatterySettingsModal"
/>
@@ -157,8 +160,6 @@
-
-
@@ -167,13 +168,12 @@ import "@h2d2/shopicons/es/filled/square";
import Modal from "bootstrap/js/dist/modal";
import Visualization from "./Visualization.vue";
import EnergyflowEntry from "./EnergyflowEntry.vue";
-import GridSettingsModal from "../GridSettingsModal.vue";
import formatter from "../../mixins/formatter";
import AnimatedNumber from "../AnimatedNumber.vue";
import settings from "../../settings";
-import { CO2_TYPE, PRICE_DYNAMIC_TYPE, PRICE_FORECAST_TYPE } from "../../units";
+import { CO2_TYPE } from "../../units";
import collector from "../../mixins/collector";
-import BatterySettingsModal from "../BatterySettingsModal.vue";
+import gridModalAvailable from "../../utils/gridModalAvailable";
export default {
name: "Energyflow",
@@ -181,8 +181,6 @@ export default {
Visualization,
EnergyflowEntry,
AnimatedNumber,
- GridSettingsModal,
- BatterySettingsModal,
},
mixins: [formatter, collector],
props: {
@@ -217,8 +215,8 @@ export default {
return { detailsOpen: false, detailsCompleteHeight: null, gridSettingsModal: null };
},
computed: {
- smartCostAvailable: function () {
- return [CO2_TYPE, PRICE_DYNAMIC_TYPE, PRICE_FORECAST_TYPE].includes(this.smartCostType);
+ gridModalAvailable: function () {
+ return gridModalAvailable(this.smartCostType);
},
gridImport: function () {
return Math.max(0, this.gridPower);
@@ -288,27 +286,15 @@ export default {
batteryFmt() {
return (soc) => `${Math.round(soc)}%`;
},
- gridSettings() {
- return this.collectProps(GridSettingsModal);
- },
- batterySettings() {
- return this.collectProps(BatterySettingsModal);
- },
co2Available() {
return this.smartCostType === CO2_TYPE;
},
},
mounted() {
- this.gridSettingsModal = Modal.getOrCreateInstance(
- document.querySelector("#gridSettingsModal")
- );
- this.batterySettingsModal = Modal.getOrCreateInstance(
- document.querySelector("#batterySettingsModal")
- );
window.addEventListener("resize", this.updateHeight);
// height must be calculated in case of initially open details
if (settings.energyflowDetails) {
- setTimeout(this.toggleDetails, 50);
+ setTimeout(this.toggleDetails, 100);
}
},
unmounted() {
@@ -349,10 +335,14 @@ export default {
this.detailsCompleteHeight = this.$refs.detailsInner.offsetHeight;
},
openGridSettingsModal() {
- this.gridSettingsModal.show();
+ const modal = Modal.getOrCreateInstance(document.getElementById("gridSettingsModal"));
+ modal.show();
},
openBatterySettingsModal() {
- this.batterySettingsModal.show();
+ const modal = Modal.getOrCreateInstance(
+ document.getElementById("batterySettingsModal")
+ );
+ modal.show();
},
},
};
diff --git a/assets/js/components/Energyflow/EnergyflowEntry.vue b/assets/js/components/Energyflow/EnergyflowEntry.vue
index 33b3bff3d..0a055aef4 100644
--- a/assets/js/components/Energyflow/EnergyflowEntry.vue
+++ b/assets/js/components/Energyflow/EnergyflowEntry.vue
@@ -13,6 +13,7 @@
ref="details"
class="fw-normal"
:class="{ 'text-decoration-underline': detailsClickable }"
+ data-testid="energyflow-entry-details"
data-bs-toggle="tooltip"
:tabindex="detailsClickable ? 0 : undefined"
@click="detailsClicked"
diff --git a/assets/js/components/TopNavigation.vue b/assets/js/components/TopNavigation.vue
index 4783087bf..9ba99d7be 100644
--- a/assets/js/components/TopNavigation.vue
+++ b/assets/js/components/TopNavigation.vue
@@ -26,18 +26,32 @@
{{ $t("header.sessions") }}
+
+
+
+
+
+
+
- Configuration 🧪
+
+ Device Configuration 🧪
+
+
@@ -73,8 +87,6 @@
-
-
@@ -85,15 +97,13 @@ import "@h2d2/shopicons/es/regular/gift";
import "@h2d2/shopicons/es/regular/moonstars";
import "@h2d2/shopicons/es/regular/menu";
import "@h2d2/shopicons/es/regular/newtab";
-import GlobalSettingsModal from "./GlobalSettingsModal.vue";
-import HelpModal from "./HelpModal.vue";
import collector from "../mixins/collector";
+import gridModalAvailable from "../utils/gridModalAvailable";
import baseAPI from "../baseapi";
export default {
name: "TopNavigation",
- components: { GlobalSettingsModal, HelpModal },
mixins: [collector],
props: {
vehicleLogins: {
@@ -104,11 +114,10 @@ export default {
},
sponsor: String,
sponsorTokenExpires: Number,
+ batteryConfigured: Boolean,
+ smartCostType: String,
},
computed: {
- globalSettingsModalProps: function () {
- return this.collectProps(GlobalSettingsModal);
- },
logoutCount() {
return this.providerLogins.filter((login) => !login.loggedIn).length;
},
@@ -126,6 +135,12 @@ export default {
showBadge() {
return this.loginRequired || this.sponsorTokenExpires;
},
+ batteryModalAvailable() {
+ return this.batteryConfigured;
+ },
+ gridModalAvailable: function () {
+ return gridModalAvailable(this.smartCostType);
+ },
},
mounted() {
const $el = document.getElementById("topNavigatonDropdown");
@@ -155,6 +170,16 @@ export default {
const modal = Modal.getOrCreateInstance(document.getElementById("helpModal"));
modal.show();
},
+ openBatterySettingsModal() {
+ const modal = Modal.getOrCreateInstance(
+ document.getElementById("batterySettingsModal")
+ );
+ modal.show();
+ },
+ openGridSettingsModal() {
+ const modal = Modal.getOrCreateInstance(document.getElementById("gridSettingsModal"));
+ modal.show();
+ },
},
};
diff --git a/assets/js/mixins/collector.js b/assets/js/mixins/collector.js
index b84b893d0..1a3b1bef5 100644
--- a/assets/js/mixins/collector.js
+++ b/assets/js/mixins/collector.js
@@ -1,9 +1,14 @@
export default {
methods: {
// collect all target component properties from current instance
- collectProps: function (component) {
+ collectProps: function (component, state) {
let data = {};
for (var p in component.props) {
+ // check in optional state
+ if (state && p in state) {
+ data[p] = state[p];
+ }
+ // check in current instance
if (p in this) {
data[p] = this[p];
}
diff --git a/assets/js/utils/gridModalAvailable.js b/assets/js/utils/gridModalAvailable.js
new file mode 100644
index 000000000..a3d02435e
--- /dev/null
+++ b/assets/js/utils/gridModalAvailable.js
@@ -0,0 +1,5 @@
+import { CO2_TYPE, PRICE_DYNAMIC_TYPE, PRICE_FORECAST_TYPE } from "../units";
+
+export default function (smartCostType) {
+ return [CO2_TYPE, PRICE_DYNAMIC_TYPE, PRICE_FORECAST_TYPE].includes(smartCostType);
+}
diff --git a/assets/js/views/App.vue b/assets/js/views/App.vue
index b99c7bc55..1074f6b0f 100644
--- a/assets/js/views/App.vue
+++ b/assets/js/views/App.vue
@@ -1,14 +1,27 @@
+
+
+
+
+