diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-07 00:33:51 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-07 00:33:51 +0200 |
| commit | 6828e64a256caea3c4e51829ae1aa09dfa725324 (patch) | |
| tree | 23d93fdb473fbcbded12bc9b68a4006aed5ce0df /packages/meshbay-hub/src/meshbay_hub/static | |
| parent | 80ca7dd0765a6c08fa5ea54c2e14972bba6fa564 (diff) | |
| download | meshbay-6828e64a256caea3c4e51829ae1aa09dfa725324.tar.gz | |
fix(client): report a directory result under the button that caused it
The message was the first thing in the section, wedged between the intro and
the table header — above everything the eye has already moved past by the time
it appears. It goes last now, under Add directory.
And it was a `settings-hint`: dim grey body text. So "two roots would both be
called uploads" read as a footnote about the section rather than as the reason
nothing happened. A refusal is styled as one and carries `role="alert"`, so it
is announced rather than only drawn; a success stays quiet.
Measured in a real Electron window rather than assumed — the failing add
driven through the typed-path form, then the message's box compared against the
table's and the button's.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011pvMdvLBG92jyhvD5pD6us
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/group-settings.js | 32 |
1 files changed, 23 insertions, 9 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js b/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js index 9646405..6c6f3d9 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js @@ -55,8 +55,22 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, const isLocal = mode === 'local'; const serverRoots = isLocal ? (localRoots || []) : (roots || []); const [busy, setBusy] = useState(false); - const [msg, setMsg] = useState(''); + // `{ text, error }` — a refusal has to look like one. Every message here was + // a `settings-hint`, which is dim grey body text, so "two roots would both + // be called uploads" read as a footnote to the section rather than as the + // reason nothing happened. + const [msg, setMsg] = useState(null); const [indexProgress, setIndexProgress] = useState(null); + const say = useCallback((text) => setMsg(text ? { text, error: false } : null), []); + const refuse = useCallback((text) => setMsg({ text, error: true }), []); + + // Rendered at the foot of the section, under the Add button — the last thing + // below the control that caused it, rather than above a table the eye has + // already moved past. + const message = !msg ? '' : html` + <p class=${msg.error ? 'error-msg' : 'settings-hint'} + role=${msg.error ? 'alert' : 'status'} + style="margin-top:10px">${msg.text}</p>`; const [pathDraft, setPathDraft] = useState(''); const [addingByPath, setAddingByPath] = useState(false); @@ -120,16 +134,16 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, // the delta the node pushes when the scan finishes carries it again along // with the files. const run = useCallback(async (work) => { - setBusy(true); setMsg(''); + setBusy(true); setMsg(null); try { await work(); if (onRootsChange) await onRootsChange(); return true; } catch (err) { - setMsg(platform.bridgeMessage(err)); + refuse(platform.bridgeMessage(err)); return false; } finally { setBusy(false); } - }, [onRootsChange]); + }, [onRootsChange, refuse]); const doUpdateRoot = useCallback(async (rootName, updates) => { if (isLocal) { @@ -184,7 +198,7 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, await platform.node.call('POST', '/api/reload'); } else throw new Error(t('node.root_no_route')); }); - if (ok) setMsg(t('node.root_removed')); + if (ok) say(t('node.root_removed')); }, [isLocal, localRoots, onLocalRootsChange, overMnp, overLoopback, transport, groupId, signFn, run]); @@ -223,7 +237,7 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, const chosen = await platform.rootPicker.choose(); if (!chosen) return; const ok = await addRootAtPath(chosen.path, chosen.name); - if (ok && !isLocal) setMsg(t('node.root_added')); + if (ok && !isLocal) say(t('node.root_added')); }, [addRootAtPath, isLocal]); const doAddByPath = useCallback(async () => { @@ -233,7 +247,7 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, // duplicate. Sending one guessed from a string typed here would be a // second opinion about something already decided in one place. const ok = await addRootAtPath(path, ''); - if (ok) { setPathDraft(''); setAddingByPath(false); if (!isLocal) setMsg(t('node.root_added')); } + if (ok) { setPathDraft(''); setAddingByPath(false); if (!isLocal) say(t('node.root_added')); } }, [pathDraft, addRootAtPath, isLocal]); const addControls = !canEdit ? '' : html` @@ -267,16 +281,15 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, if (!displayRoots.length) { return html` <div class="shared-directories-table"> - ${msg && html`<p class="settings-hint">${msg}</p>`} <p class="settings-hint">${t('settings_node.shared_directories_hint')}</p> ${addControls} + ${message} </div> `; } return html` <div class="shared-directories-table"> - ${msg && html`<p class="settings-hint">${msg}</p>`} <table class="shared-dirs-tbl"> <thead> <tr> @@ -340,6 +353,7 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, </tbody> </table> ${addControls} + ${message} ${indexProgress && indexProgress.scanning && html` <div class="index-progress" style="margin-top:8px"> <div class="index-progress-bar"> |