The cards that open the charger get a card of their own
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
4188d049cb
commit
a5842201c0
@@ -64,6 +64,12 @@
|
||||
"idle": "Oplader ikke",
|
||||
"idleHint": "Tilslut ved en station for at starte en session."
|
||||
},
|
||||
"rfid": {
|
||||
"title": "RFID-kortindstillinger",
|
||||
"none": "Ingen kort er godkendt til denne lader.",
|
||||
"unsupported": "Tjenesten, som denne lader kommer fra, rapporterer ikke RFID-kort.",
|
||||
"readOnly": "Kort tilføjes og fjernes i Anker-appen. Ankers endpoints til det er udokumenterede, så DriverVault læser listen i stedet for at gætte sig til en skrivning."
|
||||
},
|
||||
"stations": {
|
||||
"heading": "I nærheden",
|
||||
"homeHeading": "Dine ladere",
|
||||
|
||||
@@ -333,6 +333,12 @@
|
||||
"rawTitle": "As the service reports it",
|
||||
"rawHint": "Every other field the service sent about this charger, under its own field names. They are undocumented, so they are shown as they arrive rather than renamed."
|
||||
},
|
||||
"rfid": {
|
||||
"title": "RFID cards settings",
|
||||
"none": "No cards are authorised on this charger.",
|
||||
"unsupported": "The service this charger came from does not report RFID cards.",
|
||||
"readOnly": "Cards are added and removed in the Anker app. Anker's endpoints for that are undocumented, so DriverVault reads the list rather than guessing at a write."
|
||||
},
|
||||
"stations": {
|
||||
"heading": "Nearby",
|
||||
"homeHeading": "Your chargers",
|
||||
|
||||
@@ -64,6 +64,12 @@
|
||||
"idle": "Brak ładowania",
|
||||
"idleHint": "Podłącz na stacji, aby rozpocząć sesję."
|
||||
},
|
||||
"rfid": {
|
||||
"title": "Ustawienia kart RFID",
|
||||
"none": "Na tej ładowarce nie autoryzowano żadnej karty.",
|
||||
"unsupported": "Usługa, z której pochodzi ta ładowarka, nie zgłasza kart RFID.",
|
||||
"readOnly": "Karty dodaje się i usuwa w aplikacji Anker. Endpointy Ankera do tego są nieudokumentowane, więc DriverVault odczytuje listę, zamiast zgadywać zapis."
|
||||
},
|
||||
"stations": {
|
||||
"heading": "W pobliżu",
|
||||
"homeHeading": "Twoje ładowarki",
|
||||
|
||||
@@ -177,7 +177,7 @@ const sessionMetrics = computed(() =>
|
||||
// buttons just did: the limit that was applied, whether boost took. An account
|
||||
// that has already arranged this column gets it at the end instead, the same
|
||||
// rule a tab added in a later release follows, and one drag puts it anywhere.
|
||||
const ALL_CHARGER_CARDS = ["control", "settings", "connection", "readings", "info"];
|
||||
const ALL_CHARGER_CARDS = ["control", "rfid", "settings", "connection", "readings", "info"];
|
||||
|
||||
const cardKeys = ref([...ALL_CHARGER_CARDS]);
|
||||
watch(
|
||||
@@ -187,7 +187,19 @@ watch(
|
||||
for (const key of order || []) {
|
||||
if (ALL_CHARGER_CARDS.includes(key) && !arranged.includes(key)) arranged.push(key);
|
||||
}
|
||||
cardKeys.value = [...arranged, ...ALL_CHARGER_CARDS.filter((k) => !arranged.includes(k))];
|
||||
// A card added after this order was saved goes where the default order puts
|
||||
// it — behind the neighbour it was written to sit under — rather than at the
|
||||
// bottom of the column. Somebody who has arranged their cards once should not
|
||||
// have to go looking for the new one.
|
||||
for (const key of ALL_CHARGER_CARDS) {
|
||||
if (arranged.includes(key)) continue;
|
||||
const before = ALL_CHARGER_CARDS.slice(0, ALL_CHARGER_CARDS.indexOf(key))
|
||||
.reverse()
|
||||
.find((k) => arranged.includes(k));
|
||||
const at = before ? arranged.indexOf(before) + 1 : 0;
|
||||
arranged.splice(at, 0, key);
|
||||
}
|
||||
cardKeys.value = arranged;
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
@@ -1174,6 +1186,13 @@ const chargerDetailViews = computed(() => {
|
||||
}));
|
||||
});
|
||||
|
||||
// The RFID cards authorised on the charger, out of the view that answers with
|
||||
// them. A card of its own: a list of physical cards somebody holds in their hand
|
||||
// is worth more than a block in a diagnostic dump. The information card keeps
|
||||
// relaying this view as well — it relays every view the account answers, and a
|
||||
// hole in that list would be the one thing it cannot say.
|
||||
const rfidView = computed(() => chargerDetailViews.value.find((v) => v.id === "rfid") || null);
|
||||
|
||||
// Everything else the service said about this charger, under its own field
|
||||
// names. The rows above are the ones DriverVault has a name for; these are the
|
||||
// remainder — the service documents none of them, so its own key is the only
|
||||
@@ -1647,6 +1666,81 @@ onMounted(async () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- The cards that may start a charge without a phone. Directly under
|
||||
the control card because it is the same question — who may use this
|
||||
charger — asked of a person rather than of a button. It reads the
|
||||
list the account holds; adding and removing them is the Anker app's
|
||||
job, and the card says so rather than offering a button that cannot
|
||||
work. -->
|
||||
<div
|
||||
v-if="selectedHomeCharger"
|
||||
class="dh-card p-4 transition-shadow duration-150"
|
||||
:class="dropCard === 'rfid' ? 'ring-2 ring-accent' : ''"
|
||||
:style="{ order: cardOrder('rfid') }"
|
||||
@dragenter.prevent="onCardDragEnter('rfid')"
|
||||
@dragover.prevent
|
||||
@drop.prevent="commitCardOrder"
|
||||
>
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<button
|
||||
type="button"
|
||||
:draggable="canArrangeCards"
|
||||
:title="canArrangeCards ? t('charging.cards.dragHint') : ''"
|
||||
class="flex grow items-center gap-3 text-left"
|
||||
:class="[canArrangeCards ? 'cursor-grab active:cursor-grabbing' : '', dragCard === 'rfid' ? 'opacity-50' : '']"
|
||||
:aria-expanded="isOpen('rfid')"
|
||||
@click="toggleCard('rfid')"
|
||||
@dragstart="onCardDragStart('rfid', $event)"
|
||||
@dragend="commitCardOrder"
|
||||
>
|
||||
<p class="text-sm font-semibold text-strong">{{ t("charging.rfid.title") }}</p>
|
||||
<span v-if="rfidView?.items.length" class="dh-badge dh-badge-neutral">{{ rfidView.items.length }}</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="dh-btn dh-btn-ghost !px-2 !py-1 text-xs"
|
||||
:disabled="chargerDetailsLoading !== ''"
|
||||
@click="loadChargerDetails(true)"
|
||||
>
|
||||
{{ chargerDetailsLoading ? t("common.loading") : t("charging.info.refresh") }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="flex shrink-0 items-center"
|
||||
:aria-expanded="isOpen('rfid')"
|
||||
:aria-label="t('charging.rfid.title')"
|
||||
@click="toggleCard('rfid')"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||
class="h-4 w-4 shrink-0 text-muted transition-transform" :class="isOpen('rfid') ? '' : '-rotate-90'"
|
||||
><path stroke-linecap="round" stroke-linejoin="round" d="m6 9 6 6 6-6" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-show="isOpen('rfid')">
|
||||
<p class="mt-1 text-[11px] text-muted">{{ selectedHomeCharger.name }}</p>
|
||||
<!-- A service that does not answer for cards, an account that may
|
||||
not read them, and a charger with none on it are three different
|
||||
answers, and each is said in its own words. -->
|
||||
<p v-if="!rfidView" class="mt-3 text-xs text-muted">{{ t("charging.rfid.unsupported") }}</p>
|
||||
<p v-else-if="rfidView.error" class="mt-3 text-xs text-muted">{{ rfidView.error }}</p>
|
||||
<p v-else-if="!rfidView.items.length" class="mt-3 text-xs text-muted">{{ t("charging.rfid.none") }}</p>
|
||||
<div v-else class="mt-3 flex flex-col gap-2">
|
||||
<div v-for="card in rfidView.items" :key="card.key" class="rounded-control bg-sunken p-3">
|
||||
<p class="text-sm font-semibold text-strong">{{ card.label }}</p>
|
||||
<dl class="mt-1 grid grid-cols-[auto_1fr] gap-x-4 gap-y-1">
|
||||
<template v-for="row in card.rows" :key="row.key">
|
||||
<dt class="break-all text-[11px] text-muted" :class="row.named ? '' : 'data'">{{ row.label }}</dt>
|
||||
<dd class="data break-all text-[11px] text-body">{{ row.value }}</dd>
|
||||
</template>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-3 text-[11px] text-muted">{{ t("charging.rfid.readOnly") }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- What the charger is set to, as it reports it back. Its own card
|
||||
under the control one: these are the values those buttons write, so
|
||||
they are read right after pressing them, and they were buried at
|
||||
|
||||
Reference in New Issue
Block a user