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-14 11:17:42 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-14 11:17:42 +0200
commit2fb66c5baecdd8b49be904f6244f66ba04f68061 (patch)
tree3b80940e1819a811f6ec2c04831e3616a74a8eae /packages/meshbay-hub/src/meshbay_hub/static/group-page.js
parenta294c1d338ba4c20d66873d593d1c101e69c5a40 (diff)
downloadmeshbay-2fb66c5baecdd8b49be904f6244f66ba04f68061.tar.gz
feat(ui): an indexing dock above the music bar, on every page
Adding a large directory left the operator nothing to look at once they left the Settings panel that started it, and nothing at all when it was added from another machine. A band now sits above the music bar on every page: one row per group with indexing under way, naming the root being walked, percent, bytes and files, and the roots waiting their turn; "indexing finished" for a few seconds at the end. A click opens the group's Settings, and × hides the row until that group is idle. Two sources feed it. On the node's own machine the desktop client polls the loopback `GET /api/index-status` for every group, whatever the route. An operator's group page forwards MNP `index_progress` pushes, resolving the root from the roots table it opened; an ordinary member keeps the sidebar dot only, and a page clears its row when it lets go of the group. Where both describe a group, loopback wins. Reconcile passes and watchdog bursts show only past 1 GB or 5 s, so a single dropped file does not flash a bar. The logic lives in index-dock-model.js, which has no imports and is tested under node. The dock publishes `--index-dock-h` and the sidebar stops above it and the music bar. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T6jPTeocXA1BePekdsgPya
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.js26
1 files changed, 21 insertions, 5 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 18d3a8f..0f28adf 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/group-page.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/group-page.js
@@ -15,6 +15,7 @@ import { useStickyBand } from './sticky.js';
import { FilePreview } from './files-app.js';
import { VideoPlayer } from './video-player.js';
import { GroupSettingsPanel } from './group-settings.js';
+import { reportIndexPush } from './index-dock.js';
/**
* The group shell: everything a group's "applications" (Chat, Files, and
@@ -96,6 +97,9 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs,
// unplugged keeps its files listed — they are frozen, not deleted — so this is
// the only thing that lets the UI say which of the two it is.
const [nodeRoots, setNodeRoots] = useState([]);
+ // Read by the index_progress handler, which connect() installs once.
+ const nodeRootsRef = useRef(nodeRoots);
+ nodeRootsRef.current = nodeRoots;
const [isNodeAdmin, setIsNodeAdmin] = useState(false);
// Which applications this group has enabled, from the node. Falls back to
@@ -430,11 +434,18 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs,
// False transition (daemon.py _progress_pusher), so this always
// settles back to 'online' rather than getting stuck.
transport.onIndexProgress = (status) => {
- if (cancelled || !onPresence) return;
- const pct = status.total_bytes
- ? Math.min(100, Math.round(100 * status.scanned_bytes / status.total_bytes))
- : 0;
- onPresence(groupId, status.scanning ? 'indexing' : 'online', pct);
+ if (cancelled) return;
+ if (onPresence) {
+ const pct = status.total_bytes
+ ? Math.min(100, Math.round(100 * status.scanned_bytes / status.total_bytes))
+ : 0;
+ onPresence(groupId, status.scanning ? 'indexing' : 'online', pct);
+ }
+ // The operator's indexing dock. The push names no root, so the
+ // page that opened the roots table names it.
+ if (transport.memberRole === 'operator') {
+ reportIndexPush(groupId, status, nodeRootsRef.current);
+ }
};
setOperatorPaired(transport.memberRole === 'operator');
@@ -503,6 +514,9 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs,
onPresence(groupId, 'online');
}
}
+ if (transport.memberRole === 'operator' && ack.indexing) {
+ reportIndexPush(groupId, ack.indexing, indexMsg.roots || nodeRootsRef.current);
+ }
} catch (err) {
if (cancelled) return;
@@ -554,6 +568,8 @@ function GroupPage({ groupId, group, token, username, userId, userPrefs,
return () => {
cancelled = true;
+ // Nothing will update this group's dock row once the page lets go of it.
+ reportIndexPush(groupId, null);
if (transportRef.current) {
// Handed over rather than closed: a download running when you leave the
// group keeps its connection, and the last transfer using it closes it.