History

fix(web): keep grouped project renames (#7831)

Mohtasham Murshid committed 2 months agov0.0.34-nightly.20260825.1185

Commit e67074f1 parent 5d766533 files · +49 −5Browse files

Unified · Split

3 files
  1. apps/web/src/components/settings/ProjectSettingsPanel.logic.test.ts +23 −0
  2. apps/web/src/components/settings/ProjectSettingsPanel.logic.ts +7 −0
  3. apps/web/src/components/settings/ProjectSettingsPanel.tsx +19 −5
apps/web/src/components/settings/ProjectSettingsPanel.logic.test.ts+23−0
@@ -0,0 +1,23 @@
1import { describe, expect, it } from "vite-plus/test";
2
3import { projectGroupTitleNeedsUpdate } from "./ProjectSettingsPanel.logic";
4
5describe("projectGroupTitleNeedsUpdate", () => {
6 it("updates divergent member titles even when the next title is the derived group label", () => {
7 expect(
8 projectGroupTitleNeedsUpdate(["local-title", "remote-title"], "Repository name", true),
9 ).toBe(true);
10 });
11
12 it("skips an untouched blur when the derived label differs from member titles", () => {
13 expect(projectGroupTitleNeedsUpdate(["repo-slug", "repo-slug"], "Repository Name", false)).toBe(
14 false,
15 );
16 });
17
18 it("skips an update when every member already has the next title", () => {
19 expect(projectGroupTitleNeedsUpdate(["Shared name", "Shared name"], "Shared name", true)).toBe(
20 false,
21 );
22 });
23});
apps/web/src/components/settings/ProjectSettingsPanel.logic.ts+7−0
@@ -0,0 +1,7 @@
1export function projectGroupTitleNeedsUpdate(
2 memberTitles: ReadonlyArray<string>,
3 nextTitle: string,
4 wasEdited: boolean,
5): boolean {
6 return wasEdited && memberTitles.some((title) => title !== nextTitle);
7}
apps/web/src/components/settings/ProjectSettingsPanel.tsx+19−5
@@ -113,6 +113,7 @@ import { · 112 unmodified lines
113 canPickExternalProjectFavicon,113 canPickExternalProjectFavicon,
114 ProjectFaviconPickerDialog,114 ProjectFaviconPickerDialog,
115} from "./ProjectFaviconPickerDialog";115} from "./ProjectFaviconPickerDialog";
116import { projectGroupTitleNeedsUpdate } from "./ProjectSettingsPanel.logic";
116 117
117export const PROJECT_GROUPING_MODE_LABELS: Record<SidebarProjectGroupingMode, string> = {118export const PROJECT_GROUPING_MODE_LABELS: Record<SidebarProjectGroupingMode, string> = {
118 repository: "Group by repository",119 repository: "Group by repository",
@@ -304,6 +305,7 @@ function ProjectDetail({ group }: { group: SidebarProjectSnapshot }) { · 185 unmodified lines
304 const removeKeybinding = useAtomCommand(serverEnvironment.removeKeybinding, {305 const removeKeybinding = useAtomCommand(serverEnvironment.removeKeybinding, {
305 reportFailure: false,306 reportFailure: false,
306 });307 });
308 const projectNameEditedRef = useRef(false);
307 const { copyToClipboard: copyPathToClipboard } = useCopyToClipboard<{ path: string }>({309 const { copyToClipboard: copyPathToClipboard } = useCopyToClipboard<{ path: string }>({
308 onCopy: ({ path }) => {310 onCopy: ({ path }) => {
309 toastManager.add({ type: "success", title: "Path copied", description: path });311 toastManager.add({ type: "success", title: "Path copied", description: path });
@@ -392,17 +394,24 @@ function ProjectDetail({ group }: { group: SidebarProjectSnapshot }) { · 82 unmodified lines
392 );394 );
393 395
394 const renameGroup = useCallback(396 const renameGroup = useCallback(
395 async (nextTitle: string) => {397 async (nextTitle: string, wasEdited: boolean) => {
396 const title = nextTitle.trim();398 const title = nextTitle.trim();
397 if (!title) {399 if (!title) {
398 toastManager.add({ type: "warning", title: "Project title cannot be empty" });400 toastManager.add({ type: "warning", title: "Project title cannot be empty" });
399 return;401 return;
400 }402 }
401 if (title === group.displayName) return;403 if (
402 if (group.memberProjects.every((member) => member.title === title)) return;404 !projectGroupTitleNeedsUpdate(
405 group.memberProjects.map((member) => member.title),
406 title,
407 wasEdited,
408 )
409 ) {
410 return;
411 }
403 await updateAllMembers({ title }, "Failed to rename project");412 await updateAllMembers({ title }, "Failed to rename project");
404 },413 },
405 [group.displayName, group.memberProjects, updateAllMembers],414 [group.memberProjects, updateAllMembers],
406 );415 );
407 416
408 // ----- default model -----417 // ----- default model -----
@@ -767,8 +776,13 @@ function ProjectDetail({ group }: { group: SidebarProjectSnapshot }) { · 358 unmodified lines
767 className="w-full sm:w-64"776 className="w-full sm:w-64"
768 aria-label="Project name"777 aria-label="Project name"
769 defaultValue={group.displayName}778 defaultValue={group.displayName}
779 onChange={() => {
780 projectNameEditedRef.current = true;
781 }}
770 onBlur={(event) => {782 onBlur={(event) => {
771 void renameGroup(event.currentTarget.value);783 const wasEdited = projectNameEditedRef.current;
784 projectNameEditedRef.current = false;
785 void renameGroup(event.currentTarget.value, wasEdited);
772 }}786 }}
773 onKeyDown={(event) => {787 onKeyDown={(event) => {
774 if (event.key === "Enter") event.currentTarget.blur();788 if (event.key === "Enter") event.currentTarget.blur();