thunderbird2docuware/options/options.html
sylyx f6c7761182 Feld-Zuordnung: Feldname wieder als Auswahl - und die Liste bleibt gefuellt
0.12.1 hatte den Feldnamen auf eine freie Texteingabe umgestellt. Das behob zwar
die Blockade, nahm aber die Auswahl weg - eigentlich war nur die Liste leer.

Jetzt wieder ein <select>, dessen Liste sich aus drei Quellen speist und damit
nie leer ist: Felder des gewaehlten Archivs, die Namen aus DEFAULT_FIELD_MAP und
alles im Formular bereits Vergebene. Ein Eintrag "Anderer Feldname" blendet eine
freie Eingabe ein, fuer Felder die in keiner Liste stehen. Ein gespeicherter Name,
den kein Archiv kennt, wird ins Dropdown aufgenommen statt verloren zu gehen.

Kern des Problems war die Herkunft der Liste: sie kam ausschliesslich vom Server
und setzte damit gecachte Schrankliste + Passwort dieser Sitzung + Archivwahl
voraus. Die Feldnamen werden nun je Archiv in storage.local unter
"fieldsByCabinet" gemerkt und beim Oeffnen VOR dem Aufbau der Zeilen gelesen -
die Auswahl steht also sofort und auch ohne Anmeldung. Ist ein Token da, wird im
Hintergrund aufgefrischt; schlaegt das fehl, bleibt die gemerkte Liste nutzbar.

Bei Server-Wechsel wird fieldsByCabinet mitgeloescht - die Feldlisten haengen an
Schrank-GUIDs des alten Servers (gleiche Logik wie fuer cabinets/defaultCabinetId).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 10:23:36 +02:00

