mirror of
https://github.com/formbricks/formbricks.git
synced 2025-12-30 18:30:32 -06:00
feat: add basic code form page and pipelines page
This commit is contained in:
@@ -44,7 +44,7 @@ export default function FormList() {
|
||||
.map((form, formIdx) => (
|
||||
<li key={form.id} className="col-span-1 ">
|
||||
<div className="bg-white divide-y divide-gray-200 rounded-lg shadow">
|
||||
<Link href={`/forms/${form.id}/form`}>
|
||||
<Link href={`/forms/${form.id}`}>
|
||||
<a>
|
||||
<div className="px-4 py-5 sm:p-6">{form.name}</div>
|
||||
</a>
|
||||
|
||||
233
components/form/FormCode.tsx
Normal file
233
components/form/FormCode.tsx
Normal file
@@ -0,0 +1,233 @@
|
||||
import { RadioGroup } from "@headlessui/react";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { FaReact, FaVuejs } from "react-icons/fa";
|
||||
import { classNames } from "../../lib/utils";
|
||||
|
||||
const libs = [
|
||||
{
|
||||
id: "react",
|
||||
name: "React",
|
||||
href: "#",
|
||||
bgColor: "bg-cyan-500",
|
||||
ringColor: "ring-cyan-500",
|
||||
icon: FaReact,
|
||||
},
|
||||
{
|
||||
id: "reactNative",
|
||||
name: "React Native",
|
||||
comingSoon: true,
|
||||
href: "#",
|
||||
members: 12,
|
||||
bgColor: "bg-cyan-600",
|
||||
ringColor: "ring-cyan-600",
|
||||
icon: FaReact,
|
||||
},
|
||||
{
|
||||
id: "vue",
|
||||
name: "Vue.js",
|
||||
comingSoon: true,
|
||||
href: "#",
|
||||
members: 16,
|
||||
bgColor: "bg-emerald-400",
|
||||
ringColor: "ring-emerald-400",
|
||||
icon: FaVuejs,
|
||||
},
|
||||
];
|
||||
|
||||
export default function FormCode() {
|
||||
const [selectedLib, setSelectedLib] = useState(null);
|
||||
|
||||
return (
|
||||
<>
|
||||
<header>
|
||||
<div className="mx-auto mt-8 max-w-7xl">
|
||||
<h1 className="text-3xl font-bold leading-tight text-gray-900">
|
||||
Get started
|
||||
</h1>
|
||||
</div>
|
||||
</header>
|
||||
<div className="my-4">
|
||||
<p className="text-gray-700">
|
||||
Welcome to your new form! To start using snoopHub with your
|
||||
application you need to build a form using our libs for your preferred
|
||||
programming language or framework.
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<RadioGroup value={selectedLib} onChange={setSelectedLib}>
|
||||
<RadioGroup.Label className="text-xs font-medium tracking-wide text-gray-500 uppercase">
|
||||
Choose your framework
|
||||
</RadioGroup.Label>
|
||||
|
||||
<ul
|
||||
role="list"
|
||||
className="grid grid-cols-1 gap-5 mt-3 sm:gap-6 sm:grid-cols-3 lg:grid-cols-3"
|
||||
>
|
||||
{libs.map((lib) => (
|
||||
<RadioGroup.Option
|
||||
key={lib.id}
|
||||
value={lib}
|
||||
className={({ checked }) =>
|
||||
classNames(
|
||||
checked ? `ring-2 ${lib.ringColor}` : "",
|
||||
lib.comingSoon ? "opacity-50" : "",
|
||||
"flex col-span-1 rounded-md shadow-sm"
|
||||
)
|
||||
}
|
||||
disabled={lib.comingSoon}
|
||||
>
|
||||
{({}) => (
|
||||
<li
|
||||
className={classNames(
|
||||
lib.comingSoon ? "opacity-50" : "",
|
||||
"flex col-span-1 rounded-md shadow-sm w-full"
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
lib.bgColor,
|
||||
"flex-shrink-0 flex items-center justify-center w-16 text-white text-sm font-medium rounded-l-md"
|
||||
)}
|
||||
>
|
||||
<lib.icon className="w-5 h-5" />
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
lib.comingSoon ? "border-dashed" : "",
|
||||
"flex items-center justify-between flex-1 truncate bg-white border-t border-b border-r border-gray-200 rounded-r-md"
|
||||
)}
|
||||
>
|
||||
<div className="flex-1 px-4 py-5 text-sm truncate">
|
||||
<RadioGroup.Label className="font-medium text-gray-900 hover:text-gray-600">
|
||||
{lib.name}
|
||||
</RadioGroup.Label>
|
||||
{lib.comingSoon && (
|
||||
<p className="inline-block ml-1 text-gray-500">
|
||||
(coming soon)
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
)}
|
||||
</RadioGroup.Option>
|
||||
))}
|
||||
</ul>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="mt-10">
|
||||
{selectedLib?.id === "react" ? (
|
||||
<div className="relative px-5 py-16 overflow-hidden border border-gray-200 rounded-lg shadow-inner">
|
||||
<div className="relative px-4 sm:px-6 lg:px-8">
|
||||
<div className="mx-auto text-lg max-w-prose">
|
||||
<h1>
|
||||
<span className="block text-base font-semibold tracking-wide text-center text-red-600">
|
||||
snoopReact
|
||||
</span>
|
||||
<span className="block mt-2 text-3xl font-extrabold leading-8 tracking-tight text-center text-gray-900 sm:text-4xl">
|
||||
How to build your form
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div className="mx-auto mt-6 text-base prose prose-lg text-gray-500 prose-red">
|
||||
<p>
|
||||
Getting the snoopForms React Library up and running with Node
|
||||
Package Manager:
|
||||
</p>
|
||||
<pre>
|
||||
<code className="language-js">
|
||||
npm install --save @snoopforms/react
|
||||
</code>
|
||||
</pre>
|
||||
<p>Then build your form using our built-in components</p>
|
||||
<pre>
|
||||
<code className="language-js">
|
||||
{`import React from "react";
|
||||
import { SnoopForm, SnoopElement, SnoopPage } from "@snoopforms/react";
|
||||
|
||||
export default function Example({}) {
|
||||
return (
|
||||
<SnoopForm
|
||||
domain="localhost:3000"
|
||||
protocol="http"
|
||||
className="w-full space-y-6"
|
||||
onSubmit={({ submission, schema }) => {
|
||||
// do something with the data additional to sending to snoopForms
|
||||
}}
|
||||
>
|
||||
<SnoopPage name="first">
|
||||
<SnoopElement
|
||||
type="text"
|
||||
name={"name"}
|
||||
label="Your name"
|
||||
classNames={{
|
||||
label: "your-label-class",
|
||||
element: "your-input-class",
|
||||
}}
|
||||
required
|
||||
/>
|
||||
</SnoopPage>
|
||||
<SnoopPage name="second">
|
||||
<SnoopElement
|
||||
type="radio"
|
||||
name={"importance"}
|
||||
label="What's your favorite food?"
|
||||
classNames={{
|
||||
label: "your-label-class",
|
||||
radioGroup: "your-radio-group-class",
|
||||
radioOption: "your-radio-option-class",
|
||||
}}
|
||||
options={["Pizza", "Pasta", "Sushi"]}
|
||||
/>
|
||||
<SnoopElement
|
||||
type="submit"
|
||||
label="Submit"
|
||||
classNames={{
|
||||
button: "your-submit-button-class",
|
||||
}}
|
||||
/>
|
||||
</SnoopPage>
|
||||
<SnoopPage thankyou>
|
||||
<h1>Thank you!</h1>
|
||||
</SnoopPage>
|
||||
</SnoopForm>
|
||||
);
|
||||
}`}
|
||||
</code>
|
||||
</pre>
|
||||
<p>
|
||||
To read more about building your form with snoopReact, check
|
||||
out our{" "}
|
||||
<Link href="https://docs.snoopforms.com/">
|
||||
<a target="_blank">docs</a>
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
<div className="p-4 border border-gray-200 rounded-md bg-gray-50">
|
||||
<div className="flex">
|
||||
<div className="flex-1 ml-3 md:flex md:justify-between">
|
||||
<p className="text-sm text-gray-700">
|
||||
Are you ready to go live and receive submissions? Go to{" "}
|
||||
<Link href="pipelines">
|
||||
<a>Pipelines</a>
|
||||
</Link>{" "}
|
||||
to pipe your submissions to other systems or go straight
|
||||
to the{" "}
|
||||
<Link href="results">
|
||||
<a>Results</a>
|
||||
</Link>{" "}
|
||||
to see how your form is used and keep track of your
|
||||
submissions.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -38,8 +38,12 @@ export default function LayoutShare({ title, formId, currentStep, children }) {
|
||||
</header>
|
||||
|
||||
{/* Main content */}
|
||||
<main className="max-w-lg px-4 pt-10 pb-12 mx-auto lg:pb-16">
|
||||
{children}
|
||||
<main>
|
||||
<div className="mx-auto max-w-7xl sm:px-6 lg:px-8">
|
||||
{/* Replace with your content */}
|
||||
{children}
|
||||
{/* /End replace */}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,7 +1,7 @@
|
||||
import useSWR from "swr";
|
||||
import { fetcher } from "./utils";
|
||||
|
||||
export const useAnswerSessions = (formId: string) => {
|
||||
export const useSubmissionSessions = (formId: string) => {
|
||||
const { data, error, mutate } = useSWR(
|
||||
() => `/api/forms/${formId}/submissionSessions`,
|
||||
fetcher
|
||||
@@ -9,8 +9,8 @@ export const useAnswerSessions = (formId: string) => {
|
||||
|
||||
return {
|
||||
submissionSessions: data,
|
||||
isLoadingAnswerSessions: !error && !data,
|
||||
isErrorAnswerSessions: error,
|
||||
mutateAnswerSessions: mutate,
|
||||
isLoadingSubmissionSessions: !error && !data,
|
||||
isErrorSubmissionSessions: error,
|
||||
mutateSubmissionSessions: mutate,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -25,11 +25,13 @@
|
||||
"react-contenteditable": "^3.3.6",
|
||||
"react-dom": "18.1.0",
|
||||
"react-feather": "^2.0.9",
|
||||
"react-icons": "^4.4.0",
|
||||
"superjson": "^1.9.1",
|
||||
"swr": "^1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/forms": "^0.5.1",
|
||||
"@tailwindcss/typography": "^0.5.2",
|
||||
"@types/bcryptjs": "^2.4.2",
|
||||
"@types/node": "17.0.32",
|
||||
"@types/react": "18.0.9",
|
||||
|
||||
@@ -2,8 +2,9 @@ import { GetServerSideProps } from "next";
|
||||
import { getSession } from "next-auth/react";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
import FormOnboardingModal from "../../../components/build/FormOnboardingModal";
|
||||
import LayoutResults from "../../../components/layout/LayoutResults";
|
||||
import FormCode from "../../../components/form/FormCode";
|
||||
import FormOnboardingModal from "../../../components/form/FormOnboardingModal";
|
||||
import LayoutFormBasics from "../../../components/layout/LayoutFormBasic";
|
||||
import Loading from "../../../components/Loading";
|
||||
import { useForm } from "../../../lib/forms";
|
||||
|
||||
@@ -23,18 +24,32 @@ export default function FormPage() {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<LayoutResults title={form.title} formId={formId} currentStep="form">
|
||||
<div>Form</div>
|
||||
<FormOnboardingModal
|
||||
open={openOnboardingModal}
|
||||
setOpen={setOpenOnboardingModal}
|
||||
formId={formId}
|
||||
/>
|
||||
</LayoutResults>
|
||||
</>
|
||||
);
|
||||
if (form.formType === "NOCODE") {
|
||||
return (
|
||||
<>
|
||||
<LayoutFormBasics title={form.title} formId={formId} currentStep="form">
|
||||
<FormOnboardingModal
|
||||
open={openOnboardingModal}
|
||||
setOpen={setOpenOnboardingModal}
|
||||
formId={formId}
|
||||
/>
|
||||
</LayoutFormBasics>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
<LayoutFormBasics title={form.title} formId={formId} currentStep="form">
|
||||
<FormCode />
|
||||
<FormOnboardingModal
|
||||
open={openOnboardingModal}
|
||||
setOpen={setOpenOnboardingModal}
|
||||
formId={formId}
|
||||
/>
|
||||
</LayoutFormBasics>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async ({ req, res }) => {
|
||||
|
||||
26
pages/forms/[id]/index.tsx
Normal file
26
pages/forms/[id]/index.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect } from "react";
|
||||
import Loading from "../../../components/Loading";
|
||||
import { useSubmissionSessions } from "../../../lib/submissionSessions";
|
||||
|
||||
export default function FormIndex() {
|
||||
const router = useRouter();
|
||||
console.log(router.query);
|
||||
const formId = router.query.id;
|
||||
const { submissionSessions, isLoadingSubmissionSessions } =
|
||||
useSubmissionSessions(formId?.toString());
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoadingSubmissionSessions) {
|
||||
// redirect to /results if there is at least one submissionSession
|
||||
if (submissionSessions.length > 0) {
|
||||
router.push(`/forms/${formId}/results`);
|
||||
} else {
|
||||
// redirect to /form if there isn't one submissionSession
|
||||
router.push(`/forms/${formId}/form`);
|
||||
}
|
||||
}
|
||||
}, [isLoadingSubmissionSessions]);
|
||||
|
||||
return <Loading />;
|
||||
}
|
||||
@@ -1,9 +1,55 @@
|
||||
import { GetServerSideProps } from "next";
|
||||
import { getSession } from "next-auth/react";
|
||||
import { useRouter } from "next/router";
|
||||
import LayoutResults from "../../../components/layout/LayoutResults";
|
||||
import LayoutFormBasics from "../../../components/layout/LayoutFormBasic";
|
||||
import Loading from "../../../components/Loading";
|
||||
import { useForm } from "../../../lib/forms";
|
||||
import { BiPlug } from "react-icons/bi";
|
||||
import { SiZapier, SiAirtable, SiSlack } from "react-icons/si";
|
||||
import { FaCode, FaGoogle } from "react-icons/fa";
|
||||
import { classNames } from "../../../lib/utils";
|
||||
|
||||
const libs = [
|
||||
{
|
||||
id: "webhook",
|
||||
name: "Webhook",
|
||||
href: "#",
|
||||
bgColor: "bg-red-500",
|
||||
icon: FaCode,
|
||||
},
|
||||
{
|
||||
id: "googleSheets",
|
||||
name: "Google Sheets",
|
||||
comingSoon: true,
|
||||
href: "#",
|
||||
bgColor: "bg-green-700",
|
||||
icon: FaGoogle,
|
||||
},
|
||||
{
|
||||
id: "zapier",
|
||||
name: "Zapier",
|
||||
comingSoon: true,
|
||||
href: "#",
|
||||
bgColor: "bg-orange-500",
|
||||
icon: SiZapier,
|
||||
},
|
||||
{
|
||||
id: "airtable",
|
||||
name: "Airtable",
|
||||
comingSoon: true,
|
||||
href: "#",
|
||||
bgColor: "bg-sky-400",
|
||||
icon: SiAirtable,
|
||||
},
|
||||
{
|
||||
id: "slack",
|
||||
name: "Slack",
|
||||
comingSoon: true,
|
||||
href: "#",
|
||||
bgColor: "bg-purple-800",
|
||||
icon: SiSlack,
|
||||
},
|
||||
];
|
||||
|
||||
export default function PipelinesPage() {
|
||||
const router = useRouter();
|
||||
@@ -16,9 +62,96 @@ export default function PipelinesPage() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<LayoutResults title={form.title} formId={formId} currentStep="pipelines">
|
||||
<div>Pipelines</div>
|
||||
</LayoutResults>
|
||||
<LayoutFormBasics
|
||||
title={form.title}
|
||||
formId={formId}
|
||||
currentStep="pipelines"
|
||||
>
|
||||
<header>
|
||||
<div className="mx-auto mt-8 max-w-7xl">
|
||||
<h1 className="text-3xl font-bold leading-tight text-gray-900">
|
||||
Pipe your data
|
||||
</h1>
|
||||
</div>
|
||||
</header>
|
||||
<div className="my-4">
|
||||
<p className="text-gray-700">
|
||||
snoopHub automatically stores your data and gives you and overview
|
||||
of your submissions and form analytics. If you want to use your
|
||||
submissions or form events in other systems you can set up pipelines
|
||||
to let snoopHub sent the data to these applications as soon as it
|
||||
arrives.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs font-medium tracking-wide text-gray-500 uppercase">
|
||||
Active integrations
|
||||
</div>
|
||||
<div className="p-3 my-5 text-center border rounded-lg shadow-inner sm:p-6">
|
||||
<BiPlug className="w-12 h-12 mx-auto text-gray-400" />
|
||||
|
||||
<h3 className="mt-2 text-sm font-medium text-gray-900">
|
||||
You don't have any active pipelines
|
||||
</h3>
|
||||
<p className="mt-1 text-sm text-gray-500">
|
||||
Choose a method from the available integrations and set up your
|
||||
pipeline
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="mt-8">
|
||||
<div>
|
||||
<p className="text-xs font-medium tracking-wide text-gray-500 uppercase">
|
||||
Available integrations
|
||||
</p>
|
||||
|
||||
<ul
|
||||
role="list"
|
||||
className="grid grid-cols-1 gap-5 mt-3 sm:gap-6 sm:grid-cols-3 lg:grid-cols-3"
|
||||
>
|
||||
{libs.map((lib) => (
|
||||
<a
|
||||
className="flex col-span-1 rounded-md shadow-sm"
|
||||
key={lib.id}
|
||||
>
|
||||
<li
|
||||
className={classNames(
|
||||
lib.comingSoon ? "opacity-50" : "",
|
||||
"flex col-span-1 rounded-md shadow-sm w-full"
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
lib.bgColor,
|
||||
"flex-shrink-0 flex items-center justify-center w-16 text-white text-sm font-medium rounded-l-md"
|
||||
)}
|
||||
>
|
||||
<lib.icon className="w-5 h-5" />
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
lib.comingSoon ? "border-dashed" : "",
|
||||
"flex items-center justify-between flex-1 truncate bg-white border-t border-b border-r border-gray-200 rounded-r-md"
|
||||
)}
|
||||
>
|
||||
<div className="inline-flex px-4 py-8 text-sm truncate">
|
||||
<p className="font-medium text-gray-900 hover:text-gray-600">
|
||||
{lib.name}
|
||||
</p>
|
||||
{lib.comingSoon && (
|
||||
<p className="ml-1 text-gray-500">(coming soon)</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</a>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</LayoutFormBasics>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
import { GetServerSideProps } from "next";
|
||||
import { getSession } from "next-auth/react";
|
||||
import { useRouter } from "next/router";
|
||||
import LayoutResults from "../../../components/layout/LayoutResults";
|
||||
import LayoutFormBasics from "../../../components/layout/LayoutFormBasic";
|
||||
import Loading from "../../../components/Loading";
|
||||
import Submission from "../../../components/results/Submission";
|
||||
import { useForm } from "../../../lib/forms";
|
||||
import { useAnswerSessions } from "../../../lib/submissionSessions";
|
||||
import { useSubmissionSessions } from "../../../lib/submissionSessions";
|
||||
|
||||
export default function Share() {
|
||||
const router = useRouter();
|
||||
const formId = router.query.id.toString();
|
||||
const { form, isLoadingForm } = useForm(router.query.id);
|
||||
const { submissionSessions, isLoadingAnswerSessions } = useAnswerSessions(
|
||||
form?.id
|
||||
);
|
||||
const { submissionSessions, isLoadingSubmissionSessions } =
|
||||
useSubmissionSessions(form?.id);
|
||||
|
||||
if (isLoadingForm || isLoadingAnswerSessions) {
|
||||
if (isLoadingForm || isLoadingSubmissionSessions) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<LayoutResults title={form.title} formId={formId} currentStep="results">
|
||||
<LayoutFormBasics
|
||||
title={form.title}
|
||||
formId={formId}
|
||||
currentStep="results"
|
||||
>
|
||||
<div className="bg-white shadow sm:rounded-lg">
|
||||
<div className="px-4 py-5 sm:p-6">
|
||||
<h3 className="text-lg font-medium leading-6 text-gray-900">
|
||||
@@ -39,7 +42,7 @@ export default function Share() {
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</LayoutResults>
|
||||
</LayoutFormBasics>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "FormType" AS ENUM ('CODE', 'NOCODE');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "PipelineType" AS ENUM ('WEBHOOK');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Form" (
|
||||
"id" TEXT NOT NULL,
|
||||
@@ -16,6 +19,18 @@ CREATE TABLE "Form" (
|
||||
CONSTRAINT "Form_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Pipeline" (
|
||||
"id" TEXT NOT NULL,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
"type" "PipelineType" NOT NULL,
|
||||
"formId" TEXT NOT NULL,
|
||||
"data" JSONB NOT NULL,
|
||||
|
||||
CONSTRAINT "Pipeline_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SubmissionSession" (
|
||||
"id" TEXT NOT NULL,
|
||||
@@ -73,6 +88,9 @@ CREATE UNIQUE INDEX "verification_requests_token_key" ON "verification_requests"
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Form" ADD CONSTRAINT "Form_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Pipeline" ADD CONSTRAINT "Pipeline_formId_fkey" FOREIGN KEY ("formId") REFERENCES "Form"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SubmissionSession" ADD CONSTRAINT "SubmissionSession_formId_fkey" FOREIGN KEY ("formId") REFERENCES "Form"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
@@ -12,6 +12,10 @@ enum FormType {
|
||||
NOCODE
|
||||
}
|
||||
|
||||
enum PipelineType {
|
||||
WEBHOOK
|
||||
}
|
||||
|
||||
model Form {
|
||||
id String @id
|
||||
createdAt DateTime @default(now())
|
||||
@@ -24,6 +28,17 @@ model Form {
|
||||
finishedOnboarding Boolean @default(false)
|
||||
schema Json
|
||||
submissionSessions SubmissionSession[]
|
||||
pipelines Pipeline[]
|
||||
}
|
||||
|
||||
model Pipeline {
|
||||
id String @id @default(uuid())
|
||||
createdAt DateTime @default(now()) @map(name: "created_at")
|
||||
updatedAt DateTime @updatedAt @map(name: "updated_at")
|
||||
type PipelineType
|
||||
form Form @relation(fields: [formId], references: [id], onDelete: Cascade)
|
||||
formId String
|
||||
data Json
|
||||
}
|
||||
|
||||
model SubmissionSession {
|
||||
@@ -42,7 +57,7 @@ model SessionEvent {
|
||||
updatedAt DateTime @updatedAt @map(name: "updated_at")
|
||||
submissionSession SubmissionSession @relation(fields: [submissionSessionId], references: [id], onDelete: Cascade)
|
||||
submissionSessionId String
|
||||
type String
|
||||
type String
|
||||
data Json
|
||||
}
|
||||
|
||||
|
||||
@@ -6,5 +6,5 @@ module.exports = {
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [require("@tailwindcss/forms")],
|
||||
plugins: [require("@tailwindcss/forms"), require("@tailwindcss/typography")],
|
||||
};
|
||||
|
||||
46
yarn.lock
46
yarn.lock
@@ -220,6 +220,15 @@
|
||||
dependencies:
|
||||
mini-svg-data-uri "^1.2.3"
|
||||
|
||||
"@tailwindcss/typography@^0.5.2":
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.2.tgz#24b069dab24d7a2467d01aca0dd432cb4b29f0ee"
|
||||
integrity sha512-coq8DBABRPFcVhVIk6IbKyyHUt7YTEC/C992tatFB+yEx5WGBQrCgsSFjxHUr8AWXphWckadVJbominEduYBqw==
|
||||
dependencies:
|
||||
lodash.castarray "^4.4.0"
|
||||
lodash.isplainobject "^4.0.6"
|
||||
lodash.merge "^4.6.2"
|
||||
|
||||
"@tsconfig/node10@^1.0.7":
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9"
|
||||
@@ -1234,6 +1243,16 @@ has@^1.0.3:
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
|
||||
highlight.js@^10.5.0:
|
||||
version "10.7.3"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531"
|
||||
integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==
|
||||
|
||||
highlight.js@^11.5.1:
|
||||
version "11.5.1"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.5.1.tgz#027c24e4509e2f4dcd00b4a6dda542ce0a1f7aea"
|
||||
integrity sha512-LKzHqnxr4CrD2YsNoIf/o5nJ09j4yi/GcH5BnYz9UnVpZdS4ucMgvP61TDty5xJcFGRjnH4DpujkS9bHT3hq0Q==
|
||||
|
||||
hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||
@@ -1477,6 +1496,16 @@ lodash-es@^4.17.15:
|
||||
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
|
||||
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
|
||||
|
||||
lodash.castarray@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115"
|
||||
integrity sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==
|
||||
|
||||
lodash.isplainobject@^4.0.6:
|
||||
version "4.0.6"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
|
||||
integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==
|
||||
|
||||
lodash.merge@^4.6.2:
|
||||
version "4.6.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
||||
@@ -1888,6 +1917,11 @@ prisma@^3.15.1:
|
||||
dependencies:
|
||||
"@prisma/engines" "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e"
|
||||
|
||||
prismjs@^1.28.0:
|
||||
version "1.28.0"
|
||||
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.28.0.tgz#0d8f561fa0f7cf6ebca901747828b149147044b6"
|
||||
integrity sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw==
|
||||
|
||||
prop-types@^15.5.10, prop-types@^15.7.1, prop-types@^15.7.2, prop-types@^15.8.1:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
@@ -1966,6 +2000,18 @@ react-feather@^2.0.9:
|
||||
dependencies:
|
||||
prop-types "^15.7.2"
|
||||
|
||||
react-highlight@^0.14.0:
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/react-highlight/-/react-highlight-0.14.0.tgz#5aefa5518baa580f96b68d48129d7a5d2dc0c9ef"
|
||||
integrity sha512-kWE+KXOXidS7SABhVopOgMnowbI3RAfeGZbnrduLNlWrYAED8sycL9l/Fvw3w0PFpIIawB7mRDnyhDcM/cIIGA==
|
||||
dependencies:
|
||||
highlight.js "^10.5.0"
|
||||
|
||||
react-icons@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.4.0.tgz#a13a8a20c254854e1ec9aecef28a95cdf24ef703"
|
||||
integrity sha512-fSbvHeVYo/B5/L4VhB7sBA1i2tS8MkT0Hb9t2H1AVPkwGfVHLJCqyr2Py9dKMxsyM63Eng1GkdZfbWj+Fmv8Rg==
|
||||
|
||||
react-is@^16.13.1, react-is@^16.7.0:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
|
||||
Reference in New Issue
Block a user