diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-10-12 00:17:32 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-10-12 00:17:32 +0200 |
| commit | 14911aae21ec4975f7a805b91e3c4867cb41974b (patch) | |
| tree | 8c00230a88053905fd77938f3a9539efeb4c3094 /packages/meshbay-hub/src/meshbay_hub/static/group-settings.js | |
| parent | f6f107e02c7a4aa7326c9a82310a239327d81ed6 (diff) | |
| download | meshbay-14911aae21ec4975f7a805b91e3c4867cb41974b.tar.gz | |
feat: let the operator pause and resume a root's indexing (MNP 6.2)
A whole-root walk now checks its root before every file: removed or
ejected, it stops instead of reading the drive to the end; paused, it
finishes from the hash cache alone. A paused root is not watched, not
swept by reconcile and survives a restart (roster), its indexed files
stay served. Resume runs the reconcile sweep over the root, so entries
and their enrichment are kept.
Signed root_pause / root_resume over MNP, loopback routes, CLI
`root pause|resume`, a pause button on the indexing dock and
pause/resume in the roots table of Group settings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/group-settings.js')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/group-settings.js | 31 |
1 files changed, 27 insertions, 4 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 1a367be..a666c29 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,9 @@ async function readLocalNode(node, groupId, attempts = NODE_CHECK_ATTEMPTS, * mode="live" — a hosted group. What widens the node's sharing — adding * a directory, its `writable` and `removable` switches — goes * through the loopback API only, so only on the node's own - * machine. Removing, ejecting and plugging are signed ops - * over MNP, or the loopback API when there is no connection. + * machine. Removing, ejecting, plugging, pausing and + * resuming are signed ops over MNP, or the loopback API when + * there is no connection. * mode="local" — the wizard, before the group exists. Changes are held in * an array the caller owns; nothing is persisted until the * group is attached. @@ -72,7 +73,7 @@ async function readLocalNode(node, groupId, attempts = NODE_CHECK_ATTEMPTS, * * Props: * roots — the node's current roots: { name, path, writable, - * removable, ejected, available, kind } + * removable, ejected, paused, available, kind } * groupId — the group id * transport — MeshBayTransport instance, or null when not connected * signFn — signing function for admin ops @@ -153,7 +154,7 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, // signature proves that the operator's key signed, not that the operator // meant it: in a browser that key is driven by code the hub serves. // - // Narrowing — remove, eject, plug — MNP first, then loopback. + // Narrowing — remove, eject, plug, pause, resume — MNP first, then loopback. const overMnp = !isLocal && transport && transport.connected; const overLoopback = !isLocal && !overMnp && nodeAvail; const onNodeMachine = !isLocal && nodeAvail; @@ -220,6 +221,18 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, else throw new Error(t('node.root_no_route')); }), [overMnp, overLoopback, transport, groupId, signFn, run]); + const doPauseRoot = useCallback((rootName) => run(async () => { + if (overMnp) await transport.pauseRoot(groupId, rootName, signFn); + else if (overLoopback) await platform.node.op('pauseRoot', { groupId, rootName }); + else throw new Error(t('node.root_no_route')); + }), [overMnp, overLoopback, transport, groupId, signFn, run]); + + const doResumeRoot = useCallback((rootName) => run(async () => { + if (overMnp) await transport.resumeRoot(groupId, rootName, signFn); + else if (overLoopback) await platform.node.op('resumeRoot', { groupId, rootName }); + else throw new Error(t('node.root_no_route')); + }), [overMnp, overLoopback, transport, groupId, signFn, run]); + const doRemoveRoot = useCallback(async (rootName) => { if (isLocal) { if (onLocalRootsChange) { @@ -321,6 +334,8 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, <span class="node-root-badge node-root-badge-warn">${t('group.root_ejected')}</span>`} ${!isLocal && r.available === false && !r.ejected && html` <span class="node-root-badge node-root-badge-warn">${t('node.unavailable')}</span>`} + ${!isLocal && r.paused && html` + <span class="node-root-badge">${t('node.root_paused')}</span>`} </td> ${hasPaths && html` <td class="sdt-col-path" title=${r.path || ''}>${r.path || ''}</td>`} @@ -347,6 +362,14 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, `} <td class="sdt-col-actions"> ${canEdit && !isLocal && html` + <button class="sdt-action-btn" disabled=${busy || !!r.ejected} + title=${r.paused ? t('node.root_resume') : t('node.root_pause')} + aria-label=${r.paused ? t('node.root_resume') : t('node.root_pause')} + onClick=${() => r.paused ? doResumeRoot(r.name) : doPauseRoot(r.name)}> + <${Icon} name=${r.paused ? 'play' : 'pause'} /> + </button> + `} + ${canEdit && !isLocal && html` <button class="sdt-action-btn" disabled=${busy || !r.removable} title=${r.ejected ? t('group.root_plug') : t('group.root_eject')} onClick=${() => r.ejected ? doPlugRoot(r.name) : doEjectRoot(r.name)}> |