aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/static/node-page.js
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/node-page.js')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/node-page.js111
1 files changed, 67 insertions, 44 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/node-page.js b/packages/meshbay-hub/src/meshbay_hub/static/node-page.js
index 2a0b0d7..ec73128 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/node-page.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/node-page.js
@@ -47,21 +47,35 @@ function NodeServicePanel({ onChanged }) {
}
}, [refresh, onChanged]);
- const toggleAutostart = useCallback(() => {
- act('autostart', () => (info && info.autostart
- ? platform.node.autostart.remove()
- : platform.node.autostart.install()));
- }, [act, info]);
+ // "off" / "signin" / "service" -- derived from the status payload, no new
+ // backend field needed: mode/autostart already distinguish all three.
+ const startupMode = (i) => {
+ if (!i) return 'off';
+ if (i.mode === 'service') return i.mode;
+ return i.autostart ? 'signin' : 'off';
+ };
// Switching mode itself — the installer's own choice is effectively one-shot
// (it skips the question once the firewall rules exist for any reason, and
// per-user mode sets those up on its own with no Scheduled Task), so this is
// the only way back in if service mode was declined, or out if it is no
// longer wanted. One elevation, task + firewall together, same script.
- const toggleServiceMode = useCallback(() => {
- act('serviceMode', () => (info && info.mode === 'service'
- ? platform.node.serviceMode.remove()
- : platform.node.serviceMode.install()));
+ //
+ // The two mechanisms are mutually exclusive by construction here: never
+ // both installed at once, which would start the daemon twice (once at
+ // boot via the Scheduled Task, again at sign-in via the Startup .vbs).
+ // Always remove whichever one is currently active before installing the
+ // target, so every transition -- not just the two that used to be
+ // separate toggles -- keeps that invariant.
+ const changeStartupMode = useCallback((target) => {
+ const current = startupMode(info);
+ if (target === current) return;
+ act('startupMode', async () => {
+ if (current === 'service') await platform.node.serviceMode.remove();
+ else if (current === 'signin') await platform.node.autostart.remove();
+ if (target === 'service') await platform.node.serviceMode.install();
+ else if (target === 'signin') await platform.node.autostart.install();
+ });
}, [act, info]);
if (!platform.node.service.available) return null;
@@ -79,44 +93,53 @@ function NodeServicePanel({ onChanged }) {
const label = info.installed ? t('node.service_state_' + stateKey)
: t('node.service_not_installed');
+ // Own row, below the status/actions card rather than a further item
+ // crammed into its flex-wrap line -- that (plus two independent toggles
+ // for what is really one choice) is what made this a mess before.
+ const showStartupRow = (platform.node.autostart.available
+ || platform.node.serviceMode.available) && typeof info.mode === 'string';
+
return html`
- <div class="node-service">
- <div class="node-service-status">
- <span class="presence presence-${dot}" title="${label}" aria-label="${label}"></span>
- <span>${label}</span>
- </div>
- ${err && html`<div class="error-msg">${err}</div>`}
- <div class="node-service-actions">
- <button class="btn btn-small btn-secondary" disabled=${!!busy || running}
- onClick=${() => act('start', () => platform.node.start())}>
- ${busy === 'start' ? t('node.service_starting') : t('node.service_start')}</button>
- ${info.installed && html`
- <button class="btn btn-small btn-secondary" disabled=${!!busy || !running}
- onClick=${() => act('stop', () => platform.node.service.stop())}>
- ${busy === 'stop' ? t('node.service_stopping') : t('node.service_stop')}</button>
- <button class="btn btn-small btn-secondary" disabled=${!!busy}
- onClick=${() => act('restart', () => platform.node.service.restart())}>
- ${busy === 'restart' ? t('node.service_restarting') : t('node.service_restart')}</button>
+ <div>
+ <div class="node-service">
+ <div class="node-service-status">
+ <span class="presence presence-${dot}" title="${label}" aria-label="${label}"></span>
+ <span>${label}</span>
+ </div>
+ ${err && html`<div class="error-msg">${err}</div>`}
+ <div class="node-service-actions">
+ <button class="btn btn-small btn-secondary" disabled=${!!busy || running}
+ onClick=${() => act('start', () => platform.node.start())}>
+ ${busy === 'start' ? t('node.service_starting') : t('node.service_start')}</button>
+ ${info.installed && html`
+ <button class="btn btn-small btn-secondary" disabled=${!!busy || !running}
+ onClick=${() => act('stop', () => platform.node.service.stop())}>
+ ${busy === 'stop' ? t('node.service_stopping') : t('node.service_stop')}</button>
+ <button class="btn btn-small btn-secondary" disabled=${!!busy}
+ onClick=${() => act('restart', () => platform.node.service.restart())}>
+ ${busy === 'restart' ? t('node.service_restarting') : t('node.service_restart')}</button>
+ `}
+ </div>
+ ${info.mode === 'service' && html`
+ <p class="node-hint">${t('node.service_mode_hint')}</p>
`}
</div>
- ${info.mode === 'service' && html`
- <p class="node-hint">${t('node.service_mode_hint')}</p>
- `}
- ${platform.node.autostart.available && typeof info.autostart === 'boolean' && html`
- <label class="toggle-switch ${busy ? 'toggle-switch-disabled' : ''}">
- <input type="checkbox" checked=${info.autostart} disabled=${!!busy}
- onChange=${toggleAutostart} />
- <span class="toggle-switch-track"><span class="toggle-switch-thumb"></span></span>
- ${' '}${busy === 'autostart' ? t('node.autostart_updating') : t('node.autostart_label')}
- </label>
- `}
- ${platform.node.serviceMode.available && typeof info.mode === 'string' && html`
- <label class="toggle-switch ${busy ? 'toggle-switch-disabled' : ''}">
- <input type="checkbox" checked=${info.mode === 'service'} disabled=${!!busy}
- onChange=${toggleServiceMode} />
- <span class="toggle-switch-track"><span class="toggle-switch-thumb"></span></span>
- ${' '}${busy === 'serviceMode' ? t('node.service_mode_updating') : t('node.service_mode_label')}
- </label>
+ ${showStartupRow && html`
+ <div class="settings-row">
+ <span class="settings-label">${t('node.startup_mode_label')}</span>
+ <select class="settings-select" disabled=${!!busy}
+ value=${startupMode(info)}
+ onChange=${(e) => changeStartupMode(e.target.value)}>
+ <option value="off">${t('node.startup_mode_off')}</option>
+ <option value="signin">${t('node.startup_mode_signin')}</option>
+ <option value="service" disabled=${!info.canElevate}>
+ ${t('node.startup_mode_service')}</option>
+ </select>
+ </div>
+ ${busy === 'startupMode' && html`
+ <p class="settings-hint">${t('node.startup_mode_updating')}</p>`}
+ ${!info.canElevate && html`
+ <p class="settings-hint">${t('node.startup_mode_service_unavailable_hint')}</p>`}
`}
</div>`;
}