From 0a2a38942f2b99a60e525ba126e248233aee1e8a Mon Sep 17 00:00:00 2001
From: Pengusto <106893073+pengusto@users.noreply.github.com>
Date: Thu, 1 Oct 2026 14:12:38 +0200
Subject: [PATCH] fix(gui): stack native login confirmation and wrap actions
---
.../components/native-main-profiles-view.tsx | 8 ++--
.../native-main-confirmation-layout.test.tsx | 45 +++++++++++++++++++
2 files changed, 49 insertions(+), 4 deletions(-)
create mode 100644 gui/tests/native-main-confirmation-layout.test.tsx
diff --git a/gui/src/components/native-main-profiles-view.tsx b/gui/src/components/native-main-profiles-view.tsx
index 1ab3efc1441..0e773ee60a2 100644
--- a/gui/src/components/native-main-profiles-view.tsx
+++ b/gui/src/components/native-main-profiles-view.tsx
@@ -119,7 +119,7 @@ export function NativeMainProfilesView({
>}
{action && s &&
{
if (event.key === "Escape" && !busy) { event.preventDefault(); onSelect(null); }
}}>
@@ -131,9 +131,9 @@ export function NativeMainProfilesView({
onStopped(event.target.checked)} /> {t("nativeMain.stopped")}
-
-
-
}
diff --git a/gui/tests/native-main-confirmation-layout.test.tsx b/gui/tests/native-main-confirmation-layout.test.tsx
new file mode 100644
index 00000000000..27d01ad9cca
--- /dev/null
+++ b/gui/tests/native-main-confirmation-layout.test.tsx
@@ -0,0 +1,45 @@
+import { expect, test } from "bun:test";
+import { Window } from "happy-dom";
+import { renderToStaticMarkup } from "react-dom/server";
+import { NativeMainProfilesView, type NativeMainProfilesViewProps } from "../src/components/native-main-profiles-view";
+import { nativeMainTranslator } from "../src/i18n/native-main-copy";
+
+const home = `/srv/${"long-home-segment/".repeat(12)}.codex`;
+const profile = { id: "00000000-0000-4000-8000-000000000001", label: "example-profile", identityHint: "native:11111111", state: "inactive" as const };
+const noop = () => {};
+const props: NativeMainProfilesViewProps = {
+ t: nativeMainTranslator("de"), id: "fixture", open: true, busy: false, blocked: false,
+ snapshot: {
+ list: { effectiveCodexHome: home, activeProfileId: null, profiles: [profile] },
+ doctor: { effectiveCodexHome: home, activeProfileId: null, supported: true,
+ authStatus: "ok", keyStore: "available", vaultStatus: "ok", recoveryPending: false },
+ },
+ label: "", action: { kind: "switch", target: profile.id, label: profile.label },
+ confirmedStopped: false, previousId: null, error: null, result: null, refreshFailed: false,
+ onToggle: noop, onRefresh: noop, onLabel: noop, onRegister: noop, onSelect: noop,
+ onStopped: noop, onConfirm: noop,
+};
+const css = (await Bun.file(new URL("../src/styles.css", import.meta.url)).text()).replace(/^@import .*;$/gm, "");
+
+test("native confirmation overrides the shared horizontal notice and permits wrapped actions", async () => {
+ const window = new Window();
+ try {
+ window.document.head.innerHTML = ``;
+ window.document.body.innerHTML = renderToStaticMarkup();
+ const panel = window.document.querySelector('[role="group"]')!;
+ // happy-dom checks the cascade, not browser geometry. Inherited notice flex
+ // previously put heading, prose, path, consent and actions in one narrow row.
+ expect(window.getComputedStyle(panel).display).toBe("block");
+ expect(panel.querySelector("code")?.textContent).toBe(home);
+ expect(window.getComputedStyle(panel.querySelector(".row")!).flexWrap).toBe("wrap");
+ for (const button of panel.querySelectorAll("button")) {
+ const style = window.getComputedStyle(button);
+ expect(style.whiteSpace).toBe("normal");
+ expect(style.maxWidth).toBe("100%");
+ expect(style.overflowWrap).toBe("anywhere");
+ }
+ expect(panel.querySelector(".btn-primary")!.disabled).toBe(true);
+ } finally {
+ await window.happyDOM.close();
+ }
+});