From dd394f1d2c2e42376d85fc035dd04d185282c9eb Mon Sep 17 00:00:00 2001 From: Piyush Gupta <56182734+gupta-piyush19@users.noreply.github.com> Date: Thu, 11 Sep 2025 12:27:11 +0530 Subject: [PATCH] chore: remove cron jobs and survey scheduling functionality (#6505) Co-authored-by: Dhruwang --- .env.example | 2 - apps/web/Dockerfile | 3 - .../components/AddIntegrationModal.test.tsx | 2 - .../integrations/google-sheets/page.test.tsx | 2 - .../components/AddIntegrationModal.test.tsx | 2 - .../project/integrations/notion/page.test.tsx | 2 - .../AddChannelMappingModal.test.tsx | 2 - .../project/integrations/slack/page.test.tsx | 2 - .../SurveyAnalysisNavigation.test.tsx | 2 - .../[surveyId]/(analysis)/layout.test.tsx | 2 - .../components/ResponseCardModal.test.tsx | 1 - .../components/ResponseDataView.test.tsx | 1 - .../components/SuccessMessage.test.tsx | 2 - .../summary/components/SummaryList.test.tsx | 2 - .../components/SurveyAnalysisCTA.test.tsx | 2 - .../components/share-survey-modal.test.tsx | 2 - .../link-settings-tab.test.tsx | 2 - .../shareEmbedModal/share-view.test.tsx | 2 - .../summary/lib/emailTemplate.test.tsx | 2 - .../summary/lib/surveySummary.test.ts | 2 - .../(analysis)/summary/lib/utils.test.ts | 1 - .../(analysis)/summary/page.test.tsx | 2 - .../components/CustomFilter.test.tsx | 1 - .../components/SurveyStatusDropdown.test.tsx | 25 --- .../components/SurveyStatusDropdown.tsx | 84 ++++----- .../context/survey-context.test.tsx | 2 - .../surveys/[surveyId]/layout.test.tsx | 2 - .../lib/__mocks__/survey-follow-up.mock.ts | 2 - .../pipeline/lib/handleIntegrations.test.ts | 1 - apps/web/app/api/cron/ping/route.ts | 35 ---- apps/web/app/api/cron/survey-status/route.ts | 71 -------- .../app/sync/lib/survey.test.ts | 2 - .../app/sync/lib/utils.test.ts | 2 - .../environment/lib/environmentState.test.ts | 2 - .../responses/lib/utils.test.ts | 2 - apps/web/app/lib/templates.ts | 2 - .../app/middleware/endpoint-validator.test.ts | 2 - apps/web/app/middleware/endpoint-validator.ts | 2 +- apps/web/lib/env.ts | 2 - apps/web/lib/i18n/i18n.mock.ts | 2 - .../lib/response/tests/__mocks__/data.mock.ts | 2 - apps/web/lib/responses.test.ts | 2 - apps/web/lib/survey/__mock__/survey.mock.ts | 2 - apps/web/lib/survey/service.ts | 15 -- .../components/ShareSurveyLink/index.test.tsx | 1 - .../v2/management/surveys/types/surveys.ts | 6 +- .../components/response-feed.test.tsx | 2 - .../segment-table-data-row-container.test.tsx | 6 - .../components/targeting-card.test.tsx | 1 - .../question-form-input/utils.test.ts | 8 - .../components/add-action-modal.test.tsx | 1 - .../add-ending-card-button.test.tsx | 2 - .../components/logic-editor-actions.test.tsx | 8 - .../components/open-question-form.test.tsx | 2 - .../picture-selection-form.test.tsx | 1 - .../editor/components/question-card.test.tsx | 1 - .../editor/components/questions-view.test.tsx | 2 - .../recontact-options-card.test.tsx | 12 -- .../components/response-options-card.test.tsx | 24 --- .../components/response-options-card.tsx | 80 --------- .../editor/components/settings-view.test.tsx | 1 - .../editor/components/survey-editor.test.tsx | 1 - .../components/survey-menu-bar.test.tsx | 159 +++++++++++++++++- .../editor/components/survey-menu-bar.tsx | 2 +- .../components/survey-placement-card.test.tsx | 1 - .../survey-variables-card-item.test.tsx | 14 -- .../components/survey-variables-card.test.tsx | 2 - .../components/when-to-send-card.test.tsx | 1 - .../modules/survey/editor/lib/survey.test.ts | 41 ----- apps/web/modules/survey/editor/lib/survey.ts | 13 -- .../modules/survey/editor/lib/utils.test.tsx | 2 - .../survey/editor/lib/validation.test.ts | 2 - apps/web/modules/survey/lib/survey.ts | 2 - .../link/components/survey-inactive.test.tsx | 9 - .../link/components/survey-inactive.tsx | 2 +- apps/web/modules/survey/link/lib/data.test.ts | 4 - apps/web/modules/survey/link/lib/data.ts | 2 - .../survey/list/components/survey-card.tsx | 3 - .../survey/list/components/survey-filters.tsx | 9 +- .../survey/templates/lib/minimal-survey.ts | 2 - .../question-toggle-table/index.test.tsx | 1 - .../survey-status-indicator/index.test.tsx | 26 --- .../survey-status-indicator/index.tsx | 19 +-- apps/web/scripts/docker/next-start.sh | 7 - docker/cronjobs | 3 - docker/docker-compose.yml | 7 +- docker/formbricks.sh | 4 +- docs/api-reference/openapi.json | 12 -- docs/api-v2-reference/openapi.yml | 13 -- .../local-setup/github-codespaces.mdx | 53 +++--- docs/development/local-setup/gitpod.mdx | 53 +++--- docs/development/local-setup/linux.mdx | 53 +++--- docs/development/local-setup/mac.mdx | 53 +++--- docs/development/local-setup/windows.mdx | 53 +++--- .../configuration/environment-variables.mdx | 1 - docs/self-hosting/setup/cluster-setup.mdx | 13 -- docs/self-hosting/setup/docker.mdx | 20 +-- docs/self-hosting/setup/one-click.mdx | 8 +- helm-chart/templates/NOTES.txt | 2 +- helm-chart/templates/_helpers.tpl | 14 +- helm-chart/templates/cronjob.yaml | 146 ---------------- helm-chart/templates/secrets.yaml | 2 +- helm-chart/values.yaml | 64 +++---- .../values-staging.yaml.gotmpl | 53 ------ .../formbricks-cloud-helm/values.yaml.gotmpl | 55 +----- .../migration.sql | 26 +++ packages/database/schema.prisma | 3 - packages/database/zod/surveys.ts | 6 - packages/types/surveys/types.ts | 6 +- turbo.json | 1 - 110 files changed, 414 insertions(+), 1096 deletions(-) delete mode 100644 apps/web/app/api/cron/ping/route.ts delete mode 100644 apps/web/app/api/cron/survey-status/route.ts delete mode 100644 docker/cronjobs delete mode 100644 helm-chart/templates/cronjob.yaml create mode 100644 packages/database/migration/20250904145727_removes_cron_and_survey_scheduling/migration.sql diff --git a/.env.example b/.env.example index bff49baad5..67c3672ae6 100644 --- a/.env.example +++ b/.env.example @@ -99,8 +99,6 @@ PASSWORD_RESET_DISABLED=1 # Organization Invite. Disable the ability for invited users to create an account. # INVITE_DISABLED=1 -# Docker cron jobs. Disable the supercronic cron jobs in the Docker image (useful for cluster setups). -# DOCKER_CRON_ENABLED=1 ########## # Other # diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile index 5a0b9a3e54..57852becc1 100644 --- a/apps/web/Dockerfile +++ b/apps/web/Dockerfile @@ -114,9 +114,6 @@ RUN chown -R nextjs:nextjs ./node_modules/.prisma && chmod -R 755 ./node_modules COPY --from=installer /prisma_version.txt . RUN chown nextjs:nextjs ./prisma_version.txt && chmod 644 ./prisma_version.txt -COPY /docker/cronjobs /app/docker/cronjobs -RUN chmod -R 755 /app/docker/cronjobs - COPY --from=installer /app/node_modules/@paralleldrive/cuid2 ./node_modules/@paralleldrive/cuid2 RUN chmod -R 755 ./node_modules/@paralleldrive/cuid2 diff --git a/apps/web/app/(app)/environments/[environmentId]/project/integrations/google-sheets/components/AddIntegrationModal.test.tsx b/apps/web/app/(app)/environments/[environmentId]/project/integrations/google-sheets/components/AddIntegrationModal.test.tsx index 35dd827fe0..d8e5fa48b9 100644 --- a/apps/web/app/(app)/environments/[environmentId]/project/integrations/google-sheets/components/AddIntegrationModal.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/project/integrations/google-sheets/components/AddIntegrationModal.test.tsx @@ -205,7 +205,6 @@ const surveys: TSurvey[] = [ triggers: [], recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", displayPercentage: null, @@ -242,7 +241,6 @@ const surveys: TSurvey[] = [ triggers: [], recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", displayPercentage: null, diff --git a/apps/web/app/(app)/environments/[environmentId]/project/integrations/google-sheets/page.test.tsx b/apps/web/app/(app)/environments/[environmentId]/project/integrations/google-sheets/page.test.tsx index edcffe4e8a..927eec505a 100644 --- a/apps/web/app/(app)/environments/[environmentId]/project/integrations/google-sheets/page.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/project/integrations/google-sheets/page.test.tsx @@ -113,7 +113,6 @@ const mockSurveys: TSurvey[] = [ triggers: [], recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", displayPercentage: null, @@ -125,7 +124,6 @@ const mockSurveys: TSurvey[] = [ surveyClosedMessage: null, welcomeCard: { enabled: false } as unknown as TSurvey["welcomeCard"], autoComplete: null, - runOnDate: null, } as unknown as TSurvey, ]; diff --git a/apps/web/app/(app)/environments/[environmentId]/project/integrations/notion/components/AddIntegrationModal.test.tsx b/apps/web/app/(app)/environments/[environmentId]/project/integrations/notion/components/AddIntegrationModal.test.tsx index 331caeb511..cd8cc30bf8 100644 --- a/apps/web/app/(app)/environments/[environmentId]/project/integrations/notion/components/AddIntegrationModal.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/project/integrations/notion/components/AddIntegrationModal.test.tsx @@ -224,7 +224,6 @@ const surveys: TSurvey[] = [ triggers: [], recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", displayPercentage: null, @@ -259,7 +258,6 @@ const surveys: TSurvey[] = [ triggers: [], recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", displayPercentage: null, diff --git a/apps/web/app/(app)/environments/[environmentId]/project/integrations/notion/page.test.tsx b/apps/web/app/(app)/environments/[environmentId]/project/integrations/notion/page.test.tsx index cf5ae803da..5af6b66144 100644 --- a/apps/web/app/(app)/environments/[environmentId]/project/integrations/notion/page.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/project/integrations/notion/page.test.tsx @@ -125,7 +125,6 @@ const mockSurveys: TSurvey[] = [ triggers: [], recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", displayPercentage: null, @@ -137,7 +136,6 @@ const mockSurveys: TSurvey[] = [ surveyClosedMessage: null, welcomeCard: { enabled: false } as unknown as TSurvey["welcomeCard"], autoComplete: null, - runOnDate: null, } as unknown as TSurvey, ]; diff --git a/apps/web/app/(app)/environments/[environmentId]/project/integrations/slack/components/AddChannelMappingModal.test.tsx b/apps/web/app/(app)/environments/[environmentId]/project/integrations/slack/components/AddChannelMappingModal.test.tsx index 6be8126ad6..c087a991b0 100644 --- a/apps/web/app/(app)/environments/[environmentId]/project/integrations/slack/components/AddChannelMappingModal.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/project/integrations/slack/components/AddChannelMappingModal.test.tsx @@ -212,7 +212,6 @@ const surveys: TSurvey[] = [ triggers: [], recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", displayPercentage: null, @@ -249,7 +248,6 @@ const surveys: TSurvey[] = [ triggers: [], recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", displayPercentage: null, diff --git a/apps/web/app/(app)/environments/[environmentId]/project/integrations/slack/page.test.tsx b/apps/web/app/(app)/environments/[environmentId]/project/integrations/slack/page.test.tsx index 79dbba97f9..8a02a5662b 100644 --- a/apps/web/app/(app)/environments/[environmentId]/project/integrations/slack/page.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/project/integrations/slack/page.test.tsx @@ -118,8 +118,6 @@ const mockSurveys: TSurvey[] = [ styling: null, segment: null, displayPercentage: null, - closeOnDate: null, - runOnDate: null, } as unknown as TSurvey, ]; const mockSlackIntegration = { diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/components/SurveyAnalysisNavigation.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/components/SurveyAnalysisNavigation.test.tsx index 7682f17a50..39aa347102 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/components/SurveyAnalysisNavigation.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/components/SurveyAnalysisNavigation.test.tsx @@ -111,11 +111,9 @@ const mockSurvey = { surveyClosedMessage: null, welcomeCard: { enabled: false, headline: { default: "" } } as unknown as TSurvey["welcomeCard"], segment: null, - closeOnDate: null, delay: 0, autoComplete: null, recontactDays: null, - runOnDate: null, displayPercentage: null, createdBy: null, } as unknown as TSurvey; diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/layout.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/layout.test.tsx index 341bae0629..267a04f952 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/layout.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/layout.test.tsx @@ -43,14 +43,12 @@ const mockSurvey = { languages: [], segment: null, autoClose: null, - closeOnDate: null, delay: 0, displayLimit: null, displayOption: "displayOnce", isBackButtonHidden: false, pin: null, recontactDays: null, - runOnDate: null, showLanguageSwitch: false, singleUse: null, surveyClosedMessage: null, diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponseCardModal.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponseCardModal.test.tsx index 4f8af1ba34..89028c3452 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponseCardModal.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponseCardModal.test.tsx @@ -103,7 +103,6 @@ const mockSurvey = { displayOption: "displayOnce", recontactDays: 0, autoClose: null, - closeOnDate: null, delay: 0, autoComplete: null, surveyClosedMessage: null, diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponseDataView.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponseDataView.test.tsx index 805bbf0628..04254ffb65 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponseDataView.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/responses/components/ResponseDataView.test.tsx @@ -77,7 +77,6 @@ const mockSurvey = { updatedAt: new Date(), environmentId: "env1", autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SuccessMessage.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SuccessMessage.test.tsx index 6baa205ea2..911b6ef3af 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SuccessMessage.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SuccessMessage.test.tsx @@ -53,8 +53,6 @@ describe("SuccessMessage", () => { autoClose: null, delay: 0, autoComplete: null, - runOnDate: null, - closeOnDate: null, welcomeCard: { enabled: false, headline: { default: "" }, diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SummaryList.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SummaryList.test.tsx index 8f364fc122..6a09f503da 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SummaryList.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SummaryList.test.tsx @@ -181,12 +181,10 @@ const mockSurvey = { styling: null, surveyClosedMessage: null, welcomeCard: { enabled: false } as unknown as TSurvey["welcomeCard"], - closeOnDate: null, delay: 0, displayPercentage: null, recontactDays: null, autoComplete: null, - runOnDate: null, segment: null, variables: [], } as unknown as TSurvey; diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SurveyAnalysisCTA.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SurveyAnalysisCTA.test.tsx index adcee0173c..338e37d583 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SurveyAnalysisCTA.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SurveyAnalysisCTA.test.tsx @@ -277,8 +277,6 @@ const mockSurvey: TSurvey = { createdBy: null, variables: [], followUps: [], - runOnDate: null, - closeOnDate: null, styling: null, pin: null, recaptcha: null, diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/share-survey-modal.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/share-survey-modal.test.tsx index c3091e48db..d92211703f 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/share-survey-modal.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/share-survey-modal.test.tsx @@ -230,8 +230,6 @@ const mockSurvey: TSurvey = { createdBy: null, variables: [], followUps: [], - runOnDate: null, - closeOnDate: null, styling: null, pin: null, recaptcha: null, diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/link-settings-tab.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/link-settings-tab.test.tsx index a7749e31ec..73b4b84e21 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/link-settings-tab.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/link-settings-tab.test.tsx @@ -90,8 +90,6 @@ const mockSurvey: TSurvey = { createdBy: null, variables: [], followUps: [], - runOnDate: null, - closeOnDate: null, styling: null, pin: null, recaptcha: null, diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/share-view.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/share-view.test.tsx index 8521b00ebd..2c6604e11d 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/share-view.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/share-view.test.tsx @@ -259,8 +259,6 @@ const mockSurvey = { autoClose: null, delay: 0, autoComplete: null, - runOnDate: null, - closeOnDate: null, singleUse: { enabled: false, isEncrypted: false }, styling: null, } as any; diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/emailTemplate.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/emailTemplate.test.tsx index 8afd520827..b94790b905 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/emailTemplate.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/emailTemplate.test.tsx @@ -86,8 +86,6 @@ const mockSurvey = { autoClose: null, delay: 0, autoComplete: null, - runOnDate: null, - closeOnDate: null, } as unknown as TSurvey; const mockProject = { diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/surveySummary.test.ts b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/surveySummary.test.ts index 6ae1b24631..1da975bb65 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/surveySummary.test.ts +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/surveySummary.test.ts @@ -91,7 +91,6 @@ const mockBaseSurvey: TSurvey = { segment: null, recontactDays: null, autoComplete: null, - closeOnDate: null, createdAt: new Date(), updatedAt: new Date(), displayOption: "displayOnce", @@ -104,7 +103,6 @@ const mockBaseSurvey: TSurvey = { isSingleResponsePerEmailEnabled: false, isVerifyEmailEnabled: false, projectOverwrites: null, - runOnDate: null, showLanguageSwitch: false, isBackButtonHidden: false, followUps: [], diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/utils.test.ts b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/utils.test.ts index 41cfaa1e97..a40f5dfc03 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/utils.test.ts +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/utils.test.ts @@ -60,7 +60,6 @@ describe("Utils Tests", () => { triggers: [], recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, autoComplete: null, singleUse: null, diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/page.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/page.test.tsx index b4559da75a..e59fc4be80 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/page.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/page.test.tsx @@ -156,11 +156,9 @@ const mockSurvey = { triggers: [], welcomeCard: { enabled: false } as unknown as TSurvey["welcomeCard"], autoComplete: null, - closeOnDate: null, delay: 0, displayPercentage: null, languages: [], - runOnDate: null, singleUse: null, surveyClosedMessage: null, segment: null, diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/CustomFilter.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/CustomFilter.test.tsx index dd34ce26aa..226ab68c1c 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/CustomFilter.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/CustomFilter.test.tsx @@ -97,7 +97,6 @@ const mockSurvey = { displayOption: "displayOnce", recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, autoComplete: null, surveyClosedMessage: null, diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/SurveyStatusDropdown.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/SurveyStatusDropdown.test.tsx index 126e0b77b1..b70a0d6106 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/SurveyStatusDropdown.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/SurveyStatusDropdown.test.tsx @@ -90,7 +90,6 @@ const baseSurvey: TSurvey = { singleUse: null, verifyEmail: null, pin: null, - closeOnDate: null, productOverwrites: null, analytics: { numCTA: 0, @@ -105,7 +104,6 @@ const baseSurvey: TSurvey = { }, createdBy: null, autoComplete: null, - runOnDate: null, endings: [], }; @@ -123,29 +121,6 @@ describe("SurveyStatusDropdown", () => { expect(screen.queryByTestId("select-container")).toBeNull(); }); - test("disables select when status is scheduled", () => { - render( - - ); - expect(screen.getByTestId("select-container")).toHaveAttribute("data-disabled", "true"); - expect(screen.getByTestId("tooltip")).toBeInTheDocument(); - expect(screen.getByTestId("tooltip-content")).toHaveTextContent( - "environments.surveys.survey_status_tooltip" - ); - }); - - test("disables select when closeOnDate is in the past", () => { - const pastDate = new Date(); - pastDate.setDate(pastDate.getDate() - 1); - render( - - ); - expect(screen.getByTestId("select-container")).toHaveAttribute("data-disabled", "true"); - }); - test("renders SurveyStatusIndicator for link survey", () => { render( { const { t } = useTranslate(); const router = useRouter(); - const isCloseOnDateEnabled = survey.closeOnDate !== null; - const closeOnDate = survey.closeOnDate ? new Date(survey.closeOnDate) : null; - const isStatusChangeDisabled = - (survey.status === "scheduled" || (isCloseOnDateEnabled && closeOnDate && closeOnDate < new Date())) ?? - false; const handleStatusChange = async (status: TSurvey["status"]) => { const updateSurveyActionResponse = await updateSurveyAction({ ...survey, status }); @@ -68,53 +62,43 @@ export const SurveyStatusDropdown = ({ ) : ( )} diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/context/survey-context.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/context/survey-context.test.tsx index b4b9db65e7..ee8cb69654 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/context/survey-context.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/context/survey-context.test.tsx @@ -65,8 +65,6 @@ const mockSurvey: TSurvey = { followUps: [], delay: 0, autoComplete: null, - runOnDate: null, - closeOnDate: null, projectOverwrites: null, styling: null, showLanguageSwitch: null, diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/layout.test.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/layout.test.tsx index 39e2d01103..fa360506bc 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/layout.test.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/layout.test.tsx @@ -49,8 +49,6 @@ describe("SurveyLayout", () => { recontactDays: null, displayLimit: null, autoClose: null, - runOnDate: null, - closeOnDate: null, delay: 0, displayPercentage: null, autoComplete: null, diff --git a/apps/web/app/api/(internal)/pipeline/lib/__mocks__/survey-follow-up.mock.ts b/apps/web/app/api/(internal)/pipeline/lib/__mocks__/survey-follow-up.mock.ts index efaad8de60..1c464b09ed 100644 --- a/apps/web/app/api/(internal)/pipeline/lib/__mocks__/survey-follow-up.mock.ts +++ b/apps/web/app/api/(internal)/pipeline/lib/__mocks__/survey-follow-up.mock.ts @@ -148,8 +148,6 @@ export const mockSurvey: TSurvey = { recontactDays: null, displayLimit: null, autoClose: null, - runOnDate: null, - closeOnDate: null, delay: 0, displayPercentage: null, autoComplete: null, diff --git a/apps/web/app/api/(internal)/pipeline/lib/handleIntegrations.test.ts b/apps/web/app/api/(internal)/pipeline/lib/handleIntegrations.test.ts index 1e0ed34b86..f99b356523 100644 --- a/apps/web/app/api/(internal)/pipeline/lib/handleIntegrations.test.ts +++ b/apps/web/app/api/(internal)/pipeline/lib/handleIntegrations.test.ts @@ -143,7 +143,6 @@ const mockSurvey = { segment: null, recontactDays: null, autoComplete: null, - closeOnDate: null, createdAt: new Date(), updatedAt: new Date(), displayOption: "displayOnce", diff --git a/apps/web/app/api/cron/ping/route.ts b/apps/web/app/api/cron/ping/route.ts deleted file mode 100644 index b6ad114982..0000000000 --- a/apps/web/app/api/cron/ping/route.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { responses } from "@/app/lib/api/response"; -import { CRON_SECRET } from "@/lib/constants"; -import { env } from "@/lib/env"; -import { captureTelemetry } from "@/lib/telemetry"; -import packageJson from "@/package.json"; -import { headers } from "next/headers"; -import { prisma } from "@formbricks/database"; - -export const POST = async () => { - const headersList = await headers(); - const apiKey = headersList.get("x-api-key"); - - if (!apiKey || apiKey !== CRON_SECRET) { - return responses.notAuthenticatedResponse(); - } - - if (env.TELEMETRY_DISABLED === "1") { - return responses.successResponse({}, true); - } - - const [surveyCount, responseCount, userCount] = await Promise.all([ - prisma.survey.count(), - prisma.response.count(), - prisma.user.count(), - ]); - - captureTelemetry("ping", { - version: packageJson.version, - surveyCount, - responseCount, - userCount, - }); - - return responses.successResponse({}, true); -}; diff --git a/apps/web/app/api/cron/survey-status/route.ts b/apps/web/app/api/cron/survey-status/route.ts deleted file mode 100644 index c1a862f6c6..0000000000 --- a/apps/web/app/api/cron/survey-status/route.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { responses } from "@/app/lib/api/response"; -import { CRON_SECRET } from "@/lib/constants"; -import { headers } from "next/headers"; -import { prisma } from "@formbricks/database"; - -export const POST = async () => { - const headersList = await headers(); - const apiKey = headersList.get("x-api-key"); - - if (!apiKey || apiKey !== CRON_SECRET) { - return responses.notAuthenticatedResponse(); - } - - // close surveys that are in progress and have a closeOnDate in the past - const surveysToClose = await prisma.survey.findMany({ - where: { - status: "inProgress", - closeOnDate: { - lte: new Date(), - }, - }, - select: { - id: true, - environmentId: true, - }, - }); - - if (surveysToClose.length) { - await prisma.survey.updateMany({ - where: { - id: { - in: surveysToClose.map((survey) => survey.id), - }, - }, - data: { - status: "completed", - }, - }); - } - - // run surveys that are scheduled and have a runOnDate in the past - const scheduledSurveys = await prisma.survey.findMany({ - where: { - status: "scheduled", - runOnDate: { - lte: new Date(), - }, - }, - select: { - id: true, - environmentId: true, - }, - }); - - if (scheduledSurveys.length) { - await prisma.survey.updateMany({ - where: { - id: { - in: scheduledSurveys.map((survey) => survey.id), - }, - }, - data: { - status: "inProgress", - }, - }); - } - - return responses.successResponse({ - message: `Updated ${surveysToClose.length} surveys to completed and ${scheduledSurveys.length} surveys to inProgress.`, - }); -}; diff --git a/apps/web/app/api/v1/client/[environmentId]/app/sync/lib/survey.test.ts b/apps/web/app/api/v1/client/[environmentId]/app/sync/lib/survey.test.ts index 9d58c96270..1c6dd0473c 100644 --- a/apps/web/app/api/v1/client/[environmentId]/app/sync/lib/survey.test.ts +++ b/apps/web/app/api/v1/client/[environmentId]/app/sync/lib/survey.test.ts @@ -80,7 +80,6 @@ const baseSurvey: TSurvey = { displayOption: "displayOnce", recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, displayPercentage: null, autoComplete: null, @@ -100,7 +99,6 @@ const baseSurvey: TSurvey = { isSingleResponsePerEmailEnabled: false, isVerifyEmailEnabled: false, projectOverwrites: null, - runOnDate: null, showLanguageSwitch: false, isBackButtonHidden: false, followUps: [], diff --git a/apps/web/app/api/v1/client/[environmentId]/app/sync/lib/utils.test.ts b/apps/web/app/api/v1/client/[environmentId]/app/sync/lib/utils.test.ts index bb17e265a1..418cf4a7f6 100644 --- a/apps/web/app/api/v1/client/[environmentId]/app/sync/lib/utils.test.ts +++ b/apps/web/app/api/v1/client/[environmentId]/app/sync/lib/utils.test.ts @@ -51,14 +51,12 @@ const baseSurvey: TSurvey = { isSingleResponsePerEmailEnabled: false, isVerifyEmailEnabled: false, projectOverwrites: null, - runOnDate: null, showLanguageSwitch: false, isBackButtonHidden: false, followUps: [], recaptcha: { enabled: false, threshold: 0.5 }, displayOption: "displayOnce", autoClose: null, - closeOnDate: null, delay: 0, displayPercentage: null, autoComplete: null, diff --git a/apps/web/app/api/v1/client/[environmentId]/environment/lib/environmentState.test.ts b/apps/web/app/api/v1/client/[environmentId]/environment/lib/environmentState.test.ts index 4796d32126..31ab30e00a 100644 --- a/apps/web/app/api/v1/client/[environmentId]/environment/lib/environmentState.test.ts +++ b/apps/web/app/api/v1/client/[environmentId]/environment/lib/environmentState.test.ts @@ -107,13 +107,11 @@ const mockSurveys: TSurvey[] = [ isSingleResponsePerEmailEnabled: false, isVerifyEmailEnabled: false, projectOverwrites: null, - runOnDate: null, showLanguageSwitch: false, questions: [], displayOption: "displayOnce", recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, displayPercentage: null, autoComplete: null, diff --git a/apps/web/app/api/v2/client/[environmentId]/responses/lib/utils.test.ts b/apps/web/app/api/v2/client/[environmentId]/responses/lib/utils.test.ts index 6ce6a1b65c..a2701948ea 100644 --- a/apps/web/app/api/v2/client/[environmentId]/responses/lib/utils.test.ts +++ b/apps/web/app/api/v2/client/[environmentId]/responses/lib/utils.test.ts @@ -60,7 +60,6 @@ const mockSurvey: TSurvey = { displayOption: "displayOnce", recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, displayPercentage: null, autoComplete: null, @@ -83,7 +82,6 @@ const mockSurvey: TSurvey = { isSingleResponsePerEmailEnabled: false, isVerifyEmailEnabled: false, projectOverwrites: null, - runOnDate: null, showLanguageSwitch: false, }; diff --git a/apps/web/app/lib/templates.ts b/apps/web/app/lib/templates.ts index 890dec3dcc..da6a8ac412 100644 --- a/apps/web/app/lib/templates.ts +++ b/apps/web/app/lib/templates.ts @@ -3682,9 +3682,7 @@ export const previewSurvey = (projectName: string, t: TFnType) => { recontactDays: null, displayLimit: null, autoClose: null, - runOnDate: null, recaptcha: null, - closeOnDate: null, delay: 0, displayPercentage: null, autoComplete: 50, diff --git a/apps/web/app/middleware/endpoint-validator.test.ts b/apps/web/app/middleware/endpoint-validator.test.ts index 916447e51f..770b10337b 100644 --- a/apps/web/app/middleware/endpoint-validator.test.ts +++ b/apps/web/app/middleware/endpoint-validator.test.ts @@ -420,7 +420,6 @@ describe("endpoint-validator", () => { expect(isAdminDomainRoute("/api/v2/management/surveys")).toBe(true); expect(isAdminDomainRoute("/api/v1/integrations/webhook")).toBe(true); expect(isAdminDomainRoute("/pipeline/jobs")).toBe(true); - expect(isAdminDomainRoute("/cron/tasks")).toBe(true); expect(isAdminDomainRoute("/random/route")).toBe(true); }); @@ -472,7 +471,6 @@ describe("endpoint-validator", () => { expect(isRouteAllowedForDomain("/health", false)).toBe(true); expect(isRouteAllowedForDomain("/storage/env123/public/file.jpg", false)).toBe(true); expect(isRouteAllowedForDomain("/pipeline/jobs", false)).toBe(true); - expect(isRouteAllowedForDomain("/cron/tasks", false)).toBe(true); expect(isRouteAllowedForDomain("/unknown/route", false)).toBe(true); }); diff --git a/apps/web/app/middleware/endpoint-validator.ts b/apps/web/app/middleware/endpoint-validator.ts index 0bb16988f9..f8aa5001d8 100644 --- a/apps/web/app/middleware/endpoint-validator.ts +++ b/apps/web/app/middleware/endpoint-validator.ts @@ -72,7 +72,7 @@ export const isAdminDomainRoute = (url: string): boolean => { return false; } - // For non-public routes, allow them (includes known admin routes and unknown routes like pipeline, cron) + // For non-public routes, allow them (includes known admin routes and unknown routes like pipeline) return true; }; diff --git a/apps/web/lib/env.ts b/apps/web/lib/env.ts index 1229e4d745..4f1ddc600a 100644 --- a/apps/web/lib/env.ts +++ b/apps/web/lib/env.ts @@ -16,7 +16,6 @@ export const env = createEnv({ BREVO_LIST_ID: z.string().optional(), DATABASE_URL: z.string().url(), DEBUG: z.enum(["1", "0"]).optional(), - DOCKER_CRON_ENABLED: z.enum(["1", "0"]).optional(), AUTH_DEFAULT_TEAM_ID: z.string().optional(), AUTH_SKIP_INVITE_FOR_SSO: z.enum(["1", "0"]).optional(), E2E_TESTING: z.enum(["1", "0"]).optional(), @@ -148,7 +147,6 @@ export const env = createEnv({ DEBUG: process.env.DEBUG, AUTH_DEFAULT_TEAM_ID: process.env.AUTH_SSO_DEFAULT_TEAM_ID, AUTH_SKIP_INVITE_FOR_SSO: process.env.AUTH_SKIP_INVITE_FOR_SSO, - DOCKER_CRON_ENABLED: process.env.DOCKER_CRON_ENABLED, E2E_TESTING: process.env.E2E_TESTING, EMAIL_AUTH_DISABLED: process.env.EMAIL_AUTH_DISABLED, EMAIL_VERIFICATION_DISABLED: process.env.EMAIL_VERIFICATION_DISABLED, diff --git a/apps/web/lib/i18n/i18n.mock.ts b/apps/web/lib/i18n/i18n.mock.ts index 758014f39f..e6633c1f38 100644 --- a/apps/web/lib/i18n/i18n.mock.ts +++ b/apps/web/lib/i18n/i18n.mock.ts @@ -301,8 +301,6 @@ export const mockSurvey: TSurvey = { recontactDays: null, displayLimit: null, autoClose: null, - runOnDate: null, - closeOnDate: null, delay: 0, displayPercentage: null, autoComplete: null, diff --git a/apps/web/lib/response/tests/__mocks__/data.mock.ts b/apps/web/lib/response/tests/__mocks__/data.mock.ts index 8e9e55a53f..f17dab7f2f 100644 --- a/apps/web/lib/response/tests/__mocks__/data.mock.ts +++ b/apps/web/lib/response/tests/__mocks__/data.mock.ts @@ -509,8 +509,6 @@ export const mockSurvey: TSurvey = { recontactDays: null, displayLimit: null, autoClose: null, - runOnDate: null, - closeOnDate: null, delay: 0, displayPercentage: null, autoComplete: null, diff --git a/apps/web/lib/responses.test.ts b/apps/web/lib/responses.test.ts index 04f60a2c98..53e0bc2ece 100644 --- a/apps/web/lib/responses.test.ts +++ b/apps/web/lib/responses.test.ts @@ -232,8 +232,6 @@ describe("Response Processing", () => { autoClose: null, autoComplete: null, recontactDays: null, - runOnDate: null, - closeOnDate: null, welcomeCard: { enabled: false, timeToFinish: false, diff --git a/apps/web/lib/survey/__mock__/survey.mock.ts b/apps/web/lib/survey/__mock__/survey.mock.ts index 02a24e92a2..42c3c8eaa8 100644 --- a/apps/web/lib/survey/__mock__/survey.mock.ts +++ b/apps/web/lib/survey/__mock__/survey.mock.ts @@ -198,8 +198,6 @@ const baseSurveyProperties = { autoClose: 10, delay: 0, autoComplete: 7, - runOnDate: null, - closeOnDate: currentDate, redirectUrl: "https://github.com/formbricks/formbricks", recontactDays: 3, displayLimit: 3, diff --git a/apps/web/lib/survey/service.ts b/apps/web/lib/survey/service.ts index 8a911d6367..a42114b948 100644 --- a/apps/web/lib/survey/service.ts +++ b/apps/web/lib/survey/service.ts @@ -44,8 +44,6 @@ export const selectSurvey = { recontactDays: true, displayLimit: true, autoClose: true, - runOnDate: true, - closeOnDate: true, delay: true, displayPercentage: true, autoComplete: true, @@ -519,19 +517,6 @@ export const updateSurvey = async (updatedSurvey: TSurvey): Promise => type, }; - // Remove scheduled status when runOnDate is not set - if (data.status === "scheduled" && data.runOnDate === null) { - data.status = "inProgress"; - } - // Set scheduled status when runOnDate is set and in the future on completed surveys - if ( - (data.status === "completed" || data.status === "paused" || data.status === "inProgress") && - data.runOnDate && - data.runOnDate > new Date() - ) { - data.status = "scheduled"; - } - delete data.createdBy; const prismaSurvey = await prisma.survey.update({ where: { id: surveyId }, diff --git a/apps/web/modules/analysis/components/ShareSurveyLink/index.test.tsx b/apps/web/modules/analysis/components/ShareSurveyLink/index.test.tsx index 55a146c724..d02dc1abf2 100644 --- a/apps/web/modules/analysis/components/ShareSurveyLink/index.test.tsx +++ b/apps/web/modules/analysis/components/ShareSurveyLink/index.test.tsx @@ -49,7 +49,6 @@ const survey: TSurvey = { ], recontactDays: 1, autoClose: null, - closeOnDate: null, delay: 0, displayPercentage: null, displayLimit: null, diff --git a/apps/web/modules/api/v2/management/surveys/types/surveys.ts b/apps/web/modules/api/v2/management/surveys/types/surveys.ts index cfe75ab656..787e352550 100644 --- a/apps/web/modules/api/v2/management/surveys/types/surveys.ts +++ b/apps/web/modules/api/v2/management/surveys/types/surveys.ts @@ -13,7 +13,7 @@ export const ZGetSurveysFilter = z startDate: z.coerce.date().optional(), endDate: z.coerce.date().optional(), surveyType: z.enum(["link", "app"]).optional(), - surveyStatus: z.enum(["draft", "scheduled", "inProgress", "paused", "completed"]).optional(), + surveyStatus: z.enum(["draft", "inProgress", "paused", "completed"]).optional(), }) .refine( (data) => { @@ -43,8 +43,6 @@ export const ZSurveyInput = ZSurveyWithoutQuestionType.pick({ autoClose: true, autoComplete: true, delay: true, - runOnDate: true, - closeOnDate: true, singleUse: true, isVerifyEmailEnabled: true, isSingleResponsePerEmailEnabled: true, @@ -66,8 +64,6 @@ export const ZSurveyInput = ZSurveyWithoutQuestionType.pick({ displayLimit: true, autoClose: true, autoComplete: true, - runOnDate: true, - closeOnDate: true, surveyClosedMessage: true, styling: true, projectOverwrites: true, diff --git a/apps/web/modules/ee/contacts/[contactId]/components/response-feed.test.tsx b/apps/web/modules/ee/contacts/[contactId]/components/response-feed.test.tsx index 635d13138c..afa6b36041 100644 --- a/apps/web/modules/ee/contacts/[contactId]/components/response-feed.test.tsx +++ b/apps/web/modules/ee/contacts/[contactId]/components/response-feed.test.tsx @@ -60,10 +60,8 @@ describe("ResponseFeed", () => { name: "", subheading: "", }, - closeOnDate: null, displayLimit: null, autoComplete: null, - runOnDate: null, productOverwrites: null, styling: null, pin: null, diff --git a/apps/web/modules/ee/contacts/segments/components/segment-table-data-row-container.test.tsx b/apps/web/modules/ee/contacts/segments/components/segment-table-data-row-container.test.tsx index a5574c7817..898332707f 100644 --- a/apps/web/modules/ee/contacts/segments/components/segment-table-data-row-container.test.tsx +++ b/apps/web/modules/ee/contacts/segments/components/segment-table-data-row-container.test.tsx @@ -60,7 +60,6 @@ const mockSurveys: TSurvey[] = [ triggers: [], recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", displayPercentage: null, @@ -76,7 +75,6 @@ const mockSurveys: TSurvey[] = [ pin: null, surveyClosedMessage: null, autoComplete: null, - runOnDate: null, createdBy: null, } as unknown as TSurvey, { @@ -89,7 +87,6 @@ const mockSurveys: TSurvey[] = [ triggers: [], recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", displayPercentage: null, @@ -105,7 +102,6 @@ const mockSurveys: TSurvey[] = [ pin: null, surveyClosedMessage: null, autoComplete: null, - runOnDate: null, createdBy: null, } as unknown as TSurvey, { @@ -118,7 +114,6 @@ const mockSurveys: TSurvey[] = [ triggers: [], recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", displayPercentage: null, @@ -135,7 +130,6 @@ const mockSurveys: TSurvey[] = [ pin: null, surveyClosedMessage: null, autoComplete: null, - runOnDate: null, createdBy: null, } as unknown as TSurvey, ]; diff --git a/apps/web/modules/ee/contacts/segments/components/targeting-card.test.tsx b/apps/web/modules/ee/contacts/segments/components/targeting-card.test.tsx index 526fa5f103..6291d2cb8e 100644 --- a/apps/web/modules/ee/contacts/segments/components/targeting-card.test.tsx +++ b/apps/web/modules/ee/contacts/segments/components/targeting-card.test.tsx @@ -48,7 +48,6 @@ const mockSurvey = { displayOption: "displayOnce", recontactDays: 7, autoClose: null, - closeOnDate: null, delay: 0, displayPercentage: 100, autoComplete: null, diff --git a/apps/web/modules/survey/components/question-form-input/utils.test.ts b/apps/web/modules/survey/components/question-form-input/utils.test.ts index 5be9ac13d1..4ce0a335a7 100644 --- a/apps/web/modules/survey/components/question-form-input/utils.test.ts +++ b/apps/web/modules/survey/components/question-form-input/utils.test.ts @@ -157,7 +157,6 @@ describe("utils", () => { type: "app", triggers: [], recontactDays: null, - closeOnDate: null, endings: [], delay: 0, pin: null, @@ -185,7 +184,6 @@ describe("utils", () => { type: "app", triggers: [], recontactDays: null, - closeOnDate: null, endings: [], delay: 0, pin: null, @@ -216,7 +214,6 @@ describe("utils", () => { type: "app", triggers: [], recontactDays: null, - closeOnDate: null, endings: [ { type: "endScreen", @@ -250,7 +247,6 @@ describe("utils", () => { type: "app", triggers: [], recontactDays: null, - closeOnDate: null, endings: [ { type: "redirectToUrl", @@ -281,7 +277,6 @@ describe("utils", () => { type: "app", triggers: [], recontactDays: null, - closeOnDate: null, endings: [], delay: 0, pin: null, @@ -314,7 +309,6 @@ describe("utils", () => { type: "app", triggers: [], recontactDays: null, - closeOnDate: null, endings: [], delay: 0, pin: null, @@ -347,7 +341,6 @@ describe("utils", () => { type: "app", triggers: [], recontactDays: null, - closeOnDate: null, endings: [], delay: 0, pin: null, @@ -379,7 +372,6 @@ describe("utils", () => { type: "app", triggers: [], recontactDays: null, - closeOnDate: null, endings: [], delay: 0, pin: null, diff --git a/apps/web/modules/survey/editor/components/add-action-modal.test.tsx b/apps/web/modules/survey/editor/components/add-action-modal.test.tsx index 89f6d18c58..63a4ddb7ef 100644 --- a/apps/web/modules/survey/editor/components/add-action-modal.test.tsx +++ b/apps/web/modules/survey/editor/components/add-action-modal.test.tsx @@ -109,7 +109,6 @@ const mockSurvey: TSurvey = { pin: null, displayPercentage: null, segment: null, - closeOnDate: null, createdBy: null, } as unknown as TSurvey; diff --git a/apps/web/modules/survey/editor/components/add-ending-card-button.test.tsx b/apps/web/modules/survey/editor/components/add-ending-card-button.test.tsx index 2b8becf52b..626986610f 100644 --- a/apps/web/modules/survey/editor/components/add-ending-card-button.test.tsx +++ b/apps/web/modules/survey/editor/components/add-ending-card-button.test.tsx @@ -32,8 +32,6 @@ const mockSurvey: TSurvey = { createdBy: null, segment: null, displayPercentage: null, - closeOnDate: null, - runOnDate: null, } as unknown as TSurvey; describe("AddEndingCardButton", () => { diff --git a/apps/web/modules/survey/editor/components/logic-editor-actions.test.tsx b/apps/web/modules/survey/editor/components/logic-editor-actions.test.tsx index 243dc1ea7e..b9006843ae 100644 --- a/apps/web/modules/survey/editor/components/logic-editor-actions.test.tsx +++ b/apps/web/modules/survey/editor/components/logic-editor-actions.test.tsx @@ -32,12 +32,10 @@ describe("LogicEditorActions", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: null, - runOnDate: null, questions: [], endings: [], hiddenFields: { @@ -106,12 +104,10 @@ describe("LogicEditorActions", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: null, - runOnDate: null, questions: [], endings: [], hiddenFields: { @@ -198,12 +194,10 @@ describe("LogicEditorActions", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: null, - runOnDate: null, questions: [], endings: [], hiddenFields: { @@ -273,12 +267,10 @@ describe("LogicEditorActions", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: null, - runOnDate: null, questions: [], endings: [], hiddenFields: { diff --git a/apps/web/modules/survey/editor/components/open-question-form.test.tsx b/apps/web/modules/survey/editor/components/open-question-form.test.tsx index 04caae2090..33fab8d2e4 100644 --- a/apps/web/modules/survey/editor/components/open-question-form.test.tsx +++ b/apps/web/modules/survey/editor/components/open-question-form.test.tsx @@ -136,7 +136,6 @@ const mockSurvey = { productOverwrites: null, singleUse: null, verifyEmail: null, - closeOnDate: null, delay: 0, displayPercentage: null, inlineTriggers: null, @@ -146,7 +145,6 @@ const mockSurvey = { redirectUrl: null, createdBy: null, autoComplete: null, - runOnDate: null, displayProgressBar: true, } as unknown as TSurvey; diff --git a/apps/web/modules/survey/editor/components/picture-selection-form.test.tsx b/apps/web/modules/survey/editor/components/picture-selection-form.test.tsx index 34abf48061..66baf51066 100644 --- a/apps/web/modules/survey/editor/components/picture-selection-form.test.tsx +++ b/apps/web/modules/survey/editor/components/picture-selection-form.test.tsx @@ -51,7 +51,6 @@ const baseSurvey = { recontactDays: null, displayOption: "displayOnce", autoClose: null, - closeOnDate: null, delay: 0, autoComplete: null, surveyClosedMessage: null, diff --git a/apps/web/modules/survey/editor/components/question-card.test.tsx b/apps/web/modules/survey/editor/components/question-card.test.tsx index b36de46209..9e467f679d 100644 --- a/apps/web/modules/survey/editor/components/question-card.test.tsx +++ b/apps/web/modules/survey/editor/components/question-card.test.tsx @@ -144,7 +144,6 @@ const baseSurvey = { singleUse: null, surveyClosedMessage: null, verifyEmail: null, - closeOnDate: null, projectOverwrites: null, hiddenFields: { enabled: false }, } as unknown as TSurvey; diff --git a/apps/web/modules/survey/editor/components/questions-view.test.tsx b/apps/web/modules/survey/editor/components/questions-view.test.tsx index 42e7c6eba5..645adab919 100644 --- a/apps/web/modules/survey/editor/components/questions-view.test.tsx +++ b/apps/web/modules/survey/editor/components/questions-view.test.tsx @@ -242,8 +242,6 @@ const mockSurvey = { hiddenFields: { enabled: true, fieldIds: [] }, createdAt: new Date(), updatedAt: new Date(), - runOnDate: null, - closeOnDate: null, } as unknown as TSurvey; const mockProject = { diff --git a/apps/web/modules/survey/editor/components/recontact-options-card.test.tsx b/apps/web/modules/survey/editor/components/recontact-options-card.test.tsx index 79181f77f6..25c9bcd761 100755 --- a/apps/web/modules/survey/editor/components/recontact-options-card.test.tsx +++ b/apps/web/modules/survey/editor/components/recontact-options-card.test.tsx @@ -46,12 +46,10 @@ describe("RecontactOptionsCard", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: null, - runOnDate: null, questions: [], endings: [], hiddenFields: { @@ -91,12 +89,10 @@ describe("RecontactOptionsCard", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: null, - runOnDate: null, questions: [], endings: [], hiddenFields: { @@ -136,12 +132,10 @@ describe("RecontactOptionsCard", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: 1, displayLimit: null, - runOnDate: null, questions: [], endings: [], hiddenFields: { @@ -191,12 +185,10 @@ describe("RecontactOptionsCard", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displaySome", recontactDays: null, displayLimit: 1, - runOnDate: null, questions: [], endings: [], hiddenFields: { @@ -248,12 +240,10 @@ describe("RecontactOptionsCard", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: null, - runOnDate: null, questions: [], endings: [], hiddenFields: { @@ -312,12 +302,10 @@ describe("RecontactOptionsCard", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: undefined, // Initial displayLimit is undefined - runOnDate: null, questions: [], endings: [], hiddenFields: { diff --git a/apps/web/modules/survey/editor/components/response-options-card.test.tsx b/apps/web/modules/survey/editor/components/response-options-card.test.tsx index 8a4f358aef..7aaf128f4f 100755 --- a/apps/web/modules/survey/editor/components/response-options-card.test.tsx +++ b/apps/web/modules/survey/editor/components/response-options-card.test.tsx @@ -55,30 +55,6 @@ describe("ResponseOptionsCard", () => { expect(collapsibleRoot).toHaveAttribute("data-state", "open"); }); - test("should set runOnDateToggle to true when handleRunOnDateToggle is called and runOnDateToggle is false", async () => { - const localSurvey: TSurvey = { - id: "1", - name: "Test Survey", - type: "link", - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - runOnDate: null, - } as unknown as TSurvey; - - const setLocalSurvey = vi.fn(); - - render( - - ); - - const runOnDateToggle = screen.getByText("environments.surveys.edit.release_survey_on_date"); - await userEvent.click(runOnDateToggle); - - // Check if the switch element is checked after clicking - const runOnDateSwitch = screen.getByRole("switch", { name: /release_survey_on_date/i }); - expect(runOnDateSwitch).toHaveAttribute("data-state", "checked"); - }); - test("should not correct the invalid autoComplete value when it is less than or equal to responseCount after blur", async () => { const localSurvey: TSurvey = { id: "1", diff --git a/apps/web/modules/survey/editor/components/response-options-card.tsx b/apps/web/modules/survey/editor/components/response-options-card.tsx index c23cd54bce..535ae25f4c 100644 --- a/apps/web/modules/survey/editor/components/response-options-card.tsx +++ b/apps/web/modules/survey/editor/components/response-options-card.tsx @@ -3,7 +3,6 @@ import { cn } from "@/lib/cn"; import { AdvancedOptionToggle } from "@/modules/ui/components/advanced-option-toggle"; import { Alert, AlertTitle } from "@/modules/ui/components/alert"; -import { DatePicker } from "@/modules/ui/components/date-picker"; import { Input } from "@/modules/ui/components/input"; import { Label } from "@/modules/ui/components/label"; import { Slider } from "@/modules/ui/components/slider"; @@ -31,8 +30,6 @@ export const ResponseOptionsCard = ({ const { t } = useTranslate(); const [open, setOpen] = useState(localSurvey.type === "link" ? true : false); const autoComplete = localSurvey.autoComplete !== null; - const [runOnDateToggle, setRunOnDateToggle] = useState(false); - const [closeOnDateToggle, setCloseOnDateToggle] = useState(false); const [surveyClosedMessageToggle, setSurveyClosedMessageToggle] = useState(false); const [verifyEmailToggle, setVerifyEmailToggle] = useState(localSurvey.isVerifyEmailEnabled); const [recaptchaToggle, setRecaptchaToggle] = useState(localSurvey.recaptcha?.enabled ?? false); @@ -45,38 +42,12 @@ export const ResponseOptionsCard = ({ subheading: t("environments.surveys.edit.survey_completed_subheading"), }); - const [runOnDate, setRunOnDate] = useState(null); - const [closeOnDate, setCloseOnDate] = useState(null); const [recaptchaThreshold, setRecaptchaThreshold] = useState(localSurvey.recaptcha?.threshold ?? 0); const isPinProtectionEnabled = localSurvey.pin !== null; const [verifyProtectWithPinError, setVerifyProtectWithPinError] = useState(null); - const handleRunOnDateToggle = () => { - if (runOnDateToggle) { - setRunOnDateToggle(false); - if (localSurvey.runOnDate) { - setRunOnDate(null); - setLocalSurvey({ ...localSurvey, runOnDate: null }); - } - } else { - setRunOnDateToggle(true); - } - }; - - const handleCloseOnDateToggle = () => { - if (closeOnDateToggle) { - setCloseOnDateToggle(false); - if (localSurvey.closeOnDate) { - setCloseOnDate(null); - setLocalSurvey({ ...localSurvey, closeOnDate: null }); - } - } else { - setCloseOnDateToggle(true); - } - }; - const handleProtectSurveyWithPinToggle = () => { setLocalSurvey((prevSurvey) => ({ ...prevSurvey, pin: isPinProtectionEnabled ? null : "1234" })); }; @@ -126,18 +97,6 @@ export const ResponseOptionsCard = ({ }); }; - const handleRunOnDateChange = (date: Date) => { - const utcDate = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0)); - setRunOnDate(utcDate); - setLocalSurvey({ ...localSurvey, runOnDate: utcDate ?? null }); - }; - - const handleCloseOnDateChange = (date: Date) => { - const utcDate = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0)); - setCloseOnDate(utcDate); - setLocalSurvey({ ...localSurvey, closeOnDate: utcDate ?? null }); - }; - const handleClosedSurveyMessageChange = ({ heading, subheading, @@ -146,7 +105,6 @@ export const ResponseOptionsCard = ({ subheading?: string; }) => { const message = { - enabled: closeOnDateToggle, heading: heading ?? surveyClosedMessage.heading, subheading: subheading ?? surveyClosedMessage.subheading, }; @@ -167,16 +125,6 @@ export const ResponseOptionsCard = ({ }); setSurveyClosedMessageToggle(true); } - - if (localSurvey.runOnDate) { - setRunOnDate(localSurvey.runOnDate); - setRunOnDateToggle(true); - } - - if (localSurvey.closeOnDate) { - setCloseOnDate(localSurvey.closeOnDate); - setCloseOnDateToggle(true); - } }, [localSurvey, surveyClosedMessage.heading, surveyClosedMessage.subheading]); const toggleAutocomplete = () => { @@ -295,34 +243,6 @@ export const ResponseOptionsCard = ({

- {/* Run Survey on Date */} - -
- -
-
- {/* Close Survey on Date */} - -
- -
-
{/* recaptcha for spam protection */} {isSpamProtectionAllowed && ( diff --git a/apps/web/modules/survey/editor/components/settings-view.test.tsx b/apps/web/modules/survey/editor/components/settings-view.test.tsx index 879278c617..60e158fe0f 100644 --- a/apps/web/modules/survey/editor/components/settings-view.test.tsx +++ b/apps/web/modules/survey/editor/components/settings-view.test.tsx @@ -135,7 +135,6 @@ const baseSurvey = { updatedAt: new Date(), createdBy: null, variables: [], - closeOnDate: null, endings: [], hiddenFields: { enabled: false, fieldIds: [] }, } as unknown as TSurvey; diff --git a/apps/web/modules/survey/editor/components/survey-editor.test.tsx b/apps/web/modules/survey/editor/components/survey-editor.test.tsx index be1afaef7b..8c99b60045 100644 --- a/apps/web/modules/survey/editor/components/survey-editor.test.tsx +++ b/apps/web/modules/survey/editor/components/survey-editor.test.tsx @@ -97,7 +97,6 @@ const mockSurvey = { environmentId: "env1", variables: [], welcomeCard: { enabled: false } as unknown as TSurvey["welcomeCard"], - closeOnDate: null, segment: null, createdBy: null, } as unknown as TSurvey; diff --git a/apps/web/modules/survey/editor/components/survey-menu-bar.test.tsx b/apps/web/modules/survey/editor/components/survey-menu-bar.test.tsx index 7358f036a4..5948b41e07 100644 --- a/apps/web/modules/survey/editor/components/survey-menu-bar.test.tsx +++ b/apps/web/modules/survey/editor/components/survey-menu-bar.test.tsx @@ -3,7 +3,7 @@ import { updateSurveyAction } from "@/modules/survey/editor/actions"; import { SurveyMenuBar } from "@/modules/survey/editor/components/survey-menu-bar"; import { isSurveyValid } from "@/modules/survey/editor/lib/validation"; import { Project } from "@prisma/client"; -import { cleanup, render, screen } from "@testing-library/react"; +import { cleanup, fireEvent, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; import { TSurvey, TSurveyOpenTextQuestion, TSurveyQuestionTypeEnum } from "@formbricks/types/surveys/types"; @@ -71,6 +71,22 @@ vi.mock("@formbricks/i18n-utils/src/utils", () => ({ getLanguageLabel: vi.fn((code) => `Lang(${code})`), })); +vi.mock("@formbricks/types/surveys/types", async () => { + const actual = await vi.importActual("@formbricks/types/surveys/types"); + return { + ...actual, + ZSurvey: { + safeParse: vi.fn(() => ({ success: true })), + }, + ZSurveyEndScreenCard: { + parse: vi.fn((data) => data), + }, + ZSurveyRedirectUrlCard: { + parse: vi.fn((data) => data), + }, + }; +}); + vi.mock("react-hot-toast", () => ({ default: { success: vi.fn(), @@ -91,7 +107,21 @@ vi.mock("lucide-react", async () => { const mockRouter = { back: vi.fn(), push: vi.fn(), + refresh: vi.fn(), }; + +// Mock Next.js router +vi.mock("next/navigation", () => ({ + useRouter: () => mockRouter, +})); + +// Mock Tolgee translate +vi.mock("@tolgee/react", () => ({ + useTranslate: () => ({ + t: (key: string) => key, // Return the key as translation for testing + }), +})); + const mockSetLocalSurvey = vi.fn(); const mockSetActiveId = vi.fn(); const mockSetInvalidQuestions = vi.fn(); @@ -126,8 +156,6 @@ const baseSurvey = { pin: null, segment: null, languages: [], - runOnDate: null, - closeOnDate: null, welcomeCard: { enabled: false } as TSurvey["welcomeCard"], } as unknown as TSurvey; @@ -267,4 +295,129 @@ describe("SurveyMenuBar", () => { expect(saveButton).not.toBeDisabled(); expect(saveCloseButton).not.toBeDisabled(); }); + + test("shows publish button for link surveys", () => { + // For link surveys, publish button shows without audience prompt + const linkSurvey = { ...baseSurvey, type: "link" as const }; + render(); + + expect(screen.getByText("environments.surveys.edit.publish")).toBeInTheDocument(); + }); + + test("handles save with survey validation failure", async () => { + vi.mocked(isSurveyValid).mockReturnValue(false); + + render(); + const saveButton = screen.getByText("common.save").closest("button"); + await userEvent.click(saveButton!); + + expect(mockSetLocalSurvey).not.toHaveBeenCalled(); + + // Reset mock for other tests + vi.mocked(isSurveyValid).mockReturnValue(true); + }); + + test("handles save with update action error", async () => { + vi.mocked(updateSurveyAction).mockResolvedValue({ + serverError: "Something went wrong", + }); + + render(); + const saveButton = screen.getByText("common.save").closest("button"); + await userEvent.click(saveButton!); + + // Should not refresh router on error + expect(mockRouter.refresh).not.toHaveBeenCalled(); + + // Reset mock for other tests + vi.mocked(updateSurveyAction).mockResolvedValue({ data: { ...baseSurvey, updatedAt: new Date() } }); + }); + + test("handles save with thrown exception", async () => { + vi.mocked(updateSurveyAction).mockRejectedValue(new Error("Network error")); + + render(); + const saveButton = screen.getByText("common.save").closest("button"); + await userEvent.click(saveButton!); + + expect(mockRouter.refresh).not.toHaveBeenCalled(); + + // Reset mock for other tests + vi.mocked(updateSurveyAction).mockResolvedValue({ data: { ...baseSurvey, updatedAt: new Date() } }); + }); + + test("handles app survey without triggers", async () => { + const appSurveyNoTriggers = { ...baseSurvey, type: "app" as const, triggers: [] }; + render(); + + const saveButton = screen.getByText("common.save").closest("button"); + await userEvent.click(saveButton!); + + // Should show error and not save when no triggers + expect(mockSetLocalSurvey).not.toHaveBeenCalled(); + }); + + test("handles back without changes", async () => { + render(); + const backButton = screen.getByText("common.back").closest("button"); + await userEvent.click(backButton!); + + expect(mockRouter.back).toHaveBeenCalled(); + expect(screen.queryByTestId("alert-dialog")).not.toBeInTheDocument(); + }); + + test("shows dialog buttons when changes exist", () => { + const changedSurvey = { ...baseSurvey, name: "Changed Name" }; + render(); + + const backButton = screen.getByText("common.back").closest("button"); + fireEvent.click(backButton!); + + // Dialog should be visible with both buttons + expect(screen.getByTestId("alert-dialog")).toBeInTheDocument(); + expect(screen.getByText("common.discard")).toBeInTheDocument(); + }); + + test("discards changes from dialog", async () => { + const changedSurvey = { ...baseSurvey, name: "Changed Name" }; + render(); + + const backButton = screen.getByText("common.back").closest("button"); + await userEvent.click(backButton!); + + const discardButton = screen.getByText("common.discard"); + await userEvent.click(discardButton); + + expect(mockRouter.back).toHaveBeenCalled(); + }); + + test("renders save and close button for published surveys", () => { + const publishedSurvey = { + ...baseSurvey, + status: "inProgress" as const, + triggers: ["trigger1"], // Has triggers so buttons are enabled + } as unknown as TSurvey; + render(); + + expect(screen.getByText("environments.surveys.edit.save_and_close")).toBeInTheDocument(); + }); + + test("sets status to 'inProgress' when publishing survey", async () => { + vi.mocked(isSurveyValid).mockReturnValue(true); + vi.mocked(updateSurveyAction).mockResolvedValue({ data: { ...baseSurvey, status: "inProgress" } }); + + render(); + + const publishButton = screen.getByText("environments.surveys.edit.publish").closest("button"); + await userEvent.click(publishButton!); + + await new Promise((resolve) => setTimeout(resolve, 0)); + + // Verify updateSurveyAction was called with status "inProgress" + expect(updateSurveyAction).toHaveBeenCalledWith({ + ...baseSurvey, + status: "inProgress", + segment: null, + }); + }); }); diff --git a/apps/web/modules/survey/editor/components/survey-menu-bar.tsx b/apps/web/modules/survey/editor/components/survey-menu-bar.tsx index d12d0f147e..4ea37cd1aa 100644 --- a/apps/web/modules/survey/editor/components/survey-menu-bar.tsx +++ b/apps/web/modules/survey/editor/components/survey-menu-bar.tsx @@ -286,7 +286,7 @@ export const SurveyMenuBar = ({ setIsSurveyPublishing(false); return; } - const status = localSurvey.runOnDate ? "scheduled" : "inProgress"; + const status = "inProgress"; const segment = await handleSegmentUpdate(); clearSurveyLocalStorage(); diff --git a/apps/web/modules/survey/editor/components/survey-placement-card.test.tsx b/apps/web/modules/survey/editor/components/survey-placement-card.test.tsx index 8eaba34d63..aee40fee5a 100644 --- a/apps/web/modules/survey/editor/components/survey-placement-card.test.tsx +++ b/apps/web/modules/survey/editor/components/survey-placement-card.test.tsx @@ -63,7 +63,6 @@ const mockSurvey = { hiddenFields: { enabled: false }, segment: null, projectOverwrites: null, // Start with no overwrites - closeOnDate: null, createdBy: null, } as unknown as TSurvey; diff --git a/apps/web/modules/survey/editor/components/survey-variables-card-item.test.tsx b/apps/web/modules/survey/editor/components/survey-variables-card-item.test.tsx index 2d033a76c5..7638cefbca 100644 --- a/apps/web/modules/survey/editor/components/survey-variables-card-item.test.tsx +++ b/apps/web/modules/survey/editor/components/survey-variables-card-item.test.tsx @@ -64,12 +64,10 @@ describe("SurveyVariablesCardItem", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: null, - runOnDate: null, questions: [], endings: [], hiddenFields: { @@ -129,12 +127,10 @@ describe("SurveyVariablesCardItem", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: null, - runOnDate: null, questions: [], endings: [], hiddenFields: { @@ -186,12 +182,10 @@ describe("SurveyVariablesCardItem", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: null, - runOnDate: null, questions: [], endings: [], hiddenFields: { @@ -237,12 +231,10 @@ describe("SurveyVariablesCardItem", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: null, - runOnDate: null, questions: [], endings: [], hiddenFields: { @@ -284,12 +276,10 @@ describe("SurveyVariablesCardItem", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: null, - runOnDate: null, questions: [], endings: [], hiddenFields: { @@ -358,12 +348,10 @@ describe("SurveyVariablesCardItem", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: null, - runOnDate: null, questions: [ { id: "q1WithLogic", @@ -428,12 +416,10 @@ describe("SurveyVariablesCardItem", () => { showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: null, - runOnDate: null, questions: [ { id: "q1", diff --git a/apps/web/modules/survey/editor/components/survey-variables-card.test.tsx b/apps/web/modules/survey/editor/components/survey-variables-card.test.tsx index f2ea79d91f..fb79452ae9 100644 --- a/apps/web/modules/survey/editor/components/survey-variables-card.test.tsx +++ b/apps/web/modules/survey/editor/components/survey-variables-card.test.tsx @@ -50,8 +50,6 @@ const mockSurvey = { environmentId: "env-123", createdBy: null, segment: null, - closeOnDate: null, - runOnDate: null, isVerifyEmailEnabled: false, isSingleResponsePerEmailEnabled: false, recaptcha: null, diff --git a/apps/web/modules/survey/editor/components/when-to-send-card.test.tsx b/apps/web/modules/survey/editor/components/when-to-send-card.test.tsx index 3ca48d3e68..e1781bbd40 100644 --- a/apps/web/modules/survey/editor/components/when-to-send-card.test.tsx +++ b/apps/web/modules/survey/editor/components/when-to-send-card.test.tsx @@ -103,7 +103,6 @@ const mockSurveyAppBase = { singleUse: null, surveyClosedMessage: null, segment: null, - closeOnDate: null, createdAt: new Date(), updatedAt: new Date(), autoComplete: null, diff --git a/apps/web/modules/survey/editor/lib/survey.test.ts b/apps/web/modules/survey/editor/lib/survey.test.ts index 405c9b8680..7169f53656 100644 --- a/apps/web/modules/survey/editor/lib/survey.test.ts +++ b/apps/web/modules/survey/editor/lib/survey.test.ts @@ -89,8 +89,6 @@ describe("Survey Editor Library Tests", () => { hiddenFields: { enabled: false }, delay: 0, autoComplete: null, - closeOnDate: null, - runOnDate: null, projectOverwrites: null, styling: null, showLanguageSwitch: false, @@ -431,45 +429,6 @@ describe("Survey Editor Library Tests", () => { }); }); - test("should handle scheduled status based on runOnDate", async () => { - const tomorrow = new Date(); - tomorrow.setDate(tomorrow.getDate() + 1); - - const updatedSurvey: TSurvey = { - ...mockSurvey, - status: "completed", - runOnDate: tomorrow, - }; - - await updateSurvey(updatedSurvey); - - expect(prisma.survey.update).toHaveBeenCalledWith({ - where: { id: "survey123" }, - data: expect.objectContaining({ - status: "scheduled", // Should be changed to scheduled because runOnDate is in the future - }), - select: expect.any(Object), - }); - }); - - test("should remove scheduled status when runOnDate is not set", async () => { - const updatedSurvey: TSurvey = { - ...mockSurvey, - status: "scheduled", - runOnDate: null, - }; - - await updateSurvey(updatedSurvey); - - expect(prisma.survey.update).toHaveBeenCalledWith({ - where: { id: "survey123" }, - data: expect.objectContaining({ - status: "inProgress", // Should be changed to inProgress because runOnDate is null - }), - select: expect.any(Object), - }); - }); - test("should throw ResourceNotFoundError when survey is not found", async () => { vi.mocked(getSurvey).mockResolvedValueOnce(null as unknown as TSurvey); diff --git a/apps/web/modules/survey/editor/lib/survey.ts b/apps/web/modules/survey/editor/lib/survey.ts index 24577d0d75..fbe3e8066d 100644 --- a/apps/web/modules/survey/editor/lib/survey.ts +++ b/apps/web/modules/survey/editor/lib/survey.ts @@ -248,19 +248,6 @@ export const updateSurvey = async (updatedSurvey: TSurvey): Promise => type, }; - // Remove scheduled status when runOnDate is not set - if (data.status === "scheduled" && data.runOnDate === null) { - data.status = "inProgress"; - } - // Set scheduled status when runOnDate is set and in the future on completed surveys - if ( - (data.status === "completed" || data.status === "paused" || data.status === "inProgress") && - data.runOnDate && - data.runOnDate > new Date() - ) { - data.status = "scheduled"; - } - delete data.createdBy; const prismaSurvey = await prisma.survey.update({ where: { id: surveyId }, diff --git a/apps/web/modules/survey/editor/lib/utils.test.tsx b/apps/web/modules/survey/editor/lib/utils.test.tsx index fb229ff178..058d44c327 100644 --- a/apps/web/modules/survey/editor/lib/utils.test.tsx +++ b/apps/web/modules/survey/editor/lib/utils.test.tsx @@ -214,12 +214,10 @@ const createMockSurvey = (): TSurvey => showResponseCount: false, }, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", recontactDays: null, displayLimit: null, - runOnDate: null, thankYouCard: { enabled: true, title: { default: "Thank you" }, diff --git a/apps/web/modules/survey/editor/lib/validation.test.ts b/apps/web/modules/survey/editor/lib/validation.test.ts index 987f9a34ea..29d0a64946 100644 --- a/apps/web/modules/survey/editor/lib/validation.test.ts +++ b/apps/web/modules/survey/editor/lib/validation.test.ts @@ -486,11 +486,9 @@ describe("validation.isSurveyValid", () => { triggers: [], recontactDays: null, autoClose: null, - closeOnDate: null, delay: 0, displayOption: "displayOnce", displayLimit: null, - runOnDate: null, thankYouCard: { enabled: true, title: { default: "Thank you" } }, // Minimal for type check createdAt: new Date(), updatedAt: new Date(), diff --git a/apps/web/modules/survey/lib/survey.ts b/apps/web/modules/survey/lib/survey.ts index 691c10eb6d..486e87ad89 100644 --- a/apps/web/modules/survey/lib/survey.ts +++ b/apps/web/modules/survey/lib/survey.ts @@ -23,8 +23,6 @@ export const selectSurvey = { recontactDays: true, displayLimit: true, autoClose: true, - runOnDate: true, - closeOnDate: true, delay: true, displayPercentage: true, autoComplete: true, diff --git a/apps/web/modules/survey/link/components/survey-inactive.test.tsx b/apps/web/modules/survey/link/components/survey-inactive.test.tsx index 7a74713eaa..e3fd012a9c 100644 --- a/apps/web/modules/survey/link/components/survey-inactive.test.tsx +++ b/apps/web/modules/survey/link/components/survey-inactive.test.tsx @@ -121,15 +121,6 @@ describe("SurveyInactive", () => { expect(screen.getByTestId("mock-image")).toBeInTheDocument(); }); - test("renders scheduled status correctly", async () => { - const Component = await SurveyInactive({ status: "scheduled" }); - render(Component); - - expect(screen.getByText("common.survey scheduled.")).toBeInTheDocument(); - expect(screen.getByTestId("button")).toBeInTheDocument(); - expect(screen.getByTestId("mock-image")).toBeInTheDocument(); - }); - test("shows branding when linkSurveyBranding is true", async () => { const Component = await SurveyInactive({ status: "paused", project: { linkSurveyBranding: true } }); render(Component); diff --git a/apps/web/modules/survey/link/components/survey-inactive.tsx b/apps/web/modules/survey/link/components/survey-inactive.tsx index 012c2b7d8a..695e1eedaa 100644 --- a/apps/web/modules/survey/link/components/survey-inactive.tsx +++ b/apps/web/modules/survey/link/components/survey-inactive.tsx @@ -12,7 +12,7 @@ export const SurveyInactive = async ({ surveyClosedMessage, project, }: { - status: "paused" | "completed" | "link invalid" | "scheduled" | "response submitted" | "link expired"; + status: "paused" | "completed" | "link invalid" | "response submitted" | "link expired"; surveyClosedMessage?: TSurveyClosedMessage | null; project?: Pick; }) => { diff --git a/apps/web/modules/survey/link/lib/data.test.ts b/apps/web/modules/survey/link/lib/data.test.ts index c8dd446810..416b414149 100644 --- a/apps/web/modules/survey/link/lib/data.test.ts +++ b/apps/web/modules/survey/link/lib/data.test.ts @@ -90,8 +90,6 @@ describe("data", () => { recontactDays: null, displayLimit: null, autoClose: null, - runOnDate: null, - closeOnDate: null, delay: 0, displayPercentage: null, autoComplete: null, @@ -216,8 +214,6 @@ describe("data", () => { recontactDays: null, displayLimit: null, autoClose: null, - runOnDate: null, - closeOnDate: null, delay: 0, displayPercentage: null, autoComplete: null, diff --git a/apps/web/modules/survey/link/lib/data.ts b/apps/web/modules/survey/link/lib/data.ts index 798db7ffe3..d370669c0f 100644 --- a/apps/web/modules/survey/link/lib/data.ts +++ b/apps/web/modules/survey/link/lib/data.ts @@ -37,8 +37,6 @@ export const getSurveyWithMetadata = reactCache(async (surveyId: string) => { recontactDays: true, displayLimit: true, autoClose: true, - runOnDate: true, - closeOnDate: true, delay: true, displayPercentage: true, autoComplete: true, diff --git a/apps/web/modules/survey/list/components/survey-card.tsx b/apps/web/modules/survey/list/components/survey-card.tsx index 126ad85e2d..77171feacb 100644 --- a/apps/web/modules/survey/list/components/survey-card.tsx +++ b/apps/web/modules/survey/list/components/survey-card.tsx @@ -35,8 +35,6 @@ export const SurveyCard = ({ switch (survey.status) { case "inProgress": return t("common.in_progress"); - case "scheduled": - return t("common.scheduled"); case "completed": return t("common.completed"); case "draft": @@ -73,7 +71,6 @@ export const SurveyCard = ({
[ ]; const getStatusOptions = (t: TFnType): TFilterOption[] => [ - { label: t("common.scheduled"), value: "scheduled" }, { label: t("common.paused"), value: "paused" }, { label: t("common.completed"), value: "completed" }, { label: t("common.draft"), value: "draft" }, @@ -86,13 +85,7 @@ export const SurveyFilters = ({ }; const handleStatusChange = (value: string) => { - if ( - value === "inProgress" || - value === "paused" || - value === "completed" || - value === "draft" || - value === "scheduled" - ) { + if (value === "inProgress" || value === "paused" || value === "completed" || value === "draft") { if (status.includes(value)) { setSurveyFilters((prev) => ({ ...prev, status: prev.status.filter((v) => v !== value) })); } else { diff --git a/apps/web/modules/survey/templates/lib/minimal-survey.ts b/apps/web/modules/survey/templates/lib/minimal-survey.ts index fc80c38ac3..2d3a67a70b 100644 --- a/apps/web/modules/survey/templates/lib/minimal-survey.ts +++ b/apps/web/modules/survey/templates/lib/minimal-survey.ts @@ -25,8 +25,6 @@ export const getMinimalSurvey = (t: TFnType): TSurvey => ({ delay: 0, // No delay displayPercentage: null, autoComplete: null, - runOnDate: null, - closeOnDate: null, surveyClosedMessage: { enabled: false, }, diff --git a/apps/web/modules/ui/components/question-toggle-table/index.test.tsx b/apps/web/modules/ui/components/question-toggle-table/index.test.tsx index 6d5522f689..6e91fa7be4 100644 --- a/apps/web/modules/ui/components/question-toggle-table/index.test.tsx +++ b/apps/web/modules/ui/components/question-toggle-table/index.test.tsx @@ -110,7 +110,6 @@ describe("QuestionToggleTable", () => { }, styling: {}, autoComplete: false, - closeOnDate: null, recaptcha: { enabled: false, }, diff --git a/apps/web/modules/ui/components/survey-status-indicator/index.test.tsx b/apps/web/modules/ui/components/survey-status-indicator/index.test.tsx index 4ce385f8fd..0146931dd7 100644 --- a/apps/web/modules/ui/components/survey-status-indicator/index.test.tsx +++ b/apps/web/modules/ui/components/survey-status-indicator/index.test.tsx @@ -31,7 +31,6 @@ vi.mock("@tolgee/react", () => ({ t: (key: string) => { const translations: Record = { "common.gathering_responses": "Gathering responses", - "common.survey_scheduled": "Survey scheduled", "common.survey_paused": "Survey paused", "common.survey_completed": "Survey completed", }; @@ -63,21 +62,6 @@ describe("SurveyStatusIndicator", () => { expect(screen.queryByTestId("tooltip-provider")).not.toBeInTheDocument(); }); - test("renders scheduled status correctly without tooltip", () => { - const { container } = render(); - - // Find the clock icon container - const clockIconContainer = container.querySelector(".rounded-full.bg-slate-300.p-1"); - expect(clockIconContainer).toBeInTheDocument(); - - // Find the clock icon inside - const clockIcon = clockIconContainer?.querySelector("[data-testid='clock-icon']"); - expect(clockIcon).toBeInTheDocument(); - - // Should not render tooltip components - expect(screen.queryByTestId("tooltip-provider")).not.toBeInTheDocument(); - }); - test("renders paused status correctly without tooltip", () => { const { container } = render(); @@ -137,16 +121,6 @@ describe("SurveyStatusIndicator", () => { expect(tooltipContent).toHaveTextContent("Gathering responses"); }); - test("renders scheduled status with tooltip correctly", () => { - const { container } = render(); - - expect(screen.getByTestId("tooltip-content")).toHaveTextContent("Survey scheduled"); - - // Use container query to find the first clock icon - const clockIcon = container.querySelector("[data-testid='clock-icon']"); - expect(clockIcon).toBeInTheDocument(); - }); - test("renders paused status with tooltip correctly", () => { const { container } = render(); diff --git a/apps/web/modules/ui/components/survey-status-indicator/index.tsx b/apps/web/modules/ui/components/survey-status-indicator/index.tsx index 3222294d05..c522eb0878 100644 --- a/apps/web/modules/ui/components/survey-status-indicator/index.tsx +++ b/apps/web/modules/ui/components/survey-status-indicator/index.tsx @@ -2,7 +2,7 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/modules/ui/components/tooltip"; import { useTranslate } from "@tolgee/react"; -import { CheckIcon, ClockIcon, PauseIcon, PencilIcon } from "lucide-react"; +import { CheckIcon, PauseIcon, PencilIcon } from "lucide-react"; import { TSurvey } from "@formbricks/types/surveys/types"; interface SurveyStatusIndicatorProps { @@ -23,11 +23,6 @@ export const SurveyStatusIndicator = ({ status, tooltip }: SurveyStatusIndicator )} - {status === "scheduled" && ( -
- -
- )} {status === "paused" && (
@@ -54,13 +49,6 @@ export const SurveyStatusIndicator = ({ status, tooltip }: SurveyStatusIndicator - ) : status === "scheduled" ? ( - <> - {t("common.survey_scheduled")} -
- -
- ) : status === "paused" ? ( <> {t("common.survey_paused")} @@ -90,11 +78,6 @@ export const SurveyStatusIndicator = ({ status, tooltip }: SurveyStatusIndicator )} - {status === "scheduled" && ( -
- -
- )} {status === "paused" && (
diff --git a/apps/web/scripts/docker/next-start.sh b/apps/web/scripts/docker/next-start.sh index 9e40e7a260..d2e29be1ad 100755 --- a/apps/web/scripts/docker/next-start.sh +++ b/apps/web/scripts/docker/next-start.sh @@ -46,13 +46,6 @@ run_with_timeout() { fi } -# Start cron jobs if enabled -if [ "${DOCKER_CRON_ENABLED:-1}" = "1" ]; then - echo "Starting cron jobs..."; - supercronic -quiet /app/docker/cronjobs & -else - echo "Docker cron jobs are disabled via DOCKER_CRON_ENABLED=0"; -fi echo "🗃️ Running database migrations..." run_with_timeout 600 "database migration" sh -c '(cd packages/database && npm run db:migrate:deploy)' diff --git a/docker/cronjobs b/docker/cronjobs deleted file mode 100644 index e118a434e7..0000000000 --- a/docker/cronjobs +++ /dev/null @@ -1,3 +0,0 @@ -0 0 * * * curl $WEBAPP_URL/api/cron/survey-status -X POST -H 'content-type: application/json' -H 'x-api-key: '"$CRON_SECRET"'' - -0 9 * * * curl $WEBAPP_URL/api/cron/ping -X POST -H 'content-type: application/json' -H 'x-api-key: '"$CRON_SECRET"'' diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 005726cc20..5f47ad3f31 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -72,9 +72,6 @@ x-environment: &environment # Set the below to your Unsplash API Key for their Survey Backgrounds # UNSPLASH_ACCESS_KEY: - # Set the below to 0 to disable cron jobs - # DOCKER_CRON_ENABLED: 1 - # Set the below to your public domain (default is WEBAPP_URL) # PUBLIC_URL: @@ -183,8 +180,8 @@ x-environment: &environment ########################################## OPTIONAL (AUDIT LOGGING) ########################################### - # Set the below to 1 to enable audit logging. - # AUDIT_LOG_ENABLED: 1 + # Set the below to 1 to enable audit logging. + # AUDIT_LOG_ENABLED: 1 # Set the below to get the ip address of the user from the request headers # AUDIT_LOG_GET_USER_IP: 1 diff --git a/docker/formbricks.sh b/docker/formbricks.sh index 1499ea7c88..10db66cb1a 100755 --- a/docker/formbricks.sh +++ b/docker/formbricks.sh @@ -268,9 +268,9 @@ EOT encryption_key=$(openssl rand -hex 32) && sed -i "/ENCRYPTION_KEY:$/s/ENCRYPTION_KEY:.*/ENCRYPTION_KEY: $encryption_key/" docker-compose.yml echo "🚗 ENCRYPTION_KEY updated successfully!" - cron_secret=$(openssl rand -hex 32) && sed -i "/CRON_SECRET:$/s/CRON_SECRET:.*/CRON_SECRET: $cron_secret/" docker-compose.yml + cron_secret=$(openssl rand -hex 32) && sed -i "/CRON_SECRET:$/s/CRON_SECRET:.*/CRON_SECRET: $cron_secret/" docker-compose.yml echo "🚗 CRON_SECRET updated successfully!" - + if [[ -n $mail_from ]]; then sed -i "s|# MAIL_FROM:|MAIL_FROM: \"$mail_from\"|" docker-compose.yml sed -i "s|# MAIL_FROM_NAME:|MAIL_FROM_NAME: \"$mail_from_name\"|" docker-compose.yml diff --git a/docs/api-reference/openapi.json b/docs/api-reference/openapi.json index b841fe8f10..7e45c946b4 100644 --- a/docs/api-reference/openapi.json +++ b/docs/api-reference/openapi.json @@ -6033,7 +6033,6 @@ { "autoClose": null, "autoComplete": null, - "closeOnDate": null, "createdAt": "2024-08-05T11:08:27.042Z", "createdBy": "clfv1zvij0000ru0gunwpy43a", "delay": 0, @@ -6115,7 +6114,6 @@ ], "recontactDays": null, "redirectUrl": null, - "runOnDate": null, "segment": null, "showLanguageSwitch": null, "singleUse": { @@ -6218,7 +6216,6 @@ "example": { "autoClose": null, "autoComplete": null, - "closeOnDate": null, "createdBy": null, "delay": 0, "displayLimit": null, @@ -6298,7 +6295,6 @@ ], "recontactDays": null, "redirectUrl": null, - "runOnDate": null, "segmentId": null, "showLanguageSwitch": null, "singleUse": { @@ -6336,7 +6332,6 @@ "data": { "autoClose": null, "autoComplete": null, - "closeOnDate": null, "createdAt": "2024-08-05T11:08:27.042Z", "createdBy": "clfv1zvij0000ru0gunwpy43a", "delay": 0, @@ -6418,7 +6413,6 @@ ], "recontactDays": null, "redirectUrl": null, - "runOnDate": null, "segment": null, "showLanguageSwitch": null, "singleUse": { @@ -6604,7 +6598,6 @@ "data": { "autoClose": null, "autoComplete": null, - "closeOnDate": null, "createdAt": "2024-08-05T11:08:27.042Z", "createdBy": "clfv1zvij0000ru0gunwpy43a", "delay": 0, @@ -6686,7 +6679,6 @@ ], "recontactDays": null, "redirectUrl": null, - "runOnDate": null, "segment": null, "showLanguageSwitch": null, "singleUse": { @@ -6859,7 +6851,6 @@ "data": { "autoClose": null, "autoComplete": null, - "closeOnDate": null, "createdAt": "2024-08-05T11:08:27.042Z", "createdBy": "clfv1zvij0000ru0gunwpy43a", "delay": 0, @@ -6941,7 +6932,6 @@ ], "recontactDays": null, "redirectUrl": null, - "runOnDate": null, "segment": null, "showLanguageSwitch": null, "singleUse": { @@ -7064,7 +7054,6 @@ "data": { "autoClose": null, "autoComplete": null, - "closeOnDate": null, "createdAt": "2024-08-05T11:08:27.042Z", "createdBy": "clfv1zvij0000ru0gunwpy43a", "delay": 0, @@ -7146,7 +7135,6 @@ ], "recontactDays": null, "redirectUrl": null, - "runOnDate": null, "segment": null, "showLanguageSwitch": null, "singleUse": { diff --git a/docs/api-v2-reference/openapi.yml b/docs/api-v2-reference/openapi.yml index b38a8f30db..10207a8fe7 100644 --- a/docs/api-v2-reference/openapi.yml +++ b/docs/api-v2-reference/openapi.yml @@ -3982,7 +3982,6 @@ components: type: string enum: - draft - - scheduled - inProgress - paused - completed @@ -4193,16 +4192,6 @@ components: delay: type: number description: Delay before showing survey - runOnDate: - type: - - string - - "null" - description: Date to run the survey - closeOnDate: - type: - - string - - "null" - description: Date to close the survey surveyClosedMessage: type: - object @@ -4514,8 +4503,6 @@ components: - autoClose - autoComplete - delay - - runOnDate - - closeOnDate - surveyClosedMessage - segmentId - projectOverwrites diff --git a/docs/development/local-setup/github-codespaces.mdx b/docs/development/local-setup/github-codespaces.mdx index 5a25415bcf..41bc0751ab 100644 --- a/docs/development/local-setup/github-codespaces.mdx +++ b/docs/development/local-setup/github-codespaces.mdx @@ -6,9 +6,7 @@ icon: "github" ### GitHub Codespaces Setup - - This guide outlines how to set up Formbricks in a **GitHub Codespaces** environment. - +This guide outlines how to set up Formbricks in a **GitHub Codespaces** environment. **Requirements:** @@ -17,39 +15,42 @@ icon: "github" **Steps:** 1. **Open your repository in GitHub Codespaces. If needed, clone the repository:** - ```bash - git clone https://github.com/formbricks/formbricks && cd formbricks - ``` + + ```bash + git clone https://github.com/formbricks/formbricks && cd formbricks + ``` 2. **Setup NodeJS with nvm (if not already configured):** - ```bash - nvm install && nvm use - ``` + + ```bash + nvm install && nvm use + ``` 3. **Install the dependencies:** - ```bash - pnpm install - ``` + + ```bash + pnpm install + ``` 4. **Create a `.env` file from the template:** - ```bash - cp .env.example .env - ``` + + ```bash + cp .env.example .env + ``` 5. **Generate & set the required secrets:** - ```bash - sed -i '/^ENCRYPTION_KEY=/c\ENCRYPTION_KEY='$(openssl rand -hex 32) .env - sed -i '/^NEXTAUTH_SECRET=/c\NEXTAUTH_SECRET='$(openssl rand -hex 32) .env - sed -i '/^CRON_SECRET=/c\CRON_SECRET='$(openssl rand -hex 32) .env - ``` + + ```bash + sed -i '/^ENCRYPTION_KEY=/c\ENCRYPTION_KEY='$(openssl rand -hex 32) .env + sed -i '/^NEXTAUTH_SECRET=/c\NEXTAUTH_SECRET='$(openssl rand -hex 32) .env + sed -i '/^CRON_SECRET=/c\CRON_SECRET='$(openssl rand -hex 32) .env + ``` 6. **Launch the development setup:** - ```bash - pnpm go - ``` + ```bash + pnpm go + ``` Use the Codespaces port forwarding to access Formbricks at [http://localhost:3000](http://localhost:3000). - - Make sure your Codespaces port configuration is set to allow access to the app. - \ No newline at end of file +Make sure your Codespaces port configuration is set to allow access to the app. diff --git a/docs/development/local-setup/gitpod.mdx b/docs/development/local-setup/gitpod.mdx index fec0f4fa63..d633b1a823 100644 --- a/docs/development/local-setup/gitpod.mdx +++ b/docs/development/local-setup/gitpod.mdx @@ -6,9 +6,7 @@ icon: "code" ### Gitpod Setup - - This guide explains how to set up Formbricks in a **Gitpod** workspace. - +This guide explains how to set up Formbricks in a **Gitpod** workspace. **Requirements:** @@ -17,39 +15,42 @@ icon: "code" **Steps:** 1. **Open the repository in Gitpod. The workspace typically clones the repo automatically. If not:** - ```bash - git clone https://github.com/formbricks/formbricks && cd formbricks - ``` + + ```bash + git clone https://github.com/formbricks/formbricks && cd formbricks + ``` 2. **Setup NodeJS with nvm:** - ```bash - nvm install && nvm use - ``` + + ```bash + nvm install && nvm use + ``` 3. **Install dependencies:** - ```bash - pnpm install - ``` + + ```bash + pnpm install + ``` 4. **Create a `.env` file:** - ```bash - cp .env.example .env - ``` + + ```bash + cp .env.example .env + ``` 5. **Generate & set secret values:** - ```bash - sed -i '/^ENCRYPTION_KEY=/c\ENCRYPTION_KEY='$(openssl rand -hex 32) .env - sed -i '/^NEXTAUTH_SECRET=/c\NEXTAUTH_SECRET='$(openssl rand -hex 32) .env - sed -i '/^CRON_SECRET=/c\CRON_SECRET='$(openssl rand -hex 32) .env - ``` + + ```bash + sed -i '/^ENCRYPTION_KEY=/c\ENCRYPTION_KEY='$(openssl rand -hex 32) .env + sed -i '/^NEXTAUTH_SECRET=/c\NEXTAUTH_SECRET='$(openssl rand -hex 32) .env + sed -i '/^CRON_SECRET=/c\CRON_SECRET='$(openssl rand -hex 32) .env + ``` 6. **Run the development setup:** - ```bash - pnpm go - ``` + ```bash + pnpm go + ``` Access the running app via the forwarded port (typically [http://localhost:3000](http://localhost:3000) inside Gitpod). - - Check your Gitpod settings to ensure Docker is enabled if required. - \ No newline at end of file +Check your Gitpod settings to ensure Docker is enabled if required. diff --git a/docs/development/local-setup/linux.mdx b/docs/development/local-setup/linux.mdx index 5cf559c8ff..6dc96f2e95 100644 --- a/docs/development/local-setup/linux.mdx +++ b/docs/development/local-setup/linux.mdx @@ -6,9 +6,7 @@ icon: "linux" ### Local Machine Setup - Linux - - This guide is recommended for advanced users setting up Formbricks on a **Linux** machine. - +This guide is recommended for advanced users setting up Formbricks on a **Linux** machine. Here are the requirements for setting up Formbricks on Linux: @@ -19,39 +17,42 @@ Here are the requirements for setting up Formbricks on Linux: **Steps:** 1. **Clone the project & move into the directory:** - ```bash - git clone https://github.com/formbricks/formbricks && cd formbricks - ``` + + ```bash + git clone https://github.com/formbricks/formbricks && cd formbricks + ``` 2. **Setup NodeJS with nvm:** - ```bash - nvm install && nvm use - ``` + + ```bash + nvm install && nvm use + ``` 3. **Install NodeJS packages via pnpm:** - ```bash - pnpm install - ``` + + ```bash + pnpm install + ``` 4. **Create a `.env` file based on `.env.example`:** - ```bash - cp .env.example .env - ``` + + ```bash + cp .env.example .env + ``` 5. **Generate & set the secret values:** - ```bash - sed -i '/^ENCRYPTION_KEY=/c\ENCRYPTION_KEY='$(openssl rand -hex 32) .env - sed -i '/^NEXTAUTH_SECRET=/c\NEXTAUTH_SECRET='$(openssl rand -hex 32) .env - sed -i '/^CRON_SECRET=/c\CRON_SECRET='$(openssl rand -hex 32) .env - ``` + + ```bash + sed -i '/^ENCRYPTION_KEY=/c\ENCRYPTION_KEY='$(openssl rand -hex 32) .env + sed -i '/^NEXTAUTH_SECRET=/c\NEXTAUTH_SECRET='$(openssl rand -hex 32) .env + sed -i '/^CRON_SECRET=/c\CRON_SECRET='$(openssl rand -hex 32) .env + ``` 6. **Start the development setup:** - ```bash - pnpm go - ``` + ```bash + pnpm go + ``` You can now access Formbricks at [http://localhost:3000](http://localhost:3000). - - Create a new account on first login as no default account is available. - \ No newline at end of file +Create a new account on first login as no default account is available. diff --git a/docs/development/local-setup/mac.mdx b/docs/development/local-setup/mac.mdx index 8c9e33e382..352e40168d 100644 --- a/docs/development/local-setup/mac.mdx +++ b/docs/development/local-setup/mac.mdx @@ -6,9 +6,7 @@ icon: "apple" ### Local Machine Setup - Mac - - This guide is recommended for advanced users setting up Formbricks on a **Mac** machine. - +This guide is recommended for advanced users setting up Formbricks on a **Mac** machine. **Requirements:** @@ -19,39 +17,42 @@ icon: "apple" **Steps:** 1. **Clone the project & change directory:** - ```bash - git clone https://github.com/formbricks/formbricks && cd formbricks - ``` + + ```bash + git clone https://github.com/formbricks/formbricks && cd formbricks + ``` 2. **Setup NodeJS with nvm:** - ```bash - nvm install && nvm use - ``` + + ```bash + nvm install && nvm use + ``` 3. **Install NodeJS packages with pnpm:** - ```bash - pnpm install - ``` + + ```bash + pnpm install + ``` 4. **Create a `.env` file from the example:** - ```bash - cp .env.example .env - ``` + + ```bash + cp .env.example .env + ``` 5. **Generate & set secret values (using BSD sed syntax for macOS):** - ```bash - sed -i '' '/^ENCRYPTION_KEY=/s|.*|ENCRYPTION_KEY='$(openssl rand -hex 32)'|' .env - sed -i '' '/^NEXTAUTH_SECRET=/s|.*|NEXTAUTH_SECRET='$(openssl rand -hex 32)'|' .env - sed -i '' '/^CRON_SECRET=/s|.*|CRON_SECRET='$(openssl rand -hex 32)'|' .env - ``` + + ```bash + sed -i '' '/^ENCRYPTION_KEY=/s|.*|ENCRYPTION_KEY='$(openssl rand -hex 32)'|' .env + sed -i '' '/^NEXTAUTH_SECRET=/s|.*|NEXTAUTH_SECRET='$(openssl rand -hex 32)'|' .env + sed -i '' '/^CRON_SECRET=/s|.*|CRON_SECRET='$(openssl rand -hex 32)'|' .env + ``` 6. **Start the development setup:** - ```bash - pnpm go - ``` + ```bash + pnpm go + ``` Visit [http://localhost:3000](http://localhost:3000) to access Formbricks. - - Ensure you create a new account at first login. - \ No newline at end of file +Ensure you create a new account at first login. diff --git a/docs/development/local-setup/windows.mdx b/docs/development/local-setup/windows.mdx index 44b085292c..b7c38334f4 100644 --- a/docs/development/local-setup/windows.mdx +++ b/docs/development/local-setup/windows.mdx @@ -7,7 +7,8 @@ icon: "windows" ### Local Machine Setup - Windows - This guide is intended for **Windows** users. For the best experience, use **WSL2** since pure Windows is not fully supported. + This guide is intended for **Windows** users. For the best experience, use **WSL2** since pure Windows is + not fully supported. **Requirements:** @@ -19,39 +20,43 @@ icon: "windows" **Steps (Using WSL2):** 1. **Open your WSL2 terminal and clone the project:** - ```bash - git clone https://github.com/formbricks/formbricks && cd formbricks - ``` + + ```bash + git clone https://github.com/formbricks/formbricks && cd formbricks + ``` 2. **Setup NodeJS with nvm in WSL2:** - ```bash - nvm install && nvm use - ``` + + ```bash + nvm install && nvm use + ``` 3. **Install packages using pnpm:** - ```bash - pnpm install - ``` + + ```bash + pnpm install + ``` 4. **Create a `.env` file:** - ```bash - cp .env.example .env - ``` + + ```bash + cp .env.example .env + ``` 5. **Generate & set secret values (Linux commands work in WSL2):** - ```bash - sed -i '/^ENCRYPTION_KEY=/c\ENCRYPTION_KEY='$(openssl rand -hex 32) .env - sed -i '/^NEXTAUTH_SECRET=/c\NEXTAUTH_SECRET='$(openssl rand -hex 32) .env - sed -i '/^CRON_SECRET=/c\CRON_SECRET='$(openssl rand -hex 32) .env - ``` + + ```bash + sed -i '/^ENCRYPTION_KEY=/c\ENCRYPTION_KEY='$(openssl rand -hex 32) .env + sed -i '/^NEXTAUTH_SECRET=/c\NEXTAUTH_SECRET='$(openssl rand -hex 32) .env + sed -i '/^CRON_SECRET=/c\CRON_SECRET='$(openssl rand -hex 32) .env + + ``` 6. **Start the development setup:** - ```bash - pnpm go - ``` + ```bash + pnpm go + ``` Access Formbricks at [http://localhost:3000](http://localhost:3000). - - If you run into conflicts, ensure any local services (like PostgreSQL) are stopped. - \ No newline at end of file +If you run into conflicts, ensure any local services (like PostgreSQL) are stopped. diff --git a/docs/self-hosting/configuration/environment-variables.mdx b/docs/self-hosting/configuration/environment-variables.mdx index 69707ce230..7a4f5ae50c 100644 --- a/docs/self-hosting/configuration/environment-variables.mdx +++ b/docs/self-hosting/configuration/environment-variables.mdx @@ -64,7 +64,6 @@ These variables are present inside your machine's docker-compose file. Restart t | OPENTELEMETRY_LISTENER_URL | URL for OpenTelemetry listener inside Formbricks. | optional | | | PROMETHEUS_ENABLED | Enables Prometheus metrics if set to 1. | optional | | | PROMETHEUS_EXPORTER_PORT | Port for Prometheus metrics. | optional | 9090 | -| DOCKER_CRON_ENABLED | Controls whether cron jobs run in the Docker image. Set to 0 to disable (useful for cluster setups). | optional | 1 | | DEFAULT_TEAM_ID | Default team ID for new users. | optional | | | SENTRY_DSN | Set this to track errors and monitor performance in Sentry. | optional | | | SENTRY_ENVIRONMENT | Set this to identify the environment in Sentry | optional | | diff --git a/docs/self-hosting/setup/cluster-setup.mdx b/docs/self-hosting/setup/cluster-setup.mdx index 73d4b6244d..32e2dfddb9 100644 --- a/docs/self-hosting/setup/cluster-setup.mdx +++ b/docs/self-hosting/setup/cluster-setup.mdx @@ -155,19 +155,6 @@ When using S3 in a cluster setup, ensure that: - The bucket has appropriate CORS settings configured - IAM roles/users have sufficient permissions for read/write operations -## Disabling Docker Cron Jobs - -When running Formbricks in a cluster setup, you should disable the built-in cron jobs in the Docker image to prevent them from running on multiple instances simultaneously. Instead, you should set up cron jobs in your orchestration system (like Kubernetes) to run on a single instance or as separate jobs. - -To disable the Docker cron jobs, set the following environment variable: - -```sh env -# Disable Docker cron jobs (0 = disabled, 1 = enabled) -DOCKER_CRON_ENABLED=0 -``` - -This will prevent the cron jobs from starting in the Docker container while still allowing all other Formbricks functionality to work normally. - ## Kubernetes Setup Formbricks provides an official Helm chart for deploying the entire cluster stack on Kubernetes. The Helm chart is available in the [Formbricks GitHub repository](https://github.com/formbricks/formbricks/tree/main/helm-chart). diff --git a/docs/self-hosting/setup/docker.mdx b/docs/self-hosting/setup/docker.mdx index 78076a02b0..70bdf8ddfb 100644 --- a/docs/self-hosting/setup/docker.mdx +++ b/docs/self-hosting/setup/docker.mdx @@ -64,21 +64,21 @@ Make sure Docker and Docker Compose are installed on your system. These are usua sed -i '' "s/ENCRYPTION_KEY:.*/ENCRYPTION_KEY: $(openssl rand -hex 32)/" docker-compose.yml ``` -1. **Generate Cron Secret** +1. **Generate Cron Secret** - You require a Cron secret to secure API access for running cron jobs. Run one of the commands below based on your operating system: + You require a Cron secret to secure API access for running cron jobs. Run one of the commands below based on your operating system: - For Linux: + For Linux: - ```bash - sed -i "/CRON_SECRET:$/s/CRON_SECRET:.*/CRON_SECRET: $(openssl rand -hex 32)/" docker-compose.yml - ``` + ```bash + sed -i "/CRON_SECRET:$/s/CRON_SECRET:.*/CRON_SECRET: $(openssl rand -hex 32)/" docker-compose.yml + ``` - For macOS: + For macOS: - ```bash - sed -i '' "s/CRON_SECRET:.*/CRON_SECRET: $(openssl rand -hex 32)/" docker-compose.yml - ``` + ```bash + sed -i '' "s/CRON_SECRET:.*/CRON_SECRET: $(openssl rand -hex 32)/" docker-compose.yml + ``` 1. **Start the Docker Setup** diff --git a/docs/self-hosting/setup/one-click.mdx b/docs/self-hosting/setup/one-click.mdx index 303438b8ba..1123606b41 100644 --- a/docs/self-hosting/setup/one-click.mdx +++ b/docs/self-hosting/setup/one-click.mdx @@ -4,9 +4,7 @@ description: "How to set up Formbricks instance with a one-click script" icon: "rocket" --- - - This only works with an Ubuntu machine, so ensure the underlying OS is verified beforehand! - +This only works with an Ubuntu machine, so ensure the underlying OS is verified beforehand! If you’re looking to quickly set up a production instance of Formbricks on an Ubuntu server, this guide is for you. Using a convenient shell script, you can install everything—including Docker, Postgres DB, and an SSL certificate—in just a few steps. The script takes care of all the dependencies and configuration for your server, making the process smooth and simple. @@ -269,7 +267,7 @@ Y 🚙 Updating docker-compose.yml with your custom inputs... 🚗 NEXTAUTH_SECRET updated successfully! 🚗 ENCRYPTION_KEY updated successfully! -🚗 CRON_SECRET updated successfully! +🚗 CRON_SECRET updated successfully! [+] Running 4/4 ✔ Network formbricks_default Created 0.2s @@ -343,4 +341,4 @@ If you encounter any issues, consider the following steps: * **Check Formbricks Logs**: Run `cd formbricks && docker compose logs` to check the logs of the Formbricks stack. If you have any questions or require help, feel free to reach out to us on [**GitHub Discussions**](https://github.com/formbricks/formbricks/discussions). 😃[ -](https://formbricks.com/docs/developer-docs/rest-api) \ No newline at end of file +](https://formbricks.com/docs/developer-docs/rest-api) diff --git a/helm-chart/templates/NOTES.txt b/helm-chart/templates/NOTES.txt index b409563f5c..cb939a23e4 100644 --- a/helm-chart/templates/NOTES.txt +++ b/helm-chart/templates/NOTES.txt @@ -96,7 +96,7 @@ Retrieve them using: ```sh kubectl get secret --namespace {{ .Release.Namespace }} {{ include "formbricks.name" . }}-app-secrets -o jsonpath="{.data.NEXTAUTH_SECRET}" | base64 --decode kubectl get secret --namespace {{ .Release.Namespace }} {{ include "formbricks.name" . }}-app-secrets -o jsonpath="{.data.ENCRYPTION_KEY}" | base64 --decode -kubectl get secret --namespace {{ .Release.Namespace }} {{ include "formbricks.name" . }}-app-secrets -o jsonpath="{.data.CRON_SECRET}" | base64 --decode +kubectl get secret --namespace {{ .Release.Namespace }} {{ include "formbricks.name" . }}-app-secrets -o jsonpath="{.data.CRON_SECRET}" | base64 --decode ``` --- diff --git a/helm-chart/templates/_helpers.tpl b/helm-chart/templates/_helpers.tpl index bcf06347cc..5366a3e8a0 100644 --- a/helm-chart/templates/_helpers.tpl +++ b/helm-chart/templates/_helpers.tpl @@ -113,13 +113,13 @@ If `namespaceOverride` is provided, it will be used; otherwise, it defaults to ` {{- end -}} {{- end }} -{{- define "formbricks.cronSecret" -}} -{{- $secret := (lookup "v1" "Secret" .Release.Namespace (printf "%s-app-secrets" (include "formbricks.name" .))) }} -{{- if $secret }} - {{- index $secret.data "CRON_SECRET" | b64dec -}} -{{- else }} - {{- randAlphaNum 32 -}} -{{- end -}} +{{- define "formbricks.cronSecret" -}} +{{- $secret := (lookup "v1" "Secret" .Release.Namespace (printf "%s-app-secrets" (include "formbricks.name" .))) }} +{{- if $secret }} + {{- index $secret.data "CRON_SECRET" | b64dec -}} +{{- else }} + {{- randAlphaNum 32 -}} +{{- end -}} {{- end }} {{- define "formbricks.encryptionKey" -}} diff --git a/helm-chart/templates/cronjob.yaml b/helm-chart/templates/cronjob.yaml deleted file mode 100644 index 6c3cbbe46f..0000000000 --- a/helm-chart/templates/cronjob.yaml +++ /dev/null @@ -1,146 +0,0 @@ -{{- if (.Values.cronJob).enabled }} -{{- range $name, $job := .Values.cronJob.jobs }} ---- -{{ if $.Capabilities.APIVersions.Has "batch/v1/CronJob" -}} -apiVersion: batch/v1 -{{- else -}} -apiVersion: batch/v1beta1 -{{- end }} -kind: CronJob -metadata: - labels: - {{- include "formbricks.labels" $ | nindent 4 }} -{{- if $job.additionalLabels }} -{{ $job.additionalLabels | indent 4 }} -{{- end }} -{{- if $job.annotations }} - annotations: -{{ $job.annotations | indent 4 }} -{{- end }} - name: {{ $name }} - namespace: {{ template "formbricks.namespace" $ }} -spec: - schedule: {{ $job.schedule | quote }} -{{- if ge (int $.Capabilities.KubeVersion.Minor) 27 }} -{{- if $job.timeZone }} - timeZone: {{ $job.timeZone }} -{{ end }} -{{- end }} -{{- if $job.successfulJobsHistoryLimit }} - successfulJobsHistoryLimit: {{ $job.successfulJobsHistoryLimit }} -{{ end }} -{{- if $job.concurrencyPolicy }} - concurrencyPolicy: {{ $job.concurrencyPolicy }} -{{ end }} -{{- if $job.failedJobsHistoryLimit }} - failedJobsHistoryLimit: {{ $job.failedJobsHistoryLimit }} -{{ end }} - jobTemplate: - spec: - {{- with $job.activeDeadlineSeconds }} - activeDeadlineSeconds: {{ . }} - {{- end }} - {{- if not (kindIs "invalid" $job.backoffLimit) }} - backoffLimit: {{ $job.backoffLimit }} - {{- end }} - template: - metadata: - labels: - {{- include "formbricks.labels" $ | nindent 12 }} - {{- with $job.additionalPodLabels }} - {{- toYaml . | nindent 12 }} - {{- end }} - {{- with $job.additionalPodAnnotations }} - annotations: {{ toYaml . | nindent 12 }} - {{- end }} - spec: - {{- if $.Values.rbac.enabled }} - {{- if $.Values.rbac.serviceAccount.name }} - serviceAccountName: {{ $.Values.rbac.serviceAccount.name }} - {{- else }} - serviceAccountName: {{ template "formbricks.name" $ }} - {{- end }} - {{- end }} - containers: - - name: {{ $name }} - {{- $image := required (print "Undefined image repo for container '" $name "'") $job.image.repository }} - {{- with $job.image.tag }} {{- $image = print $image ":" . }} {{- end }} - {{- with $job.image.digest }} {{- $image = print $image "@" . }} {{- end }} - image: {{ $image }} - {{- if $job.image.imagePullPolicy }} - imagePullPolicy: {{ $job.image.imagePullPolicy }} - {{ end }} - {{- with $job.env }} - env: - {{- range $key, $value := $job.env }} - - name: {{ include "formbricks.tplvalues.render" ( dict "value" $key "context" $ ) }} - {{- if kindIs "string" $value }} - value: {{ include "formbricks.tplvalues.render" ( dict "value" $value "context" $ ) | quote }} - {{- else }} - {{- toYaml $value | nindent 16 }} - {{- end }} - {{- end }} - {{- end }} - {{- with $job.envFrom }} - envFrom: - {{ toYaml . | indent 12 }} - {{- end }} - {{- if $job.command }} - command: {{ $job.command }} - {{- end }} - {{- with $job.args }} - args: - {{- range . }} - - {{ . | quote }} - {{- end }} - {{- end }} - {{- with $job.resources }} - resources: - {{ toYaml . | indent 14 }} - {{- end }} - {{- with $job.volumeMounts }} - volumeMounts: -{{ toYaml . | indent 12 }} - {{- end }} - {{- with $job.securityContext }} - securityContext: {{ toYaml . | nindent 14 }} - {{- end }} - {{- with $job.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 12 }} - {{- end }} - {{- with $job.affinity }} - affinity: -{{ toYaml . | indent 12 }} - {{- end }} - {{- with $job.priorityClassName }} - priorityClassName: {{ . }} - {{- end }} - {{- with $job.tolerations }} - tolerations: {{ toYaml . | nindent 12 }} - {{- end }} - {{- with $job.topologySpreadConstraints }} - topologySpreadConstraints: {{ toYaml . | nindent 12 }} - {{- end }} - {{- if $job.restartPolicy }} - restartPolicy: {{ $job.restartPolicy }} - {{ else }} - restartPolicy: OnFailure - {{ end }} - {{- with $job.imagePullSecrets }} - imagePullSecrets: -{{ toYaml . | indent 12 }} - {{ end }} - {{- if $job.dnsConfig }} - dnsConfig: -{{ toYaml $job.dnsConfig | indent 12 }} - {{- end }} - {{- if $job.dnsPolicy }} - dnsPolicy: {{ $job.dnsPolicy }} - {{- end }} - {{- with $job.volumes }} - volumes: -{{ toYaml . | indent 12 }} - {{- end }} -{{- end }} -{{- end }} diff --git a/helm-chart/templates/secrets.yaml b/helm-chart/templates/secrets.yaml index 29e1d1c2e8..bba0d8101e 100644 --- a/helm-chart/templates/secrets.yaml +++ b/helm-chart/templates/secrets.yaml @@ -21,7 +21,7 @@ data: {{- else }} DATABASE_URL: {{ .Values.postgresql.externalDatabaseUrl | b64enc }} {{- end }} - CRON_SECRET: {{ include "formbricks.cronSecret" . | b64enc }} + CRON_SECRET: {{ include "formbricks.cronSecret" . | b64enc }} ENCRYPTION_KEY: {{ include "formbricks.encryptionKey" . | b64enc }} NEXTAUTH_SECRET: {{ include "formbricks.nextAuthSecret" . | b64enc }} {{- if and (.Values.enterprise.licenseKey) (ne .Values.enterprise.licenseKey "") }} diff --git a/helm-chart/values.yaml b/helm-chart/values.yaml index def45c5aa5..efe4b9010c 100644 --- a/helm-chart/values.yaml +++ b/helm-chart/values.yaml @@ -23,7 +23,7 @@ enterprise: deployment: # Deployment strategy configuration strategy: - type: RollingUpdate # Type of deployment strategy (RollingUpdate/Recreate) + type: RollingUpdate # Type of deployment strategy (RollingUpdate/Recreate) # rollingUpdate: # maxSurge: 25% # maxUnavailable: 25% @@ -59,9 +59,7 @@ deployment: # nameSuffix: app-secrets # Environment variables passed to the app container - env: - DOCKER_CRON_ENABLED: - value: "0" + env: {} # Tolerations for scheduling pods on tainted nodes tolerations: [] @@ -78,7 +76,7 @@ deployment: # Application container image image: repository: "ghcr.io/formbricks/formbricks" - digest: "" # If set, digest takes precedence over the tag + digest: "" # If set, digest takes precedence over the tag pullPolicy: IfNotPresent # Health probes configuration @@ -146,11 +144,11 @@ deployment: # Horizontal Pod Autoscaler (HPA) ########################################################## autoscaling: - enabled: true # Enable/disable HPA - additionalLabels: {} # Additional labels for the HPA resource - annotations: {} # Annotations for HPA - minReplicas: 1 # Minimum number of replicas - maxReplicas: 10 # Maximum number of replicas + enabled: true # Enable/disable HPA + additionalLabels: {} # Additional labels for the HPA resource + annotations: {} # Annotations for HPA + minReplicas: 1 # Minimum number of replicas + maxReplicas: 10 # Maximum number of replicas metrics: - type: Resource resource: @@ -169,29 +167,22 @@ autoscaling: # Service Configuration ########################################################## service: - enabled: true # Enable/disable Kubernetes Service - additionalLabels: {} # Additional labels for Service - annotations: {} # Annotations for Service - type: ClusterIP # Service type (ClusterIP, NodePort, LoadBalancer) - ports: [] # Additional ports + enabled: true # Enable/disable Kubernetes Service + additionalLabels: {} # Additional labels for Service + annotations: {} # Annotations for Service + type: ClusterIP # Service type (ClusterIP, NodePort, LoadBalancer) + ports: [] # Additional ports ########################################################## # Role-Based Access Control (RBAC) ########################################################## rbac: - enabled: false # Enable/disable RBAC + enabled: false # Enable/disable RBAC serviceAccount: - enabled: false # Enable/disable ServiceAccount - name: "" # Custom ServiceAccount name - additionalLabels: {} # Additional labels - annotations: {} # Annotations - -########################################################## -# Cron Job Configuration -########################################################## -cronJob: - enabled: false # Enable/disable CronJobs - jobs: {} # Define cron jobs + enabled: false # Enable/disable ServiceAccount + name: "" # Custom ServiceAccount name + additionalLabels: {} # Additional labels + annotations: {} # Annotations ########################################################## # Kubernetes Secret Configuration (Quick Start) @@ -203,33 +194,32 @@ secret: # External Secrets Configuration ########################################################## externalSecret: - enabled: false # Enable/disable ExternalSecrets + enabled: false # Enable/disable ExternalSecrets secretStore: - name: aws-secrets-manager # Secret store reference name - kind: ClusterSecretStore # Type of secret store - refreshInterval: "1h" # Frequency of secret sync + name: aws-secrets-manager # Secret store reference name + kind: ClusterSecretStore # Type of secret store + refreshInterval: "1h" # Frequency of secret sync files: {} ########################################################## # Ingress Configuration ########################################################## ingress: - enabled: false # Enable/disable Ingress - ingressClassName: alb # Specify the Ingress class + enabled: false # Enable/disable Ingress + ingressClassName: alb # Specify the Ingress class hosts: - host: k8s.formbricks.com paths: - path: / pathType: "Prefix" serviceName: "formbricks" - annotations: {} # Ingress annotations - + annotations: {} # Ingress annotations ########################################################## # Redis Configuration ########################################################## redis: - enabled: true # Enable/disable Redis + enabled: true # Enable/disable Redis externalRedisUrl: "" fullnameOverride: "formbricks-redis" architecture: standalone @@ -267,7 +257,7 @@ serviceMonitor: # PostgreSQL Configuration ########################################################## postgresql: - enabled: true # Enable/disable PostgreSQL + enabled: true # Enable/disable PostgreSQL externalDatabaseUrl: "" global: security: diff --git a/infra/formbricks-cloud-helm/values-staging.yaml.gotmpl b/infra/formbricks-cloud-helm/values-staging.yaml.gotmpl index 5d3b0b1aa4..6b45a19fb3 100644 --- a/infra/formbricks-cloud-helm/values-staging.yaml.gotmpl +++ b/infra/formbricks-cloud-helm/values-staging.yaml.gotmpl @@ -1,55 +1,4 @@ nameOverride: "formbricks-stage" -cronJob: - enabled: true - jobs: - ping: - args: - - /bin/sh - - -c - - 'curl -X POST -H "content-type: application/json" -H "x-api-key: $CRON_SECRET" - "$WEBAPP_URL/api/cron/ping"' - env: - CRON_SECRET: - valueFrom: - secretKeyRef: - key: CRON_SECRET - name: formbricks-stage-app-env - WEBAPP_URL: - valueFrom: - secretKeyRef: - key: WEBAPP_URL - name: formbricks-stage-app-env - image: - imagePullPolicy: IfNotPresent - repository: quay.io/curl/curl - tag: latest - schedule: 0 9 * * * - successfulJobsHistoryLimit: 0 - survey-status: - args: - - /bin/sh - - -c - - 'curl -X POST -H "content-type: application/json" -H "x-api-key: $CRON_SECRET" - "$WEBAPP_URL/api/cron/survey-status"' - env: - CRON_SECRET: - valueFrom: - secretKeyRef: - key: CRON_SECRET - name: formbricks-stage-app-env - WEBAPP_URL: - valueFrom: - secretKeyRef: - key: WEBAPP_URL - name: formbricks-stage-app-env - image: - imagePullPolicy: IfNotPresent - repository: quay.io/curl/curl - tag: latest - schedule: 0 0 * * * - successfulJobsHistoryLimit: 0 - - ## Deployment & Autoscaling deployment: image: @@ -62,8 +11,6 @@ deployment: cpu: 1 memory: 1Gi env: - DOCKER_CRON_ENABLED: - value: "0" RATE_LIMITING_DISABLED: value: "1" envFrom: diff --git a/infra/formbricks-cloud-helm/values.yaml.gotmpl b/infra/formbricks-cloud-helm/values.yaml.gotmpl index 0d05350022..3004f1a749 100644 --- a/infra/formbricks-cloud-helm/values.yaml.gotmpl +++ b/infra/formbricks-cloud-helm/values.yaml.gotmpl @@ -1,54 +1,3 @@ -cronJob: - enabled: true - jobs: - ping: - args: - - /bin/sh - - -c - - 'curl -X POST -H "content-type: application/json" -H "x-api-key: $CRON_SECRET" - "$WEBAPP_URL/api/cron/ping"' - env: - CRON_SECRET: - valueFrom: - secretKeyRef: - key: CRON_SECRET - name: formbricks-app-env - WEBAPP_URL: - valueFrom: - secretKeyRef: - key: WEBAPP_URL - name: formbricks-app-env - image: - imagePullPolicy: IfNotPresent - repository: quay.io/curl/curl - tag: latest - schedule: 0 9 * * * - successfulJobsHistoryLimit: 0 - survey-status: - args: - - /bin/sh - - -c - - 'curl -X POST -H "content-type: application/json" -H "x-api-key: $CRON_SECRET" - "$WEBAPP_URL/api/cron/survey-status"' - env: - CRON_SECRET: - valueFrom: - secretKeyRef: - key: CRON_SECRET - name: formbricks-app-env - WEBAPP_URL: - valueFrom: - secretKeyRef: - key: WEBAPP_URL - name: formbricks-app-env - image: - imagePullPolicy: IfNotPresent - repository: quay.io/curl/curl - tag: latest - schedule: 0 0 * * * - successfulJobsHistoryLimit: 0 - - ## Deployment & Autoscaling deployment: resources: @@ -57,9 +6,7 @@ deployment: requests: cpu: 1 memory: 1Gi - env: - DOCKER_CRON_ENABLED: - value: "0" + env: {} envFrom: app-env: nameSuffix: app-env diff --git a/packages/database/migration/20250904145727_removes_cron_and_survey_scheduling/migration.sql b/packages/database/migration/20250904145727_removes_cron_and_survey_scheduling/migration.sql new file mode 100644 index 0000000000..d5dffa705d --- /dev/null +++ b/packages/database/migration/20250904145727_removes_cron_and_survey_scheduling/migration.sql @@ -0,0 +1,26 @@ +/* + Warnings: + + - The values [scheduled] on the enum `SurveyStatus` will be removed. If these variants are still used in the database, this will fail. + - You are about to drop the column `closeOnDate` on the `Survey` table. All the data in the column will be lost. + - You are about to drop the column `runOnDate` on the `Survey` table. All the data in the column will be lost. + +*/ + +-- Update any scheduled surveys to paused +UPDATE "public"."Survey" SET "status" = 'paused' WHERE "status" = 'scheduled'; + +-- AlterEnum +BEGIN; +CREATE TYPE "public"."SurveyStatus_new" AS ENUM ('draft', 'inProgress', 'paused', 'completed'); +ALTER TABLE "public"."Survey" ALTER COLUMN "status" DROP DEFAULT; +ALTER TABLE "public"."Survey" ALTER COLUMN "status" TYPE "public"."SurveyStatus_new" USING ("status"::text::"public"."SurveyStatus_new"); +ALTER TYPE "public"."SurveyStatus" RENAME TO "SurveyStatus_old"; +ALTER TYPE "public"."SurveyStatus_new" RENAME TO "SurveyStatus"; +DROP TYPE "public"."SurveyStatus_old"; +ALTER TABLE "public"."Survey" ALTER COLUMN "status" SET DEFAULT 'draft'; +COMMIT; + +-- AlterTable +ALTER TABLE "public"."Survey" DROP COLUMN "closeOnDate", +DROP COLUMN "runOnDate"; diff --git a/packages/database/schema.prisma b/packages/database/schema.prisma index 25d6d9b0cb..366797fb36 100644 --- a/packages/database/schema.prisma +++ b/packages/database/schema.prisma @@ -213,7 +213,6 @@ model TagsOnResponses { enum SurveyStatus { draft - scheduled inProgress paused completed @@ -372,8 +371,6 @@ model Survey { autoClose Int? autoComplete Int? delay Int @default(0) - runOnDate DateTime? - closeOnDate DateTime? /// [SurveyClosedMessage] surveyClosedMessage Json? segmentId String? diff --git a/packages/database/zod/surveys.ts b/packages/database/zod/surveys.ts index 459a92d380..ab16433034 100644 --- a/packages/database/zod/surveys.ts +++ b/packages/database/zod/surveys.ts @@ -137,12 +137,6 @@ const ZSurveyBase = z.object({ delay: z.number().openapi({ description: "Delay before showing survey", }), - runOnDate: z.date().nullable().openapi({ - description: "Date to run the survey", - }), - closeOnDate: z.date().nullable().openapi({ - description: "Date to close the survey", - }), surveyClosedMessage: z .object({ enabled: z.boolean(), diff --git a/packages/types/surveys/types.ts b/packages/types/surveys/types.ts index 75b03e3e26..4dea23e814 100644 --- a/packages/types/surveys/types.ts +++ b/packages/types/surveys/types.ts @@ -772,7 +772,7 @@ export const ZSurveyType = z.enum(["link", "app"]); export type TSurveyType = z.infer; -export const ZSurveyStatus = z.enum(["draft", "scheduled", "inProgress", "paused", "completed"]); +export const ZSurveyStatus = z.enum(["draft", "inProgress", "paused", "completed"]); export type TSurveyStatus = z.infer; @@ -854,8 +854,6 @@ export const ZSurvey = z ), delay: z.number(), autoComplete: z.number().min(1, { message: "Response limit must be greater than 0" }).nullable(), - runOnDate: z.date().nullable(), - closeOnDate: z.date().nullable(), projectOverwrites: ZSurveyProjectOverwrites.nullable(), styling: ZSurveyStyling.nullable(), showLanguageSwitch: z.boolean().nullable(), @@ -2507,8 +2505,6 @@ export type TSurveyCreateInputWithEnvironmentId = z.infer; diff --git a/turbo.json b/turbo.json index 0448a1a650..ec283a0985 100644 --- a/turbo.json +++ b/turbo.json @@ -95,7 +95,6 @@ "AUTH_SKIP_INVITE_FOR_SSO", "BREVO_API_KEY", "BREVO_LIST_ID", - "DOCKER_CRON_ENABLED", "CRON_SECRET", "DATABASE_URL", "DEBUG",