From 0c2754d2d4cb1905d5e324f56fbc64e4afae526f Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Mon, 31 Aug 2026 01:06:06 +0200 Subject: refactor(ui): extract Explore, Login, Register and CreateGroup from app.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ExplorePage → explore-page.js (static import), LoginPage/RegisterPage/ FirstRunPage → auth-page.js (static import, LoginPage receives onLogin as a prop), CreateGroupPage/wizard → create-group-page.js (lazy-loaded via dynamic import(), same pattern as AdminPage/NodePage). app.js goes from 1803 to 914 lines. webapp.py _ASSETS extended with the three new files and the previously missing extracted pages. Test fixtures updated to follow the moved components. Co-Authored-By: Claude Opus 4.6 --- .../src/meshbay_hub/static/create-group-page.js | 513 +++++++++++++++++++++ 1 file changed, 513 insertions(+) create mode 100644 packages/meshbay-hub/src/meshbay_hub/static/create-group-page.js (limited to 'packages/meshbay-hub/src/meshbay_hub/static/create-group-page.js') diff --git a/packages/meshbay-hub/src/meshbay_hub/static/create-group-page.js b/packages/meshbay-hub/src/meshbay_hub/static/create-group-page.js new file mode 100644 index 0000000..b23b504 --- /dev/null +++ b/packages/meshbay-hub/src/meshbay_hub/static/create-group-page.js @@ -0,0 +1,513 @@ +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 { APPS } from './apps.js'; + +export function CreateGroupPage(props) { + if (platform.node.available) 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 /> +
+ +
+ +