feat: bind public vestibules to domain login gates
This commit is contained in:
parent
2c50b28557
commit
b24d5b5452
6 changed files with 147 additions and 22 deletions
|
|
@ -1,17 +1,23 @@
|
|||
import { Cloud, Laptop, ShieldCheck, X } from 'lucide-react';
|
||||
import { projectDomainConnectionSteps, projectDomainTrustSource, type DomainAccessProjection } from '../domain-connection';
|
||||
import { canEnterSelectedDomainRuntime, projectDomainRuntimeBoundary, type DomainEntryTarget, type DomainNodeType } from '../domain-entry-state';
|
||||
import { publicDomainDirectory, type DomainRouteId } from '../public-domain-directory';
|
||||
|
||||
interface Props {
|
||||
access: DomainAccessProjection;
|
||||
target: DomainEntryTarget | null;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
onSelectTarget: (routeId: DomainRouteId) => void;
|
||||
onSelectNodeType: (nodeType: DomainNodeType) => void;
|
||||
onEnterRuntime: () => void;
|
||||
onOpenCodeChannel: () => void;
|
||||
}
|
||||
|
||||
export function DomainConnectionSheet({ access, open, onClose, onEnterRuntime, onOpenCodeChannel }: Props) {
|
||||
export function DomainConnectionSheet({ access, target, open, onClose, onSelectTarget, onSelectNodeType, onEnterRuntime, onOpenCodeChannel }: Props) {
|
||||
if (!open) return null;
|
||||
const steps = projectDomainConnectionSteps(access);
|
||||
const canEnter = canEnterSelectedDomainRuntime(target, access);
|
||||
|
||||
return (
|
||||
<div className="storage-sheet-backdrop" role="presentation" onMouseDown={event => {
|
||||
|
|
@ -20,18 +26,22 @@ export function DomainConnectionSheet({ access, open, onClose, onEnterRuntime, o
|
|||
<section className="storage-sheet domain-connection-sheet" role="dialog" aria-modal="true" aria-labelledby="domain-connection-title">
|
||||
<header className="storage-sheet-header">
|
||||
<div>
|
||||
<small>DOM-FIFTH-0001</small>
|
||||
<h2 id="domain-connection-title">接入第五域 · 光湖本源域</h2>
|
||||
<small>{target?.domain.stableDomainId ?? 'SELECT-DOMAIN'}</small>
|
||||
<h2 id="domain-connection-title">{target ? `接入${target.domain.displayName}` : '选择要接入的域'}</h2>
|
||||
</div>
|
||||
<button className="icon-button" onClick={onClose} aria-label="关闭域接入状态"><X aria-hidden="true" /></button>
|
||||
</header>
|
||||
|
||||
<p className="domain-connection-lead">进入域不是切换页面。系统必须验证账户、登记节点、目标域授权、会话能力和在线回执。</p>
|
||||
<div className="domain-target-picker" aria-label="选择目标域">
|
||||
{publicDomainDirectory.map(domain => <button key={domain.routeId} type="button" data-selected={target?.domain.routeId === domain.routeId} onClick={() => onSelectTarget(domain.routeId)}><span>{domain.directoryNumber}</span>{domain.displayName}</button>)}
|
||||
</div>
|
||||
{!target ? <p className="domain-connection-boundary">{projectDomainRuntimeBoundary(target, access)}</p> : <>
|
||||
<p className="domain-connection-boundary">{projectDomainTrustSource(access)}</p>
|
||||
|
||||
<div className="domain-node-modes" aria-label="支持的节点类型">
|
||||
<article><Laptop aria-hidden="true" /><span><strong>本地终端节点</strong><small>使用当前联网电脑承载本地工作;正式节点登记尚未开放。</small></span></article>
|
||||
<article><Cloud aria-hidden="true" /><span><strong>云常驻节点</strong><small>服务器可持续在线;代码频道登录不等于取得域运行权限。</small></span></article>
|
||||
<button type="button" data-selected={target.nodeType === 'local-terminal'} onClick={() => onSelectNodeType('local-terminal')}><Laptop aria-hidden="true" /><span><strong>本地终端节点</strong><small>使用当前联网电脑承载本地工作;仍须完成节点登记。</small></span></button>
|
||||
<button type="button" data-selected={target.nodeType === 'cloud-resident'} onClick={() => onSelectNodeType('cloud-resident')}><Cloud aria-hidden="true" /><span><strong>云常驻节点</strong><small>服务器可持续在线;代码频道登录不等于取得域权限。</small></span></button>
|
||||
</div>
|
||||
|
||||
<ol className="domain-connection-steps">
|
||||
|
|
@ -44,14 +54,15 @@ export function DomainConnectionSheet({ access, open, onClose, onEnterRuntime, o
|
|||
))}
|
||||
</ol>
|
||||
|
||||
<p className="domain-connection-boundary">代码频道账号只用于仓库与同步,是节点身份的辅助证明之一,不能单独签发第五域权限。</p>
|
||||
<p className="domain-connection-boundary">{projectDomainRuntimeBoundary(target, access)} 代码频道账号只用于仓库与同步,不能单独签发域权限。</p>
|
||||
</>}
|
||||
|
||||
<footer className="storage-sheet-footer">
|
||||
<button className="secondary-button" onClick={onOpenCodeChannel}>代码频道与同步设置</button>
|
||||
<button className="secondary-button" onClick={onOpenCodeChannel} disabled={!target}>代码频道与同步设置</button>
|
||||
<span />
|
||||
<button className="secondary-button" onClick={onClose}>返回门厅</button>
|
||||
<button className="primary-button" onClick={onEnterRuntime} disabled={!access.runtimeReady}>
|
||||
{access.runtimeReady ? '进入第五域运行体' : '等待可信域接入'}
|
||||
<button className="primary-button" onClick={onEnterRuntime} disabled={!canEnter}>
|
||||
{canEnter ? '进入第五域运行体' : target ? '等待可信域接入' : '请先选择域'}
|
||||
</button>
|
||||
</footer>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ interface Props {
|
|||
access: { blockers: string[]; runtimeReady: boolean; stage: 'checking' | 'login-required' | 'identity-verified' | 'runtime-ready' };
|
||||
onEnterFifthRuntime: () => void;
|
||||
onEnterLocalWorkspace: () => void;
|
||||
onOpenConnection: () => void;
|
||||
onOpenConnection: (routeId: DomainRouteId | null) => void;
|
||||
}
|
||||
|
||||
export function WorldEntry({ access, onEnterFifthRuntime, onEnterLocalWorkspace, onOpenConnection }: Props) {
|
||||
|
|
@ -55,7 +55,7 @@ export function WorldEntry({ access, onEnterFifthRuntime, onEnterLocalWorkspace,
|
|||
<div><dt><DoorOpen aria-hidden="true" /><span>状态</span></dt><dd>{access.stage === 'runtime-ready' ? '节点、域清单、会话能力与连接回执已验证' : access.stage === 'identity-verified' ? '账户与节点已验证 · 尚缺域清单、会话能力和连接回执' : access.stage === 'checking' ? '正在核对真实接入证据' : '公开门厅可查看 · 尚未登录或接入节点'}</dd></div>
|
||||
</dl>
|
||||
<div className="fifth-actions">
|
||||
<button className="fifth-primary" type="button" onClick={access.runtimeReady ? onEnterFifthRuntime : onOpenConnection}><LogIn aria-hidden="true" />{access.runtimeReady ? '进入第五域运行体' : '登录或接入节点'}</button>
|
||||
<button className="fifth-primary" type="button" onClick={access.runtimeReady ? onEnterFifthRuntime : () => onOpenConnection('fifth')}><LogIn aria-hidden="true" />{access.runtimeReady ? '进入第五域运行体' : '登录或接入节点'}</button>
|
||||
<button type="button" onClick={onEnterLocalWorkspace}><DoorOpen aria-hidden="true" />进入仅本机工作空间</button>
|
||||
<button type="button" onClick={() => setStage('lighthouse')}><Landmark aria-hidden="true" />返回灯塔</button>
|
||||
</div>
|
||||
|
|
@ -82,7 +82,7 @@ export function WorldEntry({ access, onEnterFifthRuntime, onEnterLocalWorkspace,
|
|||
<button className="public-primary" type="button" onClick={() => setStage(stage === 'directory' ? 'lighthouse' : 'directory')}>
|
||||
{stage === 'directory' ? '返回公共灯塔' : '查看五域'}
|
||||
</button>
|
||||
<button type="button" onClick={onOpenConnection}>登录或接入节点</button>
|
||||
<button type="button" onClick={() => onOpenConnection(selectedDomain)}>登录或接入节点</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
@ -106,6 +106,7 @@ export function WorldEntry({ access, onEnterFifthRuntime, onEnterLocalWorkspace,
|
|||
<strong>{selectedVestibule.stableDomainId}</strong>
|
||||
<span>{selectedVestibule.themeLabel}</span>
|
||||
<small>仅公开门厅资料 · 私有资源未装载</small>
|
||||
<button type="button" onClick={() => onOpenConnection(selectedVestibule.routeId)}>登录进入此域</button>
|
||||
</aside>
|
||||
)}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue