Files
qwen-image/tour-comfy/trash.html
2026-06-27 23:01:16 +02:00

232 lines
8.7 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Qwen Rapid-AIO — Database Consistency</title>
<style>
body {
background: #111;
color: #ccc;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 20px;
}
h1, h2 { color: #eee; }
.container { max-width: 1000px; margin: 0 auto; }
.section {
background: #1a1a1a;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #333;
}
.item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px;
border-bottom: 1px solid #222;
}
.item:last-child { border-bottom: none; }
.filename { font-family: monospace; color: #aaa; }
.info { font-size: 0.9em; color: #777; }
.btn {
background: #333;
color: #eee;
border: none;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
font-size: 0.9em;
}
.btn:hover { background: #444; }
.btn.danger { background: #633; }
.btn.danger:hover { background: #844; }
.btn.success { background: #363; }
.btn.success:hover { background: #484; }
.btn.primary { background: #35a; font-weight: bold; }
.btn.primary:hover { background: #46b; }
.header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; }
.nav { margin-bottom: 20px; }
.nav a { color: #58a; text-decoration: none; font-size: 0.9em; }
.nav a:hover { text-decoration: underline; }
#toast {
position: fixed;
bottom: 20px;
right: 20px;
background: #333;
color: #fff;
padding: 10px 20px;
border-radius: 4px;
display: none;
z-index: 1000;
}
</style>
</head>
<body>
<div class="container">
<div class="nav">
<a href="car.html">← Back to Studio</a>
</div>
<div class="header">
<h1>Database Consistency</h1>
<button class="btn primary" onclick="loadInconsistencies(true)">Run Check Now</button>
</div>
<div id="loading" style="display:none">Running consistency check...</div>
<div class="section">
<h2>Archived Items <span class="info">(Manually archived, recoverable)</span></h2>
<div id="archivedList">No archived items found.</div>
</div>
<div class="section">
<h2>Missing Group IDs <span class="info">(Legacy or orphaned images with no group assigned)</span></h2>
<div id="orphansList">No images with missing groups found.</div>
</div>
<div class="section">
<h2>Orphaned Records <span class="info">(In DB, but file missing on disk)</span></h2>
<div id="missingList">No orphaned records found.</div>
</div>
<div class="section">
<h2>Untracked Files <span class="info">(On disk, but not in DB)</span></h2>
<div id="untrackedList">No untracked files found.</div>
</div>
<div class="info" id="timestamp"></div>
</div>
<div id="toast"></div>
<script>
const API = window.location.origin;
function showToast(msg) {
const t = document.getElementById('toast');
t.textContent = msg;
t.style.display = 'block';
setTimeout(() => t.style.display = 'none', 3000);
}
async function repair(filename, action) {
try {
const r = await fetch(`${API}/db/repair`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ filename, action })
});
const d = await r.json();
let msg = 'Done';
if (d.status === 'deleted') msg = 'Record deleted';
else if (d.status === 'imported') msg = 'File imported';
else if (d.status === 'restored') msg = 'Item restored';
else if (d.status === 'deleted_permanently') msg = 'Permanently deleted';
else if (d.status === 'assigned') msg = 'Group assigned';
showToast(msg);
loadInconsistencies();
} catch (e) {
console.error(e);
showToast('Action failed');
}
}
async function loadInconsistencies(runNow = false) {
if (runNow) document.getElementById('loading').style.display = 'block';
try {
const url = runNow ? `${API}/db/inconsistencies?run_now=true` : `${API}/db/inconsistencies`;
const r = await fetch(url);
const d = await r.json();
renderArchived(d.archived_items || []);
renderMissing(d.missing_files || []);
renderUntracked(d.untracked_files || []);
renderOrphans(d.missing_group || []);
if (d.timestamp) {
const date = new Date(d.timestamp * 1000);
document.getElementById('timestamp').textContent = 'Last check: ' + date.toLocaleString();
}
} catch (e) {
console.error(e);
showToast('Failed to load inconsistencies');
} finally {
document.getElementById('loading').style.display = 'none';
}
}
function renderOrphans(files) {
const container = document.getElementById('orphansList');
if (files.length === 0) {
container.innerHTML = 'No images with missing groups found.';
return;
}
container.innerHTML = files.map(f => `
<div class="item">
<div>
<div class="filename">${f.filename}</div>
<div class="info">Name: ${f.name || 'none'}</div>
</div>
<button class="btn success" onclick="repair('${f.filename}', 'assign_group')">Auto-assign Group</button>
</div>
`).join('');
}
function renderArchived(files) {
const container = document.getElementById('archivedList');
if (files.length === 0) {
container.innerHTML = 'No archived items found.';
return;
}
container.innerHTML = files.map(f => `
<div class="item">
<div>
<div class="filename">${f.filename}</div>
<div class="info">Group: ${f.group_id || 'none'} | Name: ${f.name || 'none'}</div>
</div>
<div style="display:flex;gap:8px">
<button class="btn success" onclick="repair('${f.filename}', 'restore')">Restore</button>
<button class="btn danger" onclick="if(confirm('Permanently delete ${f.filename}?')) repair('${f.filename}', 'delete_permanently')">Delete</button>
</div>
</div>
`).join('');
}
function renderMissing(files) {
const container = document.getElementById('missingList');
if (files.length === 0) {
container.innerHTML = 'No orphaned records found.';
return;
}
container.innerHTML = files.map(f => `
<div class="item">
<div>
<div class="filename">${f.filename}</div>
<div class="info">Group: ${f.group_id || 'none'} | Name: ${f.name || 'none'}</div>
</div>
<button class="btn danger" onclick="repair('${f.filename}', 'delete_record')">Delete Record</button>
</div>
`).join('');
}
function renderUntracked(files) {
const container = document.getElementById('untrackedList');
if (files.length === 0) {
container.innerHTML = 'No untracked files found.';
return;
}
container.innerHTML = files.map(f => `
<div class="item">
<div class="filename">${f}</div>
<button class="btn success" onclick="repair('${f}', 'import_file')">Import File</button>
</div>
`).join('');
}
loadInconsistencies();
</script>
</body>
</html>