Fix red main: mobile group kind, i18n catalogs, project picker check (#218)
* Fix red main: mobile group kind, i18n catalogs, project picker check Main CI failed on typecheck, unit tests and web E2E after the last two direct pushes. MobileGroup now carries the optional chat kind the mobile screens read, the Lingui catalogs are re-extracted with German strings for the new voice texts, the project overview plus icon meets the UI scale guard, and the sidebar E2E expects the renamed project lead. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R8L4XgqjAemFR2remB5hVY * Format files merged from main Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wy1md9QE1ayJbDCwJ4vAQs * Align E2E with the canvas close button and per-chat drafts The in-app browser now closes from the side panel header, and each chat keeps its own unsent draft. The group chat test waits for the settings save to land before switching chats, so the switch no longer races the panel closing. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wy1md9QE1ayJbDCwJ4vAQs --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
bb7cf3f55e
commit
263e3a31f8
@ -2144,9 +2144,7 @@ describe("stopThreadRuns", () => {
|
|||||||
updateMany: vi.fn().mockResolvedValue({ count: 1 }),
|
updateMany: vi.fn().mockResolvedValue({ count: 1 }),
|
||||||
},
|
},
|
||||||
run: {
|
run: {
|
||||||
updateManyAndReturn: vi
|
updateManyAndReturn: vi.fn().mockResolvedValue([{ id: "run-old", taskId: "task-old" }]),
|
||||||
.fn()
|
|
||||||
.mockResolvedValue([{ id: "run-old", taskId: "task-old" }]),
|
|
||||||
create: vi.fn().mockResolvedValue({ id: "run-new", status: "queued" }),
|
create: vi.fn().mockResolvedValue({ id: "run-new", status: "queued" }),
|
||||||
},
|
},
|
||||||
task: {
|
task: {
|
||||||
@ -2230,4 +2228,3 @@ describe("stopThreadRuns", () => {
|
|||||||
expect(events.notify).toHaveBeenCalledWith("thread-1", 42);
|
expect(events.notify).toHaveBeenCalledWith("thread-1", 42);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1424,9 +1424,7 @@ export async function sendQueuedThreadMessagesNow(
|
|||||||
status: "queued",
|
status: "queued",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const runCreatedAt = new Date(
|
const runCreatedAt = new Date(Math.max(Date.now(), last.message.createdAt.getTime() + 1));
|
||||||
Math.max(Date.now(), last.message.createdAt.getTime() + 1),
|
|
||||||
);
|
|
||||||
const run = await tx.run.create({
|
const run = await tx.run.create({
|
||||||
data: {
|
data: {
|
||||||
spaceId: actor.spaceId,
|
spaceId: actor.spaceId,
|
||||||
|
|||||||
@ -1660,9 +1660,7 @@ function Thread() {
|
|||||||
marginTop: 4,
|
marginTop: 4,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text style={{ color: tokens.mutedForeground, fontSize: 12 }}>
|
<Text style={{ color: tokens.mutedForeground, fontSize: 12 }}>{t("Queued")}</Text>
|
||||||
{t("Queued")}
|
|
||||||
</Text>
|
|
||||||
<Pressable
|
<Pressable
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
disabled={sendingNowId === message.id}
|
disabled={sendingNowId === message.id}
|
||||||
|
|||||||
@ -169,18 +169,26 @@ test("create group from + and see two bots in one transcript", async ({ page },
|
|||||||
await expect(desktopSettings.getByRole("button", { name: "Save", exact: true })).toBeEnabled();
|
await expect(desktopSettings.getByRole("button", { name: "Save", exact: true })).toBeEnabled();
|
||||||
await page.unroute("**/rpc/groups/update");
|
await page.unroute("**/rpc/groups/update");
|
||||||
await desktopSettings.getByRole("button", { name: "Save", exact: true }).click();
|
await desktopSettings.getByRole("button", { name: "Save", exact: true }).click();
|
||||||
|
// The panel closes once the save lands; switching chats before that races the layout change.
|
||||||
|
await expect(desktopSettings).toHaveAttribute("data-panel", "closed");
|
||||||
|
|
||||||
await page.getByRole("combobox", { name: "Message" }).fill("@Researcher unfinished draft");
|
await page.getByRole("combobox", { name: "Message" }).fill("@Researcher unfinished draft");
|
||||||
await projekte
|
await projekte
|
||||||
.getByRole("button", { name: /^Review team/ })
|
.getByRole("button", { name: /^Review team/ })
|
||||||
.first()
|
.first()
|
||||||
.click();
|
.click();
|
||||||
|
await expect(page).toHaveURL(new RegExp(`/app/g/${reviewGroup.id}`));
|
||||||
await expect(page.getByRole("combobox", { name: "Message" })).toHaveValue("");
|
await expect(page.getByRole("combobox", { name: "Message" })).toHaveValue("");
|
||||||
|
// Each chat keeps its own unsent draft.
|
||||||
await projekte
|
await projekte
|
||||||
.getByRole("button", { name: /^Draft team/ })
|
.getByRole("button", { name: /^Draft team/ })
|
||||||
.first()
|
.first()
|
||||||
.click();
|
.click();
|
||||||
await expect(page.getByRole("combobox", { name: "Message" })).toHaveValue("");
|
await expect(page).toHaveURL(new RegExp(`/app/g/${draftGroupId}`));
|
||||||
|
await expect(page.getByRole("combobox", { name: "Message" })).toHaveValue(
|
||||||
|
"@Researcher unfinished draft",
|
||||||
|
);
|
||||||
|
await page.getByRole("combobox", { name: "Message" }).fill("");
|
||||||
|
|
||||||
const composer = page.getByRole("combobox", { name: "Message" });
|
const composer = page.getByRole("combobox", { name: "Message" });
|
||||||
await composer.fill("@Res");
|
await composer.fill("@Res");
|
||||||
|
|||||||
@ -39,7 +39,7 @@ test("the in-app browser previews a page and follows it back to the browser", as
|
|||||||
await browser.getByRole("button", { name: "Open in browser" }).click();
|
await browser.getByRole("button", { name: "Open in browser" }).click();
|
||||||
expect((await popup).url()).toBe("https://preview.example/app");
|
expect((await popup).url()).toBe("https://preview.example/app");
|
||||||
|
|
||||||
await browser.getByRole("button", { name: "Close panel" }).click();
|
await page.getByTestId("side-panel").getByRole("button", { name: "Close panel" }).click();
|
||||||
await expect(browser).toHaveCount(0);
|
await expect(browser).toHaveCount(0);
|
||||||
// The last address comes back when the browser reopens.
|
// The last address comes back when the browser reopens.
|
||||||
await page.getByRole("button", { name: "Browser" }).click();
|
await page.getByRole("button", { name: "Browser" }).click();
|
||||||
@ -157,6 +157,6 @@ test("on desktop the page is a native view glued to the panel", async ({ page })
|
|||||||
await page.keyboard.press("Escape");
|
await page.keyboard.press("Escape");
|
||||||
await expect.poll(async () => (await calls()).at(-1)?.[0]).toBe("show");
|
await expect.poll(async () => (await calls()).at(-1)?.[0]).toBe("show");
|
||||||
|
|
||||||
await browser.getByRole("button", { name: "Close panel" }).click();
|
await page.getByTestId("side-panel").getByRole("button", { name: "Close panel" }).click();
|
||||||
await expect.poll(async () => (await calls()).at(-1)?.[0]).toBe("hide");
|
await expect.poll(async () => (await calls()).at(-1)?.[0]).toBe("hide");
|
||||||
});
|
});
|
||||||
|
|||||||
@ -47,14 +47,14 @@ test("conversations and projects stay separate; + opens bot picker", async ({ pa
|
|||||||
await expect(projekte.getByText("Side project", { exact: true })).toBeVisible();
|
await expect(projekte.getByText("Side project", { exact: true })).toBeVisible();
|
||||||
await expect(unterhaltungenOnly(page).getByText("Side project", { exact: true })).toHaveCount(0);
|
await expect(unterhaltungenOnly(page).getByText("Side project", { exact: true })).toHaveCount(0);
|
||||||
|
|
||||||
// The main agent leads the picker, even after other bots exist.
|
// The new project's main agent leads the picker, even after other bots exist.
|
||||||
await unterhaltungen.getByTestId("conversation-picker-trigger").click();
|
await unterhaltungen.getByTestId("conversation-picker-trigger").click();
|
||||||
await expect(
|
await expect(
|
||||||
page
|
page
|
||||||
.getByTestId("conversation-bot-picker")
|
.getByTestId("conversation-bot-picker")
|
||||||
.locator("[data-testid^='conversation-picker-bot-']")
|
.locator("[data-testid^='conversation-picker-bot-']")
|
||||||
.first(),
|
.first(),
|
||||||
).toHaveText("Chief");
|
).toHaveText("Projektmanager");
|
||||||
await page.keyboard.press("Escape");
|
await page.keyboard.press("Escape");
|
||||||
|
|
||||||
// Creating a project that already exists opens it instead of listing it twice.
|
// Creating a project that already exists opens it instead of listing it twice.
|
||||||
|
|||||||
@ -466,7 +466,7 @@ export function AgentOverview({
|
|||||||
onClick={onAddRoutine}
|
onClick={onAddRoutine}
|
||||||
className="gap-1 text-ui-label"
|
className="gap-1 text-ui-label"
|
||||||
>
|
>
|
||||||
<Plus size={13} strokeWidth={2.2} />
|
<Plus size={14} strokeWidth={2.2} />
|
||||||
<Trans>Routine</Trans>
|
<Trans>Routine</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@ -509,9 +509,7 @@ export const appContract = {
|
|||||||
)
|
)
|
||||||
.output(z.object({ ok: z.literal(true) })),
|
.output(z.object({ ok: z.literal(true) })),
|
||||||
stop: oc.input(threadTarget).output(z.object({ ok: z.literal(true) })),
|
stop: oc.input(threadTarget).output(z.object({ ok: z.literal(true) })),
|
||||||
sendNow: oc
|
sendNow: oc.input(threadTarget.safeExtend({ messageId: Id.optional() })).output(
|
||||||
.input(threadTarget.safeExtend({ messageId: Id.optional() }))
|
|
||||||
.output(
|
|
||||||
z.object({
|
z.object({
|
||||||
ok: z.literal(true),
|
ok: z.literal(true),
|
||||||
runIds: z.array(Id),
|
runIds: z.array(Id),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user