diff --git a/core/server.js b/core/server.js index 1e86672..8855e9d 100644 --- a/core/server.js +++ b/core/server.js @@ -340,7 +340,9 @@ export async function createPithos(opts = {}) { const autoFlush = createAutoFlush({ settings: () => { const p = readPrefs(configFile); - return { enabled: p.autoFlush === true, minutes: p.autoFlushMinutes ?? DEFAULT_MINUTES }; + // On unless the user turned it off: files left in the buffer otherwise + // never reach Sia, and nobody expects to have to push them. + return { enabled: p.autoFlush !== false, minutes: p.autoFlushMinutes ?? DEFAULT_MINUTES }; }, // Only an s3d that is up can be asked; a stopped one just means no flush. stats: () => (daemon.state === 'starting' || daemon.state === 'stopping' diff --git a/ui/app.js b/ui/app.js index d807cc4..00bbf0e 100644 --- a/ui/app.js +++ b/ui/app.js @@ -255,6 +255,7 @@ function overview(main) { main.append( h('div', { class: 'page-head' }, h('div', {}, h('h1', {}, 'Overview'), h('p', { class: 'muted' }, 'Your s3d gateway and its upload pipeline to Sia.'))), banners, + pendingBanner(), h('div', { class: 'grid two' }, daemonCard, statsCard), ); @@ -1285,6 +1286,33 @@ function siaAccountBlock(a, onRefresh) { 'The same phrase approved from two different logins makes two different accounts; the same phrase from the same login is the same account, even on another computer.')); } +// "N files are waiting to upload to Sia" with Upload now. s3d holds small +// uploads until about 40 MB has built up; until then they exist only on this +// computer, which is easy to miss. +function pendingBanner() { + const el = h('div', { hidden: true }); + const st = daemonState(); + if (st !== 'running' && st !== 'external') return el; + Promise.all([api('GET', '/api/stats'), api('GET', '/api/autoflush').catch(() => null)]).then(([x, af]) => { + if (!x?.pendingObjects) return; + const n = x.pendingObjects; + const when = af?.enabled + ? (af.dueAt ? `They go up by themselves in about ${Math.max(1, Math.ceil((af.dueAt - Date.now()) / 60_000))} min if nothing new arrives.` : `They go up by themselves after ${af.minutes} min with no new uploads.`) + : 'They go up only when about 40 MB has built up, or when you upload them now.'; + const btn = h('button', { class: 'btn primary small', onclick: async () => { + btn.disabled = true; put(btn, h('span', { class: 'spinner' }), ' Uploading…'); + try { await api('POST', '/api/flush'); toast('Your files are on Sia'); el.hidden = true; } + catch (e) { fail(e); btn.disabled = false; put(btn, 'Upload now'); } + } }, 'Upload now'); + put(el, h('div', { class: 'banner info' }, + h('span', {}, h('strong', {}, `${n.toLocaleString()} file${n === 1 ? '' : 's'} (${fmtBytes(x.pendingSize)}) waiting to upload to Sia. `), + h('span', { class: 'small' }, `Until then they are only on this computer. ${when}`)), + btn)); + el.hidden = false; + }).catch(() => {}); + return el; +} + // The Accounts card at the top of the navigation: which Sia account this is // and how much room it has left. Refreshed at most every 30 s as pages change. let navAccountAt = 0; @@ -1331,7 +1359,7 @@ async function bucketList(head, body, user, userSel) { h('div', { class: 'row' }, userPicker(userSel), h('button', { class: 'btn primary', onclick: create }, 'New drive'))); const card = h('div', { class: 'card' }, h('p', { class: 'muted' }, 'Loading…')); const bar = h('div', { class: 'view-bar' }); - put(body, bar, card); + put(body, pendingBanner(), bar, card); const base = `/api/s3/${encodeURIComponent(user)}/buckets`; let mode = viewMode('drives', 'icons'); let list = [];