fix(web): Projekte + opens project create, not group form

Wire the Projekte sidebar + and empty-state action to NewSpaceDialog
with project labels instead of the group creation panel. Keep space
wording for the global create menu. Add de locale strings and an e2e
regression test.

Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
This commit is contained in:
Cursor Agent 2026-09-21 23:30:57 +00:00
parent ed621b1467
commit cc59fce7bd
7 changed files with 109 additions and 21 deletions

View File

@ -1,6 +1,21 @@
import { expect, test } from "@playwright/test";
import { captureScreenshot, completeOnboarding, openNewSpace, rpc, signup } from "./helpers";
test("Projekte + opens new project dialog instead of group form", async ({ page }) => {
const stamp = Date.now();
await signup(page, `proj-create-${stamp}@rakazo.test`, "password12", "Project Create");
await completeOnboarding(page);
await page.goto("/app");
await page.waitForURL(/\/app\/[^/]+$/);
const projekte = page.locator(".sidebar-projekte");
await projekte.getByRole("button", { name: "Create a project" }).click();
await expect(page.getByRole("dialog", { name: "New project" })).toBeVisible();
await expect(page.getByRole("button", { name: "Create project", exact: true })).toBeVisible();
await expect(page.getByTestId("side-panel")).not.toHaveAttribute("data-panel", "create-group");
await expect(page.getByText("New group", { exact: true })).toHaveCount(0);
});
test("spaces stay invisible by default and chat creation requires approval", async ({
page,
}, testInfo) => {

View File

@ -476,6 +476,12 @@
"Server name": "Servername",
"Server URL": "Server-URL",
"Set up voice to call": "Stimme für Anrufe einrichten",
"Create a project": "Projekt erstellen",
"Create project": "Projekt erstellen",
"Could not create project": "Projekt konnte nicht erstellt werden",
"New project": "Neues Projekt",
"No projects yet.": "Noch keine Projekte.",
"Threads by topic · folders": "Threads nach Thema · Ordner",
"Settings": "Einstellungen",
"Settings: General": "Einstellungen: Allgemein",
"Settings: Usage": "Einstellungen: Nutzung",

View File

@ -180,6 +180,13 @@ describe("lingui catalogs", () => {
expect(i18n._({ id: "Cancel", message: "Cancel" })).toBe("Abbrechen");
expect(i18n._({ id: "Search", message: "Search" })).toBe("Suchen");
expect(i18n._({ id: "To:", message: "To:" })).toBe("An:");
expect(i18n._({ id: "Create a project", message: "Create a project" })).toBe(
"Projekt erstellen",
);
expect(i18n._({ id: "New project", message: "New project" })).toBe("Neues Projekt");
expect(i18n._({ id: "No projects yet.", message: "No projects yet." })).toBe(
"Noch keine Projekte.",
);
i18n.load("ko", ko as Record<string, string>);
i18n.activate("ko");

View File

@ -1124,7 +1124,11 @@ msgstr "Gruppe konnte nicht erstellt werden"
msgid "Could not create section"
msgstr "Abschnitt konnte nicht erstellt werden"
#: src/pages/shell/dialogs.tsx:52
#: src/pages/shell/dialogs.tsx:59
msgid "Could not create project"
msgstr "Projekt konnte nicht erstellt werden"
#: src/pages/shell/dialogs.tsx:60
msgid "Could not create space"
msgstr ""
@ -1422,6 +1426,15 @@ msgstr "Neue Gruppe erstellen"
msgid "Create new Space"
msgstr "Neuen Space erstellen"
#: src/pages/Shell.tsx:3073
#: src/pages/Shell.tsx:3099
msgid "Create a project"
msgstr "Projekt erstellen"
#: src/pages/shell/dialogs.tsx:103
msgid "Create project"
msgstr "Projekt erstellen"
#: src/pages/RoutineEditor.tsx:122
#: src/pages/RoutineEditor.tsx:123
msgid "Create Routine"
@ -2454,7 +2467,11 @@ msgstr "Neuer Abschnitt"
msgid "New skill"
msgstr "Neuer Skill"
#: src/pages/shell/dialogs.tsx:68
#: src/pages/shell/dialogs.tsx:77
msgid "New project"
msgstr "Neues Projekt"
#: src/pages/shell/dialogs.tsx:77
msgid "New space"
msgstr ""
@ -2522,6 +2539,9 @@ msgstr "Noch keine Nachrichten mit {peerBotName}."
msgid "No model catalog is available."
msgstr "Kein Modellkatalog verfügbar."
msgid "No projects yet."
msgstr "Noch keine Projekte."
#: src/pages/ModelSettingsOverlay.tsx:453
msgid "No providers found."
msgstr "Keine Anbieter gefunden."
@ -3481,6 +3501,9 @@ msgstr "Wird gewechselt…"
msgid "System"
msgstr "System"
msgid "Threads by topic · folders"
msgstr "Threads nach Thema · Ordner"
#: src/components/teach/TeachComputerOverlay.tsx:205
#: src/components/teach/TeachComputerOverlay.tsx:213
msgid "Teach a task"

View File

@ -1124,7 +1124,11 @@ msgstr "Could not create group"
msgid "Could not create section"
msgstr "Could not create section"
#: src/pages/shell/dialogs.tsx:52
#: src/pages/shell/dialogs.tsx:59
msgid "Could not create project"
msgstr "Could not create project"
#: src/pages/shell/dialogs.tsx:60
msgid "Could not create space"
msgstr "Could not create space"
@ -1422,6 +1426,15 @@ msgstr "Create new Group"
msgid "Create new Space"
msgstr "Create new Space"
#: src/pages/Shell.tsx:3073
#: src/pages/Shell.tsx:3099
msgid "Create a project"
msgstr "Create a project"
#: src/pages/shell/dialogs.tsx:103
msgid "Create project"
msgstr "Create project"
#: src/pages/RoutineEditor.tsx:122
#: src/pages/RoutineEditor.tsx:123
msgid "Create Routine"
@ -2454,7 +2467,11 @@ msgstr "New section"
msgid "New skill"
msgstr "New skill"
#: src/pages/shell/dialogs.tsx:68
#: src/pages/shell/dialogs.tsx:77
msgid "New project"
msgstr "New project"
#: src/pages/shell/dialogs.tsx:77
msgid "New space"
msgstr "New space"
@ -2523,6 +2540,9 @@ msgid "No model catalog is available."
msgstr "No model catalog is available."
#: src/pages/ModelSettingsOverlay.tsx:453
msgid "No projects yet."
msgstr "No projects yet."
msgid "No providers found."
msgstr "No providers found."
@ -3483,6 +3503,9 @@ msgstr "System"
#: src/components/teach/TeachComputerOverlay.tsx:205
#: src/components/teach/TeachComputerOverlay.tsx:213
msgid "Threads by topic · folders"
msgstr "Threads by topic · folders"
msgid "Teach a task"
msgstr "Teach a task"

View File

@ -578,6 +578,11 @@ export function ShellPage() {
null,
);
const [newSpaceOpen, setNewSpaceOpen] = useState(false);
const [newSpaceDialogVariant, setNewSpaceDialogVariant] = useState<"space" | "project">("space");
const openNewSpaceDialog = useCallback((variant: "space" | "project") => {
setNewSpaceDialogVariant(variant);
setNewSpaceOpen(true);
}, []);
const [pickerInfoTopic, setPickerInfoTopic] = useState<"group" | "space" | null>(null);
const [commandPaletteOpen, setCommandPaletteOpen] = useState(false);
@ -2980,7 +2985,7 @@ export function ShellPage() {
onCreateSpace={() => {
setCreateMenuOpen(false);
setMobileSidebarOpen(false);
setNewSpaceOpen(true);
openNewSpaceDialog("space");
}}
onShowGroupInfo={() => {
setCreateMenuOpen(false);
@ -3060,21 +3065,14 @@ export function ShellPage() {
<div>
<div className="rk-shell-section-label">{t`Projekte`}</div>
<p className="mt-0.5 px-0.5 text-ui-caption text-muted-foreground/70">
{t`Group conversations · folders`}
{t`Threads by topic · folders`}
</p>
</div>
<div className="flex items-center gap-1.5">
<button
type="button"
aria-label="Einstellungen"
className="text-muted-foreground/60 hover:text-foreground/90 transition-colors"
>
<Settings strokeWidth={2} className="size-icon-sm" />
</button>
<button
type="button"
aria-label="Neues Projekt"
onClick={() => setPanel("create-group")}
aria-label={t`Create a project`}
onClick={() => openNewSpaceDialog("project")}
className="text-muted-foreground/60 hover:text-foreground/90 transition-colors"
>
<Plus strokeWidth={2.5} className="size-icon-md" />
@ -3090,15 +3088,15 @@ export function ShellPage() {
}))
.filter((group) => group.bots.length > 0 || group.emptySpaceId).length === 0 ? (
<div className="p-4 text-center text-ui-label text-muted-foreground">
<p>{t`No project conversations yet.`}</p>
<p>{t`No projects yet.`}</p>
<Button
variant="outline"
size="sm"
className="mt-2 text-ui-label"
onClick={() => setPanel("create-group")}
onClick={() => openNewSpaceDialog("project")}
>
<Plus className="mr-1 size-icon-sm" />
{t`Start a group conversation`}
{t`Create a project`}
</Button>
</div>
) : null}
@ -4791,6 +4789,7 @@ export function ShellPage() {
{newSpaceOpen ? (
<NewSpaceDialog
variant={newSpaceDialogVariant}
onCancel={() => setNewSpaceOpen(false)}
onConfirm={async (name) => {
const space = await rpc.spaces.create({ name });

View File

@ -31,9 +31,11 @@ function closeUnlessBusy(busy: boolean, onCancel: () => void) {
}
export function NewSpaceDialog({
variant = "space",
onCancel,
onConfirm,
}: {
variant?: "space" | "project";
onCancel: () => void;
onConfirm: (name: string) => Promise<void>;
}) {
@ -42,6 +44,7 @@ export function NewSpaceDialog({
const [name, setName] = useState("");
const [saving, setSaving] = useState(false);
const [error, setError] = useState<string | null>(null);
const isProject = variant === "project";
const create = () => {
const trimmed = name.trim();
@ -49,7 +52,13 @@ export function NewSpaceDialog({
setSaving(true);
setError(null);
void onConfirm(trimmed).catch((reason: unknown) => {
setError(reason instanceof Error ? reason.message : t`Could not create space`);
setError(
reason instanceof Error
? reason.message
: isProject
? t`Could not create project`
: t`Could not create space`,
);
setSaving(false);
});
};
@ -65,7 +74,7 @@ export function NewSpaceDialog({
className="text-muted-foreground"
aria-hidden="true"
/>
<Trans>New space</Trans>
{isProject ? <Trans>New project</Trans> : <Trans>New space</Trans>}
</DialogTitle>
</DialogHeader>
<label htmlFor={nameId} className="block text-ui-body text-foreground/75">
@ -88,7 +97,13 @@ export function NewSpaceDialog({
<Trans>Cancel</Trans>
</Button>
<Button disabled={saving || !name.trim()} onClick={create}>
{saving ? <Trans>Creating…</Trans> : <Trans>Create space</Trans>}
{saving ? (
<Trans>Creating…</Trans>
) : isProject ? (
<Trans>Create project</Trans>
) : (
<Trans>Create space</Trans>
)}
</Button>
</DialogFooter>
</DialogContent>