Skip to content

Commit

Permalink
Merge branch 'master' into feat/loadpoint-config
Browse files Browse the repository at this point in the history
  • Loading branch information
naltatis committed Jul 28, 2024
2 parents 247e26a + c2b29a8 commit fb0e828
Show file tree
Hide file tree
Showing 40 changed files with 1,170 additions and 200 deletions.
1 change: 1 addition & 0 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ type Circuit interface {
SetTitle(string)
GetParent() Circuit
RegisterChild(child Circuit)
Wrap(parent Circuit) error
HasMeter() bool
GetMaxPower() float64
GetMaxCurrent() float64
Expand Down
14 changes: 14 additions & 0 deletions api/mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions assets/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,10 @@ a:hover {
--bs-btn-hover-border-color: var(--bs-gray-medium);
}

.btn-link:hover {
color: var(--bs-primary);
}

.dark .btn-outline-secondary {
--bs-btn-color: var(--bs-gray-bright);
--bs-btn-border-color: var(--bs-gray-bright);
Expand Down
19 changes: 15 additions & 4 deletions assets/js/components/ChargingPlan.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<div class="value m-0 d-block align-items-baseline justify-content-center">
<button class="value-button p-0" :class="buttonColor" @click="openModal">
<strong v-if="enabled">
<span class="targetTimeLabel"> {{ targetTimeLabel() }}</span>
<span class="targetTimeLabel"> {{ targetTimeLabel }}</span>
<div
class="extraValue text-nowrap"
:class="{ 'text-warning': planTimeUnreachable }"
Expand Down Expand Up @@ -106,6 +106,8 @@ import collector from "../mixins/collector";
import api from "../api";
import { optionStep, fmtEnergy } from "../utils/energyOptions";
const ONE_MINUTE = 60 * 1000;
export default {
name: "ChargingPlan",
components: { LabelAndValue, ChargingPlanSettings, ChargingPlanArrival },
Expand Down Expand Up @@ -140,6 +142,8 @@ export default {
modal: null,
isModalVisible: false,
activeTab: "departure",
targetTimeLabel: "",
interval: null,
};
},
computed: {
Expand Down Expand Up @@ -203,16 +207,24 @@ export default {
return `loadpoints/${this.id}/`;
},
},
watch: {
effectivePlanTime() {
this.updateTargetTimeLabel();
},
},
mounted() {
this.modal = Modal.getOrCreateInstance(this.$refs.modal);
this.$refs.modal.addEventListener("show.bs.modal", this.modalVisible);
this.$refs.modal.addEventListener("hidden.bs.modal", this.modalInvisible);
this.$refs.modal.addEventListener("hide.bs.modal", this.checkUnsavedOnClose);
this.interval = setInterval(this.updateTargetTimeLabel, ONE_MINUTE);
this.updateTargetTimeLabel();
},
unmounted() {
this.$refs.modal?.removeEventListener("show.bs.modal", this.modalVisible);
this.$refs.modal?.removeEventListener("hidden.bs.modal", this.modalInvisible);
this.$refs.modal?.removeEventListener("hide.bs.modal", this.checkUnsavedOnClose);
clearInterval(this.interval);
},
methods: {
checkUnsavedOnClose: function () {
Expand Down Expand Up @@ -241,10 +253,9 @@ export default {
}
this.modal.show();
},
// not computed because it needs to update over time
targetTimeLabel: function () {
updateTargetTimeLabel: function () {
const targetDate = new Date(this.effectivePlanTime);
return this.fmtAbsoluteDate(targetDate);
this.targetTimeLabel = this.fmtAbsoluteDate(targetDate);
},
showDeatureTab: function () {
this.activeTab = "departure";
Expand Down
1 change: 0 additions & 1 deletion assets/js/components/Config/CircuitsModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
docs="/docs/features/loadmanagement"
:defaultYaml="defaultYaml"
endpoint="/config/circuits"
size="md"
@changed="$emit('changed')"
/>
</template>
Expand Down
78 changes: 45 additions & 33 deletions assets/js/components/Config/MeterModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,26 +61,25 @@
:defaultPort="modbus.Port"
:capabilities="modbusCapabilities"
/>
<FormRow
v-for="param in templateParams"
:id="`meterParam${param.Name}`"
<PropertyEntry
v-for="param in normalParams"
:key="param.Name"
:optional="!param.Required"
:label="param.Description || `[${param.Name}]`"
:help="param.Description === param.Help ? undefined : param.Help"
:example="param.Example"
>
<PropertyField
:id="`meterParam${param.Name}`"
v-model="values[param.Name]"
:masked="param.Mask"
:property="param.Name"
:type="param.Type"
class="me-2"
:required="param.Required"
:validValues="param.ValidValues"
/>
</FormRow>
:id="`meterParam${param.Name}`"
v-bind="param"
v-model="values[param.Name]"
/>

<PropertyCollapsible>
<template v-if="advancedParams.length" #advanced>
<PropertyEntry
v-for="param in advancedParams"
:key="param.Name"
:id="`meterParam${param.Name}`"
v-bind="param"
v-model="values[param.Name]"
/>
</template>
</PropertyCollapsible>

<TestResult
v-if="templateName"
Expand Down Expand Up @@ -133,7 +132,8 @@

<script>
import FormRow from "./FormRow.vue";
import PropertyField from "./PropertyField.vue";
import PropertyEntry from "./PropertyEntry.vue";
import PropertyCollapsible from "./PropertyCollapsible.vue";
import TestResult from "./TestResult.vue";
import api from "../../api";
import test from "./mixins/test";
Expand All @@ -147,9 +147,19 @@ function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
const CUSTOM_FIELDS = ["usage", "modbus"];
export default {
name: "MeterModal",
components: { FormRow, PropertyField, Modbus, TestResult, NewDeviceButton, GenericModal },
components: {
FormRow,
PropertyEntry,
GenericModal,
Modbus,
TestResult,
NewDeviceButton,
PropertyCollapsible,
},
mixins: [test],
props: {
id: Number,
Expand Down Expand Up @@ -192,18 +202,20 @@ export default {
return this.products.filter((p) => p.group === "generic");
},
templateParams() {
const params = this.template?.Params || [];
return (
params
// deprecated fields
.filter((p) => !p.Deprecated)
// remove usage option
.filter((p) => p.Name !== "usage")
// remove modbus, handles separately
.filter((p) => p.Name !== "modbus")
// capacity only for battery meters
.filter((p) => this.meterType === "battery" || p.Name !== "capacity")
);
return (this.template?.Params || [])
.filter((p) => !CUSTOM_FIELDS.includes(p.Name))
.map((p) => {
if (this.meterType === "battery" && p.Name === "capacity") {
p.Advanced = false;
}
return p;
});
},
normalParams() {
return this.templateParams.filter((p) => !p.Advanced);
},
advancedParams() {
return this.templateParams.filter((p) => p.Advanced);
},
modbus() {
const params = this.template?.Params || [];
Expand Down
62 changes: 62 additions & 0 deletions assets/js/components/Config/PropertyCollapsible.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<template>
<div v-if="$slots.advanced || $slots.more">
<button
class="btn btn-link btn-sm text-gray px-0 border-0 d-flex align-items-center mb-2"
:class="open ? 'text-primary' : ''"
type="button"
@click="toggle"
>
<span v-if="open">Hide advanced settings</span>
<span v-else>Show advanced settings</span>
<DropdownIcon class="icon" :class="{ iconUp: open }" />
</button>

<Transition>
<div v-if="open" class="pt-2">
<slot name="advanced"></slot>
<hr v-if="$slots.advanced && $slots.more" class="my-5" />
<slot name="more"></slot>
</div>
</Transition>
</div>
</template>

<script>
import DropdownIcon from "../MaterialIcon/Dropdown.vue";
export default {
name: "PropertyCollapsible",
components: { DropdownIcon },
data() {
return { open: false };
},
methods: {
toggle() {
this.open = !this.open;
},
},
};
</script>
<style scoped>
.icon {
transform: rotate(0deg);
transition: transform var(--evcc-transition-medium) ease;
}
.iconUp {
transform: rotate(-180deg);
}
.v-enter-active,
.v-leave-active {
transition:
transform var(--evcc-transition-medium) ease,
opacity var(--evcc-transition-medium) ease;
transform: translateY(0);
}
.v-enter-from,
.v-leave-to {
opacity: 0;
transform: translateY(-0.5rem);
}
</style>
53 changes: 53 additions & 0 deletions assets/js/components/Config/PropertyEntry.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<template>
<FormRow
:id="id"
:optional="!Required"
:label="Description || `[${Name}]`"
:help="Description === Help ? undefined : Help"
:example="Example"
>
<PropertyField
:id="id"
v-model="value"
:masked="Mask"
:property="Name"
:type="Type"
class="me-2"
:required="Required"
:validValues="ValidValues"
/>
</FormRow>
</template>

<script>
import FormRow from "./FormRow.vue";
import PropertyField from "./PropertyField.vue";
export default {
name: "PropertyEntry",
components: { FormRow, PropertyField },
props: {
id: String,
Name: String,
Required: Boolean,
Description: String,
Help: String,
Example: String,
Type: String,
Mask: Boolean,
ValidValues: Array,
modelValue: [String, Number, Boolean, Object],
},
emits: ["update:modelValue"],
computed: {
value: {
get() {
return this.modelValue;
},
set(value) {
this.$emit("update:modelValue", value);
},
},
},
};
</script>
16 changes: 14 additions & 2 deletions assets/js/components/Config/PropertyField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
:step="step"
:placeholder="placeholder"
:required="required"
:autocomplete="masked ? 'off' : null"
/>
</template>

Expand Down Expand Up @@ -152,11 +153,14 @@ export default {
return this.property === "icon";
},
textarea() {
return ["accessToken", "refreshToken"].includes(this.property);
return ["accessToken", "refreshToken", "identifiers"].includes(this.property);
},
boolean() {
return this.type === "Bool";
},
array() {
return this.type === "StringList";
},
select() {
return this.validValues.length > 0;
},
Expand All @@ -182,7 +186,7 @@ export default {
get() {
// use first option if no value is set
if (this.selectOptions.length > 0 && !this.modelValue) {
return this.selectOptions[0].key;
return this.required ? this.selectOptions[0].key : "";
}
if (this.scale) {
Expand All @@ -193,6 +197,10 @@ export default {
return this.modelValue === true;
}
if (this.array) {
return Array.isArray(this.modelValue) ? this.modelValue.join("\n") : "";
}
return this.modelValue;
},
set(value) {
Expand All @@ -202,6 +210,10 @@ export default {
newValue = value / this.scale;
}
if (this.array) {
newValue = value ? value.split("\n") : [];
}
this.$emit("update:modelValue", newValue);
},
},
Expand Down
Loading

0 comments on commit fb0e828

Please sign in to comment.