feat: Lock-Badge + smartes Kontextmenue in lokaler Client-Ansicht
Die lokale Dateiliste im Client zeigt jetzt pro Datei ein 🔒-Badge mit Nutzername wenn ausgecheckt (wie Server-Ansicht + Web-GUI). browse_sync_folder zieht den Server-Tree bei jedem Aufruf und korreliert via Journal-Lookup (oder .cloud-Metadaten) die lokale Datei mit dem File-Lock-Status. Rechtsklick-Menue reagiert jetzt auf den Lock-Status: - Frei -> "Auschecken (sperren)" - Eigener/fremder -> "Entsperren (einchecken)" Neuer Tauri-Command lock_file_cmd fuer reines Sperren ohne Oeffnen. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -86,20 +86,34 @@ async function doMarkOffline(file) {
|
||||
|
||||
async function doUnlockFile(file) {
|
||||
hideContextMenu();
|
||||
// Find file ID from server tree
|
||||
const serverFile = findFileInTree(fileTree.value, file.name);
|
||||
if (!serverFile) {
|
||||
const fileId = file.file_id ?? findFileInTree(fileTree.value, file.name)?.id;
|
||||
if (!fileId) {
|
||||
syncLog.value = [`[${ts()}] Fehler: Datei nicht auf Server gefunden`, ...syncLog.value];
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await invoke("unlock_file_cmd", { fileId: serverFile.id });
|
||||
await invoke("unlock_file_cmd", { fileId });
|
||||
syncLog.value = [`[${ts()}] Entsperrt: ${file.name}`, ...syncLog.value].slice(0, 200);
|
||||
} catch (err) {
|
||||
syncLog.value = [`[${ts()}] Fehler: ${err}`, ...syncLog.value].slice(0, 200);
|
||||
}
|
||||
}
|
||||
|
||||
async function doLockOnly(file) {
|
||||
hideContextMenu();
|
||||
const fileId = file.file_id ?? findFileInTree(fileTree.value, file.name)?.id;
|
||||
if (!fileId) {
|
||||
syncLog.value = [`[${ts()}] Fehler: Datei nicht auf Server gefunden`, ...syncLog.value];
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await invoke("lock_file_cmd", { fileId });
|
||||
syncLog.value = [`[${ts()}] Ausgecheckt: ${file.name}`, ...syncLog.value].slice(0, 200);
|
||||
} catch (err) {
|
||||
syncLog.value = [`[${ts()}] Fehler: ${err}`, ...syncLog.value].slice(0, 200);
|
||||
}
|
||||
}
|
||||
|
||||
function findFileInTree(entries, name) {
|
||||
for (const e of entries) {
|
||||
if (e.name === name) return e;
|
||||
@@ -463,6 +477,7 @@ onUnmounted(() => { unlistenStatus?.(); unlistenLog?.(); unlistenError?.(); unli
|
||||
<span class="lf-name">{{ f.name }}</span>
|
||||
<span v-if="f.is_cloud" class="lf-badge cloud">Cloud</span>
|
||||
<span v-else-if="f.is_offline" class="lf-badge offline">Offline</span>
|
||||
<span v-if="f.locked" class="lf-badge locked" :title="'Ausgecheckt von ' + f.locked_by">🔒 {{ f.locked_by }}</span>
|
||||
<span class="lf-size">{{ formatSize(f.cloud_size || f.size) }}</span>
|
||||
</div>
|
||||
<div v-if="!localFiles.length" class="empty">Ordner ist leer</div>
|
||||
@@ -481,12 +496,15 @@ onUnmounted(() => { unlistenStatus?.(); unlistenLog?.(); unlistenError?.(); unli
|
||||
<div v-if="contextMenu.file?.is_offline" class="cm-item" @click="doOpenOfflineFile(contextMenu.file)">
|
||||
📂 Oeffnen (auschecken)
|
||||
</div>
|
||||
<div v-if="contextMenu.file?.is_offline && !contextMenu.file?.locked" class="cm-item" @click="doLockOnly(contextMenu.file)">
|
||||
🔒 Auschecken (sperren)
|
||||
</div>
|
||||
<div v-if="contextMenu.file?.is_offline && contextMenu.file?.locked" class="cm-item" @click="doUnlockFile(contextMenu.file)">
|
||||
🔓 Entsperren (einchecken)
|
||||
</div>
|
||||
<div v-if="contextMenu.file?.is_offline" class="cm-item" @click="doUnmarkOffline(contextMenu.file)">
|
||||
☁ Nicht mehr offline (Platzhalter)
|
||||
</div>
|
||||
<div v-if="contextMenu.file?.is_offline" class="cm-item" @click="doUnlockFile(contextMenu.file)">
|
||||
🔓 Entsperren (Freigeben fuer andere)
|
||||
</div>
|
||||
<div class="cm-item" @click="hideContextMenu">Abbrechen</div>
|
||||
</div>
|
||||
|
||||
@@ -604,6 +622,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;f
|
||||
.lf-badge{font-size:.65rem;padding:.1rem .3rem;border-radius:3px;flex-shrink:0}
|
||||
.lf-badge.cloud{background:#e3f2fd;color:#1565c0}
|
||||
.lf-badge.offline{background:#e8f5e9;color:#2e7d32}
|
||||
.lf-badge.locked{background:#fff3e0;color:#e65100}
|
||||
.lf-size{font-size:.75rem;color:#999;flex-shrink:0}
|
||||
.checkbox-row{display:flex;align-items:center;gap:.5rem;font-size:.85rem;cursor:pointer}
|
||||
.context-menu{position:fixed;background:#fff;border:1px solid #ddd;border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.15);z-index:9999;min-width:200px;padding:.25rem 0}
|
||||
|
||||
Reference in New Issue
Block a user