Compare commits
75 Commits
feat/3214-
...
v2.7.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
adcc596875 | ||
|
|
1bcdf06b43 | ||
|
|
3be78f0312 | ||
|
|
5633499834 | ||
|
|
88847a153b | ||
|
|
3e7c3a45c3 | ||
|
|
1af1a92fec | ||
|
|
7b38923b7d | ||
|
|
38500e1d79 | ||
|
|
2e82fc3ead | ||
|
|
e88ae4aa3d | ||
|
|
5f55c922dc | ||
|
|
fc3c044e00 | ||
|
|
bee0ab07b4 | ||
|
|
0c37956943 | ||
|
|
74bd40e0ff | ||
|
|
31c3f9730e | ||
|
|
da8e7c1870 | ||
|
|
ac0ec1fbcd | ||
|
|
18be650561 | ||
|
|
5977fa6f80 | ||
|
|
1e2833b742 | ||
|
|
f18b030ebf | ||
|
|
ef454d8140 | ||
|
|
1ea391e45b | ||
|
|
b3e6e8d5d0 | ||
|
|
705f55176f | ||
|
|
297f349b45 | ||
|
|
91b6a9e008 | ||
|
|
189dc52ee9 | ||
|
|
280a9a439b | ||
|
|
bc844bbb1f | ||
|
|
ea2d6de9a7 | ||
|
|
e09ab1dcbe | ||
|
|
e1e04517a9 | ||
|
|
06026b6922 | ||
|
|
19a3faadce | ||
|
|
33543f59f8 | ||
|
|
47826a45aa | ||
|
|
6f043ec16e | ||
|
|
c2703788ae | ||
|
|
ef7df0fc77 | ||
|
|
cdb8199199 | ||
|
|
b0ded570ff | ||
|
|
5c0b29eed4 | ||
|
|
8e16d8daf6 | ||
|
|
deea760a17 | ||
|
|
f56f08e3c1 | ||
|
|
5daeab6554 | ||
|
|
0d11c08be7 | ||
|
|
e7fbdb4d00 | ||
|
|
9538c2e6e3 | ||
|
|
3b5f9adcd1 | ||
|
|
90480317af | ||
|
|
352e905529 | ||
|
|
588768c849 | ||
|
|
2bab855b05 | ||
|
|
7fdc2eec34 | ||
|
|
464455be2b | ||
|
|
0a11c6aed5 | ||
|
|
8566b4c3da | ||
|
|
9465bd15f2 | ||
|
|
37791fc78f | ||
|
|
98c16eb4b8 | ||
|
|
7803de6ee7 | ||
|
|
d9e2267a3a | ||
|
|
9872d17abe | ||
|
|
4dad1226ce | ||
|
|
5a2f8c586a | ||
|
|
eba60d4777 | ||
|
|
e633fc76be | ||
|
|
700068dc9f | ||
|
|
0f2f3b1af8 | ||
|
|
35e4b1f965 | ||
|
|
047c9abe9c |
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"$schema": "https://unpkg.com/@changesets/config@2.2.0/schema.json",
|
||||
"access": "public",
|
||||
"baseBranch": "main",
|
||||
"changelog": "@changesets/cli/changelog",
|
||||
"commit": false,
|
||||
"fixed": [],
|
||||
"ignore": ["@formbricks/demo", "@formbricks/web"],
|
||||
"linked": [],
|
||||
"access": "public",
|
||||
"baseBranch": "main",
|
||||
"updateInternalDependencies": "patch",
|
||||
"ignore": ["@formbricks/demo", "@formbricks/web"]
|
||||
"updateInternalDependencies": "patch"
|
||||
}
|
||||
|
||||
@@ -2,11 +2,6 @@
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/javascript-node-postgres
|
||||
// Update the VARIANT arg in docker-compose.yml to pick a Node.js version
|
||||
{
|
||||
"name": "Node.js & PostgreSQL",
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "app",
|
||||
"workspaceFolder": "/workspace",
|
||||
|
||||
// Configure tool-specific properties.
|
||||
"customizations": {
|
||||
// Configure properties specific to VS Code.
|
||||
@@ -16,14 +11,18 @@
|
||||
}
|
||||
},
|
||||
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// This can be used to network with other containers or with the host.
|
||||
"forwardPorts": [3000, 5432, 8025],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "cp .env.example .env && 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 && pnpm install && pnpm db:migrate:dev",
|
||||
"name": "Node.js & PostgreSQL",
|
||||
"postAttachCommand": "pnpm dev --filter=@formbricks/web... --filter=@formbricks/demo...",
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "cp .env.example .env && 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 && pnpm install && pnpm db:migrate:dev",
|
||||
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||
"remoteUser": "node"
|
||||
"remoteUser": "node",
|
||||
"service": "app",
|
||||
"workspaceFolder": "/workspace"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version: '3.8'
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
@@ -22,11 +22,11 @@ services:
|
||||
# Uncomment the next line to use a non-root user for all processes.
|
||||
# user: node
|
||||
|
||||
# Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
|
||||
# Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
|
||||
# (Adding the "ports" property to this file will not forward from a Codespace.)
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
image: pgvector/pgvector:pg17
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
@@ -41,12 +41,11 @@ services:
|
||||
image: mailhog/mailhog
|
||||
network_mode: service:app
|
||||
logging:
|
||||
driver: "none" # disable saving logs
|
||||
driver:
|
||||
"none" # disable saving logs
|
||||
# ports:
|
||||
# - 8025:8025 # web ui
|
||||
# 1025:1025 # smtp server
|
||||
|
||||
|
||||
|
||||
volumes:
|
||||
postgres-data: null
|
||||
|
||||
@@ -157,7 +157,7 @@ ENTERPRISE_LICENSE_KEY=
|
||||
# Insert an existing organization id or generate a valid CUID for a new one at https://www.getuniqueid.com/cuid (e.g. cjld2cjxh0000qzrmn831i7rn)
|
||||
# (Role Management is an Enterprise feature)
|
||||
# DEFAULT_ORGANIZATION_ID=
|
||||
# DEFAULT_ORGANIZATION_ROLE=admin
|
||||
# DEFAULT_ORGANIZATION_ROLE=owner
|
||||
|
||||
# Send new users to customer.io
|
||||
# CUSTOMER_IO_API_KEY=
|
||||
@@ -180,3 +180,9 @@ UNSPLASH_ACCESS_KEY=
|
||||
|
||||
# Disable custom cache handler if necessary (e.g. if deployed on Vercel)
|
||||
# CUSTOM_CACHE_DISABLED=1
|
||||
|
||||
# Azure AI settings
|
||||
# AI_AZURE_RESSOURCE_NAME=
|
||||
# AI_AZURE_API_KEY=
|
||||
# AI_AZURE_EMBEDDINGS_DEPLOYMENT_ID=
|
||||
# AI_AZURE_LLM_DEPLOYMENT_ID=
|
||||
100
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,81 +1,25 @@
|
||||
name: Bug report
|
||||
description: "Found a bug? Please fill out the sections below. \U0001F44D"
|
||||
title: "[BUG]"
|
||||
labels: bug
|
||||
assignees: []
|
||||
labels:
|
||||
- bug
|
||||
body:
|
||||
- type: textarea
|
||||
id: issue-summary
|
||||
attributes:
|
||||
label: Issue Summary
|
||||
description: A summary of the issue. This needs to be a clear detailed-rich summary.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: steps-to-reproduce
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
value: |
|
||||
1. (for example) Went to ...
|
||||
2. Clicked on...
|
||||
3. ...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: other-information
|
||||
attributes:
|
||||
label: Other information
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If applicable, add screenshots to help explain your problem.
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
id: environment
|
||||
attributes:
|
||||
label: Environment
|
||||
options:
|
||||
- label: Formbricks Cloud (app.formbricks.com)
|
||||
- label: Self-hosted Formbricks
|
||||
- type: textarea
|
||||
id: desktop-version
|
||||
attributes:
|
||||
label: Desktop (please complete the following information)
|
||||
description: |
|
||||
examples:
|
||||
- **OS**: [e.g. iOS]
|
||||
- **Browser**: [e.g. chrome, safari]
|
||||
- **Version**: [e.g. 22]
|
||||
value: |
|
||||
- OS:
|
||||
- Node:
|
||||
- npm:
|
||||
render: markdown
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
id: nodejs-version
|
||||
attributes:
|
||||
value: |
|
||||
#### Node.JS version
|
||||
|
||||
[e.g. v18.15.0]
|
||||
- type: markdown
|
||||
id: anything-else
|
||||
attributes:
|
||||
value: |
|
||||
#### Anything else?
|
||||
|
||||
- Screen recording, console logs, network requests: You can make a recording with [Loom](https://www.loom.com).
|
||||
- Anything else that you think could be an issue?
|
||||
- type: textarea
|
||||
id: issue-summary
|
||||
attributes:
|
||||
label: Issue Summary
|
||||
description: A summary of the issue. This needs to be a clear detailed-rich summary.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: other-information
|
||||
attributes:
|
||||
label: Other information (incl. screenshots, Formbricks version, steps to reproduce,...)
|
||||
validations:
|
||||
required: false
|
||||
- type: dropdown
|
||||
id: environment
|
||||
attributes:
|
||||
label: Your Environment
|
||||
options:
|
||||
- Formbricks Cloud (app.formbricks.com)
|
||||
- Self-hosted Formbricks
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Questions
|
||||
url: https://formbricks.com/discord
|
||||
about: Ask a general question about the project on our Discord server
|
||||
url: https://github.com/formbricks/formbricks/discussions
|
||||
about: Need help selfhosting or ask a general question about the project? Open a discussion
|
||||
|
||||
22
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -1,8 +1,7 @@
|
||||
name: Feature request
|
||||
description: "Suggest an idea for this project \U0001F680"
|
||||
title: "[FEATURE]"
|
||||
labels: enhancement
|
||||
assignees: []
|
||||
labels:
|
||||
- enhancement
|
||||
body:
|
||||
- type: textarea
|
||||
id: problem-description
|
||||
@@ -18,13 +17,6 @@ body:
|
||||
description: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternate-solution-description
|
||||
attributes:
|
||||
label: Describe alternatives you've considered
|
||||
description: A clear and concise description of any alternative solutions or features you've considered.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
@@ -33,15 +25,9 @@ body:
|
||||
validations:
|
||||
required: false
|
||||
- type: markdown
|
||||
id: formbricks-info
|
||||
attributes:
|
||||
value: |
|
||||
### How we code at Formbricks 🤓
|
||||
### Additional resources 🤓
|
||||
|
||||
- Follow Best Practices lined out in our [Contributor Docs](https://formbricks.com/docs/contributing/how-we-code)
|
||||
- First time: Please read our [introductory blog post](https://formbricks.com/blog/join-the-formtribe)
|
||||
- All UI components are in the package `formbricks/ui`
|
||||
- Run `pnpm go` to find a demo app to test in-app surveys at `localhost:3002`
|
||||
- Everything is type-safe.
|
||||
- We use **chatGPT** to help refactor code.
|
||||
- Check out our [Contributor Docs](https://formbricks.com/docs/developer-docs/contributing/get-started)
|
||||
- Anything unclear? [Ask in Discord](https://formbricks.com/discord)
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
name: oss.gg hack submission 🕹️
|
||||
description: "Submit your contribution for the for the oss.gg hackathon"
|
||||
title: "[🕹️]"
|
||||
labels: 🕹️ oss.gg, player submission, hacktoberfest
|
||||
assignees: []
|
||||
body:
|
||||
- type: textarea
|
||||
id: contribution-name
|
||||
attributes:
|
||||
label: What side quest or challenge are you solving?
|
||||
description: Add the name of the side quest or challenge.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: points
|
||||
attributes:
|
||||
label: Points
|
||||
description: How many points are assigned to this contribution?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: What's the task your performed?
|
||||
validations:
|
||||
- type: textarea
|
||||
id: proof
|
||||
attributes:
|
||||
label: Provide proof that you've completed the task
|
||||
description: Screenshots, loom recordings, links to the content you shared or interacted with.
|
||||
validations:
|
||||
required: true
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<!-- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. -->
|
||||
|
||||
Fixes # (issue)
|
||||
Fixes #(issue)
|
||||
|
||||
<!-- Please provide a screenshots or a loom video for visual changes to speed up reviews
|
||||
Loom Video: https://www.loom.com/
|
||||
92
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL Advanced"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
schedule:
|
||||
- cron: '17 1 * * 1'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze (${{ matrix.language }})
|
||||
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
||||
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
||||
# - https://gh.io/supported-runners-and-hardware-resources
|
||||
# - https://gh.io/using-larger-runners (GitHub.com only)
|
||||
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
|
||||
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
||||
permissions:
|
||||
# required for all workflows
|
||||
security-events: write
|
||||
|
||||
# required to fetch internal or private CodeQL packs
|
||||
packages: read
|
||||
|
||||
# only required for workflows in private repositories
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- language: javascript-typescript
|
||||
build-mode: none
|
||||
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
|
||||
# Use `c-cpp` to analyze code written in C, C++ or both
|
||||
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
|
||||
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
|
||||
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
|
||||
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
|
||||
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
|
||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
# If the analyze step fails for one of the languages you are analyzing with
|
||||
# "We were unable to automatically build your code", modify the matrix above
|
||||
# to set the build mode to "manual" for that language. Then modify this step
|
||||
# to build your code.
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
- if: matrix.build-mode == 'manual'
|
||||
shell: bash
|
||||
run: |
|
||||
echo 'If you are using a "manual" build mode for one or more of the' \
|
||||
'languages you are analyzing, replace this with the commands to build' \
|
||||
'your code, for example:'
|
||||
echo ' make bootstrap'
|
||||
echo ' make release'
|
||||
exit 1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
@@ -4,9 +4,9 @@ on:
|
||||
workflow_dispatch:
|
||||
# "Scheduled workflows run on the latest commit on the default or base branch."
|
||||
# — https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#schedule
|
||||
# schedule:
|
||||
# Runs “At 00:00.” (see https://crontab.guru)
|
||||
# - cron: "0 0 * * *"
|
||||
schedule:
|
||||
# Runs "At 00:00." (see https://crontab.guru)
|
||||
- cron: "0 0 * * *"
|
||||
jobs:
|
||||
cron-weeklySummary:
|
||||
env:
|
||||
|
||||
3
.github/workflows/e2e.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:latest
|
||||
image: pgvector/pgvector:pg17
|
||||
env:
|
||||
POSTGRES_DB: postgres
|
||||
POSTGRES_USER: postgres
|
||||
@@ -50,6 +50,7 @@ jobs:
|
||||
sed -i "s/CRON_SECRET=.*/CRON_SECRET=${RANDOM_KEY}/" .env
|
||||
sed -i "s/NEXTAUTH_SECRET=.*/NEXTAUTH_SECRET=${RANDOM_KEY}/" .env
|
||||
sed -i "s/ENTERPRISE_LICENSE_KEY=.*/ENTERPRISE_LICENSE_KEY=${RANDOM_KEY}/" .env
|
||||
echo "" >> .env
|
||||
echo "E2E_TESTING=1" >> .env
|
||||
shell: bash
|
||||
|
||||
|
||||
@@ -2,5 +2,10 @@ const baseConfig = require("./packages/config-prettier/prettier-preset");
|
||||
|
||||
module.exports = {
|
||||
...baseConfig,
|
||||
plugins: ["@trivago/prettier-plugin-sort-imports", "prettier-plugin-tailwindcss"],
|
||||
plugins: [
|
||||
"@trivago/prettier-plugin-sort-imports",
|
||||
"prettier-plugin-tailwindcss",
|
||||
"prettier-plugin-sort-json",
|
||||
],
|
||||
jsonRecursiveSort: true,
|
||||
};
|
||||
|
||||
18
.vscode/launch.json
vendored
@@ -1,21 +1,21 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch localhost:3002",
|
||||
"type": "firefox",
|
||||
"request": "launch",
|
||||
"reAttach": true,
|
||||
"request": "launch",
|
||||
"type": "firefox",
|
||||
"url": "http://localhost:3002/",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"name": "Attach",
|
||||
"type": "firefox",
|
||||
"request": "attach"
|
||||
"request": "attach",
|
||||
"type": "firefox"
|
||||
}
|
||||
]
|
||||
],
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0"
|
||||
}
|
||||
|
||||
4
.vscode/settings.json
vendored
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"typescript.preferences.importModuleSpecifier": "non-relative"
|
||||
"typescript.preferences.importModuleSpecifier": "non-relative",
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
}
|
||||
|
||||
2
LICENSE
@@ -2,7 +2,7 @@ Copyright (c) 2024 Formbricks GmbH
|
||||
|
||||
Portions of this software are licensed as follows:
|
||||
|
||||
- All content that resides under the "packages/ee/" & "apps/web/app/(ee)" directories of this repository, if these directories exist, is licensed under the license defined in "packages/ee/LICENSE".
|
||||
- All content that resides under the "packages/ee/", "apps/web/modules/ee" & "apps/web/app/(ee)" directories of this repository, if these directories exist, is licensed under the license defined in "packages/ee/LICENSE".
|
||||
- All content that resides under the "packages/js/", "packages/react-native/" and "packages/api/" directories of this repository, if that directories exist, is licensed under the "MIT" license as defined in the "LICENSE" files of these packages.
|
||||
- All third party components incorporated into the Formbricks Software are licensed under the original license provided by the owner of the applicable component.
|
||||
- Content outside of the above mentioned directories or restrictions above is available under the "AGPLv3" license as defined below.
|
||||
|
||||
@@ -51,13 +51,13 @@ In the interest of responsibly managing vulnerabilities, please adhere to the fo
|
||||
> Do not reveal the problem to others until it has been resolved.
|
||||
|
||||
1. **Send a Detailed Report**:
|
||||
- Address emails to [security@formbricks.com](mailto:security@formbricks.com).
|
||||
- Raise a security report on [Github](https://github.com/formbricks/formbricks/issues/new/choose) or send an email to [security@formbricks.com](mailto:security@formbricks.com).
|
||||
- Include:
|
||||
- Problem description.
|
||||
- Detailed, reproducible steps, with screenshots where possible.
|
||||
- Affected version(s).
|
||||
- Known possible mitigations.
|
||||
- Your Discord username or preferred contact method.
|
||||
- Your preferred contact method.
|
||||
2. **Acknowledgement of Receipt**:
|
||||
- Our security team will acknowledge receipt and provide an initial response within 48 hours.
|
||||
- Following verification of the vulnerability and the fix, a release plan will be formulated, with the fix deployed between 7 to 28 days, depending on the severity and complexity.
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
{
|
||||
"expo": {
|
||||
"name": "react-native-demo",
|
||||
"slug": "react-native-demo",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"userInterfaceStyle": "light",
|
||||
"splash": {
|
||||
"image": "./assets/splash.png",
|
||||
"resizeMode": "contain",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"jsEngine": "hermes",
|
||||
"assetBundlePatterns": ["**/*"],
|
||||
"ios": {
|
||||
"supportsTablet": true,
|
||||
"infoPlist": {
|
||||
"NSCameraUsageDescription": "Take pictures for certain activities.",
|
||||
"NSPhotoLibraryUsageDescription": "Select pictures for certain activities.",
|
||||
"NSMicrophoneUsageDescription": "Need microphone access for recording videos."
|
||||
}
|
||||
},
|
||||
"android": {
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/adaptive-icon.png",
|
||||
"backgroundColor": "#ffffff"
|
||||
"backgroundColor": "#ffffff",
|
||||
"foregroundImage": "./assets/adaptive-icon.png"
|
||||
}
|
||||
},
|
||||
"assetBundlePatterns": ["**/*"],
|
||||
"icon": "./assets/icon.png",
|
||||
"ios": {
|
||||
"infoPlist": {
|
||||
"NSCameraUsageDescription": "Take pictures for certain activities.",
|
||||
"NSMicrophoneUsageDescription": "Need microphone access for recording videos.",
|
||||
"NSPhotoLibraryUsageDescription": "Select pictures for certain activities."
|
||||
},
|
||||
"supportsTablet": true
|
||||
},
|
||||
"jsEngine": "hermes",
|
||||
"name": "react-native-demo",
|
||||
"orientation": "portrait",
|
||||
"slug": "react-native-demo",
|
||||
"splash": {
|
||||
"backgroundColor": "#ffffff",
|
||||
"image": "./assets/splash.png",
|
||||
"resizeMode": "contain"
|
||||
},
|
||||
"userInterfaceStyle": "light",
|
||||
"version": "1.0.0",
|
||||
"web": {
|
||||
"favicon": "./assets/favicon.png"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"extends": "expo/tsconfig.base",
|
||||
"compilerOptions": {
|
||||
"strict": true
|
||||
}
|
||||
},
|
||||
"extends": "expo/tsconfig.base"
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"@formbricks/js": "workspace:*",
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"lucide-react": "0.452.0",
|
||||
"next": "14.2.15",
|
||||
"next": "14.2.16",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1"
|
||||
},
|
||||
|
||||
@@ -3,4 +3,4 @@ module.exports = {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"exclude": ["node_modules"],
|
||||
"extends": "@formbricks/config-typescript/nextjs.json",
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ All you need to do is copy a `<script>` tag to your HTML head, and that’s abou
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
Refer to our [Example HTML project](https://github.com/formbricks/examples/tree/main/html) for more help! Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
|
||||
Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
|
||||
|
||||
---
|
||||
|
||||
@@ -118,7 +118,7 @@ export default App;
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
Refer to our [Example ReactJs project](https://github.com/formbricks/examples/tree/main/reactjs) for more help! Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
|
||||
Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
|
||||
|
||||
---
|
||||
|
||||
@@ -200,8 +200,6 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
Refer to our [Example NextJS App Directory project](https://github.com/formbricks/examples/tree/main/nextjs-app) for more help!
|
||||
|
||||
### Pages Directory
|
||||
|
||||
<Col>
|
||||
@@ -239,7 +237,6 @@ export default function App({ Component, pageProps }: AppProps) {
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
Refer to our [Example NextJS Pages Directory project](https://github.com/formbricks/examples/tree/main/nextjs-pages) for more help!
|
||||
|
||||
### Required customizations to be made
|
||||
|
||||
@@ -332,7 +329,7 @@ router.afterEach((to, from) => {
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
Refer to our [Example VueJs project](https://github.com/formbricks/examples/tree/main/vuejs) for more help! Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
|
||||
Now visit the [Validate your Setup](#validate-your-setup) section to verify your setup!
|
||||
|
||||
## React Native
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 201 KiB After Width: | Height: | Size: 16 KiB |
BIN
apps/docs/app/best-practices/contact-form/images/embed.webp
Normal file
|
After Width: | Height: | Size: 16 KiB |
@@ -1,7 +1,7 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import AddQuestion from "./images/add-question.webp";
|
||||
import EmailField from "./images/email-field.webp";
|
||||
import EmbedImage from "./images/embed.png";
|
||||
import EmbedImage from "./images/embed.webp";
|
||||
import MessageField from "./images/message-field.webp";
|
||||
import NameField from "./images/name-field.webp";
|
||||
import QueryImage from "./images/query-form.webp";
|
||||
@@ -159,6 +159,8 @@ After publishing the form, follow these steps to integrate it into your site:
|
||||
2. **Embed the Code**
|
||||
- Copy the provided code and paste it into your website where you want the form to appear.
|
||||
|
||||
<Note>Note: There is an options toggle button called "Embed Mode." When enabled, it updates the `src` to `"?embed=true"` and displays your survey in a minimalist design, removing padding and background for a cleaner look.</Note>
|
||||
|
||||
3. **Test the Integration**
|
||||
- Check if the form displays correctly on your site.
|
||||
- Submit a test entry to ensure everything works and notifications are received.
|
||||
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 7.0 KiB |
@@ -39,13 +39,13 @@ To get this running, you'll need a bit of time. Here are the steps we're going t
|
||||
|
||||
1. To get started, create an account for the [Formbricks Cloud](https://app.formbricks.com/auth/signup).
|
||||
|
||||
2. In the Menu (top right) you see that you can switch between a “Development” and a “Production” environment. These are two separate environments so your test data doesn’t mess up the insights from prod. Switch to “Development”:
|
||||
2. In the Menu (top right) you see that you can toggle switch between a “Development” and a “Production” environment. These are two separate environments so your test data doesn’t mess up the insights from prod. Switch to “Development”:
|
||||
|
||||
<MdxImage
|
||||
src={SwitchToDev}
|
||||
alt="switch to dev environment"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
className="max-w-full rounded-lg sm:max-w-xs"
|
||||
/>
|
||||
|
||||
3. Then, create a survey using the template “Docs Feedback”:
|
||||
|
||||
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 462 B |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 16 KiB |
@@ -115,7 +115,7 @@ Lastly, scroll down to “Recontact Options”. Here you have full freedom to de
|
||||
src={RecontactOptions}
|
||||
alt="Set recontact options"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
className="max-w-full rounded-lg sm:max-w-2xl"
|
||||
/>
|
||||
|
||||
### 7. Congrats! You’re ready to publish your survey 💃
|
||||
|
||||
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 19 KiB |
BIN
apps/docs/app/best-practices/quiz-time/conditional-logic.webp
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
apps/docs/app/best-practices/quiz-time/ending-logic.webp
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
178
apps/docs/app/best-practices/quiz-time/page.mdx
Normal file
@@ -0,0 +1,178 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SingleSelect from "./single-select.webp";
|
||||
import Quiz from "./quiz.webp";
|
||||
import Score from "./score.webp"
|
||||
import AddLogic from "./conditional-logic.webp";
|
||||
import WhenThen from "./when-then.webp";
|
||||
import EndingLogic from "./ending-logic.webp";
|
||||
import PassFail from "./pass-fail.webp";
|
||||
|
||||
|
||||
export const metadata = {
|
||||
title: "How to Create a Quiz Using Formbricks - Step-by-Step Guide",
|
||||
description:
|
||||
"Learn to leverage Formbricks to create Quizzes. Follow our detailed step-by-step guide to build quizzes with custom logic and multiple endings.",
|
||||
};
|
||||
|
||||
|
||||
# Creating a quiz with Formbricks - Step-by-step Guide
|
||||
|
||||
|
||||
Welcome to this guide on creating engaging quizzes with Formbricks! Quizzes help you capture customer insights, explore user personalities, or simply add fun for your team. With Formbricks, you can personalize quizzes in minutes add scores, customize backgrounds, and more, all without any technical skills!
|
||||
|
||||
|
||||
## What we'll build
|
||||
|
||||
|
||||
By the end of this tutorial, you'll have created a simple trivia Quiz featuring:
|
||||
|
||||
|
||||
1. Score calculations.
|
||||
2. Multiple endings depending on the score.
|
||||
|
||||
|
||||
## Setting up the form
|
||||
|
||||
|
||||
First, make sure you have a Formbricks account. If not, you can create one [here](https://app.formbricks.com):
|
||||
|
||||
|
||||
1. Head to the Surveys page and click on **New Survey**.
|
||||
2. Select Start from Scratch to create a new form.
|
||||
3. Go to the settings and select form type as **Link Survey**
|
||||
4. In the form editor, click the three dots next to a question, then select Change Question Type and choose **Single-Select**.
|
||||
|
||||
|
||||
<MdxImage
|
||||
src={SingleSelect}
|
||||
alt="Change Question type to Single-Select"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-2xl"
|
||||
/>
|
||||
|
||||
|
||||
5. Add a welcoming statement to greet your users and explain the Quiz's purpose.
|
||||
6. Personalize the greeting to make it inviting and encourage engagement.
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** While we’re creating a Link Survey here, the process is similar for Web and App surveys.
|
||||
|
||||
|
||||
## Adding the questions
|
||||
|
||||
|
||||
Next, let's create a question for example with multiple options:
|
||||
|
||||
|
||||
What country has the longest coastline in the world?
|
||||
A) Canada
|
||||
B) Japan
|
||||
C) India
|
||||
D) Nepal
|
||||
|
||||
|
||||
<MdxImage
|
||||
src={Quiz}
|
||||
alt="Sample Question"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-xl"
|
||||
/>
|
||||
|
||||
|
||||
## Calculate Score
|
||||
|
||||
|
||||
Now that we have our question ready, let’s add the logic to calculate scores.
|
||||
|
||||
|
||||
1. Scroll down in the editor and click on variables.
|
||||
2. Create a new variable named `score` with a default value of 0
|
||||
|
||||
|
||||
<MdxImage
|
||||
src={Score}
|
||||
alt="Create Variable named Score image"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-xl"
|
||||
/>
|
||||
|
||||
|
||||
3. Now go back to the question and expand the advanced settings by clicking on `> Show Advanced Settings`.
|
||||
4. Under the conditional logic you should see the option to `Add Logic`. Click on that.
|
||||
|
||||
|
||||
<MdxImage
|
||||
src={AddLogic}
|
||||
alt="Add Logic Button"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-xl"
|
||||
/>
|
||||
|
||||
|
||||
5. Now you should see conditional logic. Customize the logic to match your needs for example:
|
||||
|
||||
|
||||
**When** `question` equals `YOUR_ANSWER_HERE` **Then** `Calculate` `score` `Add +` `01`. So it should look something like this.
|
||||
|
||||
|
||||
<MdxImage
|
||||
src={WhenThen}
|
||||
alt="When-Then Conditional Logic"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-xl"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
|
||||
6. Let's duplicate and customize these questions. Click on the duplicate icon at the top of the question.
|
||||
7. Now edit the questions, options, and answers in the **conditional logic**
|
||||
|
||||
|
||||
## Creating Multiple Endings Based on Scores
|
||||
|
||||
|
||||
Once you have all the questions and the calculation logic in place, it’s time to customize the endings. Scroll down to the Ending Card section. We will create two cards for this quiz: one for when the user fails the quiz and another for when the user passes.
|
||||
|
||||
|
||||
1. Customize the ending card.
|
||||
2. Display the score by typing `@score`. ( You can address all the variables or questions by just typing @ ).
|
||||
3. Add logic to the last question. ( this is necessary to redirect the user based on the score ). Kind of like this:
|
||||
|
||||
|
||||
**When** `score` >= `03` **Then** `Jump to` `Pass`. So it should look something like this.
|
||||
|
||||
|
||||
<MdxImage
|
||||
src={EndingLogic}
|
||||
alt="Conditional Logic for ending card"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-xl"
|
||||
/>
|
||||
|
||||
|
||||
4. Ensure that the Fail card is positioned above the Pass card. This allows any condition that does not meet the criteria of being greater than or equal to 3 to jump to the Fail card.
|
||||
|
||||
|
||||
<MdxImage
|
||||
src={PassFail}
|
||||
alt="Pass or Fail ending Cards"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-xl"
|
||||
/>
|
||||
|
||||
|
||||
5. That's it! Now you can save and publish the quiz.
|
||||
|
||||
|
||||
# Wrapping Up
|
||||
|
||||
|
||||
Congratulations! You’ve successfully created a Quiz with Formbricks. You can play around with the quiz that we just created [here](https://app.formbricks.com/s/cm2wwt3vu0001ir8o7ys0bezz).
|
||||
|
||||
|
||||
A great quiz can serve as an excellent lead generator, a job fit checker, or just a fun icebreaker for your team. You now have the skills to build that! If you want to read more about building quizzes and how you can create a Job Fit Quiz check this article [here](https://www.harshbhat.me/blog/formbricks-quiz).
|
||||
|
||||
|
||||
BIN
apps/docs/app/best-practices/quiz-time/pass-fail.webp
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
apps/docs/app/best-practices/quiz-time/quiz.webp
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
apps/docs/app/best-practices/quiz-time/score.webp
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
apps/docs/app/best-practices/quiz-time/single-select.webp
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
apps/docs/app/best-practices/quiz-time/when-then.webp
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
@@ -67,7 +67,19 @@ git clone https://github.com/formbricks/formbricks && cd formbricks
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
2. Install Node.JS packages via pnpm. Don't have pnpm? Get it [here](https://pnpm.io/installation)
|
||||
2. Setup Node.JS with nvm:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Setup Node version with nvm">
|
||||
|
||||
```bash
|
||||
nvm install && nvm use
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
3. Install Node.JS packages via pnpm. Don't have pnpm? Get it [here](https://pnpm.io/installation)
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Install dependencies via pnpm">
|
||||
@@ -79,7 +91,7 @@ pnpm install
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
3. Create a `.env` file based on `.env.example`. It's already preset to work with the local development setup but you can also change values if needed.
|
||||
4. Create a `.env` file based on `.env.example`. It's already preset to work with the local development setup but you can also change values if needed.
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Define environment variables">
|
||||
@@ -91,7 +103,7 @@ cp .env.example .env
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
4. Generate & set some secret values mandatory for the `ENCRYPTION_KEY`, `NEXTAUTH_SECRET` and `CRON_SECRET` in the .env file. You can use the following command to generate the random string of required length:
|
||||
5. Generate & set some secret values mandatory for the `ENCRYPTION_KEY`, `NEXTAUTH_SECRET` and `CRON_SECRET` in the .env file. You can use the following command to generate the random string of required length:
|
||||
|
||||
- For Linux
|
||||
|
||||
@@ -121,7 +133,7 @@ sed -i '' '/^CRON_SECRET=/s|.*|CRON_SECRET='$(openssl rand -hex 32)'|' .env
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
5. Make sure you have [`Docker`](https://docs.docker.com/compose/) & [`docker-compose`](https://docs.docker.com/compose/) installed and running on your machine. Then run the following command to start the Formbricks dev setup:
|
||||
6. Make sure you have [`Docker`](https://docs.docker.com/compose/) & [`docker-compose`](https://docs.docker.com/compose/) installed and running on your machine. Then run the following command to start the Formbricks dev setup:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Start Formbricks Dev Setup">
|
||||
|
||||
@@ -48,7 +48,7 @@ Initialize the Formbricks JS Client for surveys. When used in a web app, pass a
|
||||
<CodeGroup title="Initialize Formbricks">
|
||||
|
||||
```javascript
|
||||
import formbricks from "@formbricks/js/app";
|
||||
import formbricks from "@formbricks/js";
|
||||
|
||||
formbricks.init({
|
||||
environmentId: "<your-environment-id>", // required
|
||||
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 20 KiB |
@@ -6,71 +6,98 @@ import IndvInvite from "./images/individual-invite.webp";
|
||||
import MenuItem from "./images/organization-settings-menu.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Organization Access Roles",
|
||||
title: "User Management",
|
||||
description:
|
||||
"Assign different roles to organization members to grant them specific rights like creating surveys, viewing responses, or managing organization members.",
|
||||
};
|
||||
|
||||
# Organization Access Roles
|
||||
|
||||
Assign different roles to organization members to grant them specific rights like creating surveys, viewing responses, or managing organization members.
|
||||
Learn about the different organization-level and team-level roles and how they affect permissions in Formbricks.
|
||||
|
||||
## Memberships
|
||||
|
||||
Permissions in Formbricks are broadly handled using organization-level roles, which apply to all teams and projects in the organization. Users on a self-hosting and Enterprise plan, have access to team-level roles, which enable more granular permissions.
|
||||
|
||||
<Note>
|
||||
Access Roles is a feature of the **Enterprise Edition**. In the **Community Edition** and on the **Free**
|
||||
and **Startup** plan in the Cloud you can invite unlimited organization members as `Admins`.
|
||||
and **Startup** plan in the Cloud you can invite unlimited organization members as `Owner`.
|
||||
</Note>
|
||||
|
||||
Here are the different access permissions, ranked from highest to lowest access
|
||||
|
||||
1. Owner
|
||||
2. Admin
|
||||
3. Developer
|
||||
4. Editor
|
||||
5. Viewer
|
||||
2. Manager
|
||||
3. Billing
|
||||
4. Member
|
||||
|
||||
### Organisational level
|
||||
|
||||
All users and their organization-level roles are listed in **Organization Settings > General**. Users can hold any of the following org-level roles:
|
||||
|
||||
- **Billing** users can manage payment and compliance details in the organization.
|
||||
- **Org Members** can view most data in the organization and act in the products they are members of. They cannot join products on their own and need to be assigned.
|
||||
- **Org Managers** have full management access to all teams and products. They can also manage the organization's membership. Org Managers can perform Team Admin actions without needing to join the team. They cannot change other organization settings.
|
||||
- **Org Owners** have full access to the organization, its data, and settings. Org Owners can perform Team Admin actions without needing to join the team.
|
||||
|
||||
### Permissions at product level
|
||||
|
||||
- **read**: read access to all resources (except settings) in the product.
|
||||
- **read & write**: read & write access to all resources (except settings) in the product.
|
||||
- **manage**: read & write access to all resources including settings in the product.
|
||||
|
||||
### Team-level Roles
|
||||
|
||||
- **Team Contributors** can view and act on surveys and responses.
|
||||
- **Team Admins** have additional permissions to manage their team's membership and products. These permissions are granted at the team-level, and don't apply to teams where they're not a Team Admin.
|
||||
|
||||
For more information on user roles & permissions, see below:
|
||||
|
||||
| | Owner | Admin | Editor | Developer | Viewer |
|
||||
| -------------------------------- | ----- | ----- | ------ | --------- | ------ |
|
||||
| **Organization** | | | | | |
|
||||
| Update organization | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| Delete organization | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| Add new Member | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| Delete Member | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| Update Member Access | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| Update Billing | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| **Product** | | | | | |
|
||||
| Create Product | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| Update Product Name | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| Update Product Recontact Options | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| Update Look & Feel | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| Update Survey Languages | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| Delete Product | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Surveys** | | | | | |
|
||||
| Create New Survey | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| Edit Survey | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| Delete Survey | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| View survey results | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| **Response** | | | | | |
|
||||
| Delete response | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| Add tags on response | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| Edit tags on response | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Actions** | | | | | |
|
||||
| Create Action | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| Update Action | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| Delete Action | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| **API Keys** | | | | | |
|
||||
| Create API key | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| Update API key | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| Delete API key | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Tags** | | | | | |
|
||||
| Create tags | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| Update tags | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| Delete tags | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| **People** | | | | | |
|
||||
| Delete Person | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Integrations** | | | | | |
|
||||
| Manage Integrations | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| | Owner | Manager | Billing | Member |
|
||||
| -------------------------------- | ----- | ------- | ------- | ------ |
|
||||
| **Organization** | | | | |
|
||||
| Update organization | ✅ | ❌ | ❌ | ❌ |
|
||||
| Delete organization | ✅ | ❌ | ❌ | ❌ |
|
||||
| Add new Member | ✅ | ✅ | ❌ | ❌ |
|
||||
| Delete Member | ✅ | ✅ | ❌ | ❌ |
|
||||
| Update Member Access | ✅ | ✅ | ❌ | ❌ |
|
||||
| Update Billing | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Product** | | | | |
|
||||
| Create Product | ✅ | ✅ | ❌ | ❌ |
|
||||
| Update Product Name | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| Update Product Recontact Options | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| Update Look & Feel | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| Update Survey Languages | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| Delete Product | ✅ | ✅ | ❌ | ❌ |
|
||||
| **Surveys** | | | | |
|
||||
| Create New Survey | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Edit Survey | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Delete Survey | ✅ | ✅ | ❌ | ✅\* |
|
||||
| View survey results | ✅ | ✅ | ❌ | ✅ |
|
||||
| **Response** | | | | |
|
||||
| Delete response | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Add tags on response | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Edit tags on response | ✅ | ✅ | ❌ | ✅\* |
|
||||
| **Actions** | | | | |
|
||||
| Create Action | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Update Action | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Delete Action | ✅ | ✅ | ❌ | ✅\* |
|
||||
| **API Keys** | | | | |
|
||||
| Create API key | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| Update API key | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| Delete API key | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| **Tags** | | | | |
|
||||
| Create tags | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Update tags | ✅ | ✅ | ❌ | ✅\* |
|
||||
| Delete tags | ✅ | ✅ | ❌ | ✅\*\* |
|
||||
| **People** | | | | |
|
||||
| Delete Person | ✅ | ✅ | ❌ | ✅\* |
|
||||
| **Integrations** | | | | |
|
||||
| Manage Integrations | ✅ | ✅ | ❌ | ✅\* |
|
||||
|
||||
\* - for the read & write permissions team members
|
||||
|
||||
\*\* - for the manage permissions team members
|
||||
|
||||
## Inviting organization members
|
||||
|
||||
@@ -107,7 +134,7 @@ There are two ways to invite organization members: One by one or in bulk.
|
||||
|
||||
<Note>
|
||||
Access Roles is a feature of the **Enterprise Edition**. In the **Community Edition** and on the **Free**
|
||||
and **Startup** plan in the Cloud you can invite unlimited organization members as `Admins`.
|
||||
and **Startup** plan in the Cloud you can invite unlimited organization members as `Owners`.
|
||||
</Note>
|
||||
|
||||
Formbricks sends an email to the organization member with an invitation link. The organization member can accept the invitation or create a new account by clicking on the link.
|
||||
|
||||
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
45
apps/docs/app/global/add-image-or-video-question/page.mdx
Normal file
@@ -0,0 +1,45 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import AddImageOrVideoToQuestionImage from "./images/add-image-or-video-to-question-image.webp";
|
||||
import AddImageOrVideoToQuestionVideo from "./images/add-image-or-video-to-question-video.webp";
|
||||
import AddImageOrVideoToQuestion from "./images/add-image-or-video-to-question.webp";
|
||||
|
||||
#### Add Image or Video to a Question
|
||||
|
||||
Enhance your questions by adding images or videos. This makes instructions clearer and the survey more engaging.
|
||||
|
||||
## How to Add Images
|
||||
|
||||
Click the icon on the right side of the question to add an image or video:
|
||||
|
||||
<MdxImage
|
||||
src={AddImageOrVideoToQuestion}
|
||||
alt="Overview of adding image or video to question"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Upload an image by clicking the upload icon or dragging the file:
|
||||
|
||||
<MdxImage
|
||||
src={AddImageOrVideoToQuestionImage}
|
||||
alt="Overview of adding image to question"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
## How to Add Videos
|
||||
Toggle to add a video via link:
|
||||
|
||||
<MdxImage
|
||||
src={AddImageOrVideoToQuestionVideo}
|
||||
alt="Overview of adding video to question"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Supported Video Platforms
|
||||
|
||||
We support YouTube, Vimeo, and Loom URLs.
|
||||
|
||||
<Note>**YouTube Privacy Mode**: This option reduces tracking by converting YouTube URLs to no-cookie URLs. It only works with YouTube.</Note>
|
||||
BIN
apps/docs/app/global/question-type/address/images/address.webp
Normal file
|
After Width: | Height: | Size: 10 KiB |
36
apps/docs/app/global/question-type/address/page.mdx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import Address from "./images/address.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Address
|
||||
|
||||
The Address question type allows respondents to input their address details, including multiple fields such as address lines, city, state, and country. You can configure the question by adding a title, an optional description, and toggling specific fields to be required.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/m8w91e8wi52pdao8un1f4twu" />
|
||||
|
||||
## Elements
|
||||
|
||||
<MdxImage
|
||||
src={Address}
|
||||
alt="Overview of Address question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Question
|
||||
Provide a question to describe the address information you are requesting.
|
||||
|
||||
### Description
|
||||
Optionally, add a description to guide the user.
|
||||
|
||||
### Toggle Fields
|
||||
You can choose to show and require any or all of the following fields in the form:
|
||||
- Address Line 1
|
||||
- Address Line 2
|
||||
- City
|
||||
- State
|
||||
- Zip Code
|
||||
- Country
|
||||
|
||||
BIN
apps/docs/app/global/question-type/consent/images/consent.webp
Normal file
|
After Width: | Height: | Size: 18 KiB |
28
apps/docs/app/global/question-type/consent/page.mdx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import Consent from "./images/consent.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Consent
|
||||
|
||||
The Consent card is used to obtain user agreement regarding a product, service, or policy. It features a bold statement or question as the title, followed by a brief description. At the end of the card, users can confirm their consent by checking a checkbox to indicate their agreement.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/orxp15pca6x2nfr3v8pttpwm" />
|
||||
|
||||
## Elements
|
||||
<MdxImage
|
||||
src={Consent}
|
||||
alt="Overview of Consent question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
A bold statement or question asking for user consent, displayed prominently at the top of the card.
|
||||
|
||||
### Description
|
||||
A short explanation or additional context for the consent request, displayed below the title. The text can be formatted, and hyperlinks are allowed within the description.
|
||||
|
||||
### Checkbox
|
||||
At the bottom of the card, users can confirm their agreement by checking the box, indicating their consent to the question or statement above. The label for the checkbox is also editable.
|
||||
BIN
apps/docs/app/global/question-type/contact/images/contact.webp
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
36
apps/docs/app/global/question-type/contact/page.mdx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import Contact from "./images/contact.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Contact Info
|
||||
|
||||
The Contact Info question type allows respondents to provide their basic contact information such as name, email, and phone number. You can customize the form with a title, an optional description, and control which fields to display and require.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/z2zjoonfeythx5n6z5qijbsg" />
|
||||
|
||||
## Elements
|
||||
<MdxImage
|
||||
src={Contact}
|
||||
alt="Overview of Contact Info question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
|
||||
Specify a title to describe the information you're collecting.
|
||||
|
||||
### Description
|
||||
|
||||
Optionally, add a description to give additional context.
|
||||
|
||||
### Toggle Fields
|
||||
|
||||
You can choose to show and require any or all of the following fields:
|
||||
- First Name
|
||||
- Last Name
|
||||
- Email
|
||||
- Phone Number
|
||||
- Company
|
||||
BIN
apps/docs/app/global/question-type/date/images/date.webp
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
32
apps/docs/app/global/question-type/date/page.mdx
Normal file
@@ -0,0 +1,32 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import Date from "./images/date.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Date
|
||||
|
||||
The Date question type allows respondents to provide a date, such as when they are available or when an event is scheduled. It features a title to guide the respondent on what date to enter, and an optional description to provide further details or context.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/rk844spc8ffls25vzkxzzhse" />
|
||||
|
||||
## Elements
|
||||
<MdxImage
|
||||
src={Date}
|
||||
alt="Overview of Date question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
Add a clear title to inform the respondent what date you are asking for.
|
||||
|
||||
### Description
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Date Format
|
||||
Choose from multiple date formats for the input:
|
||||
- MM-DD-YYYY
|
||||
- DD-MM-YYYY
|
||||
- YYYY-MM-DD
|
||||
|
||||
|
After Width: | Height: | Size: 9.2 KiB |
34
apps/docs/app/global/question-type/file-upload/page.mdx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import FileUpload from "./images/file-upload.webp";
|
||||
|
||||
#### Questions Type
|
||||
|
||||
# File Upload
|
||||
|
||||
The File Upload question type allows respondents to upload files related to your survey, such as production documents or requirement specifications. It features a title to guide the user on what to upload and an optional description to provide additional context.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/oo4e6vva48w0trn01ht8krwo" />
|
||||
|
||||
## Elements
|
||||
<MdxImage
|
||||
src={FileUpload}
|
||||
alt="Overview of Fill Upload question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
Add a clear title that informs the respondent about the purpose of the file upload.
|
||||
|
||||
### Description
|
||||
Provide an optional description to give respondents more details or instructions about what files they need to upload.
|
||||
|
||||
### Allow Multiple Files
|
||||
Enable this option to allow respondents to upload multiple files at once.
|
||||
|
||||
### Max File Size
|
||||
You can set a maximum file size limit, and an input box will appear to specify the size in MB.
|
||||
|
||||
### File Type Restrictions
|
||||
You can restrict the allowed file types. An input box will appear where you can specify the file formats, such as `.pdf`, `.jpg`, `.docx`, etc.
|
||||
|
After Width: | Height: | Size: 11 KiB |
43
apps/docs/app/global/question-type/free-text/page.mdx
Normal file
@@ -0,0 +1,43 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import FreeText from "./images/free-text.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Free Text",
|
||||
description: "Free text questions allow respondents to enter a custom answer.",
|
||||
};
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Free Text
|
||||
|
||||
Free text questions allow respondents to enter a custom answer. Displays a title and an input field for the respondent to type in.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/cm2b2eftv000012b0l3htbu0a" />
|
||||
|
||||
## Elements
|
||||
<MdxImage
|
||||
src={FreeText}
|
||||
alt="Overview of Free Text question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
Add a clear title to inform the respondent what information you are asking for.
|
||||
|
||||
### Description
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Placeholder
|
||||
Specify a placeholder text to display in the input field.
|
||||
|
||||
### Input Type
|
||||
|
||||
Choose the type of input field to display. Options include:
|
||||
|
||||
- **Text**: A text area input. This can be converted to a single line input field if needed, by toggling the _"Long answer"_ switch at the bottom of the question segment.
|
||||
- **Email**: A single-line text input that validates the input as an email address.
|
||||
- **URL**: A single-line text input that validates the input as a URL.
|
||||
- **Number**: A single-line text input that validates the input as a number and shows "increase" and "decrease" buttons.
|
||||
- **Phone**: A single-line text input that validates the input as a phone number.
|
||||
BIN
apps/docs/app/global/question-type/matrix/images/matrix.webp
Normal file
|
After Width: | Height: | Size: 12 KiB |
41
apps/docs/app/global/question-type/matrix/page.mdx
Normal file
@@ -0,0 +1,41 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import Matrix from "./images/matrix.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Matrix
|
||||
|
||||
Matrix questions allow respondents to select a value for each option presented in rows. The values range from 0 to a user-defined maximum (e.g., 0 to X). The selection is made using radio buttons, and users can choose any value within the defined range, including 0.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/obqeey0574jig4lo2gqyv51e" />
|
||||
|
||||
## Elements
|
||||
|
||||
<MdxImage
|
||||
src={Matrix}
|
||||
alt="Overview of Matrix question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
|
||||
Add a clear title to inform the respondent what information you are asking for.
|
||||
|
||||
### Description
|
||||
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Rows
|
||||
|
||||
Define the options shown on the left side of the matrix. These represent the items for which users will select a value.
|
||||
|
||||
### Columns
|
||||
|
||||
Represent the range of values from 0 to X (right side of the screen). Users can choose any value, including 0, using radio buttons.
|
||||
|
||||
### Select ordering
|
||||
|
||||
- Keep current order: This will keep the order of options the same for all respondents.
|
||||
- Randomize all: This will randomize the options for each respondent.
|
||||
|
After Width: | Height: | Size: 16 KiB |
36
apps/docs/app/global/question-type/multi-select/page.mdx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import MultiSelect from "./images/multi-select.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Multi Select",
|
||||
description: "Multi select questions allow respondents to select several answers from a list",
|
||||
};
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Multi Select
|
||||
|
||||
Multi select questions allow respondents to select several answers from a list. Displays a title and a list of checkboxes for the respondent to choose from.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/jhyo6lwzf6eh3fyplhlp7h5f" />
|
||||
|
||||
## Elements
|
||||
<MdxImage
|
||||
src={MultiSelect}
|
||||
alt="Overview of Multi Select question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
Add a clear title to inform the respondent what information you are asking for.
|
||||
|
||||
### Description
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Options
|
||||
Define the options shown in the list. These represent the items for which users will select.
|
||||
|
||||
Other than the fact that respondents can select multiple options, multi select questions are similar to [single select](/global/question-types/single-select) questions.
|
||||
|
||||
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,31 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import NetPromoterScore from "./images/net-promoter-score.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Net Promoter Score
|
||||
|
||||
Net Promoter Score questions allow respondents to rate a question on a scale from 0 to 10. Displays a title and a list of radio buttons for the respondent to choose from.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/vqmpasmnt5qcpsa4enheips0" />
|
||||
|
||||
## Elements
|
||||
<MdxImage
|
||||
src={NetPromoterScore}
|
||||
alt="Overview of Net Promoter Score question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
Add a clear title to inform the respondent what information you are asking for.
|
||||
|
||||
### Description
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Labels
|
||||
Add labels for the lower and upper bounds of the score. The default is "Not at all likely" and "Extremely likely".
|
||||
|
||||
### Add color coding
|
||||
Add color coding to the score. This will show a color bar above the score.
|
||||
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,36 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import PictureSelection from "./images/picture-selection.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Picture Selection",
|
||||
description: "Picture selection questions allow respondents to select one or more images from a list",
|
||||
};
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Picture Selection
|
||||
|
||||
Picture selection questions allow respondents to select one or more images from a list. Displays a title and a list of images for the respondent to choose from.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/xtgmwxlk7jxxr4oi6ym7odki" />
|
||||
|
||||
## Elements
|
||||
<MdxImage
|
||||
src={PictureSelection}
|
||||
alt="Overview of Picture Selection question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
Add a clear title to inform the respondent what information you are asking for.
|
||||
|
||||
### Description
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Images
|
||||
Images can be uploaded via click or drag and drop. At least two images are required.
|
||||
|
||||
### Allow Multi Select
|
||||
This option allows user to select more than one image.
|
||||
BIN
apps/docs/app/global/question-type/ranking/images/ranking.webp
Normal file
|
After Width: | Height: | Size: 10 KiB |
32
apps/docs/app/global/question-type/ranking/page.mdx
Normal file
@@ -0,0 +1,32 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import Ranking from "./images/ranking.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Ranking
|
||||
|
||||
Ranking questions let respondents select options in order from 1 to the total number of options. As they make their choices, the list is automatically rearranged in numerical order.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/z6s84x9wbyk0yqqtfaz238px" />
|
||||
|
||||
## Elements
|
||||
<MdxImage
|
||||
src={Ranking}
|
||||
alt="Overview of Ranking question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
Add a clear title to inform the respondent what information you are asking for.
|
||||
|
||||
### Description
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Options
|
||||
You need to add at least two options so that users can rearrange them in numerical order based on their selection.
|
||||
|
||||
### Select ordering
|
||||
- Keep current order: This will keep the order of options the same for all respondents.
|
||||
- Randomize all: This will randomize the options for each respondent.
|
||||
BIN
apps/docs/app/global/question-type/rating/images/rating.webp
Normal file
|
After Width: | Height: | Size: 12 KiB |
39
apps/docs/app/global/question-type/rating/page.mdx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import Rating from "./images/rating.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Rating",
|
||||
description: "Rating questions allow respondents to rate questions on a scale",
|
||||
};
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Rating
|
||||
|
||||
Rating questions allow respondents to rate questions on a scale. Displays a title and a rating scale consisting of a number of images and labels for the lower and upper ends of the scale.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/cx7u4n6hwvc3nztuk4vdezl9" />
|
||||
|
||||
## Elements
|
||||
<MdxImage
|
||||
src={Rating}
|
||||
alt="Overview of Rating question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
Add a clear title to inform the respondent what information you are asking for.
|
||||
|
||||
### Description
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Scale
|
||||
Select the icon to be used for the rating scale. The options include: stars, numbers or smileys. The default is stars.
|
||||
|
||||
### Range
|
||||
Select the range of the rating scale. the options include: 3, 4, 5, 7 or 10. The default is 5.
|
||||
|
||||
### Labels
|
||||
Add labels for the lower and upper bounds of the rating scale. The default is "Not good" and "Very good".
|
||||
|
After Width: | Height: | Size: 10 KiB |
31
apps/docs/app/global/question-type/schedule/page.mdx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import ScheduleCall from "./images/schedule-call.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Schedule A Meeting
|
||||
|
||||
The Schedule A Meeting question type allows respondents to book a meeting by selecting a date and time. It includes a title to guide the respondent, along with an optional description to provide additional context for the meeting setup.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/hx08x27c2aghywh57rroe6fi" />
|
||||
|
||||
## Elements
|
||||
<MdxImage
|
||||
src={ScheduleCall}
|
||||
alt="Overview of Schedule question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
Add a clear title to inform the respondent what information you are asking for.
|
||||
|
||||
### Description
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Cal.com Username/Event
|
||||
Add an input box where users can enter their [`cal.com`](https://cal.com/) username and event URL (e.g., `username/event`).
|
||||
|
||||
### Custom Hostname (Optional)
|
||||
Enable an input box for adding a custom hostname, which is necessary if using a self-hosted instance of [`cal.com`](https://cal.com/docs/self-hosting/installation).
|
||||
|
After Width: | Height: | Size: 12 KiB |
44
apps/docs/app/global/question-type/single-select/page.mdx
Normal file
@@ -0,0 +1,44 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import SingleSelect from "./images/single-select.webp";
|
||||
|
||||
export const metadata = {
|
||||
title: "Single Select",
|
||||
description: "Single select questions allow respondents to select one answer from a list",
|
||||
};
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Single Select
|
||||
|
||||
Single select questions allow respondents to select one answer from a list. Displays a title and a list of radio buttons for the respondent to choose from.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/wybd3v3cxpdfve4472fu3lhi" />
|
||||
|
||||
## Elements
|
||||
<MdxImage
|
||||
src={SingleSelect}
|
||||
alt="Overview of Single Select question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
Add a clear title to inform the respondent what information you are asking for.
|
||||
|
||||
### Description
|
||||
Provide an optional description with further instructions.
|
||||
|
||||
### Options
|
||||
The list of answers the respondent can choose from.
|
||||
|
||||
### Additional Actions
|
||||
|
||||
- Add "Other": Adds an "Other" option to allow respondents to enter a custom answer. This will show two inputs, one for the label text and one for the placeholder.
|
||||
|
||||
- Convert to Multiple Select: Converts the question to a multiple select question. This will show checkboxes instead of radio buttons.
|
||||
|
||||
- Order dropdown: Allows you to choose the order in which the options are displayed.
|
||||
- Keep current order: Options will be displayed in the order you added them.
|
||||
- Randomize all: Options will be displayed in a random order.
|
||||
- Randomize all except last option: Options will be displayed in a random order, except for the last one.
|
||||
|
After Width: | Height: | Size: 13 KiB |
29
apps/docs/app/global/question-type/statement-cta/page.mdx
Normal file
@@ -0,0 +1,29 @@
|
||||
import { MdxImage } from "@/components/MdxImage";
|
||||
import SurveyEmbed from "@/components/SurveyEmbed";
|
||||
import StatementCTA from "./images/statement-CTA.webp";
|
||||
|
||||
#### Question Type
|
||||
|
||||
# Statement (Call to Action)
|
||||
|
||||
The Statement question type allows you to display descriptive information in your survey, such as a message or instruction. It consists of a title (can be Question or Short Note) and a description, which can be a brief note(realted to CTA) or guideline. Instead of collecting input, this type includes a call to action button for further steps, such as booking an interview call.
|
||||
|
||||
<SurveyEmbed surveyUrl="https://app.formbricks.com/s/k3p7r7riyy504u4zziqat8zj" />
|
||||
|
||||
## Elements
|
||||
<MdxImage
|
||||
src={StatementCTA}
|
||||
alt="Overview of Statement question type"
|
||||
quality="100"
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
### Title
|
||||
This is the main question or heading that appears at the top of the card.
|
||||
|
||||
### Description
|
||||
A brief note or instruction displayed under the title, typically used to provide context or instructions for the next step.
|
||||
|
||||
### Button Options
|
||||
- Button to continue in survey: This will continue respondent with the survey, form or fillups.
|
||||
- Button to link to external URL: Selecting this option will open-up URL input box below when us set URL the button will redirect to your setted link.
|
||||
@@ -63,7 +63,7 @@ These variables are present inside your machine’s docker-compose file. Restart
|
||||
| TELEMETRY_DISABLED | Disables telemetry if set to 1. | optional | |
|
||||
| DEFAULT_BRAND_COLOR | Default brand color for your app (Can be overwritten from the UI as well). | optional | #64748b |
|
||||
| DEFAULT_ORGANIZATION_ID | Automatically assign new users to a specific organization when joining | optional | |
|
||||
| DEFAULT_ORGANIZATION_ROLE | Role of the user in the default organization. | optional | admin |
|
||||
| DEFAULT_ORGANIZATION_ROLE | Role of the user in the default organization. | optional | owner |
|
||||
| OIDC_DISPLAY_NAME | Display name for Custom OpenID Connect Provider | optional | |
|
||||
| OIDC_CLIENT_ID | Client ID for Custom OpenID Connect Provider | optional (required if OIDC auth is enabled) | |
|
||||
| OIDC_CLIENT_SECRET | Secret for Custom OpenID Connect Provider | optional (required if OIDC auth is enabled) | |
|
||||
|
||||
@@ -48,7 +48,7 @@ We have step-by-step guides to configure our third-party integrations with a sel
|
||||
<Note>
|
||||
{" "}
|
||||
Once you’ve configured your integration, See our Integration sections to see how to use them within your Formbricks
|
||||
app [here](/how-to-formbricks/integrations)
|
||||
app [here](/developer-docs/integrations/airtable)
|
||||
</Note>
|
||||
|
||||
### Step by Step Guides
|
||||
@@ -102,12 +102,11 @@ Enabling the Airtable Integration in a self-hosted environment requires creating
|
||||
/>
|
||||
|
||||
5. Click on the "Save" button and you are done
|
||||
6. Now just copy **Client ID** and **Redirect URL** for your integration & add it to your **Formbricks environment variables** as in the docker compose file:
|
||||
6. Now just copy **Client ID** for your integration & add it to your **Formbricks environment variables** as in the docker compose file:
|
||||
|
||||
- `AIRTABLE_CLIENT_ID`
|
||||
- `AIRTABLE_REDIRECT_URL`
|
||||
|
||||
Voila! You have successfully enabled the Airtable integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in [Airtable Integration with Formbricks](/integrations#airtable) section to link an Airtable with Formbricks.
|
||||
Voila! You have successfully enabled the Airtable integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in [Airtable Integration with Formbricks](/developer-docs/integrations/airtable) section to link an Airtable with Formbricks.
|
||||
|
||||
## Google Sheets
|
||||
|
||||
@@ -152,7 +151,7 @@ Now just copy **GOOGLE_SHEETS_CLIENT_ID**, **GOOGLE_SHEETS_CLIENT_SECRET** and *
|
||||
- `GOOGLE_SHEETS_CLIENT_SECRET`
|
||||
- `GOOGLE_SHEETS_REDIRECT_URL`
|
||||
|
||||
Voila! You have successfully enabled the Google Sheets integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in [Google Sheets Integration with Formbricks](/integrations#google-sheets) section to link a Google Sheet with Formbricks.
|
||||
Voila! You have successfully enabled the Google Sheets integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in [Google Sheets Integration with Formbricks](/developer-docs/integrations/google-sheets) section to link a Google Sheet with Formbricks.
|
||||
|
||||
## Notion:
|
||||
|
||||
@@ -170,7 +169,7 @@ Enabling the Notion Integration in a self-hosted environment requires a setup us
|
||||
- `NOTION_OAUTH_CLIENT_ID` - OAuth Client ID
|
||||
- `NOTION_OAUTH_CLIENT_SECRET` - OAuth Client Secret
|
||||
|
||||
Voila! You have successfully enabled the Notion integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in [Notion Integration with Formbricks](/integrations#notion) section to link your Notion with Formbricks.
|
||||
Voila! You have successfully enabled the Notion integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in [Notion Integration with Formbricks](/developer-docs/integrations/notion) section to link your Notion with Formbricks.
|
||||
|
||||
## n8n
|
||||
|
||||
@@ -289,7 +288,7 @@ Once the execution is successful, you'll receive the content in the discord chan
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Voila! You have successfully enabled the n8n integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in the [Formbricks](/integrations#n8n) Integrations section to know more about the capabilities with Formbricks with n8n.
|
||||
Voila! You have successfully enabled the n8n integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in the [Formbricks](/developer-docs/integrations/n8n) Integrations section to know more about the capabilities with Formbricks with n8n.
|
||||
|
||||
## Slack
|
||||
|
||||
@@ -321,7 +320,7 @@ Enabling the Slack Integration in a self-hosted environment requires a setup usi
|
||||
8. Now, you need to enable the public distribution of your app. Go to the **Basic Information** tab and click on the **Manage distribution** button and click on the "Distribute App".
|
||||
9. Scroll down to the **Share your app with other workspaces** section, complete the checklist and click on the **Activate public distribution** button.
|
||||
|
||||
Voila! You have successfully enabled the Slack integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in the [Slack Integration](/integrations#slack) section to link a Slack workspace with Formbricks.
|
||||
Voila! You have successfully enabled the Slack integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in the [Slack Integration](/developer-docs/integrations/slack) section to link a Slack workspace with Formbricks.
|
||||
|
||||
## Zapier
|
||||
|
||||
@@ -348,7 +347,7 @@ Then, choose the event you want to trigger the Zap on:
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Now you need an API key. Please refer to the [API Key Setup](/developer-docs/rest-api#api-key) page to learn how to create one.
|
||||
Now you need an API key. Please refer to the [API Key Setup](/developer-docs/rest-api##how-to-generate-an-api-key) page to learn how to create one.
|
||||
|
||||
Once you copied it in the newly opened Zapier window, you will be connected:
|
||||
|
||||
@@ -359,6 +358,6 @@ Once you copied it in the newly opened Zapier window, you will be connected:
|
||||
className="max-w-full rounded-lg sm:max-w-3xl"
|
||||
/>
|
||||
|
||||
Voila! You have successfully configured Zapier to work with your self-hosted Formbricks instance. Now you can follow the steps mentioned in the [Zapier Integration](/integrations#zapier) section to connect it with your Formbricks app and see it live.
|
||||
Voila! You have successfully configured Zapier to work with your self-hosted Formbricks instance. Now you can follow the steps mentioned in the [Zapier Integration](/developer-docs/integrations/zapier) section to connect it with your Formbricks app and see it live.
|
||||
|
||||
---
|
||||
|
||||
@@ -8,6 +8,123 @@ export const metadata = {
|
||||
|
||||
# Migration Guide
|
||||
|
||||
## v2.7
|
||||
|
||||
<Note>
|
||||
This release sets the foundation for our upcoming AI features, currently in private beta. Formbricks now
|
||||
requires the `pgvector` extension to be installed in the PostgreSQL database. For users of our one-click
|
||||
setup, simply use the `pgvector/pgvector:pg15` image instead of `postgres:15-alpine`.
|
||||
</Note>
|
||||
|
||||
Formbricks v2.7 includes all the features and improvements developed by the community during hacktoberfest 2024. Additionally we introduce an advanced team-based access control system (requires Formbricks Enterprise Edition).
|
||||
|
||||
### Additional Updates
|
||||
|
||||
If you previously used organization-based access control (enterprise feature) as well as the `DEFAULT_ORGANIZATION_ROLE` environment variable, make sure to update the value to one of the following roles: `owner`, `manager`, `member`. Read more about the new roles in the [Docs](/global/access-roles).
|
||||
|
||||
### 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.7_$(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. If you use an older `docker-compose.yml` file from the one-click setup, modify it to use the `pgvector/pgvector:pg15` image instead of `postgres:15-alpine`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
postgres:
|
||||
image: pgvector/pgvector:pg15
|
||||
volumes:
|
||||
- postgres:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_DB=postgres
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
ports:
|
||||
- 5432:5432
|
||||
```
|
||||
|
||||
3. Pull the latest version of Formbricks:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Stop the containers">
|
||||
|
||||
```bash
|
||||
docker compose pull
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
4. Stop the running Formbricks instance & remove the related containers:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Stop the containers">
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
5. Restarting the containers with the latest version of Formbricks:
|
||||
|
||||
<Col>
|
||||
<CodeGroup title="Restart the containers">
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
6. 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.7" \
|
||||
ghcr.io/formbricks/data-migrations:v2.7.0
|
||||
```
|
||||
|
||||
</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.
|
||||
|
||||
7. That's it! Once the migration is complete, you can **now access your Formbricks instance** at the same URL as before.
|
||||
|
||||
## v2.6
|
||||
|
||||
Formbricks v2.6 introduces advanced logic jumps for surveys, allowing you to add more advanced branching logic to your surveys including variables, and/or conditions and many more. This release also includes a lot of bug fixes, big performance improvements to website and app surveys and a lot of stability improvements.
|
||||
|
||||
@@ -160,6 +160,33 @@ const NavigationGroup = ({
|
||||
const pathname = usePathname();
|
||||
const [isActiveGroup, setIsActiveGroup] = useState<boolean>(false);
|
||||
|
||||
// We need to expand the group with the current link so we loop over all links
|
||||
// Until we find the one and then expand the groups
|
||||
useEffect(() => {
|
||||
const findMatchingGroup = () => {
|
||||
for (const group of navigation) {
|
||||
for (const link of group.links) {
|
||||
if (!link.children) continue;
|
||||
|
||||
const matchingChild = link.children.find((child) => pathname && child.href.startsWith(pathname));
|
||||
|
||||
if (matchingChild) {
|
||||
setOpenGroups([`${group.title}-${link.title}`]);
|
||||
setActiveGroup(group);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
findMatchingGroup();
|
||||
|
||||
return () => {
|
||||
setOpenGroups([]);
|
||||
setActiveGroup(null);
|
||||
};
|
||||
}, [pathname, setActiveGroup, setOpenGroups]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsActiveGroup(activeGroup?.title === group.title);
|
||||
}, [activeGroup?.title, group.title]);
|
||||
@@ -262,6 +289,25 @@ interface NavigationProps extends React.ComponentPropsWithoutRef<"nav"> {
|
||||
export const Navigation = ({ isMobile, ...props }: NavigationProps) => {
|
||||
const [activeGroup, setActiveGroup] = useState<NavGroup | null>(navigation[0]);
|
||||
const [openGroups, setOpenGroups] = useState<string[]>([]);
|
||||
const pathname = usePathname();
|
||||
|
||||
useEffect(() => {
|
||||
// Check the current pathname and set the active group
|
||||
navigation.forEach((group) => {
|
||||
group.links.forEach((link) => {
|
||||
if (link.href && pathname.startsWith(link.href)) {
|
||||
setActiveGroup(group);
|
||||
} else if (link.children) {
|
||||
link.children.forEach((child) => {
|
||||
if (pathname.startsWith(child.href)) {
|
||||
setActiveGroup(group);
|
||||
setOpenGroups([`${group.title}-${link.title}`]); // Ensure parent is open
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
<nav {...props}>
|
||||
|
||||
25
apps/docs/components/SurveyEmbed.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import React from "react";
|
||||
|
||||
interface SurveyEmbedProps {
|
||||
surveyUrl: string;
|
||||
}
|
||||
|
||||
const SurveyEmbed: React.FC<SurveyEmbedProps> = ({ surveyUrl }) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
height: "90vh",
|
||||
maxHeight: "100vh",
|
||||
overflow: "auto",
|
||||
borderRadius: "12px",
|
||||
}}>
|
||||
<iframe
|
||||
src={surveyUrl}
|
||||
style={{ position: "absolute", left: 0, top: 0, width: "100%", height: "100%", border: 0 }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SurveyEmbed;
|
||||
@@ -9,7 +9,7 @@ export const TwitterIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}>
|
||||
<path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path>
|
||||
<path d="M403.229 0h78.506L310.219 196.04 512 462.799H354.002L230.261 301.007 88.669 462.799h-78.56l183.455-209.683L0 0h161.999l111.856 147.88L403.229 0zm-27.556 415.805h43.505L138.363 44.527h-46.68l283.99 371.278z" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@ export const navigation: Array<NavGroup> = [
|
||||
{ title: "Docs Feedback", href: "/best-practices/docs-feedback" },
|
||||
{ title: "Improve Email Content", href: "/best-practices/improve-email-content" },
|
||||
{ title: "Contact Form", href: "/best-practices/contact-form" },
|
||||
{ title: "Quiz Time", href: "/best-practices/quiz-time" },
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -49,6 +50,10 @@ export const navigation: Array<NavGroup> = [
|
||||
{ title: "Verify Email before Survey", href: "/link-surveys/verify-email-before-survey" },
|
||||
{ title: "PIN Protected Surveys", href: "/link-surveys/pin-protected-surveys" },
|
||||
{ title: "Partial Submissions", href: "/global/partial-submissions" },
|
||||
{
|
||||
title: "Add Image/Video to Question",
|
||||
href: "/global/add-image-or-video-question",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -76,6 +81,10 @@ export const navigation: Array<NavGroup> = [
|
||||
{ title: "Recall Functionality", href: "/global/recall" }, // global
|
||||
{ title: "Partial Submissions", href: "/global/partial-submissions" }, // global
|
||||
{ title: "Shareable Dashboards", href: "/global/shareable-dashboards" },
|
||||
{
|
||||
title: "Add Image/Video to Question",
|
||||
href: "/global/add-image-or-video-question",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -83,6 +92,26 @@ export const navigation: Array<NavGroup> = [
|
||||
{
|
||||
title: "Core Features",
|
||||
links: [
|
||||
{
|
||||
title: "Question Types",
|
||||
children: [
|
||||
{ title: "Free Text", href: "/global/question-type/free-text" },
|
||||
{ title: "Select Single", href: "/global/question-type/single-select" },
|
||||
{ title: "Select Multiple", href: "/global/question-type/multi-select" },
|
||||
{ title: "Select Picture", href: "/global/question-type/picture-selection" },
|
||||
{ title: "Rating", href: "/global/question-type/rating" },
|
||||
{ title: "Net Promoter Score", href: "/global/question-type/net-promoter-score" },
|
||||
{ title: "Ranking", href: "/global/question-type/ranking" },
|
||||
{ title: "Matrix", href: "/global/question-type/matrix" },
|
||||
{ title: "Statement (Call to Action)", href: "/global/question-type/statement-cta" },
|
||||
{ title: "Consent", href: "/global/question-type/consent" },
|
||||
{ title: "File Upload", href: "/global/question-type/file-upload" },
|
||||
{ title: "Date", href: "/global/question-type/date" },
|
||||
{ title: "Schedule a Meeting", href: "/global/question-type/schedule" },
|
||||
{ title: "Address", href: "/global/question-type/address" },
|
||||
{ title: "Contact Info", href: "/global/question-type/contact" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Integrations",
|
||||
children: [
|
||||
@@ -97,7 +126,7 @@ export const navigation: Array<NavGroup> = [
|
||||
{ title: "Zapier", href: "/developer-docs/integrations/zapier" },
|
||||
],
|
||||
},
|
||||
{ title: "Access Roles", href: "/global/access-roles" },
|
||||
{ title: "User Management", href: "/global/access-roles" },
|
||||
{ title: "Styling Theme", href: "/global/styling-theme" },
|
||||
],
|
||||
},
|
||||
|
||||
@@ -2,9 +2,19 @@ import { slugifyWithCounter } from "@sindresorhus/slugify";
|
||||
import * as acorn from "acorn";
|
||||
import { toString } from "mdast-util-to-string";
|
||||
import { mdxAnnotations } from "mdx-annotations";
|
||||
import { getHighlighter, renderToHtml } from "shiki";
|
||||
import { createCssVariablesTheme, createHighlighter } from "shiki";
|
||||
import { visit } from "unist-util-visit";
|
||||
|
||||
let highlighterPromise;
|
||||
const supportedLanguages = ["javascript", "html", "shell", "tsx", "json", "yml", "ts"];
|
||||
|
||||
const myTheme = createCssVariablesTheme({
|
||||
name: "css-variables",
|
||||
variablePrefix: "--shiki-",
|
||||
variableDefaults: {},
|
||||
fontStyle: true,
|
||||
});
|
||||
|
||||
const rehypeParseCodeBlocks = () => {
|
||||
return (tree) => {
|
||||
visit(tree, "element", (node, _nodeIndex, parentNode) => {
|
||||
@@ -15,29 +25,31 @@ const rehypeParseCodeBlocks = () => {
|
||||
};
|
||||
};
|
||||
|
||||
let highlighter;
|
||||
|
||||
const getHighlighter = async () => {
|
||||
if (!highlighterPromise) {
|
||||
highlighterPromise = createHighlighter({
|
||||
langs: supportedLanguages,
|
||||
themes: [myTheme],
|
||||
})
|
||||
}
|
||||
|
||||
return highlighterPromise;
|
||||
}
|
||||
const rehypeShiki = () => {
|
||||
return async (tree) => {
|
||||
highlighter = highlighter ?? (await getHighlighter({ theme: "css-variables" }));
|
||||
const highlighter = await getHighlighter();
|
||||
|
||||
visit(tree, "element", (node) => {
|
||||
if (node.tagName === "pre" && node.children[0]?.tagName === "code") {
|
||||
let codeNode = node.children[0];
|
||||
let textNode = codeNode.children[0];
|
||||
|
||||
if (!codeNode || !textNode) return;
|
||||
node.properties.code = textNode.value;
|
||||
|
||||
if (node.properties.language) {
|
||||
let tokens = highlighter.codeToThemedTokens(textNode.value, node.properties.language);
|
||||
|
||||
textNode.value = renderToHtml(tokens, {
|
||||
elements: {
|
||||
pre: ({ children }) => children,
|
||||
code: ({ children }) => children,
|
||||
line: ({ children }) => `<span>${children}</span>`,
|
||||
},
|
||||
});
|
||||
if (codeNode.properties.className && codeNode.properties.className.length > 0) {
|
||||
let lang = codeNode.properties.className[0].replace("language-", "");
|
||||
const code = highlighter.codeToHtml(textNode.value, { lang, theme: "css-variables" });
|
||||
textNode.value = code;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
"lucide-react": "0.452.0",
|
||||
"mdast-util-to-string": "4.0.0",
|
||||
"mdx-annotations": "0.1.4",
|
||||
"next": "14.2.15",
|
||||
"next": "14.2.16",
|
||||
"next-plausible": "3.12.2",
|
||||
"next-seo": "6.6.0",
|
||||
"next-sitemap": "4.2.3",
|
||||
@@ -57,7 +57,7 @@
|
||||
"remark-mdx": "3.0.1",
|
||||
"schema-dts": "1.1.2",
|
||||
"sharp": "0.33.5",
|
||||
"shiki": "0.14.7",
|
||||
"shiki": "1.22.0",
|
||||
"simple-functional-loader": "1.2.1",
|
||||
"tailwindcss": "3.4.13",
|
||||
"unist-util-filter": "5.0.1",
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
{
|
||||
"extends": "@formbricks/config-typescript/nextjs.json",
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "../../packages/types/*.d.ts"],
|
||||
"exclude": ["../../.env", "node_modules"],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
@@ -13,5 +10,8 @@
|
||||
}
|
||||
],
|
||||
"strictNullChecks": true
|
||||
}
|
||||
},
|
||||
"exclude": ["../../.env", "node_modules"],
|
||||
"extends": "@formbricks/config-typescript/nextjs.json",
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "../../packages/types/*.d.ts"]
|
||||
}
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
import { Meta } from "@storybook/blocks";
|
||||
|
||||
import Github from "./assets/github.svg";
|
||||
import Discord from "./assets/discord.svg";
|
||||
import Youtube from "./assets/youtube.svg";
|
||||
import Tutorials from "./assets/tutorials.svg";
|
||||
import Styling from "./assets/styling.png";
|
||||
import Context from "./assets/context.png";
|
||||
import Assets from "./assets/assets.png";
|
||||
import Docs from "./assets/docs.png";
|
||||
import Share from "./assets/share.png";
|
||||
import FigmaPlugin from "./assets/figma-plugin.png";
|
||||
import Testing from "./assets/testing.png";
|
||||
import Accessibility from "./assets/accessibility.png";
|
||||
import Theming from "./assets/theming.png";
|
||||
import AddonLibrary from "./assets/addon-library.png";
|
||||
import Assets from "./assets/assets.png";
|
||||
import Context from "./assets/context.png";
|
||||
import Discord from "./assets/discord.svg";
|
||||
import Docs from "./assets/docs.png";
|
||||
import FigmaPlugin from "./assets/figma-plugin.png";
|
||||
import Github from "./assets/github.svg";
|
||||
import Share from "./assets/share.png";
|
||||
import Styling from "./assets/styling.png";
|
||||
import Testing from "./assets/testing.png";
|
||||
import Theming from "./assets/theming.png";
|
||||
import Tutorials from "./assets/tutorials.svg";
|
||||
import Youtube from "./assets/youtube.svg";
|
||||
|
||||
export const RightArrow = () => <svg
|
||||
viewBox="0 0 14 14"
|
||||
width="8px"
|
||||
height="14px"
|
||||
style={{
|
||||
marginLeft: '4px',
|
||||
display: 'inline-block',
|
||||
shapeRendering: 'inherit',
|
||||
verticalAlign: 'middle',
|
||||
fill: 'currentColor',
|
||||
'path fill': 'currentColor'
|
||||
}}
|
||||
>
|
||||
<path d="m11.1 7.35-5.5 5.5a.5.5 0 0 1-.7-.7L10.04 7 4.9 1.85a.5.5 0 1 1 .7-.7l5.5 5.5c.2.2.2.5 0 .7Z" />
|
||||
</svg>
|
||||
export const RightArrow = () => (
|
||||
<svg
|
||||
viewBox="0 0 14 14"
|
||||
width="8px"
|
||||
height="14px"
|
||||
style={{
|
||||
marginLeft: "4px",
|
||||
display: "inline-block",
|
||||
shapeRendering: "inherit",
|
||||
verticalAlign: "middle",
|
||||
fill: "currentColor",
|
||||
"path fill": "currentColor",
|
||||
}}>
|
||||
<path d="m11.1 7.35-5.5 5.5a.5.5 0 0 1-.7-.7L10.04 7 4.9 1.85a.5.5 0 1 1 .7-.7l5.5 5.5c.2.2.2.5 0 .7Z" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
<Meta title="Configure your project" />
|
||||
|
||||
@@ -38,6 +39,7 @@ export const RightArrow = () => <svg
|
||||
# Configure your project
|
||||
|
||||
Because Storybook works separately from your app, you'll need to configure it for your specific stack and setup. Below, explore guides for configuring Storybook with popular frameworks and tools. If you get stuck, learn how you can ask for help from our community.
|
||||
|
||||
</div>
|
||||
<div className="sb-section">
|
||||
<div className="sb-section-item">
|
||||
@@ -84,6 +86,7 @@ export const RightArrow = () => <svg
|
||||
# Do more with Storybook
|
||||
|
||||
Now that you know the basics, let's explore other parts of Storybook that will improve your experience. This list is just to get you started. You can customise Storybook in many ways to fit your needs.
|
||||
|
||||
</div>
|
||||
|
||||
<div className="sb-section">
|
||||
@@ -203,6 +206,7 @@ export const RightArrow = () => <svg
|
||||
target="_blank"
|
||||
>Discover tutorials<RightArrow /></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
|
||||