Skip to content

Commit 1f806cb

Browse files
authored
Grid Charge UI: allow limit change when disabled (#27766)
1 parent 9b2b42a commit 1f806cb

File tree

5 files changed

+74
-48
lines changed

5 files changed

+74
-48
lines changed

assets/css/app.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,10 @@ small {
501501
overflow: hidden;
502502
text-overflow: ellipsis;
503503
}
504+
.form-select.disabled,
505+
.form-select:disabled {
506+
background-color: var(--bs-secondary-bg);
507+
}
504508

505509
.dark .dropdown-menu {
506510
box-shadow: 0 0 8px var(--evcc-background);
@@ -515,6 +519,7 @@ small {
515519
color: var(--bs-gray-medium) !important;
516520
}
517521

522+
.dark .form-select.disabled,
518523
.dark .form-select:disabled {
519524
opacity: 0.5;
520525
}

assets/js/components/Tariff/SmartCostLimit.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,12 @@ export default defineComponent({
7373
// Smart cost: charge when costs are below or equal to limit
7474
return value <= this.currentLimit;
7575
},
76-
async saveLimit(limit: number) {
76+
async saveLimit(limit: number, active: boolean) {
7777
// save last selected value to be suggest again when reactivating limit
7878
this.saveLastLimit(limit);
7979
80+
if (!active) return;
81+
8082
const url = this.isLoadpoint
8183
? `loadpoints/${this.loadpointId}/smartcostlimit`
8284
: "batterygridchargelimit";

assets/js/components/Tariff/SmartFeedInPriority.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,12 @@ export default defineComponent({
6565
// Smart feed-in priority: pause when rates are above or equal to limit
6666
return value >= this.currentLimit;
6767
},
68-
async saveLimit(limit: number) {
68+
async saveLimit(limit: number, active: boolean) {
6969
// save last selected value to be suggest again when reactivating limit
7070
this.saveLastLimit(limit);
7171
72+
if (!active) return;
73+
7274
const url = `loadpoints/${this.loadpointId}/smartfeedinprioritylimit`;
7375
await api.post(`${url}/${encodeURIComponent(limit)}`);
7476
},

assets/js/components/Tariff/SmartTariffBase.vue

Lines changed: 50 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
:id="formId"
2828
v-model.number="selectedLimit"
2929
class="form-select form-select-sm"
30-
:disabled="!active"
30+
:class="{ disabled: !active }"
3131
:aria-label="limitLabel"
3232
@change="changeLimit"
3333
>
@@ -74,7 +74,8 @@
7474
</div>
7575
<TariffChart
7676
v-if="rates.length"
77-
:slots="slots"
77+
:slots="chartSlots"
78+
:inactive="!active"
7879
@slot-hovered="slotHovered"
7980
@slot-selected="slotSelected"
8081
/>
@@ -205,42 +206,10 @@ export default defineComponent({
205206
return { min, max };
206207
},
207208
slots(): Slot[] {
208-
if (!this.rates?.length) {
209-
return [];
210-
}
211-
212-
const rates = this.rates;
213-
const quarterHour = 15 * 60 * 1000;
214-
215-
const base = new Date();
216-
base.setSeconds(0, 0);
217-
base.setMinutes(base.getMinutes() - (base.getMinutes() % 15));
218-
219-
return Array.from({ length: 96 * 4 }, (_, i) => {
220-
const start = new Date(base.getTime() + quarterHour * i);
221-
const end = new Date(start.getTime() + quarterHour);
222-
const value = this.findRateInRange(start, end, rates)?.value;
223-
const active =
224-
this.limitDirection === "below" &&
225-
this.currentLimit !== null &&
226-
value !== undefined &&
227-
value <= this.currentLimit;
228-
const warning =
229-
this.limitDirection === "above" &&
230-
this.currentLimit !== null &&
231-
value !== undefined &&
232-
value >= this.currentLimit;
233-
234-
return {
235-
day: this.weekdayShort(start),
236-
value,
237-
start,
238-
end,
239-
charging: active,
240-
selectable: value !== undefined,
241-
warning,
242-
};
243-
});
209+
return this.slotsForLimit(this.currentLimit);
210+
},
211+
chartSlots(): Slot[] {
212+
return this.slotsForLimit(this.currentLimit ?? this.selectedLimit);
244213
},
245214
totalSlots() {
246215
return this.slots.filter((s) => s.value !== undefined);
@@ -356,16 +325,53 @@ export default defineComponent({
356325
}
357326
return this.fmtPricePerKWh(value, this.currency, true);
358327
},
328+
slotsForLimit(limit: number | null): Slot[] {
329+
if (!this.rates?.length) {
330+
return [];
331+
}
332+
333+
const rates = this.rates;
334+
const quarterHour = 15 * 60 * 1000;
335+
336+
const base = new Date();
337+
base.setSeconds(0, 0);
338+
base.setMinutes(base.getMinutes() - (base.getMinutes() % 15));
339+
340+
return Array.from({ length: 96 * 4 }, (_, i) => {
341+
const start = new Date(base.getTime() + quarterHour * i);
342+
const end = new Date(start.getTime() + quarterHour);
343+
const value = this.findRateInRange(start, end, rates)?.value;
344+
const active =
345+
this.limitDirection === "below" &&
346+
limit !== null &&
347+
value !== undefined &&
348+
value <= limit;
349+
const warning =
350+
this.limitDirection === "above" &&
351+
limit !== null &&
352+
value !== undefined &&
353+
value >= limit;
354+
355+
return {
356+
day: this.weekdayShort(start),
357+
value,
358+
start,
359+
end,
360+
charging: active,
361+
selectable: value !== undefined,
362+
warning,
363+
};
364+
});
365+
},
359366
slotHovered(index: number) {
360367
this.activeIndex = index;
361368
},
362369
slotSelected(index: number) {
363-
const value = this.slots[index]?.value;
370+
const value = this.chartSlots[index]?.value;
364371
if (value !== undefined) {
365372
// 3 decimal precision
366373
const valueRounded = Math.ceil(value * 1000) / 1000;
367374
this.selectedLimit = valueRounded;
368-
this.active = true;
369375
this.saveLimit(valueRounded);
370376
}
371377
},
@@ -374,20 +380,19 @@ export default defineComponent({
374380
this.saveLimit(value);
375381
},
376382
toggleActive($event: Event) {
377-
const active = ($event.target as HTMLInputElement).checked;
378-
if (active) {
383+
this.active = ($event.target as HTMLInputElement).checked;
384+
if (this.active) {
379385
this.saveLimit(this.lastLimit);
380386
} else {
381387
this.resetLimit();
382388
}
383-
this.active = active;
384389
if (this.applyAll) {
385390
this.applyToAllVisible = true;
386391
}
387392
},
388393
saveLimit(limit: number) {
389-
this.$emit("save-limit", limit);
390-
if (this.applyAll) {
394+
this.$emit("save-limit", limit, this.active);
395+
if (this.applyAll && this.active) {
391396
this.applyToAllVisible = true;
392397
}
393398
},

assets/js/components/Tariff/TariffChart.vue

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
<template>
22
<div class="root position-relative">
3-
<div class="chart position-relative" :class="{ 'chart--with-target': targetText }">
3+
<div
4+
class="chart position-relative"
5+
:class="{ 'chart--with-target': targetText, inactive }"
6+
>
47
<div
58
v-for="(slot, index) in slots"
69
:key="`${slot.day}-${fmtHourMinute(slot.start)}`"
@@ -73,6 +76,7 @@ export default defineComponent({
7376
slots: { type: Array as PropType<Slot[]>, default: () => [] },
7477
targetText: [String, null],
7578
targetOffset: { type: Number, default: 0 },
79+
inactive: { type: Boolean, default: false },
7680
},
7781
emits: ["slot-hovered", "slot-selected"],
7882
data() {
@@ -282,4 +286,12 @@ export default defineComponent({
282286
.slot.faded {
283287
opacity: 0.33;
284288
}
289+
.chart.inactive .slot.active .slot-bar,
290+
.chart.inactive .slot.warning .slot-bar {
291+
background: var(--bs-gray-medium);
292+
}
293+
.chart.inactive .slot.active .slot-label,
294+
.chart.inactive .slot.warning .slot-label {
295+
color: var(--bs-gray-medium);
296+
}
285297
</style>

0 commit comments

Comments
 (0)