aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/src')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/app.js30
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/de.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/en.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/es.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/it.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/node-page.js23
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/platform.js10
13 files changed, 61 insertions, 12 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js
index c1913c0..b9466d0 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/app.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js
@@ -429,7 +429,7 @@ function Nav({ user, theme, onThemeChange, onLogout, onMenuToggle, unreadCount,
// ── Sidebar ──────────────────────────────────────────────────────────────────
-function Sidebar({ groups, presence, indexProgressPct, route, menuOpen, role, hasNodeKey,
+function Sidebar({ groups, presence, indexProgressPct, route, menuOpen, role, showNode,
allowPublicGroups = true }) {
const isStaff = role === 'moderator' || role === 'admin';
return html`
@@ -449,7 +449,7 @@ function Sidebar({ groups, presence, indexProgressPct, route, menuOpen, role, ha
<a class="sidebar-item ${route === '/search' ? 'active' : ''}"
href="#/search"><${Icon} name="search" /> ${t('sidebar.search')}</a>
</div>
- ${platform.capabilities.nodeAdmin && hasNodeKey && html`
+ ${platform.capabilities.nodeAdmin && showNode && html`
<div class="sidebar-section">
<div class="sidebar-heading">${t('sidebar.node')}</div>
<a class="sidebar-item ${route === '/node' ? 'active' : ''}"
@@ -781,6 +781,9 @@ function App() {
const [notifDisabled, setNotifDisabled] = useState(false);
const [userPrefs, setUserPrefs] = useState({});
const [hasNodeKey, setHasNodeKey] = useState(false);
+ // A node on this machine, linked to the account or not: the Node section is
+ // where it is looked after, so it cannot wait for a link to show up.
+ const [localNode, setLocalNode] = useState(false);
// Instance policy, fetched once, unauthenticated. `null` until it answers;
// treat unknown as "allowed" so a slow hub never blocks a legitimate private
// group — the hub refuses a public one server-side regardless.
@@ -1041,6 +1044,25 @@ function App() {
fetchNotifications();
}, [user]);
+ // The node this application ships, set up, started and linked for whoever
+ // signs in (main.js `ensureNode`): installing it is all it should take.
+ // Keyed on the account, not the session object -- the token rotates, and a
+ // renewal is not a sign-in.
+ const signedInAs = user ? user.username : null;
+ useEffect(() => {
+ setLocalNode(false);
+ if (!signedInAs || !platform.capabilities.nodeAdmin || !platform.node.available) return;
+ let cancelled = false;
+ platform.node.installed()
+ .then((r) => { if (!cancelled) setLocalNode(Boolean(r && r.installed)); })
+ .catch(() => {});
+ const live = userRef.current;
+ platform.node.ensure({ username: live.username, token: live.token })
+ .then(() => { if (!cancelled) refreshNodeKey(); })
+ .catch(() => {});
+ return () => { cancelled = true; };
+ }, [signedInAs]);
+
// After an invitation is accepted: the group is ours now, and only the hub
// knows its row the way `/mine` answers it.
const reloadGroups = useCallback(() => {
@@ -1316,7 +1338,7 @@ function App() {
.catch(() => {});
refreshNodeKey();
}} />`;
- } else if (route === '/node' && platform.capabilities.nodeAdmin && hasNodeKey) {
+ } else if (route === '/node' && platform.capabilities.nodeAdmin && (hasNodeKey || localNode)) {
page = html`<${LazyNodePage} groups=${groups} token=${user.token} username=${user.username} />`;
} else if (groupId) {
page = html`<${GroupPage}
@@ -1380,7 +1402,7 @@ function App() {
menuOpen=${menuOpen}
role=${user.role}
allowPublicGroups=${allowPublicGroups}
- hasNodeKey=${hasNodeKey} />`}
+ showNode=${hasNodeKey || localNode} />`}
${menuOpen && html`<div class="overlay visible"
onClick=${() => setMenuOpen(false)} />`}
<main class="main">
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 f4151f7..4dff605 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
@@ -939,6 +939,7 @@ export default {
'node.pair_code_placeholder': 'Kopplungscode',
'node.pair_button': 'Diesen Browser koppeln',
'node.pair_success': 'Erfolgreich gekoppelt.',
+ 'node.pair_pending': 'Kopplungscode bereit: Er wird verwendet, wenn Sie das nächste Mal eine Gruppe dieses Nodes öffnen.',
'node.reload': 'Konfiguration neu laden',
'node.reloaded': 'Konfiguration neu geladen. Verzeichnisänderungen an bestehenden Gruppen sind jetzt aktiv.',
'node.restart_needed': 'Nach dem Hinzufügen: Gruppenschlüssel initialisieren (meshbay-node gek-init --group <name>).',
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 84607e7..90c043e 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
@@ -1079,6 +1079,7 @@ export default {
'node.pair_code_placeholder': 'Pairing code',
'node.pair_button': 'Pair this browser',
'node.pair_success': 'Paired successfully.',
+ 'node.pair_pending': "Pairing code ready: it is used the next time you open one of this node's groups.",
'node.reload': 'Reload config',
'node.reloaded': 'Config reloaded. Root changes on existing groups are now active.',
'node.attach_group': 'Add group',
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 28ad85e..7b46b17 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
@@ -933,6 +933,7 @@ export default {
'node.pair_code_placeholder': 'Código de emparejamiento',
'node.pair_button': 'Emparejar este navegador',
'node.pair_success': 'Emparejamiento exitoso.',
+ 'node.pair_pending': 'Código de emparejamiento listo: se usará la próxima vez que abra uno de los grupos de este Node.',
'node.reload': 'Recargar configuración',
'node.reloaded': 'Configuración recargada. Los cambios de directorios en los grupos existentes ya están activos.',
'node.restart_needed': 'Después de añadir: inicialice la clave de grupo (meshbay-node gek-init --group <nombre>).',
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 9e8dbbe..d3f9200 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
@@ -936,6 +936,7 @@ export default {
'node.pair_code_placeholder': "Code d'appairage",
'node.pair_button': 'Appairer ce navigateur',
'node.pair_success': 'Appairage réussi.',
+ 'node.pair_pending': "Code d'appairage prêt : il sera utilisé à la prochaine ouverture d'un des groupes de ce node.",
'node.reload': 'Recharger la configuration',
'node.reloaded': 'Configuration rechargée. Les modifications de répertoires sur les groupes existants sont maintenant actives.',
'node.restart_needed': 'Après l\'ajout : initialisez la clé de groupe (meshbay-node gek-init --group <name>).',
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 493455d..715738e 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
@@ -935,6 +935,7 @@ export default {
'node.pair_code_placeholder': 'Codice di associazione',
'node.pair_button': 'Associa questo browser',
'node.pair_success': 'Associazione riuscita.',
+ 'node.pair_pending': 'Codice di associazione pronto: verrà usato la prossima volta che apri uno dei gruppi di questo Node.',
'node.reload': 'Ricarica configurazione',
'node.reloaded': 'Configurazione ricaricata. Le modifiche alle directory dei gruppi esistenti sono ora attive.',
'node.restart_needed': "Dopo l'aggiunta: inizializzi la chiave di gruppo (meshbay-node gek-init --group <nome>).",
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 35a639a..23358c2 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
@@ -923,6 +923,7 @@ export default {
'node.pair_code_placeholder': 'ペアリングコード',
'node.pair_button': 'このブラウザをペアリング',
'node.pair_success': 'ペアリングに成功しました。',
+ 'node.pair_pending': 'ペアリングコードの準備ができました。この Node のグループを次に開いたときに使用されます。',
'node.reload': '設定を再読み込み',
'node.reloaded': '設定を再読み込みしました。既存グループのルート変更が反映されました。',
'node.restart_needed': '追加後、グループ鍵を初期化してください(meshbay-node gek-init --group <name>)。',
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 73731cf..5e53084 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
@@ -937,6 +937,7 @@ export default {
'node.pair_code_placeholder': 'Koppelingscode',
'node.pair_button': 'Deze browser koppelen',
'node.pair_success': 'Succesvol gekoppeld.',
+ 'node.pair_pending': 'Koppelingscode klaar: die wordt gebruikt zodra u een van de groepen van deze Node opent.',
'node.reload': 'Configuratie herladen',
'node.reloaded': 'Configuratie herladen. Mapwijzigingen op bestaande groepen zijn nu actief.',
'node.restart_needed': 'Na het toevoegen: initialiseer de groepssleutel (meshbay-node gek-init --group <naam>).',
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 849c632..5d6d852 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
@@ -955,6 +955,7 @@ export default {
'node.pair_code_placeholder': 'Kod parowania',
'node.pair_button': 'Sparuj tę przeglądarkę',
'node.pair_success': 'Parowanie zakończone sukcesem.',
+ 'node.pair_pending': 'Kod parowania gotowy: zostanie użyty przy następnym otwarciu jednej z grup tego Node.',
'node.reload': 'Przeładuj konfigurację',
'node.reloaded': 'Konfiguracja przeładowana. Zmiany katalogów w istniejących grupach są teraz aktywne.',
'node.restart_needed': 'Po dodaniu: zainicjalizuj klucz grupy (meshbay-node gek-init --group <nazwa>).',
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 5672b60..6fe50f6 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
@@ -934,6 +934,7 @@ export default {
'node.pair_code_placeholder': 'Código de pareamento',
'node.pair_button': 'Parear este navegador',
'node.pair_success': 'Pareamento realizado com sucesso.',
+ 'node.pair_pending': 'Código de pareamento pronto: ele será usado na próxima vez que você abrir um dos grupos deste Node.',
'node.reload': 'Recarregar configuração',
'node.reloaded': 'Configuração recarregada. Alterações de diretórios em grupos existentes estão ativas.',
'node.restart_needed': 'Após adicionar: inicialize a chave do grupo (meshbay-node gek-init --group <nome>).',
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 26025ef..b3886ff 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
@@ -911,6 +911,7 @@ export default {
'node.pair_code_placeholder': '配对码',
'node.pair_button': '配对此浏览器',
'node.pair_success': '配对成功。',
+ 'node.pair_pending': '配对码已就绪:下次打开此 Node 的任一群组时将自动使用。',
'node.reload': '重新加载配置',
'node.reloaded': '配置已重新加载。对现有群组的目录更改现已生效。',
'node.restart_needed': '添加后请初始化群组密钥(meshbay-node gek-init --group <名称>)。',
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 9d230c1..04f4abc 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/node-page.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/node-page.js
@@ -6,7 +6,7 @@ import { t } from './i18n.js';
import { ask } from './ask.js';
import * as platform from './platform.js';
import { Icon } from './icon.js';
-import { HUB } from './hub-client.js';
+import { HUB, session } from './hub-client.js';
// ── Node management (D5) ────────────────────────────────────────────────────
//
@@ -108,6 +108,9 @@ function NodeServicePanel({ onChanged, token, username }) {
const KNOWN_STATES = ['active', 'inactive', 'failed', 'activating', 'deactivating'];
const stateKey = KNOWN_STATES.includes(info.activeState) ? info.activeState : 'unknown';
const running = info.activeState === 'active' || info.activeState === 'activating';
+ // A node process that does not answer ('unknown': on its way up or down, or
+ // stuck) is still one to stop -- only "nothing there" takes Stop away.
+ const stoppable = info.activeState !== 'inactive';
const dot = info.activeState === 'active' ? 'online'
: info.activeState === 'failed' ? 'offline' : 'unknown';
const label = info.installed ? t('node.service_state_' + stateKey)
@@ -132,7 +135,7 @@ function NodeServicePanel({ onChanged, token, username }) {
onClick=${() => act('start', () => platform.node.start({ hubUrl: HUB, username, token }))}>
${busy === 'start' ? t('node.service_starting') : t('node.service_start')}</button>
${info.installed && html`
- <button class="btn btn-small btn-secondary" disabled=${!!busy || !running}
+ <button class="btn btn-small btn-secondary" disabled=${!!busy || !stoppable}
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}
@@ -520,13 +523,17 @@ export function NodePage({ groups, token, username }) {
setPairBusy(true);
setPairStatus('');
try {
+ // An operator code is redeemed over MNP, with the account's identity in
+ // a group -- this page has no transport. It used to store the code where
+ // nothing read it and say "Paired successfully", and the banner came back
+ // on the next refresh. Queued the way the Create Group wizard queues it:
+ // the next group of this node to open redeems it.
const result = await nodeOp('pairOperator');
if (result && result.code) {
await platform.node.setPairingCode(result.code);
+ session.pendingJoinCode = result.code;
}
- setPairStatus('paired');
- setOperatorPaired(true);
- await refresh();
+ setPairStatus('pending');
} catch (err) {
setPairStatus(platform.bridgeMessage(err));
} finally {
@@ -712,15 +719,15 @@ export function NodePage({ groups, token, username }) {
</div>
<${NodeServicePanel} onChanged=${fetchStatus} token=${token} username=${username} />
${actionMsg && html`<div class="node-message">${actionMsg}</div>`}
- ${operatorPaired === false && html`
+ ${operatorPaired === false && nodeGroups.length > 0 && html`
<div class="node-pair-banner">
<p>${t('node.pair_needed')}</p>
<button class="btn btn-primary btn-small"
disabled=${pairBusy}
onClick=${doPairOperator}>
${pairBusy ? t('node.settings_saving') : t('node.pair_button')}</button>
- ${pairStatus === 'paired'
- ? html`<p class="success-msg">${t('node.pair_success')}</p>`
+ ${pairStatus === 'pending'
+ ? html`<p class="success-msg">${t('node.pair_pending')}</p>`
: pairStatus ? html`<p class="error-msg">${pairStatus}</p>` : null}
</div>
`}
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/platform.js b/packages/meshbay-hub/src/meshbay_hub/static/platform.js
index 28817c7..e3b3d2d 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/platform.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/platform.js
@@ -253,6 +253,16 @@ export const node = {
return bridge.node.start(opts);
},
/**
+ * After sign-in: set up, start and link the node this application ships,
+ * for the signed-in account ({username, token}). Leaves alone a node set up
+ * for another account and an account linked to another node. Resolves to
+ * `{ state }`; a build or platform with nothing to do answers 'unsupported'.
+ */
+ async ensure(opts) {
+ if (!bridge || !bridge.node || !bridge.node.ensure) return { state: 'unsupported' };
+ return bridge.node.ensure(opts);
+ },
+ /**
* One of the local node's operations, by name (`NODE_OPS` in the desktop
* client's main.js). The page never names a route: the main process checks
* the arguments, builds the request, and asks the person itself before