diff --git a/.gitignore b/.gitignore
index 683b324..5e2c2d7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-defaults.local.js
+defaults.local.json
diff --git a/README.md b/README.md
index e079821..17620d5 100644
--- a/README.md
+++ b/README.md
@@ -58,6 +58,7 @@ Mapping von Abteilungs-E-Mail-Adressen zu Ordnernamen. Wird vom Plugin gelesen,
| `lib/gitea-sync.js` | Gitea-API-Client + Sync-Manager |
| `lib/mdi/` | Material Design Icons (Subset) |
| `templates_options/` | Einstellungsseite (Vorlagen, Signaturen, Verbindung) |
+| `defaults.local.json` | Optionale vorkonfigurierte Verbindungsdaten (gitignored) |
## Installation
@@ -71,12 +72,32 @@ Mapping von Abteilungs-E-Mail-Adressen zu Ordnernamen. Wird vom Plugin gelesen,
### XPI bauen
```bash
+# Ohne vorkonfigurierte Verbindungsdaten:
7z a templates-reply-hotel.xpi manifest.json background.js popup.html popup.js lib/ templates_options/ icons/
+
+# Mit vorkonfigurierten Verbindungsdaten (für Deployment):
+7z a templates-reply-hotel.xpi manifest.json background.js popup.html popup.js lib/ templates_options/ icons/ defaults.local.json
```
+### Vorkonfigurierte Verbindungsdaten (`defaults.local.json`)
+
+Wenn eine `defaults.local.json` im Plugin-Root existiert und in die XPI eingebaut wird, werden die Verbindungsdaten beim ersten Start automatisch gesetzt. Der User muss dann nur noch "Verbindung speichern" klicken.
+
+```json
+{
+ "baseUrl": "https://git.example.com",
+ "owner": "organisation",
+ "repo": "email-vorlagen",
+ "branch": "main",
+ "token": "dein-api-token"
+}
+```
+
+Die Datei ist in `.gitignore` — Tokens landen nicht im Repository.
+
## Einrichtung
-1. **Verbindung konfigurieren**: Einstellungen-Tab (⚙) → Server-URL, Repository, Token eingeben → Verbindung speichern
+1. **Verbindung konfigurieren**: Einstellungen-Tab (⚙) → Server-URL, Repository, Token eingeben → Verbindung speichern (entfällt bei vorkonfigurierter XPI)
2. **Abteilung wählen** (oder automatisch erkannt via `abteilungen.json`)
3. **Vorlagen erstellen**: Vorlagen-Tab → Neue Vorlage → Sichtbarkeit wählen → Speichern
4. **Signaturen einrichten**: Signaturen-Tab → Identität wählen → Kopfbereich bearbeiten → Speichern
diff --git a/lib/gitea-sync.js b/lib/gitea-sync.js
index daa7064..53c5288 100644
--- a/lib/gitea-sync.js
+++ b/lib/gitea-sync.js
@@ -3,7 +3,8 @@
const SYNC_CONFIG_KEY = 'gitea_config';
const SYNC_STATE_KEY = 'sync_state';
const TEMPLATE_STORAGE_KEY = 'message_templates';
-const SYNC_INTERVAL_MS = 15 * 60 * 1000; // 15 minutes
+const SHA_CHECK_INTERVAL_MS = 5 * 1000; // 5 seconds — lightweight SHA check
+const FULL_SYNC_COOLDOWN_MS = 10 * 1000; // min 10s between full pulls
const SHARED_FOLDER = '_gemeinsam';
const USER_FOLDER = '_benutzer';
const CONFIG_FOLDER = '_config';
@@ -762,24 +763,66 @@ browser.runtime.onMessage.addListener(async (msg, sender) => {
// ── Auto-sync on startup (pull only) ──
-async function autoSync() {
+let lastKnownShas = null;
+let lastFullSync = 0;
+let syncInProgress = false;
+const HASH_STORAGE_KEY_BG = 'sync_hashes';
+
+function simpleHashBg(str) {
+ let h = 0;
+ for (let i = 0; i < str.length; i++) {
+ h = ((h << 5) - h + str.charCodeAt(i)) | 0;
+ }
+ return h;
+}
+
+async function updateSyncHashes() {
+ const templates = await syncManager.getLocalTemplates();
+ const result = await browser.storage.local.get(HASH_STORAGE_KEY_BG);
+ const data = result[HASH_STORAGE_KEY_BG] || {};
+ data.tpl = {};
+ for (const t of templates) {
+ data.tpl[t.id] = simpleHashBg(t.content || '');
+ }
+ await browser.storage.local.set({ [HASH_STORAGE_KEY_BG]: data });
+}
+
+async function smartSync() {
+ if (syncInProgress) return;
try {
const initialized = await syncManager.init();
if (!initialized) return;
- if (syncManager.department) {
- console.log('[Sync] Auto-pull Vorlagen gestartet...');
- const result = await syncManager.pullTemplates();
- console.log('[Sync] Auto-pull Vorlagen abgeschlossen:', result);
- }
+ // Lightweight SHA check
+ const shaResult = await syncManager.checkRemoteShas();
+ if (!shaResult?.success) return;
- console.log('[Sync] Auto-pull Signaturen gestartet...');
- const sigResult = await syncManager.pullSignatures();
- console.log('[Sync] Auto-pull Signaturen abgeschlossen:', sigResult);
+ const currentShas = JSON.stringify(shaResult.remoteShas);
+
+ // First run or SHAs changed → full pull
+ if (lastKnownShas === null || currentShas !== lastKnownShas) {
+ const now = Date.now();
+ if (now - lastFullSync < FULL_SYNC_COOLDOWN_MS) return;
+
+ syncInProgress = true;
+ lastFullSync = now;
+ console.log('[Sync] Änderung erkannt, lade Vorlagen...');
+
+ const result = await syncManager.pullTemplates();
+ console.log('[Sync] Vorlagen geladen:', result);
+ await updateSyncHashes();
+
+ const sigResult = await syncManager.pullSignatures();
+ console.log('[Sync] Signaturen geladen:', sigResult);
+
+ lastKnownShas = JSON.stringify((await syncManager.checkRemoteShas()).remoteShas || {});
+ syncInProgress = false;
+ }
} catch (err) {
- console.error('[Sync] Auto-pull fehlgeschlagen:', err);
+ console.error('[Sync] Check fehlgeschlagen:', err);
+ syncInProgress = false;
}
}
-autoSync();
-setInterval(autoSync, SYNC_INTERVAL_MS);
+smartSync();
+setInterval(smartSync, SHA_CHECK_INTERVAL_MS);
diff --git a/templates-reply-hotel.xpi b/templates-reply-hotel.xpi
index 25021d6..67c21da 100644
Binary files a/templates-reply-hotel.xpi and b/templates-reply-hotel.xpi differ
diff --git a/templates_options/templates_options.html b/templates_options/templates_options.html
index 7404451..ad92766 100644
--- a/templates_options/templates_options.html
+++ b/templates_options/templates_options.html
@@ -1062,7 +1062,6 @@
-