Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d02228e4c9 | |||
| 589c0018a9 | |||
| 03baacd5d8 | |||
| ea6a518c9c |
@ -1,97 +1,127 @@
|
||||
/* DocuWare-naher Dark-Style – identische Palette wie die Optionsseite. */
|
||||
:root {
|
||||
--bg: #11151b;
|
||||
--surface: #1a1f27;
|
||||
--surface-2: #222a34;
|
||||
--border: #2b3340;
|
||||
--border-strong: #38424f;
|
||||
--text: #e8edf2;
|
||||
--muted: #8c97a4;
|
||||
--accent: #2aa4df;
|
||||
--accent-hover: #3cb6f0;
|
||||
--accent-weak: rgba(42,164,223,.14);
|
||||
--ok: #46c98a;
|
||||
--err: #ec6b75;
|
||||
color-scheme: dark; /* native Datepicker/Scrollbars/Checkboxen im Dark-Mode */
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
font: 13px/1.45 "Segoe UI", system-ui, sans-serif;
|
||||
margin: 0; color: #1a1a1a; background: #fff;
|
||||
font: 13px/1.45 "Segoe UI", "Helvetica Neue", system-ui, sans-serif;
|
||||
margin: 0; color: var(--text); background: var(--bg);
|
||||
display: flex; flex-direction: column; height: 100vh;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
/* Titel-Leiste wie im Connect-to-Outlook-Dialog */
|
||||
/* Titel-Leiste */
|
||||
.titlebar {
|
||||
background: #2b3a44; color: #fff;
|
||||
padding: 8px 14px; font-weight: 600; font-size: 13px;
|
||||
background: #0f1318; color: var(--text);
|
||||
padding: 9px 16px; font-weight: 600; font-size: 13px; letter-spacing: .2px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
box-shadow: 0 1px 0 rgba(42,164,223,.35);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
header { padding: 12px 18px 6px; border-bottom: 1px solid #e5e7eb; flex-shrink: 0; }
|
||||
header h1 { font-size: 16px; font-weight: 600; margin: 0 0 10px; }
|
||||
header { padding: 14px 18px 8px; border-bottom: 1px solid var(--border); flex-shrink: 0; }
|
||||
header h1 { font-size: 16px; font-weight: 650; margin: 0 0 10px; }
|
||||
|
||||
.toolbar { display: flex; align-items: center; gap: 14px; }
|
||||
.toolbar .spacer { flex: 1; }
|
||||
button { font: inherit; cursor: pointer; }
|
||||
button.link {
|
||||
background: none; border: 0; color: #1f2937; cursor: pointer;
|
||||
font: inherit; padding: 4px 2px; display: inline-flex; align-items: center; gap: 5px;
|
||||
background: none; border: 0; color: var(--muted);
|
||||
padding: 4px 2px; display: inline-flex; align-items: center; gap: 5px;
|
||||
}
|
||||
button.link:hover { color: #2563eb; }
|
||||
button.link:hover { color: var(--accent); }
|
||||
button.primary {
|
||||
background: #f4b400; color: #1a1a1a; border: 0; border-radius: 3px;
|
||||
padding: 7px 22px; font-weight: 600; cursor: pointer;
|
||||
border: 0; border-radius: 8px; padding: 8px 22px; 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 { background: #e0a500; }
|
||||
button:disabled { opacity: .5; cursor: default; }
|
||||
button.primary:hover { filter: brightness(1.06); }
|
||||
button:disabled { opacity: .5; cursor: default; filter: none; }
|
||||
|
||||
main { flex: 1; overflow-y: auto; padding: 14px 18px; }
|
||||
main { flex: 1; overflow-y: auto; padding: 16px 18px; }
|
||||
|
||||
.target { display: grid; grid-template-columns: 150px 1fr; align-items: center; gap: 10px; margin-bottom: 12px; }
|
||||
.target > label { text-align: right; color: #374151; font-weight: 500; }
|
||||
.target > label { text-align: right; color: var(--muted); font-weight: 500; }
|
||||
|
||||
/* Indexfelder: rechtsbündiges Label links, Eingabe rechts */
|
||||
.fields { display: flex; flex-direction: column; gap: 8px; }
|
||||
.fields { display: flex; flex-direction: column; gap: 9px; }
|
||||
.field { display: grid; grid-template-columns: 150px 1fr; align-items: center; gap: 10px; }
|
||||
.field > label { text-align: right; color: #374151; font-weight: 500; padding-top: 2px; }
|
||||
.field > label { text-align: right; color: var(--muted); font-weight: 500; padding-top: 2px; }
|
||||
.field.full { grid-template-columns: 150px 1fr; align-items: start; }
|
||||
.field .req { color: #b91c1c; }
|
||||
.field .req { color: var(--err); }
|
||||
|
||||
select, input[type="text"], input[type="number"], input[type="date"], textarea {
|
||||
width: 100%; padding: 6px 9px; border: 1px solid #b9c0c8; border-radius: 3px; font: inherit; background: #fff;
|
||||
select, input[type="text"], input[type="number"], input[type="date"], input[type="password"], textarea {
|
||||
width: 100%; padding: 8px 10px; 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;
|
||||
}
|
||||
select:focus, input:focus, textarea:focus { outline: none; border-color: #2563eb; box-shadow: 0 0 0 2px #2563eb33; }
|
||||
textarea { resize: vertical; min-height: 56px; }
|
||||
select { appearance: none; padding-right: 30px;
|
||||
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;
|
||||
}
|
||||
select:focus, input:focus, textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-weak); }
|
||||
input::placeholder { color: #5f6b78; }
|
||||
textarea { resize: vertical; min-height: 60px; }
|
||||
|
||||
/* Vorbefüllte (aus der Mail übernommene) Felder dezent kennzeichnen */
|
||||
.field.prefilled input, .field.prefilled textarea { background: #f3f4f6; color: #4b5563; }
|
||||
.field.prefilled input, .field.prefilled textarea, .field.prefilled select {
|
||||
background: rgba(42,164,223,.08); color: #bcc8d3;
|
||||
}
|
||||
|
||||
.options { margin: 0; }
|
||||
.format { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin: 5px 0; }
|
||||
.format-label { font-weight: 500; }
|
||||
.format { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin: 6px 0; }
|
||||
.format-label { font-weight: 550; }
|
||||
.format .radio { margin: 0; }
|
||||
.radio, .check { display: flex; align-items: center; gap: 8px; margin: 5px 0; font-weight: 400; }
|
||||
.radio input, .check input { accent-color: #2563eb; }
|
||||
.radio, .check { display: flex; align-items: center; gap: 8px; margin: 6px 0; font-weight: 400; }
|
||||
.radio input, .check input { width: 16px; height: 16px; accent-color: var(--accent); flex: none; }
|
||||
|
||||
.att-list { list-style: none; margin: 6px 0 0 26px; padding: 0; max-height: 110px; overflow-y: auto; }
|
||||
.att-list li { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 2px 0; color: #374151; }
|
||||
.att-list li { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 2px 0; color: var(--muted); }
|
||||
|
||||
/* Footer bleibt fix sichtbar, nur der Felderbereich (main) scrollt. */
|
||||
footer { border-top: 1px solid #e5e7eb; padding: 10px 18px; background: #fafafa; flex-shrink: 0; }
|
||||
.muted { color: #6b7280; font-size: 12px; }
|
||||
.err { color: #b91c1c; } .ok { color: #15803d; }
|
||||
.field.invalid input, .field.invalid textarea, .field.invalid select { border-color: #b91c1c; }
|
||||
footer { border-top: 1px solid var(--border); padding: 11px 18px; background: var(--surface); flex-shrink: 0; }
|
||||
.muted { color: var(--muted); font-size: 12px; }
|
||||
.err { color: var(--err); } .ok { color: var(--ok); }
|
||||
.field.invalid input, .field.invalid textarea, .field.invalid select { border-color: var(--err); }
|
||||
|
||||
/* „Bereits abgelegt"-Banner */
|
||||
.banner {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
background: #ecfdf5; border: 1px solid #6ee7b7; color: #065f46;
|
||||
border-radius: 4px; padding: 7px 10px; margin-bottom: 10px; font-size: 12px;
|
||||
background: rgba(70,201,138,.12); border: 1px solid rgba(70,201,138,.4); color: #8be0b4;
|
||||
border-radius: 8px; padding: 8px 11px; margin-bottom: 10px; font-size: 12px;
|
||||
}
|
||||
.banner[hidden] { display: none; }
|
||||
.banner .banner-text { flex: 1; }
|
||||
.banner .link { color: #065f46; text-decoration: underline; }
|
||||
.banner .link { color: #8be0b4; text-decoration: underline; }
|
||||
.banner .link:hover { color: var(--ok); }
|
||||
|
||||
/* Passwort-Abfrage (Sitzungs-Login, nicht gespeichert) */
|
||||
/* Overlays: Passwort-Abfrage / Dubletten-Hinweis */
|
||||
.overlay {
|
||||
position: fixed; inset: 0; background: rgba(0, 0, 0, .35);
|
||||
position: fixed; inset: 0; background: rgba(0, 0, 0, .55);
|
||||
display: flex; align-items: center; justify-content: center; z-index: 50;
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
.overlay[hidden] { display: none; }
|
||||
.overlay-box {
|
||||
background: #fff; border-radius: 6px; padding: 18px 20px; width: 340px;
|
||||
box-shadow: 0 8px 30px rgba(0, 0, 0, .25);
|
||||
background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
|
||||
padding: 20px 22px; width: 350px;
|
||||
box-shadow: 0 18px 50px rgba(0, 0, 0, .5);
|
||||
}
|
||||
.overlay-box h2 { font-size: 15px; font-weight: 600; margin: 0 0 8px; }
|
||||
.overlay-box input[type="password"] {
|
||||
width: 100%; padding: 7px 9px; border: 1px solid #b9c0c8; border-radius: 3px;
|
||||
font: inherit; margin-top: 8px;
|
||||
}
|
||||
.overlay-box input[type="password"]:focus { outline: none; border-color: #2563eb; box-shadow: 0 0 0 2px #2563eb33; }
|
||||
.overlay-box h2 { font-size: 15px; font-weight: 650; margin: 0 0 8px; }
|
||||
.overlay-box input[type="password"] { margin-top: 8px; }
|
||||
.overlay-box .err { min-height: 1em; margin-top: 6px; }
|
||||
.overlay-actions { display: flex; justify-content: flex-end; align-items: center; gap: 12px; margin-top: 10px; }
|
||||
.overlay-actions { display: flex; justify-content: flex-end; align-items: center; gap: 12px; margin-top: 12px; }
|
||||
.overlay-box .pw-note { margin-top: 10px; }
|
||||
|
||||
@ -15,6 +15,7 @@ let STATE = {
|
||||
fields: [], // Felddefinitionen des Store-Dialogs
|
||||
existingDoc: null, // Treffer der Dedup-Suche im gewählten Schrank (oder null)
|
||||
cabinetFieldsByCab: {}, // Cache: cabinetId -> [Feldnamen] (für EML_ID-Erkennung)
|
||||
uploadedIds: new Set(), // bereits erfolgreich abgelegte Nachrichten (für Retry-Schutz)
|
||||
};
|
||||
|
||||
// Mail-Token -> Funktion, die den Wert aus den Mail-Metadaten liefert.
|
||||
@ -186,11 +187,27 @@ function renderAttachments() {
|
||||
const ul = $("attList");
|
||||
ul.innerHTML = "";
|
||||
STATE.attachments.forEach((a, i) => {
|
||||
// Bewusst per DOM-API (nicht innerHTML): der Anhang-Name stammt aus der Mail
|
||||
// und ist angreiferkontrolliert – als Text einsetzen, nie als HTML.
|
||||
const li = document.createElement("li");
|
||||
li.innerHTML =
|
||||
`<input type="checkbox" id="att-${i}" checked /> ` +
|
||||
`<label for="att-${i}" style="margin:0;font-weight:400">${a.name} ` +
|
||||
`<span class="muted">(${formatSize(a.size)})</span></label>`;
|
||||
|
||||
const cb = document.createElement("input");
|
||||
cb.type = "checkbox";
|
||||
cb.id = `att-${i}`;
|
||||
cb.checked = true;
|
||||
|
||||
const label = document.createElement("label");
|
||||
label.setAttribute("for", `att-${i}`);
|
||||
label.style.margin = "0";
|
||||
label.style.fontWeight = "400";
|
||||
label.textContent = `${a.name} `;
|
||||
|
||||
const size = document.createElement("span");
|
||||
size.className = "muted";
|
||||
size.textContent = `(${formatSize(a.size)})`;
|
||||
label.appendChild(size);
|
||||
|
||||
li.append(cb, document.createTextNode(" "), label);
|
||||
ul.appendChild(li);
|
||||
});
|
||||
}
|
||||
@ -429,7 +446,8 @@ function buildInput(f) {
|
||||
if (f.isSelectList) {
|
||||
// Combobox: frei tippbar mit Vorschlagsliste (wie in Connect-to-Outlook).
|
||||
const dl = document.createElement("datalist");
|
||||
dl.id = "dl-" + f.name;
|
||||
// Feldnamen können Leer-/Sonderzeichen enthalten -> auf gültige id-Zeichen reduzieren.
|
||||
dl.id = "dl-" + String(f.name).replace(/[^A-Za-z0-9_-]/g, "_");
|
||||
el.setAttribute("list", dl.id);
|
||||
el._datalist = dl;
|
||||
}
|
||||
@ -457,7 +475,7 @@ function prefillFields() {
|
||||
|
||||
// Setzt einen Wert auf das Control eines Feldes (kümmert sich um Datum/Select).
|
||||
function setFieldValue(name, f, val) {
|
||||
const wrap = document.querySelector(`.field[data-name="${name}"]`);
|
||||
const wrap = document.querySelector(`.field[data-name="${cssEsc(name)}"]`);
|
||||
const el = wrap && wrap.querySelector("[data-role='value']");
|
||||
if (!el) return;
|
||||
if (el.type === "date") {
|
||||
@ -488,7 +506,7 @@ async function populateSelectLists() {
|
||||
);
|
||||
} catch (_) { /* leere Liste ist ok */ }
|
||||
if (!vals.length) continue;
|
||||
const wrap = document.querySelector(`.field[data-name="${f.name}"]`);
|
||||
const wrap = document.querySelector(`.field[data-name="${cssEsc(f.name)}"]`);
|
||||
const el = wrap && wrap.querySelector("[data-role='value']");
|
||||
if (!el) continue;
|
||||
if (el.tagName === "SELECT") {
|
||||
@ -530,7 +548,10 @@ function collectFieldValues() {
|
||||
if (!firstInvalid) firstInvalid = name;
|
||||
}
|
||||
if (String(raw).trim() !== "") {
|
||||
result[name] = { value: el.type === "date" ? new Date(raw) : raw, type };
|
||||
// Date-Input als LOKALE Mitternacht parsen (raw+"T00:00:00"), sonst
|
||||
// interpretiert new Date("YYYY-MM-DD") als UTC.
|
||||
const value = el.type === "date" ? new Date(`${raw}T00:00:00`) : raw;
|
||||
result[name] = { value, type };
|
||||
}
|
||||
});
|
||||
return { result, firstInvalid };
|
||||
@ -584,6 +605,8 @@ async function submit() {
|
||||
let mi = 0;
|
||||
for (const mid of STATE.messageIds) {
|
||||
mi++;
|
||||
// Retry-Schutz: nach einem Teilfehler nicht erneut hochladen (sonst Dubletten).
|
||||
if (STATE.uploadedIds.has(mid)) continue;
|
||||
const prefix = multi ? `Mail ${mi}/${STATE.messageIds.length}: ` : "";
|
||||
// Meta/Anhänge der jeweiligen Nachricht.
|
||||
const meta = mid === STATE.messageId ? STATE.meta : await Mail.getMeta(mid);
|
||||
@ -632,6 +655,9 @@ async function submit() {
|
||||
.sendMessage({ type: "archive:done", rfcMessageId: meta.rfcMessageId, cabinetId: STATE.cabinetId })
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
// Diese Nachricht ist vollständig abgelegt -> bei einem späteren Retry überspringen.
|
||||
STATE.uploadedIds.add(mid);
|
||||
}
|
||||
|
||||
const base = multi ? `${STATE.messageIds.length} E-Mails abgelegt.` : "Erfolgreich abgelegt.";
|
||||
@ -695,7 +721,17 @@ async function tagMessage(messageId) {
|
||||
|
||||
// --- Helfer ---
|
||||
const isMemo = (f) => /memo/i.test(f.type) || f.name === "EML_BODY";
|
||||
const toDateInput = (d) => d.toISOString().slice(0, 10);
|
||||
// Lokales Datum als YYYY-MM-DD (NICHT toISOString -> das rechnet auf UTC um und
|
||||
// kippt eine Uhrzeit nahe Mitternacht auf den Vortag).
|
||||
const toDateInput = (d) => {
|
||||
const y = d.getFullYear();
|
||||
const m = String(d.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(d.getDate()).padStart(2, "0");
|
||||
return `${y}-${m}-${day}`;
|
||||
};
|
||||
// Sicheres CSS-Escaping für Attribut-Selektoren (Feldnamen aus DocuWare).
|
||||
const cssEsc = (s) =>
|
||||
window.CSS && CSS.escape ? CSS.escape(String(s)) : String(s).replace(/["\\\]]/g, "\\$&");
|
||||
function formatSize(b) {
|
||||
if (!b) return "–";
|
||||
if (b < 1024) return `${b} B`;
|
||||
|
||||
@ -414,7 +414,12 @@ const DocuWare = {
|
||||
if (t.includes("date")) {
|
||||
// DocuWare erwartet /Date(ms)/ oder ISO; ISO funktioniert bei Platform.
|
||||
const d = value instanceof Date ? value : new Date(value);
|
||||
return { FieldName: name, Item: d.toISOString(), ItemElementName: "Date" };
|
||||
if (isNaN(d)) return { FieldName: name, Item: String(value), ItemElementName: "Date" };
|
||||
// Auf den LOKALEN Kalendertag als UTC-Mitternacht normalisieren. Sonst würde
|
||||
// toISOString eine Uhrzeit nahe Mitternacht in eine andere Zeitzone und damit
|
||||
// auf den Vor-/Folgetag kippen (Datumsfelder tragen keine Uhrzeit).
|
||||
const utcDay = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
|
||||
return { FieldName: name, Item: utcDay.toISOString(), ItemElementName: "Date" };
|
||||
}
|
||||
if (t.includes("decimal") || t.includes("currency")) {
|
||||
return { FieldName: name, Item: Number(value), ItemElementName: "Decimal" };
|
||||
|
||||
@ -29,7 +29,7 @@ const Mail = {
|
||||
date: header.date instanceof Date ? header.date : new Date(header.date),
|
||||
bodyText,
|
||||
account,
|
||||
direction: this._direction(header, account),
|
||||
direction: this._direction(header),
|
||||
sizeBytes: header.size || 0,
|
||||
};
|
||||
},
|
||||
@ -140,9 +140,8 @@ const Mail = {
|
||||
return "";
|
||||
},
|
||||
|
||||
_direction(header, accountName) {
|
||||
// Heuristik: ist der Account-Name/eine Identität Absender -> Ausgang.
|
||||
// Robustere Erkennung erfolgt später über Identitäten; v1 simpel:
|
||||
_direction(header) {
|
||||
// Heuristik über den Ordnertyp; robustere Erkennung via Identitäten käme später.
|
||||
const folderType = header.folder && header.folder.type;
|
||||
if (folderType === "sent" || folderType === "outbox") return "Ausgang";
|
||||
return "Eingang";
|
||||
|
||||
22
lib/store.js
22
lib/store.js
@ -73,13 +73,23 @@ const Settings = {
|
||||
return s;
|
||||
},
|
||||
|
||||
// Laufende Schreibkette: serialisiert parallele set()-Aufrufe, damit zwei fast
|
||||
// gleichzeitige Writes (z.B. Schrankwahl + Format-Umschalten) sich nicht beim
|
||||
// read-modify-write gegenseitig überschreiben.
|
||||
_writeQueue: Promise.resolve(),
|
||||
|
||||
async set(partial) {
|
||||
const current = await this.get();
|
||||
const next = { ...current, ...partial };
|
||||
// Sicherheitsnetz: Passwort darf NIE persistiert werden (z.B. aus Alt-Importen).
|
||||
delete next.password;
|
||||
await browser.storage.local.set({ settings: next });
|
||||
return next;
|
||||
const run = async () => {
|
||||
const current = await this.get();
|
||||
const next = { ...current, ...partial };
|
||||
// Sicherheitsnetz: Passwort darf NIE persistiert werden (z.B. aus Alt-Importen).
|
||||
delete next.password;
|
||||
await browser.storage.local.set({ settings: next });
|
||||
return next;
|
||||
};
|
||||
const p = this._writeQueue.then(run, run);
|
||||
this._writeQueue = p.catch(() => {}); // Fehler bricht die Kette nicht ab
|
||||
return p;
|
||||
},
|
||||
|
||||
/** Basis-URL der Platform-API ohne abschließenden Slash. */
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"manifest_version": 2,
|
||||
"name": "DocuWare Ablage",
|
||||
"description": "Legt markierte E-Mails (als .eml, PDF und mit Anhängen) in DocuWare ab.",
|
||||
"version": "0.10.6",
|
||||
"version": "0.10.8",
|
||||
"author": "l.lingler",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
|
||||
@ -12,6 +12,14 @@ function setStatus(msg, kind) {
|
||||
el.className = kind || "";
|
||||
}
|
||||
|
||||
// Warnt, wenn der Server über unverschlüsseltes http:// läuft – dann ginge das
|
||||
// Passwort im Klartext über die Leitung. Liefert einen anzuhängenden Hinweis.
|
||||
function insecureWarning(url) {
|
||||
return /^http:\/\//i.test(String(url || "").trim())
|
||||
? " ⚠ Achtung: http:// ist unverschlüsselt – bitte https:// verwenden."
|
||||
: "";
|
||||
}
|
||||
|
||||
async function load() {
|
||||
const s = await Settings.get();
|
||||
FIELDS.forEach((f) => ($(f).value = s[f] || ""));
|
||||
@ -213,8 +221,10 @@ function collect() {
|
||||
// --- Events ----------------------------------------------------------------
|
||||
|
||||
$("save").addEventListener("click", async () => {
|
||||
await Settings.set(collect());
|
||||
setStatus("Gespeichert.", "ok");
|
||||
const data = collect();
|
||||
await Settings.set(data);
|
||||
const warn = insecureWarning(data.serverUrl);
|
||||
setStatus("Gespeichert." + warn, warn ? "err" : "ok");
|
||||
});
|
||||
|
||||
$("test").addEventListener("click", async () => {
|
||||
@ -228,7 +238,8 @@ $("test").addEventListener("click", async () => {
|
||||
fillCabinets(cabinets, s.defaultCabinetId);
|
||||
const arch = cabinets.filter((c) => !c.isBasket).length;
|
||||
const bk = cabinets.filter((c) => c.isBasket).length;
|
||||
setStatus(`Verbindung ok – ${arch} Archive, ${bk} Briefkörbe gefunden.`, "ok");
|
||||
const warn = insecureWarning(s.serverUrl);
|
||||
setStatus(`Verbindung ok – ${arch} Archive, ${bk} Briefkörbe gefunden.` + warn, warn ? "err" : "ok");
|
||||
} catch (e) {
|
||||
setStatus(`Fehler: ${e.message}`, "err");
|
||||
}
|
||||
|
||||
@ -29,6 +29,14 @@
|
||||
{
|
||||
"version": "0.10.6",
|
||||
"update_link": "https://sylyx.xyz/sylyx/thunderbird2docuware/releases/download/v0.10.6/docuware-ablage-0.10.6.xpi"
|
||||
},
|
||||
{
|
||||
"version": "0.10.7",
|
||||
"update_link": "https://sylyx.xyz/sylyx/thunderbird2docuware/releases/download/v0.10.7/docuware-ablage-0.10.7.xpi"
|
||||
},
|
||||
{
|
||||
"version": "0.10.8",
|
||||
"update_link": "https://sylyx.xyz/sylyx/thunderbird2docuware/releases/download/v0.10.8/docuware-ablage-0.10.8.xpi"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user