Skip to content

Commit 7f48c7f

Browse files
authored
fix: Ignore userIds form filter segment if no permission (calcom#24194)
* Update get.handler.ts * fix: Ignore userIds form filter segment if no permission * add tests * Update booking-filters.e2e.ts * Update booking-filters.e2e.ts
1 parent 2101051 commit 7f48c7f

2 files changed

Lines changed: 98 additions & 4 deletions

File tree

apps/web/modules/bookings/views/bookings-view.tsx

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { useMemo } from "react";
88
import dayjs from "@calcom/dayjs";
99
import {
1010
DataTableProvider,
11+
DataTableFilters,
12+
DataTableSegment,
1113
type SystemFilterSegment,
1214
useDataTable,
1315
ColumnFilterType,
@@ -403,10 +405,25 @@ function BookingsContent({ status, permissions, isCalendarViewEnabled }: Booking
403405
</div>
404406
<main className="w-full">
405407
<div className="flex w-full flex-col">
406-
{query.status === "error" && (
407-
<Alert severity="error" title={t("something_went_wrong")} message={query.error.message} />
408-
)}
409-
{query.status !== "error" && (
408+
{query.status === "error" ? (
409+
<>
410+
<div className="grid w-full items-center gap-2 pb-4">
411+
<div className="flex w-full flex-col gap-2">
412+
<div className="flex w-full flex-wrap justify-between gap-2">
413+
<div className="flex flex-wrap items-center gap-2">
414+
<DataTableFilters.FilterBar table={table} />
415+
</div>
416+
<div className="flex flex-wrap items-center gap-2">
417+
<DataTableFilters.ClearFiltersButton />
418+
<DataTableSegment.SaveButton />
419+
<DataTableSegment.Select />
420+
</div>
421+
</div>
422+
</div>
423+
</div>
424+
<Alert severity="error" title={t("something_went_wrong")} message={query.error.message} />
425+
</>
426+
) : (
410427
<>
411428
{!!bookingsToday.length && status === "upcoming" && (
412429
<WipeMyCalActionButton bookingStatus={status} bookingsEmpty={isEmpty} />

apps/web/playwright/booking-filters.e2e.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { expect } from "@playwright/test";
22

33
import { applySelectFilter } from "./filter-helpers";
44
import { test } from "./lib/fixtures";
5+
import { MembershipRole } from "@calcom/prisma/enums";
56

67
test.describe.configure({ mode: "parallel" });
78

@@ -228,4 +229,80 @@ test.describe("Booking Filters", () => {
228229
const eventTypeSearchParams = new URL(page.url()).searchParams;
229230
expect(eventTypeSearchParams.get("activeFilters")).toBeFalsy();
230231
});
232+
233+
test("Filter segments with removed team members should not cause stuck UI", async ({
234+
page,
235+
users,
236+
prisma,
237+
}) => {
238+
const teamOwner = await users.create(undefined, {
239+
hasTeam: true,
240+
teamRole: MembershipRole.OWNER,
241+
});
242+
const secondUser = await users.create({ name: "Second" });
243+
const thirdUser = await users.create({ name: "Third" });
244+
const { team } = await teamOwner.getFirstTeamMembership();
245+
// Add teammates to the team
246+
await prisma.membership.createMany({
247+
data: [
248+
{
249+
teamId: team.id,
250+
userId: secondUser.id,
251+
role: MembershipRole.MEMBER,
252+
accepted: true,
253+
},
254+
{
255+
teamId: team.id,
256+
userId: thirdUser.id,
257+
role: MembershipRole.MEMBER,
258+
accepted: true,
259+
},
260+
],
261+
});
262+
263+
await teamOwner.apiLogin();
264+
265+
const bookingsGetResponse = page.waitForResponse((response) =>
266+
/\/api\/trpc\/bookings\/get.*/.test(response.url())
267+
);
268+
269+
await page.goto(`/bookings/upcoming`);
270+
271+
await bookingsGetResponse;
272+
273+
await test.step("Create filter segment with team member userIds", async () => {
274+
await page.getByTestId("add-filter-button").click();
275+
await page.getByTestId("add-filter-item-userId").click();
276+
277+
await page.getByTestId(`select-filter-options-userId`).getByRole("option", { name: "Second" }).click();
278+
await page.getByTestId(`select-filter-options-userId`).getByRole("option", { name: "Third" }).click();
279+
await page.keyboard.press("Escape");
280+
281+
const segmentName = "Team Members Filter";
282+
await page.getByTestId("save-filter-segment-button").click();
283+
await page.getByTestId("save-filter-segment-name").fill(segmentName);
284+
await page.getByTestId("save-filter-segment-dialog").getByRole("button", { name: "Save" }).click();
285+
await expect(page.getByText("Filter segment saved")).toBeVisible();
286+
});
287+
288+
await test.step("Remove one team member from team", async () => {
289+
await prisma.membership.delete({
290+
where: {
291+
userId_teamId: {
292+
userId: secondUser.id,
293+
teamId: team.id,
294+
},
295+
},
296+
});
297+
});
298+
299+
await test.step("Verify filter segment still works and UI is not stuck", async () => {
300+
await page.reload();
301+
await page.waitForLoadState("domcontentloaded");
302+
303+
await expect(page.getByTestId("add-filter-button")).toBeVisible();
304+
305+
await expect(page.getByText("You do not have permissions")).toBeHidden();
306+
});
307+
});
231308
});

0 commit comments

Comments
 (0)