// CreateProjectModal.jsx — §22 S5. The create-project form the deployment // directory's "Create your first project" / "New project" control opens, gated // on the viewer's `can_create_project` capability (a global Owner action). // // The form lets the Owner choose a project id (a slug, not "default"), a display // name, the type of its initial (default) collection, a visibility, and an // optional content-repo name (defaulting to `-content`). The backend // provisions the Gitea content repo, commits the project to projects.yaml, // re-mirrors the registry, and returns the new project; on success the caller // refreshes the directory (and the N=1 redirect then lands in the new project). import { useState } from 'react' import { createProject } from '../api' const TYPE_OPTIONS = [ { value: 'document', label: 'Document — prose RFCs' }, { value: 'specification', label: 'Specification' }, { value: 'bdd', label: 'BDD — behaviour scenarios' }, ] const VISIBILITY_OPTIONS = [ { value: 'public', label: 'Public' }, { value: 'unlisted', label: 'Unlisted (link-only)' }, { value: 'gated', label: 'Gated (hidden from the public)' }, ] export default function CreateProjectModal({ onClose, onCreated }) { const [projectId, setProjectId] = useState('') const [name, setName] = useState('') const [type, setType] = useState('document') const [visibility, setVisibility] = useState('public') const [contentRepo, setContentRepo] = useState('') const [submitting, setSubmitting] = useState(false) const [error, setError] = useState(null) async function handleCreate(e) { e.preventDefault() const pid = projectId.trim().toLowerCase() if (!pid || !name.trim()) return setSubmitting(true) setError(null) try { const project = await createProject({ projectId: pid, name: name.trim(), type, visibility, contentRepo: contentRepo.trim() || null, }) onCreated?.(project) } catch (err) { setError(err.message || 'Failed to create the project.') } finally { setSubmitting(false) } } return (
{ if (e.target === e.currentTarget) onClose() }}>

New project

setProjectId(e.target.value)} placeholder="e.g. ohm, acme" autoFocus required /> setName(e.target.value)} placeholder="e.g. Open Human Model" required /> setContentRepo(e.target.value)} placeholder="defaults to -content" />
{error && {error}}
) }