diff options
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)}> |