Skip to content

Commit b390214

Browse files
committed
fix: workspace review fixes — auth view, clone errors, remove order, approval filter, cleanup ::migration::
1 parent ae5814c commit b390214

35 files changed

Lines changed: 1197 additions & 369 deletions

apps/builder/app/dashboard/dashboard-utils.test.ts

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { describe, test, expect } from "vitest";
2-
import { resolveCurrentWorkspace } from "./dashboard-utils";
2+
import {
3+
resolveCurrentWorkspace,
4+
isDowngradedForMember,
5+
} from "./dashboard-utils";
36
import type { WorkspaceWithRelation } from "@webstudio-is/project";
47

58
const createWorkspace = (
@@ -8,6 +11,7 @@ const createWorkspace = (
811
id: "ws-1",
912
name: "Workspace",
1013
isDefault: false,
14+
isDeleted: false,
1115
createdAt: "2024-01-01T00:00:00.000Z",
1216
userId: "user-1",
1317
workspaceRelation: "own",
@@ -98,3 +102,52 @@ describe("resolveCurrentWorkspace", () => {
98102
}
99103
});
100104
});
105+
106+
describe("isDowngradedForMember", () => {
107+
test("returns false for undefined workspace", () => {
108+
expect(isDowngradedForMember(undefined)).toBe(false);
109+
});
110+
111+
test("returns false for non-downgraded workspace", () => {
112+
expect(
113+
isDowngradedForMember(
114+
createWorkspace({ isDowngraded: false, workspaceRelation: "editors" })
115+
)
116+
).toBe(false);
117+
});
118+
119+
test("returns false for downgraded workspace owned by current user", () => {
120+
expect(
121+
isDowngradedForMember(
122+
createWorkspace({ isDowngraded: true, workspaceRelation: "own" })
123+
)
124+
).toBe(false);
125+
});
126+
127+
test("returns true for downgraded workspace where user is a member", () => {
128+
expect(
129+
isDowngradedForMember(
130+
createWorkspace({ isDowngraded: true, workspaceRelation: "editors" })
131+
)
132+
).toBe(true);
133+
});
134+
135+
test("returns true for downgraded workspace with viewer relation", () => {
136+
expect(
137+
isDowngradedForMember(
138+
createWorkspace({ isDowngraded: true, workspaceRelation: "viewers" })
139+
)
140+
).toBe(true);
141+
});
142+
143+
test("returns true for downgraded workspace with admin relation", () => {
144+
expect(
145+
isDowngradedForMember(
146+
createWorkspace({
147+
isDowngraded: true,
148+
workspaceRelation: "administrators",
149+
})
150+
)
151+
).toBe(true);
152+
});
153+
});

apps/builder/app/dashboard/dashboard-utils.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,13 @@ export const resolveCurrentWorkspace = (
2121
}
2222
return { type: "resolved", workspace: workspaces.find((w) => w.isDefault) };
2323
};
24+
25+
/**
26+
* Pure function: returns true when the workspace owner's plan has been
27+
* downgraded and the current user is a non-owner member.
28+
* In that case the dashboard should hide shared projects on reload.
29+
*/
30+
export const isDowngradedForMember = (
31+
workspace: WorkspaceWithRelation | undefined
32+
): boolean =>
33+
workspace?.isDowngraded === true && workspace.workspaceRelation !== "own";

