mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-13 12:02:01 -05:00
Compare commits
3 Commits
ReviewBot/
...
ReviewBot/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3952431de2 | ||
|
|
f54e2e032a | ||
|
|
1a28660dfd |
3
.github/workflows/pr.yml
vendored
3
.github/workflows/pr.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
- "!(**.md|.github/CODEOWNERS)"
|
||||
|
||||
test:
|
||||
name: Run Tests
|
||||
name: Run Unit Tests
|
||||
needs: [changes]
|
||||
if: ${{ needs.changes.outputs.has-files-requiring-all-checks == 'true' }}
|
||||
uses: ./.github/workflows/test.yml
|
||||
@@ -58,6 +58,7 @@ jobs:
|
||||
secrets: inherit
|
||||
|
||||
required:
|
||||
name: PR Check Summary
|
||||
needs: [lint, test, build, e2e-test]
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -3,7 +3,7 @@ on:
|
||||
workflow_call:
|
||||
jobs:
|
||||
build:
|
||||
name: Tests
|
||||
name: Unit Tests
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import * as DOMPurify from "dompurify";
|
||||
|
||||
export default function HtmlBody({ htmlString, questionId }: { htmlString: string; questionId: string }) {
|
||||
return (
|
||||
<label
|
||||
htmlFor={questionId}
|
||||
className="fb-block fb-font-normal fb-leading-6 text-sm text-slate-500 dark:text-slate-300"
|
||||
dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(htmlString) }}></label>
|
||||
dangerouslySetInnerHTML={{ __html: htmlString }}></label>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,50 +1,51 @@
|
||||
import { slugifyWithCounter } from "@sindresorhus/slugify";
|
||||
import glob from "fast-glob";
|
||||
import * as fs from "fs";
|
||||
import { toString } from "mdast-util-to-string";
|
||||
import * as path from "path";
|
||||
import { remark } from "remark";
|
||||
import remarkMdx from "remark-mdx";
|
||||
import { createLoader } from "simple-functional-loader";
|
||||
import { filter } from "unist-util-filter";
|
||||
import { SKIP, visit } from "unist-util-visit";
|
||||
import * as url from "url";
|
||||
import { slugifyWithCounter } from '@sindresorhus/slugify'
|
||||
import glob from 'fast-glob'
|
||||
import * as fs from 'fs'
|
||||
import { toString } from 'mdast-util-to-string'
|
||||
import * as path from 'path'
|
||||
import { remark } from 'remark'
|
||||
import remarkMdx from 'remark-mdx'
|
||||
import { createLoader } from 'simple-functional-loader'
|
||||
import { filter } from 'unist-util-filter'
|
||||
import { SKIP, visit } from 'unist-util-visit'
|
||||
import * as url from 'url'
|
||||
|
||||
const __filename = url.fileURLToPath(import.meta.url);
|
||||
const processor = remark().use(remarkMdx).use(extractSections);
|
||||
const slugify = slugifyWithCounter();
|
||||
const __filename = url.fileURLToPath(import.meta.url)
|
||||
const processor = remark().use(remarkMdx).use(extractSections)
|
||||
const slugify = slugifyWithCounter()
|
||||
|
||||
function isObjectExpression(node) {
|
||||
return (
|
||||
node.type === "mdxTextExpression" && node.data?.estree?.body?.[0]?.expression?.type === "ObjectExpression"
|
||||
);
|
||||
node.type === 'mdxTextExpression' &&
|
||||
node.data?.estree?.body?.[0]?.expression?.type === 'ObjectExpression'
|
||||
)
|
||||
}
|
||||
|
||||
function excludeObjectExpressions(tree) {
|
||||
return filter(tree, (node) => !isObjectExpression(node));
|
||||
return filter(tree, (node) => !isObjectExpression(node))
|
||||
}
|
||||
|
||||
function extractSections() {
|
||||
return (tree, { sections }) => {
|
||||
slugify.reset();
|
||||
slugify.reset()
|
||||
|
||||
visit(tree, (node) => {
|
||||
if (node.type === "heading" || node.type === "paragraph") {
|
||||
let content = toString(excludeObjectExpressions(node));
|
||||
if (node.type === "heading" && node.depth <= 2) {
|
||||
let hash = node.depth === 1 ? null : slugify(content);
|
||||
sections.push([content, hash, []]);
|
||||
if (node.type === 'heading' || node.type === 'paragraph') {
|
||||
let content = toString(excludeObjectExpressions(node))
|
||||
if (node.type === 'heading' && node.depth <= 2) {
|
||||
let hash = node.depth === 1 ? null : slugify(content)
|
||||
sections.push([content, hash, []])
|
||||
} else {
|
||||
sections.at(-1)?.[2].push(content);
|
||||
sections.at(-1)?.[2].push(content)
|
||||
}
|
||||
return SKIP;
|
||||
return SKIP
|
||||
}
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default function (nextConfig = {}) {
|
||||
let cache = new Map();
|
||||
export default function Search(nextConfig = {}) {
|
||||
let cache = new Map()
|
||||
|
||||
return Object.assign({}, nextConfig, {
|
||||
webpack(config, options) {
|
||||
@@ -52,26 +53,26 @@ export default function (nextConfig = {}) {
|
||||
test: __filename,
|
||||
use: [
|
||||
createLoader(function () {
|
||||
let appDir = path.resolve("./app");
|
||||
this.addContextDependency(appDir);
|
||||
let appDir = path.resolve('./src/app')
|
||||
this.addContextDependency(appDir)
|
||||
|
||||
let files = glob.sync("**/*.mdx", { cwd: appDir });
|
||||
let files = glob.sync('**/*.mdx', { cwd: appDir })
|
||||
let data = files.map((file) => {
|
||||
let url = "/" + file.replace(/(^|\/)page\.mdx$/, "");
|
||||
let mdx = fs.readFileSync(path.join(appDir, file), "utf8");
|
||||
let url = '/' + file.replace(/(^|\/)page\.mdx$/, '')
|
||||
let mdx = fs.readFileSync(path.join(appDir, file), 'utf8')
|
||||
|
||||
let sections = [];
|
||||
let sections = []
|
||||
|
||||
if (cache.get(file)?.[0] === mdx) {
|
||||
sections = cache.get(file)[1];
|
||||
sections = cache.get(file)[1]
|
||||
} else {
|
||||
let vfile = { value: mdx, sections };
|
||||
processor.runSync(processor.parse(vfile), vfile);
|
||||
cache.set(file, [mdx, sections]);
|
||||
let vfile = { value: mdx, sections }
|
||||
processor.runSync(processor.parse(vfile), vfile)
|
||||
cache.set(file, [mdx, sections])
|
||||
}
|
||||
|
||||
return { url, sections };
|
||||
});
|
||||
return { url, sections }
|
||||
})
|
||||
|
||||
// When this file is imported within the application
|
||||
// the following module is loaded:
|
||||
@@ -119,16 +120,16 @@ export default function (nextConfig = {}) {
|
||||
pageTitle: item.doc.pageTitle,
|
||||
}))
|
||||
}
|
||||
`;
|
||||
`
|
||||
}),
|
||||
],
|
||||
});
|
||||
})
|
||||
|
||||
if (typeof nextConfig.webpack === "function") {
|
||||
return nextConfig.webpack(config, options);
|
||||
if (typeof nextConfig.webpack === 'function') {
|
||||
return nextConfig.webpack(config, options)
|
||||
}
|
||||
|
||||
return config;
|
||||
return config
|
||||
},
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12,62 +12,60 @@
|
||||
},
|
||||
"browserslist": "defaults, not ie <= 11",
|
||||
"dependencies": {
|
||||
"@algolia/autocomplete-core": "^1.13.0",
|
||||
"@algolia/autocomplete-core": "^1.17.0",
|
||||
"@calcom/embed-react": "^1.3.2",
|
||||
"@docsearch/react": "^3.5.2",
|
||||
"@docsearch/react": "^3.6.0",
|
||||
"@formbricks/lib": "workspace:*",
|
||||
"@formbricks/types": "workspace:*",
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"@headlessui/react": "^1.7.17",
|
||||
"@headlessui/react": "^1.7.18",
|
||||
"@headlessui/tailwindcss": "^0.2.0",
|
||||
"lucide-react": "^0.344.0",
|
||||
"lucide-react": "^0.356.0",
|
||||
"@mapbox/rehype-prism": "^0.9.0",
|
||||
"@mdx-js/loader": "^3.0.0",
|
||||
"@mdx-js/react": "^3.0.0",
|
||||
"@next/mdx": "14.0.4",
|
||||
"@mdx-js/loader": "^3.0.1",
|
||||
"@mdx-js/react": "^3.0.1",
|
||||
"@next/mdx": "14.1.3",
|
||||
"@paralleldrive/cuid2": "^2.2.2",
|
||||
"@radix-ui/react-slider": "^1.1.2",
|
||||
"@radix-ui/react-tooltip": "^1.0.6",
|
||||
"@sindresorhus/slugify": "^2.2.1",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/react-highlight-words": "^0.16.5",
|
||||
"acorn": "^8.10.0",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"clsx": "^2.0.0",
|
||||
"fast-glob": "^3.3.1",
|
||||
"flexsearch": "^0.7.31",
|
||||
"framer-motion": "10.17.8",
|
||||
"acorn": "^8.11.3",
|
||||
"autoprefixer": "^10.4.18",
|
||||
"clsx": "^2.1.0",
|
||||
"fast-glob": "^3.3.2",
|
||||
"flexsearch": "^0.7.43",
|
||||
"framer-motion": "11.0.13",
|
||||
"lottie-web": "^5.12.2",
|
||||
"mdast-util-to-string": "^4.0.0",
|
||||
"mdx-annotations": "^0.1.4",
|
||||
"next": "13.4.19",
|
||||
"next": "14.1.3",
|
||||
"next-plausible": "^3.12.0",
|
||||
"next-seo": "^6.4.0",
|
||||
"next-seo": "^6.5.0",
|
||||
"next-sitemap": "^4.2.3",
|
||||
"next-themes": "^0.2.1",
|
||||
"next-themes": "^0.3.0",
|
||||
"node-fetch": "^3.3.2",
|
||||
"prism-react-renderer": "^2.3.1",
|
||||
"prismjs": "^1.29.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-highlight-words": "^0.20.0",
|
||||
"react-icons": "^4.12.0",
|
||||
"react-icons": "^5.0.1",
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-responsive-embed": "^2.1.0",
|
||||
"remark": "^15.0.1",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"remark-mdx": "^3.0.0",
|
||||
"sharp": "^0.33.1",
|
||||
"remark-mdx": "^3.0.1",
|
||||
"sharp": "^0.33.2",
|
||||
"shiki": "^0.14.7",
|
||||
"simple-functional-loader": "^1.2.1",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"unist-util-filter": "^5.0.1",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"zustand": "^4.4.7"
|
||||
"zustand": "^4.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formbricks/tsconfig": "workspace:*",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/react-highlight-words": "^0.16.7",
|
||||
"eslint-config-formbricks": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
{
|
||||
"extends": "@formbricks/tsconfig/nextjs.json",
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "../../packages/types/*.d.ts"],
|
||||
"exclude": ["../../.env"],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"strictNullChecks": true
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
"test": "dotenv -e ../../.env -- vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "3.529.1",
|
||||
"@aws-sdk/s3-presigned-post": "3.529.1",
|
||||
"@aws-sdk/s3-request-presigner": "3.529.1",
|
||||
"@aws-sdk/client-s3": "3.533.0",
|
||||
"@aws-sdk/s3-presigned-post": "3.533.0",
|
||||
"@aws-sdk/s3-request-presigner": "3.533.0",
|
||||
"@formbricks/api": "*",
|
||||
"@formbricks/database": "*",
|
||||
"@formbricks/types": "*",
|
||||
|
||||
@@ -5,9 +5,31 @@ interface QuestionImageProps {
|
||||
|
||||
export default function QuestionImage({ imgUrl, altText = "Image" }: QuestionImageProps) {
|
||||
return (
|
||||
<div className="mb-4 rounded-md">
|
||||
<div className="group/image relative mb-4 block rounded-md">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img src={imgUrl} alt={altText} className="mb-4 rounded-md" />
|
||||
<img src={imgUrl} alt={altText} className="rounded-md" />
|
||||
<a
|
||||
href={imgUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="absolute bottom-2 right-2 flex items-center gap-2 rounded-md bg-gray-800 bg-opacity-40 p-1.5 text-white opacity-0 backdrop-blur-lg transition duration-300 ease-in-out hover:bg-opacity-65 group-hover/image:opacity-100">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-expand">
|
||||
<path d="m21 21-6-6m6 6v-4.8m0 4.8h-4.8" />
|
||||
<path d="M3 16.2V21m0 0h4.8M3 21l6-6" />
|
||||
<path d="M21 7.8V3m0 0h-4.8M21 3l-6 6" />
|
||||
<path d="M3 7.8V3m0 0h4.8M3 3l6 6" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ export default function PictureSelectionQuestion({
|
||||
Array.isArray(value) && value.includes(choice.id)
|
||||
? `border-brand text-brand z-10 border-4 shadow-xl focus:border-4`
|
||||
: "",
|
||||
"border-border focus:border-border-highlight focus:bg-accent-selected-bg relative box-border inline-block h-28 w-full overflow-hidden rounded-xl border focus:outline-none"
|
||||
"border-border focus:border-border-highlight focus:bg-accent-selected-bg group/image relative box-border inline-block h-28 w-full cursor-pointer overflow-hidden rounded-xl border focus:outline-none"
|
||||
)}>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
@@ -127,6 +127,30 @@ export default function PictureSelectionQuestion({
|
||||
alt={choice.imageUrl.split("/").pop()}
|
||||
className="h-full w-full object-cover"
|
||||
/>
|
||||
<a
|
||||
href={choice.imageUrl}
|
||||
target="_blank"
|
||||
title="Open in new tab"
|
||||
rel="noreferrer"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="absolute bottom-2 right-2 flex items-center gap-2 whitespace-nowrap rounded-md bg-gray-800 bg-opacity-40 p-1.5 text-white opacity-0 backdrop-blur-lg transition duration-300 ease-in-out hover:bg-opacity-65 group-hover/image:opacity-100">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-expand">
|
||||
<path d="m21 21-6-6m6 6v-4.8m0 4.8h-4.8" />
|
||||
<path d="M3 16.2V21m0 0h4.8M3 21l6-6" />
|
||||
<path d="M21 7.8V3m0 0h-4.8M21 3l-6 6" />
|
||||
<path d="M3 7.8V3m0 0h4.8M3 3l6 6" />
|
||||
</svg>
|
||||
</a>
|
||||
{question.allowMulti ? (
|
||||
<input
|
||||
id={`${choice.id}-checked`}
|
||||
|
||||
2273
pnpm-lock.yaml
generated
2273
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user