diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index bcc25bd390..fa0d33dbca 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -31,9 +31,10 @@ Fixes # (issue)
-- [ ] Added a screen recording or screenshots to this PR
+### Required
+
- [ ] Filled out the "How to test" section in this PR
-- [ ] Read the [contributing guide](https://github.com/formbricks/formbricks/blob/main/CONTRIBUTING.md)
+- [ ] Read [How we Code at Formbricks](<[https://github.com/formbricks/formbricks/blob/main/CONTRIBUTING.md](https://formbricks.com/docs/contributing/how-we-code)>)
- [ ] Self-reviewed my own code
- [ ] Commented on my code in hard-to-understand bits
- [ ] Ran `pnpm build`
@@ -41,4 +42,8 @@ Fixes # (issue)
- [ ] Removed all `console.logs`
- [ ] Merged the latest changes from main onto my branch with `git pull origin main`
- [ ] My changes don't cause any responsiveness issues
+
+### Appreciated
+
+- [ ] If a UI change was made: Added a screen recording or screenshots to this PR
- [ ] Updated the Formbricks Docs if changes were necessary
diff --git a/apps/web/app/(app)/environments/[environmentId]/integrations/page.tsx b/apps/web/app/(app)/environments/[environmentId]/integrations/page.tsx
index af6407fd7e..90e8d14a35 100644
--- a/apps/web/app/(app)/environments/[environmentId]/integrations/page.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/integrations/page.tsx
@@ -6,82 +6,121 @@ import n8nLogo from "@/images/n8n.png";
import MakeLogo from "@/images/make-small.png";
import { Card } from "@formbricks/ui";
import Image from "next/image";
+import { getCountOfWebhooksBasedOnSource } from "@formbricks/lib/services/webhook";
+import { getEnvironment } from "@formbricks/lib/services/environment";
import { getIntegrations } from "@formbricks/lib/services/integrations";
export default async function IntegrationsPage({ params }) {
- const integrations = await getIntegrations(params.environmentId);
+ const environmentId = params.environmentId;
+
+ const [environment, integrations, userWebhooks, zapierWebhooks] = await Promise.all([
+ getEnvironment(environmentId),
+ getIntegrations(environmentId),
+ getCountOfWebhooksBasedOnSource(environmentId, "user"),
+ getCountOfWebhooksBasedOnSource(environmentId, "zapier"),
+ ]);
+
const containsGoogleSheetIntegration = integrations.some(
(integration) => integration.type === "googleSheets"
);
+ const integrationCards = [
+ {
+ docsHref: "https://formbricks.com/docs/getting-started/framework-guides#next-js",
+ docsText: "Docs",
+ docsNewTab: true,
+ label: "Javascript Widget",
+ description: "Integrate Formbricks into your Webapp",
+ icon: ,
+ connected: environment?.widgetSetupCompleted,
+ statusText: environment?.widgetSetupCompleted ? "Connected" : "Not Connected",
+ },
+ {
+ docsHref: "https://formbricks.com/docs/integrations/zapier",
+ docsText: "Docs",
+ docsNewTab: true,
+ connectHref: "https://zapier.com/apps/formbricks/integrations",
+ connectText: "Connect",
+ connectNewTab: true,
+ label: "Zapier",
+ description: "Integrate Formbricks with 5000+ apps via Zapier",
+ icon: ,
+ connected: zapierWebhooks > 0,
+ statusText:
+ zapierWebhooks === 1 ? "1 zap" : zapierWebhooks === 0 ? "Not Connected" : `${zapierWebhooks} zaps`,
+ },
+ {
+ connectHref: `/environments/${params.environmentId}/integrations/webhooks`,
+ connectText: "Manage Webhooks",
+ connectNewTab: false,
+ docsHref: "https://formbricks.com/docs/webhook-api/overview",
+ docsText: "Docs",
+ docsNewTab: true,
+ label: "Webhooks",
+ description: "Trigger Webhooks based on actions in your surveys",
+ icon: ,
+ connected: userWebhooks > 0,
+ statusText:
+ userWebhooks === 1 ? "1 webhook" : userWebhooks === 0 ? "Not Connected" : `${userWebhooks} zaps`,
+ },
+ {
+ connectHref: `/environments/${params.environmentId}/integrations/google-sheets`,
+ connectText: `${containsGoogleSheetIntegration ? "Manage Sheets" : "Connect"}`,
+ connectNewTab: false,
+ docsHref: "https://formbricks.com/docs/integrations/google-sheets",
+ docsText: "Docs",
+ docsNewTab: true,
+ label: "Google Sheets",
+ description: "Instantly populate your spreadsheets with survey data",
+ icon: ,
+ connected: containsGoogleSheetIntegration ? true : false,
+ statusText: containsGoogleSheetIntegration ? "Connected" : "Not Connected",
+ },
+ {
+ docsHref: "https://formbricks.com/docs/integrations/n8n",
+ docsText: "Docs",
+ docsNewTab: true,
+ connectHref: "https://n8n.io",
+ connectText: "Connect",
+ connectNewTab: true,
+ label: "n8n",
+ description: "Integrate Formbricks with 350+ apps via n8n",
+ icon: ,
+ },
+ {
+ docsHref: "https://formbricks.com/docs/integrations/make",
+ docsText: "Docs",
+ docsNewTab: true,
+ connectHref: "https://www.make.com/en/integrations/formbricks",
+ connectText: "Connect",
+ connectNewTab: true,
+ label: "Make.com",
+ description: "Integrate Formbricks with 1000+ apps via Make",
+ icon: ,
+ },
+ ];
+
return (
Integrations
Connect Formbricks with your favorite tools.
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
- }
- />
+ {integrationCards.map((card) => (
+
+ ))}
);
diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships/EditMemberships.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships/EditMemberships.tsx
index 0c801df40b..682fac982c 100644
--- a/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships/EditMemberships.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships/EditMemberships.tsx
@@ -2,7 +2,7 @@ import { TTeam } from "@formbricks/types/v1/teams";
import React from "react";
import MembersInfo from "@/app/(app)/environments/[environmentId]/settings/members/EditMemberships/MembersInfo";
import { getMembersByTeamId } from "@formbricks/lib/services/membership";
-import { getInviteesByTeamId } from "@formbricks/lib/services/invite";
+import { getInvitesByTeamId } from "@formbricks/lib/services/invite";
import { TMembership } from "@formbricks/types/v1/memberships";
type EditMembershipsProps = {
@@ -18,7 +18,7 @@ export async function EditMemberships({
currentUserMembership: membership,
}: EditMembershipsProps) {
const members = await getMembersByTeamId(team.id);
- const invites = await getInviteesByTeamId(team.id);
+ const invites = await getInvitesByTeamId(team.id);
const currentUserRole = membership?.role;
const isUserAdminOrOwner = membership?.role === "admin" || membership?.role === "owner";
diff --git a/packages/lib/actionClass/auth.ts b/packages/lib/actionClass/auth.ts
index 1d7a431361..381d981b46 100644
--- a/packages/lib/actionClass/auth.ts
+++ b/packages/lib/actionClass/auth.ts
@@ -1,8 +1,11 @@
+import "server-only";
+
import { ZId } from "@formbricks/types/v1/environment";
import { validateInputs } from "../utils/validate";
import { hasUserEnvironmentAccess } from "../environment/auth";
import { getActionClass } from "./service";
import { unstable_cache } from "next/cache";
+import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
export const canUserAccessActionClass = async (userId: string, actionClassId: string): Promise =>
await unstable_cache(
@@ -20,5 +23,5 @@ export const canUserAccessActionClass = async (userId: string, actionClassId: st
},
[`users-${userId}-actionClasses-${actionClassId}`],
- { revalidate: 30 * 60, tags: [`actionClasses-${actionClassId}`] }
- )(); // 30 minutes
+ { revalidate: SERVICES_REVALIDATION_INTERVAL, tags: [`actionClasses-${actionClassId}`] }
+ )();
diff --git a/packages/lib/actionClass/service.ts b/packages/lib/actionClass/service.ts
index f69cb1bb05..2631636ce0 100644
--- a/packages/lib/actionClass/service.ts
+++ b/packages/lib/actionClass/service.ts
@@ -2,14 +2,13 @@
import "server-only";
import { prisma } from "@formbricks/database";
+import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
import { TActionClass, TActionClassInput, ZActionClassInput } from "@formbricks/types/v1/actionClasses";
import { ZId } from "@formbricks/types/v1/environment";
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/v1/errors";
import { revalidateTag, unstable_cache } from "next/cache";
import { validateInputs } from "../utils/validate";
-const halfHourInSeconds = 60 * 30;
-
export const getActionClassCacheTag = (name: string, environmentId: string): string =>
`environments-${environmentId}-actionClass-${name}`;
@@ -50,7 +49,7 @@ export const getActionClasses = (environmentId: string): Promise
[`environments-${environmentId}-actionClasses`],
{
tags: [getActionClassesCacheTag(environmentId)],
- revalidate: halfHourInSeconds,
+ revalidate: SERVICES_REVALIDATION_INTERVAL,
}
)();
@@ -168,6 +167,6 @@ export const getActionClassCached = async (name: string, environmentId: string)
[`environments-${environmentId}-actionClasses-${name}`],
{
tags: [getActionClassesCacheTag(environmentId)],
- revalidate: halfHourInSeconds,
+ revalidate: SERVICES_REVALIDATION_INTERVAL,
}
)();
diff --git a/packages/lib/apiKey/auth.ts b/packages/lib/apiKey/auth.ts
index 6699514ddc..1ba3027163 100644
--- a/packages/lib/apiKey/auth.ts
+++ b/packages/lib/apiKey/auth.ts
@@ -1,8 +1,11 @@
+import "server-only";
+
import { ZId } from "@formbricks/types/v1/environment";
import { validateInputs } from "../utils/validate";
import { hasUserEnvironmentAccess } from "../environment/auth";
import { getApiKey } from "./service";
import { unstable_cache } from "next/cache";
+import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
export const canUserAccessApiKey = async (userId: string, apiKeyId: string): Promise =>
await unstable_cache(
@@ -19,5 +22,5 @@ export const canUserAccessApiKey = async (userId: string, apiKeyId: string): Pro
},
[`users-${userId}-apiKeys-${apiKeyId}`],
- { revalidate: 30 * 60, tags: [`apiKeys-${apiKeyId}`] }
- )(); // 30 minutes
+ { revalidate: SERVICES_REVALIDATION_INTERVAL, tags: [`apiKeys-${apiKeyId}`] }
+ )();
diff --git a/packages/lib/apiKey/service.ts b/packages/lib/apiKey/service.ts
index 89bfd03d80..e181dd3992 100644
--- a/packages/lib/apiKey/service.ts
+++ b/packages/lib/apiKey/service.ts
@@ -1,4 +1,5 @@
import "server-only";
+
import z from "zod";
import { prisma } from "@formbricks/database";
import { TApiKey, TApiKeyCreateInput, ZApiKeyCreateInput } from "@formbricks/types/v1/apiKeys";
diff --git a/packages/lib/constants.ts b/packages/lib/constants.ts
index b7a8ae1a36..b2c8a7c0a6 100644
--- a/packages/lib/constants.ts
+++ b/packages/lib/constants.ts
@@ -4,6 +4,7 @@ import { env } from "@/env.mjs";
export const RESPONSES_LIMIT_FREE = 100;
export const IS_FORMBRICKS_CLOUD = env.IS_FORMBRICKS_CLOUD === "1";
export const REVALIDATION_INTERVAL = 0; //TODO: find a good way to cache and revalidate data when it changes
+export const SERVICES_REVALIDATION_INTERVAL = 60 * 30; // 30 minutes
export const MAU_LIMIT = IS_FORMBRICKS_CLOUD ? 5000 : 1000000;
// URLs
diff --git a/packages/lib/environment/auth.ts b/packages/lib/environment/auth.ts
index 4a693e6ed0..b9186ef812 100644
--- a/packages/lib/environment/auth.ts
+++ b/packages/lib/environment/auth.ts
@@ -2,6 +2,7 @@ import { prisma } from "@formbricks/database";
import { ZId } from "@formbricks/types/v1/environment";
import { unstable_cache } from "next/cache";
import { validateInputs } from "../utils/validate";
+import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
export const hasUserEnvironmentAccess = async (userId: string, environmentId: string) => {
return await unstable_cache(
@@ -31,6 +32,6 @@ export const hasUserEnvironmentAccess = async (userId: string, environmentId: st
return environmentUsers.includes(userId);
},
[`users-${userId}-environments-${environmentId}`],
- { revalidate: 30 * 60, tags: [`environments-${environmentId}`] }
- )(); // 30 minutes
+ { revalidate: SERVICES_REVALIDATION_INTERVAL, tags: [`environments-${environmentId}`] }
+ )();
};
diff --git a/packages/lib/response/auth.ts b/packages/lib/response/auth.ts
index 48ea212553..f4adfe0858 100644
--- a/packages/lib/response/auth.ts
+++ b/packages/lib/response/auth.ts
@@ -1,9 +1,12 @@
+import "server-only";
+
import { ZId } from "@formbricks/types/v1/environment";
import { validateInputs } from "../utils/validate";
import { hasUserEnvironmentAccess } from "../environment/auth";
import { getResponse, getResponseCacheTag } from "./service";
import { unstable_cache } from "next/cache";
import { getSurvey } from "../services/survey";
+import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
export const canUserAccessResponse = async (userId: string, responseId: string): Promise =>
await unstable_cache(
@@ -24,5 +27,5 @@ export const canUserAccessResponse = async (userId: string, responseId: string):
return true;
},
[`users-${userId}-responses-${responseId}`],
- { revalidate: 30 * 60, tags: [getResponseCacheTag(responseId)] }
- )(); // 30 minutes
+ { revalidate: SERVICES_REVALIDATION_INTERVAL, tags: [getResponseCacheTag(responseId)] }
+ )();
diff --git a/packages/lib/response/service.ts b/packages/lib/response/service.ts
index b0f2595826..4e7f9a820f 100644
--- a/packages/lib/response/service.ts
+++ b/packages/lib/response/service.ts
@@ -1,3 +1,5 @@
+import "server-only";
+
import { prisma } from "@formbricks/database";
import {
TResponse,
@@ -11,7 +13,6 @@ import { TPerson } from "@formbricks/types/v1/people";
import { TTag } from "@formbricks/types/v1/tags";
import { Prisma } from "@prisma/client";
import { cache } from "react";
-import "server-only";
import { getPerson, transformPrismaPerson } from "../services/person";
import { captureTelemetry } from "../telemetry";
import { validateInputs } from "../utils/validate";
diff --git a/packages/lib/services/attributeClass.ts b/packages/lib/services/attributeClass.ts
index 5684995ca8..2a75547f9f 100644
--- a/packages/lib/services/attributeClass.ts
+++ b/packages/lib/services/attributeClass.ts
@@ -1,5 +1,6 @@
"use server";
import "server-only";
+
import { prisma } from "@formbricks/database";
import {
TAttributeClass,
@@ -12,6 +13,7 @@ import { validateInputs } from "../utils/validate";
import { DatabaseError } from "@formbricks/types/v1/errors";
import { cache } from "react";
import { revalidateTag, unstable_cache } from "next/cache";
+import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
const attributeClassesCacheTag = (environmentId: string): string =>
`environments-${environmentId}-attributeClasses`;
@@ -99,7 +101,7 @@ export const getAttributeClassByNameCached = async (environmentId: string, name:
getAttributeClassesCacheKey(environmentId),
{
tags: getAttributeClassesCacheKey(environmentId),
- revalidate: 30 * 60, // 30 minutes
+ revalidate: SERVICES_REVALIDATION_INTERVAL,
}
)();
diff --git a/packages/lib/services/displays.ts b/packages/lib/services/displays.ts
index e07d0f54a5..5cbe1983d9 100644
--- a/packages/lib/services/displays.ts
+++ b/packages/lib/services/displays.ts
@@ -1,3 +1,5 @@
+import "server-only";
+
import { prisma } from "@formbricks/database";
import {
TDisplay,
diff --git a/packages/lib/services/environment.ts b/packages/lib/services/environment.ts
index be03a3a159..87714c5f19 100644
--- a/packages/lib/services/environment.ts
+++ b/packages/lib/services/environment.ts
@@ -1,4 +1,5 @@
import "server-only";
+
import { prisma } from "@formbricks/database";
import { z } from "zod";
import { Prisma, EnvironmentType } from "@prisma/client";
@@ -8,6 +9,7 @@ import { populateEnvironment } from "../utils/createDemoProductHelpers";
import { ZEnvironment, ZEnvironmentUpdateInput, ZId } from "@formbricks/types/v1/environment";
import { validateInputs } from "../utils/validate";
import { unstable_cache, revalidateTag } from "next/cache";
+import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
export const getEnvironmentCacheTag = (environmentId: string) => `environments-${environmentId}`;
export const getEnvironmentsCacheTag = (productId: string) => `products-${productId}-environments`;
@@ -45,7 +47,7 @@ export const getEnvironment = (environmentId: string) =>
[`environments-${environmentId}`],
{
tags: [getEnvironmentCacheTag(environmentId)],
- revalidate: 30 * 60, // 30 minutes
+ revalidate: SERVICES_REVALIDATION_INTERVAL,
}
)();
@@ -92,7 +94,7 @@ export const getEnvironments = async (productId: string): Promise => {
+export const getInvitesByTeamId = cache(async (teamId: string): Promise => {
const invites = await prisma.invite.findMany({
where: { teamId },
select: inviteSelect,
diff --git a/packages/lib/services/membership.ts b/packages/lib/services/membership.ts
index dee3b587ec..c1e2ab07ed 100644
--- a/packages/lib/services/membership.ts
+++ b/packages/lib/services/membership.ts
@@ -1,3 +1,5 @@
+import "server-only";
+
import { prisma } from "@formbricks/database";
import { ResourceNotFoundError } from "@formbricks/types/v1/errors";
import { TMember, TMembership, TMembershipUpdateInput } from "@formbricks/types/v1/memberships";
diff --git a/packages/lib/services/person.ts b/packages/lib/services/person.ts
index c8e80598ae..bc2ca3f203 100644
--- a/packages/lib/services/person.ts
+++ b/packages/lib/services/person.ts
@@ -10,6 +10,7 @@ import { cache } from "react";
import { PEOPLE_PER_PAGE } from "../constants";
import { validateInputs } from "../utils/validate";
import { getAttributeClassByName } from "./attributeClass";
+import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
export const selectPerson = {
id: true,
@@ -100,7 +101,7 @@ export const getPersonCached = async (personId: string) =>
getPersonCacheKey(personId),
{
tags: getPersonCacheKey(personId),
- revalidate: 30 * 60, // 30 minutes
+ revalidate: SERVICES_REVALIDATION_INTERVAL,
}
)();
diff --git a/packages/lib/services/product.ts b/packages/lib/services/product.ts
index db57c09b29..8072f3a88e 100644
--- a/packages/lib/services/product.ts
+++ b/packages/lib/services/product.ts
@@ -1,3 +1,5 @@
+import "server-only";
+
import { prisma } from "@formbricks/database";
import { ZId } from "@formbricks/types/v1/environment";
import { DatabaseError, ValidationError } from "@formbricks/types/v1/errors";
@@ -6,12 +8,12 @@ import { ZProduct, ZProductUpdateInput } from "@formbricks/types/v1/product";
import { Prisma } from "@prisma/client";
import { revalidateTag, unstable_cache } from "next/cache";
import { cache } from "react";
-import "server-only";
import { z } from "zod";
import { validateInputs } from "../utils/validate";
import { EnvironmentType } from "@prisma/client";
import { EventType } from "@prisma/client";
import { getEnvironmentCacheTag, getEnvironmentsCacheTag } from "./environment";
+import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
export const getProductsCacheTag = (teamId: string): string => `teams-${teamId}-products`;
const getProductCacheTag = (environmentId: string): string => `environments-${environmentId}-product`;
@@ -85,7 +87,7 @@ export const getProducts = async (teamId: string): Promise =>
[`teams-${teamId}-products`],
{
tags: [getProductsCacheTag(teamId)],
- revalidate: 30 * 60, // 30 minutes
+ revalidate: SERVICES_REVALIDATION_INTERVAL,
}
)();
@@ -124,7 +126,7 @@ export const getProductByEnvironmentIdCached = (environmentId: string) =>
getProductCacheKey(environmentId),
{
tags: getProductCacheKey(environmentId),
- revalidate: 30 * 60, // 30 minutes
+ revalidate: SERVICES_REVALIDATION_INTERVAL,
}
)();
diff --git a/packages/lib/services/profile.ts b/packages/lib/services/profile.ts
index dc6e4d8dc5..b176dff86f 100644
--- a/packages/lib/services/profile.ts
+++ b/packages/lib/services/profile.ts
@@ -1,3 +1,5 @@
+import "server-only";
+
import { prisma } from "@formbricks/database";
import { ZId } from "@formbricks/types/v1/environment";
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/v1/errors";
@@ -8,6 +10,7 @@ import { unstable_cache, revalidateTag } from "next/cache";
import { validateInputs } from "../utils/validate";
import { deleteTeam } from "./team";
import { z } from "zod";
+import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
const responseSelection = {
id: true,
@@ -50,7 +53,7 @@ export const getProfile = async (userId: string): Promise =>
[`profiles-${userId}`],
{
tags: [getProfileByEmailCacheTag(userId)],
- revalidate: 30 * 60, // 30 minutes
+ revalidate: SERVICES_REVALIDATION_INTERVAL,
}
)();
@@ -82,7 +85,7 @@ export const getProfileByEmail = async (email: string): Promise
[`profiles-${email}`],
{
tags: [getProfileCacheTag(email)],
- revalidate: 30 * 60, // 30 minutes
+ revalidate: SERVICES_REVALIDATION_INTERVAL,
}
)();
@@ -195,29 +198,3 @@ export const deleteProfile = async (userId: string): Promise => {
throw error;
}
};
-export async function getUserIdFromEnvironment(environmentId: string) {
- const environment = await prisma.environment.findUnique({
- where: { id: environmentId },
- select: {
- product: {
- select: {
- team: {
- select: {
- memberships: {
- select: {
- user: {
- select: {
- id: true,
- },
- },
- },
- },
- },
- },
- },
- },
- },
- });
-
- return environment?.product.team.memberships[0].user.id;
-}
diff --git a/packages/lib/services/survey.ts b/packages/lib/services/survey.ts
index c7466cdb00..6deb20e1e0 100644
--- a/packages/lib/services/survey.ts
+++ b/packages/lib/services/survey.ts
@@ -1,3 +1,5 @@
+import "server-only";
+
import { prisma } from "@formbricks/database";
import { ZId } from "@formbricks/types/v1/environment";
import { DatabaseError, ResourceNotFoundError, ValidationError } from "@formbricks/types/v1/errors";
@@ -10,7 +12,6 @@ import {
} from "@formbricks/types/v1/surveys";
import { Prisma } from "@prisma/client";
import { revalidateTag, unstable_cache } from "next/cache";
-import "server-only";
import { z } from "zod";
import { captureTelemetry } from "../telemetry";
import { validateInputs } from "../utils/validate";
diff --git a/packages/lib/services/tagOnResponse.ts b/packages/lib/services/tagOnResponse.ts
index 4e22c16afb..0ee7952999 100644
--- a/packages/lib/services/tagOnResponse.ts
+++ b/packages/lib/services/tagOnResponse.ts
@@ -1,3 +1,5 @@
+import "server-only";
+
import { prisma } from "@formbricks/database";
import { TTagsCount } from "@formbricks/types/v1/tags";
import { cache } from "react";
diff --git a/packages/lib/services/team.ts b/packages/lib/services/team.ts
index 9288851fb7..a9417cd90a 100644
--- a/packages/lib/services/team.ts
+++ b/packages/lib/services/team.ts
@@ -1,3 +1,5 @@
+import "server-only";
+
import { prisma } from "@formbricks/database";
import { ZId } from "@formbricks/types/v1/environment";
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/v1/errors";
@@ -24,6 +26,7 @@ import {
updateEnvironmentArgs,
} from "../utils/createDemoProductHelpers";
import { validateInputs } from "../utils/validate";
+import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
export const select = {
id: true,
@@ -64,7 +67,7 @@ export const getTeamsByUserId = async (userId: string): Promise =>
[`users-${userId}-teams`],
{
tags: [getTeamsByUserIdCacheTag(userId)],
- revalidate: 30 * 60, // 30 minutes
+ revalidate: SERVICES_REVALIDATION_INTERVAL,
}
)();
@@ -100,7 +103,7 @@ export const getTeamByEnvironmentId = async (environmentId: string): Promise {
export const createDemoProduct = async (teamId: string) => {
validateInputs([teamId, ZId]);
- const productWithEnvironment = Prisma.validator()({
- include: {
- environments: true,
- },
- });
- type ProductWithEnvironment = Prisma.ProductGetPayload;
-
- const demoProduct: ProductWithEnvironment = await prisma.product.create({
+ const demoProduct = await prisma.product.create({
data: {
name: "Demo Product",
team: {
diff --git a/packages/lib/services/teamDetails.ts b/packages/lib/services/teamDetails.ts
index 02dcb90832..c3704f9dfc 100644
--- a/packages/lib/services/teamDetails.ts
+++ b/packages/lib/services/teamDetails.ts
@@ -1,3 +1,5 @@
+import "server-only";
+
import { prisma } from "@formbricks/database";
import { Prisma } from "@prisma/client";
import { validateInputs } from "../utils/validate";
diff --git a/packages/lib/services/webhook.ts b/packages/lib/services/webhook.ts
index 7427f46687..404bec267d 100644
--- a/packages/lib/services/webhook.ts
+++ b/packages/lib/services/webhook.ts
@@ -22,6 +22,24 @@ export const getWebhooks = cache(async (environmentId: string): Promise => {
+ validateInputs([environmentId, ZId], [source, ZId]);
+ try {
+ const count = await prisma.webhook.count({
+ where: {
+ environmentId,
+ source,
+ },
+ });
+ return count;
+ } catch (error) {
+ throw new DatabaseError(`Database error when fetching webhooks for environment ${environmentId}`);
+ }
+};
+
export const getWebhook = async (id: string): Promise => {
validateInputs([id, ZId]);
const webhook = await prisma.webhook.findUnique({
diff --git a/packages/lib/tag/auth.ts b/packages/lib/tag/auth.ts
index d9c3b85543..2c5874f723 100644
--- a/packages/lib/tag/auth.ts
+++ b/packages/lib/tag/auth.ts
@@ -1,8 +1,11 @@
+import "server-only";
+
import { validateInputs } from "../utils/validate";
import { hasUserEnvironmentAccess } from "../environment/auth";
import { getTag } from "./service";
import { unstable_cache } from "next/cache";
import { ZId } from "@formbricks/types/v1/environment";
+import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
export const canUserAccessTag = async (userId: string, tagId: string): Promise =>
await unstable_cache(
@@ -19,6 +22,6 @@ export const canUserAccessTag = async (userId: string, tagId: string): Promise setHoveredNumber(number)}
onMouseLeave={() => setHoveredNumber(0)}
- className="max-w-10 relative max-h-10 flex-1 cursor-pointer bg-white text-center text-sm leading-10">
+ className="max-w-10 relative flex max-h-10 flex-1 cursor-pointer justify-center bg-white text-center text-sm leading-10">
{question.scale === "number" ? (