diff --git a/core/app/c/[communitySlug]/pubs/[pubId]/page.tsx b/core/app/c/[communitySlug]/pubs/[pubId]/page.tsx index 01b003a0f9..0641e404f1 100644 --- a/core/app/c/[communitySlug]/pubs/[pubId]/page.tsx +++ b/core/app/c/[communitySlug]/pubs/[pubId]/page.tsx @@ -1,25 +1,29 @@ -import { PubField, PubFieldSchema, PubValue, Prisma } from "@prisma/client"; +import { Prisma, PubField, PubFieldSchema, PubValue } from "@prisma/client"; import { AnySchema, JSONSchemaType } from "ajv"; import Link from "next/link"; import { - Button, Avatar, AvatarFallback, AvatarImage, - Card, - CardTitle, + Button, CardContent, CardHeader, + CardTitle, + HoverCard, + HoverCardContent, + HoverCardTrigger, Separator, } from "ui"; + import IntegrationActions from "~/app/components/IntegrationActions"; import { PubTitle } from "~/app/components/PubTitle"; import { getLoginData } from "~/lib/auth/loginData"; +import cn from "~/lib/cn"; +import { FileUpload } from "~/lib/fields/fileUpload"; import { getPubUsers } from "~/lib/permissions"; import { createToken } from "~/lib/server/token"; import { pubInclude } from "~/lib/types"; import prisma from "~/prisma/db"; -import cn from "~/lib/cn"; const getPub = async (pubId: string) => { return await prisma.pub.findUnique({ @@ -37,8 +41,43 @@ interface PubValueWithFieldAndSchema extends PubValue { field: PubFieldWithValue; } +function FileUploadPreview({ files }: { files: FileUpload }) { + return ( + + ); +} + function recursivelyGetScalarFields(schema: JSONSchemaType, value: Prisma.JsonValue) { const fields: any[] = []; + if (schema.$id === "pubpub:fileUpload") { + return ; + } // TODO: get schema IDs and render specific stuff -- e.g. file upload, confidence intervals if (!schema.properties) { switch (schema.type) { diff --git a/core/lib/fields/fileUpload.ts b/core/lib/fields/fileUpload.ts new file mode 100644 index 0000000000..eaac7ab6a3 --- /dev/null +++ b/core/lib/fields/fileUpload.ts @@ -0,0 +1,47 @@ +import { JSONSchemaType } from "ajv"; + +export type FileUploadFile = { + fileName: string; + fileSource: string; + fileType: string; + fileSize: number; + fileMeta: object; + fileUploadUrl: string; + filePreview: string; +}; +export type FileUpload = FileUploadFile[]; + +export const FileUpload = { + $id: "pubpub:fileUpload", + title: "Upload Files", + type: "array", + items: { + type: "object", + properties: { + fileName: { + type: "string", + }, + fileSource: { + type: "string", + }, + fileType: { + type: "string", + }, + fileSize: { + type: "number", + }, + fileMeta: { + type: "object", + }, + fileUploadUrl: { + type: "string", + format: "uri", + }, + filePreview: { + type: "string", + format: "uri", + }, + }, + }, +} as unknown as JSONSchemaType; + diff --git a/core/prisma/exampleCommunitySeeds/unjournal.ts b/core/prisma/exampleCommunitySeeds/unjournal.ts index 43d856205d..348a243776 100644 --- a/core/prisma/exampleCommunitySeeds/unjournal.ts +++ b/core/prisma/exampleCommunitySeeds/unjournal.ts @@ -1,6 +1,7 @@ import { PrismaClient } from "@prisma/client"; import { v4 as uuidv4 } from "uuid"; import { faker } from "@faker-js/faker"; +import { FileUpload } from "../../lib/fields/fileUpload"; export const unJournalId = "03e7a5fd-bdca-4682-9221-3a69992c1f3b"; @@ -258,39 +259,7 @@ export default async function main(prisma: PrismaClient, communityUUID: string) data: { name: "uploadFile", namespace: "pubpub", - schema: { - $id: "pubpub:fileUpload", - title: "Upload Files", - type: "array", - items: { - type: "object", - properties: { - fileName: { - type: "string", - }, - fileSource: { - type: "string", - }, - fileType: { - type: "string", - }, - fileSize: { - type: "number", - }, - fileMeta: { - type: "object", - }, - fileUploadUrl: { - type: "string", - format: "uri", - }, - filePreview: { - type: "string", - format: "uri", - }, - }, - }, - }, + schema: FileUpload, }, }); diff --git a/integrations/evaluations/app/actions/evaluate/evaluate.tsx b/integrations/evaluations/app/actions/evaluate/evaluate.tsx index 856448eb97..29a8b7130a 100644 --- a/integrations/evaluations/app/actions/evaluate/evaluate.tsx +++ b/integrations/evaluations/app/actions/evaluate/evaluate.tsx @@ -8,7 +8,6 @@ import { fullFormats } from "ajv-formats/dist/formats"; import { useEffect, useMemo } from "react"; import { useForm } from "react-hook-form"; import { Button, Form, Icon, useLocalStorage, useToast } from "ui"; -import { cn } from "utils"; import { Process } from "~/lib/components/Process"; import { Research } from "~/lib/components/Research"; import { InstanceConfig } from "~/lib/types"; diff --git a/packages/ui/package.json b/packages/ui/package.json index 5142378b40..b7f70258d1 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -18,6 +18,7 @@ "@radix-ui/react-collapsible": "^1.0.3", "@radix-ui/react-dialog": "^1.0.4", "@radix-ui/react-dropdown-menu": "^2.0.5", + "@radix-ui/react-hover-card": "^1.0.7", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-popover": "^1.0.6", diff --git a/packages/ui/src/customRenderers/fileUpload/fileUpload.tsx b/packages/ui/src/customRenderers/fileUpload/fileUpload.tsx index 1b73941489..76be614fca 100644 --- a/packages/ui/src/customRenderers/fileUpload/fileUpload.tsx +++ b/packages/ui/src/customRenderers/fileUpload/fileUpload.tsx @@ -9,7 +9,6 @@ import { Dashboard } from "@uppy/react"; import "@uppy/core/dist/style.min.css"; import "@uppy/dashboard/dist/style.min.css"; -import { cn } from "utils"; import AwsS3 from "@uppy/aws-s3"; const uppy = new Uppy().use(AwsS3); @@ -19,15 +18,6 @@ type FileUploadProps = { onUpdateFiles: Function; }; -type UploadedFile = { - fileName: String; - fileSource?: String; - fileType?: String; - fileSize?: Number; - fileMeta?: Object; - filePreview?: String; - fileUploadUrl: String; -}; const FileUpload = forwardRef(function FileUpload(props: FileUploadProps, ref) { useEffect(() => { uppy.on("complete", () => { diff --git a/packages/ui/src/hover-card.tsx b/packages/ui/src/hover-card.tsx new file mode 100644 index 0000000000..d9b0522668 --- /dev/null +++ b/packages/ui/src/hover-card.tsx @@ -0,0 +1,29 @@ +"use client"; + +import * as React from "react"; +import * as HoverCardPrimitive from "@radix-ui/react-hover-card"; + +import { cn } from "utils"; + +const HoverCard = HoverCardPrimitive.Root; + +const HoverCardTrigger = HoverCardPrimitive.Trigger; + +const HoverCardContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( + +)); +HoverCardContent.displayName = HoverCardPrimitive.Content.displayName; + +export { HoverCard, HoverCardTrigger, HoverCardContent }; diff --git a/packages/ui/src/index.tsx b/packages/ui/src/index.tsx index 63be3f77b7..e314adb011 100644 --- a/packages/ui/src/index.tsx +++ b/packages/ui/src/index.tsx @@ -13,6 +13,7 @@ export * from "./checkbox"; export * from "./dialog"; export * from "./dropdown-menu"; export * from "./form"; +export * from "./hover-card"; export * from "./input"; export * from "./label"; export * from "./popover"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6017c4010f..4062335a3f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -446,6 +446,9 @@ importers: '@radix-ui/react-dropdown-menu': specifier: ^2.0.5 version: 2.0.5(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-hover-card': + specifier: ^1.0.7 + version: 1.0.7(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-icons': specifier: ^1.3.0 version: 1.3.0(react@18.2.0) @@ -3378,6 +3381,30 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-dismissable-layer@1.0.5(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.22.10 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.12)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.12)(react@18.2.0) + '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.12)(react@18.2.0) + '@types/react': 18.2.12 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-dropdown-menu@2.0.5(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-xdOrZzOTocqqkCkYo8yRPCib5OkTkqN7lqNCdxwPOdE466DOaNl4N8PkUIlsXthQvW5Wwkd+aEmWpfWlBoDPEw==} peerDependencies: @@ -3440,6 +3467,34 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-hover-card@1.0.7(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-OcUN2FU0YpmajD/qkph3XzMcK/NmSk9hGWnjV68p6QiZMgILugusgQwnLSDs3oFSJYGKf3Y49zgFedhGh04k9A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.22.10 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.12)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.12)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-popper': 1.1.3(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.12)(react@18.2.0) + '@types/react': 18.2.12 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-icons@1.3.0(react@18.2.0): resolution: {integrity: sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw==} peerDependencies: @@ -3583,6 +3638,35 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-popper@1.1.3(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.22.10 + '@floating-ui/react-dom': 2.0.1(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-arrow': 1.0.3(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.12)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.12)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.12)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.12)(react@18.2.0) + '@radix-ui/react-use-rect': 1.0.1(@types/react@18.2.12)(react@18.2.0) + '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.12)(react@18.2.0) + '@radix-ui/rect': 1.0.1 + '@types/react': 18.2.12 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-portal@1.0.3(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-xLYZeHrWoPmA5mEKEfZZevoVRK/Q43GfzRXkWV6qawIWWK8t6ifIiLQdd7rmQ4Vk1bmI21XhqF9BN3jWf+phpA==} peerDependencies: @@ -3603,6 +3687,26 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-portal@1.0.4(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.22.10 + '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.12 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-presence@1.0.1(@types/react@18.2.12)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} peerDependencies: