@@ -90,11 +102,11 @@ function WorkflowsPage() {
) : null}
}
noResultsScreen={
}
SkeletonLoader={SkeletonLoader}>
-
+
>
diff --git a/packages/features/ee/workflows/pages/workflow.tsx b/packages/features/ee/workflows/pages/workflow.tsx
index 293632cc4b..42dfac1966 100644
--- a/packages/features/ee/workflows/pages/workflow.tsx
+++ b/packages/features/ee/workflows/pages/workflow.tsx
@@ -12,6 +12,7 @@ import { SENDER_ID } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { useParamsWithFallback } from "@calcom/lib/hooks/useParamsWithFallback";
import { HttpError } from "@calcom/lib/http-error";
+import type { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import type { TimeUnit, WorkflowTriggerEvents } from "@calcom/prisma/enums";
import { MembershipRole, WorkflowActions } from "@calcom/prisma/enums";
import type { RouterOutputs } from "@calcom/trpc/react";
@@ -37,7 +38,17 @@ export type FormValues = {
selectAll: boolean;
};
-function WorkflowPage() {
+type PageProps = {
+ workflowData?: Awaited
>;
+ verifiedNumbers?: Awaited>;
+ verifiedEmails?: Awaited>;
+};
+
+function WorkflowPage({
+ workflowData: workflowDataProp,
+ verifiedNumbers: verifiedNumbersProp,
+ verifiedEmails: verifiedEmailsProp,
+}: PageProps) {
const { t, i18n } = useLocale();
const session = useSession();
const params = useParamsWithFallback();
@@ -58,27 +69,36 @@ function WorkflowPage() {
const user = userQuery.data;
const {
- data: workflow,
- isError,
+ data: workflowData,
+ isError: _isError,
error,
- isPending: isPendingWorkflow,
+ isPending: _isPendingWorkflow,
} = trpc.viewer.workflows.get.useQuery(
{ id: +workflowId },
{
- enabled: !!workflowId,
+ enabled: workflowDataProp ? false : !!workflowId,
}
);
- const { data: verifiedNumbers } = trpc.viewer.workflows.getVerifiedNumbers.useQuery(
+ const workflow = workflowDataProp || workflowData;
+ const isPendingWorkflow = workflowDataProp ? false : _isPendingWorkflow;
+ const isError = workflowDataProp ? false : _isError;
+
+ const { data: verifiedNumbersData } = trpc.viewer.workflows.getVerifiedNumbers.useQuery(
{ teamId: workflow?.team?.id },
{
- enabled: !!workflow?.id,
+ enabled: verifiedNumbersProp ? false : !!workflow?.id,
}
);
+ const verifiedNumbers = verifiedNumbersProp || verifiedNumbersData;
- const { data: verifiedEmails } = trpc.viewer.workflows.getVerifiedEmails.useQuery({
- teamId: workflow?.team?.id,
- });
+ const { data: verifiedEmailsData } = trpc.viewer.workflows.getVerifiedEmails.useQuery(
+ {
+ teamId: workflow?.team?.id,
+ },
+ { enabled: !verifiedEmailsProp }
+ );
+ const verifiedEmails = verifiedEmailsProp || verifiedEmailsData;
const isOrg = workflow?.team?.isOrganization ?? false;
@@ -135,7 +155,7 @@ function WorkflowPage() {
setSelectedOptions(activeOn || []);
} else {
setSelectedOptions(
- workflowData.activeOn.flatMap((active) => {
+ workflowData.activeOn?.flatMap((active) => {
if (workflowData.teamId && active.eventType.parentId) return [];
return {
value: String(active.eventType.id),
@@ -152,7 +172,7 @@ function WorkflowPage() {
}
}
//translate dynamic variables into local language
- const steps = workflowData.steps.map((step) => {
+ const steps = workflowData.steps?.map((step) => {
const updatedStep = {
...step,
senderName: step.sender,
@@ -342,7 +362,7 @@ function WorkflowPage() {
)}
>
) : (
-
+
)}
diff --git a/packages/lib/server/repository/workflow.ts b/packages/lib/server/repository/workflow.ts
index 29beff25b8..26e43aa62b 100644
--- a/packages/lib/server/repository/workflow.ts
+++ b/packages/lib/server/repository/workflow.ts
@@ -1,6 +1,13 @@
import { z } from "zod";
+import type { WorkflowType } from "@calcom/ee/workflows/components/WorkflowListPage";
+import { hasFilter } from "@calcom/features/filters/lib/hasFilter";
import prisma from "@calcom/prisma";
+import { MembershipRole } from "@calcom/prisma/client";
+import { Prisma } from "@calcom/prisma/client";
+import type { TFilteredListInputSchema } from "@calcom/trpc/server/routers/viewer/workflows/filteredList.schema";
+import type { TGetVerifiedEmailsInputSchema } from "@calcom/trpc/server/routers/viewer/workflows/getVerifiedEmails.schema";
+import type { TGetVerifiedNumbersInputSchema } from "@calcom/trpc/server/routers/viewer/workflows/getVerifiedNumbers.schema";
export const ZGetInputSchema = z.object({
id: z.number(),
@@ -8,6 +15,48 @@ export const ZGetInputSchema = z.object({
export type TGetInputSchema = z.infer;
+const { include: includedFields } = Prisma.validator()({
+ include: {
+ activeOn: {
+ select: {
+ eventType: {
+ select: {
+ id: true,
+ title: true,
+ parentId: true,
+ _count: {
+ select: {
+ children: true,
+ },
+ },
+ },
+ },
+ },
+ },
+ activeOnTeams: {
+ select: {
+ team: {
+ select: {
+ id: true,
+ name: true,
+ },
+ },
+ },
+ },
+ steps: true,
+ team: {
+ select: {
+ id: true,
+ slug: true,
+ name: true,
+ members: true,
+ logoUrl: true,
+ isOrganization: true,
+ },
+ },
+ },
+});
+
export class WorkflowRepository {
static async getById({ id }: TGetInputSchema) {
return await prisma.workflow.findFirst({
@@ -50,4 +99,181 @@ export class WorkflowRepository {
},
});
}
+
+ static async getVerifiedNumbers({
+ userId,
+ teamId,
+ }: TGetVerifiedNumbersInputSchema & { userId: number | null }) {
+ if (!userId) {
+ throw new Error("User Id not found");
+ }
+ const verifiedNumbers = await prisma.verifiedNumber.findMany({
+ where: {
+ OR: [{ userId }, { teamId }],
+ },
+ });
+
+ return verifiedNumbers;
+ }
+
+ static async getVerifiedEmails({
+ userEmail,
+ userId,
+ teamId,
+ }: TGetVerifiedEmailsInputSchema & { userEmail: string | null; userId: number | null }) {
+ if (!userId) {
+ throw new Error("User Id not found");
+ }
+ if (!userEmail) {
+ throw new Error("User email not found");
+ }
+
+ let verifiedEmails: string[] = [userEmail];
+
+ if (teamId) {
+ const team = await prisma.team.findFirst({
+ where: {
+ id: teamId,
+ },
+ select: {
+ members: {
+ include: {
+ user: {
+ select: {
+ id: true,
+ email: true,
+ },
+ },
+ },
+ },
+ },
+ });
+
+ if (!team) {
+ throw new Error("Team not found");
+ }
+
+ const isTeamMember = team.members.some((member) => member.userId === userId);
+
+ if (!isTeamMember) {
+ throw new Error("You are not a member of this team");
+ }
+
+ verifiedEmails = verifiedEmails.concat(team.members.map((member) => member.user.email));
+ }
+
+ const emails = (
+ await prisma.verifiedEmail.findMany({
+ where: {
+ OR: [{ userId }, { teamId }],
+ },
+ })
+ ).map((verifiedEmail) => verifiedEmail.email);
+
+ verifiedEmails = verifiedEmails.concat(emails);
+
+ return verifiedEmails;
+ }
+
+ static async getFilteredList({ userId, input }: { userId?: number; input: TFilteredListInputSchema }) {
+ const filters = input?.filters;
+
+ const filtered = filters && hasFilter(filters);
+
+ const allWorkflows = await prisma.workflow.findMany({
+ where: {
+ OR: [
+ {
+ userId,
+ },
+ {
+ team: {
+ members: {
+ some: {
+ userId,
+ accepted: true,
+ },
+ },
+ },
+ },
+ ],
+ },
+ include: includedFields,
+ orderBy: [
+ {
+ position: "desc",
+ },
+ {
+ id: "asc",
+ },
+ ],
+ });
+
+ if (!filtered) {
+ const workflowsWithReadOnly: WorkflowType[] = allWorkflows.map((workflow) => {
+ const readOnly = !!workflow.team?.members?.find(
+ (member) => member.userId === userId && member.role === MembershipRole.MEMBER
+ );
+
+ return { readOnly, isOrg: workflow.team?.isOrganization ?? false, ...workflow };
+ });
+
+ return {
+ filtered: workflowsWithReadOnly,
+ totalCount: allWorkflows.length,
+ };
+ }
+
+ const where = {
+ OR: [] as Prisma.WorkflowWhereInput[],
+ };
+
+ if (filtered) {
+ if (!!filters.teamIds) {
+ where.OR.push({
+ team: {
+ id: {
+ in: filters.teamIds ?? [],
+ },
+ members: {
+ some: {
+ userId,
+ accepted: true,
+ },
+ },
+ },
+ });
+ }
+
+ if (!!filters.userIds) {
+ where.OR.push({
+ userId: {
+ in: filters.userIds,
+ },
+ teamId: null,
+ });
+ }
+
+ const filteredWorkflows = await prisma.workflow.findMany({
+ where,
+ include: includedFields,
+ orderBy: {
+ id: "asc",
+ },
+ });
+
+ const workflowsWithReadOnly: WorkflowType[] = filteredWorkflows.map((workflow) => {
+ const readOnly = !!workflow.team?.members?.find(
+ (member) => member.userId === userId && member.role === MembershipRole.MEMBER
+ );
+
+ return { readOnly, isOrg: workflow.team?.isOrganization ?? false, ...workflow };
+ });
+
+ return {
+ filtered: workflowsWithReadOnly,
+ totalCount: allWorkflows.length,
+ };
+ }
+ }
}
diff --git a/packages/trpc/server/routers/viewer/workflows/filteredList.handler.tsx b/packages/trpc/server/routers/viewer/workflows/filteredList.handler.tsx
index 46e850ea57..f9986484d8 100644
--- a/packages/trpc/server/routers/viewer/workflows/filteredList.handler.tsx
+++ b/packages/trpc/server/routers/viewer/workflows/filteredList.handler.tsx
@@ -1,8 +1,6 @@
-import type { WorkflowType } from "@calcom/ee/workflows/components/WorkflowListPage";
-import { hasFilter } from "@calcom/features/filters/lib/hasFilter";
+import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import type { PrismaClient } from "@calcom/prisma";
import { Prisma } from "@calcom/prisma/client";
-import { MembershipRole } from "@calcom/prisma/client";
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
import type { TFilteredListInputSchema } from "./filteredList.schema";
@@ -58,105 +56,5 @@ const { include: includedFields } = Prisma.validator
});
export const filteredListHandler = async ({ ctx, input }: FilteredListOptions) => {
- const { prisma, user } = ctx;
-
- const filters = input?.filters;
-
- const filtered = filters && hasFilter(filters);
-
- const allWorkflows = await prisma.workflow.findMany({
- where: {
- OR: [
- {
- userId: user.id,
- },
- {
- team: {
- members: {
- some: {
- userId: user.id,
- accepted: true,
- },
- },
- },
- },
- ],
- },
- include: includedFields,
- orderBy: [
- {
- position: "desc",
- },
- {
- id: "asc",
- },
- ],
- });
-
- if (!filtered) {
- const workflowsWithReadOnly: WorkflowType[] = allWorkflows.map((workflow) => {
- const readOnly = !!workflow.team?.members?.find(
- (member) => member.userId === ctx.user.id && member.role === MembershipRole.MEMBER
- );
-
- return { readOnly, isOrg: workflow.team?.isOrganization ?? false, ...workflow };
- });
-
- return {
- filtered: workflowsWithReadOnly,
- totalCount: allWorkflows.length,
- };
- }
-
- const where = {
- OR: [] as Prisma.WorkflowWhereInput[],
- };
-
- if (filtered) {
- if (!!filters.teamIds) {
- where.OR.push({
- team: {
- id: {
- in: filters.teamIds ?? [],
- },
- members: {
- some: {
- userId: user.id,
- accepted: true,
- },
- },
- },
- });
- }
-
- if (!!filters.userIds) {
- where.OR.push({
- userId: {
- in: filters.userIds,
- },
- teamId: null,
- });
- }
-
- const filteredWorkflows = await prisma.workflow.findMany({
- where,
- include: includedFields,
- orderBy: {
- id: "asc",
- },
- });
-
- const workflowsWithReadOnly: WorkflowType[] = filteredWorkflows.map((workflow) => {
- const readOnly = !!workflow.team?.members?.find(
- (member) => member.userId === ctx.user.id && member.role === MembershipRole.MEMBER
- );
-
- return { readOnly, isOrg: workflow.team?.isOrganization ?? false, ...workflow };
- });
-
- return {
- filtered: workflowsWithReadOnly,
- totalCount: allWorkflows.length,
- };
- }
+ return await WorkflowRepository.getFilteredList({ userId: ctx.user.id, input });
};
diff --git a/packages/trpc/server/routers/viewer/workflows/getVerifiedEmails.handler.ts b/packages/trpc/server/routers/viewer/workflows/getVerifiedEmails.handler.ts
index 735cdf1aee..e4fd4b0a71 100644
--- a/packages/trpc/server/routers/viewer/workflows/getVerifiedEmails.handler.ts
+++ b/packages/trpc/server/routers/viewer/workflows/getVerifiedEmails.handler.ts
@@ -1,8 +1,6 @@
-import { prisma } from "@calcom/prisma";
+import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
-import { TRPCError } from "@trpc/server";
-
import type { TGetVerifiedEmailsInputSchema } from "./getVerifiedEmails.schema";
type GetVerifiedEmailsOptions = {
@@ -13,51 +11,9 @@ type GetVerifiedEmailsOptions = {
};
export const getVerifiedEmailsHandler = async ({ ctx, input }: GetVerifiedEmailsOptions) => {
- const { user } = ctx;
- const { teamId } = input;
- let verifiedEmails: string[] = [user.email];
-
- if (teamId) {
- const team = await prisma.team.findFirst({
- where: {
- id: teamId,
- },
- select: {
- members: {
- include: {
- user: {
- select: {
- id: true,
- email: true,
- },
- },
- },
- },
- },
- });
-
- if (!team) {
- throw new TRPCError({ code: "NOT_FOUND", message: "Team not found" });
- }
-
- const isTeamMember = team.members.some((member) => member.userId === user.id);
-
- if (!isTeamMember) {
- throw new TRPCError({ code: "FORBIDDEN", message: "You are not a member of this team" });
- }
-
- verifiedEmails = verifiedEmails.concat(team.members.map((member) => member.user.email));
- }
-
- const emails = (
- await prisma.verifiedEmail.findMany({
- where: {
- OR: [{ userId: user.id }, { teamId: input.teamId }],
- },
- })
- ).map((verifiedEmail) => verifiedEmail.email);
-
- verifiedEmails = verifiedEmails.concat(emails);
-
- return verifiedEmails;
+ return await WorkflowRepository.getVerifiedEmails({
+ userId: ctx.user.id,
+ userEmail: ctx.user.email,
+ teamId: input.teamId,
+ });
};
diff --git a/packages/trpc/server/routers/viewer/workflows/getVerifiedNumbers.handler.ts b/packages/trpc/server/routers/viewer/workflows/getVerifiedNumbers.handler.ts
index 406fcde53b..b0c71bc82d 100644
--- a/packages/trpc/server/routers/viewer/workflows/getVerifiedNumbers.handler.ts
+++ b/packages/trpc/server/routers/viewer/workflows/getVerifiedNumbers.handler.ts
@@ -1,4 +1,4 @@
-import { prisma } from "@calcom/prisma";
+import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
import type { TGetVerifiedNumbersInputSchema } from "./getVerifiedNumbers.schema";
@@ -11,12 +11,8 @@ type GetVerifiedNumbersOptions = {
};
export const getVerifiedNumbersHandler = async ({ ctx, input }: GetVerifiedNumbersOptions) => {
- const { user } = ctx;
- const verifiedNumbers = await prisma.verifiedNumber.findMany({
- where: {
- OR: [{ userId: user.id }, { teamId: input.teamId }],
- },
+ return await WorkflowRepository.getVerifiedNumbers({
+ userId: ctx.user.id,
+ teamId: input.teamId,
});
-
- return verifiedNumbers;
};