273 lines
13 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8" />
<title>DocuWare Ablage – Einstellungen</title>
<style>
/* DocuWare-naher Dark-Style: tiefes Slate, DocuWare-Blau als Akzent. */
:root {
--bg: #11151b;
--bg-grad: radial-gradient(1200px 500px at 80% -10%, #18324a 0%, rgba(17,21,27,0) 60%);
--surface: #1a1f27;
--surface-2: #222a34;
--border: #2b3340;
--border-strong: #38424f;
--text: #e8edf2;
--muted: #8c97a4;
--accent: #2aa4df; /* DocuWare-Blau */
--accent-hover: #3cb6f0;
--accent-weak: rgba(42,164,223,.14);
--ok: #46c98a;
--err: #ec6b75;
--radius: 10px;
--shadow: 0 1px 0 rgba(255,255,255,.02) inset, 0 8px 24px rgba(0,0,0,.28);
font-synthesis: none;
}
* { box-sizing: border-box; }
html, body { background: var(--bg); }
body {
font: 14px/1.55 "Segoe UI", "Helvetica Neue", system-ui, sans-serif;
color: var(--text);
margin: 0;
padding: 0 16px 120px;
background-image: var(--bg-grad);
background-repeat: no-repeat;
-webkit-font-smoothing: antialiased;
}
.wrap { max-width: 620px; margin: 0 auto; }
/* Kopfzeile */
header.app {
display: flex; align-items: center; gap: 12px;
padding: 26px 2px 18px;
}
.logo {
width: 34px; height: 34px; border-radius: 8px; flex: none;
background: linear-gradient(135deg, var(--accent), #1c6fae);
display: grid; place-items: center;
box-shadow: 0 4px 14px rgba(42,164,223,.35);
}
.logo svg { width: 20px; height: 20px; }
header.app h1 { font-size: 18px; font-weight: 650; margin: 0; letter-spacing: .2px; }
header.app .sub { font-size: 12px; color: var(--muted); margin-top: 1px; }
/* Karten / Abschnitte */
section.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
box-shadow: var(--shadow);
padding: 18px 20px 20px;
margin: 14px 0;
}
.card-head { display: flex; align-items: baseline; gap: 10px; margin: 0 0 6px; }
.card-head h2 {
font-size: 13px; font-weight: 650; text-transform: uppercase;
letter-spacing: .8px; color: var(--accent); margin: 0;
}
.card-head .num {
font-size: 11px; color: var(--muted); border: 1px solid var(--border-strong);
border-radius: 999px; padding: 1px 8px; line-height: 1.5;
}
label { display: block; margin: 14px 0 5px; font-weight: 550; font-size: 13px; }
input[type="text"], input[type="password"], input[type="url"], select {
width: 100%; padding: 9px 11px; color: var(--text);
background: var(--surface-2); border: 1px solid var(--border-strong);
border-radius: 8px; font: inherit; outline: none;
transition: border-color .15s, box-shadow .15s, background .15s;
}
select { appearance: none;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'><path d='M2 4l4 4 4-4' fill='none' stroke='%238c97a4' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>");
background-repeat: no-repeat; background-position: right 11px center; padding-right: 30px;
}
input:focus, select:focus {
border-color: var(--accent);
box-shadow: 0 0 0 3px var(--accent-weak);
}
input::placeholder { color: #5f6b78; }
code { background: var(--surface-2); border: 1px solid var(--border); border-radius: 4px;
padding: 1px 5px; font-size: 12px; color: #b7c2cd; }
.hint { font-size: 12px; color: var(--muted); margin-top: 5px; }
.check { display: flex; align-items: center; gap: 9px; margin: 9px 0; font-weight: 450; }
.check label { margin: 0; font-weight: 450; font-size: 13px; }
input[type="checkbox"], input[type="radio"] { width: 16px; height: 16px; accent-color: var(--accent); flex: none; }
/* Mapping-Tabelle */
.map-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 4px 0 12px; }
.map-toolbar .grow { flex: 1; min-width: 180px; }
/* Mapping-Zeilen: Feldname + Attribut links gestapelt, fester Wert breit daneben. */
.map { margin-top: 4px; }
.map-row {
display: flex; align-items: center; gap: 10px;
background: var(--surface-2); border: 1px solid var(--border);
border-radius: 9px; padding: 8px 8px 8px 10px; margin-bottom: 8px;
}
.map-left { display: flex; flex-direction: column; gap: 6px; flex: 1 1 auto; min-width: 0; }
.map-row.has-const .map-left { flex: 0 0 250px; }
.map-right { display: none; flex: 1 1 auto; min-width: 0; }
.map-row.has-const .map-right { display: flex; align-items: center; }
.map-left select, .map-left input, .map-right input { width: 100%; padding: 7px 9px; }
.map-left input[hidden] { display: none; }
.map-hint { font-size: 11px; letter-spacing: .4px; text-transform: uppercase;
color: var(--muted); font-weight: 600; margin: 2px 2px 8px; }
.icon-btn {
width: 30px; height: 30px; padding: 0; border-radius: 7px; cursor: pointer;
background: var(--surface-2); border: 1px solid var(--border-strong); color: var(--muted);
font-size: 14px; line-height: 1; transition: .15s;
}
.icon-btn:hover { color: var(--err); border-color: var(--err); }
/* Teilen / JSON */
details.share { margin-top: 14px; border-top: 1px solid var(--border); padding-top: 10px; }
details.share summary {
cursor: pointer; font-size: 13px; font-weight: 600; color: var(--accent);
list-style: none; user-select: none; padding: 2px 0;
}
details.share summary::-webkit-details-marker { display: none; }
details.share summary::before { content: "▸ "; color: var(--muted); }
details.share[open] summary::before { content: "▾ "; }
textarea {
width: 100%; padding: 10px 11px; color: var(--text); background: var(--surface-2);
border: 1px solid var(--border-strong); border-radius: 8px; box-sizing: border-box;
font: 12px/1.45 ui-monospace, "Cascadia Code", Consolas, monospace; resize: vertical; outline: none;
}
textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-weak); }
/* Buttons */
button { font: inherit; cursor: pointer; border-radius: 8px; }
button.primary {
padding: 9px 18px; border: 0; font-weight: 650; color: #04222f;
background: linear-gradient(180deg, var(--accent-hover), var(--accent));
box-shadow: 0 4px 14px rgba(42,164,223,.3);
}
button.primary:hover { filter: brightness(1.06); }
button.ghost {
padding: 8px 15px; font-weight: 550; color: var(--text);
background: var(--surface-2); border: 1px solid var(--border-strong);
}
button.ghost:hover { border-color: var(--accent); color: var(--accent); }
button:disabled { opacity: .5; cursor: default; }
/* Sticky Aktionsleiste */
.actionbar {
position: fixed; left: 0; right: 0; bottom: 0; z-index: 5;
background: rgba(17,21,27,.82); backdrop-filter: blur(8px);
border-top: 1px solid var(--border);
}
.actionbar .inner { max-width: 620px; margin: 0 auto; padding: 12px 16px;
display: flex; align-items: center; gap: 12px; }
#status { font-size: 13px; min-height: 18px; }
.ok { color: var(--ok); } .err { color: var(--err); }
.spacer { flex: 1; }
</style>
</head>
<body>
<div class="wrap">
<header class="app">
<span class="logo" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none"><path d="M4 5.5A1.5 1.5 0 0 1 5.5 4H13l3 3h2.5A1.5 1.5 0 0 1 20 8.5v10A1.5 1.5 0 0 1 18.5 20h-13A1.5 1.5 0 0 1 4 18.5v-13Z" fill="#fff" opacity=".95"/><path d="M9 13.5h6M12 11v5" stroke="#1c6fae" stroke-width="1.6" stroke-linecap="round"/></svg>
</span>
<div>
<h1>DocuWare Ablage</h1>
<div class="sub">Einstellungen</div>
</div>
</header>
<section class="card">
<div class="card-head"><span class="num">1</span><h2>Verbindung</h2></div>
<label for="serverUrl">Server-URL</label>
<input type="url" id="serverUrl" placeholder="https://docuware.example.com" />
<div class="hint">Basis-URL ohne <code>/DocuWare/Platform</code>.</div>
<label for="organization">Organisation</label>
<input type="text" id="organization" />
<label for="username">Benutzername</label>
<input type="text" id="username" autocomplete="username" />
<label for="password">Passwort</label>
<input type="password" id="password" autocomplete="off" />
<div class="hint">Wird <strong>nicht gespeichert</strong> – nur zum Anmelden/Testen für
diese Sitzung. Im Ablage-Fenster wird es 1× pro Sitzung abgefragt.</div>
</section>
<section class="card">
<div class="card-head"><span class="num">2</span><h2>Standardwerte</h2></div>
<label for="defaultCabinet">Standard-Ziel (Archiv oder Briefkorb)</label>
<select id="defaultCabinet"><option value="">— keiner —</option></select>
<div class="hint">Liste wird nach erfolgreichem Verbindungstest gefüllt.</div>
<label>Standard-Format der E-Mail</label>
<div class="check"><input type="radio" name="mailFormat" id="fmtEml" value="eml" /> <label for="fmtEml">Original (.eml)</label></div>
<div class="check"><input type="radio" name="mailFormat" id="fmtPdf" value="pdf" /> <label for="fmtPdf">PDF</label></div>
<div class="hint">Die E-Mail wird immer in genau einem Format abgelegt (nicht beides). Im Ablage-Fenster umstellbar.</div>
<div class="check" style="margin-top:12px"><input type="checkbox" id="storeAttachments" /> <label for="storeAttachments">Anhänge mit ablegen</label></div>
<div class="check"><input type="checkbox" id="tagOnSuccess" /> <label for="tagOnSuccess">Mail nach Ablage als „DocuWare" markieren</label></div>
</section>
<section class="card">
<div class="card-head"><span class="num">3</span><h2>Feld-Zuordnung</h2></div>
<div class="hint" style="margin-bottom:10px">Welches DocuWare-Indexfeld wird aus welchem
Mail-Attribut vorbefüllt? Gilt für alle Aktenschränke. Leere/entfernte Zeilen befüllen
nichts vor.</div>
<div class="map-toolbar">
<div class="grow">
<select id="mapCabinet"><option value="">Feldnamen aus Archiv vorschlagen …</option></select>
</div>
<span id="mapFieldStatus" class="hint" style="margin:0"></span>
</div>
<div class="map-hint">DocuWare-Feld&nbsp;→ Mail-Attribut · fester Wert</div>
<div id="mapBody" class="map"></div>
<div class="map-toolbar" style="margin-top:10px">
<button id="mapAdd" class="ghost" type="button">+ Zeile</button>
<button id="mapReset" class="ghost" type="button">Auf Standard zurücksetzen</button>
</div>
<div class="hint" style="margin-top:8px">Steht ein Feld nicht in der Liste,
„<strong>✎ Anderer Feldname</strong>" wählen und den Namen eintippen.</div>
<div class="hint" style="margin-top:8px">Als Mail-Attribut „<strong>Fester Wert</strong>"
wählen, um einen festen Text (z. B. <code>NEU</code>) ins Feld zu schreiben.</div>
<details class="share">
<summary>Mapping teilen / übernehmen</summary>
<label for="mappingUrl">Aus Repo/URL laden</label>
<div class="map-toolbar">
<input type="url" id="mappingUrl" class="grow" placeholder="https://gitea.example/…/mapping.json" />
<button id="mappingPull" class="ghost" type="button">Von URL laden</button>
</div>
<div class="hint">Eine raw-JSON-Datei aus einem Gitea/GitHub-Repo. Lädt das Mapping in
den Editor – mit „Speichern" übernehmen. (Lesen/Pull; Zurückschreiben ins Repo nicht.)</div>
<label for="mappingJson">JSON (kopieren / einfügen)</label>
<textarea id="mappingJson" rows="6" placeholder='{ "EML_SUBJECT": "subject", "STATUS": { "const": "NEU" } }'></textarea>
<div class="map-toolbar">
<button id="mappingExport" class="ghost" type="button">Aktuelles als JSON</button>
<button id="mappingCopy" class="ghost" type="button">Kopieren</button>
<button id="mappingApply" class="ghost" type="button">JSON anwenden</button>
</div>
</details>
</section>
</div>
<div class="actionbar">
<div class="inner">
<button id="save" class="primary">Speichern</button>
<button id="test" class="ghost">Verbindung testen</button>
<span class="spacer"></span>
<span id="status"></span>
</div>
</div>
<script src="../lib/store.js"></script>
<script src="../lib/auth.js"></script>
<script src="../lib/docuware.js"></script>
<script src="options.js"></script>
</body>
</html>