aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/static/group-page.js
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-10 17:23:40 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-10 17:23:40 +0200
commit1dcedc77083b908b7b3b431bad679a4813884355 (patch)
treedb6ae06c05e5f337aeb42dde5c7bd2a7fe9444b5 /packages/meshbay-hub/src/meshbay_hub/static/group-page.js
parent6964ff112fec47498ed778a491cf2a1490392c79 (diff)
downloadmeshbay-1dcedc77083b908b7b3b431bad679a4813884355.tar.gz
refactor(mnp)!: one answer to "may this member write", and it is the root
The group-wide `member_upload` switch is gone: the message, the signed operation, the field on the handshake ack, the `upload` alias on every root in the index payload, and the client's fallback path to it. Whether a member may write has been a property of each root for a while, and that is the model that survives: a single flag over the group cannot express "this library is published read-only and that folder is a drop box", which is the ordinary arrangement. What was left of the switch was a handler that logged a deprecation and acted on nothing, and a client that read `ack.member_upload` whenever the roots carried no `writable` — a second source for one question, with whichever the code consulted first deciding it. `roots.describe()` drops `upload` for the same reason: it was `writable` under an older name, and two names for one boolean is one too many. The paperclip now says "nowhere to write" rather than picking a root, in a group that has none writable. That is the honest answer; the fallback picked whatever came first and failed at send time. Node suite 1215 passed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AsoWC3GmhNdwVFomW3QjH3
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/group-page.js')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/group-page.js21
1 files changed, 3 insertions, 18 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/group-page.js b/packages/meshbay-hub/src/meshbay_hub/static/group-page.js
index 1b7ed53..0f442cf 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/group-page.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/group-page.js
@@ -98,11 +98,6 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs,
const [nodeRoots, setNodeRoots] = useState([]);
const [isNodeAdmin, setIsNodeAdmin] = useState(false);
- // Legacy: the group-wide upload switch a node speaking MNP 1.0 sends on its
- // handshake ack. Per-root `writable` replaced it, and this is read only when
- // the roots carry no flags at all — see `attachRoot` below. Defaults to true
- // so such a node behaves as it always did.
- const [memberUpload, setMemberUpload] = useState(true);
// Which applications this group has enabled, from the node. Falls back to
// every registered app when a node predates the setting (or hasn't answered
// yet), so nothing disappears for an existing group.
@@ -350,7 +345,6 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs,
session.pendingJoinCode = null;
if (cancelled) return;
setIsNodeAdmin(!!ack.is_node_admin);
- setMemberUpload(ack.member_upload !== false);
setEnabledApps(ack.enabled_apps || null);
setScanSettings(ack.scan_settings || null);
setTmdbConfig({
@@ -377,10 +371,6 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs,
setMusicbrainzConfig({
enabled: ack.musicbrainz_enabled !== false,
});
- // Changed while we are connected, by an operator who may be someone
- // else entirely. Without this the button stays until a reconnection,
- // and a button that is still there is a button people press.
- transport.onUploadPolicy = (allowed) => setMemberUpload(allowed);
transport.onAppsEnabled = (apps) => setEnabledApps(apps);
// Two independent acks now (tmdb_config_ack: token/language,
// node-wide; tmdb_enabled_ack: the per-group switch) — each merges
@@ -612,14 +602,9 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs,
// the same rule the node applies when a client names no root at all. It
// becomes an operator-chosen directory in phase 2 (refactor-groups.md §1.7).
//
- // `memberUpload` is the fallback for a node still speaking MNP 1.0, whose
- // roots carry no `writable` at all: there, the single upload root is the one
- // the node marked, and the ack's computed flag is all we get.
const writableRoots = useMemo(
() => nodeRoots.filter((r) => r.writable && r.available !== false),
[nodeRoots]);
- const legacyNode = nodeRoots.length > 0
- && nodeRoots.every((r) => r.writable === undefined);
// The operator's chosen attachment folder wins where there is one — that is
// what the Chat settings pane is for. Its root has to be writable and
// present, or the choice is stale (they made it read-only, or ejected the
@@ -628,11 +613,11 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs,
const chatDirUsable = Boolean(
chatDirRoot && writableRoots.some((r) => r.name === chatDirRoot));
const attachDir = chatDirUsable ? chatDirectory : '';
+ // Nowhere to write is a real answer: the paperclip says so rather than
+ // picking a read-only root and failing at send time.
const attachRoot = chatDirUsable ? chatDirRoot
: writableRoots.length ? writableRoots[0].name
- : (legacyNode && memberUpload
- ? (nodeRoots.find((r) => r.upload) || nodeRoots[0]).name
- : '');
+ : '';
// A single dispatcher so any app can open the right modal without owning
// video/preview state itself — Files' table and Chat's attachments both