Protokollseite: Kopfdaten einklappbar, Netzbereich-Vorschlag

Phase 6 (Bedienung unter Arbeitsbedingungen). Standort/Netzbereich/Notiz
standen bisher immer offen und schoben die Werkzeuge unter die Bildkante -
beim Kunden braucht man aber zuerst die Werkzeuge, die Kopfdaten meist nur
einmal.

- Abschnitt einklappbar, mit Zusammenfassung in der Kopfzeile. Offen genau
  dann, wenn noch nichts eingetragen ist - dann ist Ausfuellen der naechste
  sinnvolle Schritt.
- Erkanntes Subnetz als Chip zum Uebernehmen ("10.0.2.0/24 uebernehmen")
  statt Abtippen von der Statusseite.
- inputmode="decimal" auf dem Netzbereich - Zifferntastatur statt Buchstaben.

Im Emulator geprueft.
This commit is contained in:
Eduard Wisch 2026-08-16 17:48:53 +02:00
parent 9eef6177ba
commit e25b909d18

View file

@ -20,6 +20,7 @@
saveScan, saveScan,
deleteScan, deleteScan,
} from '$lib/protocols'; } from '$lib/protocols';
import { scanner } from '$lib/scanner';
import { resumeFinishedStressSessions } from '$lib/stresstest'; import { resumeFinishedStressSessions } from '$lib/stresstest';
import { sync } from '$lib/sync.svelte'; import { sync } from '$lib/sync.svelte';
import { toast } from '$lib/toast.svelte'; import { toast } from '$lib/toast.svelte';
@ -39,6 +40,20 @@
let saveScanOpen = $state(false); let saveScanOpen = $state(false);
let expandedScan = $state<string | null>(null); let expandedScan = $state<string | null>(null);
let deleteScanId = $state<string | null>(null); let deleteScanId = $state<string | null>(null);
/** Kopfdaten sind zugeklappt, solange nichts eingetragen ist (siehe Kommentar im Markup) */
let kopfdatenOffen = $state(false);
/** vom Adapter erkanntes Subnetz — als antippbarer Vorschlag im Eingabefeld */
let erkanntesSubnetz = $state('');
/** Menü hinter den drei Punkten (selten gebrauchte, gefährliche Aktionen) */
let ueberlaufOffen = $state(false);
/** Kompakte Zusammenfassung für die zugeklappte Kopfzeile */
const kopfZusammenfassung = $derived(
[protocol?.location, protocol?.subnet, protocol?.note?.split('\n')[0]]
.map((t) => (t ?? '').trim())
.filter(Boolean)
.join(' · '),
);
let appStateListener: PluginListenerHandle | null = null; let appStateListener: PluginListenerHandle | null = null;
@ -102,6 +117,19 @@
await persist(); await persist();
} }
// Kopfdaten offen lassen, solange noch nichts eingetragen ist — dann ist
// das Ausfüllen der nächste sinnvolle Schritt. Sind sie gefüllt, bleibt
// der Platz für die Werkzeuge frei.
kopfdatenOffen = !(p.location || p.subnet || p.note);
// Erkanntes Subnetz als Eingabevorschlag bereitstellen (best effort)
try {
const local = await scanner.getLocalSubnet();
erkanntesSubnetz = String(local.subnet ?? '').trim();
} catch {
/* kein Adapter aktiv — dann gibt es eben keinen Vorschlag */
}
// App wechselt in den Hintergrund (anderer App-Wechsel, Display aus) → // App wechselt in den Hintergrund (anderer App-Wechsel, Display aus) →
// sofort sichern, bevor Android den Prozess evtl. beendet. // sofort sichern, bevor Android den Prozess evtl. beendet.
appStateListener = await App.addListener('appStateChange', ({ isActive }) => { appStateListener = await App.addListener('appStateChange', ({ isActive }) => {
@ -284,8 +312,35 @@
/> />
<div class="flex-1 overflow-y-auto pb-24"> <div class="flex-1 overflow-y-auto pb-24">
<!-- Stammdaten --> <!--
<section class="flex flex-col gap-2 border-b border-zinc-800 p-3"> Kopfdaten eingeklappt, Werkzeuge zuerst.
Vor Ort wird zuerst gemessen und erst danach (wenn überhaupt) beschriftet.
Vorher füllten Standort/Netzbereich/Notiz den ganzen ersten Bildschirm und
man musste an ihnen vorbeiscrollen, um überhaupt an ein Werkzeug zu
kommen. Sind bereits Daten eingetragen, zeigt die Kopfzeile sie kompakt.
-->
<section class="border-b border-zinc-800">
<button
class="flex w-full items-center gap-2 px-3 py-2.5 text-left active:bg-zinc-900"
onclick={() => (kopfdatenOffen = !kopfdatenOffen)}
>
<Icons.FileText size={15} class="shrink-0 text-zinc-500" />
<span class="min-w-0 flex-1 text-xs text-zinc-400">
{#if kopfZusammenfassung}
<span class="text-zinc-300">{kopfZusammenfassung}</span>
{:else}
Standort, Netzbereich, Notiz
{/if}
</span>
<Icons.ChevronDown
size={16}
class="shrink-0 text-zinc-500 {kopfdatenOffen ? 'rotate-180' : ''}"
/>
</button>
{#if kopfdatenOffen}
<div class="flex flex-col gap-2 px-3 pb-3">
<label class="flex flex-col gap-1 text-xs text-zinc-400"> <label class="flex flex-col gap-1 text-xs text-zinc-400">
Standort Standort
<input <input
@ -302,7 +357,24 @@
bind:value={protocol.subnet} bind:value={protocol.subnet}
onblur={persist} onblur={persist}
placeholder="192.168.1.0/24" placeholder="192.168.1.0/24"
inputmode="decimal"
autocapitalize="off"
autocorrect="off"
spellcheck="false"
/> />
<!-- Vorschlag aus dem tatsächlich erkannten Netz: spart das
fehleranfällige Eintippen einer CIDR-Angabe auf dem Handy -->
{#if erkanntesSubnetz && erkanntesSubnetz !== protocol.subnet}
<button
class="mt-0.5 w-fit rounded bg-zinc-800 px-2 py-1 text-[11px] text-sky-300 active:bg-zinc-700"
onclick={() => {
if (protocol) protocol.subnet = erkanntesSubnetz;
void persist();
}}
>
{erkanntesSubnetz} übernehmen
</button>
{/if}
</label> </label>
<label class="flex flex-col gap-1 text-xs text-zinc-400"> <label class="flex flex-col gap-1 text-xs text-zinc-400">
Notiz Notiz
@ -313,6 +385,8 @@
onblur={persist} onblur={persist}
></textarea> ></textarea>
</label> </label>
</div>
{/if}
</section> </section>
<!-- Werkzeuge --> <!-- Werkzeuge -->