{form.label} - {team.name} + {workspace.name}
@@ -174,7 +176,7 @@ export default function FormOverviewPage() {{form.label}
Forms - {team.name} + {workspace.name}
-Device
-{submission.meta.userAgent}
++ {parseUserAgent(submission.meta.userAgent)} +
Page
diff --git a/apps/hq/src/components/forms/feedback/SetupInstructions.tsx b/apps/web/src/components/forms/feedback/SetupInstructions.tsx similarity index 100% rename from apps/hq/src/components/forms/feedback/SetupInstructions.tsx rename to apps/web/src/components/forms/feedback/SetupInstructions.tsx diff --git a/apps/hq/src/components/forms/pipelines/AddPipelineModal.tsx b/apps/web/src/components/forms/pipelines/AddPipelineModal.tsx similarity index 97% rename from apps/hq/src/components/forms/pipelines/AddPipelineModal.tsx rename to apps/web/src/components/forms/pipelines/AddPipelineModal.tsx index 1c5055160f..b7120f6b09 100644 --- a/apps/hq/src/components/forms/pipelines/AddPipelineModal.tsx +++ b/apps/web/src/components/forms/pipelines/AddPipelineModal.tsx @@ -23,7 +23,7 @@ export default function AddPipelineModal({ open, setOpen }) { const [pipeline, setPipeline] = useState(getEmptyPipeline()); const { pipelines, mutatePipelines } = usePipelines( router.query.formId?.toString(), - router.query.teamId?.toString() + router.query.workspaceId?.toString() ); useEffect(() => { @@ -43,7 +43,7 @@ export default function AddPipelineModal({ open, setOpen }) { e.preventDefault(); const newPipeline = await createPipeline( router.query.formId?.toString(), - router.query.teamId?.toString(), + router.query.workspaceId?.toString(), pipeline ); const newPipelines = JSON.parse(JSON.stringify(pipelines)); diff --git a/apps/hq/src/components/forms/pipelines/PipelineSettings.tsx b/apps/web/src/components/forms/pipelines/PipelineSettings.tsx similarity index 100% rename from apps/hq/src/components/forms/pipelines/PipelineSettings.tsx rename to apps/web/src/components/forms/pipelines/PipelineSettings.tsx diff --git a/apps/hq/src/components/forms/pipelines/PipelinesOverview.tsx b/apps/web/src/components/forms/pipelines/PipelinesOverview.tsx similarity index 95% rename from apps/hq/src/components/forms/pipelines/PipelinesOverview.tsx rename to apps/web/src/components/forms/pipelines/PipelinesOverview.tsx index 75b5aa51ce..7ed987a0c4 100644 --- a/apps/hq/src/components/forms/pipelines/PipelinesOverview.tsx +++ b/apps/web/src/components/forms/pipelines/PipelinesOverview.tsx @@ -4,7 +4,7 @@ import EmptyPageFiller from "@/components/EmptyPageFiller"; import LoadingSpinner from "@/components/LoadingSpinner"; import { useForm } from "@/lib/forms"; import { deletePipeline, persistPipeline, usePipelines } from "@/lib/pipelines"; -import { useTeam } from "@/lib/teams"; +import { useWorkspace } from "@/lib/workspaces"; import { Button } from "@formbricks/ui"; import { Switch } from "@headlessui/react"; import { BoltIcon, Cog6ToothIcon, TrashIcon } from "@heroicons/react/20/solid"; @@ -87,12 +87,14 @@ export default function PipelinesOverview({}) { const router = useRouter(); const { form, isLoadingForm, isErrorForm } = useForm( router.query.formId?.toString(), - router.query.teamId?.toString() + router.query.workspaceId?.toString() + ); + const { workspace, isLoadingWorkspace, isErrorWorkspace } = useWorkspace( + router.query.workspaceId?.toString() ); - const { team, isLoadingTeam, isErrorTeam } = useTeam(router.query.teamId?.toString()); const { pipelines, isLoadingPipelines, isErrorPipelines, mutatePipelines } = usePipelines( router.query.formId?.toString(), - router.query.teamId?.toString() + router.query.workspaceId?.toString() ); const [openAddModal, setOpenAddModal] = useState(false); @@ -102,7 +104,7 @@ export default function PipelinesOverview({}) { const toggleEnabled = async (pipeline) => { const newPipeline = JSON.parse(JSON.stringify(pipeline)); newPipeline.enabled = !newPipeline.enabled; - await persistPipeline(router.query.formId, router.query.teamId, newPipeline); + await persistPipeline(router.query.formId, router.query.workspaceId, newPipeline); const pipelineIdx = pipelines.findIndex((p) => p.id === pipeline.id); if (pipelineIdx !== -1) { const newPipelines = JSON.parse(JSON.stringify(pipelines)); @@ -117,7 +119,7 @@ export default function PipelinesOverview({}) { }; const deletePipelineAction = async (pipelineId) => { - await deletePipeline(router.query.formId?.toString(), router.query.teamId?.toString(), pipelineId); + await deletePipeline(router.query.formId?.toString(), router.query.workspaceId?.toString(), pipelineId); const newPipelines = JSON.parse(JSON.stringify(pipelines)); const pipelineIdx = newPipelines.findIndex((p) => p.id === pipelineId); if (pipelineIdx > -1) { @@ -126,7 +128,7 @@ export default function PipelinesOverview({}) { } }; - if (isLoadingForm || isLoadingTeam || isLoadingPipelines) { + if (isLoadingForm || isLoadingWorkspace || isLoadingPipelines) { return (Summary - {form.label} - {team.name} + {workspace.name}
diff --git a/apps/hq/src/components/layout/LayoutApp.tsx b/apps/web/src/components/layout/LayoutApp.tsx similarity index 98% rename from apps/hq/src/components/layout/LayoutApp.tsx rename to apps/web/src/components/layout/LayoutApp.tsx index 6a755f1739..5a95dcb8ec 100644 --- a/apps/hq/src/components/layout/LayoutApp.tsx +++ b/apps/web/src/components/layout/LayoutApp.tsx @@ -18,7 +18,7 @@ export default function LayoutApp({ children }) { { name: "Settings", onClick: () => { - router.push("/app/me/settings"); + router.push("/me/settings"); }, }, { name: "Sign out", onClick: () => signOut() }, @@ -51,7 +51,7 @@ export default function LayoutApp({ children }) {Settings - {team.name} + {workspace.name}
@@ -38,7 +40,9 @@ export default function SettingsPage() {Team Management Settings coming to Formbricks HQ soon.
++ Workspace Management Settings coming to Formbricks HQ soon. +
${verificationRequestLink}
- Your Formbricks Team`, + Your Formbricks Workspace`, }); }; @@ -66,7 +66,7 @@ export const sendForgotPasswordEmail = async (user) => {
Your password won't change until you access the link above and create a new one.
- Your Formbricks Team`, + Your Formbricks Workspace`, }); }; @@ -76,13 +76,13 @@ export const sendPasswordResetNotifyEmail = async (user) => { subject: "Your Formbricks password has been changed", html: `We're contacting you to notify you that your password has been changed.
- Your Formbricks Team`, + Your Formbricks Workspace`, }); }; export const sendSubmissionEmail = async ( email: string, - teamId, + workspaceId, formId, formLabel: string, schema: any, @@ -104,7 +104,7 @@ export const sendSubmissionEmail = async ( Click here to see new submission. + }/workspaces/${workspaceId}/forms/${formId}/feedback">here to see new submission. ${submission.customer?.email ? "
You can reply to this email to contact the user directly." : ""}`, }); }; diff --git a/apps/hq/src/lib/forms.ts b/apps/web/src/lib/forms.ts similarity index 77% rename from apps/hq/src/lib/forms.ts rename to apps/web/src/lib/forms.ts index 88dc16c75c..99f8edb57a 100644 --- a/apps/hq/src/lib/forms.ts +++ b/apps/web/src/lib/forms.ts @@ -1,8 +1,8 @@ import useSWR from "swr"; import { fetcher } from "./utils"; -export const useForms = (teamId: string) => { - const { data, error, mutate } = useSWR(`/api/teams/${teamId}/forms`, fetcher); +export const useForms = (workspaceId: string) => { + const { data, error, mutate } = useSWR(`/api/workspaces/${workspaceId}/forms`, fetcher); return { forms: data, @@ -12,8 +12,8 @@ export const useForms = (teamId: string) => { }; }; -export const useForm = (id: string, teamId: string) => { - const { data, error, mutate } = useSWR(`/api/teams/${teamId}/forms/${id}`, fetcher); +export const useForm = (id: string, workspaceId: string) => { + const { data, error, mutate } = useSWR(`/api/workspaces/${workspaceId}/forms/${id}`, fetcher); return { form: data, @@ -25,7 +25,7 @@ export const useForm = (id: string, teamId: string) => { export const persistForm = async (form) => { try { - await fetch(`/api/teams/${form.teamId}/forms/${form.id}/`, { + await fetch(`/api/workspaces/${form.workspaceId}/forms/${form.id}/`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(form), @@ -35,9 +35,9 @@ export const persistForm = async (form) => { } }; -export const createForm = async (teamId: string, form = {}) => { +export const createForm = async (workspaceId: string, form = {}) => { try { - const res = await fetch(`/api/teams/${teamId}/forms`, { + const res = await fetch(`/api/workspaces/${workspaceId}/forms`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(form), @@ -49,9 +49,9 @@ export const createForm = async (teamId: string, form = {}) => { } }; -export const deleteForm = async (teamId: string, formId: string) => { +export const deleteForm = async (workspaceId: string, formId: string) => { try { - await fetch(`/api/teams/${teamId}/forms/${formId}`, { + await fetch(`/api/workspaces/${workspaceId}/forms/${formId}`, { method: "DELETE", }); } catch (error) { diff --git a/apps/hq/src/lib/jwt.ts b/apps/web/src/lib/jwt.ts similarity index 100% rename from apps/hq/src/lib/jwt.ts rename to apps/web/src/lib/jwt.ts diff --git a/apps/hq/src/lib/memberships.ts b/apps/web/src/lib/memberships.ts similarity index 100% rename from apps/hq/src/lib/memberships.ts rename to apps/web/src/lib/memberships.ts diff --git a/apps/hq/src/lib/pipelines.ts b/apps/web/src/lib/pipelines.ts similarity index 54% rename from apps/hq/src/lib/pipelines.ts rename to apps/web/src/lib/pipelines.ts index 1e79936d12..2d18707bcc 100644 --- a/apps/hq/src/lib/pipelines.ts +++ b/apps/web/src/lib/pipelines.ts @@ -2,8 +2,8 @@ import useSWR from "swr"; import { fetcher } from "./utils"; -export const usePipelines = (formId: string, teamId: string) => { - const { data, error, mutate } = useSWR(`/api/teams/${teamId}/forms/${formId}/pipelines`, fetcher); +export const usePipelines = (formId: string, workspaceId: string) => { + const { data, error, mutate } = useSWR(`/api/workspaces/${workspaceId}/forms/${formId}/pipelines`, fetcher); return { pipelines: data, @@ -13,9 +13,9 @@ export const usePipelines = (formId: string, teamId: string) => { }; }; -export const usePipeline = (teamId: string, formId: string, pipelineId: string) => { +export const usePipeline = (workspaceId: string, formId: string, pipelineId: string) => { const { data, error, mutate } = useSWR( - `/api/teams/${teamId}/forms/${formId}/pipelines/${pipelineId}`, + `/api/workspaces/${workspaceId}/forms/${formId}/pipelines/${pipelineId}`, fetcher ); @@ -27,9 +27,9 @@ export const usePipeline = (teamId: string, formId: string, pipelineId: string) }; }; -export const persistPipeline = async (formId, teamId, pipeline) => { +export const persistPipeline = async (formId, workspaceId, pipeline) => { try { - await fetch(`/api/teams/${teamId}/forms/${formId}/pipelines/${pipeline.id}/`, { + await fetch(`/api/workspaces/${workspaceId}/forms/${formId}/pipelines/${pipeline.id}/`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(pipeline), @@ -39,9 +39,9 @@ export const persistPipeline = async (formId, teamId, pipeline) => { } }; -export const createPipeline = async (formId: string, teamId: string, pipeline = {}) => { +export const createPipeline = async (formId: string, workspaceId: string, pipeline = {}) => { try { - const res = await fetch(`/api/teams/${teamId}/forms/${formId}/pipelines`, { + const res = await fetch(`/api/workspaces/${workspaceId}/forms/${formId}/pipelines`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(pipeline), @@ -53,9 +53,9 @@ export const createPipeline = async (formId: string, teamId: string, pipeline = } }; -export const deletePipeline = async (formId: string, teamId: string, pipelineId: string) => { +export const deletePipeline = async (formId: string, workspaceId: string, pipelineId: string) => { try { - await fetch(`/api/teams/${teamId}/forms/${formId}/pipelines/${pipelineId}`, { + await fetch(`/api/workspaces/${workspaceId}/forms/${formId}/pipelines/${pipelineId}`, { method: "DELETE", }); } catch (error) { diff --git a/apps/hq/src/lib/pipelinesHandler.ts b/apps/web/src/lib/pipelinesHandler.ts similarity index 92% rename from apps/hq/src/lib/pipelinesHandler.ts rename to apps/web/src/lib/pipelinesHandler.ts index b2381adeb5..1e7b7919fb 100644 --- a/apps/hq/src/lib/pipelinesHandler.ts +++ b/apps/web/src/lib/pipelinesHandler.ts @@ -50,7 +50,7 @@ async function handleEmailNotification(pipeline, form, submission) { const { email } = pipeline.config.valueOf() as { email: string }; if (pipeline.events.includes("submissionCreated")) { - await sendSubmissionEmail(email, form.teamId, form.id, form.label, form.schema, submission); + await sendSubmissionEmail(email, form.workspaceId, form.id, form.label, form.schema, submission); } } @@ -64,7 +64,7 @@ async function handleSlackNotification(pipeline, form, submission) { type: "section", text: { type: "mrkdwn", - text: `Someone just filled out your form "${form.label}". <${process.env.NEXTAUTH_URL}/app/teams/${form.teamId}/forms/${form.id}/feedback|View in Formbricks>`, + text: `Someone just filled out your form "${form.label}". <${process.env.NEXTAUTH_URL}/workspaces/${form.workspaceId}/forms/${form.id}/feedback|View in Formbricks>`, }, }, { diff --git a/apps/hq/src/lib/posthog.ts b/apps/web/src/lib/posthog.ts similarity index 100% rename from apps/hq/src/lib/posthog.ts rename to apps/web/src/lib/posthog.ts diff --git a/apps/hq/src/lib/session.ts b/apps/web/src/lib/session.ts similarity index 100% rename from apps/hq/src/lib/session.ts rename to apps/web/src/lib/session.ts diff --git a/apps/hq/src/lib/submissions.ts b/apps/web/src/lib/submissions.ts similarity index 64% rename from apps/hq/src/lib/submissions.ts rename to apps/web/src/lib/submissions.ts index e9b7d6c0c1..5fbe51584b 100644 --- a/apps/hq/src/lib/submissions.ts +++ b/apps/web/src/lib/submissions.ts @@ -1,8 +1,11 @@ import useSWR from "swr"; import { fetcher } from "@/lib/utils"; -export const useSubmissions = (teamId: string, formId: string) => { - const { data, error, mutate } = useSWR(`/api/teams/${teamId}/forms/${formId}/submissions`, fetcher); +export const useSubmissions = (workspaceId: string, formId: string) => { + const { data, error, mutate } = useSWR( + `/api/workspaces/${workspaceId}/forms/${formId}/submissions`, + fetcher + ); return { submissions: data, @@ -12,9 +15,9 @@ export const useSubmissions = (teamId: string, formId: string) => { }; }; -export const deleteSubmission = async (teamId: string, formId: string, submissionId: string) => { +export const deleteSubmission = async (workspaceId: string, formId: string, submissionId: string) => { try { - await fetch(`/api/teams/${teamId}/forms/${formId}/submissions/${submissionId}`, { + await fetch(`/api/workspaces/${workspaceId}/forms/${formId}/submissions/${submissionId}`, { method: "DELETE", }); } catch (error) { @@ -23,9 +26,9 @@ export const deleteSubmission = async (teamId: string, formId: string, submissio } }; -export const persistSubmission = async (submission, teamId) => { +export const persistSubmission = async (submission, workspaceId) => { try { - await fetch(`/api/teams/${teamId}/forms/${submission.formId}/submissions/${submission.id}/`, { + await fetch(`/api/workspaces/${workspaceId}/forms/${submission.formId}/submissions/${submission.id}/`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(submission), diff --git a/apps/hq/src/lib/telemetry.ts b/apps/web/src/lib/telemetry.ts similarity index 100% rename from apps/hq/src/lib/telemetry.ts rename to apps/web/src/lib/telemetry.ts diff --git a/apps/hq/src/lib/token.ts b/apps/web/src/lib/token.ts similarity index 100% rename from apps/hq/src/lib/token.ts rename to apps/web/src/lib/token.ts diff --git a/apps/hq/src/lib/users.ts b/apps/web/src/lib/users.ts similarity index 100% rename from apps/hq/src/lib/users.ts rename to apps/web/src/lib/users.ts diff --git a/apps/hq/src/lib/utils.ts b/apps/web/src/lib/utils.ts similarity index 91% rename from apps/hq/src/lib/utils.ts rename to apps/web/src/lib/utils.ts index 6214a820d3..32d3977ce5 100644 --- a/apps/hq/src/lib/utils.ts +++ b/apps/web/src/lib/utils.ts @@ -1,6 +1,7 @@ import crypto from "crypto"; import intlFormat from "date-fns/intlFormat"; import { formatDistance } from "date-fns"; +import platform from "platform"; export const fetcher = async (url) => { const res = await fetch(url); @@ -86,3 +87,8 @@ export const hashString = (string: string) => { export const onlyUnique = (value, index, self) => { return self.indexOf(value) === index; }; + +export const parseUserAgent = (userAgent: string) => { + const info = platform.parse(userAgent); + return info.description; +}; diff --git a/apps/web/src/lib/workspaces.ts b/apps/web/src/lib/workspaces.ts new file mode 100644 index 0000000000..69c42c6f3a --- /dev/null +++ b/apps/web/src/lib/workspaces.ts @@ -0,0 +1,13 @@ +import useSWR from "swr"; +import { fetcher } from "./utils"; + +export const useWorkspace = (id: string) => { + const { data, error, mutate } = useSWR(`/api/workspaces/${id}/`, fetcher); + + return { + workspace: data, + isLoadingWorkspace: !error && !data, + isErrorWorkspace: error, + mutateWorkspace: mutate, + }; +}; diff --git a/apps/hq/src/pages/_app.tsx b/apps/web/src/pages/_app.tsx similarity index 100% rename from apps/hq/src/pages/_app.tsx rename to apps/web/src/pages/_app.tsx diff --git a/apps/hq/src/pages/_document.tsx b/apps/web/src/pages/_document.tsx similarity index 100% rename from apps/hq/src/pages/_document.tsx rename to apps/web/src/pages/_document.tsx diff --git a/apps/hq/src/pages/_error.js b/apps/web/src/pages/_error.js similarity index 100% rename from apps/hq/src/pages/_error.js rename to apps/web/src/pages/_error.js diff --git a/apps/hq/src/pages/api/auth/[...nextauth].ts b/apps/web/src/pages/api/auth/[...nextauth].ts similarity index 98% rename from apps/hq/src/pages/api/auth/[...nextauth].ts rename to apps/web/src/pages/api/auth/[...nextauth].ts index f406c59706..ec7f07a9b6 100644 --- a/apps/hq/src/pages/api/auth/[...nextauth].ts +++ b/apps/web/src/pages/api/auth/[...nextauth].ts @@ -226,14 +226,14 @@ export const authOptions: NextAuthOptions = { accounts: { create: [{ ...account }], }, - teams: { + workspaces: { create: [ { accepted: true, role: "owner", - team: { + workspace: { create: { - name: `${user.name}'s Team`, + name: `${user.name}'s Workspace`, }, }, }, diff --git a/apps/hq/src/pages/api/capture/forms/[formId]/schema/index.ts b/apps/web/src/pages/api/capture/forms/[formId]/schema/index.ts similarity index 100% rename from apps/hq/src/pages/api/capture/forms/[formId]/schema/index.ts rename to apps/web/src/pages/api/capture/forms/[formId]/schema/index.ts diff --git a/apps/hq/src/pages/api/capture/forms/[formId]/submissions/index.ts b/apps/web/src/pages/api/capture/forms/[formId]/submissions/index.ts similarity index 90% rename from apps/hq/src/pages/api/capture/forms/[formId]/submissions/index.ts rename to apps/web/src/pages/api/capture/forms/[formId]/submissions/index.ts index ad2bf91f70..51fe74bf43 100644 --- a/apps/hq/src/pages/api/capture/forms/[formId]/submissions/index.ts +++ b/apps/web/src/pages/api/capture/forms/[formId]/submissions/index.ts @@ -43,14 +43,14 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) event.data.customer = { connectOrCreate: { where: { - id_teamId: { + id_workspaceId: { id: submission.customer.id, - teamId: form.teamId, + workspaceId: form.workspaceId, }, }, create: { id: customerId, - team: { connect: { id: form.teamId } }, + workspace: { connect: { id: form.workspaceId } }, data: customerData, }, }, @@ -61,7 +61,7 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) const submissionResult = await prisma.submission.create(event); await runPipelines(form, submission); // tracking - capturePosthogEvent(form.teamId, "submission received", { + capturePosthogEvent(form.workspaceId, "submission received", { formId, }); captureTelemetry("submission received"); diff --git a/apps/hq/src/pages/api/memberships/index.ts b/apps/web/src/pages/api/memberships/index.ts similarity index 90% rename from apps/hq/src/pages/api/memberships/index.ts rename to apps/web/src/pages/api/memberships/index.ts index 1fbfa00e56..1b8b74d20d 100644 --- a/apps/hq/src/pages/api/memberships/index.ts +++ b/apps/web/src/pages/api/memberships/index.ts @@ -9,15 +9,15 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.status(401).json({ message: "Not authenticated" }); } - // GET /api/teams - // Get all of my teams + // GET /api/workspaces + // Get all of my workspaces if (req.method === "GET") { const memberships = await prisma.membership.findMany({ where: { user: { email: session.email }, }, include: { - team: true, + workspace: true, }, }); return res.json(memberships); diff --git a/apps/hq/src/pages/api/users/forgot-password.tsx b/apps/web/src/pages/api/users/forgot-password.tsx similarity index 100% rename from apps/hq/src/pages/api/users/forgot-password.tsx rename to apps/web/src/pages/api/users/forgot-password.tsx diff --git a/apps/hq/src/pages/api/users/index.tsx b/apps/web/src/pages/api/users/index.tsx similarity index 94% rename from apps/hq/src/pages/api/users/index.tsx rename to apps/web/src/pages/api/users/index.tsx index c0839824c5..25c7fbc1d7 100644 --- a/apps/hq/src/pages/api/users/index.tsx +++ b/apps/web/src/pages/api/users/index.tsx @@ -21,14 +21,14 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) const userData = await prisma.user.create({ data: { ...user, - teams: { + workspaces: { create: [ { accepted: true, role: "owner", - team: { + workspace: { create: { - name: `${user.name}'s Team`, + name: `${user.name}'s Workspace`, }, }, }, diff --git a/apps/hq/src/pages/api/users/me/api-keys/[apiKeyId]/index.ts b/apps/web/src/pages/api/users/me/api-keys/[apiKeyId]/index.ts similarity index 100% rename from apps/hq/src/pages/api/users/me/api-keys/[apiKeyId]/index.ts rename to apps/web/src/pages/api/users/me/api-keys/[apiKeyId]/index.ts diff --git a/apps/hq/src/pages/api/users/me/api-keys/index.ts b/apps/web/src/pages/api/users/me/api-keys/index.ts similarity index 100% rename from apps/hq/src/pages/api/users/me/api-keys/index.ts rename to apps/web/src/pages/api/users/me/api-keys/index.ts diff --git a/apps/hq/src/pages/api/users/me/index.ts b/apps/web/src/pages/api/users/me/index.ts similarity index 100% rename from apps/hq/src/pages/api/users/me/index.ts rename to apps/web/src/pages/api/users/me/index.ts diff --git a/apps/hq/src/pages/api/users/reset-password.tsx b/apps/web/src/pages/api/users/reset-password.tsx similarity index 100% rename from apps/hq/src/pages/api/users/reset-password.tsx rename to apps/web/src/pages/api/users/reset-password.tsx diff --git a/apps/hq/src/pages/api/users/verification-email.tsx b/apps/web/src/pages/api/users/verification-email.tsx similarity index 100% rename from apps/hq/src/pages/api/users/verification-email.tsx rename to apps/web/src/pages/api/users/verification-email.tsx diff --git a/apps/hq/src/pages/api/teams/[teamId]/customers/[customerId]/index.ts b/apps/web/src/pages/api/workspaces/[workspaceId]/customers/[customerId]/index.ts similarity index 70% rename from apps/hq/src/pages/api/teams/[teamId]/customers/[customerId]/index.ts rename to apps/web/src/pages/api/workspaces/[workspaceId]/customers/[customerId]/index.ts index 149108afe5..08f0073fba 100644 --- a/apps/hq/src/pages/api/teams/[teamId]/customers/[customerId]/index.ts +++ b/apps/web/src/pages/api/workspaces/[workspaceId]/customers/[customerId]/index.ts @@ -9,31 +9,33 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.status(401).json({ message: "Not authenticated" }); } - const teamId = req.query.teamId.toString(); + const workspaceId = req.query.workspaceId.toString(); const customerId = req.query.customerId.toString(); - // check team permission + // check workspace permission const membership = await prisma.membership.findUnique({ where: { - userId_teamId: { + userId_workspaceId: { userId: user.id, - teamId, + workspaceId, }, }, }); if (membership === null) { - return res.status(403).json({ message: "You don't have access to this team or this team doesn't exist" }); + return res + .status(403) + .json({ message: "You don't have access to this workspace or this workspace doesn't exist" }); } - // GET /api/teams[teamId]/customers/[customerId] - // Get a specific team + // GET /api/workspaces[workspaceId]/customers/[customerId] + // Get a specific workspace if (req.method === "GET") { const customer = await prisma.customer.findUnique({ where: { - id_teamId: { + id_workspaceId: { id: customerId, - teamId, + workspaceId, }, }, include: { @@ -44,15 +46,15 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.json(customer); } - // POST /api/teams[teamId]/customer/[customerId] + // POST /api/workspaces[workspaceId]/customer/[customerId] // Replace a specific customer else if (req.method === "POST") { const data = { ...req.body, updatedAt: new Date() }; const prismaRes = await prisma.customer.update({ where: { - id_teamId: { + id_workspaceId: { id: customerId, - teamId, + workspaceId, }, }, data, @@ -60,14 +62,14 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.json(prismaRes); } - // Delete /api/teams[teamId]/customer/[customerId] + // Delete /api/workspaces[workspaceId]/customer/[customerId] // Deletes a single customer else if (req.method === "DELETE") { const prismaRes = await prisma.customer.delete({ where: { - id_teamId: { + id_workspaceId: { id: customerId, - teamId: teamId, + workspaceId: workspaceId, }, }, }); diff --git a/apps/hq/src/pages/api/teams/[teamId]/customers/index.ts b/apps/web/src/pages/api/workspaces/[workspaceId]/customers/index.ts similarity index 69% rename from apps/hq/src/pages/api/teams/[teamId]/customers/index.ts rename to apps/web/src/pages/api/workspaces/[workspaceId]/customers/index.ts index 8ff2831801..5d10257faa 100644 --- a/apps/hq/src/pages/api/teams/[teamId]/customers/index.ts +++ b/apps/web/src/pages/api/workspaces/[workspaceId]/customers/index.ts @@ -9,28 +9,30 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.status(401).json({ message: "Not authenticated" }); } - const teamId = req.query.teamId.toString(); + const workspaceId = req.query.workspaceId.toString(); - // check team permission + // check workspace permission const membership = await prisma.membership.findUnique({ where: { - userId_teamId: { + userId_workspaceId: { userId: user.id, - teamId, + workspaceId, }, }, }); if (membership === null) { - return res.status(403).json({ message: "You don't have access to this team or this team doesn't exist" }); + return res + .status(403) + .json({ message: "You don't have access to this workspace or this workspace doesn't exist" }); } - // GET /api/teams[teamId]/customers - // Get all customers of a specific team + // GET /api/workspaces[workspaceId]/customers + // Get all customers of a specific workspace if (req.method === "GET") { const forms = await prisma.customer.findMany({ where: { - team: { - id: teamId, + workspace: { + id: workspaceId, }, }, include: { diff --git a/apps/hq/src/pages/api/teams/[teamId]/forms/[formId]/index.ts b/apps/web/src/pages/api/workspaces/[workspaceId]/forms/[formId]/index.ts similarity index 72% rename from apps/hq/src/pages/api/teams/[teamId]/forms/[formId]/index.ts rename to apps/web/src/pages/api/workspaces/[workspaceId]/forms/[formId]/index.ts index a35d12b04f..5fc4d624b0 100644 --- a/apps/hq/src/pages/api/teams/[teamId]/forms/[formId]/index.ts +++ b/apps/web/src/pages/api/workspaces/[workspaceId]/forms/[formId]/index.ts @@ -10,37 +10,39 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.status(401).json({ message: "Not authenticated" }); } - const teamId = req.query.teamId.toString(); + const workspaceId = req.query.workspaceId.toString(); const formId = req.query.formId.toString(); - // check team permission + // check workspace permission const membership = await prisma.membership.findUnique({ where: { - userId_teamId: { + userId_workspaceId: { userId: user.id, - teamId, + workspaceId, }, }, }); if (membership === null) { - return res.status(403).json({ message: "You don't have access to this team or this team doesn't exist" }); + return res + .status(403) + .json({ message: "You don't have access to this workspace or this workspace doesn't exist" }); } - // GET /api/teams[teamId]/forms/[formId] - // Get a specific team + // GET /api/workspaces[workspaceId]/forms/[formId] + // Get a specific workspace if (req.method === "GET") { const forms = await prisma.form.findFirst({ where: { id: formId, - teamId, + workspaceId, }, }); return res.json(forms); } - // POST /api/teams[teamId]/forms/[formId] + // POST /api/workspaces[workspaceId]/forms/[formId] // Replace a specific form else if (req.method === "POST") { const data = { ...req.body, updatedAt: new Date() }; @@ -51,13 +53,13 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.json(prismaRes); } - // Delete /api/teams[teamId]/forms/[formId] + // Delete /api/workspaces[workspaceId]/forms/[formId] // Deletes a single form else if (req.method === "DELETE") { const prismaRes = await prisma.form.delete({ where: { id: formId }, }); - capturePosthogEvent(teamId, "form created", { + capturePosthogEvent(workspaceId, "form created", { formId, }); return res.json(prismaRes); diff --git a/apps/hq/src/pages/api/teams/[teamId]/forms/[formId]/pipelines/[pipelineId]/index.ts b/apps/web/src/pages/api/workspaces/[workspaceId]/forms/[formId]/pipelines/[pipelineId]/index.ts similarity index 73% rename from apps/hq/src/pages/api/teams/[teamId]/forms/[formId]/pipelines/[pipelineId]/index.ts rename to apps/web/src/pages/api/workspaces/[workspaceId]/forms/[formId]/pipelines/[pipelineId]/index.ts index 74b493f6ce..a73850ada5 100644 --- a/apps/hq/src/pages/api/teams/[teamId]/forms/[formId]/pipelines/[pipelineId]/index.ts +++ b/apps/web/src/pages/api/workspaces/[workspaceId]/forms/[formId]/pipelines/[pipelineId]/index.ts @@ -10,24 +10,26 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.status(401).json({ message: "Not authenticated" }); } - const teamId = req.query.teamId.toString(); + const workspaceId = req.query.workspaceId.toString(); const formId = req.query.formId.toString(); const pipelineId = req.query.pipelineId.toString(); - // check team permission + // check workspace permission const membership = await prisma.membership.findUnique({ where: { - userId_teamId: { + userId_workspaceId: { userId: user.id, - teamId, + workspaceId, }, }, }); if (membership === null) { - return res.status(403).json({ message: "You don't have access to this team or this team doesn't exist" }); + return res + .status(403) + .json({ message: "You don't have access to this workspace or this workspace doesn't exist" }); } - // GET /api/teams[teamId]/forms/[formId]/pipelines/[pipelineId] + // GET /api/workspaces[workspaceId]/forms/[formId]/pipelines/[pipelineId] // Get a specific pipeline if (req.method === "GET") { const pipeline = await prisma.pipeline.findFirst({ @@ -40,7 +42,7 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.json(pipeline); } - // POST /api/teams[teamId]/forms/[formId]/pipelines/[pipelineId] + // POST /api/workspaces[workspaceId]/forms/[formId]/pipelines/[pipelineId] // Replace a specific pipeline else if (req.method === "POST") { const data = { ...req.body, updatedAt: new Date() }; @@ -51,13 +53,13 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.json(prismaRes); } - // Delete /api/teams[teamId]/forms/[formId]/pipelines/[pipelineId] + // Delete /api/workspaces[workspaceId]/forms/[formId]/pipelines/[pipelineId] // Deletes a single form else if (req.method === "DELETE") { const prismaRes = await prisma.pipeline.delete({ where: { id: pipelineId }, }); - capturePosthogEvent(teamId, "pipeline deleted", { + capturePosthogEvent(workspaceId, "pipeline deleted", { formId, pipelineId, }); diff --git a/apps/hq/src/pages/api/teams/[teamId]/forms/[formId]/pipelines/index.ts b/apps/web/src/pages/api/workspaces/[workspaceId]/forms/[formId]/pipelines/index.ts similarity index 75% rename from apps/hq/src/pages/api/teams/[teamId]/forms/[formId]/pipelines/index.ts rename to apps/web/src/pages/api/workspaces/[workspaceId]/forms/[formId]/pipelines/index.ts index ad00a02fe5..ac926614a7 100644 --- a/apps/hq/src/pages/api/teams/[teamId]/forms/[formId]/pipelines/index.ts +++ b/apps/web/src/pages/api/workspaces/[workspaceId]/forms/[formId]/pipelines/index.ts @@ -10,23 +10,25 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.status(401).json({ message: "Not authenticated" }); } - const teamId = req.query.teamId.toString(); + const workspaceId = req.query.workspaceId.toString(); const formId = req.query.formId.toString(); - // check team permission + // check workspace permission const membership = await prisma.membership.findUnique({ where: { - userId_teamId: { + userId_workspaceId: { userId: user.id, - teamId, + workspaceId, }, }, }); if (membership === null) { - return res.status(403).json({ message: "You don't have access to this team or this team doesn't exist" }); + return res + .status(403) + .json({ message: "You don't have access to this workspace or this workspace doesn't exist" }); } - // GET /api/teams[teamId]/forms/[formId]/pipelines + // GET /api/workspaces[workspaceId]/forms/[formId]/pipelines // Get pipelines if (req.method === "GET") { // get submission @@ -34,7 +36,7 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) where: { form: { id: formId, - teamId, + workspaceId, }, }, }); @@ -42,7 +44,7 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.json(pipelines); } - // POST /api/teams[teamId]/forms/[formId]/pipelines + // POST /api/workspaces[workspaceId]/forms/[formId]/pipelines // Create a new pipeline // Required fields in body: name, type // Optional fields in body: enabled, config @@ -56,7 +58,7 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) form: { connect: { id: formId } }, }, }); - capturePosthogEvent(teamId, "pipeline created", { + capturePosthogEvent(workspaceId, "pipeline created", { formId, pipelineId: result.id, }); diff --git a/apps/hq/src/pages/api/teams/[teamId]/forms/[formId]/submissions/[submissionId]/index.ts b/apps/web/src/pages/api/workspaces/[workspaceId]/forms/[formId]/submissions/[submissionId]/index.ts similarity index 75% rename from apps/hq/src/pages/api/teams/[teamId]/forms/[formId]/submissions/[submissionId]/index.ts rename to apps/web/src/pages/api/workspaces/[workspaceId]/forms/[formId]/submissions/[submissionId]/index.ts index 46545bf9d4..535df85622 100644 --- a/apps/hq/src/pages/api/teams/[teamId]/forms/[formId]/submissions/[submissionId]/index.ts +++ b/apps/web/src/pages/api/workspaces/[workspaceId]/forms/[formId]/submissions/[submissionId]/index.ts @@ -10,24 +10,26 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.status(401).json({ message: "Not authenticated" }); } - const teamId = req.query.teamId.toString(); + const workspaceId = req.query.workspaceId.toString(); const formId = req.query.formId.toString(); const submissionId = req.query.submissionId.toString(); - // check team permission + // check workspace permission const membership = await prisma.membership.findUnique({ where: { - userId_teamId: { + userId_workspaceId: { userId: user.id, - teamId, + workspaceId, }, }, }); if (membership === null) { - return res.status(403).json({ message: "You don't have access to this team or this team doesn't exist" }); + return res + .status(403) + .json({ message: "You don't have access to this workspace or this workspace doesn't exist" }); } - // GET /api/teams[teamId]/forms/[formId]/submissions/[submissionId] + // GET /api/workspaces[workspaceId]/forms/[formId]/submissions/[submissionId] // Get a specific submission if (req.method === "GET") { const submission = await prisma.submission.findFirst({ @@ -40,7 +42,7 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.json(submission); } - // POST /api/teams[teamId]/forms/[formId]/submissions/[submissionId] + // POST /api/workspaces[workspaceId]/forms/[formId]/submissions/[submissionId] // Replace a specific submission else if (req.method === "POST") { const data = { ...req.body, updatedAt: new Date() }; @@ -51,7 +53,7 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.json(prismaRes); } - // Delete /api/teams[teamId]/forms/[formId]/submissions/[submissionId] + // Delete /api/workspaces[workspaceId]/forms/[formId]/submissions/[submissionId] // Deletes a single form else if (req.method === "DELETE") { const prismaRes = await prisma.submission.delete({ diff --git a/apps/hq/src/pages/api/teams/[teamId]/forms/[formId]/submissions/index.ts b/apps/web/src/pages/api/workspaces/[workspaceId]/forms/[formId]/submissions/index.ts similarity index 76% rename from apps/hq/src/pages/api/teams/[teamId]/forms/[formId]/submissions/index.ts rename to apps/web/src/pages/api/workspaces/[workspaceId]/forms/[formId]/submissions/index.ts index d6d7ddcb3c..362b8e5918 100644 --- a/apps/hq/src/pages/api/teams/[teamId]/forms/[formId]/submissions/index.ts +++ b/apps/web/src/pages/api/workspaces/[workspaceId]/forms/[formId]/submissions/index.ts @@ -9,23 +9,25 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.status(401).json({ message: "Not authenticated" }); } - const teamId = req.query.teamId.toString(); + const workspaceId = req.query.workspaceId.toString(); const formId = req.query.formId.toString(); - // check team permission + // check workspace permission const membership = await prisma.membership.findUnique({ where: { - userId_teamId: { + userId_workspaceId: { userId: user.id, - teamId, + workspaceId, }, }, }); if (membership === null) { - return res.status(403).json({ message: "You don't have access to this team or this team doesn't exist" }); + return res + .status(403) + .json({ message: "You don't have access to this workspace or this workspace doesn't exist" }); } - // GET /api/teams[teamId]/forms/[formId]/submissions + // GET /api/workspaces[workspaceId]/forms/[formId]/submissions // Get submissions if (req.method === "GET") { // get submission diff --git a/apps/hq/src/pages/api/teams/[teamId]/forms/index.ts b/apps/web/src/pages/api/workspaces/[workspaceId]/forms/index.ts similarity index 70% rename from apps/hq/src/pages/api/teams/[teamId]/forms/index.ts rename to apps/web/src/pages/api/workspaces/[workspaceId]/forms/index.ts index 2e89f36afd..9f59c8c008 100644 --- a/apps/hq/src/pages/api/teams/[teamId]/forms/index.ts +++ b/apps/web/src/pages/api/workspaces/[workspaceId]/forms/index.ts @@ -10,28 +10,30 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.status(401).json({ message: "Not authenticated" }); } - const teamId = req.query.teamId.toString(); + const workspaceId = req.query.workspaceId.toString(); - // check team permission + // check workspace permission const membership = await prisma.membership.findUnique({ where: { - userId_teamId: { + userId_workspaceId: { userId: user.id, - teamId, + workspaceId, }, }, }); if (membership === null) { - return res.status(403).json({ message: "You don't have access to this team or this team doesn't exist" }); + return res + .status(403) + .json({ message: "You don't have access to this workspace or this workspace doesn't exist" }); } - // GET /api/teams[teamId]/forms - // Get a specific team + // GET /api/workspaces[workspaceId]/forms + // Get a specific workspace if (req.method === "GET") { const forms = await prisma.form.findMany({ where: { - team: { - id: teamId, + workspace: { + id: workspaceId, }, }, include: { @@ -44,7 +46,7 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.json(forms); } - // POST /api/teams[teamId]/forms + // POST /api/workspaces[workspaceId]/forms // Create a new form // Required fields in body: - // Optional fields in body: label, schema @@ -55,10 +57,10 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) const result = await prisma.form.create({ data: { ...form, - team: { connect: { id: teamId } }, + workspace: { connect: { id: workspaceId } }, }, }); - capturePosthogEvent(teamId, "form created", { + capturePosthogEvent(workspaceId, "form created", { formId: result.id, }); res.json(result); diff --git a/apps/hq/src/pages/api/teams/[teamId]/index.ts b/apps/web/src/pages/api/workspaces/[workspaceId]/index.ts similarity index 68% rename from apps/hq/src/pages/api/teams/[teamId]/index.ts rename to apps/web/src/pages/api/workspaces/[workspaceId]/index.ts index 7bb1df8c72..c34465e824 100644 --- a/apps/hq/src/pages/api/teams/[teamId]/index.ts +++ b/apps/web/src/pages/api/workspaces/[workspaceId]/index.ts @@ -9,31 +9,31 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.status(401).json({ message: "Not authenticated" }); } - const teamId = req.query.teamId.toString(); + const workspaceId = req.query.workspaceId.toString(); - // GET /api/teams[teamId] - // Get a specific team + // GET /api/workspaces[workspaceId] + // Get a specific workspace if (req.method === "GET") { // check if membership exists const membership = await prisma.membership.findUnique({ where: { - userId_teamId: { + userId_workspaceId: { userId: user.id, - teamId, + workspaceId, }, }, }); if (membership === null) { return res .status(403) - .json({ message: "You don't have access to this team or this team doesn't exist" }); + .json({ message: "You don't have access to this workspace or this workspace doesn't exist" }); } - const team = await prisma.team.findUnique({ + const workspace = await prisma.workspace.findUnique({ where: { - id: teamId, + id: workspaceId, }, }); - return res.json(team); + return res.json(workspace); } // Unknown HTTP Method diff --git a/apps/hq/src/pages/auth/forgot-password/email-sent/index.tsx b/apps/web/src/pages/auth/forgot-password/email-sent/index.tsx similarity index 100% rename from apps/hq/src/pages/auth/forgot-password/email-sent/index.tsx rename to apps/web/src/pages/auth/forgot-password/email-sent/index.tsx diff --git a/apps/hq/src/pages/auth/forgot-password/index.tsx b/apps/web/src/pages/auth/forgot-password/index.tsx similarity index 100% rename from apps/hq/src/pages/auth/forgot-password/index.tsx rename to apps/web/src/pages/auth/forgot-password/index.tsx diff --git a/apps/hq/src/pages/auth/forgot-password/reset/index.tsx b/apps/web/src/pages/auth/forgot-password/reset/index.tsx similarity index 100% rename from apps/hq/src/pages/auth/forgot-password/reset/index.tsx rename to apps/web/src/pages/auth/forgot-password/reset/index.tsx diff --git a/apps/hq/src/pages/auth/forgot-password/reset/success/index.tsx b/apps/web/src/pages/auth/forgot-password/reset/success/index.tsx similarity index 100% rename from apps/hq/src/pages/auth/forgot-password/reset/success/index.tsx rename to apps/web/src/pages/auth/forgot-password/reset/success/index.tsx diff --git a/apps/hq/src/pages/auth/signin/index.tsx b/apps/web/src/pages/auth/signin/index.tsx similarity index 100% rename from apps/hq/src/pages/auth/signin/index.tsx rename to apps/web/src/pages/auth/signin/index.tsx diff --git a/apps/hq/src/pages/auth/signup-without-verification-success/index.tsx b/apps/web/src/pages/auth/signup-without-verification-success/index.tsx similarity index 100% rename from apps/hq/src/pages/auth/signup-without-verification-success/index.tsx rename to apps/web/src/pages/auth/signup-without-verification-success/index.tsx diff --git a/apps/hq/src/pages/auth/signup/index.tsx b/apps/web/src/pages/auth/signup/index.tsx similarity index 100% rename from apps/hq/src/pages/auth/signup/index.tsx rename to apps/web/src/pages/auth/signup/index.tsx diff --git a/apps/hq/src/pages/auth/verification-requested/index.tsx b/apps/web/src/pages/auth/verification-requested/index.tsx similarity index 100% rename from apps/hq/src/pages/auth/verification-requested/index.tsx rename to apps/web/src/pages/auth/verification-requested/index.tsx diff --git a/apps/hq/src/pages/auth/verify/index.tsx b/apps/web/src/pages/auth/verify/index.tsx similarity index 100% rename from apps/hq/src/pages/auth/verify/index.tsx rename to apps/web/src/pages/auth/verify/index.tsx diff --git a/apps/hq/src/pages/app/index.tsx b/apps/web/src/pages/index.tsx similarity index 84% rename from apps/hq/src/pages/app/index.tsx rename to apps/web/src/pages/index.tsx index 132ed7b942..a4789d52fd 100644 --- a/apps/hq/src/pages/app/index.tsx +++ b/apps/web/src/pages/index.tsx @@ -5,7 +5,7 @@ import { useMemberships } from "@/lib/memberships"; import { useSession } from "next-auth/react"; import { useRouter } from "next/navigation"; import { useEffect } from "react"; -import LoadingSpinner from "../../components/LoadingSpinner"; +import LoadingSpinner from "@/components/LoadingSpinner"; export default function ProjectsPage() { const { data: session } = useSession(); @@ -14,8 +14,8 @@ export default function ProjectsPage() { useEffect(() => { if (session && memberships && memberships.length > 0) { - const teamId = memberships[0].teamId; - router.push(`/app/teams/${teamId}/forms`); + const workspaceId = memberships[0].workspaceId; + router.push(`/workspaces/${workspaceId}/forms`); } if (!session) { router.push(`/auth/signin?callbackUrl=${encodeURIComponent(window.location.href)}`); diff --git a/apps/hq/src/pages/app/me/settings/index.tsx b/apps/web/src/pages/me/settings/index.tsx similarity index 81% rename from apps/hq/src/pages/app/me/settings/index.tsx rename to apps/web/src/pages/me/settings/index.tsx index dfa8796f1d..4d12104d2e 100644 --- a/apps/hq/src/pages/app/me/settings/index.tsx +++ b/apps/web/src/pages/me/settings/index.tsx @@ -3,7 +3,7 @@ import LayoutApp from "@/components/layout/LayoutApp"; import ProfileSettingsPage from "@/components/me/ProfileSettingsPage"; -export default function TeamFormsPage({}) { +export default function WorkspaceFormsPage({}) { return (