Setting up the connection is not the same as using it
The control card opened with the parts that get touched once — which charger, and where it lives on the network — and only then reached what gets used every day. Split in two: a connection card holding the picker, the address and the connected badge, then a control card holding the tiles and the buttons. The not-connected hint and the error line move up with the connection, since that is what they are about, and the control card simply does not appear until there is a connection to control over. That also retires the inner template that repeated the card's own condition. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
5547daa689
commit
bcc44da735
@@ -78,6 +78,7 @@
|
||||
},
|
||||
|
||||
"control": {
|
||||
"connectionTitle": "Laderforbindelse",
|
||||
"title": "Laderstyring",
|
||||
"connected": "Forbundet",
|
||||
"disconnected": "Offline",
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
"idleHint": "Plug in at a station to start a session."
|
||||
},
|
||||
"control": {
|
||||
"connectionTitle": "Charger connection",
|
||||
"title": "Charger control",
|
||||
"connected": "Connected",
|
||||
"disconnected": "Offline",
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
},
|
||||
|
||||
"control": {
|
||||
"connectionTitle": "Połączenie z ładowarką",
|
||||
"title": "Sterowanie ładowarką",
|
||||
"connected": "Połączono",
|
||||
"disconnected": "Offline",
|
||||
|
||||
@@ -729,7 +729,7 @@ onMounted(async () => {
|
||||
<div class="flex flex-col gap-4">
|
||||
<div v-if="ctlActive" class="dh-card p-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<p class="text-sm font-semibold text-strong">{{ t("charging.control.title") }}</p>
|
||||
<p class="text-sm font-semibold text-strong">{{ t("charging.control.connectionTitle") }}</p>
|
||||
<span class="dh-badge" :class="ctlConnected ? 'dh-badge-success' : 'dh-badge-warning'">
|
||||
{{ ctlConnected ? t("charging.control.connected") : t("charging.control.disconnected") }}
|
||||
</span>
|
||||
@@ -802,96 +802,102 @@ onMounted(async () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-if="ctlConnected">
|
||||
<div class="mt-3 grid grid-cols-2 gap-2">
|
||||
<div class="rounded-control bg-sunken px-3 py-2">
|
||||
<div class="data text-sm font-semibold text-strong">{{ ctlStatusLabel }}</div>
|
||||
<div class="text-[11px] text-muted">{{ t("charging.control.status") }}</div>
|
||||
</div>
|
||||
<div class="rounded-control bg-sunken px-3 py-2">
|
||||
<div class="data text-sm font-semibold text-strong">{{ ctlMeterKwh }} kWh</div>
|
||||
<div class="text-[11px] text-muted">{{ t("charging.control.meter") }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex gap-2">
|
||||
<button class="dh-btn dh-btn-primary grow" :disabled="ctlBusy === 'start'" @click="doAction('start')">
|
||||
{{ t("charging.control.start") }}
|
||||
</button>
|
||||
<button class="dh-btn dh-btn-ghost grow" :disabled="ctlBusy === 'stop'" @click="doAction('stop')">
|
||||
{{ t("charging.control.stop") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<label class="dh-label flex justify-between">
|
||||
<span>{{ t("charging.control.limit") }}</span><span class="data text-body">{{ limitAmps }} A</span>
|
||||
</label>
|
||||
<input v-model.number="limitAmps" type="range" min="6" max="32" step="1" class="w-full accent-[var(--accent)]" />
|
||||
<div class="mt-2 flex gap-2">
|
||||
<button class="dh-btn dh-btn-ghost grow" :disabled="ctlBusy === 'limit'" @click="doAction('limit', { amps: limitAmps })">
|
||||
{{ t("charging.control.applyLimit") }}
|
||||
</button>
|
||||
<!-- Clearing a limit is an OCPP command; the register map takes an
|
||||
explicit ceiling, so in Modbus mode there is nothing to clear to. -->
|
||||
<button
|
||||
v-if="!ctlIsModbus"
|
||||
class="dh-btn dh-btn-ghost grow"
|
||||
:disabled="ctlBusy === 'clear-limit'"
|
||||
@click="doAction('clear-limit')"
|
||||
>
|
||||
{{ t("charging.control.clearLimit") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Boost is a Modbus command, and lasts for the current session only. -->
|
||||
<button
|
||||
v-if="ctlIsModbus"
|
||||
class="dh-btn dh-btn-ghost mt-3 w-full"
|
||||
:disabled="ctlBusy === 'boost'"
|
||||
@click="doAction('boost', { on: true })"
|
||||
>
|
||||
{{ t("charging.control.boost") }}
|
||||
</button>
|
||||
|
||||
<!-- Reset reboots the charger over OCPP; the register map has no
|
||||
equivalent, so the button is not offered on the local path. -->
|
||||
<button
|
||||
v-if="!ctlIsModbus && !resetPrompt"
|
||||
class="dh-btn dh-btn-ghost mt-3 w-full"
|
||||
:disabled="ctlBusy === 'reset'"
|
||||
@click="askReset"
|
||||
>
|
||||
{{ t("charging.control.reset") }}
|
||||
</button>
|
||||
<!-- Step-up: destructive reset requires re-entering the password. -->
|
||||
<div v-else-if="resetPrompt" class="mt-3 rounded-control border border-danger/40 bg-danger-soft p-3">
|
||||
<p class="text-xs font-medium text-danger">{{ t("charging.control.resetConfirm") }}</p>
|
||||
<input
|
||||
v-model="resetPassword"
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
class="dh-input mt-2"
|
||||
:placeholder="t('charging.control.resetPassword')"
|
||||
@keyup.enter="confirmReset"
|
||||
/>
|
||||
<div class="mt-2 flex gap-2">
|
||||
<button class="dh-btn dh-btn-ghost grow" @click="cancelReset">{{ t("common.cancel") }}</button>
|
||||
<button class="dh-btn dh-btn-danger grow" :disabled="!resetPassword || ctlBusy === 'reset'" @click="confirmReset">
|
||||
{{ t("charging.control.reset") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- Not connected. In Modbus mode the server has already tried to reach
|
||||
the charger and says what it found, which beats a generic hint. -->
|
||||
<p v-else class="mt-3 text-xs text-muted">
|
||||
<!-- Why there is nothing to control yet. In Modbus mode the server has
|
||||
already tried to reach the charger and says what it found, which
|
||||
beats a generic hint. -->
|
||||
<p v-if="!ctlConnected" class="mt-3 text-xs text-muted">
|
||||
{{ ctl?.detail || t(ctlIsModbus ? "charging.control.modbusHint" : "charging.control.connectHint") }}
|
||||
</p>
|
||||
<p v-if="ctlError" class="mt-2 text-sm text-danger">{{ ctlError }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Acting on the charger, once there is a connection to act over. The
|
||||
card above is where that connection is set up. -->
|
||||
<div v-if="ctlActive && ctlConnected" class="dh-card p-4">
|
||||
<p class="text-sm font-semibold text-strong">{{ t("charging.control.title") }}</p>
|
||||
|
||||
<div class="mt-3 grid grid-cols-2 gap-2">
|
||||
<div class="rounded-control bg-sunken px-3 py-2">
|
||||
<div class="data text-sm font-semibold text-strong">{{ ctlStatusLabel }}</div>
|
||||
<div class="text-[11px] text-muted">{{ t("charging.control.status") }}</div>
|
||||
</div>
|
||||
<div class="rounded-control bg-sunken px-3 py-2">
|
||||
<div class="data text-sm font-semibold text-strong">{{ ctlMeterKwh }} kWh</div>
|
||||
<div class="text-[11px] text-muted">{{ t("charging.control.meter") }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex gap-2">
|
||||
<button class="dh-btn dh-btn-primary grow" :disabled="ctlBusy === 'start'" @click="doAction('start')">
|
||||
{{ t("charging.control.start") }}
|
||||
</button>
|
||||
<button class="dh-btn dh-btn-ghost grow" :disabled="ctlBusy === 'stop'" @click="doAction('stop')">
|
||||
{{ t("charging.control.stop") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<label class="dh-label flex justify-between">
|
||||
<span>{{ t("charging.control.limit") }}</span><span class="data text-body">{{ limitAmps }} A</span>
|
||||
</label>
|
||||
<input v-model.number="limitAmps" type="range" min="6" max="32" step="1" class="w-full accent-[var(--accent)]" />
|
||||
<div class="mt-2 flex gap-2">
|
||||
<button class="dh-btn dh-btn-ghost grow" :disabled="ctlBusy === 'limit'" @click="doAction('limit', { amps: limitAmps })">
|
||||
{{ t("charging.control.applyLimit") }}
|
||||
</button>
|
||||
<!-- Clearing a limit is an OCPP command; the register map takes an
|
||||
explicit ceiling, so in Modbus mode there is nothing to clear to. -->
|
||||
<button
|
||||
v-if="!ctlIsModbus"
|
||||
class="dh-btn dh-btn-ghost grow"
|
||||
:disabled="ctlBusy === 'clear-limit'"
|
||||
@click="doAction('clear-limit')"
|
||||
>
|
||||
{{ t("charging.control.clearLimit") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Boost is a Modbus command, and lasts for the current session only. -->
|
||||
<button
|
||||
v-if="ctlIsModbus"
|
||||
class="dh-btn dh-btn-ghost mt-3 w-full"
|
||||
:disabled="ctlBusy === 'boost'"
|
||||
@click="doAction('boost', { on: true })"
|
||||
>
|
||||
{{ t("charging.control.boost") }}
|
||||
</button>
|
||||
|
||||
<!-- Reset reboots the charger over OCPP; the register map has no
|
||||
equivalent, so the button is not offered on the local path. -->
|
||||
<button
|
||||
v-if="!ctlIsModbus && !resetPrompt"
|
||||
class="dh-btn dh-btn-ghost mt-3 w-full"
|
||||
:disabled="ctlBusy === 'reset'"
|
||||
@click="askReset"
|
||||
>
|
||||
{{ t("charging.control.reset") }}
|
||||
</button>
|
||||
<!-- Step-up: destructive reset requires re-entering the password. -->
|
||||
<div v-else-if="resetPrompt" class="mt-3 rounded-control border border-danger/40 bg-danger-soft p-3">
|
||||
<p class="text-xs font-medium text-danger">{{ t("charging.control.resetConfirm") }}</p>
|
||||
<input
|
||||
v-model="resetPassword"
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
class="dh-input mt-2"
|
||||
:placeholder="t('charging.control.resetPassword')"
|
||||
@keyup.enter="confirmReset"
|
||||
/>
|
||||
<div class="mt-2 flex gap-2">
|
||||
<button class="dh-btn dh-btn-ghost grow" @click="cancelReset">{{ t("common.cancel") }}</button>
|
||||
<button class="dh-btn dh-btn-danger grow" :disabled="!resetPassword || ctlBusy === 'reset'" @click="confirmReset">
|
||||
{{ t("charging.control.reset") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- What the charger reports over Modbus. Its own card rather than a
|
||||
tail on the control one: control is for acting on the charger, and
|
||||
this is a long read that pushed the buttons off the screen. -->
|
||||
|
||||
Reference in New Issue
Block a user