feat: blocklist table (#24459)
* feat: blocklist table * feat: blocklist table * refactor: feedback * chore: add select * UI improvements * chore: remove un unsed --------- Co-authored-by: CarinaWolli <wollencarina@gmail.com>
This commit is contained in:
1 parent
17ab088af8
commit
5a59bb86cd
30 files changed
+2209
-24
No files matched your search
@@ -1,4 +1,6 @@
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
"use client";
|
||||
|
||||
|
||||
import debounce from "lodash/debounce";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ function MembersList(props: MembersListProps) {
|
||||
return (
|
||||
<div className="flex flex-col gap-y-3">
|
||||
{members?.length && team ? (
|
||||
<ul className="divide-subtle border-subtle divide-y rounded-md border ">
|
||||
<ul className="divide-subtle border-subtle divide-y rounded-md border">
|
||||
{members.map((member) => {
|
||||
return <MemberListItem key={member.id} member={member} />;
|
||||
})}
|
||||
@@ -95,7 +95,6 @@ const MembersView = () => {
|
||||
const router = useRouter();
|
||||
const params = useParamsWithFallback();
|
||||
const teamId = Number(params.id);
|
||||
const session = useSession();
|
||||
const utils = trpc.useUtils();
|
||||
// const [query, setQuery] = useState<string | undefined>("");
|
||||
// const [queryToFetch, setQueryToFetch] = useState<string | undefined>("");
|
||||
@@ -193,7 +192,7 @@ const MembersView = () => {
|
||||
|
||||
{team && (
|
||||
<>
|
||||
<hr className="border-subtle my-8" />
|
||||
<hr className="border-subtle my-8 mt-6" />
|
||||
<MakeTeamPrivateSwitch
|
||||
teamId={team.id}
|
||||
isPrivate={team.isPrivate}
|
||||
|
||||
@@ -1,10 +1,26 @@
|
||||
"use client";
|
||||
|
||||
import { DataTableProvider } from "@calcom/features/data-table";
|
||||
import { useSegments } from "@calcom/features/data-table/hooks/useSegments";
|
||||
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
|
||||
import MakeTeamPrivateSwitch from "@calcom/features/ee/teams/components/MakeTeamPrivateSwitch";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
|
||||
const PrivacyView = ({ permissions }: { permissions: { canRead: boolean; canEdit: boolean } }) => {
|
||||
import { BlocklistTable } from "~/settings/organizations/privacy/blocklist-table";
|
||||
|
||||
const PrivacyView = ({
|
||||
permissions,
|
||||
watchlistPermissions,
|
||||
}: {
|
||||
permissions: { canRead: boolean; canEdit: boolean };
|
||||
watchlistPermissions?: {
|
||||
canRead: boolean;
|
||||
canCreate: boolean;
|
||||
canDelete: boolean;
|
||||
};
|
||||
}) => {
|
||||
const { t } = useLocale();
|
||||
const { data: currentOrg } = trpc.viewer.organizations.listCurrent.useQuery();
|
||||
const isInviteOpen = !currentOrg?.user.accepted;
|
||||
|
||||
@@ -14,13 +30,27 @@ const PrivacyView = ({ permissions }: { permissions: { canRead: boolean; canEdit
|
||||
|
||||
return (
|
||||
<LicenseRequired>
|
||||
<div>
|
||||
<div className="space-y-8">
|
||||
<MakeTeamPrivateSwitch
|
||||
isOrg={true}
|
||||
teamId={currentOrg.id}
|
||||
isPrivate={currentOrg.isPrivate}
|
||||
disabled={isDisabled}
|
||||
/>
|
||||
|
||||
{watchlistPermissions?.canRead && (
|
||||
<div>
|
||||
<div>
|
||||
<h2 className="text-emphasis text-base font-semibold">{t("organization_blocklist")}</h2>
|
||||
<p className="text-muted text-sm">{t("manage_blocked_emails_and_domains")}</p>
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
<DataTableProvider useSegments={useSegments} defaultPageSize={25}>
|
||||
<BlocklistTable permissions={watchlistPermissions} />
|
||||
</DataTableProvider>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</LicenseRequired>
|
||||
);
|
||||
|
||||
@@ -45,7 +45,6 @@ const MakeTeamPrivateSwitch = ({
|
||||
setTeamPrivate(checked);
|
||||
mutation.mutate({ id: teamId, isPrivate: checked });
|
||||
}}
|
||||
switchContainerClassName="mt-6"
|
||||
data-testid="make-team-private-check"
|
||||
/>
|
||||
</>
|
||||
|
||||
@@ -159,7 +159,6 @@ const PrivacySettingsView = ({ team }: ProfileViewProps) => {
|
||||
const isAdmin = team && checkAdminOrOwner(team.membership.role);
|
||||
const isOrgAdminOrOwner = checkAdminOrOwner(session?.data?.user.org?.role);
|
||||
const isInviteOpen = !team?.membership.accepted;
|
||||
const { t } = useLocale();
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -173,12 +172,14 @@ const PrivacySettingsView = ({ team }: ProfileViewProps) => {
|
||||
)}
|
||||
|
||||
{team && team.id && (isAdmin || isOrgAdminOrOwner) && (
|
||||
<MakeTeamPrivateSwitch
|
||||
isOrg={false}
|
||||
teamId={team.id}
|
||||
isPrivate={team.isPrivate ?? false}
|
||||
disabled={isInviteOpen}
|
||||
/>
|
||||
<div className="mt-6">
|
||||
<MakeTeamPrivateSwitch
|
||||
isOrg={false}
|
||||
teamId={team.id}
|
||||
isPrivate={team.isPrivate ?? false}
|
||||
disabled={isInviteOpen}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -12,6 +12,7 @@ export enum Resource {
|
||||
Webhook = "webhook",
|
||||
Availability = "availability",
|
||||
OutOfOffice = "ooo",
|
||||
Watchlist = "watchlist",
|
||||
}
|
||||
|
||||
export enum CrudAction {
|
||||
@@ -120,7 +121,7 @@ export const isValidPermissionString = (val: unknown): val is PermissionString =
|
||||
* @returns A new object without the _resource property
|
||||
*/
|
||||
export const filterResourceConfig = (config: ResourceConfig): Omit<ResourceConfig, "_resource"> => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
|
||||
const { _resource, ...rest } = config;
|
||||
return rest;
|
||||
};
|
||||
@@ -147,7 +148,8 @@ export const getPermissionsForScope = (scope: Scope, isPrivate?: boolean): Permi
|
||||
const scopeMatches = !permissionDetails.scope || permissionDetails.scope.includes(scope);
|
||||
|
||||
// Check privacy visibility (only if isPrivate is provided)
|
||||
const privacyMatches = teamPrivacy === undefined ||
|
||||
const privacyMatches =
|
||||
teamPrivacy === undefined ||
|
||||
!permissionDetails.visibleWhen?.teamPrivacy ||
|
||||
permissionDetails.visibleWhen.teamPrivacy === "both" ||
|
||||
permissionDetails.visibleWhen.teamPrivacy === teamPrivacy;
|
||||
@@ -672,4 +674,40 @@ export const PERMISSION_REGISTRY: PermissionRegistry = {
|
||||
dependsOn: ["ooo.read"],
|
||||
},
|
||||
},
|
||||
[Resource.Watchlist]: {
|
||||
_resource: {
|
||||
i18nKey: "pbac_resource_blocklist",
|
||||
},
|
||||
[CrudAction.Create]: {
|
||||
description: "Create watchlist entries",
|
||||
category: "watchlist",
|
||||
i18nKey: "pbac_action_create",
|
||||
descriptionI18nKey: "pbac_desc_create_watchlist_entries",
|
||||
scope: [Scope.Organization],
|
||||
dependsOn: ["watchlist.read"],
|
||||
},
|
||||
[CrudAction.Read]: {
|
||||
description: "View watchlist entries",
|
||||
category: "watchlist",
|
||||
i18nKey: "pbac_action_read",
|
||||
descriptionI18nKey: "pbac_desc_view_watchlist_entries",
|
||||
scope: [Scope.Organization],
|
||||
},
|
||||
[CrudAction.Update]: {
|
||||
description: "Update watchlist entries",
|
||||
category: "watchlist",
|
||||
i18nKey: "pbac_action_update",
|
||||
descriptionI18nKey: "pbac_desc_update_watchlist_entries",
|
||||
scope: [Scope.Organization],
|
||||
dependsOn: ["watchlist.read"],
|
||||
},
|
||||
[CrudAction.Delete]: {
|
||||
description: "Delete watchlist entries",
|
||||
category: "watchlist",
|
||||
i18nKey: "pbac_action_delete",
|
||||
descriptionI18nKey: "pbac_desc_delete_watchlist_entries",
|
||||
scope: [Scope.Organization],
|
||||
dependsOn: ["watchlist.read"],
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1042,6 +1042,19 @@ export class UserRepository {
|
||||
});
|
||||
}
|
||||
|
||||
async findUsersByIds(userIds: number[]) {
|
||||
return this.prismaClient.user.findMany({
|
||||
where: {
|
||||
id: { in: userIds },
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async findUsersWithLastBooking({ userIds, eventTypeId }: { userIds: number[]; eventTypeId: number }) {
|
||||
return this.prismaClient.user.findMany({
|
||||
where: {
|
||||
|
||||
Reference in new issue
Block a user