From a073dccab6bd2028950a6bcc1966590a4e0af1a0 Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Fri, 13 Sep 2024 18:20:29 +0100 Subject: [PATCH 01/43] add schemas for moderation and reports --- .../frontpage/app/(app)/moderation/page.tsx | 0 packages/frontpage/lib/schema.ts | 31 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 packages/frontpage/app/(app)/moderation/page.tsx diff --git a/packages/frontpage/app/(app)/moderation/page.tsx b/packages/frontpage/app/(app)/moderation/page.tsx new file mode 100644 index 00000000..e69de29b diff --git a/packages/frontpage/lib/schema.ts b/packages/frontpage/lib/schema.ts index fbede435..17b0060a 100644 --- a/packages/frontpage/lib/schema.ts +++ b/packages/frontpage/lib/schema.ts @@ -127,3 +127,34 @@ export const BetaUser = sqliteTable("beta_users", { export const ConsumedOffset = sqliteTable("consumed_offsets", { offset: integer("offset").primaryKey(), }); + +export const ModerationEvent = sqliteTable("moderation_events", { + subjectUri: text("subject_uri").notNull(), + subjectDid: text("subject_did").notNull(), + subjectCollection: text("subject_collection"), + subjectRkey: text("subject_rkey"), + subjectCid: text("subject_cid").notNull(), + createdBy: text("created_by").notNull(), + createdAt: dateIsoText("created_at").notNull(), + labelsAdded: text("labels_added"), + labelsRemoved: text("labels_removed"), +}); + +export const LabelledProfile = sqliteTable("labelled_profiles", { + did: text("did").notNull().unique(), + labels: text("labels"), +}); + +export const Report = sqliteTable("reports", { + actionedAt: dateIsoText("actioned_at"), + actionedBy: text("actioned_by"), + subjectUri: text("subject_uri").notNull(), + subjectDid: text("subject_did").notNull(), + subjectCollection: text("subject_collection"), + subjectRkey: text("subject_rkey"), + subjectCid: text("subject_cid").notNull(), + createdBy: text("created_by").notNull(), + createdAt: dateIsoText("created_at").notNull(), + creatorComment: text("creator_comment"), + labelsAdded: text("labels_added"), +}); From 4b9750f92d2dde651cd9c60aa210005ed3dcd85d Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Fri, 20 Sep 2024 01:32:06 +0100 Subject: [PATCH 02/43] add moderation page --- .../frontpage/app/(app)/moderation/page.tsx | 229 ++++++++++++++++++ packages/frontpage/lib/components/ui/card.tsx | 76 ++++++ .../lib/components/ui/scroll-area.tsx | 48 ++++ packages/frontpage/package.json | 2 + pnpm-lock.yaml | 180 ++++++-------- 5 files changed, 429 insertions(+), 106 deletions(-) create mode 100644 packages/frontpage/lib/components/ui/card.tsx create mode 100644 packages/frontpage/lib/components/ui/scroll-area.tsx diff --git a/packages/frontpage/app/(app)/moderation/page.tsx b/packages/frontpage/app/(app)/moderation/page.tsx index e69de29b..3ffa341f 100644 --- a/packages/frontpage/app/(app)/moderation/page.tsx +++ b/packages/frontpage/app/(app)/moderation/page.tsx @@ -0,0 +1,229 @@ +import { CheckCircle, ExternalLink, Flag, Shield, XCircle } from "lucide-react"; +import { Button } from "@/lib/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/lib/components/ui/card"; +import { ScrollArea } from "@/lib/components/ui/scroll-area"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/lib/components/ui/tooltip"; + +type Report = { + id: string; + type: "post" | "comment"; + content: string; + reason: string; + status: "pending" | "approved" | "rejected"; + did: string; + cid: string; + rkey: string; + uri: string; + community: string; +}; + +type Community = { + name: string; + icon: string; +}; + +export default function Component() { + const reports = [ + { + id: "1", + type: "post", + content: "This is a reported post", + reason: "Inappropriate content", + status: "pending", + did: "did:plc:abcdefghijklmnop", + cid: "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi", + rkey: "abcdef123456", + uri: "at://did:plc:abcdefghijklmnop/app.bsky.feed.post/abcdef123456", + community: "General", + }, + { + id: "2", + type: "comment", + content: "This is a reported comment", + reason: "Spam", + status: "pending", + did: "did:plc:qrstuvwxyz123456", + cid: "bafybeihbgxvydgnxlfapxnzb7zyqbbs6tkvhflemvwogzb5zzp7ufuz7ky", + rkey: "ghijkl789012", + uri: "at://did:plc:qrstuvwxyz123456/app.bsky.feed.post/ghijkl789012", + community: "Tech", + }, + { + id: "3", + type: "post", + content: "Another reported post", + reason: "Misinformation", + status: "pending", + did: "did:plc:123456abcdefghij", + cid: "bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xccnlnmzhe5h6y7afcvqpqom", + rkey: "mnopqr456789", + uri: "at://did:plc:123456abcdefghij/app.bsky.feed.post/mnopqr456789", + community: "Science", + }, + ]; + + // const handleAction = (id: string, action: "approve" | "reject") => { + // setReports( + // reports.map((report) => + // report.id === id ? { ...report, status: action } : report, + // ), + // ); + // }; + + const stats = { + total: reports.length, + pending: reports.filter((r) => r.status === "pending").length, + approved: reports.filter((r) => r.status === "approved").length, + rejected: reports.filter((r) => r.status === "rejected").length, + }; + + return ( +
+ + + + + Moderation Dashboard + + + Review and take action on reported content + + + +
+ + + + Total Reports + + + +
+ {stats.total} +
+
+
+ + + + Pending + + + +
+ {stats.pending} +
+
+
+ + + + Approved + + + +
+ {stats.approved} +
+
+
+ + + + Rejected + + + +
+ {stats.rejected} +
+
+
+
+
+ {reports.map((report) => ( + + + + + Reported {report.type} in {report.community} + + + {report.status.charAt(0).toUpperCase() + + report.status.slice(1)} + + + + +

{report.content}

+
+
+ DID: {report.did} +
+
+ CID: {report.cid} +
+
+ Record Key: {report.rkey} +
+ +
+
+ + Reason: {report.reason} +
+
+ + +
+
+
+ ))} +
+
+
+
+ ); +} diff --git a/packages/frontpage/lib/components/ui/card.tsx b/packages/frontpage/lib/components/ui/card.tsx new file mode 100644 index 00000000..77e9fb78 --- /dev/null +++ b/packages/frontpage/lib/components/ui/card.tsx @@ -0,0 +1,76 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Card.displayName = "Card" + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardHeader.displayName = "CardHeader" + +const CardTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardTitle.displayName = "CardTitle" + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardDescription.displayName = "CardDescription" + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardContent.displayName = "CardContent" + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardFooter.displayName = "CardFooter" + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/packages/frontpage/lib/components/ui/scroll-area.tsx b/packages/frontpage/lib/components/ui/scroll-area.tsx new file mode 100644 index 00000000..0b4a48d8 --- /dev/null +++ b/packages/frontpage/lib/components/ui/scroll-area.tsx @@ -0,0 +1,48 @@ +"use client" + +import * as React from "react" +import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area" + +import { cn } from "@/lib/utils" + +const ScrollArea = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + {children} + + + + +)) +ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName + +const ScrollBar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, orientation = "vertical", ...props }, ref) => ( + + + +)) +ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName + +export { ScrollArea, ScrollBar } diff --git a/packages/frontpage/package.json b/packages/frontpage/package.json index f521737c..bf6725dd 100644 --- a/packages/frontpage/package.json +++ b/packages/frontpage/package.json @@ -22,6 +22,7 @@ "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-popover": "^1.1.1", + "@radix-ui/react-scroll-area": "^1.1.0", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-tabs": "^1.1.0", "@radix-ui/react-toast": "^1.2.1", @@ -33,6 +34,7 @@ "date-fns": "^3.6.0", "drizzle-orm": "^0.31.2", "jose": "^5.4.0", + "lucide-react": "^0.441.0", "next": "15.0.0-rc.0", "next-auth": "5.0.0-beta.19", "next-themes": "^0.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7d03d987..49688589 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -138,6 +138,9 @@ importers: '@radix-ui/react-popover': specifier: ^1.1.1 version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-scroll-area': + specifier: ^1.1.0 + version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) '@radix-ui/react-slot': specifier: ^1.1.0 version: 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) @@ -171,6 +174,9 @@ importers: jose: specifier: ^5.4.0 version: 5.4.0 + lucide-react: + specifier: ^0.441.0 + version: 0.441.0(react@19.0.0-rc-f994737d14-20240522) next: specifier: 15.0.0-rc.0 version: 15.0.0-rc.0(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) @@ -1597,6 +1603,9 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@radix-ui/number@1.1.0': + resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==} + '@radix-ui/primitive@1.1.0': resolution: {integrity: sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==} @@ -1871,6 +1880,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-scroll-area@1.1.0': + resolution: {integrity: sha512-9ArIZ9HWhsrfqS765h+GZuLoxaRHD/j0ZWOWilsCvYTpYJp8XwCqNG7Dt9Nu/TItKOdgLGkOPCodQvDc+UMwYg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-slot@1.1.0': resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==} peerDependencies: @@ -4261,6 +4283,11 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lucide-react@0.441.0: + resolution: {integrity: sha512-0vfExYtvSDhkC2lqg0zYVW1Uu9GsI4knuV9GP9by5z0Xhc4Zi5RejTxfz9LsjRmCyWVzHCJvxGKZWcRyvQCWVg==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc + lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -6087,8 +6114,8 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.588.0 - '@aws-sdk/client-sts': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0) + '@aws-sdk/client-sso-oidc': 3.588.0(@aws-sdk/client-sts@3.588.0) + '@aws-sdk/client-sts': 3.588.0 '@aws-sdk/core': 3.588.0 '@aws-sdk/credential-provider-node': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -6136,8 +6163,8 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.588.0 - '@aws-sdk/client-sts': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0) + '@aws-sdk/client-sso-oidc': 3.588.0(@aws-sdk/client-sts@3.588.0) + '@aws-sdk/client-sts': 3.588.0 '@aws-sdk/core': 3.588.0 '@aws-sdk/credential-provider-node': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -6183,8 +6210,8 @@ snapshots: '@aws-crypto/sha1-browser': 3.0.0 '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.588.0 - '@aws-sdk/client-sts': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0) + '@aws-sdk/client-sso-oidc': 3.588.0(@aws-sdk/client-sts@3.588.0) + '@aws-sdk/client-sts': 3.588.0 '@aws-sdk/core': 3.588.0 '@aws-sdk/credential-provider-node': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0) '@aws-sdk/middleware-bucket-endpoint': 3.587.0 @@ -6241,11 +6268,11 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.588.0': + '@aws-sdk/client-sso-oidc@3.588.0(@aws-sdk/client-sts@3.588.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0) + '@aws-sdk/client-sts': 3.588.0 '@aws-sdk/core': 3.588.0 '@aws-sdk/credential-provider-node': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -6284,6 +6311,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 transitivePeerDependencies: + - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso@3.588.0': @@ -6329,11 +6357,11 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sts@3.588.0(@aws-sdk/client-sso-oidc@3.588.0)': + '@aws-sdk/client-sts@3.588.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.588.0 + '@aws-sdk/client-sso-oidc': 3.588.0(@aws-sdk/client-sts@3.588.0) '@aws-sdk/core': 3.588.0 '@aws-sdk/credential-provider-node': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -6372,7 +6400,6 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/core@3.588.0': @@ -6406,7 +6433,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0)': dependencies: - '@aws-sdk/client-sts': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0) + '@aws-sdk/client-sts': 3.588.0 '@aws-sdk/credential-provider-env': 3.587.0 '@aws-sdk/credential-provider-http': 3.587.0 '@aws-sdk/credential-provider-process': 3.587.0 @@ -6464,7 +6491,7 @@ snapshots: '@aws-sdk/credential-provider-web-identity@3.587.0(@aws-sdk/client-sts@3.588.0)': dependencies: - '@aws-sdk/client-sts': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0) + '@aws-sdk/client-sts': 3.588.0 '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.1.0 '@smithy/types': 3.0.0 @@ -6591,7 +6618,7 @@ snapshots: '@aws-sdk/token-providers@3.587.0(@aws-sdk/client-sso-oidc@3.588.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.588.0 + '@aws-sdk/client-sso-oidc': 3.588.0(@aws-sdk/client-sts@3.588.0) '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.1.0 '@smithy/shared-ini-file-loader': 3.1.0 @@ -7450,6 +7477,8 @@ snapshots: '@pkgr/core@0.1.1': {} + '@radix-ui/number@1.1.0': {} + '@radix-ui/primitive@1.1.0': {} '@radix-ui/react-alert-dialog@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': @@ -7734,6 +7763,23 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + '@radix-ui/react-scroll-area@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + dependencies: + '@radix-ui/number': 1.1.0 + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + react: 19.0.0-rc-f994737d14-20240522 + react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 + '@radix-ui/react-slot@1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) @@ -9501,8 +9547,8 @@ snapshots: '@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.4.5) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-react: 7.34.2(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) @@ -9537,8 +9583,8 @@ snapshots: '@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.5.2) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-react: 7.34.2(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) @@ -9586,23 +9632,6 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0): - dependencies: - debug: 4.3.5 - enhanced-resolve: 5.16.1 - eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - fast-glob: 3.3.2 - get-tsconfig: 4.7.5 - is-core-module: 2.13.1 - is-glob: 4.0.3 - transitivePeerDependencies: - - '@typescript-eslint/parser' - - eslint-import-resolver-node - - eslint-import-resolver-webpack - - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0): dependencies: debug: 4.3.5 @@ -9620,13 +9649,13 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0): dependencies: debug: 4.3.5 enhanced-resolve: 5.16.1 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.5 is-core-module: 2.13.1 @@ -9648,17 +9677,6 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.4.5) - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0) - transitivePeerDependencies: - - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 @@ -9670,14 +9688,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.5.2) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) transitivePeerDependencies: - supports-color @@ -9714,33 +9732,6 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): - dependencies: - array-includes: 3.1.8 - array.prototype.findlastindex: 1.2.5 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - hasown: 2.0.2 - is-core-module: 2.13.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.0 - semver: 6.3.1 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.4.5) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: array-includes: 3.1.8 @@ -9751,7 +9742,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.5.2))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -9768,33 +9759,6 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): - dependencies: - array-includes: 3.1.8 - array.prototype.findlastindex: 1.2.5 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - hasown: 2.0.2 - is-core-module: 2.13.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.0 - semver: 6.3.1 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.5.2) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@7.14.1(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2): dependencies: '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.5.2) @@ -10769,6 +10733,10 @@ snapshots: dependencies: yallist: 3.1.1 + lucide-react@0.441.0(react@19.0.0-rc-f994737d14-20240522): + dependencies: + react: 19.0.0-rc-f994737d14-20240522 + lz-string@1.5.0: {} magic-string@0.30.10: From dbca7abfd3057e62d37c91e08e8c767de348f623 Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Fri, 20 Sep 2024 01:48:09 +0100 Subject: [PATCH 03/43] no unused imports --- .../frontpage/app/(app)/moderation/page.tsx | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/packages/frontpage/app/(app)/moderation/page.tsx b/packages/frontpage/app/(app)/moderation/page.tsx index 3ffa341f..3336073a 100644 --- a/packages/frontpage/app/(app)/moderation/page.tsx +++ b/packages/frontpage/app/(app)/moderation/page.tsx @@ -7,13 +7,6 @@ import { CardHeader, CardTitle, } from "@/lib/components/ui/card"; -import { ScrollArea } from "@/lib/components/ui/scroll-area"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/lib/components/ui/tooltip"; type Report = { id: string; @@ -28,13 +21,8 @@ type Report = { community: string; }; -type Community = { - name: string; - icon: string; -}; - export default function Component() { - const reports = [ + const reports: Report[] = [ { id: "1", type: "post", @@ -73,14 +61,6 @@ export default function Component() { }, ]; - // const handleAction = (id: string, action: "approve" | "reject") => { - // setReports( - // reports.map((report) => - // report.id === id ? { ...report, status: action } : report, - // ), - // ); - // }; - const stats = { total: reports.length, pending: reports.filter((r) => r.status === "pending").length, From e3f38eed0b1e7fdbf2d09a1994a31b81971594fe Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Fri, 20 Sep 2024 02:12:41 +0100 Subject: [PATCH 04/43] update card to use children, we're allys here --- packages/frontpage/lib/components/ui/card.tsx | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/packages/frontpage/lib/components/ui/card.tsx b/packages/frontpage/lib/components/ui/card.tsx index 77e9fb78..f7693328 100644 --- a/packages/frontpage/lib/components/ui/card.tsx +++ b/packages/frontpage/lib/components/ui/card.tsx @@ -1,6 +1,6 @@ -import * as React from "react" +import * as React from "react"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; const Card = React.forwardRef< HTMLDivElement, @@ -10,12 +10,12 @@ const Card = React.forwardRef< ref={ref} className={cn( "rounded-xl border bg-card text-card-foreground shadow", - className + className, )} {...props} /> -)) -Card.displayName = "Card" +)); +Card.displayName = "Card"; const CardHeader = React.forwardRef< HTMLDivElement, @@ -26,20 +26,22 @@ const CardHeader = React.forwardRef< className={cn("flex flex-col space-y-1.5 p-6", className)} {...props} /> -)) -CardHeader.displayName = "CardHeader" +)); +CardHeader.displayName = "CardHeader"; const CardTitle = React.forwardRef< HTMLParagraphElement, React.HTMLAttributes ->(({ className, ...props }, ref) => ( +>(({ className, children, ...props }, ref) => (

-)) -CardTitle.displayName = "CardTitle" + > + {children} +

+)); +CardTitle.displayName = "CardTitle"; const CardDescription = React.forwardRef< HTMLParagraphElement, @@ -50,16 +52,16 @@ const CardDescription = React.forwardRef< className={cn("text-sm text-muted-foreground", className)} {...props} /> -)) -CardDescription.displayName = "CardDescription" +)); +CardDescription.displayName = "CardDescription"; const CardContent = React.forwardRef< HTMLDivElement, React.HTMLAttributes >(({ className, ...props }, ref) => (
-)) -CardContent.displayName = "CardContent" +)); +CardContent.displayName = "CardContent"; const CardFooter = React.forwardRef< HTMLDivElement, @@ -70,7 +72,14 @@ const CardFooter = React.forwardRef< className={cn("flex items-center p-6 pt-0", className)} {...props} /> -)) -CardFooter.displayName = "CardFooter" +)); +CardFooter.displayName = "CardFooter"; -export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardDescription, + CardContent, +}; From b75666dad5432860223b4019e2c1df26d5a5dbb0 Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Sat, 21 Sep 2024 02:18:59 +0100 Subject: [PATCH 05/43] add client component, start adding actions and checks for roles --- .../app/(app)/moderation/_client.tsx | 158 +++++ .../app/(app)/moderation/actions.tsx | 3 + .../frontpage/app/(app)/moderation/page.tsx | 255 ++----- .../drizzle/0001_glamorous_starfox.sql | 32 + .../frontpage/drizzle/meta/0001_snapshot.json | 636 ++++++++++++++++++ packages/frontpage/drizzle/meta/_journal.json | 7 + packages/frontpage/lib/data/user.ts | 14 + packages/frontpage/lib/schema.ts | 9 +- 8 files changed, 918 insertions(+), 196 deletions(-) create mode 100644 packages/frontpage/app/(app)/moderation/_client.tsx create mode 100644 packages/frontpage/app/(app)/moderation/actions.tsx create mode 100644 packages/frontpage/drizzle/0001_glamorous_starfox.sql create mode 100644 packages/frontpage/drizzle/meta/0001_snapshot.json diff --git a/packages/frontpage/app/(app)/moderation/_client.tsx b/packages/frontpage/app/(app)/moderation/_client.tsx new file mode 100644 index 00000000..2cd90c8d --- /dev/null +++ b/packages/frontpage/app/(app)/moderation/_client.tsx @@ -0,0 +1,158 @@ +"use client"; +import { CheckCircle, ExternalLink, Flag, Shield, XCircle } from "lucide-react"; +import { Button } from "@/lib/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/lib/components/ui/card"; +import { Report } from "./page"; + +export default function ModerationPage({ + reports, + stats, +}: { + reports: Report[]; + stats: { total: number; pending: number; approved: number; rejected: number }; +}) { + return ( +
+ + + + + Moderation Dashboard + + + Review and take action on reported content + + + +
+ + + + Total Reports + + + +
+ {stats.total} +
+
+
+ + + + Pending + + + +
+ {stats.pending} +
+
+
+ + + + Approved + + + +
+ {stats.approved} +
+
+
+ + + + Rejected + + + +
+ {stats.rejected} +
+
+
+
+
+ {reports.map((report) => ( + + + + + Reported {report.type} in {report.community} + + + {report.status.charAt(0).toUpperCase() + + report.status.slice(1)} + + + + +

{report.content}

+
+
+ DID: {report.did} +
+
+ CID: {report.cid} +
+
+ Record Key: {report.rkey} +
+ +
+
+ + Reason: {report.reason} +
+
+ + +
+
+
+ ))} +
+
+
+
+ ); +} diff --git a/packages/frontpage/app/(app)/moderation/actions.tsx b/packages/frontpage/app/(app)/moderation/actions.tsx new file mode 100644 index 00000000..d431e6ac --- /dev/null +++ b/packages/frontpage/app/(app)/moderation/actions.tsx @@ -0,0 +1,3 @@ +"use server"; + +//TODO: add actions for creating, updating, deleting moderation reports diff --git a/packages/frontpage/app/(app)/moderation/page.tsx b/packages/frontpage/app/(app)/moderation/page.tsx index 3336073a..15235924 100644 --- a/packages/frontpage/app/(app)/moderation/page.tsx +++ b/packages/frontpage/app/(app)/moderation/page.tsx @@ -1,14 +1,10 @@ -import { CheckCircle, ExternalLink, Flag, Shield, XCircle } from "lucide-react"; -import { Button } from "@/lib/components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/lib/components/ui/card"; +"use server"; -type Report = { +import { hasRole } from "@/lib/data/user"; +import { redirect } from "next/navigation"; +import ModerationPage from "./_client"; + +export type Report = { id: string; type: "post" | "comment"; content: string; @@ -21,189 +17,62 @@ type Report = { community: string; }; -export default function Component() { - const reports: Report[] = [ - { - id: "1", - type: "post", - content: "This is a reported post", - reason: "Inappropriate content", - status: "pending", - did: "did:plc:abcdefghijklmnop", - cid: "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi", - rkey: "abcdef123456", - uri: "at://did:plc:abcdefghijklmnop/app.bsky.feed.post/abcdef123456", - community: "General", - }, - { - id: "2", - type: "comment", - content: "This is a reported comment", - reason: "Spam", - status: "pending", - did: "did:plc:qrstuvwxyz123456", - cid: "bafybeihbgxvydgnxlfapxnzb7zyqbbs6tkvhflemvwogzb5zzp7ufuz7ky", - rkey: "ghijkl789012", - uri: "at://did:plc:qrstuvwxyz123456/app.bsky.feed.post/ghijkl789012", - community: "Tech", - }, - { - id: "3", - type: "post", - content: "Another reported post", - reason: "Misinformation", - status: "pending", - did: "did:plc:123456abcdefghij", - cid: "bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xccnlnmzhe5h6y7afcvqpqom", - rkey: "mnopqr456789", - uri: "at://did:plc:123456abcdefghij/app.bsky.feed.post/mnopqr456789", - community: "Science", - }, - ]; +const reports: Report[] = [ + { + id: "1", + type: "post", + content: "This is a reported post", + reason: "Inappropriate content", + status: "pending", + did: "did:plc:abcdefghijklmnop", + cid: "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi", + rkey: "abcdef123456", + uri: "at://did:plc:abcdefghijklmnop/app.bsky.feed.post/abcdef123456", + community: "General", + }, + { + id: "2", + type: "comment", + content: "This is a reported comment", + reason: "Spam", + status: "pending", + did: "did:plc:qrstuvwxyz123456", + cid: "bafybeihbgxvydgnxlfapxnzb7zyqbbs6tkvhflemvwogzb5zzp7ufuz7ky", + rkey: "ghijkl789012", + uri: "at://did:plc:qrstuvwxyz123456/app.bsky.feed.post/ghijkl789012", + community: "Tech", + }, + { + id: "3", + type: "post", + content: "Another reported post", + reason: "Misinformation", + status: "pending", + did: "did:plc:123456abcdefghij", + cid: "bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xccnlnmzhe5h6y7afcvqpqom", + rkey: "mnopqr456789", + uri: "at://did:plc:123456abcdefghij/app.bsky.feed.post/mnopqr456789", + community: "Science", + }, +]; + +const stats = { + total: reports.length, + pending: reports.filter((r) => r.status === "pending").length, + approved: reports.filter((r) => r.status === "approved").length, + rejected: reports.filter((r) => r.status === "rejected").length, +}; - const stats = { - total: reports.length, - pending: reports.filter((r) => r.status === "pending").length, - approved: reports.filter((r) => r.status === "approved").length, - rejected: reports.filter((r) => r.status === "rejected").length, - }; +export default async function Moderation() { + //TODO: get moderation reports, get moderator's stats etc. + if (await hasRole("moderator")) { + // const [reports, stats] = await Promise.all([ + // await getReports(), + // await getStats(did), + // ]); - return ( -
- - - - - Moderation Dashboard - - - Review and take action on reported content - - - -
- - - - Total Reports - - - -
- {stats.total} -
-
-
- - - - Pending - - - -
- {stats.pending} -
-
-
- - - - Approved - - - -
- {stats.approved} -
-
-
- - - - Rejected - - - -
- {stats.rejected} -
-
-
-
-
- {reports.map((report) => ( - - - - - Reported {report.type} in {report.community} - - - {report.status.charAt(0).toUpperCase() + - report.status.slice(1)} - - - - -

{report.content}

-
-
- DID: {report.did} -
-
- CID: {report.cid} -
-
- Record Key: {report.rkey} -
- -
-
- - Reason: {report.reason} -
-
- - -
-
-
- ))} -
-
-
-
- ); + return ; + } else { + redirect("/"); + } } diff --git a/packages/frontpage/drizzle/0001_glamorous_starfox.sql b/packages/frontpage/drizzle/0001_glamorous_starfox.sql new file mode 100644 index 00000000..e866378a --- /dev/null +++ b/packages/frontpage/drizzle/0001_glamorous_starfox.sql @@ -0,0 +1,32 @@ +CREATE TABLE `labelled_profiles` ( + `did` text NOT NULL, + `labels` text +); + +CREATE TABLE `moderation_events` ( + `subject_uri` text NOT NULL, + `subject_did` text NOT NULL, + `subject_collection` text, + `subject_rkey` text, + `subject_cid` text, + `created_by` text NOT NULL, + `created_at` text NOT NULL, + `labels_added` text, + `report_type` text +); + +CREATE TABLE `reports` ( + `actioned_at` text, + `actioned_by` text, + `subject_uri` text NOT NULL, + `subject_did` text NOT NULL, + `subject_collection` text, + `subject_rkey` text, + `subject_cid` text, + `created_by` text NOT NULL, + `created_at` text NOT NULL, + `creator_comment` text, + `labels_added` text +); + +CREATE UNIQUE INDEX `labelled_profiles_did_unique` ON `labelled_profiles` (`did`); diff --git a/packages/frontpage/drizzle/meta/0001_snapshot.json b/packages/frontpage/drizzle/meta/0001_snapshot.json new file mode 100644 index 00000000..7a377d2f --- /dev/null +++ b/packages/frontpage/drizzle/meta/0001_snapshot.json @@ -0,0 +1,636 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "00d0dbbe-737a-4ae8-985f-58fcc4d8d3fc", + "prevId": "b13e6740-b488-43a0-a373-49d5657df2bc", + "tables": { + "beta_users": { + "name": "beta_users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "did": { + "name": "did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "beta_users_did_unique": { + "name": "beta_users_did_unique", + "columns": [ + "did" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "comments": { + "name": "comments", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "rkey": { + "name": "rkey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cid": { + "name": "cid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "post_id": { + "name": "post_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "body": { + "name": "body", + "type": "text(10000)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "author_did": { + "name": "author_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'live'" + }, + "parent_comment_id": { + "name": "parent_comment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "comments_cid_unique": { + "name": "comments_cid_unique", + "columns": [ + "cid" + ], + "isUnique": true + }, + "comments_author_did_rkey_unique": { + "name": "comments_author_did_rkey_unique", + "columns": [ + "author_did", + "rkey" + ], + "isUnique": true + } + }, + "foreignKeys": { + "comments_post_id_posts_id_fk": { + "name": "comments_post_id_posts_id_fk", + "tableFrom": "comments", + "tableTo": "posts", + "columnsFrom": [ + "post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "parent_comment_id_fkey": { + "name": "parent_comment_id_fkey", + "tableFrom": "comments", + "tableTo": "comments", + "columnsFrom": [ + "parent_comment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "comment_votes": { + "name": "comment_votes", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "comment_id": { + "name": "comment_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "author_did": { + "name": "author_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cid": { + "name": "cid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rkey": { + "name": "rkey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "comment_votes_cid_unique": { + "name": "comment_votes_cid_unique", + "columns": [ + "cid" + ], + "isUnique": true + }, + "comment_votes_author_did_rkey_unique": { + "name": "comment_votes_author_did_rkey_unique", + "columns": [ + "author_did", + "rkey" + ], + "isUnique": true + }, + "comment_votes_author_did_comment_id_unique": { + "name": "comment_votes_author_did_comment_id_unique", + "columns": [ + "author_did", + "comment_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "comment_votes_comment_id_comments_id_fk": { + "name": "comment_votes_comment_id_comments_id_fk", + "tableFrom": "comment_votes", + "tableTo": "comments", + "columnsFrom": [ + "comment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "consumed_offsets": { + "name": "consumed_offsets", + "columns": { + "offset": { + "name": "offset", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "labelled_profiles": { + "name": "labelled_profiles", + "columns": { + "did": { + "name": "did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "labels": { + "name": "labels", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "labelled_profiles_did_unique": { + "name": "labelled_profiles_did_unique", + "columns": [ + "did" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "moderation_events": { + "name": "moderation_events", + "columns": { + "subject_uri": { + "name": "subject_uri", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_did": { + "name": "subject_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_collection": { + "name": "subject_collection", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_rkey": { + "name": "subject_rkey", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_cid": { + "name": "subject_cid", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "labels_added": { + "name": "labels_added", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "report_type": { + "name": "report_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "posts": { + "name": "posts", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "rkey": { + "name": "rkey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cid": { + "name": "cid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text(300)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "author_did": { + "name": "author_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'live'" + } + }, + "indexes": { + "posts_cid_unique": { + "name": "posts_cid_unique", + "columns": [ + "cid" + ], + "isUnique": true + }, + "posts_author_did_rkey_unique": { + "name": "posts_author_did_rkey_unique", + "columns": [ + "author_did", + "rkey" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "post_votes": { + "name": "post_votes", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "post_id": { + "name": "post_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "author_did": { + "name": "author_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cid": { + "name": "cid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rkey": { + "name": "rkey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "post_votes_cid_unique": { + "name": "post_votes_cid_unique", + "columns": [ + "cid" + ], + "isUnique": true + }, + "post_votes_author_did_rkey_unique": { + "name": "post_votes_author_did_rkey_unique", + "columns": [ + "author_did", + "rkey" + ], + "isUnique": true + }, + "post_votes_author_did_post_id_unique": { + "name": "post_votes_author_did_post_id_unique", + "columns": [ + "author_did", + "post_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "post_votes_post_id_posts_id_fk": { + "name": "post_votes_post_id_posts_id_fk", + "tableFrom": "post_votes", + "tableTo": "posts", + "columnsFrom": [ + "post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "reports": { + "name": "reports", + "columns": { + "actioned_at": { + "name": "actioned_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actioned_by": { + "name": "actioned_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_uri": { + "name": "subject_uri", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_did": { + "name": "subject_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_collection": { + "name": "subject_collection", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_rkey": { + "name": "subject_rkey", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_cid": { + "name": "subject_cid", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_comment": { + "name": "creator_comment", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "labels_added": { + "name": "labels_added", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/packages/frontpage/drizzle/meta/_journal.json b/packages/frontpage/drizzle/meta/_journal.json index e06a2c9b..1307d38e 100644 --- a/packages/frontpage/drizzle/meta/_journal.json +++ b/packages/frontpage/drizzle/meta/_journal.json @@ -8,6 +8,13 @@ "when": 1725040407942, "tag": "0000_sturdy_rage", "breakpoints": true + }, + { + "idx": 1, + "version": "6", + "when": 1726875517497, + "tag": "0001_glamorous_starfox", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/frontpage/lib/data/user.ts b/packages/frontpage/lib/data/user.ts index c8e7e6b7..a0dfe5d5 100644 --- a/packages/frontpage/lib/data/user.ts +++ b/packages/frontpage/lib/data/user.ts @@ -81,6 +81,20 @@ export const isBetaUser = cache(async () => { ); }); +export const hasRole = cache(async (role: string) => { + const user = await getUser(); + if (!user) { + return false; + } + + return Boolean( + role === "moderator", + // await db.query.User.findFirst({ + // where: and(eq(schema.User.did, user.did), eq(schema.User.role, role)), + // }), + ); +}); + const ProfileResponse = z.object({ avatar: z.string(), handle: z.string(), diff --git a/packages/frontpage/lib/schema.ts b/packages/frontpage/lib/schema.ts index 17b0060a..ee63fc46 100644 --- a/packages/frontpage/lib/schema.ts +++ b/packages/frontpage/lib/schema.ts @@ -128,16 +128,19 @@ export const ConsumedOffset = sqliteTable("consumed_offsets", { offset: integer("offset").primaryKey(), }); +const createColumnReportType = (col: string) => + text(col, { enum: ["post", "comment", "user"] }); + export const ModerationEvent = sqliteTable("moderation_events", { subjectUri: text("subject_uri").notNull(), subjectDid: text("subject_did").notNull(), subjectCollection: text("subject_collection"), subjectRkey: text("subject_rkey"), - subjectCid: text("subject_cid").notNull(), + subjectCid: text("subject_cid"), createdBy: text("created_by").notNull(), createdAt: dateIsoText("created_at").notNull(), labelsAdded: text("labels_added"), - labelsRemoved: text("labels_removed"), + reportType: createColumnReportType("report_type"), }); export const LabelledProfile = sqliteTable("labelled_profiles", { @@ -152,7 +155,7 @@ export const Report = sqliteTable("reports", { subjectDid: text("subject_did").notNull(), subjectCollection: text("subject_collection"), subjectRkey: text("subject_rkey"), - subjectCid: text("subject_cid").notNull(), + subjectCid: text("subject_cid"), createdBy: text("created_by").notNull(), createdAt: dateIsoText("created_at").notNull(), creatorComment: text("creator_comment"), From f8606ddf8bc20d4a15caf021f2914ee03bd2a115 Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Sun, 22 Sep 2024 21:08:57 +0100 Subject: [PATCH 06/43] remove extra div on mod page --- .../app/(app)/moderation/_client.tsx | 252 +++++++++--------- 1 file changed, 125 insertions(+), 127 deletions(-) diff --git a/packages/frontpage/app/(app)/moderation/_client.tsx b/packages/frontpage/app/(app)/moderation/_client.tsx index 2cd90c8d..0da9133b 100644 --- a/packages/frontpage/app/(app)/moderation/_client.tsx +++ b/packages/frontpage/app/(app)/moderation/_client.tsx @@ -18,141 +18,139 @@ export default function ModerationPage({ stats: { total: number; pending: number; approved: number; rejected: number }; }) { return ( -
- - - - - Moderation Dashboard - - - Review and take action on reported content - - - -
- + + + + + Moderation Dashboard + + + Review and take action on reported content + + + +
+ + + + Total Reports + + + +
+ {stats.total} +
+
+
+ + + + Pending + + + +
+ {stats.pending} +
+
+
+ + + + Approved + + + +
+ {stats.approved} +
+
+
+ + + + Rejected + + + +
+ {stats.rejected} +
+
+
+
+
+ {reports.map((report) => ( + - - Total Reports + + + Reported {report.type} in {report.community} + + + {report.status.charAt(0).toUpperCase() + + report.status.slice(1)} + -
- {stats.total} -
-
-
- - - - Pending - - - -
- {stats.pending} +

{report.content}

+
+
+ DID: {report.did} +
+
+ CID: {report.cid} +
+
+ Record Key: {report.rkey} +
+
- - - - - - Approved - - - -
- {stats.approved} +
+ + Reason: {report.reason}
- - - - - - Rejected - - - -
- {stats.rejected} +
+ +
-
-
- {reports.map((report) => ( - - - - - Reported {report.type} in {report.community} - - - {report.status.charAt(0).toUpperCase() + - report.status.slice(1)} - - - - -

{report.content}

-
-
- DID: {report.did} -
-
- CID: {report.cid} -
-
- Record Key: {report.rkey} -
- -
-
- - Reason: {report.reason} -
-
- - -
-
-
- ))} -
-
-
-
+ ))} +
+
+
); } From 06f8fb6706dce764b2bc2ee812a8fde27b539579 Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Mon, 23 Sep 2024 01:45:25 +0100 Subject: [PATCH 07/43] delete generated migration --- .../drizzle/0001_glamorous_starfox.sql | 32 - .../frontpage/drizzle/meta/0001_snapshot.json | 636 ------------------ packages/frontpage/drizzle/meta/_journal.json | 9 +- 3 files changed, 1 insertion(+), 676 deletions(-) delete mode 100644 packages/frontpage/drizzle/0001_glamorous_starfox.sql delete mode 100644 packages/frontpage/drizzle/meta/0001_snapshot.json diff --git a/packages/frontpage/drizzle/0001_glamorous_starfox.sql b/packages/frontpage/drizzle/0001_glamorous_starfox.sql deleted file mode 100644 index e866378a..00000000 --- a/packages/frontpage/drizzle/0001_glamorous_starfox.sql +++ /dev/null @@ -1,32 +0,0 @@ -CREATE TABLE `labelled_profiles` ( - `did` text NOT NULL, - `labels` text -); - -CREATE TABLE `moderation_events` ( - `subject_uri` text NOT NULL, - `subject_did` text NOT NULL, - `subject_collection` text, - `subject_rkey` text, - `subject_cid` text, - `created_by` text NOT NULL, - `created_at` text NOT NULL, - `labels_added` text, - `report_type` text -); - -CREATE TABLE `reports` ( - `actioned_at` text, - `actioned_by` text, - `subject_uri` text NOT NULL, - `subject_did` text NOT NULL, - `subject_collection` text, - `subject_rkey` text, - `subject_cid` text, - `created_by` text NOT NULL, - `created_at` text NOT NULL, - `creator_comment` text, - `labels_added` text -); - -CREATE UNIQUE INDEX `labelled_profiles_did_unique` ON `labelled_profiles` (`did`); diff --git a/packages/frontpage/drizzle/meta/0001_snapshot.json b/packages/frontpage/drizzle/meta/0001_snapshot.json deleted file mode 100644 index 7a377d2f..00000000 --- a/packages/frontpage/drizzle/meta/0001_snapshot.json +++ /dev/null @@ -1,636 +0,0 @@ -{ - "version": "6", - "dialect": "sqlite", - "id": "00d0dbbe-737a-4ae8-985f-58fcc4d8d3fc", - "prevId": "b13e6740-b488-43a0-a373-49d5657df2bc", - "tables": { - "beta_users": { - "name": "beta_users", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "did": { - "name": "did", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "beta_users_did_unique": { - "name": "beta_users_did_unique", - "columns": [ - "did" - ], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "comments": { - "name": "comments", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "rkey": { - "name": "rkey", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "cid": { - "name": "cid", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "post_id": { - "name": "post_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "body": { - "name": "body", - "type": "text(10000)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "author_did": { - "name": "author_did", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "'live'" - }, - "parent_comment_id": { - "name": "parent_comment_id", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "comments_cid_unique": { - "name": "comments_cid_unique", - "columns": [ - "cid" - ], - "isUnique": true - }, - "comments_author_did_rkey_unique": { - "name": "comments_author_did_rkey_unique", - "columns": [ - "author_did", - "rkey" - ], - "isUnique": true - } - }, - "foreignKeys": { - "comments_post_id_posts_id_fk": { - "name": "comments_post_id_posts_id_fk", - "tableFrom": "comments", - "tableTo": "posts", - "columnsFrom": [ - "post_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "parent_comment_id_fkey": { - "name": "parent_comment_id_fkey", - "tableFrom": "comments", - "tableTo": "comments", - "columnsFrom": [ - "parent_comment_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "comment_votes": { - "name": "comment_votes", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "comment_id": { - "name": "comment_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "author_did": { - "name": "author_did", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "cid": { - "name": "cid", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "rkey": { - "name": "rkey", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "comment_votes_cid_unique": { - "name": "comment_votes_cid_unique", - "columns": [ - "cid" - ], - "isUnique": true - }, - "comment_votes_author_did_rkey_unique": { - "name": "comment_votes_author_did_rkey_unique", - "columns": [ - "author_did", - "rkey" - ], - "isUnique": true - }, - "comment_votes_author_did_comment_id_unique": { - "name": "comment_votes_author_did_comment_id_unique", - "columns": [ - "author_did", - "comment_id" - ], - "isUnique": true - } - }, - "foreignKeys": { - "comment_votes_comment_id_comments_id_fk": { - "name": "comment_votes_comment_id_comments_id_fk", - "tableFrom": "comment_votes", - "tableTo": "comments", - "columnsFrom": [ - "comment_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "consumed_offsets": { - "name": "consumed_offsets", - "columns": { - "offset": { - "name": "offset", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "labelled_profiles": { - "name": "labelled_profiles", - "columns": { - "did": { - "name": "did", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "labels": { - "name": "labels", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "labelled_profiles_did_unique": { - "name": "labelled_profiles_did_unique", - "columns": [ - "did" - ], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "moderation_events": { - "name": "moderation_events", - "columns": { - "subject_uri": { - "name": "subject_uri", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject_did": { - "name": "subject_did", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject_collection": { - "name": "subject_collection", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subject_rkey": { - "name": "subject_rkey", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subject_cid": { - "name": "subject_cid", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_by": { - "name": "created_by", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "labels_added": { - "name": "labels_added", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "report_type": { - "name": "report_type", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "posts": { - "name": "posts", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "rkey": { - "name": "rkey", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "cid": { - "name": "cid", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "title": { - "name": "title", - "type": "text(300)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "url": { - "name": "url", - "type": "text(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "author_did": { - "name": "author_did", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "'live'" - } - }, - "indexes": { - "posts_cid_unique": { - "name": "posts_cid_unique", - "columns": [ - "cid" - ], - "isUnique": true - }, - "posts_author_did_rkey_unique": { - "name": "posts_author_did_rkey_unique", - "columns": [ - "author_did", - "rkey" - ], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "post_votes": { - "name": "post_votes", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "post_id": { - "name": "post_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "author_did": { - "name": "author_did", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "cid": { - "name": "cid", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "rkey": { - "name": "rkey", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "post_votes_cid_unique": { - "name": "post_votes_cid_unique", - "columns": [ - "cid" - ], - "isUnique": true - }, - "post_votes_author_did_rkey_unique": { - "name": "post_votes_author_did_rkey_unique", - "columns": [ - "author_did", - "rkey" - ], - "isUnique": true - }, - "post_votes_author_did_post_id_unique": { - "name": "post_votes_author_did_post_id_unique", - "columns": [ - "author_did", - "post_id" - ], - "isUnique": true - } - }, - "foreignKeys": { - "post_votes_post_id_posts_id_fk": { - "name": "post_votes_post_id_posts_id_fk", - "tableFrom": "post_votes", - "tableTo": "posts", - "columnsFrom": [ - "post_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "reports": { - "name": "reports", - "columns": { - "actioned_at": { - "name": "actioned_at", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "actioned_by": { - "name": "actioned_by", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subject_uri": { - "name": "subject_uri", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject_did": { - "name": "subject_did", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "subject_collection": { - "name": "subject_collection", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subject_rkey": { - "name": "subject_rkey", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subject_cid": { - "name": "subject_cid", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_by": { - "name": "created_by", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "creator_comment": { - "name": "creator_comment", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "labels_added": { - "name": "labels_added", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - } - }, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "indexes": {} - } -} \ No newline at end of file diff --git a/packages/frontpage/drizzle/meta/_journal.json b/packages/frontpage/drizzle/meta/_journal.json index 1307d38e..02e6469e 100644 --- a/packages/frontpage/drizzle/meta/_journal.json +++ b/packages/frontpage/drizzle/meta/_journal.json @@ -8,13 +8,6 @@ "when": 1725040407942, "tag": "0000_sturdy_rage", "breakpoints": true - }, - { - "idx": 1, - "version": "6", - "when": 1726875517497, - "tag": "0001_glamorous_starfox", - "breakpoints": true } ] -} \ No newline at end of file +} From 51a32bb99b007d908c1e388758d1bd5fdd14a00a Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Mon, 23 Sep 2024 04:35:37 +0100 Subject: [PATCH 08/43] update report to reflect schema, start working on actual page components --- .../app/(app)/moderation/_client.tsx | 260 +++++++++--------- .../frontpage/app/(app)/moderation/page.tsx | 97 ++++--- 2 files changed, 197 insertions(+), 160 deletions(-) diff --git a/packages/frontpage/app/(app)/moderation/_client.tsx b/packages/frontpage/app/(app)/moderation/_client.tsx index 0da9133b..37ac6a39 100644 --- a/packages/frontpage/app/(app)/moderation/_client.tsx +++ b/packages/frontpage/app/(app)/moderation/_client.tsx @@ -9,6 +9,13 @@ import { CardTitle, } from "@/lib/components/ui/card"; import { Report } from "./page"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/lib/components/ui/tabs"; +import { useState } from "react"; export default function ModerationPage({ reports, @@ -17,140 +24,143 @@ export default function ModerationPage({ reports: Report[]; stats: { total: number; pending: number; approved: number; rejected: number }; }) { + const [selectedTab, setSelectedTab] = useState("all"); + return ( - - - - - Moderation Dashboard - - - Review and take action on reported content - - - -
- - - - Total Reports - - - -
- {stats.total} -
-
-
- - - - Pending - - - -
- {stats.pending} -
-
-
- - - - Approved - - - -
- {stats.approved} -
-
-
- - - - Rejected - - - -
- {stats.rejected} -
-
-
-
-
- {reports.map((report) => ( - + <> + + + + + Moderation Dashboard + + + Review and take action on reported content + + + +
+ setSelectedTab("all")} + > - - - Reported {report.type} in {report.community} - - - {report.status.charAt(0).toUpperCase() + - report.status.slice(1)} - + + Total Reports -

{report.content}

-
-
- DID: {report.did} -
-
- CID: {report.cid} -
-
- Record Key: {report.rkey} -
- +
+ {stats.total}
-
- - Reason: {report.reason} + + + setSelectedTab("pending")} + > + + + Pending + + + +
+ {stats.pending}
-
- - + + + setSelectedTab("approved")} + > + + + Approved + + + +
+ {stats.approved} +
+
+
+ setSelectedTab("rejected")} + > + + + Rejected + + + +
+ {stats.rejected}
- ))} -
-
-
+
+ + + {reports + .filter( + (report) => report.status === selectedTab || selectedTab === "all", + ) + .map((report) => ( + + + + Reported {report.type} + + {report.status.charAt(0).toUpperCase() + + report.status.slice(1)} + + + + +

{report.creatorComment}

+
+
+ DID: {report.subjectDid} +
+
+ CID: {report.subjectCid} +
+
+ Record Key: {report.subjectRkey} +
+ +
+
+ + Reason: {report.creatorComment} +
+
+
+ ))} + ); } diff --git a/packages/frontpage/app/(app)/moderation/page.tsx b/packages/frontpage/app/(app)/moderation/page.tsx index 15235924..afbdc6e2 100644 --- a/packages/frontpage/app/(app)/moderation/page.tsx +++ b/packages/frontpage/app/(app)/moderation/page.tsx @@ -5,54 +5,81 @@ import { redirect } from "next/navigation"; import ModerationPage from "./_client"; export type Report = { - id: string; - type: "post" | "comment"; - content: string; - reason: string; - status: "pending" | "approved" | "rejected"; - did: string; - cid: string; - rkey: string; - uri: string; - community: string; + actionedAt?: string; // Optional field + actionedBy?: string; // Optional field + subjectUri: string; + subjectDid: string; + subjectCollection?: string; // Optional field + subjectRkey?: string; // Optional field + subjectCid?: string; // Optional field + createdBy: string; + createdAt: string; + creatorComment?: string; // Optional field + labelsAdded?: string; // Optional field + //TODO: add a type field to the report schema so you know if it's a post, comment or user report + //TODO: add a status field to the report schema so you know if it's pending, approved or rejected + type: "post" | "comment" | "user"; // New field to indicate the type of report + status: "pending" | "approved" | "rejected"; // New field to indicate the status of the report }; const reports: Report[] = [ { - id: "1", + actionedAt: "2023-10-01T12:00:00Z", + actionedBy: "moderator1", + subjectUri: "uri1", + subjectDid: "did1", + subjectCollection: "collection1", + subjectRkey: "rkey1", + subjectCid: "cid1", + createdBy: "user1", + createdAt: "2023-09-30T12:00:00Z", + creatorComment: "This is a comment by the creator.", + labelsAdded: "label1,label2", type: "post", - content: "This is a reported post", - reason: "Inappropriate content", - status: "pending", - did: "did:plc:abcdefghijklmnop", - cid: "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi", - rkey: "abcdef123456", - uri: "at://did:plc:abcdefghijklmnop/app.bsky.feed.post/abcdef123456", - community: "General", + status: "approved", }, { - id: "2", + actionedAt: "2023-10-02T12:00:00Z", + actionedBy: "moderator2", + subjectUri: "uri2", + subjectDid: "did2", + subjectCollection: "collection2", + subjectRkey: "rkey2", + subjectCid: "cid2", + createdBy: "user2", + createdAt: "2023-09-29T12:00:00Z", + creatorComment: "This is another comment by the creator.", + labelsAdded: "label3,label4", type: "comment", - content: "This is a reported comment", - reason: "Spam", + status: "rejected", + }, + { + subjectUri: "uri3", + subjectDid: "did3", + createdBy: "user3", + createdAt: "2023-09-28T12:00:00Z", + type: "user", status: "pending", - did: "did:plc:qrstuvwxyz123456", - cid: "bafybeihbgxvydgnxlfapxnzb7zyqbbs6tkvhflemvwogzb5zzp7ufuz7ky", - rkey: "ghijkl789012", - uri: "at://did:plc:qrstuvwxyz123456/app.bsky.feed.post/ghijkl789012", - community: "Tech", }, { - id: "3", + subjectUri: "uri4", + subjectDid: "did4", + subjectCollection: "collection4", + createdBy: "user4", + createdAt: "2023-09-27T12:00:00Z", + creatorComment: "Yet another comment by the creator.", type: "post", - content: "Another reported post", - reason: "Misinformation", status: "pending", - did: "did:plc:123456abcdefghij", - cid: "bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xccnlnmzhe5h6y7afcvqpqom", - rkey: "mnopqr456789", - uri: "at://did:plc:123456abcdefghij/app.bsky.feed.post/mnopqr456789", - community: "Science", + }, + { + subjectUri: "uri5", + subjectDid: "did5", + subjectRkey: "rkey5", + createdBy: "user5", + createdAt: "2023-09-26T12:00:00Z", + labelsAdded: "label5,label6", + type: "comment", + status: "approved", }, ]; From 4b5c2ef4099eaba7fd6f520e23fbc9668dfecf11 Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Mon, 23 Sep 2024 04:35:45 +0100 Subject: [PATCH 09/43] update readme typos --- packages/frontpage/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontpage/README.md b/packages/frontpage/README.md index 5812dcc5..6ed84acd 100644 --- a/packages/frontpage/README.md +++ b/packages/frontpage/README.md @@ -10,10 +10,10 @@ If you just need to work on the app in a logged-out state, then you just need to pnpm run dev ``` -If you need to login, you need to setup some additional env vars and serve your dev server over the public internet. You can do this with `cloudflared` altho other options are available eg. `ngrok` or `tailscale`: +If you need to login, you need to setup some additional env vars and serve your dev server over the public internet. You can do this with `cloudflared` although other options are available eg. `ngrok` or `tailscale`: ```bash -pnpm exec tsx ./scripts/generate-jwks.mts # Copy this output into .env.local +pnpm exec tsx ./scripts/generate-jwk.mts # Copy this output into .env.local # In one terminal, start the dev server pnpm run dev From db46d9243ed2b628062f8b8a91249a5641548221 Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Mon, 23 Sep 2024 10:39:27 +0100 Subject: [PATCH 10/43] remove unused imports for build --- packages/frontpage/app/(app)/moderation/_client.tsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/frontpage/app/(app)/moderation/_client.tsx b/packages/frontpage/app/(app)/moderation/_client.tsx index 37ac6a39..f8bb5f62 100644 --- a/packages/frontpage/app/(app)/moderation/_client.tsx +++ b/packages/frontpage/app/(app)/moderation/_client.tsx @@ -1,6 +1,5 @@ "use client"; -import { CheckCircle, ExternalLink, Flag, Shield, XCircle } from "lucide-react"; -import { Button } from "@/lib/components/ui/button"; +import { ExternalLink, Flag, Shield } from "lucide-react"; import { Card, CardContent, @@ -9,12 +8,6 @@ import { CardTitle, } from "@/lib/components/ui/card"; import { Report } from "./page"; -import { - Tabs, - TabsContent, - TabsList, - TabsTrigger, -} from "@/lib/components/ui/tabs"; import { useState } from "react"; export default function ModerationPage({ From 4bd324f50d8153fb6351ab93b8401462b42fd02c Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Wed, 25 Sep 2024 20:50:33 +0100 Subject: [PATCH 11/43] generate schema, migrate --- .../app/(app)/moderation/actions.tsx | 16 + .../moderation/{_client.tsx => client.tsx} | 0 .../frontpage/app/(app)/moderation/page.tsx | 8 +- .../drizzle/0002_windy_ezekiel_stane.sql | 37 + .../frontpage/drizzle/meta/0002_snapshot.json | 845 ++++++++++++++++++ packages/frontpage/drizzle/meta/_journal.json | 9 +- packages/frontpage/lib/schema.ts | 12 +- 7 files changed, 920 insertions(+), 7 deletions(-) rename packages/frontpage/app/(app)/moderation/{_client.tsx => client.tsx} (100%) create mode 100644 packages/frontpage/drizzle/0002_windy_ezekiel_stane.sql create mode 100644 packages/frontpage/drizzle/meta/0002_snapshot.json diff --git a/packages/frontpage/app/(app)/moderation/actions.tsx b/packages/frontpage/app/(app)/moderation/actions.tsx index d431e6ac..8912df36 100644 --- a/packages/frontpage/app/(app)/moderation/actions.tsx +++ b/packages/frontpage/app/(app)/moderation/actions.tsx @@ -1,3 +1,19 @@ "use server"; //TODO: add actions for creating, updating, deleting moderation reports + +export async function createModerationAction( + _prevState: unknown, + formData: FormData, +) { + //create the moderation action and update the report as actioned + return { error: "Not implemented" }; +} + +export async function rejectReportAction( + _prevState: unknown, + formData: FormData, +) { + //reject the report and update the report as actioned + return { error: "Not implemented" }; +} diff --git a/packages/frontpage/app/(app)/moderation/_client.tsx b/packages/frontpage/app/(app)/moderation/client.tsx similarity index 100% rename from packages/frontpage/app/(app)/moderation/_client.tsx rename to packages/frontpage/app/(app)/moderation/client.tsx diff --git a/packages/frontpage/app/(app)/moderation/page.tsx b/packages/frontpage/app/(app)/moderation/page.tsx index afbdc6e2..9fd1ff66 100644 --- a/packages/frontpage/app/(app)/moderation/page.tsx +++ b/packages/frontpage/app/(app)/moderation/page.tsx @@ -2,9 +2,10 @@ import { hasRole } from "@/lib/data/user"; import { redirect } from "next/navigation"; -import ModerationPage from "./_client"; +import ModerationPage from "./client"; export type Report = { + id: number; actionedAt?: string; // Optional field actionedBy?: string; // Optional field subjectUri: string; @@ -24,6 +25,7 @@ export type Report = { const reports: Report[] = [ { + id: 1, actionedAt: "2023-10-01T12:00:00Z", actionedBy: "moderator1", subjectUri: "uri1", @@ -39,6 +41,7 @@ const reports: Report[] = [ status: "approved", }, { + id: 2, actionedAt: "2023-10-02T12:00:00Z", actionedBy: "moderator2", subjectUri: "uri2", @@ -54,6 +57,7 @@ const reports: Report[] = [ status: "rejected", }, { + id: 3, subjectUri: "uri3", subjectDid: "did3", createdBy: "user3", @@ -62,6 +66,7 @@ const reports: Report[] = [ status: "pending", }, { + id: 4, subjectUri: "uri4", subjectDid: "did4", subjectCollection: "collection4", @@ -72,6 +77,7 @@ const reports: Report[] = [ status: "pending", }, { + id: 5, subjectUri: "uri5", subjectDid: "did5", subjectRkey: "rkey5", diff --git a/packages/frontpage/drizzle/0002_windy_ezekiel_stane.sql b/packages/frontpage/drizzle/0002_windy_ezekiel_stane.sql new file mode 100644 index 00000000..dba1ce15 --- /dev/null +++ b/packages/frontpage/drizzle/0002_windy_ezekiel_stane.sql @@ -0,0 +1,37 @@ +CREATE TABLE `labelled_profiles` ( + `id` integer PRIMARY KEY NOT NULL, + `did` text NOT NULL, + `is_hidden` integer DEFAULT false NOT NULL, + `labels` text +); +--> statement-breakpoint +CREATE TABLE `moderation_events` ( + `id` integer PRIMARY KEY NOT NULL, + `subject_uri` text NOT NULL, + `subject_did` text NOT NULL, + `subject_collection` text, + `subject_rkey` text, + `subject_cid` text, + `created_by` text NOT NULL, + `created_at` text NOT NULL, + `labels_added` text, + `labels_removed` text, + `report_type` text +); +--> statement-breakpoint +CREATE TABLE `reports` ( + `id` integer PRIMARY KEY NOT NULL, + `actioned_at` text, + `actioned_by` text, + `subject_uri` text NOT NULL, + `subject_did` text NOT NULL, + `subject_collection` text, + `subject_rkey` text, + `subject_cid` text, + `created_by` text NOT NULL, + `created_at` text NOT NULL, + `creator_comment` text, + `report_reason` text +); +--> statement-breakpoint +CREATE UNIQUE INDEX `labelled_profiles_did_unique` ON `labelled_profiles` (`did`); \ No newline at end of file diff --git a/packages/frontpage/drizzle/meta/0002_snapshot.json b/packages/frontpage/drizzle/meta/0002_snapshot.json new file mode 100644 index 00000000..4bd598a0 --- /dev/null +++ b/packages/frontpage/drizzle/meta/0002_snapshot.json @@ -0,0 +1,845 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "0374b59d-b2ce-4b76-8dde-835281e84750", + "prevId": "dcb0c712-e046-420d-9fc3-bdcc9f58fa45", + "tables": { + "beta_users": { + "name": "beta_users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "did": { + "name": "did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "beta_users_did_unique": { + "name": "beta_users_did_unique", + "columns": [ + "did" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "comments": { + "name": "comments", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "rkey": { + "name": "rkey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cid": { + "name": "cid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "post_id": { + "name": "post_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "body": { + "name": "body", + "type": "text(10000)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "author_did": { + "name": "author_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'live'" + }, + "parent_comment_id": { + "name": "parent_comment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "comments_cid_unique": { + "name": "comments_cid_unique", + "columns": [ + "cid" + ], + "isUnique": true + }, + "comments_author_did_rkey_unique": { + "name": "comments_author_did_rkey_unique", + "columns": [ + "author_did", + "rkey" + ], + "isUnique": true + } + }, + "foreignKeys": { + "comments_post_id_posts_id_fk": { + "name": "comments_post_id_posts_id_fk", + "tableFrom": "comments", + "tableTo": "posts", + "columnsFrom": [ + "post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "parent_comment_id_fkey": { + "name": "parent_comment_id_fkey", + "tableFrom": "comments", + "tableTo": "comments", + "columnsFrom": [ + "parent_comment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "comment_votes": { + "name": "comment_votes", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "comment_id": { + "name": "comment_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "author_did": { + "name": "author_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cid": { + "name": "cid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rkey": { + "name": "rkey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "comment_votes_cid_unique": { + "name": "comment_votes_cid_unique", + "columns": [ + "cid" + ], + "isUnique": true + }, + "comment_votes_author_did_rkey_unique": { + "name": "comment_votes_author_did_rkey_unique", + "columns": [ + "author_did", + "rkey" + ], + "isUnique": true + }, + "comment_votes_author_did_comment_id_unique": { + "name": "comment_votes_author_did_comment_id_unique", + "columns": [ + "author_did", + "comment_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "comment_votes_comment_id_comments_id_fk": { + "name": "comment_votes_comment_id_comments_id_fk", + "tableFrom": "comment_votes", + "tableTo": "comments", + "columnsFrom": [ + "comment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "consumed_offsets": { + "name": "consumed_offsets", + "columns": { + "offset": { + "name": "offset", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "labelled_profiles": { + "name": "labelled_profiles", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "did": { + "name": "did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_hidden": { + "name": "is_hidden", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "labels": { + "name": "labels", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "labelled_profiles_did_unique": { + "name": "labelled_profiles_did_unique", + "columns": [ + "did" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "moderation_events": { + "name": "moderation_events", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "subject_uri": { + "name": "subject_uri", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_did": { + "name": "subject_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_collection": { + "name": "subject_collection", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_rkey": { + "name": "subject_rkey", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_cid": { + "name": "subject_cid", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "labels_added": { + "name": "labels_added", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "labels_removed": { + "name": "labels_removed", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "report_type": { + "name": "report_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "oauth_auth_requests": { + "name": "oauth_auth_requests", + "columns": { + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "iss": { + "name": "iss", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "did": { + "name": "did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nonce": { + "name": "nonce", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "pkce_verifier": { + "name": "pkce_verifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dpop_private_jwk": { + "name": "dpop_private_jwk", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dpop_public_jwk": { + "name": "dpop_public_jwk", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "oauth_auth_requests_state_unique": { + "name": "oauth_auth_requests_state_unique", + "columns": [ + "state" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "oauth_sessions": { + "name": "oauth_sessions", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "did": { + "name": "did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "iss": { + "name": "iss", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dpop_nonce": { + "name": "dpop_nonce", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dpop_private_jwk": { + "name": "dpop_private_jwk", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dpop_public_jwk": { + "name": "dpop_public_jwk", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "posts": { + "name": "posts", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "rkey": { + "name": "rkey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cid": { + "name": "cid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text(300)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "author_did": { + "name": "author_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'live'" + } + }, + "indexes": { + "posts_cid_unique": { + "name": "posts_cid_unique", + "columns": [ + "cid" + ], + "isUnique": true + }, + "posts_author_did_rkey_unique": { + "name": "posts_author_did_rkey_unique", + "columns": [ + "author_did", + "rkey" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "post_votes": { + "name": "post_votes", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "post_id": { + "name": "post_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "author_did": { + "name": "author_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cid": { + "name": "cid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rkey": { + "name": "rkey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "post_votes_cid_unique": { + "name": "post_votes_cid_unique", + "columns": [ + "cid" + ], + "isUnique": true + }, + "post_votes_author_did_rkey_unique": { + "name": "post_votes_author_did_rkey_unique", + "columns": [ + "author_did", + "rkey" + ], + "isUnique": true + }, + "post_votes_author_did_post_id_unique": { + "name": "post_votes_author_did_post_id_unique", + "columns": [ + "author_did", + "post_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "post_votes_post_id_posts_id_fk": { + "name": "post_votes_post_id_posts_id_fk", + "tableFrom": "post_votes", + "tableTo": "posts", + "columnsFrom": [ + "post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "reports": { + "name": "reports", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "actioned_at": { + "name": "actioned_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actioned_by": { + "name": "actioned_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_uri": { + "name": "subject_uri", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_did": { + "name": "subject_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_collection": { + "name": "subject_collection", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_rkey": { + "name": "subject_rkey", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_cid": { + "name": "subject_cid", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_comment": { + "name": "creator_comment", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "report_reason": { + "name": "report_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/packages/frontpage/drizzle/meta/_journal.json b/packages/frontpage/drizzle/meta/_journal.json index b1ec7017..b85b060c 100644 --- a/packages/frontpage/drizzle/meta/_journal.json +++ b/packages/frontpage/drizzle/meta/_journal.json @@ -15,6 +15,13 @@ "when": 1725476942887, "tag": "0001_confused_norrin_radd", "breakpoints": true + }, + { + "idx": 2, + "version": "6", + "when": 1727293406638, + "tag": "0002_windy_ezekiel_stane", + "breakpoints": true } ] -} +} \ No newline at end of file diff --git a/packages/frontpage/lib/schema.ts b/packages/frontpage/lib/schema.ts index 790fde79..8a2bd093 100644 --- a/packages/frontpage/lib/schema.ts +++ b/packages/frontpage/lib/schema.ts @@ -155,10 +155,8 @@ export const OauthSession = sqliteTable("oauth_sessions", { createdAt: dateIsoText("created_at").notNull(), }); -const createColumnReportType = (col: string) => - text(col, { enum: ["post", "comment", "user"] }); - export const ModerationEvent = sqliteTable("moderation_events", { + id: integer("id").primaryKey(), subjectUri: text("subject_uri").notNull(), subjectDid: text("subject_did").notNull(), subjectCollection: text("subject_collection"), @@ -167,15 +165,19 @@ export const ModerationEvent = sqliteTable("moderation_events", { createdBy: text("created_by").notNull(), createdAt: dateIsoText("created_at").notNull(), labelsAdded: text("labels_added"), - reportType: createColumnReportType("report_type"), + labelsRemoved: text("labels_removed"), + creatorReportReason: text("report_type"), }); export const LabelledProfile = sqliteTable("labelled_profiles", { + id: integer("id").primaryKey(), did: text("did").notNull().unique(), + isHidden: integer("is_hidden", { mode: "boolean" }).notNull().default(false), labels: text("labels"), }); export const Report = sqliteTable("reports", { + id: integer("id").primaryKey(), actionedAt: dateIsoText("actioned_at"), actionedBy: text("actioned_by"), subjectUri: text("subject_uri").notNull(), @@ -186,5 +188,5 @@ export const Report = sqliteTable("reports", { createdBy: text("created_by").notNull(), createdAt: dateIsoText("created_at").notNull(), creatorComment: text("creator_comment"), - labelsAdded: text("labels_added"), + reportReason: text("report_reason"), }); From 3f35e596f1153beebae397a7f804c4130fe30cb1 Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Thu, 26 Sep 2024 05:01:11 +0100 Subject: [PATCH 12/43] add status to schema, start chunking out actions, get forms and actions in --- .../app/(app)/moderation/actions.tsx | 9 +- .../frontpage/app/(app)/moderation/client.tsx | 140 +-- .../frontpage/app/(app)/moderation/page.tsx | 49 +- .../drizzle/0003_superb_lilandra.sql | 1 + .../frontpage/drizzle/meta/0003_snapshot.json | 853 ++++++++++++++++++ packages/frontpage/drizzle/meta/_journal.json | 7 + packages/frontpage/lib/data/db/report.ts | 40 + packages/frontpage/lib/schema.ts | 4 + 8 files changed, 1015 insertions(+), 88 deletions(-) create mode 100644 packages/frontpage/drizzle/0003_superb_lilandra.sql create mode 100644 packages/frontpage/drizzle/meta/0003_snapshot.json create mode 100644 packages/frontpage/lib/data/db/report.ts diff --git a/packages/frontpage/app/(app)/moderation/actions.tsx b/packages/frontpage/app/(app)/moderation/actions.tsx index 8912df36..6720af9a 100644 --- a/packages/frontpage/app/(app)/moderation/actions.tsx +++ b/packages/frontpage/app/(app)/moderation/actions.tsx @@ -6,14 +6,19 @@ export async function createModerationAction( _prevState: unknown, formData: FormData, ) { + const test = !!formData.get("test"); //create the moderation action and update the report as actioned - return { error: "Not implemented" }; + console.log("Creating moderation action", test); + await new Promise((resolve) => setTimeout(resolve, 1000)); + return { error: "Not implemented", test: test }; } export async function rejectReportAction( _prevState: unknown, formData: FormData, ) { + const test = !!formData.get("test"); //reject the report and update the report as actioned - return { error: "Not implemented" }; + console.log("Rejecting report", test); + return { error: "Not implemented", test: test }; } diff --git a/packages/frontpage/app/(app)/moderation/client.tsx b/packages/frontpage/app/(app)/moderation/client.tsx index f8bb5f62..bd6d768d 100644 --- a/packages/frontpage/app/(app)/moderation/client.tsx +++ b/packages/frontpage/app/(app)/moderation/client.tsx @@ -8,16 +8,18 @@ import { CardTitle, } from "@/lib/components/ui/card"; import { Report } from "./page"; -import { useState } from "react"; +import { useActionState, useState } from "react"; +import { createModerationAction } from "./actions"; export default function ModerationPage({ reports, stats, }: { reports: Report[]; - stats: { total: number; pending: number; approved: number; rejected: number }; + stats: { total: number; pending: number; accepted: number; rejected: number }; }) { const [selectedTab, setSelectedTab] = useState("all"); + const [_, action, isPending] = useActionState(createModerationAction, null); return ( <> @@ -64,17 +66,17 @@ export default function ModerationPage({ setSelectedTab("approved")} + className={`bg-gray-700 border-gray-600 ${selectedTab === "accepted" ? "ring-2 ring-blue-500" : ""}`} + onClick={() => setSelectedTab("accepted")} > - Approved + Accepted
- {stats.approved} + {stats.accepted}
@@ -98,61 +100,87 @@ export default function ModerationPage({ {reports .filter( - (report) => report.status === selectedTab || selectedTab === "all", + (report) => selectedTab === "all" || report.status === selectedTab, ) .map((report) => ( - - - - Reported {report.type} - +
+ + + + {isPending ?? "Report Actions????"} Report Actions + + + +
+
+ Reported By: {report.createdBy} +
+
+ Reported Reason: {report.creatorComment} +
+
+
+ + + ); +} diff --git a/packages/frontpage/app/(app)/moderation/_user-handle.tsx b/packages/frontpage/app/(app)/moderation/_user-handle.tsx new file mode 100644 index 00000000..bcd8a3fb --- /dev/null +++ b/packages/frontpage/app/(app)/moderation/_user-handle.tsx @@ -0,0 +1,13 @@ +import { DID } from "@/lib/data/atproto/did"; +import { getVerifiedHandle } from "@/lib/data/atproto/identity"; +import Link from "next/link"; + +export async function UserHandle({ userDid }: { userDid: DID }) { + const handle = (await getVerifiedHandle(userDid)) ?? userDid; + + return ( + + {handle} + + ); +} diff --git a/packages/frontpage/app/(app)/moderation/actions.tsx b/packages/frontpage/app/(app)/moderation/actions.tsx deleted file mode 100644 index 6720af9a..00000000 --- a/packages/frontpage/app/(app)/moderation/actions.tsx +++ /dev/null @@ -1,24 +0,0 @@ -"use server"; - -//TODO: add actions for creating, updating, deleting moderation reports - -export async function createModerationAction( - _prevState: unknown, - formData: FormData, -) { - const test = !!formData.get("test"); - //create the moderation action and update the report as actioned - console.log("Creating moderation action", test); - await new Promise((resolve) => setTimeout(resolve, 1000)); - return { error: "Not implemented", test: test }; -} - -export async function rejectReportAction( - _prevState: unknown, - formData: FormData, -) { - const test = !!formData.get("test"); - //reject the report and update the report as actioned - console.log("Rejecting report", test); - return { error: "Not implemented", test: test }; -} diff --git a/packages/frontpage/app/(app)/moderation/client.tsx b/packages/frontpage/app/(app)/moderation/client.tsx deleted file mode 100644 index bd6d768d..00000000 --- a/packages/frontpage/app/(app)/moderation/client.tsx +++ /dev/null @@ -1,187 +0,0 @@ -"use client"; -import { ExternalLink, Flag, Shield } from "lucide-react"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/lib/components/ui/card"; -import { Report } from "./page"; -import { useActionState, useState } from "react"; -import { createModerationAction } from "./actions"; - -export default function ModerationPage({ - reports, - stats, -}: { - reports: Report[]; - stats: { total: number; pending: number; accepted: number; rejected: number }; -}) { - const [selectedTab, setSelectedTab] = useState("all"); - const [_, action, isPending] = useActionState(createModerationAction, null); - - return ( - <> - - - - - Moderation Dashboard - - - Review and take action on reported content - - - -
- setSelectedTab("all")} - > - - - Total Reports - - - -
- {stats.total} -
-
-
- setSelectedTab("pending")} - > - - - Pending - - - -
- {stats.pending} -
-
-
- setSelectedTab("accepted")} - > - - - Accepted - - - -
- {stats.accepted} -
-
-
- setSelectedTab("rejected")} - > - - - Rejected - - - -
- {stats.rejected} -
-
-
-
-
-
- {reports - .filter( - (report) => selectedTab === "all" || report.status === selectedTab, - ) - .map((report) => ( - <> -
- - - - {isPending ?? "Report Actions????"} Report Actions - - - -
-
- Reported By: {report.createdBy} -
-
- Reported Reason: {report.creatorComment} -
-
-
- -
-
- - - - Reported Item - - {report.status} - - - - -

{report.creatorComment}

-
-
- DID: {report.subjectDid} -
-
- CID: {report.subjectCid} -
-
- Record Key: {report.subjectRkey} -
- -
-
- - Reason: {report.creatorComment} -
-
-
- - ))} - - ); -} diff --git a/packages/frontpage/app/(app)/moderation/page.tsx b/packages/frontpage/app/(app)/moderation/page.tsx index bdedd20e..65286b88 100644 --- a/packages/frontpage/app/(app)/moderation/page.tsx +++ b/packages/frontpage/app/(app)/moderation/page.tsx @@ -1,99 +1,249 @@ -"use server"; - -import { hasRole } from "@/lib/data/user"; +import { ExternalLink, Flag, Shield } from "lucide-react"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/lib/components/ui/card"; +import { Button } from "@/lib/components/ui/button"; +import { ensureUser, isAdmin as isAdmin } from "@/lib/data/user"; import { redirect } from "next/navigation"; -import ModerationPage from "./client"; +import { + getModeratorReportStats, + getReport, + getReports, + updateReport, +} from "@/lib/data/db/report"; +import { + ModerationEventDTO, + createModerationEvent, +} from "@/lib/data/db/moderation"; +import { PostCollection } from "@/lib/data/atproto/post"; +import { CommentCollection } from "@/lib/data/atproto/comment"; +import { revalidatePath } from "next/cache"; +import Link from "next/link"; +import { getVerifiedHandle } from "@/lib/data/atproto/identity"; +import { UserHandle } from "./_user-handle"; +import { DID } from "@/lib/data/atproto/did"; + +export async function performModerationAction( + input: { reportId: number; status: "accepted" | "rejected" }, + _: FormData, +) { + "use server"; + console.log("creating moderation action"); + console.log("input", input); + const user = await ensureUser(); + const report = await getReport(input.reportId); + + if (!report) { + throw new Error("Report not found"); + } + + const newModEvent: ModerationEventDTO = { + subjectUri: report.subjectUri, + subjectDid: report.subjectDid, + createdBy: user.did, + createdAt: new Date(), + labelsAdded: report.reportReason, + creatorReportReason: report.creatorComment, + }; + + if (report.subjectCollection) { + if (report.subjectCollection === PostCollection) { + newModEvent.subjectCollection = PostCollection; + } else if (report.subjectCollection === CommentCollection) { + newModEvent.subjectCollection = CommentCollection; + } + + newModEvent.subjectRkey = report.subjectRkey; + newModEvent.subjectCid = report.subjectCid; + } + + await Promise.all([ + createModerationEvent(newModEvent), + updateReport(report.id, input.status, user.did), + ]); + + revalidatePath("/moderation"); + return; +} -export type Report = { - id: number; - actionedAt?: Date; - actionedBy?: string; - subjectUri: string; - subjectDid: string; - subjectCollection?: string; - subjectRkey?: string; - subjectCid?: string; - createdBy: string; - createdAt: Date; - creatorComment?: string; - reportReason?: string; - status: "pending" | "accepted" | "rejected"; -}; +export default async function Moderation({ + searchParams, +}: { + searchParams: { status: string }; +}) { + const status = + (searchParams.status as "pending" | "accepted" | "rejected") ?? null; -const reports: Report[] = [ - { - id: 1, - actionedAt: new Date("2023-10-01T12:00:00Z"), - actionedBy: "moderator1", - subjectUri: "uri1", - subjectDid: "did1", - subjectCollection: "collection1", - subjectRkey: "rkey1", - subjectCid: "cid1", - createdBy: "user1", - createdAt: new Date("2023-09-30T12:00:00Z"), - creatorComment: "This is a comment by the creator.", - status: "accepted", - }, - { - id: 2, - actionedAt: new Date("2023-10-02T12:00:00Z"), - actionedBy: "moderator2", - subjectUri: "uri2", - subjectDid: "did2", - subjectCollection: "collection2", - subjectRkey: "rkey2", - subjectCid: "cid2", - createdBy: "user2", - createdAt: new Date("2023-09-29T12:00:00Z"), - creatorComment: "This is another comment by the creator.", - status: "rejected", - }, - { - id: 3, - subjectUri: "uri3", - subjectDid: "did3", - createdBy: "user3", - createdAt: new Date("2023-09-28T12:00:00Z"), - status: "pending", - }, - { - id: 4, - subjectUri: "uri4", - subjectDid: "did4", - subjectCollection: "collection4", - createdBy: "user4", - createdAt: new Date("2023-09-27T12:00:00Z"), - creatorComment: "Yet another comment by the creator.", - status: "pending", - }, - { - id: 5, - subjectUri: "uri5", - subjectDid: "did5", - subjectRkey: "rkey5", - createdBy: "user5", - createdAt: new Date("2023-09-26T12:00:00Z"), - status: "pending", - }, -]; + const reports = await getReports(status).then((reports) => + reports.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()), + ); -const stats = { - total: reports.length, - pending: reports.filter((r) => r.status === "pending").length, - accepted: reports.filter((r) => r.status === "accepted").length, - rejected: reports.filter((r) => r.status === "rejected").length, -}; + const stats = await getModeratorReportStats(); + // const stats = { + // total: reports.length, + // pending: reports.filter((r) => r.status === "pending").length, + // accepted: reports.filter((r) => r.status === "accepted").length, + // rejected: reports.filter((r) => r.status === "rejected").length, + // }; -export default async function Moderation() { - //TODO: get moderation reports, get moderator's stats etc. - if (await hasRole("moderator")) { - // const [reports, stats] = await Promise.all([ - // await getReports(), - // await getStats(did), - // ]); + if (await isAdmin()) { + return ( + <> + + + + + Moderation Dashboard + + + Review and take action on reported content + + + +
+ + + + + Total Reports + + + +
+ {stats.total} +
+
+
+ + + + + + Pending + + + +
+ {stats.pending} +
+
+
+ + + + + + Accepted + + + +
+ {stats.accepted} +
+
+
+ - return ; + + + + + Rejected + + + +
+ {stats.rejected} +
+
+
+ +
+
+
+ {reports.map((report) => ( + + + + Reported Item + + {report.status} + + + + + +
+ + Reason: {report.creatorComment} +
+
+
+ Reported By: + +
+
+ Reported Reason: {report.creatorComment} +
+
+
+ + +
+
+
+ ))} + + ); } else { redirect("/"); } diff --git a/packages/frontpage/app/globals.css b/packages/frontpage/app/globals.css index a56bc16d..9abc86b3 100644 --- a/packages/frontpage/app/globals.css +++ b/packages/frontpage/app/globals.css @@ -28,6 +28,9 @@ --destructive: 0 84.2% 60.2%; --destructive-foreground: 210 40% 98%; + --success: 142 71% 45%; + --success-foreground: 210 40% 98%; + --border: 214.3 31.8% 91.4%; --input: 214.3 31.8% 91.4%; --ring: 222.2 84% 4.9%; @@ -79,6 +82,9 @@ --destructive: 0 62.8% 30.6%; --destructive-foreground: 210 40% 98%; + --success: 142 40% 25%; + --success-foreground: 210 40% 98%; + --border: 217.2 32.6% 17.5%; --input: 217.2 32.6% 17.5%; --ring: 215.4 16.3% 46.9%; diff --git a/packages/frontpage/drizzle/0004_jittery_random.sql b/packages/frontpage/drizzle/0004_jittery_random.sql new file mode 100644 index 00000000..8b3edc88 --- /dev/null +++ b/packages/frontpage/drizzle/0004_jittery_random.sql @@ -0,0 +1,7 @@ +CREATE TABLE `admin_users` ( + `id` integer PRIMARY KEY NOT NULL, + `created_at` text NOT NULL, + `did` text NOT NULL +); +--> statement-breakpoint +CREATE UNIQUE INDEX `admin_users_did_unique` ON `admin_users` (`did`); \ No newline at end of file diff --git a/packages/frontpage/drizzle/meta/0004_snapshot.json b/packages/frontpage/drizzle/meta/0004_snapshot.json new file mode 100644 index 00000000..a726bee7 --- /dev/null +++ b/packages/frontpage/drizzle/meta/0004_snapshot.json @@ -0,0 +1,891 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "4b487ed2-7950-4a44-b051-057460b6f589", + "prevId": "568f232e-f6bf-4e4d-b3da-c7dc1fae9cc0", + "tables": { + "admin_users": { + "name": "admin_users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "did": { + "name": "did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "admin_users_did_unique": { + "name": "admin_users_did_unique", + "columns": [ + "did" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "beta_users": { + "name": "beta_users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "did": { + "name": "did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "beta_users_did_unique": { + "name": "beta_users_did_unique", + "columns": [ + "did" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "comments": { + "name": "comments", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "rkey": { + "name": "rkey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cid": { + "name": "cid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "post_id": { + "name": "post_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "body": { + "name": "body", + "type": "text(10000)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "author_did": { + "name": "author_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'live'" + }, + "parent_comment_id": { + "name": "parent_comment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "comments_cid_unique": { + "name": "comments_cid_unique", + "columns": [ + "cid" + ], + "isUnique": true + }, + "comments_author_did_rkey_unique": { + "name": "comments_author_did_rkey_unique", + "columns": [ + "author_did", + "rkey" + ], + "isUnique": true + } + }, + "foreignKeys": { + "comments_post_id_posts_id_fk": { + "name": "comments_post_id_posts_id_fk", + "tableFrom": "comments", + "tableTo": "posts", + "columnsFrom": [ + "post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "parent_comment_id_fkey": { + "name": "parent_comment_id_fkey", + "tableFrom": "comments", + "tableTo": "comments", + "columnsFrom": [ + "parent_comment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "comment_votes": { + "name": "comment_votes", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "comment_id": { + "name": "comment_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "author_did": { + "name": "author_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cid": { + "name": "cid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rkey": { + "name": "rkey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "comment_votes_cid_unique": { + "name": "comment_votes_cid_unique", + "columns": [ + "cid" + ], + "isUnique": true + }, + "comment_votes_author_did_rkey_unique": { + "name": "comment_votes_author_did_rkey_unique", + "columns": [ + "author_did", + "rkey" + ], + "isUnique": true + }, + "comment_votes_author_did_comment_id_unique": { + "name": "comment_votes_author_did_comment_id_unique", + "columns": [ + "author_did", + "comment_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "comment_votes_comment_id_comments_id_fk": { + "name": "comment_votes_comment_id_comments_id_fk", + "tableFrom": "comment_votes", + "tableTo": "comments", + "columnsFrom": [ + "comment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "consumed_offsets": { + "name": "consumed_offsets", + "columns": { + "offset": { + "name": "offset", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "labelled_profiles": { + "name": "labelled_profiles", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "did": { + "name": "did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_hidden": { + "name": "is_hidden", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "labels": { + "name": "labels", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "labelled_profiles_did_unique": { + "name": "labelled_profiles_did_unique", + "columns": [ + "did" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "moderation_events": { + "name": "moderation_events", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "subject_uri": { + "name": "subject_uri", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_did": { + "name": "subject_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_collection": { + "name": "subject_collection", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_rkey": { + "name": "subject_rkey", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_cid": { + "name": "subject_cid", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "labels_added": { + "name": "labels_added", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "labels_removed": { + "name": "labels_removed", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "report_type": { + "name": "report_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "oauth_auth_requests": { + "name": "oauth_auth_requests", + "columns": { + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "iss": { + "name": "iss", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "did": { + "name": "did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nonce": { + "name": "nonce", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "pkce_verifier": { + "name": "pkce_verifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dpop_private_jwk": { + "name": "dpop_private_jwk", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dpop_public_jwk": { + "name": "dpop_public_jwk", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "oauth_auth_requests_state_unique": { + "name": "oauth_auth_requests_state_unique", + "columns": [ + "state" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "oauth_sessions": { + "name": "oauth_sessions", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "did": { + "name": "did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "iss": { + "name": "iss", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dpop_nonce": { + "name": "dpop_nonce", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dpop_private_jwk": { + "name": "dpop_private_jwk", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dpop_public_jwk": { + "name": "dpop_public_jwk", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "posts": { + "name": "posts", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "rkey": { + "name": "rkey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cid": { + "name": "cid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text(300)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "author_did": { + "name": "author_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'live'" + } + }, + "indexes": { + "posts_cid_unique": { + "name": "posts_cid_unique", + "columns": [ + "cid" + ], + "isUnique": true + }, + "posts_author_did_rkey_unique": { + "name": "posts_author_did_rkey_unique", + "columns": [ + "author_did", + "rkey" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "post_votes": { + "name": "post_votes", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "post_id": { + "name": "post_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "author_did": { + "name": "author_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cid": { + "name": "cid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rkey": { + "name": "rkey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "post_votes_cid_unique": { + "name": "post_votes_cid_unique", + "columns": [ + "cid" + ], + "isUnique": true + }, + "post_votes_author_did_rkey_unique": { + "name": "post_votes_author_did_rkey_unique", + "columns": [ + "author_did", + "rkey" + ], + "isUnique": true + }, + "post_votes_author_did_post_id_unique": { + "name": "post_votes_author_did_post_id_unique", + "columns": [ + "author_did", + "post_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "post_votes_post_id_posts_id_fk": { + "name": "post_votes_post_id_posts_id_fk", + "tableFrom": "post_votes", + "tableTo": "posts", + "columnsFrom": [ + "post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "reports": { + "name": "reports", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "actioned_at": { + "name": "actioned_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actioned_by": { + "name": "actioned_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_uri": { + "name": "subject_uri", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_did": { + "name": "subject_did", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_collection": { + "name": "subject_collection", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_rkey": { + "name": "subject_rkey", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subject_cid": { + "name": "subject_cid", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_comment": { + "name": "creator_comment", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "report_reason": { + "name": "report_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'pending'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/packages/frontpage/drizzle/meta/_journal.json b/packages/frontpage/drizzle/meta/_journal.json index b9910832..755e7859 100644 --- a/packages/frontpage/drizzle/meta/_journal.json +++ b/packages/frontpage/drizzle/meta/_journal.json @@ -29,6 +29,13 @@ "when": 1727320432120, "tag": "0003_superb_lilandra", "breakpoints": true + }, + { + "idx": 4, + "version": "6", + "when": 1727472551203, + "tag": "0004_jittery_random", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/frontpage/lib/components/ui/button.tsx b/packages/frontpage/lib/components/ui/button.tsx index 041e7fd3..280d2f57 100644 --- a/packages/frontpage/lib/components/ui/button.tsx +++ b/packages/frontpage/lib/components/ui/button.tsx @@ -11,6 +11,8 @@ const buttonVariants = cva( variant: { default: "bg-primary text-primary-foreground shadow hover:bg-primary/90 dark:bg-slate-200 dark:hover:bg-slate-100", + success: + "bg-success text-success-foreground shadow-sm hover:bg-success/90", destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", outline: diff --git a/packages/frontpage/lib/data/db/moderation.ts b/packages/frontpage/lib/data/db/moderation.ts new file mode 100644 index 00000000..3695478f --- /dev/null +++ b/packages/frontpage/lib/data/db/moderation.ts @@ -0,0 +1,22 @@ +import { db } from "@/lib/db"; +import "server-only"; +import * as schema from "@/lib/schema"; + +export type ModerationEventDTO = { + subjectUri: string; + subjectDid: string; + subjectCollection?: string | null; + subjectRkey?: string | null; + subjectCid?: string | null; + createdBy: string; + createdAt: Date; + labelsAdded?: string | null; + labelsRemoved?: string | null; + creatorReportReason?: string | null; +}; + +export async function createModerationEvent( + moderationEvent: ModerationEventDTO, +) { + await db.insert(schema.ModerationEvent).values(moderationEvent); +} diff --git a/packages/frontpage/lib/data/db/post.ts b/packages/frontpage/lib/data/db/post.ts index ae62e095..531ab572 100644 --- a/packages/frontpage/lib/data/db/post.ts +++ b/packages/frontpage/lib/data/db/post.ts @@ -249,3 +249,5 @@ export async function unauthed_deletePost({ rkey, offset }: DeletePostInput) { }); console.log("Done deleting post transaction"); } + +export async function moderatePost(cid: string) {} diff --git a/packages/frontpage/lib/data/db/report.ts b/packages/frontpage/lib/data/db/report.ts index b22bbcc8..ab8b0db0 100644 --- a/packages/frontpage/lib/data/db/report.ts +++ b/packages/frontpage/lib/data/db/report.ts @@ -2,17 +2,74 @@ import "server-only"; import { db } from "@/lib/db"; import * as schema from "@/lib/schema"; import { cache } from "react"; -import { InferSelectModel } from "drizzle-orm"; +import { InferSelectModel, eq } from "drizzle-orm"; -export const getReports = cache(async () => { +export type ReportDTO = { + actionedAt?: Date | null; + actionedBy?: string | null; + subjectUri: string; + subjectDid: string; + subjectCollection?: string | null; + subjectRkey?: string | null; + subjectCid?: string | null; + createdBy: string; + createdAt: Date; + creatorComment?: string | null; + reportReason?: string | null; + status?: "pending" | "accepted" | "rejected" | null; +}; + +export type Report = InferSelectModel; + +export const getReport = cache( + async (reportId: number): Promise => { + const [report] = await db + .select() + .from(schema.Report) + .where(eq(schema.Report.id, reportId)); + + return report ?? null; + }, +); + +export const getModeratorReportStats = async () => { const reports = await db.select().from(schema.Report); - return reports; -}); + return { + total: reports.length, + pending: reports.filter((r) => r.status === "pending").length, + accepted: reports.filter((r) => r.status === "accepted").length, + rejected: reports.filter((r) => r.status === "rejected").length, + }; +}; + +export const getReports = async ( + status: "pending" | "accepted" | "rejected" | null, +): Promise => { + if (status) { + return await db + .select() + .from(schema.Report) + .where(eq(schema.Report.status, status)); + } else { + return await db.select().from(schema.Report); + } +}; -type ReportInfer = InferSelectModel; +export const updateReport = async ( + reportId: number, + status: "pending" | "accepted" | "rejected", + actionedBy?: string, +) => { + await db + .update(schema.Report) + .set({ status, actionedBy, actionedAt: new Date() }) + .where(eq(schema.Report.id, reportId)); + + return; +}; -export const createReport = async (report: ReportInfer) => { +export const createReport = async (report: ReportDTO) => { await db.insert(schema.Report).values(report); // await sendDiscordMessage({ diff --git a/packages/frontpage/lib/data/user.ts b/packages/frontpage/lib/data/user.ts index d6664d77..f58b3233 100644 --- a/packages/frontpage/lib/data/user.ts +++ b/packages/frontpage/lib/data/user.ts @@ -64,18 +64,17 @@ export const isBetaUser = cache(async () => { ); }); -export const hasRole = cache(async (role: string) => { +export const isAdmin = cache(async () => { const user = await getUser(); if (!user) { return false; } - return Boolean( - role === "moderator", - // await db.query.User.findFirst({ - // where: and(eq(schema.User.did, user.did), eq(schema.User.role, role)), - // }), - ); + const isAdmin = await db.query.AdminUser.findFirst({ + where: and(eq(schema.AdminUser.did, user.did)), + }); + + return isAdmin; }); const ProfileResponse = z.object({ diff --git a/packages/frontpage/lib/schema.ts b/packages/frontpage/lib/schema.ts index a27a2681..f6c810d4 100644 --- a/packages/frontpage/lib/schema.ts +++ b/packages/frontpage/lib/schema.ts @@ -124,6 +124,12 @@ export const BetaUser = sqliteTable("beta_users", { did: did("did").notNull().unique(), }); +export const AdminUser = sqliteTable("admin_users", { + id: integer("id").primaryKey(), + createdAt: dateIsoText("created_at").notNull(), + did: did("did").notNull().unique(), +}); + export const ConsumedOffset = sqliteTable("consumed_offsets", { offset: integer("offset").primaryKey(), }); diff --git a/packages/frontpage/tailwind.config.ts b/packages/frontpage/tailwind.config.ts index 3c38bb32..f1d39754 100644 --- a/packages/frontpage/tailwind.config.ts +++ b/packages/frontpage/tailwind.config.ts @@ -37,6 +37,10 @@ const config = { DEFAULT: "hsl(var(--destructive))", foreground: "hsl(var(--destructive-foreground))", }, + success: { + DEFAULT: "hsl(var(--success))", + foreground: "hsl(var(--success-foreground))", + }, muted: { DEFAULT: "hsl(var(--muted))", foreground: "hsl(var(--muted-foreground))", From 281276d7a13b2d045875c1ecf6c54611bda57d09 Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Sat, 28 Sep 2024 01:01:31 +0100 Subject: [PATCH 14/43] update packages --- packages/frontpage/package.json | 1 + pnpm-lock.yaml | 614 ++++++++++++++++---------------- 2 files changed, 308 insertions(+), 307 deletions(-) diff --git a/packages/frontpage/package.json b/packages/frontpage/package.json index f6e74854..26136050 100644 --- a/packages/frontpage/package.json +++ b/packages/frontpage/package.json @@ -37,6 +37,7 @@ "date-fns": "^3.6.0", "drizzle-orm": "^0.33.0", "jose": "^5.4.0", + "lucide-react": "^0.441.0", "next": "15.0.0-canary.168", "next-themes": "^0.3.0", "oauth4webapi": "^2.12.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aa5f7fa3..2dfaec7f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -67,10 +67,10 @@ importers: specifier: ^20 version: 20.13.0 '@types/react': - specifier: ^18 - version: 18.3.3 + specifier: ^18.3.10 + version: 18.3.10 '@types/react-dom': - specifier: ^18 + specifier: ^18.3.0 version: 18.3.0 eslint: specifier: ^8 @@ -125,46 +125,46 @@ importers: version: 14.2.4 '@radix-ui/react-alert-dialog': specifier: ^1.1.1 - version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) '@radix-ui/react-avatar': specifier: ^1.1.0 - version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) '@radix-ui/react-dropdown-menu': specifier: ^2.1.1 - version: 2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + version: 2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) '@radix-ui/react-hover-card': specifier: ^1.1.1 - version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) '@radix-ui/react-icons': specifier: ^1.3.0 version: 1.3.0(react@19.0.0-rc-f994737d14-20240522) '@radix-ui/react-label': specifier: ^2.1.0 - version: 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + version: 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) '@radix-ui/react-popover': specifier: ^1.1.1 - version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) '@radix-ui/react-scroll-area': specifier: ^1.1.0 - version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) '@radix-ui/react-slot': specifier: ^1.1.0 - version: 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + version: 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) '@radix-ui/react-tabs': specifier: ^1.1.0 - version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) '@radix-ui/react-toast': specifier: ^1.2.1 - version: 1.2.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + version: 1.2.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) '@radix-ui/react-tooltip': specifier: ^1.1.1 - version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) '@vercel/analytics': specifier: ^1.3.1 - version: 1.3.1(next@15.0.0-canary.167(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + version: 1.3.1(next@15.0.0-canary.168(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) '@vercel/speed-insights': specifier: ^1.0.12 - version: 1.0.12(next@15.0.0-canary.167(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + version: 1.0.12(next@15.0.0-canary.168(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) class-variance-authority: specifier: ^0.7.0 version: 0.7.0 @@ -176,7 +176,7 @@ importers: version: 3.6.0 drizzle-orm: specifier: ^0.33.0 - version: 0.33.0(@libsql/client@0.9.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.7.2)(@types/better-sqlite3@7.6.10)(@types/pg@8.6.6)(@types/react@18.3.3)(@vercel/postgres@0.8.0)(better-sqlite3@11.0.0)(kysely@0.22.0)(react@19.0.0-rc-f994737d14-20240522) + version: 0.33.0(@libsql/client@0.9.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.7.2)(@types/better-sqlite3@7.6.10)(@types/pg@8.6.6)(@types/react@18.3.10)(@vercel/postgres@0.8.0)(better-sqlite3@11.0.0)(kysely@0.22.0)(react@19.0.0-rc-f994737d14-20240522) jose: specifier: ^5.4.0 version: 5.4.0 @@ -184,8 +184,8 @@ importers: specifier: ^0.441.0 version: 0.441.0(react@19.0.0-rc-f994737d14-20240522) next: - specifier: 15.0.0-canary.167 - version: 15.0.0-canary.167(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + specifier: 15.0.0-canary.168 + version: 15.0.0-canary.168(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) next-themes: specifier: ^0.3.0 version: 0.3.0(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) @@ -222,15 +222,15 @@ importers: version: link:../typescript-config '@testing-library/react': specifier: ^16.0.0 - version: 16.0.0(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + version: 16.0.0(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) '@types/node': specifier: ^20 version: 20.13.0 '@types/react': - specifier: ^18 - version: 18.3.3 + specifier: ^18.3.10 + version: 18.3.10 '@types/react-dom': - specifier: ^18 + specifier: ^18.3.0 version: 18.3.0 '@vitejs/plugin-react': specifier: ^4.3.1 @@ -284,7 +284,7 @@ importers: dependencies: '@markdoc/markdoc': specifier: ^0.4.0 - version: 0.4.0(@types/react@18.3.3)(react@19.0.0-rc-3563387fe3-20240621) + version: 0.4.0(@types/react@18.3.10)(react@19.0.0-rc-3563387fe3-20240621) clsx: specifier: ^2.1.1 version: 2.1.1 @@ -323,8 +323,8 @@ importers: specifier: ^20 version: 20.13.0 '@types/react': - specifier: ^18.3.3 - version: 18.3.3 + specifier: ^18.3.10 + version: 18.3.10 '@types/react-dom': specifier: ^18.3.0 version: 18.3.0 @@ -1613,8 +1613,8 @@ packages: '@next/env@14.2.4': resolution: {integrity: sha512-3EtkY5VDkuV2+lNmKlbkibIJxcO4oIHEhBWne6PaAp+76J9KoSsGvNikp6ivzAT8dhhBMYrm6op2pS1ApG0Hzg==} - '@next/env@15.0.0-canary.167': - resolution: {integrity: sha512-0navqyyiycRAb3l6BmvXpb5AsTCp9mFwGoQhCaCK5RM/eUJKY0loApQKlh2iOfhUXJOZgbBQj0N4UaHo5+jbHA==} + '@next/env@15.0.0-canary.168': + resolution: {integrity: sha512-I9i6y7OxNO9FXbLZi0aOPpf9czuhgbSqvANIIMkZtzc/oidfvaR5ZovZQP4AtL6VBpHXa5AVzcBODyDpbx4MVw==} '@next/env@15.0.0-rc.0': resolution: {integrity: sha512-6W0ndQvHR9sXcqcKeR/inD2UTRCs9+VkSK3lfaGmEuZs7EjwwXMO2BPYjz9oBrtfPL3xuTjtXsHKSsalYQ5l1Q==} @@ -1625,8 +1625,8 @@ packages: '@next/eslint-plugin-next@15.0.0-rc.0': resolution: {integrity: sha512-/rQXrN47qxlFHtZg77LdcCYbL54ogQuLeqIGV/6HMGnZH8iL81XEFOITO8GZjOukR5i3BbwyfrsmIqFl/scg+w==} - '@next/swc-darwin-arm64@15.0.0-canary.167': - resolution: {integrity: sha512-LTEM9VY036HWlNVaq6VMAwkkPvd62g6bXuxX9PjiVvzdCBba+WVjP6XL7kXOLnKV6auXY7+lBAzNgV2gi+IeYA==} + '@next/swc-darwin-arm64@15.0.0-canary.168': + resolution: {integrity: sha512-7nT2Xs5LymGANojseGti6l9n0ZRMCijzRkZcJeKEVoQ//JJZ/wcP4JrLiwqVzPVXW6MuoXPbSEbt5TNRE9BcoA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -1637,8 +1637,8 @@ packages: cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.0.0-canary.167': - resolution: {integrity: sha512-VuePFs/JJtO+mlBiWRBL62piZ13uEtEhjyhk2scMy0g/d7AnxXbbk9XtX9hLPlcr3IJM+UZE2bS/69PS9s3qjQ==} + '@next/swc-darwin-x64@15.0.0-canary.168': + resolution: {integrity: sha512-PE3l7TqBYSIbYs8JXYABip4ZRKYmWfJo8cySThqKPM3WkJTtTEb6t+IaPGCHK0Iu0f8zAs0UaMaNNf+qMvYBgA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -1649,8 +1649,8 @@ packages: cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.0.0-canary.167': - resolution: {integrity: sha512-+iHcycCrdQCNkFVPiSGwdgpr/fx4bwGCSG1HuMphsTtCcxKUyE6fJ5rZYGfiPYI8tynnwXkwJAcS1Gh3HEyFLw==} + '@next/swc-linux-arm64-gnu@15.0.0-canary.168': + resolution: {integrity: sha512-bJNCmJSerl1v2iVsJSlv427c3RyKj5z4rYyOGCH2WiUGc6GvhDXh06sG8zmAzKrr6vLNaVwIbZsdlwJxroTOug==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -1661,8 +1661,8 @@ packages: cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.0.0-canary.167': - resolution: {integrity: sha512-DOOMODRtDlm4FX35ag5N5akr89IE2MQvFBHEeoeI0FWJmUtGJ4DMXzGSlnv1XwKBiREPgzA9MFfBeDccPymYLw==} + '@next/swc-linux-arm64-musl@15.0.0-canary.168': + resolution: {integrity: sha512-PqRH1Dk/1Z5RfOO4ewoHnhoZH/nShR48NyhIngmfSrmzBeR/fqM12a5fAP0VgBLpwGozZ/1RPfGgL5QhQH6gPg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -1673,8 +1673,8 @@ packages: cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.0.0-canary.167': - resolution: {integrity: sha512-kOe1pilqNeHR9+5CJKeIM0C5eWw4OSqfSuMYpW/9cjVnvjVmCttchazo8rv1e0oEXvDhn0HB9sgj76d73pMU/g==} + '@next/swc-linux-x64-gnu@15.0.0-canary.168': + resolution: {integrity: sha512-RSfGiiqWgRzxH5pV0u7f+Vr2g0t8y7s/tcdSFj0GoAeDAc79PfQq5Wyyd/qbSfGqcxE8gBfZkRvtEDRShSBykQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -1685,8 +1685,8 @@ packages: cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.0.0-canary.167': - resolution: {integrity: sha512-SQVYb/WD/VxyVZT06YyBhod/ukh1UQMKO30s/vRVkjX+/nyxJdz6K8EAHsdCYbjMnX0On8vbFw2TVAqfFOVNqQ==} + '@next/swc-linux-x64-musl@15.0.0-canary.168': + resolution: {integrity: sha512-bgITMce1qBBuqspeBOf4f88ln04yK/AJ6cEVZOMFxH4wAfpGGPbMbBTfC7aUqBdX3ktyF+YSs2D137rr0b23kA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -1697,8 +1697,8 @@ packages: cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.0.0-canary.167': - resolution: {integrity: sha512-5F9yMwmpfKdAOBmQarpVvuWTau3Dk/v9s2VfELK3tGeThRpHb4JOpksClw5C7RDYAxWwcqK4EoFeciIT1iIc9A==} + '@next/swc-win32-arm64-msvc@15.0.0-canary.168': + resolution: {integrity: sha512-xooyrTjrJokmDIXqwQGC8p9sJFWeV0ALwWSefdiHAoeLEG4V8Wpui4rw5OctMhBbnjg3SPXSM0iMJn2WGdaTJw==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -1709,8 +1709,8 @@ packages: cpu: [arm64] os: [win32] - '@next/swc-win32-ia32-msvc@15.0.0-canary.167': - resolution: {integrity: sha512-8tRWrbpPyzHdSjQFFNzAHpWuyU5n5DvvNxWd61hFqxZRJZIwnlUjwgvVpobOZLoWtab0DZK1tEvOuzQX5mOLgw==} + '@next/swc-win32-ia32-msvc@15.0.0-canary.168': + resolution: {integrity: sha512-hcqPQORa0d3v/7lQpbhGMI52iCPG03j6/RFq1kjj6pq4jvnZC1F2/npU0v2OQ6C6z/IG+MqgYCuedaPVvoGi8g==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -1721,8 +1721,8 @@ packages: cpu: [ia32] os: [win32] - '@next/swc-win32-x64-msvc@15.0.0-canary.167': - resolution: {integrity: sha512-xGkJ0shYzUbSBENSoyXd6a3yFvIaf4x4ro+X56ORHjkaTODFQk9uia6D40PGyGBmSGmJtdXNKYPG2T9DKaQcnQ==} + '@next/swc-win32-x64-msvc@15.0.0-canary.168': + resolution: {integrity: sha512-ZPojtdhs2bNdQhlG2O+IRdzQ3jJvdkpYGAfqet2gzOYjVT+qPBLwGtKNqsaaqga0Z9FFfFwnklb8OrwU7TQOXA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -2545,8 +2545,8 @@ packages: '@types/react-dom@18.3.0': resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} - '@types/react@18.3.3': - resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} + '@types/react@18.3.10': + resolution: {integrity: sha512-02sAAlBnP39JgXwkAq3PeU9DVaaGpZyF3MGcC0MKgQVkZor5IiiDAipVaxQHtDJAmO4GIy/rVBy/LzVj76Cyqg==} '@types/semver@7.5.8': resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} @@ -4580,8 +4580,8 @@ packages: react: ^16.8 || ^17 || ^18 react-dom: ^16.8 || ^17 || ^18 - next@15.0.0-canary.167: - resolution: {integrity: sha512-IifSWU8gNQ8kTXRf2QnEGvUUpnkZk8WKLKWX6rypnEDDmn38sXaWpemjMUIM98UrT/y9sXBIiBA84X2MvignIA==} + next@15.0.0-canary.168: + resolution: {integrity: sha512-iiKSwHyyJ/LRe5ZcSt6KOPxjmoH7+NPM/zknLsa180vKT3URVJw9rKwR5z9mb/+/b4CqAYLQqpG/CTptv7/m3w==} engines: {node: '>=18.18.0'} hasBin: true peerDependencies: @@ -7648,10 +7648,10 @@ snapshots: '@libsql/win32-x64-msvc@0.4.1': optional: true - '@markdoc/markdoc@0.4.0(@types/react@18.3.3)(react@19.0.0-rc-3563387fe3-20240621)': + '@markdoc/markdoc@0.4.0(@types/react@18.3.10)(react@19.0.0-rc-3563387fe3-20240621)': optionalDependencies: '@types/markdown-it': 12.2.3 - '@types/react': 18.3.3 + '@types/react': 18.3.10 react: 19.0.0-rc-3563387fe3-20240621 '@microsoft/tsdoc-config@0.16.2': @@ -7672,7 +7672,7 @@ snapshots: '@next/env@14.2.4': {} - '@next/env@15.0.0-canary.167': {} + '@next/env@15.0.0-canary.168': {} '@next/env@15.0.0-rc.0': {} @@ -7684,55 +7684,55 @@ snapshots: dependencies: glob: 10.3.10 - '@next/swc-darwin-arm64@15.0.0-canary.167': + '@next/swc-darwin-arm64@15.0.0-canary.168': optional: true '@next/swc-darwin-arm64@15.0.0-rc.0': optional: true - '@next/swc-darwin-x64@15.0.0-canary.167': + '@next/swc-darwin-x64@15.0.0-canary.168': optional: true '@next/swc-darwin-x64@15.0.0-rc.0': optional: true - '@next/swc-linux-arm64-gnu@15.0.0-canary.167': + '@next/swc-linux-arm64-gnu@15.0.0-canary.168': optional: true '@next/swc-linux-arm64-gnu@15.0.0-rc.0': optional: true - '@next/swc-linux-arm64-musl@15.0.0-canary.167': + '@next/swc-linux-arm64-musl@15.0.0-canary.168': optional: true '@next/swc-linux-arm64-musl@15.0.0-rc.0': optional: true - '@next/swc-linux-x64-gnu@15.0.0-canary.167': + '@next/swc-linux-x64-gnu@15.0.0-canary.168': optional: true '@next/swc-linux-x64-gnu@15.0.0-rc.0': optional: true - '@next/swc-linux-x64-musl@15.0.0-canary.167': + '@next/swc-linux-x64-musl@15.0.0-canary.168': optional: true '@next/swc-linux-x64-musl@15.0.0-rc.0': optional: true - '@next/swc-win32-arm64-msvc@15.0.0-canary.167': + '@next/swc-win32-arm64-msvc@15.0.0-canary.168': optional: true '@next/swc-win32-arm64-msvc@15.0.0-rc.0': optional: true - '@next/swc-win32-ia32-msvc@15.0.0-canary.167': + '@next/swc-win32-ia32-msvc@15.0.0-canary.168': optional: true '@next/swc-win32-ia32-msvc@15.0.0-rc.0': optional: true - '@next/swc-win32-x64-msvc@15.0.0-canary.167': + '@next/swc-win32-x64-msvc@15.0.0-canary.168': optional: true '@next/swc-win32-x64-msvc@15.0.0-rc.0': @@ -7771,415 +7771,415 @@ snapshots: '@radix-ui/primitive@1.1.0': {} - '@radix-ui/react-alert-dialog@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-alert-dialog@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-dialog': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-dialog': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-arrow@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-arrow@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-avatar@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-avatar@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: - '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-collection@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-collection@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-compose-refs@1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-compose-refs@1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522)': dependencies: react: 19.0.0-rc-f994737d14-20240522 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - '@radix-ui/react-context@1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-context@1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522)': dependencies: react: 19.0.0-rc-f994737d14-20240522 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - '@radix-ui/react-dialog@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-dialog@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) aria-hidden: 1.2.4 react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) - react-remove-scroll: 2.5.7(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + react-remove-scroll: 2.5.7(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-direction@1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-direction@1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522)': dependencies: react: 19.0.0-rc-f994737d14-20240522 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - '@radix-ui/react-dismissable-layer@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-dismissable-layer@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-dropdown-menu@2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-dropdown-menu@2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-menu': 2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-menu': 2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-focus-guards@1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-focus-guards@1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522)': dependencies: react: 19.0.0-rc-f994737d14-20240522 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - '@radix-ui/react-focus-scope@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-focus-scope@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-hover-card@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-hover-card@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 '@radix-ui/react-icons@1.3.0(react@19.0.0-rc-f994737d14-20240522)': dependencies: react: 19.0.0-rc-f994737d14-20240522 - '@radix-ui/react-id@1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-id@1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - '@radix-ui/react-label@2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-label@2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-menu@2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-menu@2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-direction': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) aria-hidden: 1.2.4 react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) - react-remove-scroll: 2.5.7(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + react-remove-scroll: 2.5.7(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-popover@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-popover@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) aria-hidden: 1.2.4 react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) - react-remove-scroll: 2.5.7(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + react-remove-scroll: 2.5.7(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-popper@1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-popper@1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@floating-ui/react-dom': 2.1.0(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-arrow': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-rect': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-arrow': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-rect': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) '@radix-ui/rect': 1.1.0 react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-portal@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-portal@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-presence@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-presence@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-primitive@2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-primitive@2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-roving-focus@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-roving-focus@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-direction': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-scroll-area@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-scroll-area@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@radix-ui/number': 1.1.0 '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-direction': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-slot@1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-slot@1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522)': dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - '@radix-ui/react-tabs@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-tabs@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-direction': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-toast@1.2.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-toast@1.2.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-tooltip@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-tooltip@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-id': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-slot': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 - '@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522)': dependencies: react: 19.0.0-rc-f994737d14-20240522 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - '@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - '@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522)': dependencies: react: 19.0.0-rc-f994737d14-20240522 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - '@radix-ui/react-use-rect@1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-use-rect@1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@radix-ui/rect': 1.1.0 react: 19.0.0-rc-f994737d14-20240522 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - '@radix-ui/react-use-size@1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-use-size@1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - '@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 '@radix-ui/rect@1.1.0': {} @@ -8569,14 +8569,14 @@ snapshots: lz-string: 1.5.0 pretty-format: 27.5.1 - '@testing-library/react@16.0.0(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@testing-library/react@16.0.0(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@babel/runtime': 7.24.6 '@testing-library/dom': 10.4.0 react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@types/react-dom': 18.3.0 '@tokenizer/token@0.3.0': {} @@ -8663,9 +8663,9 @@ snapshots: '@types/react-dom@18.3.0': dependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - '@types/react@18.3.3': + '@types/react@18.3.10': dependencies: '@types/prop-types': 15.7.12 csstype: 3.1.3 @@ -8874,11 +8874,11 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vercel/analytics@1.3.1(next@15.0.0-canary.167(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@vercel/analytics@1.3.1(next@15.0.0-canary.168(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': dependencies: server-only: 0.0.1 optionalDependencies: - next: 15.0.0-canary.167(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + next: 15.0.0-canary.168(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 '@vercel/postgres@0.8.0': @@ -8889,9 +8889,9 @@ snapshots: ws: 8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3) optional: true - '@vercel/speed-insights@1.0.12(next@15.0.0-canary.167(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': + '@vercel/speed-insights@1.0.12(next@15.0.0-canary.168(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)': optionalDependencies: - next: 15.0.0-canary.167(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + next: 15.0.0-canary.168(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) react: 19.0.0-rc-f994737d14-20240522 '@vercel/style-guide@6.0.0(@next/eslint-plugin-next@14.2.3)(eslint@8.57.0)(prettier@3.3.0)(typescript@5.5.2)(vitest@2.0.4)': @@ -9600,13 +9600,13 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.33.0(@libsql/client@0.9.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.7.2)(@types/better-sqlite3@7.6.10)(@types/pg@8.6.6)(@types/react@18.3.3)(@vercel/postgres@0.8.0)(better-sqlite3@11.0.0)(kysely@0.22.0)(react@19.0.0-rc-f994737d14-20240522): + drizzle-orm@0.33.0(@libsql/client@0.9.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.7.2)(@types/better-sqlite3@7.6.10)(@types/pg@8.6.6)(@types/react@18.3.10)(@vercel/postgres@0.8.0)(better-sqlite3@11.0.0)(kysely@0.22.0)(react@19.0.0-rc-f994737d14-20240522): optionalDependencies: '@libsql/client': 0.9.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) '@neondatabase/serverless': 0.7.2 '@types/better-sqlite3': 7.6.10 '@types/pg': 8.6.6 - '@types/react': 18.3.3 + '@types/react': 18.3.10 '@vercel/postgres': 0.8.0 better-sqlite3: 11.0.0 kysely: 0.22.0 @@ -10037,7 +10037,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.5.2))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -11123,9 +11123,9 @@ snapshots: react: 19.0.0-rc-f994737d14-20240522 react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) - next@15.0.0-canary.167(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522): + next@15.0.0-canary.168(@babel/core@7.24.7)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522): dependencies: - '@next/env': 15.0.0-canary.167 + '@next/env': 15.0.0-canary.168 '@swc/counter': 0.1.3 '@swc/helpers': 0.5.13 busboy: 1.6.0 @@ -11135,15 +11135,15 @@ snapshots: react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522) styled-jsx: 5.1.6(@babel/core@7.24.7)(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@next/swc-darwin-arm64': 15.0.0-canary.167 - '@next/swc-darwin-x64': 15.0.0-canary.167 - '@next/swc-linux-arm64-gnu': 15.0.0-canary.167 - '@next/swc-linux-arm64-musl': 15.0.0-canary.167 - '@next/swc-linux-x64-gnu': 15.0.0-canary.167 - '@next/swc-linux-x64-musl': 15.0.0-canary.167 - '@next/swc-win32-arm64-msvc': 15.0.0-canary.167 - '@next/swc-win32-ia32-msvc': 15.0.0-canary.167 - '@next/swc-win32-x64-msvc': 15.0.0-canary.167 + '@next/swc-darwin-arm64': 15.0.0-canary.168 + '@next/swc-darwin-x64': 15.0.0-canary.168 + '@next/swc-linux-arm64-gnu': 15.0.0-canary.168 + '@next/swc-linux-arm64-musl': 15.0.0-canary.168 + '@next/swc-linux-x64-gnu': 15.0.0-canary.168 + '@next/swc-linux-x64-musl': 15.0.0-canary.168 + '@next/swc-win32-arm64-msvc': 15.0.0-canary.168 + '@next/swc-win32-ia32-msvc': 15.0.0-canary.168 + '@next/swc-win32-x64-msvc': 15.0.0-canary.168 babel-plugin-react-compiler: 0.0.0-experimental-334f00b-20240725 sharp: 0.33.5 transitivePeerDependencies: @@ -11635,33 +11635,33 @@ snapshots: react-refresh@0.14.2: {} - react-remove-scroll-bar@2.3.6(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522): + react-remove-scroll-bar@2.3.6(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522): dependencies: react: 19.0.0-rc-f994737d14-20240522 - react-style-singleton: 2.2.1(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + react-style-singleton: 2.2.1(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) tslib: 2.6.2 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - react-remove-scroll@2.5.7(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522): + react-remove-scroll@2.5.7(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522): dependencies: react: 19.0.0-rc-f994737d14-20240522 - react-remove-scroll-bar: 2.3.6(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - react-style-singleton: 2.2.1(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + react-remove-scroll-bar: 2.3.6(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + react-style-singleton: 2.2.1(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) tslib: 2.6.2 - use-callback-ref: 1.3.2(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) - use-sidecar: 1.1.2(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522) + use-callback-ref: 1.3.2(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) + use-sidecar: 1.1.2(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - react-style-singleton@2.2.1(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522): + react-style-singleton@2.2.1(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522): dependencies: get-nonce: 1.0.1 invariant: 2.2.4 react: 19.0.0-rc-f994737d14-20240522 tslib: 2.6.2 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 react@19.0.0-rc-3563387fe3-20240621: {} @@ -12481,20 +12481,20 @@ snapshots: querystringify: 2.2.0 requires-port: 1.0.0 - use-callback-ref@1.3.2(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522): + use-callback-ref@1.3.2(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522): dependencies: react: 19.0.0-rc-f994737d14-20240522 tslib: 2.6.2 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 - use-sidecar@1.1.2(@types/react@18.3.3)(react@19.0.0-rc-f994737d14-20240522): + use-sidecar@1.1.2(@types/react@18.3.10)(react@19.0.0-rc-f994737d14-20240522): dependencies: detect-node-es: 1.1.0 react: 19.0.0-rc-f994737d14-20240522 tslib: 2.6.2 optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.10 use-sync-external-store@1.2.2(react@19.0.0-rc-f994737d14-20240522): dependencies: From ac5e36534fcc338f364d096575360f7abe3cd574 Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Sun, 29 Sep 2024 04:22:25 +0100 Subject: [PATCH 15/43] add dropdown menu to posts wip --- .../(app)/_components/ellipsis-dropdown.tsx | 92 +++++++++++++ .../app/(app)/_components/post-card.tsx | 53 ++++---- packages/frontpage/app/(app)/layout.tsx | 9 +- .../moderation/_components/report-card.tsx | 89 +++++++++++++ .../user-handle.tsx} | 0 .../frontpage/app/(app)/moderation/page.tsx | 85 +----------- .../frontpage/lib/components/ui/dialog.tsx | 122 ++++++++++++++++++ packages/frontpage/package.json | 1 + 8 files changed, 346 insertions(+), 105 deletions(-) create mode 100644 packages/frontpage/app/(app)/_components/ellipsis-dropdown.tsx create mode 100644 packages/frontpage/app/(app)/moderation/_components/report-card.tsx rename packages/frontpage/app/(app)/moderation/{_user-handle.tsx => _components/user-handle.tsx} (100%) create mode 100644 packages/frontpage/lib/components/ui/dialog.tsx diff --git a/packages/frontpage/app/(app)/_components/ellipsis-dropdown.tsx b/packages/frontpage/app/(app)/_components/ellipsis-dropdown.tsx new file mode 100644 index 00000000..f026483f --- /dev/null +++ b/packages/frontpage/app/(app)/_components/ellipsis-dropdown.tsx @@ -0,0 +1,92 @@ +"use client"; + +import * as React from "react"; +import { MoreHorizontal, Trash } from "lucide-react"; +import { Button } from "@/lib/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from "@/lib/components/ui/dropdown-menu"; +import { ExclamationTriangleIcon } from "@radix-ui/react-icons"; +import { DialogHeader } from "@/lib/components/ui/dialog"; +import { + Dialog, + DialogContent, + DialogTitle, + DialogDescription, + DialogTrigger, +} from "@radix-ui/react-dialog"; + +type EllipsisDropdownProps = { + onReport: () => Promise; + onDelete: () => Promise; + isAuthor: boolean; +}; + +export function EllipsisDropdown({ + onReport, + onDelete, + isAuthor, +}: EllipsisDropdownProps) { + const [open, setOpen] = React.useState(false); + + return ( + + + + + + Actions + + + + { + e.preventDefault(); + void onReport?.(); + setOpen(false); + }} + > + + Report + + + + + Are you absolutely sure? + + This will report the comment. This action cannot be undone. + + + + + {isAuthor || true ? ( + <> + + { + e.preventDefault(); + void onDelete?.(); + setOpen(false); + }} + > + + Delete + ⌘⌫ + + + ) : null} + + + + ); +} diff --git a/packages/frontpage/app/(app)/_components/post-card.tsx b/packages/frontpage/app/(app)/_components/post-card.tsx index 8ceea066..e9f7e37f 100644 --- a/packages/frontpage/app/(app)/_components/post-card.tsx +++ b/packages/frontpage/app/(app)/_components/post-card.tsx @@ -8,8 +8,8 @@ import { PostCollection } from "@/lib/data/atproto/post"; import { getVerifiedHandle } from "@/lib/data/atproto/identity"; import { UserHoverCard } from "@/lib/components/user-hover-card"; import type { DID } from "@/lib/data/atproto/did"; -import { ReportButton } from "./report-button"; import { createReport } from "@/lib/data/db/report"; +import { EllipsisDropdown } from "./ellipsis-dropdown"; type PostProps = { id: number; @@ -74,26 +74,6 @@ export async function PostCard({ } votes={votes} /> - { - "use server"; - const user = await ensureUser(); - - await createReport({ - actionedAt: new Date(), - subjectUri: `at://${author}/${PostCollection}/${rkey}`, - subjectDid: author, - subjectCollection: PostCollection, - subjectRkey: rkey, - subjectCid: cid, - createdBy: user.did, - createdAt: new Date(), - creatorComment: "This post is spam", - reportReason: "spam", - status: "pending", - }); - }} - />

@@ -109,7 +89,7 @@ export async function PostCard({

-
+
• @@ -130,6 +110,35 @@ export async function PostCard({
+
+ { + "use server"; + console.log("Deleting post", rkey); + return; + }} + onReport={async () => { + "use server"; + const user = await ensureUser(); + + console.log("Reporting post", rkey); + + await createReport({ + subjectUri: `at://${author}/${PostCollection}/${rkey}`, + subjectDid: author, + subjectCollection: PostCollection, + subjectRkey: rkey, + subjectCid: cid, + createdBy: user.did, + createdAt: new Date(), + creatorComment: "This post is terrible", + reportReason: "spam", + status: "pending", + }); + }} + /> +
diff --git a/packages/frontpage/app/(app)/layout.tsx b/packages/frontpage/app/(app)/layout.tsx index f1cdeeb4..4281f408 100644 --- a/packages/frontpage/app/(app)/layout.tsx +++ b/packages/frontpage/app/(app)/layout.tsx @@ -2,7 +2,7 @@ import { deleteAuthCookie, getSession, signOut } from "@/lib/auth"; import Link from "next/link"; import { Suspense } from "react"; import { Button } from "@/lib/components/ui/button"; -import { isBetaUser } from "@/lib/data/user"; +import { isAdmin, isBetaUser } from "@/lib/data/user"; import { OpenInNewWindowIcon } from "@radix-ui/react-icons"; import { ThemeToggle } from "./_components/theme-toggle"; import { @@ -123,6 +123,13 @@ async function LoginOrLogout() { Profile + {(await isAdmin()) ? ( + + + Moderation + + + ) : null}
{ diff --git a/packages/frontpage/app/(app)/moderation/_components/report-card.tsx b/packages/frontpage/app/(app)/moderation/_components/report-card.tsx new file mode 100644 index 00000000..6fb3fe8a --- /dev/null +++ b/packages/frontpage/app/(app)/moderation/_components/report-card.tsx @@ -0,0 +1,89 @@ +import { Button } from "@/lib/components/ui/button"; +import { + Card, + CardHeader, + CardTitle, + CardContent, +} from "@/lib/components/ui/card"; +import { DID } from "@/lib/data/atproto/did"; +import { Report } from "@/lib/data/db/report"; +import { ExternalLink, Flag } from "lucide-react"; +import { performModerationAction } from "../page"; +import { UserHandle } from "./user-handle"; + +export async function ReportCard({ report }: { report: Report }) { + return ( + + + + Reported Item + + {report.status} + + + + + +
+ + Reason: {report.creatorComment} +
+
+
+ Reported By: + +
+
+ Reported Reason: {report.creatorComment} +
+
+ + + + +
+
+ ); +} diff --git a/packages/frontpage/app/(app)/moderation/_user-handle.tsx b/packages/frontpage/app/(app)/moderation/_components/user-handle.tsx similarity index 100% rename from packages/frontpage/app/(app)/moderation/_user-handle.tsx rename to packages/frontpage/app/(app)/moderation/_components/user-handle.tsx diff --git a/packages/frontpage/app/(app)/moderation/page.tsx b/packages/frontpage/app/(app)/moderation/page.tsx index 65286b88..9ba99f0f 100644 --- a/packages/frontpage/app/(app)/moderation/page.tsx +++ b/packages/frontpage/app/(app)/moderation/page.tsx @@ -1,4 +1,4 @@ -import { ExternalLink, Flag, Shield } from "lucide-react"; +import { Shield } from "lucide-react"; import { Card, CardContent, @@ -6,7 +6,6 @@ import { CardHeader, CardTitle, } from "@/lib/components/ui/card"; -import { Button } from "@/lib/components/ui/button"; import { ensureUser, isAdmin as isAdmin } from "@/lib/data/user"; import { redirect } from "next/navigation"; import { @@ -23,17 +22,13 @@ import { PostCollection } from "@/lib/data/atproto/post"; import { CommentCollection } from "@/lib/data/atproto/comment"; import { revalidatePath } from "next/cache"; import Link from "next/link"; -import { getVerifiedHandle } from "@/lib/data/atproto/identity"; -import { UserHandle } from "./_user-handle"; -import { DID } from "@/lib/data/atproto/did"; +import { ReportCard } from "./_components/report-card"; export async function performModerationAction( input: { reportId: number; status: "accepted" | "rejected" }, _: FormData, ) { "use server"; - console.log("creating moderation action"); - console.log("input", input); const user = await ensureUser(); const report = await getReport(input.reportId); @@ -166,81 +161,7 @@ export default async function Moderation({ {reports.map((report) => ( - - - - Reported Item - - {report.status} - - - - - -
- - Reason: {report.creatorComment} -
-
-
- Reported By: - -
-
- Reported Reason: {report.creatorComment} -
-
-
- - -
-
-
+ ))} ); diff --git a/packages/frontpage/lib/components/ui/dialog.tsx b/packages/frontpage/lib/components/ui/dialog.tsx new file mode 100644 index 00000000..95b0d38a --- /dev/null +++ b/packages/frontpage/lib/components/ui/dialog.tsx @@ -0,0 +1,122 @@ +"use client" + +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { Cross2Icon } from "@radix-ui/react-icons" + +import { cn } from "@/lib/utils" + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogHeader.displayName = "DialogHeader" + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogFooter.displayName = "DialogFooter" + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogTrigger, + DialogClose, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} diff --git a/packages/frontpage/package.json b/packages/frontpage/package.json index 26136050..870b3940 100644 --- a/packages/frontpage/package.json +++ b/packages/frontpage/package.json @@ -20,6 +20,7 @@ "@next/env": "^14.2.4", "@radix-ui/react-alert-dialog": "^1.1.1", "@radix-ui/react-avatar": "^1.1.0", + "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-dropdown-menu": "^2.1.1", "@radix-ui/react-hover-card": "^1.1.1", "@radix-ui/react-icons": "^1.3.0", From b845fe01b367f6cd34e53f9cdd8d6ed22f55d19f Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Sun, 29 Sep 2024 04:24:30 +0100 Subject: [PATCH 16/43] why --- pnpm-lock.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2dfaec7f..ab48925f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -129,6 +129,9 @@ importers: '@radix-ui/react-avatar': specifier: ^1.1.0 version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) + '@radix-ui/react-dialog': + specifier: ^1.1.1 + version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) '@radix-ui/react-dropdown-menu': specifier: ^2.1.1 version: 2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.10)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) From 18ca0321a25ea0344f040ac3865a13235d5f8cfe Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Sun, 29 Sep 2024 04:29:58 +0100 Subject: [PATCH 17/43] remove unused --- packages/frontpage/lib/data/db/post.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/frontpage/lib/data/db/post.ts b/packages/frontpage/lib/data/db/post.ts index e2d872a5..dd6c38aa 100644 --- a/packages/frontpage/lib/data/db/post.ts +++ b/packages/frontpage/lib/data/db/post.ts @@ -256,5 +256,3 @@ export async function unauthed_deletePost({ }); console.log("Done deleting post transaction"); } - -export async function moderatePost(cid: string) {} From 87f43bb606f262df940ae68b71d1ecb9901275e0 Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Sun, 29 Sep 2024 15:22:51 +0100 Subject: [PATCH 18/43] add confirmation dialogs --- .../(app)/_components/ellipsis-dropdown.tsx | 115 +++++++++--------- .../frontpage/app/(app)/moderation/page.tsx | 6 - 2 files changed, 59 insertions(+), 62 deletions(-) diff --git a/packages/frontpage/app/(app)/_components/ellipsis-dropdown.tsx b/packages/frontpage/app/(app)/_components/ellipsis-dropdown.tsx index f026483f..7029947e 100644 --- a/packages/frontpage/app/(app)/_components/ellipsis-dropdown.tsx +++ b/packages/frontpage/app/(app)/_components/ellipsis-dropdown.tsx @@ -10,18 +10,21 @@ import { DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, - DropdownMenuShortcut, DropdownMenuTrigger, } from "@/lib/components/ui/dropdown-menu"; import { ExclamationTriangleIcon } from "@radix-ui/react-icons"; -import { DialogHeader } from "@/lib/components/ui/dialog"; import { - Dialog, - DialogContent, - DialogTitle, - DialogDescription, - DialogTrigger, -} from "@radix-ui/react-dialog"; + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "@/lib/components/ui/alert-dialog"; +import { toast } from "@/lib/components/ui/use-toast"; type EllipsisDropdownProps = { onReport: () => Promise; @@ -37,56 +40,56 @@ export function EllipsisDropdown({ const [open, setOpen] = React.useState(false); return ( - - - - - - Actions - - - - { - e.preventDefault(); - void onReport?.(); - setOpen(false); - }} - > + + + + + + + Actions + + + Report - - - - Are you absolutely sure? - - This will report the comment. This action cannot be undone. - - - - - {isAuthor || true ? ( - <> - - { - e.preventDefault(); - void onDelete?.(); - setOpen(false); - }} - > - - Delete - ⌘⌫ - - - ) : null} - - - + + {isAuthor || true ? ( + <> + + + + Delete + + + ) : null} + + + + + + Are you absolutely sure? + + This will report the post. This action cannot be undone. + + + + { + void onReport(); + toast({ + title: "Post reported", + type: "foreground", + }); + }} + > + Confirm + + Cancel + + + ); } diff --git a/packages/frontpage/app/(app)/moderation/page.tsx b/packages/frontpage/app/(app)/moderation/page.tsx index 9ba99f0f..72f8526d 100644 --- a/packages/frontpage/app/(app)/moderation/page.tsx +++ b/packages/frontpage/app/(app)/moderation/page.tsx @@ -78,12 +78,6 @@ export default async function Moderation({ ); const stats = await getModeratorReportStats(); - // const stats = { - // total: reports.length, - // pending: reports.filter((r) => r.status === "pending").length, - // accepted: reports.filter((r) => r.status === "accepted").length, - // rejected: reports.filter((r) => r.status === "rejected").length, - // }; if (await isAdmin()) { return ( From 1796b6cf146fa190c023f2cd6b458bb5cbb5b39a Mon Sep 17 00:00:00 2001 From: WillCorrigan Date: Mon, 30 Sep 2024 06:30:47 +0100 Subject: [PATCH 19/43] get ellipsis working for posts, create moderator actions in db, add ellipsis to comments, delete is wip --- .../(app)/_components/ellipsis-dropdown.tsx | 172 +++++++++++++----- .../app/(app)/_components/post-card.tsx | 59 +++--- .../moderation/_components/report-card.tsx | 163 ++++++++++------- .../moderation/_components/user-handle.tsx | 2 +- .../frontpage/app/(app)/moderation/page.tsx | 34 +++- .../[postAuthor]/[postRkey]/_lib/actions.tsx | 27 +++ .../[postRkey]/_lib/comment-client.tsx | 21 +++ .../frontpage/lib/components/ui/select.tsx | 164 +++++++++++++++++ packages/frontpage/lib/constants.ts | 7 + packages/frontpage/lib/data/db/comment.ts | 24 +++ packages/frontpage/lib/data/db/moderation.ts | 3 +- packages/frontpage/lib/data/db/post.ts | 25 +++ packages/frontpage/lib/data/db/report.ts | 1 + packages/frontpage/lib/data/db/user.ts | 16 ++ packages/frontpage/package.json | 1 + pnpm-lock.yaml | 62 ++++++- 16 files changed, 639 insertions(+), 142 deletions(-) create mode 100644 packages/frontpage/lib/components/ui/select.tsx create mode 100644 packages/frontpage/lib/data/db/user.ts diff --git a/packages/frontpage/app/(app)/_components/ellipsis-dropdown.tsx b/packages/frontpage/app/(app)/_components/ellipsis-dropdown.tsx index 7029947e..d691b528 100644 --- a/packages/frontpage/app/(app)/_components/ellipsis-dropdown.tsx +++ b/packages/frontpage/app/(app)/_components/ellipsis-dropdown.tsx @@ -9,7 +9,6 @@ import { DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, - DropdownMenuSeparator, DropdownMenuTrigger, } from "@/lib/components/ui/dropdown-menu"; import { ExclamationTriangleIcon } from "@radix-ui/react-icons"; @@ -25,71 +24,148 @@ import { AlertDialogTrigger, } from "@/lib/components/ui/alert-dialog"; import { toast } from "@/lib/components/ui/use-toast"; +import { Textarea } from "@/lib/components/ui/textarea"; +import { + Select, + SelectTrigger, + SelectValue, + SelectContent, + SelectItem, +} from "@/lib/components/ui/select"; +import { ReportReason } from "@/lib/constants"; type EllipsisDropdownProps = { - onReport: () => Promise; - onDelete: () => Promise; + onReportAction: ( + creatorComment: string, + reportReason: ReportReason, + ) => Promise; + onDeleteAction: () => Promise; isAuthor: boolean; }; export function EllipsisDropdown({ - onReport, - onDelete, + onReportAction, + onDeleteAction, isAuthor, }: EllipsisDropdownProps) { const [open, setOpen] = React.useState(false); + const [input, setInput] = React.useState(""); + const [reportReason, setReportReason] = React.useState("SPAM"); return ( - - - - - - - Actions - + + + + + + Actions + + - + { + e.preventDefault(); + }} + > Report - {isAuthor || true ? ( - <> - - + + + Are you absolutely sure? + + This will report the post. This action cannot be undone. + + + +