fix(desktop): render the Nous Cloud-down recovery when a cloud backend fails (#85335)
The electron boot path now classifies a Nous Cloud 502/503/504 at both the OAuth ticket-mint and readiness boundaries and carries isCloudBackendDown / statusCode through DesktopBootProgress, but the renderer never consumed the structured signal — a cloud-backend failure fell into the generic remote- failure recovery copy. Make BootFailureOverlay branch on isCloudBackendDown: lead with the cloud-specific title/description, drop the local-only Repair action, and surface the actionable portal / Local-mode / Discord guidance (the electron factory's full message is still shown in the error box). Adds the cloudDown i18n keys (en + ar/ja/zh/zh-hant) and a regression test asserting the cloud-down recovery renders and Repair is dropped.
This commit is contained in:
@@ -98,4 +98,38 @@ describe('BootFailureOverlay', () => {
|
||||
restore()
|
||||
}
|
||||
})
|
||||
|
||||
it('shows the Nous Cloud down recovery when the backend flags isCloudBackendDown', async () => {
|
||||
const restore = stubDesktop(remoteToken)
|
||||
$desktopBoot.set({
|
||||
error: 'Nous Cloud agent ares-3009.agents.nousresearch.com is down (HTTP 503: server-side fault).',
|
||||
fakeMode: false,
|
||||
isCloudBackendDown: true,
|
||||
message: 'boot failed',
|
||||
phase: 'renderer.error',
|
||||
progress: 40,
|
||||
running: false,
|
||||
statusCode: 503,
|
||||
timestamp: Date.now(),
|
||||
visible: true
|
||||
})
|
||||
|
||||
try {
|
||||
render(<BootFailureOverlay />)
|
||||
// Cloud-specific title + actionable portal guidance instead of the
|
||||
// generic remote-failure copy.
|
||||
expect(await screen.findByText(/Nous Cloud agent is down/i)).toBeTruthy()
|
||||
expect(screen.getByText(/portal\.nousresearch\.com/i)).toBeTruthy()
|
||||
// Cloud-down is a remote failure: local-only Repair is dropped; the
|
||||
// actionable paths are Gateway settings + Use local gateway.
|
||||
expect(screen.queryByRole('button', { name: /repair/i })).toBeNull()
|
||||
expect(screen.getByRole('button', { name: /gateway settings/i })).toBeTruthy()
|
||||
expect(screen.getByRole('button', { name: /use local gateway/i })).toBeTruthy()
|
||||
// The electron-built error message (portal / local mode / Discord) is
|
||||
// still surfaced in the error box.
|
||||
expect(screen.getByText(/ares-3009\.agents\.nousresearch\.com/i)).toBeTruthy()
|
||||
} finally {
|
||||
restore()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -247,6 +247,11 @@ export function BootFailureOverlay() {
|
||||
|
||||
let actions: RecoveryAction[]
|
||||
let hint: string
|
||||
// The electron boot path flags a Nous Cloud backend-down (502/503/504) with
|
||||
// the structured isCloudBackendDown/statusCode it carries through boot
|
||||
// progress. When set, the recovery screen leads with the cloud-specific
|
||||
// guidance instead of the generic remote-failure copy (#85335).
|
||||
const cloudDown = Boolean(boot.isCloudBackendDown)
|
||||
|
||||
if (remoteReauth) {
|
||||
actions = [
|
||||
@@ -261,6 +266,12 @@ export function BootFailureOverlay() {
|
||||
localAction
|
||||
]
|
||||
hint = copy.remoteSignInHint(label)
|
||||
} else if (cloudDown) {
|
||||
// A Nous Cloud agent is down — the user cannot restart the managed
|
||||
// instance and Repair is local-only, so the actionable paths are Gateway
|
||||
// settings (switch host / use local), a secondary Retry, and open logs.
|
||||
actions = [settingsAction, { ...retryAction, variant: 'secondary' }, localAction]
|
||||
hint = copy.cloudDownHint
|
||||
} else if (remoteFailure) {
|
||||
actions = [settingsAction, { ...retryAction, variant: 'secondary' }, localAction]
|
||||
hint = copy.remoteFailureHint
|
||||
@@ -323,10 +334,10 @@ export function BootFailureOverlay() {
|
||||
<ErrorIcon className="mt-0.5" size="1.25rem" />
|
||||
<div>
|
||||
<h2 className="text-[0.9375rem] font-semibold tracking-tight">
|
||||
{remoteReauth ? copy.remoteTitle : copy.title}
|
||||
{remoteReauth ? copy.remoteTitle : cloudDown ? copy.cloudDownTitle : copy.title}
|
||||
</h2>
|
||||
<p className="mt-1 text-[0.8125rem] leading-5 text-(--ui-text-tertiary)">
|
||||
{remoteReauth ? copy.remoteDescription : copy.description}
|
||||
{remoteReauth ? copy.remoteDescription : cloudDown ? copy.cloudDownDescription : copy.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -85,6 +85,9 @@ export const ar = defineLocale({
|
||||
retry: 'إعادة المحاولة',
|
||||
repairInstall: 'إصلاح التثبيت',
|
||||
useLocalGateway: 'استخدام البوابة المحلية',
|
||||
cloudDownTitle: 'عامل Nous Cloud معطّل',
|
||||
cloudDownDescription: 'يعيد عامل السحابة المُدار من Nous الذي يتصل به هذا البوابة خطأً من الخادم. لا يمكن إعادة تشغيله من هنا — تحقق من حالته، أو بدّل إلى البوابة المحلية، أو احصل على الدعم.',
|
||||
cloudDownHint: 'تحقق من https://portal.nousresearch.com لحالة الخادم، أو استخدم البوابة المحلية أدناه، أو تواصل معنا عبر Discord (discord.gg/NousResearch).',
|
||||
openLogs: 'فتح السجلات',
|
||||
repairHint: 'يعيد الإصلاح تشغيل المثبت وقد يستغرق بضع دقائق على جهاز جديد.',
|
||||
remoteSignInHint: signInLabel =>
|
||||
|
||||
@@ -102,6 +102,11 @@ export const en: Translations = {
|
||||
`Signs out of the saved remote browser session, then opens ${signInLabel}. Use local gateway to switch to the bundled backend instead.`,
|
||||
signOutAndSignIn: 'Sign out & sign in',
|
||||
remoteFailureHint: 'Check the gateway URL and sign-in under Gateway settings, or switch to the local gateway.',
|
||||
cloudDownTitle: 'Nous Cloud agent is down',
|
||||
cloudDownDescription:
|
||||
'The Nous-managed cloud agent this gateway connects to is returning a server error. It cannot be restarted from here — check its status, switch to the local gateway, or get support.',
|
||||
cloudDownHint:
|
||||
'Check https://portal.nousresearch.com for backend status, use the local gateway below, or reach out on Discord (discord.gg/NousResearch).',
|
||||
hideRecentLogs: 'Hide recent logs',
|
||||
showRecentLogs: 'Show recent logs',
|
||||
signedInTitle: 'Signed in',
|
||||
|
||||
@@ -103,6 +103,11 @@ export const ja = defineLocale({
|
||||
signOutAndSignIn: 'サインアウトして再サインイン',
|
||||
remoteFailureHint:
|
||||
'「ゲートウェイ設定」でゲートウェイの URL とサインインを確認するか、ローカルゲートウェイに切り替えてください。',
|
||||
cloudDownTitle: 'Nous Cloud エージェントが停止しています',
|
||||
cloudDownDescription:
|
||||
'このゲートウェイが接続している Nous 管理のクラウドエージェントがサーバーエラーを返しています。ここから再起動することはできません。ステータスを確認するか、ローカルゲートウェイに切り替えるか、サポートに連絡してください。',
|
||||
cloudDownHint:
|
||||
'https://portal.nousresearch.com でバックエンドのステータスを確認するか、下のローカルゲートウェイを使用するか、Discord (discord.gg/NousResearch) でご連絡ください。',
|
||||
hideRecentLogs: '最近のログを非表示',
|
||||
showRecentLogs: '最近のログを表示',
|
||||
signedInTitle: 'サインインしました',
|
||||
|
||||
@@ -145,6 +145,9 @@ export interface Translations {
|
||||
remoteSignInHint: (signInLabel: string) => string
|
||||
signOutAndSignIn: string
|
||||
remoteFailureHint: string
|
||||
cloudDownTitle: string
|
||||
cloudDownDescription: string
|
||||
cloudDownHint: string
|
||||
hideRecentLogs: string
|
||||
showRecentLogs: string
|
||||
signedInTitle: string
|
||||
|
||||
@@ -100,6 +100,9 @@ export const zhHant = defineLocale({
|
||||
`先登出已儲存的遠端瀏覽器工作階段,然後開啟${signInLabel}。使用本機閘道可切換至內建後端。`,
|
||||
signOutAndSignIn: '登出並重新登入',
|
||||
remoteFailureHint: '在「閘道設定」中檢查閘道 URL 與登入,或切換至本機閘道。',
|
||||
cloudDownTitle: 'Nous Cloud 代理已停機',
|
||||
cloudDownDescription: '此閘道連線的 Nous 託管雲端代理正在回傳伺服器錯誤。無法在此處重新啟動——請檢查其狀態、切換至本機閘道,或取得支援。',
|
||||
cloudDownHint: '請前往 https://portal.nousresearch.com 查看後端狀態,使用下方的本機閘道,或在 Discord (discord.gg/NousResearch) 上與我們聯繫。',
|
||||
hideRecentLogs: '隱藏最近記錄',
|
||||
showRecentLogs: '顯示最近記錄',
|
||||
signedInTitle: '已登入',
|
||||
|
||||
@@ -100,6 +100,9 @@ export const zh: Translations = {
|
||||
`先退出已保存的远程浏览器会话,然后打开${signInLabel}。也可以使用本地网关切换到随应用提供的后端。`,
|
||||
signOutAndSignIn: '退出并重新登录',
|
||||
remoteFailureHint: '在“网关设置”中检查网关 URL 和登录,或切换到本地网关。',
|
||||
cloudDownTitle: 'Nous Cloud 代理已宕机',
|
||||
cloudDownDescription: '此网关连接的 Nous 托管云代理正在返回服务器错误。无法在此处重启——请检查其状态、切换到本地网关或获取支持。',
|
||||
cloudDownHint: '请访问 https://portal.nousresearch.com 查看后端状态,使用下方的本地网关,或在 Discord (discord.gg/NousResearch) 上联系我们。',
|
||||
hideRecentLogs: '隐藏最近日志',
|
||||
showRecentLogs: '显示最近日志',
|
||||
signedInTitle: '已登录',
|
||||
|
||||
Reference in New Issue
Block a user