Skip to content

Commit

Permalink
feat: attributes filter / refactor of user data table (#17014)
Browse files Browse the repository at this point in the history
* WIP restored from .git cache

* fix exports

* sortable row model

* feat column visibility component

* wip filters with nuqs

* pull in unique values from table into filters

* correctly assign filters via v/f

* inital selection bar refactor

* data-table selection bar + optmistic update of delete

* dynamic link

* migrate member list table to new data-table

* total list shows filtered value > db valuie

* add filters for attributes

* type errors

* make content bigger on lg

* add mb-6 to teams user datatable to match spacing spec

* correctly render multi-badge

* fix: masss asignment optimistic UI

* fix type errors

* remove log

* fix toolbar type error

* chore: Remove debug artifact

* type errors

* Update apps/web/public/static/locales/en/common.json

* use max-w-fit

* chore: Remove unused translation now we don't specify 'mass' in assign

* perf: fix: use the onBlur event to prevent focus loss whilst the list is rerendering

* Move the data-table exports together in the main barrel, then import

* fix exports that were lost in a merge

* fix exports that were lost in a merge

* fix groupteammapping/availbilityslider

* fix overflow problems

* add scrollbar-thin class

* fix type error

* user serverside values for faceted filters

* pass filters to serverside

* filter serverside

* fix team server side filter

* add loaded x of y

* attributes icon change

* correct implementation for text/input attr optimistic

* type check fixes

* fix platform checks

* fix types again

* fix types again

* fix types again

* add use client

* add use client

* fix-types

* fix: Add missing translation in EN

* fix e2e tests via testid

* fix e2e tests via testid

* fix: Member invite popup not popping up

* Update copyInviteLink to new-member-button testid

* Hopefully fix test ids this time

* fix: Use the right buttons on the right pages

---------

Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
  • Loading branch information
4 people authored Oct 15, 2024
1 parent 0b914be commit 7e44e68
Show file tree
Hide file tree
Showing 43 changed files with 1,457 additions and 1,044 deletions.
6 changes: 5 additions & 1 deletion apps/web/pages/settings/organizations/members.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import MembersView from "@calcom/features/ee/organizations/pages/settings/members";
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
import SettingsLayout from "@calcom/features/settings/layouts/SettingsLayout";

import PageWrapper from "@components/PageWrapper";

Expand All @@ -8,6 +8,10 @@ export {
type PageProps,
} from "@calcom/features/ee/organizations/pages/settings/getServerSidePropsMembers";

export const getLayout = (page: React.ReactElement) => (
<SettingsLayout containerClassName="lg:max-w-screen-2xl">{page}</SettingsLayout>
);

const Page = () => <MembersView />;

Page.getLayout = getLayout;
Expand Down
2 changes: 1 addition & 1 deletion apps/web/playwright/organization/lib/inviteUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export async function acceptTeamOrOrgInvite(page: Page) {
}

async function inviteAnEmail(page: Page, invitedUserEmail: string) {
await page.locator('button:text("Add")').click();
await page.getByTestId("new-organization-member-button").click();
await page.locator('input[name="inviteUser"]').fill(invitedUserEmail);
await submitAndWaitForResponse(page, "/api/trpc/teams/inviteMember?batch=1", {
action: () => page.locator('button:text("Send invite")').click(),
Expand Down
24 changes: 16 additions & 8 deletions apps/web/playwright/organization/organization-invitation.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ test.describe("Organization", () => {
const invitedUserEmail = users.trackEmail({ username: "rick", domain: "domain.com" });
// '-domain' because the email doesn't match orgAutoAcceptEmail
const usernameDerivedFromEmail = `${invitedUserEmail.split("@")[0]}-domain`;
await inviteAnEmail(page, invitedUserEmail);
await inviteAnEmail(page, invitedUserEmail, true);
await expectUserToBeAMemberOfTeam({
page,
teamId: team.id,
Expand Down Expand Up @@ -164,7 +164,7 @@ test.describe("Organization", () => {

await test.step("By invite link", async () => {
await page.goto(`/settings/teams/${team.id}/members`);
const inviteLink = await copyInviteLink(page);
const inviteLink = await copyInviteLink(page, true);
const email = users.trackEmail({ username: "rick", domain: "domain.com" });
// '-domain' because the email doesn't match orgAutoAcceptEmail
const usernameDerivedFromEmail = `${email.split("@")[0]}-domain`;
Expand Down Expand Up @@ -333,7 +333,7 @@ test.describe("Organization", () => {
await page.goto(`/settings/teams/${team.id}/members`);
const invitedUserEmail = users.trackEmail({ username: "rick", domain: "example.com" });
const usernameDerivedFromEmail = invitedUserEmail.split("@")[0];
await inviteAnEmail(page, invitedUserEmail);
await inviteAnEmail(page, invitedUserEmail, true);
await expectUserToBeAMemberOfTeam({
page,
teamId: team.id,
Expand Down Expand Up @@ -391,7 +391,7 @@ test.describe("Organization", () => {
await test.step("By invite link", async () => {
await page.goto(`/settings/teams/${team.id}/members`);

const inviteLink = await copyInviteLink(page);
const inviteLink = await copyInviteLink(page, true);
const email = users.trackEmail({ username: "rick", domain: "example.com" });
// '-domain' because the email doesn't match orgAutoAcceptEmail
const usernameDerivedFromEmail = `${email.split("@")[0]}`;
Expand Down Expand Up @@ -481,8 +481,12 @@ export async function signupFromEmailInviteLink({
await signupPage.close();
}

async function inviteAnEmail(page: Page, invitedUserEmail: string) {
await page.locator('button:text("Add")').click();
async function inviteAnEmail(page: Page, invitedUserEmail: string, teamPage?: boolean) {
if (teamPage) {
await page.getByTestId("new-member-button").click();
} else {
await page.getByTestId("new-organization-member-button").click();
}
await page.locator('input[name="inviteUser"]').fill(invitedUserEmail);
const submitPromise = page.waitForResponse("/api/trpc/teams/inviteMember?batch=1");
await page.locator('button:text("Send invite")').click();
Expand Down Expand Up @@ -558,8 +562,12 @@ function assertInviteLink(inviteLink: string | null | undefined): asserts invite
if (!inviteLink) throw new Error("Invite link not found");
}

async function copyInviteLink(page: Page) {
await page.locator('button:text("Add")').click();
async function copyInviteLink(page: Page, teamPage?: boolean) {
if (teamPage) {
await page.getByTestId("new-member-button").click();
} else {
await page.getByTestId("new-organization-member-button").click();
}
const inviteLink = await getInviteLink(page);
return inviteLink;
}
7 changes: 4 additions & 3 deletions apps/web/playwright/team/team-invitation.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ test.describe("Team", () => {
username: "rick",
domain: `domain-${Date.now()}.com`,
});
await page.locator(`button:text("${t("add")}")`).click();
await page.getByTestId("new-member-button").click();
await page.locator('input[name="inviteUser"]').fill(invitedUserEmail);
await page.locator(`button:text("${t("send_invite")}")`).click();
const inviteLink = await expectInvitationEmailToBeReceived(
Expand Down Expand Up @@ -74,7 +74,8 @@ test.describe("Team", () => {
email: `user-invite-${Date.now()}@domain.com`,
password: "P4ssw0rd!",
});
await page.locator(`button:text("${t("add")}")`).click();

await page.getByTestId("new-member-button").click();
const inviteLink = await getInviteLink(page);

const context = await browser.newContext();
Expand Down Expand Up @@ -105,7 +106,7 @@ test.describe("Team", () => {
username: "rick",
domain: `example.com`,
});
await page.locator(`button:text("${t("add")}")`).click();
await page.getByTestId("new-member-button").click();
await page.locator('input[name="inviteUser"]').fill(invitedUserEmail);
await page.locator(`button:text("${t("send_invite")}")`).click();
await expectInvitationEmailToBeReceived(
Expand Down
4 changes: 4 additions & 0 deletions apps/web/public/static/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -2599,6 +2599,7 @@
"new_option": "New option",
"update_profile": "Update member",
"attribute_updated_successfully": "Attribute updated successfully",
"attribute_deleted_successfully": "Attribute deleted successfully",
"attributes_edited_successfully": "Attributes edited successfully",
"attribute_meta_description": "Manage attributes for your team members",
"attributes_edit_description": "Edit attributes for your team members",
Expand Down Expand Up @@ -2644,6 +2645,9 @@
"month_to_date": "month to date",
"year_to_date": "year to date",
"custom_range": "custom range",
"show_all_columns": "Show all columns",
"toggle_columns": "Toggle columns",
"no_columns_found": "No columns found",
"salesforce_create_record_as": "On booking, add events on and new attendees as:",
"salesforce_lead": "Lead",
"salesforce_contact_under_account": "Contact under an account",
Expand Down
22 changes: 15 additions & 7 deletions packages/features/ee/dsync/components/GroupTeamMappingTable.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { ColumnDef } from "@tanstack/react-table";
import { useReactTable, getCoreRowModel } from "@tanstack/react-table";
import { useRef, useState } from "react";

import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { DataTable, Button } from "@calcom/ui";
import { DataTable, DataTableToolbar } from "@calcom/ui";

import CreateTeamDialog from "./CreateTeamDialog";
import GroupNameCell from "./GroupNameCell";
Expand Down Expand Up @@ -44,14 +45,21 @@ const GroupTeamMappingTable = () => {
},
];

const table = useReactTable({
data: data?.teamGroupMapping ?? [],
columns,
getCoreRowModel: getCoreRowModel(),
});

return (
<>
<DataTable
data={data ? data.teamGroupMapping : []}
tableContainerRef={tableContainerRef}
columns={columns}
tableCTA={<Button onClick={() => setCreateTeamDialogOpen(true)}>Create team</Button>}
/>
<DataTable table={table} tableContainerRef={tableContainerRef}>
<DataTableToolbar.Root>
<DataTableToolbar.CTA onClick={() => setCreateTeamDialogOpen(true)}>
Create team
</DataTableToolbar.CTA>
</DataTableToolbar.Root>
</DataTable>
<CreateTeamDialog open={createTeamDialogOpen} onOpenChange={setCreateTeamDialogOpen} />
</>
);
Expand Down
Loading

0 comments on commit 7e44e68

Please sign in to comment.