aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/meshbay-client/src/main.js99
-rw-r--r--packages/meshbay-client/src/tray-icon.pngbin415 -> 504 bytes
-rw-r--r--packages/meshbay-client/src/tray-icon@2x.pngbin755 -> 967 bytes
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/app.js5
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/icon.js7
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/de.js2
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/en.js2
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/es.js2
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js2
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/it.js2
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js2
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js2
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js2
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js2
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js2
15 files changed, 105 insertions, 26 deletions
diff --git a/packages/meshbay-client/src/main.js b/packages/meshbay-client/src/main.js
index 71b56be..273d151 100644
--- a/packages/meshbay-client/src/main.js
+++ b/packages/meshbay-client/src/main.js
@@ -339,6 +339,19 @@ let mainWindow = null;
// files are the interface's, the main process has no i18n, and a second string
// table is how two of them start disagreeing.
let tray = null;
+let trayLabels = null;
+let trayTimer = null;
+let nodeService = null; // assigned by registerBridge()
+
+const TRAY_FALLBACK = {
+ show: 'Show MeshBay', quit: 'Quit',
+ start_node: 'Start the node', stop_node: 'Stop the node',
+};
+
+// libappindicator offers no "menu is about to open" event, so a menu built once
+// would show a stale Start/Stop for as long as the app runs. `systemctl --user
+// show` is a few milliseconds and this only ticks while an indicator exists.
+const TRAY_POLL_MS = 5000;
function showFromTray() {
if (!mainWindow) return;
@@ -347,18 +360,51 @@ function showFromTray() {
mainWindow.focus();
}
+async function buildTrayMenu() {
+ const text = { ...TRAY_FALLBACK, ...(trayLabels || {}) };
+ const items = [{ label: text.show, click: showFromTray }];
+
+ // Only when there is a daemon to act on: not installed means no entry at all,
+ // rather than a control that reports failure when used.
+ let status = null;
+ try {
+ status = nodeService ? await nodeService.status() : null;
+ } catch {
+ status = null; // unreadable state is the same as no control
+ }
+ if (status && status.supported && status.installed) {
+ const running = status.activeState === 'active';
+ items.push({ type: 'separator' });
+ items.push({
+ label: running ? text.stop_node : text.start_node,
+ click: async () => {
+ try {
+ // `restart` starts a stopped unit, which is what systemd's restart
+ // means; there is no separate start verb to call.
+ if (running) await nodeService.stop();
+ else await nodeService.restart();
+ } catch (err) {
+ console.error('[MeshBay] tray: node action failed', err);
+ }
+ refreshTrayMenu(); // reflect the new state without waiting a tick
+ },
+ });
+ }
+
+ items.push({ type: 'separator' },
+ { label: text.quit, click: () => app.quit() });
+ return Menu.buildFromTemplate(items);
+}
+
+async function refreshTrayMenu() {
+ if (!tray) return;
+ tray.setContextMenu(await buildTrayMenu());
+}
+
function ensureTray(labels) {
- const text = {
- show: (labels && labels.show) || 'Show MeshBay',
- quit: (labels && labels.quit) || 'Quit',
- };
+ if (labels) trayLabels = labels; // the person may have changed language
if (tray) {
- // Relabel in place: the person may have changed language since it was made.
- tray.setContextMenu(Menu.buildFromTemplate([
- { label: text.show, click: showFromTray },
- { type: 'separator' },
- { label: text.quit, click: () => app.quit() },
- ]));
+ refreshTrayMenu();
return tray;
}
// In src/, not build/: electron-builder packages only `src/**` and `ui/**`
@@ -366,17 +412,13 @@ function ensureTray(labels) {
// missing from every installed one.
tray = new Tray(path.join(__dirname, 'tray-icon.png'));
tray.setToolTip('MeshBay');
- tray.setContextMenu(Menu.buildFromTemplate([
- { label: text.show, click: showFromTray },
- { type: 'separator' },
- { label: text.quit, click: () => app.quit() },
- ]));
+ refreshTrayMenu();
// Harmless where it does nothing (GNOME), useful on desktops that do send it.
tray.on('click', showFromTray);
+ if (!trayTimer) trayTimer = setInterval(refreshTrayMenu, TRAY_POLL_MS);
return tray;
}
-
function createWindow() {
const bounds = (config.window && config.window.width) ? config.window : {
width: 1200, height: 800,
@@ -1073,7 +1115,16 @@ function registerBridge() {
// of the Node page. Deliberately not `probeNode()`: that asks the daemon's
// own HTTP API, which cannot answer while the daemon is stopped or crash-
// looping — exactly the states this panel exists to show and act on.
- ipcMain.handle('node:service-status', async () => {
+ // The tray menu drives the same daemon controls as the Node page. Declared
+ // here because these close over registerBridge's helpers; the tray is created
+ // long after, so it reads them through this binding rather than duplicating
+ // the systemctl and Task Scheduler branches.
+ nodeService = { status: nodeServiceStatus, stop: nodeServiceStop,
+ restart: nodeServiceRestart };
+
+ ipcMain.handle('node:service-status', () => nodeServiceStatus());
+
+ async function nodeServiceStatus() {
if (process.platform === 'win32') {
const svc = await winServiceTaskStatus();
if (svc.installed) {
@@ -1133,9 +1184,11 @@ function registerBridge() {
});
});
});
- });
+ }
- ipcMain.handle('node:service-stop', async () => {
+ ipcMain.handle('node:service-stop', () => nodeServiceStop());
+
+ async function nodeServiceStop() {
if (process.platform === 'win32') {
const svc = await winServiceTaskStatus();
if (svc.installed) await winServiceTaskEnd();
@@ -1154,9 +1207,11 @@ function registerBridge() {
});
});
return { stopped: true };
- });
+ }
- ipcMain.handle('node:service-restart', async () => {
+ ipcMain.handle('node:service-restart', () => nodeServiceRestart());
+
+ async function nodeServiceRestart() {
if (process.platform === 'win32') {
const svc = await winServiceTaskStatus();
if (svc.installed) await winServiceTaskEnd();
@@ -1181,7 +1236,7 @@ function registerBridge() {
});
});
return { restarted: true };
- });
+ }
// Install / remove the Windows Startup-folder launcher, and query it.
ipcMain.handle('node:autostart', async (_e, action) => {
diff --git a/packages/meshbay-client/src/tray-icon.png b/packages/meshbay-client/src/tray-icon.png
index 394604d..98fd63b 100644
--- a/packages/meshbay-client/src/tray-icon.png
+++ b/packages/meshbay-client/src/tray-icon.png
Binary files differ
diff --git a/packages/meshbay-client/src/tray-icon@2x.png b/packages/meshbay-client/src/tray-icon@2x.png
index 3e533fb..9cf613d 100644
--- a/packages/meshbay-client/src/tray-icon@2x.png
+++ b/packages/meshbay-client/src/tray-icon@2x.png
Binary files differ
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js
index 5857821..c7e46d8 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/app.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js
@@ -244,8 +244,9 @@ function Nav({ user, theme, onThemeChange, onLogout, onMenuToggle, unreadCount,
<div class="nav-right">
${user && html`<${TransferWidget} />`}
${platform.capabilities.tray && html`
- <button class="nav-tray" onClick=${() => platform.minimizeToTray(
- { show: t('tray.show'), quit: t('tray.quit') })}
+ <button class="nav-tray" onClick=${() => platform.minimizeToTray({
+ show: t('tray.show'), quit: t('tray.quit'),
+ start_node: t('tray.start_node'), stop_node: t('tray.stop_node') })}
title=${t('nav.minimize_tray')} aria-label=${t('nav.minimize_tray')}>
<${Icon} name="tray" />
</button>
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/icon.js b/packages/meshbay-hub/src/meshbay_hub/static/icon.js
index 79a3a08..90d9194 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/icon.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/icon.js
@@ -13,8 +13,11 @@ import { html } from './vendor/htm-preact.js';
const ICON_PATHS = {
menu: ['M4 7h16M4 12h16M4 17h16'],
- tray: ['M12 3.5v9', 'M8.5 9l3.5 3.5L15.5 9',
- 'M4 15v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3'],
+ // A window with a chevron folding into it. Deliberately no shaft: a
+ // vertical stem above a receptacle is the download glyph, and the first
+ // attempt here read as one.
+ tray: ['M6 4h12a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V7a3 3 0 0 1 3-3z',
+ 'M8 10l4 4 4-4'],
bell: ['M18 9a6 6 0 1 0-12 0c0 6-2.5 7.5-2.5 7.5h17S18 15 18 9',
'M10.3 20a2 2 0 0 0 3.4 0'],
shield: ['M12 3l7.5 3v5.2c0 4.6-3.1 8.6-7.5 10.3-4.4-1.7-7.5-5.7-7.5-10.3V6z'],
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
index 24ff315..46168cf 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
@@ -17,6 +17,8 @@ export default {
'nav.minimize_tray': 'In den Infobereich minimieren',
'tray.show': 'MeshBay anzeigen',
'tray.quit': 'Beenden',
+ 'tray.start_node': 'Node starten',
+ 'tray.stop_node': 'Node stoppen',
// Sidebar
'sidebar.my_groups': 'Meine Gruppen',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
index ce08f1f..2d38e4b 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
@@ -20,6 +20,8 @@ export default {
'nav.minimize_tray': 'Minimize to tray',
'tray.show': 'Show MeshBay',
'tray.quit': 'Quit',
+ 'tray.start_node': 'Start the node',
+ 'tray.stop_node': 'Stop the node',
// Sidebar
'sidebar.my_groups': 'My Groups',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
index 7aa1d98..471ad82 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
@@ -16,6 +16,8 @@ export default {
'nav.minimize_tray': 'Minimizar en la bandeja',
'tray.show': 'Mostrar MeshBay',
'tray.quit': 'Salir',
+ 'tray.start_node': 'Iniciar el nodo',
+ 'tray.stop_node': 'Detener el nodo',
// Sidebar
'sidebar.my_groups': 'Mis grupos',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
index b87cb81..48f26a2 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
@@ -16,6 +16,8 @@ export default {
'nav.minimize_tray': 'Réduire dans la zone de notification',
'tray.show': 'Afficher MeshBay',
'tray.quit': 'Quitter',
+ 'tray.start_node': 'Démarrer le nœud',
+ 'tray.stop_node': 'Arrêter le nœud',
// Sidebar
'sidebar.my_groups': 'Mes groupes',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
index 242bdb4..564f34b 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
@@ -17,6 +17,8 @@ export default {
'nav.minimize_tray': 'Riduci nella barra di sistema',
'tray.show': 'Mostra MeshBay',
'tray.quit': 'Esci',
+ 'tray.start_node': 'Avvia il nodo',
+ 'tray.stop_node': 'Arresta il nodo',
// Sidebar
'sidebar.my_groups': 'I miei gruppi',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
index 8c8f654..3eed305 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
@@ -17,6 +17,8 @@ export default {
'nav.minimize_tray': 'トレイに最小化',
'tray.show': 'MeshBay を表示',
'tray.quit': '終了',
+ 'tray.start_node': 'ノードを開始',
+ 'tray.stop_node': 'ノードを停止',
// Sidebar
'sidebar.my_groups': 'マイグループ',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
index 566677d..711a22f 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
@@ -17,6 +17,8 @@ export default {
'nav.minimize_tray': 'Minimaliseren naar systeemvak',
'tray.show': 'MeshBay tonen',
'tray.quit': 'Afsluiten',
+ 'tray.start_node': 'Node starten',
+ 'tray.stop_node': 'Node stoppen',
// Sidebar
'sidebar.my_groups': 'Mijn groepen',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
index 4e75670..67615a2 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
@@ -20,6 +20,8 @@ export default {
'nav.minimize_tray': 'Zminimalizuj do zasobnika',
'tray.show': 'Pokaż MeshBay',
'tray.quit': 'Zakończ',
+ 'tray.start_node': 'Uruchom węzeł',
+ 'tray.stop_node': 'Zatrzymaj węzeł',
// Sidebar
'sidebar.my_groups': 'Moje grupy',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js
index a9fd638..2d07994 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js
@@ -18,6 +18,8 @@ export default {
'nav.minimize_tray': 'Minimizar na bandeja',
'tray.show': 'Mostrar o MeshBay',
'tray.quit': 'Sair',
+ 'tray.start_node': 'Iniciar o nó',
+ 'tray.stop_node': 'Parar o nó',
// Sidebar
'sidebar.my_groups': 'Meus grupos',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js
index ca39837..fd0c7f9 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js
@@ -17,6 +17,8 @@ export default {
'nav.minimize_tray': '最小化到托盘',
'tray.show': '显示 MeshBay',
'tray.quit': '退出',
+ 'tray.start_node': '启动节点',
+ 'tray.stop_node': '停止节点',
// Sidebar
'sidebar.my_groups': '我的群组',