apps/builder/app/dashboard/projects/project-dialogs.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,14 @@ const useRenameProject = ({
224224
: undefined;
225225
setErrors(errors);
226226
if (parsed.success) {
227-
send({ projectId, title }, () => {
227+
send({ projectId, title }, (result) => {
228+
if (result && "error" in result) {
229+
setErrors(result.error);
230+
return;
231+
}
232+
onOpenChange(false);
228233
revalidator.revalidate();
229234
});
230-
onOpenChange(false);
231235
}
232236
};
233237

apps/builder/app/dashboard/projects/transfer-dialog.stories.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,34 @@ const createRouter = (element: React.ReactElement) =>
2424

2525
export const OwnedAndSharedWorkspaces: StoryFn = () => {
2626
$workspaces.set([
27-
{ id: "ws-1", name: "My workspace", workspaceRelation: "own" },
28-
{ id: "ws-2", name: "Client projects", workspaceRelation: "own" },
27+
{
28+
id: "ws-1",
29+
name: "My workspace",
30+
isDefault: true,
31+
workspaceRelation: "own",
32+
},
33+
{
34+
id: "ws-2",
35+
name: "Client projects",
36+
isDefault: false,
37+
workspaceRelation: "own",
38+
},
2939
{
3040
id: "ws-3",
3141
name: "Team workspace (admin)",
42+
isDefault: false,
3243
workspaceRelation: "administrators",
3344
},
3445
{
3546
id: "ws-4",
3647
name: "Agency workspace (editor)",
48+
isDefault: false,
3749
workspaceRelation: "editors",
3850
},
3951
{
4052
id: "ws-5",
4153
name: "Partner workspace (builder)",
54+
isDefault: false,
4255
workspaceRelation: "builders",
4356
},
4457
]);

apps/builder/app/dashboard/projects/transfer-dialog.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,21 +87,23 @@ export const TransferProjectDialog = ({
8787
return urlWorkspaceId;
8888
}
8989
// When no workspaceId in URL, the user is on the default workspace
90-
return ownedWorkspaces[0]?.id;
90+
return (
91+
ownedWorkspaces.find((w) => w.isDefault)?.id ?? ownedWorkspaces[0]?.id
92+
);
9193
};
9294

9395
// Reset state when dialog opens — pre-select the current workspace
9496
useEffect(() => {
9597
if (isOpen) {
9698
setSelectedWorkspaceId(getCurrentWorkspaceId());
97-
return;
99+
} else {
100+
setEmail("");
101+
setSelectedWorkspaceId(undefined);
102+
setFilteredWorkspaces([]);
103+
setIsFiltered(false);
104+
setError(undefined);
105+
clearTimeout(debounceTimerRef.current);
98106
}
99-
setEmail("");
100-
setSelectedWorkspaceId(undefined);
101-
setFilteredWorkspaces([]);
102-
setIsFiltered(false);
103-
setError(undefined);
104-
clearTimeout(debounceTimerRef.current);
105107

106108
return () => clearTimeout(debounceTimerRef.current);
107109
// eslint-disable-next-line react-hooks/exhaustive-deps

apps/builder/app/dashboard/shared/subscription.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,13 @@ export const startDashboardSubscription = () => {
8888
export const stopDashboardSubscription = () => {
8989
subscription?.unsubscribe();
9090
subscription = undefined;
91+
manager?.destroy();
92+
manager = undefined;
9193
isFirstLoad = true;
9294
};
9395

9496
/**
9597
* Force an immediate refresh — useful after accept/decline mutations
9698
* so the popover updates without waiting for the next poll cycle.
9799
*/
98-
export const refreshNotifications = () => getManager().refresh();
100+
export const refreshNotifications = () => manager?.refresh();

apps/builder/app/dashboard/workspace-dialogs.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const createWorkspace = (overrides: Partial<Workspace> = {}): Workspace => ({
1717
id: "ws-1",
1818
name: "Client projects",
1919
isDefault: false,
20+
isDeleted: false,
2021
createdAt: new Date().toISOString(),
2122
userId: "user-1",
2223
...overrides,

apps/builder/app/dashboard/workspace-dialogs.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ const MemberRow = (props: MemberRowProps) => {
216216
workspaceRelationLabels[option]
217217
}
218218
onChange={handleChange}
219-
disabled={!props.canRemove}
219+
disabled={!props.canRemove || role === "pending"}
220220
/>
221221
);
222222
})();

apps/builder/app/dashboard/workspace-selector.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const createWorkspace = (
1616
id: "ws-1",
1717
name: "My workspace",
1818
isDefault: false,
19+
isDeleted: false,
1920
createdAt: new Date().toISOString(),
2021
userId: "user-1",
2122
workspaceRelation: "own",

apps/builder/app/dashboard/workspace-selector.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const createWorkspace = (
1010
id: "ws-1",
1111
name: "Workspace",
1212
isDefault: false,
13+
isDeleted: false,
1314
createdAt: "2024-01-01T00:00:00.000Z",
1415
userId: "user-1",
1516
workspaceRelation: "own",

0 commit comments

Comments
 (0)