Merge branch 'main' of github.com:formbricks/formbricks into feature/FOR-772

This commit is contained in:
Matthias Nannt
2023-06-14 17:23:53 +02:00
12 changed files with 53 additions and 12 deletions
+2 -1
View File
@@ -31,6 +31,7 @@ COPY --from=installer /app/apps/web/package.json .
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/standalone ./
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static
COPY --from=installer --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public
COPY --from=installer --chown=nextjs:nodejs /app/packages/database/prisma ./packages/database/prisma
COPY --from=installer --chown=nextjs:nodejs /app/packages/database/schema.prisma ./packages/database/schema.prisma
COPY --from=installer --chown=nextjs:nodejs /app/packages/database/migrations ./packages/database/migrations
CMD pnpm dlx prisma migrate deploy && node apps/web/server.js
@@ -2,7 +2,7 @@
import LoadingSpinner from "@/components/shared/LoadingSpinner";
import { useAttributeClasses } from "@/lib/attributeClasses/attributeClasses";
import { Button, ErrorComponent } from "@formbricks/ui";
import { Badge, Button, ErrorComponent, Switch } from "@formbricks/ui";
import { QuestionMarkCircleIcon, TagIcon } from "@heroicons/react/24/solid";
import { useState } from "react";
import AttributeDetailModal from "./AttributeDetailModal";
@@ -16,6 +16,7 @@ export default function AttributeClassesList({ environmentId }: { environmentId:
const [isAttributeDetailModalOpen, setAttributeDetailModalOpen] = useState(false);
const [isUploadCSVModalOpen, setUploadCSVModalOpen] = useState(false);
const [activeAttributeClass, setActiveAttributeClass] = useState("" as any);
const [showArchived, setShowArchived] = useState(false);
if (isLoadingAttributeClasses) {
return <LoadingSpinner />;
@@ -30,9 +31,24 @@ export default function AttributeClassesList({ environmentId }: { environmentId:
setAttributeDetailModalOpen(true);
};
const toggleShowArchived = () => {
setShowArchived(!showArchived);
};
const displayedAttributeClasses = showArchived ? attributeClasses : attributeClasses.filter(ac => !ac.archived);
const hasArchived = attributeClasses.some(ac => ac.archived);
return (
<>
<div className="mb-6 text-right">
<div className="mb-6 text-right flex items-center justify-end">
{hasArchived && <div className="flex items-center text-sm font-medium">
Show archived
<Switch
className="mx-3"
checked={showArchived}
onCheckedChange={toggleShowArchived}
/>
</div>}
<Button
variant="secondary"
href="http://formbricks.com/docs/attributes/custom-attributes"
@@ -48,7 +64,7 @@ export default function AttributeClassesList({ environmentId }: { environmentId:
<div className="text-center">Last Updated</div>
</div>
<div className="grid-cols-7">
{attributeClasses.map((attributeClass) => (
{displayedAttributeClasses.map((attributeClass) => (
<button
onClick={(e) => {
handleOpenAttributeDetailModalClick(e, attributeClass);
@@ -62,7 +78,11 @@ export default function AttributeClassesList({ environmentId }: { environmentId:
<TagIcon className="h-8 w-8 flex-shrink-0 text-slate-500" />
</div>
<div className="ml-4 text-left">
<div className="font-medium text-slate-900">{attributeClass.name}</div>
<div className="font-medium text-slate-900">{attributeClass.name}
<span className="ml-2">
{attributeClass.archived && <Badge text="Archived" type="gray" size="tiny" />}
</span>
</div>
<div className="text-xs text-slate-400">{attributeClass.description}</div>
</div>
</div>
@@ -3,6 +3,7 @@ import { useAttributeClassMutation } from "@/lib/attributeClasses/mutateAttribut
import { Button, Input, Label } from "@formbricks/ui";
import type { AttributeClass } from "@prisma/client";
import { useForm } from "react-hook-form";
import { ArchiveBoxArrowDownIcon, ArchiveBoxXMarkIcon } from "@heroicons/react/24/solid";
interface AttributeSettingsTabProps {
environmentId: string;
@@ -31,6 +32,12 @@ export default function AttributeSettingsTab({
setOpen(false);
};
const handleArchiveToggle = async () => {
const data = { archived: !attributeClass.archived };
await triggerAttributeClassMutate(data);
mutateAttributeClasses();
};
return (
<div>
<form className="space-y-4" onSubmit={handleSubmit(onSubmit)}>
@@ -67,13 +74,22 @@ export default function AttributeSettingsTab({
) : null}
</div>
<div className="flex justify-between border-t border-slate-200 pt-6">
<div>
<div className="flex items-center">
<Button
variant="secondary"
href="https://formbricks.com/docs/getting-started/identify-users"
target="_blank">
Read Docs
</Button>
{attributeClass.type !== "automatic" && (
<Button className="ml-3" variant="secondary" onClick={handleArchiveToggle}>
{attributeClass.archived ? (
<> <ArchiveBoxXMarkIcon className="h-4 mr-2 text-slate-600" /><span>Unarchive</span></>
) : (
<> <ArchiveBoxArrowDownIcon className="h-4 mr-2 text-slate-600" /><span>Archive</span></>
)}
</Button>
)}
</div>
{attributeClass.type !== "automatic" && (
<div className="flex space-x-2">
@@ -36,7 +36,7 @@ export default function EventClassesList({ environmentId }) {
<>
<div className="mb-6 text-right">
<Button
variant="primary"
variant="darkCTA"
onClick={() => {
setAddEventModalOpen(true);
}}>
@@ -38,7 +38,7 @@ export default function PersonDetails({ environmentId, personId }: PersonDetails
const otherAttributes = useMemo(
() =>
person?.attributes?.filter(
(attribute) => attribute.attributeClass.name !== "email" && attribute.attributeClass.name !== "userId"
(attribute) => attribute.attributeClass.name !== "email" && attribute.attributeClass.name !== "userId" && !attribute.attributeClass.archived
) as any[],
[person]
);
@@ -158,7 +158,7 @@ export default function WhoToSendCard({ environmentId, localSurvey, setLocalSurv
<SelectValue />
</SelectTrigger>
<SelectContent>
{attributeClasses.map((attributeClass) => (
{attributeClasses.filter(attributeClass => !attributeClass.archived).map((attributeClass) => (
<SelectItem value={attributeClass.id}>{attributeClass.name}</SelectItem>
))}
</SelectContent>
@@ -52,7 +52,7 @@ export default function ResponseNote({
!isOpen && responseNotes.length && "group/hint cursor-pointer bg-white hover:-right-3",
!isOpen && !responseNotes.length && "cursor-pointer bg-slate-50",
isOpen
? "-right-5 top-0 h-full w-1/4 bg-white"
? "-right-5 top-0 h-5/6 max-h-[600px] w-1/4 bg-white"
: responseNotes.length
? "right-0 top-[8.33%] h-5/6 max-h-[600px] w-1/12"
: "right-[120px] top-[8.333%] h-5/6 max-h-[600px] w-1/12 group-hover:right-[0]"
@@ -87,7 +87,7 @@ export default function SingleResponse({ data, environmentId, surveyId }: OpenTe
className="group flex items-center"
href={`/environments/${environmentId}/people/${data.personId}`}>
<PersonAvatar personId={data.personId} />
<h3 className="ph-no-capture ml-4 pb-1 font-semibold text-slate-600 group-hover:underline">
<h3 className="ph-no-capture ml-4 pb-1 font-semibold text-slate-600 hover:underline">
{displayIdentifier}
</h3>
</Link>
@@ -73,6 +73,7 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse)
select: {
name: true,
description: true,
archived: true,
},
},
},
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "AttributeClass" ADD COLUMN "archived" BOOLEAN NOT NULL DEFAULT false;
+1
View File
@@ -64,6 +64,7 @@ model AttributeClass {
updatedAt DateTime @updatedAt @map(name: "updated_at")
name String
description String?
archived Boolean @default(false)
type AttributeType
environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade)
environmentId String
+1 -1
View File
@@ -1,6 +1,6 @@
import { z } from "zod";
export const ZResponseData = z.record(z.union([z.string(), z.number()]));
export const ZResponseData = z.record(z.union([z.string(), z.number(), z.array(z.string())]));
export type TResponseData = z.infer<typeof ZResponseData>;