import { html, useState, useEffect, useCallback, useRef, } from './vendor/htm-preact.js'; import { t } from './i18n.js'; import { HUB, hubFetch, session, navigate } from './hub-client.js'; import * as platform from './platform.js'; import { Icon } from './icon.js'; import { SharedDirectoriesTable } from './group-settings.js'; export function CreateGroupPage(props) { // The wizard assumes a LOCAL node it can link right there (waiting_for_ // account / waiting_for_node_key, below) -- exactly what a "Light" desktop // build (electron-builder.light.yml, no bundled node-runtime) does not // have. Without this check that polling loop hangs forever, the same // "Detecting local node…" failure mode already found and fixed once for // Full (see the Windows-port history around linkNodeKeyAndAwaitRunning). // `bundled` starts null (unknown) and resolves once via IPC; a plain // browser has no bridge at all and skips straight to false, the same // outcome `platform.node.available` already gave it. Falling back to // CreateGroupFormSimple is not a lesser feature for Light -- it is the // exact form a browser-only member already uses to create a group with no // node of their own; hosting it can be linked from a device that has one. const [bundled, setBundled] = useState(null); useEffect(() => { if (!platform.node.available) { setBundled(false); return undefined; } let cancelled = false; platform.node.bundled().then((b) => { if (!cancelled) setBundled(b); }); return () => { cancelled = true; }; }, []); if (platform.node.available && bundled === null) { return html`
${' '}${t('node.service_checking')}
`; } if (platform.node.available && bundled) return html`<${CreateGroupWizard} ...${props} />`; return html`<${CreateGroupFormSimple} ...${props} />`; } function CreateGroupFormSimple({ token, onCreated, allowPublicGroups = true }) { const [name, setName] = useState(''); const [description, setDescription] = useState(''); const [joinPolicy, setJoinPolicy] = useState('invite'); const [error, setError] = useState(''); const [loading, setLoading] = useState(false); const onSubmit = async (e) => { e.preventDefault(); if (!name.trim()) return; setLoading(true); setError(''); try { const body = { name: name.trim(), join_policy: joinPolicy, visibility: joinPolicy === 'open' ? 'public' : 'private' }; if (description.trim()) body.description = description.trim().slice(0, 512); const data = await hubFetch('/v1/groups', { method: 'POST', token, body, }); if (onCreated) onCreated(); navigate('/'); } catch (err) { setError(err.message); } finally { setLoading(false); } }; return html`

${t('create_group.title')}

${t('create_group.hint')}

${error && html`
${error}
`}
setName(e.target.value)} required autofocus />