mirror of
https://github.com/formbricks/formbricks.git
synced 2026-02-14 19:08:55 -06:00
chore: prepare 2.1 release (#2753)
This commit is contained in:
@@ -87,6 +87,7 @@ EMAIL_VERIFICATION_DISABLED=1
|
||||
PASSWORD_RESET_DISABLED=1
|
||||
|
||||
# Signup. Disable the ability for new users to create an account.
|
||||
# Note: This variable is only available to the SaaS setup of Formbricks Cloud. Signup is disable by default for self-hosting.
|
||||
# SIGNUP_DISABLED=1
|
||||
|
||||
# Email login. Disable the ability for users to login with email.
|
||||
|
||||
@@ -28,7 +28,6 @@ These variables are present inside your machine’s docker-compose file. Restart
|
||||
| PRIVACY_URL | URL for privacy policy. | optional | |
|
||||
| TERMS_URL | URL for terms of service. | optional | |
|
||||
| IMPRINT_URL | URL for imprint. | optional | |
|
||||
| SIGNUP_DISABLED | Disables the ability for new users to create an account if set to 1. | optional | |
|
||||
| EMAIL_AUTH_DISABLED | Disables the ability for users to signup or login via email and password if set to 1. | optional | |
|
||||
| PASSWORD_RESET_DISABLED | Disables password reset functionality if set to 1. | optional | |
|
||||
| EMAIL_VERIFICATION_DISABLED | Disables email verification if set to 1. | optional | |
|
||||
@@ -176,10 +175,10 @@ An example configuration for a FusionAuth OpenID Connect in Formbricks would loo
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Formbricks Env for FusionAuth OIDC">
|
||||
```yml {{ title: ".env" }}
|
||||
```yml {{ title: ".env" }}
|
||||
OIDC_CLIENT_ID=59cada54-56d4-4aa8-a5e7-5823bbe0e5b7 OIDC_CLIENT_SECRET=4f4dwP0ZoOAqMW8fM9290A7uIS3E8Xg29xe1umhlB_s
|
||||
OIDC_ISSUER=http://localhost:9011 OIDC_DISPLAY_NAME=FusionAuth OIDC_SIGNING_ALGORITHM=HS256
|
||||
```
|
||||
OIDC_ISSUER=http://localhost:9011 OIDC_DISPLAY_NAME=FusionAuth OIDC_SIGNING_ALGORITHM=HS256
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
|
||||
@@ -8,6 +8,112 @@ export const metadata = {
|
||||
|
||||
# Migration Guide
|
||||
|
||||
## v2.1
|
||||
|
||||
Formbricks v2.1 introduces more options for creating No-Code Actions and lays the foundation for easier self-hosting of Formbricks starting with an Onboarding for fresh instances.
|
||||
|
||||
<Note>
|
||||
To improve the user experience in self-hosting instances and to simplify setup, we are moving to a single
|
||||
organization approach for self-hosting instances with this release. This will allow self-hosters to
|
||||
centrally manage their instance and more easily restrict access to the instance. We will soon introduce a
|
||||
new permissions system that will allow more granular access to projects and other resources within an
|
||||
organization. If you have created multiple organizations in the past, you will still be able to switch
|
||||
between them in the UI, but don't have an option to create new organizations.
|
||||
</Note>
|
||||
|
||||
### Steps to Migrate
|
||||
|
||||
This guide is for users who are self-hosting Formbricks using our one-click setup. If you are using a different setup, you might adjust the commands accordingly.
|
||||
|
||||
To run all these steps, please navigate to the `formbricks` folder where your `docker-compose.yml` file is located.
|
||||
|
||||
1. **Backup your Database**: This is a crucial step. Please make sure to backup your database before proceeding with the upgrade. You can use the following command to backup your database:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Backup Postgres">
|
||||
|
||||
```bash
|
||||
docker exec formbricks-postgres-1 pg_dump -Fc -U postgres -d formbricks > formbricks_pre_v2.1_$(date +%Y%m%d_%H%M%S).dump
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
<Note>
|
||||
If you run into “No such container”, use `docker ps` to find your container name, e.g.
|
||||
`formbricks_postgres_1`.
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
If you prefer storing the backup as an `*.sql` file remove the `-Fc` (custom format) option. In case of a
|
||||
restore scenario you will need to use `psql` then with an empty `formbricks` database.
|
||||
</Note>
|
||||
|
||||
2. Pull the latest version of Formbricks:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Stop the containers">
|
||||
|
||||
```bash
|
||||
docker compose pull
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
3. Stop the running Formbricks instance & remove the related containers:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Stop the containers">
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
4. Restarting the containers with the latest version of Formbricks:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Restart the containers">
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
5. Now let's migrate the data to the latest schema:
|
||||
|
||||
<Note>To find your Docker Network name for your Postgres Database, find it using `docker network ls`</Note>
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Migrate the data">
|
||||
|
||||
```bash
|
||||
docker pull ghcr.io/formbricks/data-migrations:latest && \
|
||||
docker run --rm \
|
||||
--network=formbricks_default \
|
||||
-e DATABASE_URL="postgresql://postgres:postgres@postgres:5432/formbricks?schema=public" \
|
||||
-e UPGRADE_TO_VERSION="v2.1" \
|
||||
ghcr.io/formbricks/data-migrations:latest
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
The above command will migrate your data to the latest schema. This is a crucial step to migrate your existing data to the new structure. Only if the script runs successful, changes are made to the database. The script can safely run multiple times.
|
||||
|
||||
6. That's it! Once the migration is complete, you can **now access your Formbricks instance** at the same URL as before.
|
||||
|
||||
### Changes in Environment Variables
|
||||
|
||||
- `SIGNUP_DISABLED` is now deprecated since self-hosting instaces have signup disabled by default and new users can only be invited by the organization owner or admin.
|
||||
- `DEFAULT_TEAM_ID` got renamed to `DEFAULT_ORGANIZATION_ID`
|
||||
- `DEFAULT_TEAM_ROLE` got renamed to `DEFAULT_ORGANIZATION_ROLE`
|
||||
|
||||
## v2.0
|
||||
|
||||
Formbricks v2.0 comes with huge features such as Multi-Language Surveys and Advanced Styling for Surveys. We have also shipped various optimisations, bug fixes & smaller fixes on the way to make your experience more seamless. This guide will help you migrate your existing Formbricks instance to v2.0 without any hassles or build errors.
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import { formbricksLogout } from "@/app/lib/formbricks";
|
||||
import { Session } from "next-auth";
|
||||
import { useState } from "react";
|
||||
|
||||
import { ProfileAvatar } from "@formbricks/ui/Avatars";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
import { DeleteAccountModal } from "@formbricks/ui/DeleteAccountModal";
|
||||
@@ -39,7 +38,7 @@ export const DeleteAccount = ({
|
||||
open={isModalOpen}
|
||||
setOpen={setModalOpen}
|
||||
session={session}
|
||||
IS_FORMBRICKS_CLOUD={IS_FORMBRICKS_CLOUD}
|
||||
isFormbricksCloud={IS_FORMBRICKS_CLOUD}
|
||||
formbricksLogout={formbricksLogout}
|
||||
/>
|
||||
<p className="text-sm text-slate-700">
|
||||
|
||||
@@ -2,7 +2,6 @@ import { FormWrapper } from "@/app/(auth)/auth/components/FormWrapper";
|
||||
import { Testimonial } from "@/app/(auth)/auth/components/Testimonial";
|
||||
import { SignupForm } from "@/app/(auth)/auth/signup/components/SignupForm";
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
import { getIsMultiOrgEnabled } from "@formbricks/ee/lib/service";
|
||||
import {
|
||||
AZURE_OAUTH_ENABLED,
|
||||
@@ -19,10 +18,11 @@ import {
|
||||
WEBAPP_URL,
|
||||
} from "@formbricks/lib/constants";
|
||||
|
||||
const Page = async () => {
|
||||
const Page = async ({ searchParams }: { searchParams: { [key: string]: string | string[] | undefined } }) => {
|
||||
const inviteToken = searchParams["inviteToken"] ?? null;
|
||||
const isMultOrgEnabled = await getIsMultiOrgEnabled();
|
||||
|
||||
if (!SIGNUP_ENABLED || !isMultOrgEnabled) {
|
||||
if (!inviteToken && (!SIGNUP_ENABLED || !isMultOrgEnabled)) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { Session } from "next-auth";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
import { authOptions } from "@formbricks/lib/authOptions";
|
||||
import { ONBOARDING_DISABLED } from "@formbricks/lib/constants";
|
||||
import { getFirstEnvironmentByUserId } from "@formbricks/lib/environment/service";
|
||||
@@ -26,7 +25,8 @@ const Page = async () => {
|
||||
}
|
||||
|
||||
const userOrganizations = await getOrganizationsByUserId(session.user.id);
|
||||
if (!userOrganizations || userOrganizations.length === 0) {
|
||||
|
||||
if (userOrganizations.length === 0) {
|
||||
return redirect("/setup/organization/create");
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { Organization } from "@prisma/client";
|
||||
import { getServerSession } from "next-auth";
|
||||
|
||||
import { getIsMultiOrgEnabled } from "@formbricks/ee/lib/service";
|
||||
import { authOptions } from "@formbricks/lib/authOptions";
|
||||
import { gethasNoOrganizations } from "@formbricks/lib/instance/service";
|
||||
import { createMembership } from "@formbricks/lib/membership/service";
|
||||
@@ -16,7 +16,9 @@ export const createOrganizationAction = async (organizationName: string): Promis
|
||||
if (!session) throw new AuthorizationError("Not authorized");
|
||||
|
||||
const hasNoOrganizations = await gethasNoOrganizations();
|
||||
if (!hasNoOrganizations) {
|
||||
const isMultiOrgEnabled = await getIsMultiOrgEnabled();
|
||||
|
||||
if (!hasNoOrganizations && !isMultiOrgEnabled) {
|
||||
throw new OperationNotAllowedError("This action can only be performed on a fresh instance.");
|
||||
}
|
||||
|
||||
|
||||
@@ -7,30 +7,29 @@ import { useState } from "react";
|
||||
import { SubmitHandler, useForm } from "react-hook-form";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { z } from "zod";
|
||||
|
||||
import { ZOrganization } from "@formbricks/types/organizations";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
import { FormControl, FormError, FormField, FormItem, FormProvider } from "@formbricks/ui/Form";
|
||||
import { Input } from "@formbricks/ui/Input";
|
||||
|
||||
const ZCreateFirstOrganizationFormSchema = ZOrganization.pick({ name: true });
|
||||
type TCreateFirstOrganizationForm = z.infer<typeof ZCreateFirstOrganizationFormSchema>;
|
||||
const ZCreateOrganizationFormSchema = ZOrganization.pick({ name: true });
|
||||
type TCreateOrganizationForm = z.infer<typeof ZCreateOrganizationFormSchema>;
|
||||
|
||||
export const CreateFirstOrganization = () => {
|
||||
export const CreateOrganization = () => {
|
||||
const router = useRouter();
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const form = useForm<TCreateFirstOrganizationForm>({
|
||||
const form = useForm<TCreateOrganizationForm>({
|
||||
defaultValues: {
|
||||
name: "",
|
||||
},
|
||||
mode: "onChange",
|
||||
resolver: zodResolver(ZCreateFirstOrganizationFormSchema),
|
||||
resolver: zodResolver(ZCreateOrganizationFormSchema),
|
||||
});
|
||||
|
||||
const organizationName = form.watch("name");
|
||||
|
||||
const onSubmit: SubmitHandler<TCreateFirstOrganizationForm> = async (data) => {
|
||||
const onSubmit: SubmitHandler<TCreateOrganizationForm> = async (data) => {
|
||||
try {
|
||||
setIsSubmitting(true);
|
||||
const organizationName = data.name.trim();
|
||||
@@ -3,25 +3,24 @@
|
||||
import { formbricksLogout } from "@/app/lib/formbricks";
|
||||
import { Session } from "next-auth";
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { Alert, AlertDescription, AlertTitle } from "@formbricks/ui/Alert";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
import { DeleteAccountModal } from "@formbricks/ui/DeleteAccountModal";
|
||||
|
||||
interface RemovedFromOrganizationProps {
|
||||
session: Session;
|
||||
IS_FORMBRICKS_CLOUD: boolean;
|
||||
isFormbricksCloud: boolean;
|
||||
}
|
||||
|
||||
export const RemovedFromOrganization = ({ session, IS_FORMBRICKS_CLOUD }: RemovedFromOrganizationProps) => {
|
||||
export const RemovedFromOrganization = ({ session, isFormbricksCloud }: RemovedFromOrganizationProps) => {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<Alert variant="warning">
|
||||
<AlertTitle>No membership found!</AlertTitle>
|
||||
<AlertDescription>
|
||||
Unfortunately, you have been removed from the organization. If you believe this was a mistake,
|
||||
please reach out to the organization owner.
|
||||
You are not a member of any organization at this time. If you believe this is a mistake, please
|
||||
reach out to the organization owner.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<hr className="my-4 border-slate-200" />
|
||||
@@ -32,7 +31,7 @@ export const RemovedFromOrganization = ({ session, IS_FORMBRICKS_CLOUD }: Remove
|
||||
open={isModalOpen}
|
||||
setOpen={setIsModalOpen}
|
||||
session={session}
|
||||
IS_FORMBRICKS_CLOUD={IS_FORMBRICKS_CLOUD}
|
||||
isFormbricksCloud={isFormbricksCloud}
|
||||
formbricksLogout={formbricksLogout}
|
||||
/>
|
||||
<Button variant="darkCTA" onClick={() => setIsModalOpen(true)}>
|
||||
|
||||
@@ -2,15 +2,13 @@ import { RemovedFromOrganization } from "@/app/setup/organization/create/compone
|
||||
import { Metadata } from "next";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
import { getIsMultiOrgEnabled } from "@formbricks/ee/lib/service";
|
||||
import { authOptions } from "@formbricks/lib/authOptions";
|
||||
import { IS_FORMBRICKS_CLOUD } from "@formbricks/lib/constants";
|
||||
import { gethasNoOrganizations } from "@formbricks/lib/instance/service";
|
||||
import { getOrganizationsByUserId } from "@formbricks/lib/organization/service";
|
||||
import { AuthenticationError } from "@formbricks/types/errors";
|
||||
|
||||
import { CreateFirstOrganization } from "./components/CreateFirstOrganiztion";
|
||||
import { CreateOrganization } from "./components/CreateOrganization";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Organization",
|
||||
@@ -26,15 +24,15 @@ const Page = async () => {
|
||||
const isMultiOrgEnabled = await getIsMultiOrgEnabled();
|
||||
const userOrganizations = await getOrganizationsByUserId(session.user.id);
|
||||
|
||||
if (hasNoOrganizations || isMultiOrgEnabled) {
|
||||
return <CreateOrganization />;
|
||||
}
|
||||
|
||||
if (!hasNoOrganizations && userOrganizations.length === 0 && !isMultiOrgEnabled) {
|
||||
return <RemovedFromOrganization session={session} IS_FORMBRICKS_CLOUD={IS_FORMBRICKS_CLOUD} />;
|
||||
return <RemovedFromOrganization session={session} isFormbricksCloud={IS_FORMBRICKS_CLOUD} />;
|
||||
}
|
||||
|
||||
if (userOrganizations.length !== 0 || (!hasNoOrganizations && !isMultiOrgEnabled)) {
|
||||
return notFound();
|
||||
}
|
||||
|
||||
return <CreateFirstOrganization />;
|
||||
return notFound();
|
||||
};
|
||||
|
||||
export default Page;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@formbricks/web",
|
||||
"version": "2.0.3",
|
||||
"version": "2.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"clean": "rimraf .turbo node_modules .next",
|
||||
|
||||
@@ -56,10 +56,6 @@ x-environment: &environment
|
||||
# Set the below to 0 to enable Password Reset (will required Email Configuration)
|
||||
PASSWORD_RESET_DISABLED: 1
|
||||
|
||||
# Set the below to 1 to disable signups. The first user will be created in the Onboarding process and all other users must be invited.
|
||||
# Note: Signup cannot be enabled on self-hosting instances.
|
||||
SIGNUP_DISABLED: 1
|
||||
|
||||
# Set the below to 1 to disable logins with email
|
||||
# EMAIL_AUTH_DISABLED:
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ echo "🔗 To edit more variables and deeper config, go to the formbricks/docker
|
||||
|
||||
echo "🚨 Make sure you have set up the DNS records as well as inbound rules for the domain name and IP address of this instance."
|
||||
echo ""
|
||||
echo "🎉 All done! Check the status of Formbricks & Traefik with 'cd formbricks && sudo docker compose ps.'"
|
||||
echo "🎉 All done! Please setup your Formbricks instance by visiting your domain at https://$domain_name. You can check the status of Formbricks & Traefik with 'cd formbricks && sudo docker compose ps.'"
|
||||
|
||||
END
|
||||
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
"data-migration:refactor-actions": "ts-node ./data-migrations/20240501111944_refactors_actions_and_removes_inline_triggers/data-migration.ts",
|
||||
"data-migration:mls-welcomeCard-fix": "ts-node ./data-migrations/20240318050527_add_languages_and_survey_languages/data-migration-welcomeCard-fix.ts",
|
||||
"data-migration:v2.0": "pnpm data-migration:mls && pnpm data-migration:styling && pnpm data-migration:styling-fix && pnpm data-migration:website-surveys && pnpm data-migration:userId && pnpm data-migration:mls-welcomeCard-fix && pnpm data-migration:refactor-actions",
|
||||
"data-migration:extended-noCodeActions": "ts-node ./data-migrations/20240524053239_extends_no_code_action_schema/data-migration.ts"
|
||||
"data-migration:extended-noCodeActions": "ts-node ./data-migrations/20240524053239_extends_no_code_action_schema/data-migration.ts",
|
||||
"data-migration:v2.1": "pnpm data-migration:extended-noCodeActions"
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^5.14.0",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -4,9 +4,7 @@ import AzureAD from "next-auth/providers/azure-ad";
|
||||
import CredentialsProvider from "next-auth/providers/credentials";
|
||||
import GitHubProvider from "next-auth/providers/github";
|
||||
import GoogleProvider from "next-auth/providers/google";
|
||||
|
||||
import { prisma } from "@formbricks/database";
|
||||
|
||||
import { createAccount } from "./account/service";
|
||||
import { verifyPassword } from "./auth/utils";
|
||||
import {
|
||||
@@ -29,7 +27,6 @@ import {
|
||||
import { verifyToken } from "./jwt";
|
||||
import { createMembership } from "./membership/service";
|
||||
import { createOrganization, getOrganization } from "./organization/service";
|
||||
import { createProduct } from "./product/service";
|
||||
import { createUser, getUserByEmail, updateUser } from "./user/service";
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
@@ -281,31 +278,7 @@ export const authOptions: NextAuthOptions = {
|
||||
return true;
|
||||
}
|
||||
// Without default organization assignment
|
||||
else {
|
||||
const organization = await createOrganization({ name: userProfile.name + "'s Organization" });
|
||||
await createMembership(organization.id, userProfile.id, { role: "owner", accepted: true });
|
||||
await createAccount({
|
||||
...account,
|
||||
userId: userProfile.id,
|
||||
});
|
||||
const product = await createProduct(organization.id, { name: "My Product" });
|
||||
const updatedNotificationSettings = {
|
||||
...userProfile.notificationSettings,
|
||||
alert: {
|
||||
...userProfile.notificationSettings?.alert,
|
||||
},
|
||||
weeklySummary: {
|
||||
...userProfile.notificationSettings?.weeklySummary,
|
||||
[product.id]: true,
|
||||
},
|
||||
};
|
||||
|
||||
await updateUser(userProfile.id, {
|
||||
notificationSettings: updatedNotificationSettings,
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
"tailwind-merge": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formbricks/config-typescript": "*",
|
||||
"@formbricks/config-typescript": "workspace:*",
|
||||
"@types/jsonwebtoken": "^9.0.6",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/ungap__structured-clone": "^1.2.0",
|
||||
|
||||
@@ -4,7 +4,6 @@ import { Session } from "next-auth";
|
||||
import { signOut } from "next-auth/react";
|
||||
import { Dispatch, SetStateAction, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
import { DeleteDialog } from "../DeleteDialog";
|
||||
import { Input } from "../Input";
|
||||
import { deleteUserAction } from "./actions";
|
||||
@@ -13,7 +12,7 @@ interface DeleteAccountModalProps {
|
||||
open: boolean;
|
||||
setOpen: Dispatch<SetStateAction<boolean>>;
|
||||
session: Session;
|
||||
IS_FORMBRICKS_CLOUD: boolean;
|
||||
isFormbricksCloud: boolean;
|
||||
formbricksLogout: () => void;
|
||||
}
|
||||
|
||||
@@ -21,7 +20,7 @@ export const DeleteAccountModal = ({
|
||||
setOpen,
|
||||
open,
|
||||
session,
|
||||
IS_FORMBRICKS_CLOUD,
|
||||
isFormbricksCloud,
|
||||
formbricksLogout,
|
||||
}: DeleteAccountModalProps) => {
|
||||
const [deleting, setDeleting] = useState(false);
|
||||
@@ -36,7 +35,7 @@ export const DeleteAccountModal = ({
|
||||
await deleteUserAction();
|
||||
await formbricksLogout();
|
||||
// redirect to account deletion survey in Formbricks Cloud
|
||||
if (IS_FORMBRICKS_CLOUD) {
|
||||
if (isFormbricksCloud) {
|
||||
await signOut({ redirect: true });
|
||||
window.location.replace("https://app.formbricks.com/s/clri52y3z8f221225wjdhsoo2");
|
||||
} else {
|
||||
|
||||
26814
pnpm-lock.yaml
generated
26814
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user