From 6828e64a256caea3c4e51829ae1aa09dfa725324 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Mon, 7 Sep 2026 00:33:51 +0200 Subject: fix(client): report a directory result under the button that caused it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Claude-Session: https://claude.ai/code/session_011pvMdvLBG92jyhvD5pD6us --- .../src/meshbay_hub/static/group-settings.js | 32 ++++++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'packages/meshbay-hub/src') 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` +

${msg.text}

`; 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`
- ${msg && html`

${msg}

`}

${t('settings_node.shared_directories_hint')}

${addControls} + ${message}
`; } return html`
- ${msg && html`

${msg}

`} @@ -340,6 +353,7 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn,
${addControls} + ${message} ${indexProgress && indexProgress.scanning && html`
-- cgit v1.2.3