Calculate directory sizes in background
This commit is contained in:
+57
-1
@@ -15,6 +15,8 @@ const state = {
|
||||
nextDebugId: 1,
|
||||
jobs: new Map(),
|
||||
jobRefresh: new Map(),
|
||||
sizeJobs: new Map(),
|
||||
sizeResults: new Map(),
|
||||
nextWindowId: 1,
|
||||
zIndex: 20
|
||||
};
|
||||
@@ -339,19 +341,23 @@ function renderProperties(body) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sizeLabel = entry.type === 'directory' ? directorySizeLabel(entry) : formatBytes(entry.size);
|
||||
body.classList.add('properties');
|
||||
body.innerHTML = `
|
||||
<dl>
|
||||
<dt>Name</dt><dd>${escapeHtml(entry.name)}</dd>
|
||||
<dt>Typ</dt><dd>${escapeHtml(entry.type)}</dd>
|
||||
<dt>Pfad</dt><dd>${escapeHtml(entry.path)}</dd>
|
||||
<dt>Größe</dt><dd>${formatBytes(entry.size)}</dd>
|
||||
<dt>Größe</dt><dd>${escapeHtml(sizeLabel)}</dd>
|
||||
<dt>Geändert</dt><dd>${new Date(entry.modifiedAt).toLocaleString()}</dd>
|
||||
<dt>Besitzer</dt><dd>${escapeHtml(formatPrincipal(entry.owner, entry.ownerId))}</dd>
|
||||
<dt>Gruppe</dt><dd>${escapeHtml(formatPrincipal(entry.group, entry.groupId))}</dd>
|
||||
<dt>Rechte</dt><dd>${escapeHtml(entry.permissions ? `0${entry.permissions}`.slice(-4) : '-')}</dd>
|
||||
</dl>
|
||||
`;
|
||||
if (entry.type === 'directory') {
|
||||
ensureDirectorySize(entry);
|
||||
}
|
||||
}
|
||||
|
||||
function renderQueue(body) {
|
||||
@@ -452,6 +458,24 @@ async function createJob(type, source, destination, refreshWindowIds = []) {
|
||||
return job;
|
||||
}
|
||||
|
||||
async function createSizeJob(entry) {
|
||||
recordDebug('size.create.request', { source: entry.path });
|
||||
const body = new URLSearchParams();
|
||||
body.set('source', entry.path);
|
||||
appendCsrf(body);
|
||||
const job = await api(apiUrl('job.php?action=size'), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
|
||||
body
|
||||
});
|
||||
recordDebug('size.create.response', job);
|
||||
state.jobs.set(job.id, job);
|
||||
state.sizeJobs.set(entry.path, job.id);
|
||||
pollJob(job.id);
|
||||
render();
|
||||
return job;
|
||||
}
|
||||
|
||||
async function reloadExplorerWindows(ids) {
|
||||
const uniqueIds = new Set(ids);
|
||||
const targets = state.windows.filter((win) => win.kind === 'explorer' && (uniqueIds.has(win.id) || !uniqueIds.size));
|
||||
@@ -601,6 +625,8 @@ async function pollJob(id) {
|
||||
render();
|
||||
if (['queued', 'running', 'cancel_requested'].includes(job.status)) {
|
||||
setTimeout(() => pollJob(id), 700);
|
||||
} else if (job.type === 'size') {
|
||||
finishSizeJob(job);
|
||||
} else {
|
||||
await refreshAfterJob(job);
|
||||
}
|
||||
@@ -610,6 +636,26 @@ async function pollJob(id) {
|
||||
}
|
||||
}
|
||||
|
||||
function ensureDirectorySize(entry) {
|
||||
if (state.sizeResults.has(entry.path) || state.sizeJobs.has(entry.path)) {
|
||||
return;
|
||||
}
|
||||
state.sizeJobs.set(entry.path, 'pending');
|
||||
createSizeJob(entry).catch((error) => {
|
||||
state.sizeJobs.delete(entry.path);
|
||||
showError(error);
|
||||
});
|
||||
}
|
||||
|
||||
function finishSizeJob(job) {
|
||||
state.sizeJobs.delete(job.source);
|
||||
if (job.status === 'completed' && job.result) {
|
||||
state.sizeResults.set(job.source, job.result);
|
||||
}
|
||||
recordDebug('size.finish', { id: job.id, source: job.source, status: job.status, result: job.result || null });
|
||||
updatePropertiesWindows();
|
||||
}
|
||||
|
||||
async function refreshAfterJob(job) {
|
||||
const refresh = state.jobRefresh.get(job.id);
|
||||
if (refresh?.done) {
|
||||
@@ -961,6 +1007,16 @@ function formatBytes(bytes) {
|
||||
return `${(value / 1024 / 1024 / 1024).toFixed(1)} GB`;
|
||||
}
|
||||
|
||||
function directorySizeLabel(entry) {
|
||||
const result = state.sizeResults.get(entry.path);
|
||||
if (!result) {
|
||||
return state.sizeJobs.has(entry.path) ? 'Berechne...' : 'Noch nicht berechnet';
|
||||
}
|
||||
const files = Number(result.files || 0);
|
||||
const directories = Math.max(0, Number(result.directories || 0) - 1);
|
||||
return `${formatBytes(result.size)} · ${files} Dateien · ${directories} Ordner`;
|
||||
}
|
||||
|
||||
function formatPrincipal(name, id) {
|
||||
if (name == null && id == null) return '-';
|
||||
if (name == null || String(name) === String(id)) return String(id);
|
||||
|
||||
Reference in New Issue
Block a user