feat: drag files between file panes (move or copy, SSH hosts too) and into a terminal of the same machine
This commit is contained in:
1 parent
a30b89f1d8
commit
f2740c50b4
12 files changed
+484
-32
No files matched your search
@@ -748,6 +748,31 @@
|
||||
$('mv-prog').hidden = !on;
|
||||
if (on) requestAnimationFrame(() => $('mv-prog').scrollIntoView({block: 'nearest', behavior: 'smooth'}));
|
||||
}
|
||||
// followJob waits for a transfer job to end, telling onProgress how far
|
||||
// it has got (the progress and a line about it), and gives its result.
|
||||
async function followJob(job, onProgress) {
|
||||
let v = 0;
|
||||
const seen = [];
|
||||
for (;;) {
|
||||
let j;
|
||||
try { j = await fetch('/api/panel/fs/job/' + job + '?v=' + v, {cache: 'no-store'}).then(x => x.json()); }
|
||||
catch (e) { await new Promise(ok => setTimeout(ok, 1500)); continue; }
|
||||
v = j.v || 0;
|
||||
const p = j.progress || {};
|
||||
let text = '';
|
||||
if (p.total > 0 || p.done > 0) {
|
||||
// Speed over the last few seconds.
|
||||
seen.push([Date.now(), p.done]);
|
||||
while (seen.length > 2 && Date.now() - seen[0][0] > 4000) seen.shift();
|
||||
const dt = (seen[seen.length - 1][0] - seen[0][0]) / 1000, rate = dt > 0.5 ? (seen[seen.length - 1][1] - seen[0][1]) / dt : 0;
|
||||
text = fmtSize(p.done) + ' из ' + fmtSize(p.total) + ' · файлов: ' + p.files + (rate ? ' · ' + fmtSize(Math.round(rate)) + '/с' : '');
|
||||
} else if (p.note) {
|
||||
text = p.note === 'подсчёт' ? 'подсчёт…' : p.note + '…';
|
||||
}
|
||||
onProgress(p, text);
|
||||
if (j.done) return j.result || {ok: false, error: 'ошибка'};
|
||||
}
|
||||
}
|
||||
// ship sends to the other machine and follows the job to its end.
|
||||
async function ship(dir, name, conflict, move) {
|
||||
const body = {src: M.src, name, dir, conflict, move};
|
||||
@@ -771,27 +796,14 @@
|
||||
$('mv-pw').value = ''; $('mv-pass').value = '';
|
||||
if (!r.ok) { busy(false); toast(r.error || 'ошибка', true); return; }
|
||||
const job = M.job = r.data.job;
|
||||
let v = 0, res = null;
|
||||
const t0 = Date.now(), seen = [];
|
||||
while (!res) {
|
||||
let j;
|
||||
try { j = await fetch('/api/panel/fs/job/' + job + '?v=' + v, {cache: 'no-store'}).then(x => x.json()); }
|
||||
catch (e) { await new Promise(ok => setTimeout(ok, 1500)); continue; }
|
||||
v = j.v || 0;
|
||||
const p = j.progress || {};
|
||||
const t0 = Date.now();
|
||||
const res = await followJob(job, (p, text) => {
|
||||
if (p.total > 0 || p.done > 0) {
|
||||
$('mv-bar').parentNode.classList.remove('wait');
|
||||
$('mv-bar').style.width = (p.total ? Math.min(100, p.done / p.total * 100) : 0).toFixed(1) + '%';
|
||||
// Speed over the last few seconds.
|
||||
seen.push([Date.now(), p.done]);
|
||||
while (seen.length > 2 && Date.now() - seen[0][0] > 4000) seen.shift();
|
||||
const dt = (seen[seen.length - 1][0] - seen[0][0]) / 1000, rate = dt > 0.5 ? (seen[seen.length - 1][1] - seen[0][1]) / dt : 0;
|
||||
$('mv-ptext').textContent = fmtSize(p.done) + ' из ' + fmtSize(p.total) + ' · файлов: ' + p.files + (rate ? ' · ' + fmtSize(Math.round(rate)) + '/с' : '');
|
||||
} else if (p.note) {
|
||||
$('mv-ptext').textContent = p.note === 'подсчёт' ? 'подсчёт…' : p.note + '…';
|
||||
}
|
||||
if (j.done) res = j.result;
|
||||
}
|
||||
if (text) $('mv-ptext').textContent = text;
|
||||
});
|
||||
M.job = null;
|
||||
if (!res.ok) { busy(false); toast(res.error || 'ошибка', true); return; }
|
||||
$('mv-bar').style.width = '100%';
|
||||
@@ -927,6 +939,6 @@
|
||||
del: (pane, e) => use(pane, del)(e),
|
||||
uploads(pane) { upPane = pane; openModal($('updlg')); renderUploadList(); },
|
||||
uploadsChanged(pane) { if (pane === upPane) renderUploadList(); },
|
||||
sendFile, toast, openModal, join, parent, fmtSize, fmtTime, esc, b64ToBytes
|
||||
sendFile, followJob, toast, openModal, join, parent, fmtSize, fmtTime, esc, b64ToBytes
|
||||
};
|
||||
})();
|
||||
Reference in new issue
Block a user