fix(product): restore HoloLake world entry hierarchy
This commit is contained in:
parent
da26f27e35
commit
3ff80d583a
6 changed files with 105 additions and 33 deletions
|
|
@ -762,7 +762,7 @@ describe('App', () => {
|
|||
})
|
||||
})
|
||||
|
||||
it('shows the external AI setup dialog from the menu when AI onboarding is active', async () => {
|
||||
it('keeps external AI setup available from the menu without making it startup', async () => {
|
||||
localStorage.removeItem(AI_AGENTS_ONBOARDING_DISMISSED_STORAGE_NAME)
|
||||
localStorage.removeItem(CLAUDE_CODE_ONBOARDING_DISMISSED_STORAGE_NAME)
|
||||
mockCommandResults.get_ai_agents_status = {
|
||||
|
|
@ -777,8 +777,9 @@ describe('App', () => {
|
|||
render(<App />)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('AI is ready')).toBeInTheDocument()
|
||||
expect(screen.getByText('All Notes')).toBeInTheDocument()
|
||||
}, { timeout: SLOW_APP_READY_TIMEOUT_MS })
|
||||
expect(screen.queryByText('AI is ready')).not.toBeInTheDocument()
|
||||
|
||||
await waitFor(() => {
|
||||
expect(typeof window.__laputaTest?.dispatchBrowserMenuCommand).toBe('function')
|
||||
|
|
@ -792,7 +793,6 @@ describe('App', () => {
|
|||
expect(screen.getByText('Manage External AI Tools')).toBeInTheDocument()
|
||||
})
|
||||
expect(screen.getByTestId('mcp-setup-dialog')).toBeInTheDocument()
|
||||
expect(screen.queryByText('AI is ready')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('routes right-panel AI chat messages to the selected default agent', async () => {
|
||||
|
|
@ -903,7 +903,7 @@ describe('App', () => {
|
|||
expect(screen.getByTestId('welcome-open-folder')).toHaveTextContent('Open existing vault')
|
||||
})
|
||||
|
||||
it('persists an existing vault and shows AI onboarding after first-run open', async () => {
|
||||
it('persists an existing vault without putting optional AI setup in front of HoloLake', async () => {
|
||||
const selectedVaultPath = '/Users/mock/Documents/Work Vault'
|
||||
const saveVaultList = vi.fn()
|
||||
const promptSpy = vi.spyOn(window, 'prompt').mockReturnValue('file:///Users/mock/Documents/Work%20Vault')
|
||||
|
|
@ -947,9 +947,9 @@ describe('App', () => {
|
|||
expect(saveVaultList).toHaveBeenCalledTimes(1)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('ai-agents-onboarding-screen')).toBeInTheDocument()
|
||||
expect(screen.getByText('All Notes')).toBeInTheDocument()
|
||||
}, { timeout: SLOW_APP_READY_TIMEOUT_MS })
|
||||
expect(screen.getByText('AI setup is optional')).toBeInTheDocument()
|
||||
expect(screen.queryByTestId('ai-agents-onboarding-screen')).not.toBeInTheDocument()
|
||||
|
||||
promptSpy.mockRestore()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1424,7 +1424,9 @@ function MainApp({
|
|||
shouldResumeFreshStartOnboarding,
|
||||
shouldShowStartupScreen,
|
||||
} = useStartupScreenState({
|
||||
aiAgentsPromptVisible: aiAgentsOnboarding.showPrompt,
|
||||
// HoloLake is the human entry into the world. Optional Agent setup belongs
|
||||
// inside the Agent workspace/settings and must never replace that entry.
|
||||
aiAgentsPromptVisible: false,
|
||||
isNoteWindow: Boolean(noteWindowParams) || aiWorkspaceWindow,
|
||||
onboardingState: onboarding.state,
|
||||
runtimeMissingVaultPath,
|
||||
|
|
@ -1794,10 +1796,10 @@ function MainApp({
|
|||
</div>
|
||||
<UpdateBanner status={updateStatus} actions={updateActions} locale={appLocale} />
|
||||
<RenameDetectedBanner renames={detectedRenames} onUpdate={handleUpdateWikilinks} onDismiss={handleDismissRenames} />
|
||||
<div style={{ background: showHoloLakeHome ? '#050b1a' : undefined }}>
|
||||
<StatusBar galaxyMode={showHoloLakeHome} noteCount={visibleEntries.length} modifiedCount={gitModifiedCount} vaultPath={resolvedPath} defaultWorkspacePath={defaultWorkspacePath} vaults={vaultSwitcher.allVaults} multiWorkspaceEnabled={multiWorkspaceEnabled} onSwitchVault={vaultSwitcher.switchVault} onSetDefaultWorkspace={vaultSwitcher.setDefaultWorkspace} onOpenSettings={handleOpenSettings} onOpenVaultSettings={handleOpenVaultSettings} onOpenFeedback={openFeedback} onOpenDocs={openDocs} onOpenLocalFolder={vaultSwitcher.handleOpenLocalFolder} onCreateEmptyVault={vaultSwitcher.handleCreateEmptyVault} onCloneVault={dialogs.openCloneVault} onCloneGettingStarted={cloneGettingStartedVault} onClickPending={() => handleSetSelection({ kind: 'filter', filter: 'changes' })} onClickPulse={() => handleSetSelection({ kind: 'filter', filter: 'pulse' })} onCommitPush={handleCommitPush} commitActionPending={commitFlow.isOpeningCommitDialog} gitFeaturesEnabled={gitFeaturesEnabled} onInitializeGit={openGitSetupDialog} isOffline={networkStatus.isOffline} isGitVault={isGitVault} isVaultReloading={vault.isReloading || isVaultContentLoading} syncStatus={autoSync.syncStatus} lastSyncTime={autoSync.lastSyncTime} conflictCount={autoSync.conflictFiles.length} remoteStatus={autoSync.remoteStatus} repositories={gitRepositories} selectedRepositoryPath={gitSurfaces.syncRepositoryPath} onRepositoryChange={gitSurfaces.setSyncRepositoryPath} onTriggerSync={handlePullSelectedRepository} onPullAndPush={handlePullAndPushSelectedRepository} onOpenConflictResolver={conflictFlow.handleOpenConflictResolver} zoomLevel={zoom.zoomLevel} themeMode={documentThemeMode} onZoomReset={zoom.zoomReset} onToggleThemeMode={settingsLoaded ? handleToggleThemeMode : undefined} buildNumber={buildNumber} onCheckForUpdates={handleCheckForUpdates} onRemoveVault={vaultSwitcher.removeVault} onReorderVaults={vaultSwitcher.reorderVaults} onUpdateWorkspaceIdentity={vaultSwitcher.updateWorkspaceIdentity} aiFeaturesEnabled={aiFeaturesEnabled} mcpStatus={mcpSetupDialog.status} onInstallMcp={mcpSetupDialog.openDialog} locale={appLocale} />
|
||||
</div>
|
||||
{aiFeaturesEnabled && !effectiveShowAIChat ? (
|
||||
{!showHoloLakeHome ? (
|
||||
<StatusBar galaxyMode={false} noteCount={visibleEntries.length} modifiedCount={gitModifiedCount} vaultPath={resolvedPath} defaultWorkspacePath={defaultWorkspacePath} vaults={vaultSwitcher.allVaults} multiWorkspaceEnabled={multiWorkspaceEnabled} onSwitchVault={vaultSwitcher.switchVault} onSetDefaultWorkspace={vaultSwitcher.setDefaultWorkspace} onOpenSettings={handleOpenSettings} onOpenVaultSettings={handleOpenVaultSettings} onOpenFeedback={openFeedback} onOpenDocs={openDocs} onOpenLocalFolder={vaultSwitcher.handleOpenLocalFolder} onCreateEmptyVault={vaultSwitcher.handleCreateEmptyVault} onCloneVault={dialogs.openCloneVault} onCloneGettingStarted={cloneGettingStartedVault} onClickPending={() => handleSetSelection({ kind: 'filter', filter: 'changes' })} onClickPulse={() => handleSetSelection({ kind: 'filter', filter: 'pulse' })} onCommitPush={handleCommitPush} commitActionPending={commitFlow.isOpeningCommitDialog} gitFeaturesEnabled={gitFeaturesEnabled} onInitializeGit={openGitSetupDialog} isOffline={networkStatus.isOffline} isGitVault={isGitVault} isVaultReloading={vault.isReloading || isVaultContentLoading} syncStatus={autoSync.syncStatus} lastSyncTime={autoSync.lastSyncTime} conflictCount={autoSync.conflictFiles.length} remoteStatus={autoSync.remoteStatus} repositories={gitRepositories} selectedRepositoryPath={gitSurfaces.syncRepositoryPath} onRepositoryChange={gitSurfaces.setSyncRepositoryPath} onTriggerSync={handlePullSelectedRepository} onPullAndPush={handlePullAndPushSelectedRepository} onOpenConflictResolver={conflictFlow.handleOpenConflictResolver} zoomLevel={zoom.zoomLevel} themeMode={documentThemeMode} onZoomReset={zoom.zoomReset} onToggleThemeMode={settingsLoaded ? handleToggleThemeMode : undefined} buildNumber={buildNumber} onCheckForUpdates={handleCheckForUpdates} onRemoveVault={vaultSwitcher.removeVault} onReorderVaults={vaultSwitcher.reorderVaults} onUpdateWorkspaceIdentity={vaultSwitcher.updateWorkspaceIdentity} aiFeaturesEnabled={aiFeaturesEnabled} mcpStatus={mcpSetupDialog.status} onInstallMcp={mcpSetupDialog.openDialog} locale={appLocale} />
|
||||
) : null}
|
||||
{!showHoloLakeHome && aiFeaturesEnabled && !effectiveShowAIChat ? (
|
||||
<AiWorkspaceFloatingButton
|
||||
statuses={aiAgentsStatus}
|
||||
defaultAgent={aiAgentPreferences.defaultAiAgent}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ type FifthDomainSystemId = 'pufferfish' | 'eternal-lake-heart'
|
|||
|
||||
type FifthDomainSystemsProps = {
|
||||
detail?: 'overview' | 'pufferfish'
|
||||
evidenceMode?: 'receipt' | 'visual-preview'
|
||||
onEnterEternalLake: () => void
|
||||
onEnterPufferfish: () => void
|
||||
}
|
||||
|
|
@ -18,6 +19,7 @@ const PUFFERFISH_FACTS = {
|
|||
|
||||
export function FifthDomainSystems({
|
||||
detail = 'overview',
|
||||
evidenceMode = 'receipt',
|
||||
onEnterEternalLake,
|
||||
onEnterPufferfish,
|
||||
}: FifthDomainSystemsProps) {
|
||||
|
|
@ -26,6 +28,9 @@ export function FifthDomainSystems({
|
|||
)
|
||||
const pufferfishSelected = selected === 'pufferfish'
|
||||
const eternalLakeSelected = selected === 'eternal-lake-heart'
|
||||
const isVisualPreview = evidenceMode === 'visual-preview'
|
||||
const evidenceLabel = isVisualPreview ? '本地拓扑预览' : '真实接入'
|
||||
const nodeState = isVisualPreview ? '未实时核验' : '在线回执'
|
||||
|
||||
return (
|
||||
<section className="fifth-systems" data-detail={detail}>
|
||||
|
|
@ -38,7 +43,7 @@ export function FifthDomainSystems({
|
|||
: '不同人类系统通过各自真实服务器接入,同时保持系统归属与主权边界。'}
|
||||
</p>
|
||||
</div>
|
||||
<span className="fifth-systems__presence"><i />真实接入</span>
|
||||
<span className="fifth-systems__presence"><i />{evidenceLabel}</span>
|
||||
</header>
|
||||
|
||||
<div className="fifth-systems__layout">
|
||||
|
|
@ -53,7 +58,7 @@ export function FifthDomainSystems({
|
|||
<header>
|
||||
<button type="button" onClick={() => setSelected('pufferfish')}>
|
||||
<span className="system-path__mark">鱼</span>
|
||||
<span><strong>胖头鱼语言子系统</strong><small><i />真实接入</small></span>
|
||||
<span><strong>胖头鱼语言子系统</strong><small><i />{evidenceLabel}</small></span>
|
||||
</button>
|
||||
</header>
|
||||
<div className="system-path__route" aria-label="胖头鱼系统真实连接路径">
|
||||
|
|
@ -61,14 +66,14 @@ export function FifthDomainSystems({
|
|||
<span>大脑服务器</span>
|
||||
<strong>新加坡大脑服务器</strong>
|
||||
<code>{PUFFERFISH_FACTS.brain}</code>
|
||||
<small><i />在线</small>
|
||||
<small><i />{nodeState}</small>
|
||||
</div>
|
||||
<b aria-hidden />
|
||||
<div className="system-node">
|
||||
<span>执行节点</span>
|
||||
<strong>苍耳家庭 Ubuntu</strong>
|
||||
<code>{PUFFERFISH_FACTS.node}</code>
|
||||
<small><i />已登记</small>
|
||||
<small><i />{isVisualPreview ? '本地登记' : '登记回执'}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div className="system-path__persona">
|
||||
|
|
@ -86,7 +91,7 @@ export function FifthDomainSystems({
|
|||
<header>
|
||||
<button type="button" onClick={() => setSelected('eternal-lake-heart')}>
|
||||
<span className="system-path__mark">湖</span>
|
||||
<span><strong>永恒湖心系统</strong><small><i />真实接入</small></span>
|
||||
<span><strong>永恒湖心系统</strong><small><i />{evidenceLabel}</small></span>
|
||||
</button>
|
||||
</header>
|
||||
<div className="system-path__route system-path__route--single">
|
||||
|
|
@ -94,7 +99,7 @@ export function FifthDomainSystems({
|
|||
<span>接入节点</span>
|
||||
<strong>第五域国内主控</strong>
|
||||
<code>JD-FD-PRIMARY</code>
|
||||
<small><i />在线回执</small>
|
||||
<small><i />{nodeState}</small>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
|
@ -116,12 +121,12 @@ export function FifthDomainSystems({
|
|||
) : <>
|
||||
<header>
|
||||
<h2>{pufferfishSelected ? '胖头鱼语言子系统' : '永恒湖心系统'}</h2>
|
||||
<span><i />真实接入</span>
|
||||
<span><i />{evidenceLabel}</span>
|
||||
</header>
|
||||
{pufferfishSelected ? (
|
||||
<>
|
||||
<dl>
|
||||
<div><dt>系统状态</dt><dd>真实接入</dd></div>
|
||||
<div><dt>系统状态</dt><dd>{evidenceLabel}</dd></div>
|
||||
<div><dt>大脑服务器</dt><dd>{PUFFERFISH_FACTS.brain}</dd></div>
|
||||
<div><dt>执行节点</dt><dd title={PUFFERFISH_FACTS.node}>{PUFFERFISH_FACTS.node}</dd></div>
|
||||
<div><dt>节点编号</dt><dd>{PUFFERFISH_FACTS.nodeId}</dd></div>
|
||||
|
|
@ -135,7 +140,7 @@ export function FifthDomainSystems({
|
|||
) : (
|
||||
<>
|
||||
<dl>
|
||||
<div><dt>系统状态</dt><dd>真实接入</dd></div>
|
||||
<div><dt>系统状态</dt><dd>{evidenceLabel}</dd></div>
|
||||
<div><dt>入口节点</dt><dd>JD-FD-PRIMARY</dd></div>
|
||||
<div><dt>系统归属</dt><dd>冰朔个人系统</dd></div>
|
||||
<div><dt>下一频道</dt><dd>心跳核心频道</dd></div>
|
||||
|
|
@ -144,7 +149,11 @@ export function FifthDomainSystems({
|
|||
</>
|
||||
)}
|
||||
</>}
|
||||
<footer>拓扑信息来自本地系统登记与真实路由事实。</footer>
|
||||
<footer>
|
||||
{isVisualPreview
|
||||
? '本页仅展示本地登记拓扑,不能证明节点在线或人格体已恢复。'
|
||||
: '拓扑信息来自本地登记;在线状态仅以当前会话回执为准。'}
|
||||
</footer>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ const domains: Array<{
|
|||
description: '光湖世界公共航道与跨域共识入口。',
|
||||
id: 'main',
|
||||
node: 'GL-MAIN',
|
||||
status: '稳定运行',
|
||||
status: '等待公共回执',
|
||||
subtitle: '稳定的远洋星系',
|
||||
title: '光湖主域',
|
||||
},
|
||||
|
|
@ -53,7 +53,7 @@ const domains: Array<{
|
|||
description: '世界规则、协议与系统校准所在的基础域。',
|
||||
id: 'zero',
|
||||
node: 'GL-ZERO',
|
||||
status: '已登记',
|
||||
status: '等待登记回执',
|
||||
subtitle: '精密校准环',
|
||||
title: '光湖零域',
|
||||
},
|
||||
|
|
@ -62,7 +62,7 @@ const domains: Array<{
|
|||
description: '由多个真实节点共同组成的协作星群。',
|
||||
id: 'sub',
|
||||
node: 'GL-SUB',
|
||||
status: '联接中',
|
||||
status: '等待连接回执',
|
||||
subtitle: '联接的岛屿星群',
|
||||
title: '光湖分域',
|
||||
},
|
||||
|
|
@ -71,7 +71,7 @@ const domains: Array<{
|
|||
description: '冰朔的独立语言域,从这里归航至永恒湖心。',
|
||||
id: 'fifth',
|
||||
node: 'JD-FD-PRIMARY',
|
||||
status: '可授权登录',
|
||||
status: '可发起授权',
|
||||
subtitle: '深空湖心星系',
|
||||
title: '第五域',
|
||||
},
|
||||
|
|
@ -86,6 +86,13 @@ const domains: Array<{
|
|||
},
|
||||
]
|
||||
|
||||
function loginErrorCopy(error: string): string {
|
||||
if (error === 'guanghu_world_login_desktop_runtime_required') {
|
||||
return '当前是本地视觉预览,未向第五域服务器发送登录请求。请从已签名的 HoloLake 桌面端进入。'
|
||||
}
|
||||
return error
|
||||
}
|
||||
|
||||
export function GuanghuWorldLoginGate({
|
||||
locale,
|
||||
onBack,
|
||||
|
|
@ -108,6 +115,12 @@ export function GuanghuWorldLoginGate({
|
|||
: waiting || requesting
|
||||
? '授权处理中'
|
||||
: '访客入口 · 未验证'
|
||||
const isVisualPreview = state.workorderId === 'local-visual-preview'
|
||||
const worldState = isVisualPreview
|
||||
? ['本地视觉预览', '未连接真实服务器']
|
||||
: state.phase === 'online'
|
||||
? ['世界入口:已验证回执', '语言共识层:已连接']
|
||||
: ['世界入口:等待验证', '语言共识层:未建立连接']
|
||||
|
||||
const selectDomain = (id: DomainId) => {
|
||||
setSelectedDomainId(id)
|
||||
|
|
@ -125,8 +138,8 @@ export function GuanghuWorldLoginGate({
|
|||
<strong>HoloLake Era · 光湖 OS</strong>
|
||||
</div>
|
||||
<div className="guanghu-login__world-state">
|
||||
<span><i />世界状态:稳定</span>
|
||||
<span>语言共识层:已同步</span>
|
||||
<span><i />{worldState[0]}</span>
|
||||
<span>{worldState[1]}</span>
|
||||
</div>
|
||||
<div className="guanghu-login__top-actions">
|
||||
<button type="button" aria-label="聚焦五域节点" onClick={() => setActiveRail('domains')}><MagnifyingGlass aria-hidden /><span>查找域</span></button>
|
||||
|
|
@ -237,7 +250,7 @@ export function GuanghuWorldLoginGate({
|
|||
{state.error ? (
|
||||
<div className="guanghu-login__error" role="alert">
|
||||
<strong>{t('hololake.login.errorTitle')}</strong>
|
||||
<span>{state.error}</span>
|
||||
<span>{loginErrorCopy(state.error)}</span>
|
||||
<Button variant="outline" onClick={onLogin}>
|
||||
{t('hololake.login.retry')}
|
||||
</Button>
|
||||
|
|
@ -259,10 +272,10 @@ export function GuanghuWorldLoginGate({
|
|||
</aside>
|
||||
|
||||
<footer className="guanghu-login__news">
|
||||
<span>世界实况</span>
|
||||
<p><i data-tone="cyan" />光湖分域 · 涧语群岛<small>新航道「涧光径」完成共识校准</small></p>
|
||||
<p><i data-tone="gold" />光湖零感域 · 安泊港<small>港区协同协议更新至 v7.3</small></p>
|
||||
<p><i data-tone="violet" />第五域 · 星洞回廊<small>回声观测站记录到罕见语义涟漪</small></p>
|
||||
<span>世界导览</span>
|
||||
<p><i data-tone="cyan" />光湖分域 · 涧语群岛<small>视觉叙事 · 非实时状态</small></p>
|
||||
<p><i data-tone="gold" />光湖零感域 · 安泊港<small>等待企业节点接入回执</small></p>
|
||||
<p><i data-tone="violet" />第五域 · 星洞回廊<small>授权后读取真实域内状态</small></p>
|
||||
<code>{state.nodeId}</code>
|
||||
</footer>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ describe('HoloLakeHome', () => {
|
|||
|
||||
fireEvent.click(screen.getByRole('button', { name: /验证并进入第五域/ }))
|
||||
expect(screen.getByRole('button', { name: /冰朔,访客入口 · 未验证/ })).toBeInTheDocument()
|
||||
fireEvent.click(screen.getByRole('button', { name: /光湖主域.*稳定运行/ }))
|
||||
fireEvent.click(screen.getByRole('button', { name: /光湖主域.*等待公共回执/ }))
|
||||
expect(screen.getByRole('heading', { name: '光湖主域' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: '当前入口尚未开放' })).toBeDisabled()
|
||||
expect(screen.queryByRole('button', { name: /给我发送授权链接/ })).not.toBeInTheDocument()
|
||||
|
|
@ -361,6 +361,24 @@ describe('HoloLakeHome', () => {
|
|||
expect(screen.getByRole('heading', { name: '心跳核心频道' })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('labels the forced online browser route as a visual preview, not a live receipt', () => {
|
||||
useGuanghuWorldLoginMock.mockReturnValue(worldLogin('online', {
|
||||
state: {
|
||||
...worldLogin('online').state,
|
||||
navigation: { domains: 5, map_hash: 'local-visual-preview' },
|
||||
workorderId: 'local-visual-preview',
|
||||
},
|
||||
}))
|
||||
|
||||
render(<HoloLakeHome locale="zh-CN" onEnterKnowledgeBase={vi.fn()} />)
|
||||
fireEvent.click(screen.getByRole('button', { name: /进入第五域/ }))
|
||||
|
||||
expect(screen.getAllByText('本地拓扑预览').length).toBeGreaterThan(0)
|
||||
expect(screen.getAllByText('未实时核验').length).toBeGreaterThan(0)
|
||||
expect(screen.getByText('本页仅展示本地登记拓扑,不能证明节点在线或人格体已恢复。')).toBeInTheDocument()
|
||||
expect(screen.queryByText('在线回执')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('shows receipt-backed Eternal Lake information without invented resonance scores', () => {
|
||||
useGuanghuRouterMock.mockReturnValue(onlineRouter())
|
||||
|
||||
|
|
@ -505,6 +523,33 @@ describe('HoloLakeHome', () => {
|
|||
expect(screen.getByRole('button', { name: '重新尝试' })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('translates a browser preview limitation into human recovery guidance', () => {
|
||||
useGuanghuWorldLoginMock.mockReturnValue(worldLogin('error', {
|
||||
state: {
|
||||
...worldLogin('error').state,
|
||||
error: 'guanghu_world_login_desktop_runtime_required',
|
||||
},
|
||||
}))
|
||||
|
||||
render(<HoloLakeHome locale="zh-CN" onEnterKnowledgeBase={vi.fn()} />)
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: /验证并进入第五域/ }))
|
||||
expect(screen.getByRole('alert')).toHaveTextContent('当前是本地视觉预览,未向第五域服务器发送登录请求。')
|
||||
expect(screen.getByRole('alert')).toHaveTextContent('请从已签名的 HoloLake 桌面端进入。')
|
||||
expect(screen.queryByText('guanghu_world_login_desktop_runtime_required')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not claim a live world connection before a receipt exists', () => {
|
||||
useGuanghuWorldLoginMock.mockReturnValue(worldLogin('idle'))
|
||||
|
||||
render(<HoloLakeHome locale="zh-CN" onEnterKnowledgeBase={vi.fn()} />)
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: /验证并进入第五域/ }))
|
||||
expect(screen.getByText('世界入口:等待验证')).toBeInTheDocument()
|
||||
expect(screen.getByText('语言共识层:未建立连接')).toBeInTheDocument()
|
||||
expect(screen.queryByText('世界状态:稳定')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('opens the public development repository from the entered Heartbeat Core channel', () => {
|
||||
useGuanghuRouterMock.mockReturnValue(onlineRouter())
|
||||
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ export function HoloLakeHome({
|
|||
const restoreAttempted = useRef(false)
|
||||
const livingRequestSequence = useRef(0)
|
||||
const worldOpen = login.state.phase === 'online'
|
||||
const isVisualPreview = login.state.workorderId === 'local-visual-preview'
|
||||
const fifthDomainOpen = worldOpen && route !== 'world'
|
||||
const worldRouterState = worldOpen && router.state.status !== 'online'
|
||||
? {
|
||||
|
|
@ -325,6 +326,7 @@ export function HoloLakeHome({
|
|||
if (route === 'fifth-domain') {
|
||||
return (
|
||||
<FifthDomainSystems
|
||||
evidenceMode={isVisualPreview ? 'visual-preview' : 'receipt'}
|
||||
onEnterEternalLake={() => navigate('eternal-lake-heart')}
|
||||
onEnterPufferfish={() => navigate('pufferfish')}
|
||||
/>
|
||||
|
|
@ -335,6 +337,7 @@ export function HoloLakeHome({
|
|||
return (
|
||||
<FifthDomainSystems
|
||||
detail="pufferfish"
|
||||
evidenceMode={isVisualPreview ? 'visual-preview' : 'receipt'}
|
||||
onEnterEternalLake={() => navigate('eternal-lake-heart')}
|
||||
onEnterPufferfish={() => navigate('pufferfish')}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue