From 52e8942e6d6ee3774c56bd3d093f2d65e9912b6d Mon Sep 17 00:00:00 2001 From: sylyx Date: Tue, 16 Jun 2026 14:41:52 +0200 Subject: [PATCH] =?UTF-8?q?Optionen:=20DocuWare-Dark-Style,=20in=20Karten?= =?UTF-8?q?=20aufgeteilt;=20Export/Import=20+=20Diagnose=20entfernt;=20Map?= =?UTF-8?q?ping=20mit=20Archiv-Feldvorschl=C3=A4gen=20(datalist)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- options/options.html | 286 ++++++++++++++++++++++++++++++------------- options/options.js | 161 +++++++++++------------- 2 files changed, 272 insertions(+), 175 deletions(-) diff --git a/options/options.html b/options/options.html index 36aa31c..d0ea903 100644 --- a/options/options.html +++ b/options/options.html @@ -4,109 +4,219 @@ DocuWare Ablage – Einstellungen -

DocuWare Ablage – Einstellungen

+
+
+ +
+

DocuWare Ablage

+
Einstellungen
+
+
-
- Verbindung - - -
Basis-URL ohne /DocuWare/Platform.
+
+
1

Verbindung

+ + +
Basis-URL ohne /DocuWare/Platform.
- - + + - - + + - - -
Wird nicht gespeichert – nur zum Anmelden/Testen für - diese Sitzung. Im Ablage-Fenster wird es 1× pro Sitzung abgefragt.
-
+ + +
Wird nicht gespeichert – nur zum Anmelden/Testen für + diese Sitzung. Im Ablage-Fenster wird es 1× pro Sitzung abgefragt.
+ -
- Standardwerte - - -
Liste wird nach erfolgreichem Verbindungstest gefüllt.
+
+
2

Standardwerte

+ + +
Liste wird nach erfolgreichem Verbindungstest gefüllt.
- -
-
-
Die E-Mail wird immer in genau einem Format abgelegt (nicht beides). Im Ablage-Fenster umstellbar.
+ +
+
+
Die E-Mail wird immer in genau einem Format abgelegt (nicht beides). Im Ablage-Fenster umstellbar.
-
-
-
+
+
+ -
- - - +
+
3

Feld-Zuordnung

+
Welches DocuWare-Indexfeld wird aus welchem + Mail-Attribut vorbefüllt? Gilt für alle Aktenschränke. Leere/entfernte Zeilen befüllen + nichts vor.
+ +
+
+ +
+ +
+ + + + +
DocuWare-FeldnameMail-Attribut
+ + +
+ + +
+
-
- Feld-Zuordnung (Vorbefüllung) -
Legt fest, welches DocuWare-Indexfeld aus welchem Mail-Attribut vorbefüllt - wird. Feldname = DocuWare-Datenbankname (z. B. EML_SUBJECT). - Gilt für alle Aktenschränke. Leere/entfernte Zeilen befüllen nichts vor.
- - - -
DocuWare-FeldnameMail-Attribut
-
- - +
+
+ + + +
-
- -
- Einstellungen sichern -
Exportiert/importiert die Einstellungen (Server, Organisation, - Benutzer, Standardwerte) als Datei. Das Passwort ist nicht enthalten - und muss nach einer Neuinstallation einmal neu eingegeben werden.
-
- - - -
-
- -
- Diagnose (für Entwicklung) -
Analysiert den Store-Dialog des oben gewählten Standard-Ziels und - zeigt die Rohstruktur (Felder, Auswahllisten, Defaults). Inhalt bitte kopieren und - an den Entwickler geben.
-
- -
- -
+
diff --git a/options/options.js b/options/options.js index 2375709..25e4f8e 100644 --- a/options/options.js +++ b/options/options.js @@ -32,6 +32,53 @@ function getMailFormat() { return el ? el.value : "eml"; } +function fillCabinets(cabinets, selectedId) { + // Standard-Ziel (Archive + Briefkörbe) + const sel = $("defaultCabinet"); + sel.innerHTML = ''; + const addGroup = (label, list) => { + if (!list.length) return; + const g = document.createElement("optgroup"); + g.label = label; + list.forEach((c) => { + const o = document.createElement("option"); + o.value = c.id; + o.textContent = c.name; + if (String(c.id) === String(selectedId)) o.selected = true; + g.appendChild(o); + }); + sel.appendChild(g); + }; + addGroup("Archive", cabinets.filter((c) => !c.isBasket)); + addGroup("Briefkörbe", cabinets.filter((c) => c.isBasket)); + + // Mapping-Helfer: nur Archive (Briefkörbe haben keine Indexfelder). + const mc = $("mapCabinet"); + const keep = mc.value; + mc.innerHTML = ''; + cabinets.filter((c) => !c.isBasket).forEach((c) => { + const o = document.createElement("option"); + o.value = c.id; + o.textContent = c.name; + mc.appendChild(o); + }); + if (keep) mc.value = keep; +} + +// Besorgt einen Sitzungs-Token: vorhandenen vom Broker nutzen, sonst mit dem +// (transienten) Passwortfeld anmelden. Liefert false, wenn kein Passwort da ist. +async function ensureToken() { + const st = await browser.runtime.sendMessage({ type: "auth:status" }); + if (st && st.hasToken && st.token) { Auth.setToken(st.token); return true; } + const pw = $("password").value; + if (!pw) return false; + const res = await browser.runtime.sendMessage({ type: "auth:logon", password: pw }); + if (!res || !res.ok) throw new Error(res && res.error ? res.error : "Anmeldung fehlgeschlagen."); + Auth.setToken(res.token); + $("password").value = ""; // Passwort nicht behalten + return true; +} + // --- Feld-Mapping-Editor --------------------------------------------------- function addMapRow(field = "", token = "") { @@ -40,6 +87,7 @@ function addMapRow(field = "", token = "") { const inp = document.createElement("input"); inp.type = "text"; inp.className = "map-field"; inp.value = field; inp.placeholder = "EML_SUBJECT"; + inp.setAttribute("list", "fieldNames"); // Vorschläge aus gewähltem Archiv const tdF = document.createElement("td"); tdF.appendChild(inp); const sel = document.createElement("select"); sel.className = "map-token"; @@ -54,7 +102,7 @@ function addMapRow(field = "", token = "") { const tdT = document.createElement("td"); tdT.appendChild(sel); const del = document.createElement("button"); - del.type = "button"; del.className = "secondary"; del.textContent = "✕"; + del.type = "button"; del.className = "icon-btn"; del.textContent = "✕"; del.title = "Zeile entfernen"; del.addEventListener("click", () => tr.remove()); const tdX = document.createElement("td"); tdX.className = "del"; tdX.appendChild(del); @@ -77,26 +125,6 @@ function collectMapping() { return map; } -function fillCabinets(cabinets, selectedId) { - const sel = $("defaultCabinet"); - sel.innerHTML = ''; - const addGroup = (label, list) => { - if (!list.length) return; - const g = document.createElement("optgroup"); - g.label = label; - list.forEach((c) => { - const o = document.createElement("option"); - o.value = c.id; - o.textContent = c.name; - if (String(c.id) === String(selectedId)) o.selected = true; - g.appendChild(o); - }); - sel.appendChild(g); - }; - addGroup("Archive", cabinets.filter((c) => !c.isBasket)); - addGroup("Briefkörbe", cabinets.filter((c) => c.isBasket)); -} - function collect() { const partial = {}; FIELDS.forEach((f) => (partial[f] = $(f).value.trim())); @@ -107,8 +135,7 @@ function collect() { return partial; } -$("mapAdd").addEventListener("click", () => addMapRow()); -$("mapReset").addEventListener("click", () => loadMapping(DEFAULT_FIELD_MAP)); +// --- Events ---------------------------------------------------------------- $("save").addEventListener("click", async () => { await Settings.set(collect()); @@ -116,17 +143,11 @@ $("save").addEventListener("click", async () => { }); $("test").addEventListener("click", async () => { - const pw = $("password").value; - if (!pw) { setStatus("Bitte Passwort eingeben.", "err"); return; } setStatus("Verbinde …"); try { const s = await Settings.set(collect()); // erst speichern (ohne Passwort), dann testen - // Anmeldung über den Hintergrund-Broker: primt zugleich die Sitzung, sodass - // das Ablege-Fenster danach nicht erneut nach dem Passwort fragt. - const res = await browser.runtime.sendMessage({ type: "auth:logon", password: pw }); - if (!res || !res.ok) throw new Error(res && res.error ? res.error : "Anmeldung fehlgeschlagen."); - Auth.setToken(res.token); - $("password").value = ""; // Passwort nicht behalten + const ok = await ensureToken(); + if (!ok) { setStatus("Bitte Passwort eingeben.", "err"); return; } const cabinets = await DocuWare.listCabinets(s); await browser.storage.local.set({ cabinets }); fillCabinets(cabinets, s.defaultCabinetId); @@ -138,65 +159,31 @@ $("test").addEventListener("click", async () => { } }); -$("exportBtn").addEventListener("click", async () => { - const s = await Settings.get(); - const blob = new Blob([JSON.stringify(s, null, 2)], { type: "application/json" }); - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = "docuware-ablage-einstellungen.json"; - document.body.appendChild(a); - a.click(); - a.remove(); - setTimeout(() => URL.revokeObjectURL(url), 1000); - setStatus("Einstellungen exportiert.", "ok"); -}); +$("mapAdd").addEventListener("click", () => addMapRow()); +$("mapReset").addEventListener("click", () => loadMapping(DEFAULT_FIELD_MAP)); -$("importBtn").addEventListener("click", () => $("importFile").click()); - -$("importFile").addEventListener("change", async (e) => { - const file = e.target.files && e.target.files[0]; - if (!file) return; +// Archiv wählen -> dessen Indexfelder als Vorschläge (datalist) für alle Feldnamen. +$("mapCabinet").addEventListener("change", async () => { + const id = $("mapCabinet").value; + const dl = $("fieldNames"); + const st = $("mapFieldStatus"); + if (!id) { dl.innerHTML = ""; st.textContent = ""; return; } + st.textContent = "Lade Felder …"; try { - const text = await file.text(); - const data = JSON.parse(text); - await Settings.set(data); - await load(); - setStatus("Einstellungen importiert.", "ok"); - } catch (err) { - setStatus(`Import fehlgeschlagen: ${err.message}`, "err"); - } finally { - e.target.value = ""; - } -}); - -$("diagBtn").addEventListener("click", async () => { - const cabinetId = $("defaultCabinet").value; - const out = $("diag"); - out.style.display = "block"; - if (!cabinetId) { - out.value = "Bitte oben zuerst ein Standard-Ziel (Archiv) wählen."; - return; - } - out.value = "Analysiere …"; - try { - const s = await Settings.set(collect()); - // Sitzungs-Token nutzen; falls noch keiner da ist, Passwortfeld verwenden. - const st = await browser.runtime.sendMessage({ type: "auth:status" }); - if (st && st.hasToken && st.token) { - Auth.setToken(st.token); - } else { - const pw = $("password").value; - if (!pw) { out.value = "Bitte Passwort eingeben (oder zuerst „Verbindung testen“)."; return; } - const res = await browser.runtime.sendMessage({ type: "auth:logon", password: pw }); - if (!res || !res.ok) throw new Error(res && res.error ? res.error : "Anmeldung fehlgeschlagen."); - Auth.setToken(res.token); - $("password").value = ""; - } - const dump = await DocuWare.diagnoseStoreDialog(s, cabinetId); - out.value = JSON.stringify(dump, null, 2); + const s = await Settings.get(); + const ok = await ensureToken(); + if (!ok) { st.textContent = "Erst „Verbindung testen“ (Passwort nötig)."; return; } + const names = (await DocuWare.cabinetFieldNames(s, id)) + .filter((n) => n && !/^DW[A-Z]/.test(n)); // DW*-Systemfelder ausblenden + dl.innerHTML = ""; + names.sort().forEach((n) => { + const o = document.createElement("option"); + o.value = n; + dl.appendChild(o); + }); + st.textContent = `${names.length} Felder als Vorschlag geladen.`; } catch (e) { - out.value = `Fehler: ${e.message}`; + st.textContent = `Fehler: ${e.message}`; } });