Release v2.5.0 — Client-Versions-Übersicht im Web-Editor
Jeder Client meldet beim Start seinen Status (Name, Abteilung, Plugin- und Thunderbird-Version) als _clients/<email>.json ins Gitea-Repo — aber nur, wenn sich tatsächlich etwas geändert hat (kein Commit-Spam pro Start). Web-Editor: neuer Admin-Unterpunkt "User & Versionen" (Route /api/clients) mit Tabelle je User und "veraltet"-Markierung für Clients, die nicht auf der neuesten gemeldeten Version laufen. _clients/ ist in den Ordner-Filtern ausgenommen, damit es nicht als Abteilung erscheint. Nebenbei: Web-Editor-Button-Label "Abteilung" -> "Vorlage" (Templates-Tab). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015PZHd9vRsBiH8cKYdQo1Yv
This commit is contained in:
@@ -8,6 +8,7 @@ const FULL_SYNC_COOLDOWN_MS = 10 * 1000; // min 10s between full pulls
|
||||
const SHARED_FOLDER = '_gemeinsam';
|
||||
const USER_FOLDER = '_benutzer';
|
||||
const CONFIG_FOLDER = '_config';
|
||||
const CLIENTS_FOLDER = '_clients';
|
||||
const SCHLAGWOERTER_CACHE_KEY = 'schlagwoerter_cache';
|
||||
|
||||
// ── Gitea API Client ──
|
||||
@@ -190,6 +191,59 @@ class SyncManager {
|
||||
return this.config?.authorEmail || '';
|
||||
}
|
||||
|
||||
get authorName() {
|
||||
return this.config?.authorName || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Meldet den eigenen Client-Status (Name, Abteilung, Plugin- + TB-Version)
|
||||
* als _clients/<email>.json ins Repo — Basis für die Admin-Übersicht im
|
||||
* Web-Editor. Schreibt NUR, wenn sich tatsächlich etwas geändert hat
|
||||
* (Plugin-Version, TB-Version, Name oder Abteilung) — sonst kein Commit.
|
||||
*/
|
||||
async reportClientStatus() {
|
||||
if (!this.isConfigured) return { success: false, skipped: 'not-configured' };
|
||||
const email = this.authorEmail.trim().toLowerCase();
|
||||
if (!email) return { success: false, skipped: 'no-email' };
|
||||
|
||||
let tbVersion = '';
|
||||
try {
|
||||
const info = await browser.runtime.getBrowserInfo();
|
||||
tbVersion = [info.name, info.version].filter(Boolean).join(' ');
|
||||
} catch (_) {}
|
||||
|
||||
const status = {
|
||||
name: this.authorName,
|
||||
email,
|
||||
department: this.department,
|
||||
pluginVersion: browser.runtime.getManifest().version,
|
||||
tbVersion,
|
||||
lastSeen: new Date().toISOString()
|
||||
};
|
||||
|
||||
const filepath = `${CLIENTS_FOLDER}/${email}.json`;
|
||||
const body = JSON.stringify(status, null, 2);
|
||||
const commitMsg = `Client-Status: ${email} (v${status.pluginVersion})`;
|
||||
|
||||
const existing = await this.client.getFile(filepath);
|
||||
if (existing && existing.content) {
|
||||
try {
|
||||
const prev = JSON.parse(GiteaClient.fromBase64(existing.content));
|
||||
const unchanged = prev.name === status.name
|
||||
&& prev.department === status.department
|
||||
&& prev.pluginVersion === status.pluginVersion
|
||||
&& prev.tbVersion === status.tbVersion;
|
||||
if (unchanged) {
|
||||
return { success: true, skipped: 'unchanged' };
|
||||
}
|
||||
} catch (_) { /* kaputter Vorgänger → einfach überschreiben */ }
|
||||
await this.client.updateFile(filepath, body, existing.sha, commitMsg);
|
||||
} else {
|
||||
await this.client.createFile(filepath, body, commitMsg);
|
||||
}
|
||||
return { success: true, status };
|
||||
}
|
||||
|
||||
async autoDetect() {
|
||||
if (!this.isConfigured) return null;
|
||||
return await this.client.getConfig();
|
||||
@@ -233,7 +287,7 @@ class SyncManager {
|
||||
const entries = await this.client.listDir('');
|
||||
const departments = [];
|
||||
for (const entry of entries) {
|
||||
if (entry.type === 'dir' && entry.name !== SHARED_FOLDER && entry.name !== USER_FOLDER && entry.name !== CONFIG_FOLDER && entry.name !== 'signatures' && !entry.name.startsWith('.')) {
|
||||
if (entry.type === 'dir' && entry.name !== SHARED_FOLDER && entry.name !== USER_FOLDER && entry.name !== CONFIG_FOLDER && entry.name !== CLIENTS_FOLDER && entry.name !== 'signatures' && !entry.name.startsWith('.')) {
|
||||
departments.push(entry.name);
|
||||
}
|
||||
}
|
||||
@@ -968,6 +1022,7 @@ let lastKnownShas = null;
|
||||
let lastFullSync = 0;
|
||||
let lastTagSync = 0;
|
||||
let syncInProgress = false;
|
||||
let clientStatusReported = false;
|
||||
const TAG_SYNC_INTERVAL_MS = 60 * 1000;
|
||||
const HASH_STORAGE_KEY_BG = 'sync_hashes';
|
||||
|
||||
@@ -1009,6 +1064,15 @@ async function smartSync() {
|
||||
const initialized = await syncManager.init();
|
||||
if (!initialized) return;
|
||||
|
||||
// Einmal pro Session den eigenen Client-Status melden (Admin-Übersicht).
|
||||
// Fire-and-forget, blockiert den Sync nicht.
|
||||
if (!clientStatusReported) {
|
||||
clientStatusReported = true;
|
||||
syncManager.reportClientStatus()
|
||||
.then((r) => { if (r?.status) console.log('[Sync] Client-Status gemeldet:', r.status.email, 'v' + r.status.pluginVersion); })
|
||||
.catch((e) => console.error('[Sync] Client-Status fehlgeschlagen:', e));
|
||||
}
|
||||
|
||||
syncInProgress = true;
|
||||
|
||||
// Tag sync every 60s (schlagwoerter.json is not in SHA-checked folders)
|
||||
|
||||
Reference in New Issue
Block a user