From 32b661e8a7eafe9de008bbbc2066854ac3e73a11 Mon Sep 17 00:00:00 2001 From: saladday <1203511142@qq.com> Date: Fri, 25 Sep 2026 18:20:19 +0000 Subject: [PATCH 01/18] Read Core's address from config.json on the Nodes page The sandbox wizard no longer asks for a Core address or sends core_url: its review shows the deployment's read-only address (config.json's public_url) with where it is set. When Core rejects a configuration it cannot serve (409 sandbox_configuration_error, such as E2B without an HTTPS public_url), the wizard keeps Core's message and adds the config file and apply command from GET /core/v1/installation; nothing is marked uncertain. Nodes warns when nodes are still bound to an old address. --- .../sandbox/SandboxDeploymentSettings.tsx | 2 +- .../features/sandbox/SandboxManagerView.css | 7 ++ .../features/sandbox/SandboxManagerView.tsx | 19 ++++-- .../features/sandbox/SandboxSetupWizard.tsx | 64 +++++++++++-------- .../src/features/sandbox/sandbox-wizard.css | 43 +++++++++++++ apps/web/src/lib/installation.ts | 13 ++++ apps/web/src/lib/locale-strings.ts | 11 ++-- apps/web/src/lib/sandbox-labels.ts | 9 +++ 8 files changed, 128 insertions(+), 40 deletions(-) create mode 100644 apps/web/src/lib/installation.ts diff --git a/apps/web/src/features/sandbox/SandboxDeploymentSettings.tsx b/apps/web/src/features/sandbox/SandboxDeploymentSettings.tsx index 218b6db26..2f4043148 100644 --- a/apps/web/src/features/sandbox/SandboxDeploymentSettings.tsx +++ b/apps/web/src/features/sandbox/SandboxDeploymentSettings.tsx @@ -67,7 +67,7 @@ export function SandboxDeploymentSettings({ deployment, disabled, fresh, onMaint
{!changing ? : <>{t("Maintenance is enabled. New sandbox placement is paused.")}
: null} + {hostedNodes && staleNodes > 0 ?{staleNodes === 1 ? t("1 node is still bound to an old Core address. Add it again.") : t("{{count}} nodes are still bound to an old Core address. Add them again.", { count: staleNodes })}
: null}{release.source_commit!.slice(0, 12)} : {t("Runtime release needed")}{origin} : {t("Core address needed")}}{address} : "—"}{t("Set by public_url in config.json")}{rejection}
+ {configuration ? ( +{data.core_url}{about.public_url} : {t("installation.notSet")}}{about.source_commit.slice(0, 12)} : {t("installation.unknown")}}{t("howToCall.localOnly")}
: null}{about.public_url} : {t("installation.notSet")}}{about.source_commit.slice(0, 12)} : {t("installation.unknown")}}{t("Maintenance is enabled. New sandbox placement is paused.")}
: null} - {hostedNodes && staleNodes > 0 ?{staleNodes === 1 ? t("1 node is still bound to an old Core address. Add it again.") : t("{{count}} nodes are still bound to an old Core address. Add them again.", { count: staleNodes })}
: null} + {staleNodes.length ?{staleNodes.length === 1 + ? t("{{name}} is still bound to an old Core address. Remove it and add it again.", { name: staleNodes[0] }) + : t("{{count}} nodes are still bound to an old Core address: {{names}}. Remove them and add them again.", { count: staleNodes.length, names: staleNodes.join(", ") })}
: null}{t("howToCall.failed")}
{t("howToCall.loading")}
; + // The first sample's place, as the console's other first reads hold theirs. + :{t("howToCall.localOnly")}
; + body ={t("howToCall.noAddress")}
; } else { const samples = callSamples(base, apiKey); body = <> {installation.data.local_only ?{t("howToCall.localOnly")}
: null} -{t("howToCall.model")}
@@ -69,15 +73,29 @@ export function HowToCall({ apiKey }: { apiKey: string }) { ); } +/** A labelled sample with a copy button; when the clipboard refuses, the sample is selected to copy by hand. */ function CodeSample({ label, value }: { label: string; value: string }) { const { t } = useTranslation("keys"); + const code = useRef{value}
+ {value}
+ {state === "failed" ? {t("howToCall.copyFailed")}
: null}{address} : "—"}{t("Set by public_url in config.json")}{address} : "—"}
+ {t("Set by public_url in config.json")}
+ {installation.data?.local_only ? {t("Only the Core machine can reach this address: nodes on other machines and E2B sandboxes can't. Set an HTTPS public_url in config.json.")} : null}
+
+ {t("Enter the E2B key again to save.")}
+
{address} : "—"}
{t("Set by public_url in config.json")}
- {installation.data?.local_only ? {t("Only the Core machine can reach this address: nodes on other machines and E2B sandboxes can't. Set an HTTPS public_url in config.json.")} : null}
+ {installation.data?.local_only ? {t("Only the Core machine can reach this address: nodes on other machines and E2B sandboxes can't. Set a public_url in config.json that other machines can reach (not loopback).")} : null}
{t("loading")}
: null} {facts} {body} - {about ?{t("Maintenance is enabled. New sandbox placement is paused.")}
: null} {staleNodes.length ?{staleNodes.length === 1 ? t("{{name}} is still bound to an old Core address. Remove it and add it again.", { name: staleNodes[0] }) - : t("{{count}} nodes are still bound to an old Core address: {{names}}. Remove them and add them again.", { count: staleNodes.length, names: staleNodes.join(", ") })}
: null} + : t("{{count}} nodes are still bound to an old Core address: {{names}}. Remove them and add them again.", { count: staleNodes.length, names: new Intl.ListFormat(i18n.resolvedLanguage, { type: "conjunction" }).format(staleNodes) })} : null}{provider.base_url}