diff --git a/apps/web/actions/videos/generate-ai-metadata.ts b/apps/web/actions/videos/generate-ai-metadata.ts index eecd46de68..744d4d7cc9 100644 --- a/apps/web/actions/videos/generate-ai-metadata.ts +++ b/apps/web/actions/videos/generate-ai-metadata.ts @@ -45,13 +45,11 @@ export async function generateAiMetadata(videoId: string, userId: string) { metadata: { ...metadata, aiProcessing: false, - generationError: null, }, }) .where(eq(videos.id, videoId)); metadata.aiProcessing = false; - metadata.generationError = null; } else { return; } @@ -296,8 +294,6 @@ ${transcriptText}`; metadata: { ...currentMetadata, aiProcessing: false, - generationError: - error instanceof Error ? error.message : String(error), }, }) .where(eq(videos.id, videoId)); diff --git a/apps/web/actions/videos/get-status.ts b/apps/web/actions/videos/get-status.ts index 26bc9c06e6..ac73e509ac 100644 --- a/apps/web/actions/videos/get-status.ts +++ b/apps/web/actions/videos/get-status.ts @@ -20,7 +20,7 @@ export interface VideoStatusResult { aiTitle: string | null; summary: string | null; chapters: { title: string; start: number }[] | null; - generationError: string | null; + // generationError: string | null; error?: string; } @@ -62,7 +62,7 @@ export async function getVideoStatus( aiTitle: metadata.aiTitle || null, summary: metadata.summary || null, chapters: metadata.chapters || null, - generationError: metadata.generationError || null, + // generationError: metadata.generationError || null, }; } catch (error) { console.error( @@ -75,7 +75,7 @@ export async function getVideoStatus( aiTitle: metadata.aiTitle || null, summary: metadata.summary || null, chapters: metadata.chapters || null, - generationError: metadata.generationError || null, + // generationError: metadata.generationError || null, error: "Failed to start transcription", }; } @@ -88,7 +88,7 @@ export async function getVideoStatus( aiTitle: metadata.aiTitle || null, summary: metadata.summary || null, chapters: metadata.chapters || null, - generationError: metadata.generationError || null, + // generationError: metadata.generationError || null, error: "Transcription failed", }; } @@ -110,7 +110,7 @@ export async function getVideoStatus( metadata: { ...metadata, aiProcessing: false, - generationError: "AI processing timed out and was reset", + // generationError: "AI processing timed out and was reset", }, }) .where(eq(videos.id, videoId)); @@ -133,7 +133,7 @@ export async function getVideoStatus( aiTitle: updatedMetadata.aiTitle || null, summary: updatedMetadata.summary || null, chapters: updatedMetadata.chapters || null, - generationError: updatedMetadata.generationError || null, + // generationError: updatedMetadata.generationError || null, error: "AI processing timed out and was reset", }; } @@ -144,8 +144,8 @@ export async function getVideoStatus( video.transcriptionStatus === "COMPLETE" && !metadata.aiProcessing && !metadata.summary && - !metadata.chapters && - !metadata.generationError + !metadata.chapters + // !metadata.generationError ) { console.log( `[Get Status] Transcription complete but no AI data, checking feature flag for video owner ${video.ownerId}`, @@ -198,8 +198,8 @@ export async function getVideoStatus( metadata: { ...currentMetadata, aiProcessing: false, - generationError: - error instanceof Error ? error.message : String(error), + // generationError: + // error instanceof Error ? error.message : String(error), }, }) .where(eq(videos.id, videoId)); @@ -221,7 +221,7 @@ export async function getVideoStatus( aiTitle: metadata.aiTitle || null, summary: metadata.summary || null, chapters: metadata.chapters || null, - generationError: metadata.generationError || null, + // generationError: metadata.generationError || null, }; } else { const videoOwner = videoOwnerQuery[0]; @@ -239,6 +239,6 @@ export async function getVideoStatus( aiTitle: metadata.aiTitle || null, summary: metadata.summary || null, chapters: metadata.chapters || null, - generationError: metadata.generationError || null, + // generationError: metadata.generationError || null, }; } diff --git a/apps/web/app/(org)/dashboard/folder/[id]/components/ClientCapCard.tsx b/apps/web/app/(org)/dashboard/folder/[id]/components/ClientCapCard.tsx index f45cdbc9a2..496898652a 100644 --- a/apps/web/app/(org)/dashboard/folder/[id]/components/ClientCapCard.tsx +++ b/apps/web/app/(org)/dashboard/folder/[id]/components/ClientCapCard.tsx @@ -103,7 +103,11 @@ export function ClientCapCard(props: ClientCapCardProps) { onDragEnd={handleDragEnd} className={isDragging ? "opacity-50" : ""} > - + ); } diff --git a/apps/web/app/(org)/dashboard/folder/[id]/components/NewSubfolderButton.tsx b/apps/web/app/(org)/dashboard/folder/[id]/components/NewSubfolderButton.tsx index 0cda644140..77e4ce789a 100644 --- a/apps/web/app/(org)/dashboard/folder/[id]/components/NewSubfolderButton.tsx +++ b/apps/web/app/(org)/dashboard/folder/[id]/components/NewSubfolderButton.tsx @@ -1,13 +1,14 @@ "use client"; import { Button } from "@cap/ui"; +import type { Folder } from "@cap/web-domain"; import { faFolderPlus } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useState } from "react"; import { SubfolderDialog } from "./SubfolderDialog"; interface NewSubfolderButtonProps { - parentFolderId: string; + parentFolderId: Folder.FolderId; } export const NewSubfolderButton = ({ diff --git a/apps/web/app/(org)/dashboard/folder/[id]/components/useUploadPlaceholders.ts b/apps/web/app/(org)/dashboard/folder/[id]/components/useUploadPlaceholders.ts deleted file mode 100644 index 69c558aeea..0000000000 --- a/apps/web/app/(org)/dashboard/folder/[id]/components/useUploadPlaceholders.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { useCallback } from "react"; -import { useUploadContext } from "./UploadContext"; - -export interface UploadPlaceholder { - id: string; - progress: number; - thumbnail?: string; - uploadProgress?: number; -} - -export function useUploadPlaceholders() { - const { uploadPlaceholders, setUploadPlaceholders, isUploading } = - useUploadContext(); - - const handleUploadStart = useCallback( - (id: string, thumbnail?: string) => { - setUploadPlaceholders((prev) => [ - { id, progress: 0, thumbnail }, - ...prev, - ]); - }, - [setUploadPlaceholders], - ); - - const handleUploadProgress = useCallback( - (id: string, progress: number, uploadProgress?: number) => { - setUploadPlaceholders((prev) => - prev.map((u) => (u.id === id ? { ...u, progress, uploadProgress } : u)), - ); - }, - [setUploadPlaceholders], - ); - - const handleUploadComplete = useCallback( - (id: string) => { - setUploadPlaceholders((prev) => prev.filter((u) => u.id !== id)); - }, - [setUploadPlaceholders], - ); - - return { - uploadPlaceholders, - isUploading, - handleUploadStart, - handleUploadProgress, - handleUploadComplete, - }; -} diff --git a/apps/web/app/(org)/dashboard/spaces/[spaceId]/folder/[folderId]/page.tsx b/apps/web/app/(org)/dashboard/spaces/[spaceId]/folder/[folderId]/page.tsx index 3959becb1b..466e1f8323 100644 --- a/apps/web/app/(org)/dashboard/spaces/[spaceId]/folder/[folderId]/page.tsx +++ b/apps/web/app/(org)/dashboard/spaces/[spaceId]/folder/[folderId]/page.tsx @@ -74,7 +74,6 @@ const FolderPage = async ({ cardType="shared" initialVideos={videosData} dubApiKeyEnabled={!!serverEnv().DUB_API_KEY} - userId={userId} /> ); diff --git a/apps/web/app/(org)/verify-otp/form.tsx b/apps/web/app/(org)/verify-otp/form.tsx index 6bce9e63b5..f2effe76cf 100644 --- a/apps/web/app/(org)/verify-otp/form.tsx +++ b/apps/web/app/(org)/verify-otp/form.tsx @@ -172,7 +172,9 @@ export function VerifyOTPForm({ {code.map((digit, index) => ( (inputRefs.current[index] = el)} + ref={(el) => { + inputRefs.current[index] = el; + }} type="text" inputMode="numeric" pattern="[0-9]*" diff --git a/apps/web/app/(site)/tools/trim/metadata.ts b/apps/web/app/(site)/tools/trim/metadata.ts index 364a780a38..c0fced6962 100644 --- a/apps/web/app/(site)/tools/trim/metadata.ts +++ b/apps/web/app/(site)/tools/trim/metadata.ts @@ -4,7 +4,7 @@ import { trimVideoContent } from "@/components/tools/content"; export const metadata: Metadata = { title: trimVideoContent.title, description: trimVideoContent.description, - keywords: trimVideoContent.tags.join(", "), + keywords: trimVideoContent.tags?.join(", "), openGraph: { title: trimVideoContent.title, description: trimVideoContent.description, diff --git a/apps/web/app/api/upload/[...route]/multipart.ts b/apps/web/app/api/upload/[...route]/multipart.ts index 667c461e4f..6f0bb1674a 100644 --- a/apps/web/app/api/upload/[...route]/multipart.ts +++ b/apps/web/app/api/upload/[...route]/multipart.ts @@ -1,9 +1,8 @@ import { db, updateIfDefined } from "@cap/database"; import { s3Buckets, videos } from "@cap/database/schema"; -import type { VideoMetadata } from "@cap/database/types"; import { serverEnv } from "@cap/env"; import { zValidator } from "@hono/zod-validator"; -import { eq, sql } from "drizzle-orm"; +import { and, eq } from "drizzle-orm"; import { Hono } from "hono"; import { z } from "zod"; import { withAuth } from "@/app/api/utils"; diff --git a/apps/web/app/embed/[videoId]/_components/EmbedVideo.tsx b/apps/web/app/embed/[videoId]/_components/EmbedVideo.tsx index 264258eca2..a94617ae88 100644 --- a/apps/web/app/embed/[videoId]/_components/EmbedVideo.tsx +++ b/apps/web/app/embed/[videoId]/_components/EmbedVideo.tsx @@ -44,7 +44,7 @@ type CommentWithAuthor = typeof commentsSchema.$inferSelect & { export const EmbedVideo = forwardRef< HTMLVideoElement, { - data: typeof videos.$inferSelect; + data: Omit; user: typeof userSelectProps | null; comments: CommentWithAuthor[]; chapters?: { title: string; start: number }[]; diff --git a/apps/web/app/embed/[videoId]/page.tsx b/apps/web/app/embed/[videoId]/page.tsx index 16b2b1ec93..cc88f96d7b 100644 --- a/apps/web/app/embed/[videoId]/page.tsx +++ b/apps/web/app/embed/[videoId]/page.tsx @@ -11,7 +11,7 @@ import type { VideoMetadata } from "@cap/database/types"; import { buildEnv } from "@cap/env"; import { provideOptionalAuth, Videos, VideosPolicy } from "@cap/web-backend"; import { Policy, type Video } from "@cap/web-domain"; -import { eq } from "drizzle-orm"; +import { eq, sql } from "drizzle-orm"; import { Effect, Option } from "effect"; import type { Metadata } from "next"; import Link from "next/link"; @@ -142,6 +142,11 @@ export default async function EmbedVideoPage(props: Props) { transcriptionStatus: videos.transcriptionStatus, source: videos.source, folderId: videos.folderId, + width: videos.width, + height: videos.height, + duration: videos.duration, + fps: videos.fps, + hasPassword: sql`IF(${videos.password} IS NULL, 0, 1)`, sharedOrganization: { organizationId: sharedVideos.organizationId, }, diff --git a/apps/web/app/lib/compose-refs.ts b/apps/web/app/lib/compose-refs.ts index 2aaa3e9d5d..ad5c278c0c 100644 --- a/apps/web/app/lib/compose-refs.ts +++ b/apps/web/app/lib/compose-refs.ts @@ -1,6 +1,6 @@ import * as React from "react"; -type PossibleRef = React.Ref | undefined; +type PossibleRef = React.LegacyRef | React.Ref | undefined; /** * Set a given ref to a given value @@ -12,7 +12,7 @@ function setRef(ref: PossibleRef, value: T) { } if (ref !== null && ref !== undefined) { - ref.current = value; + (ref as any).current = value; } } diff --git a/apps/web/app/s/[videoId]/Share.tsx b/apps/web/app/s/[videoId]/Share.tsx index 27942428a2..72d8260832 100644 --- a/apps/web/app/s/[videoId]/Share.tsx +++ b/apps/web/app/s/[videoId]/Share.tsx @@ -2,6 +2,7 @@ import type { userSelectProps } from "@cap/database/auth/session"; import type { comments as commentsSchema, videos } from "@cap/database/schema"; +import type { Video } from "@cap/web-domain"; import { useQuery } from "@tanstack/react-query"; import { startTransition, @@ -62,7 +63,7 @@ interface ShareProps { } const useVideoStatus = ( - videoId: string, + videoId: Video.VideoId, aiGenerationEnabled: boolean, initialData?: { transcriptionStatus?: string | null; @@ -93,7 +94,6 @@ const useVideoStatus = ( aiTitle: initialData.aiData?.title || null, summary: initialData.aiData?.summary || null, chapters: initialData.aiData?.chapters || null, - generationError: null, } : undefined, refetchInterval: (query) => { @@ -177,7 +177,7 @@ export const Share = ({ summary: videoStatus?.summary || null, chapters: videoStatus?.chapters || null, processing: videoStatus?.aiProcessing || false, - generationError: videoStatus?.generationError || null, + // generationError: videoStatus?.generationError || null, }), [videoStatus], ); @@ -196,9 +196,9 @@ export const Share = ({ } if (transcriptionStatus === "COMPLETE") { - if (aiData.generationError) { - return false; - } + // if (aiData.generationError) { + // return false; + // } if (aiData.processing === true) { return true; } diff --git a/apps/web/app/s/[videoId]/_components/ShareHeader.tsx b/apps/web/app/s/[videoId]/_components/ShareHeader.tsx index 7aa36a2402..48c2823758 100644 --- a/apps/web/app/s/[videoId]/_components/ShareHeader.tsx +++ b/apps/web/app/s/[videoId]/_components/ShareHeader.tsx @@ -2,7 +2,7 @@ import type { userSelectProps } from "@cap/database/auth/session"; import type { videos } from "@cap/database/schema"; -import { buildEnv } from "@cap/env"; +import { buildEnv, NODE_ENV } from "@cap/env"; import { Button } from "@cap/ui"; import { userIsPro } from "@cap/utils"; import { faChevronDown, faLock } from "@fortawesome/free-solid-svg-icons"; @@ -28,7 +28,6 @@ export const ShareHeader = ({ sharedOrganizations = [], sharedSpaces = [], spacesData = null, - NODE_ENV, }: { data: typeof videos.$inferSelect; user: typeof userSelectProps | null; @@ -49,7 +48,6 @@ export const ShareHeader = ({ organizationId: string; }[]; spacesData?: Spaces[] | null; - NODE_ENV: "production" | "development" | "test"; }) => { const { push, refresh } = useRouter(); const [isEditing, setIsEditing] = useState(false); diff --git a/apps/web/app/s/[videoId]/_components/Toolbar.tsx b/apps/web/app/s/[videoId]/_components/Toolbar.tsx index 3516483faf..415331c7ec 100644 --- a/apps/web/app/s/[videoId]/_components/Toolbar.tsx +++ b/apps/web/app/s/[videoId]/_components/Toolbar.tsx @@ -13,8 +13,8 @@ const MotionButton = motion.create(Button); interface ToolbarProps { data: typeof videos.$inferSelect; user: typeof userSelectProps | null; - onOptimisticComment: (comment: CommentType) => void; - onCommentSuccess: (comment: CommentType) => void; + onOptimisticComment?: (comment: CommentType) => void; + onCommentSuccess?: (comment: CommentType) => void; } export const Toolbar = ({ @@ -68,7 +68,7 @@ export const Toolbar = ({ sending: true, }; - onOptimisticComment(optimisticComment); + onOptimisticComment?.(optimisticComment); try { const newCommentData = await newComment({ @@ -78,7 +78,7 @@ export const Toolbar = ({ type: "emoji", }); startTransition(() => { - onCommentSuccess(newCommentData); + onCommentSuccess?.(newCommentData); }); } catch (error) { console.error("Error posting comment:", error); @@ -107,7 +107,7 @@ export const Toolbar = ({ sending: true, }; - onOptimisticComment(optimisticComment); + onOptimisticComment?.(optimisticComment); try { const newCommentData = await newComment({ @@ -117,7 +117,7 @@ export const Toolbar = ({ type: "text", }); startTransition(() => { - onCommentSuccess(newCommentData); + onCommentSuccess?.(newCommentData); }); } catch (error) { console.error("Error posting comment:", error); diff --git a/apps/web/app/s/[videoId]/_components/tabs/Activity/Analytics.tsx b/apps/web/app/s/[videoId]/_components/tabs/Activity/Analytics.tsx index 814eb3a08f..436714a48b 100644 --- a/apps/web/app/s/[videoId]/_components/tabs/Activity/Analytics.tsx +++ b/apps/web/app/s/[videoId]/_components/tabs/Activity/Analytics.tsx @@ -9,6 +9,7 @@ const Analytics = (props: { videoId: string; views: MaybePromise; comments: CommentType[]; + isLoadingAnalytics: boolean; }) => { const [views, setViews] = useState( props.views instanceof Promise ? use(props.views) : props.views, @@ -40,6 +41,7 @@ const Analytics = (props: { return ( } diff --git a/apps/web/app/s/[videoId]/_components/video/media-player.tsx b/apps/web/app/s/[videoId]/_components/video/media-player.tsx index f5de1b2864..6114c8fc0b 100644 --- a/apps/web/app/s/[videoId]/_components/video/media-player.tsx +++ b/apps/web/app/s/[videoId]/_components/video/media-player.tsx @@ -120,18 +120,18 @@ function createStore( ): Store { const store: Store = { subscribe: (cb) => { - listenersRef.current.add(cb); - return () => listenersRef.current.delete(cb); + listenersRef.current?.add(cb); + return () => listenersRef.current?.delete(cb); }, - getState: () => stateRef.current, + getState: () => stateRef.current!, setState: (key, value) => { - if (Object.is(stateRef.current[key], value)) return; - stateRef.current[key] = value; + if (Object.is(stateRef.current?.[key], value)) return; + stateRef.current![key] = value; onValueChange?.[key]?.(value, store); store.notify(); }, notify: () => { - for (const cb of listenersRef.current) { + for (const cb of listenersRef.current ?? []) { cb(); } }, diff --git a/apps/web/app/s/[videoId]/page.tsx b/apps/web/app/s/[videoId]/page.tsx index d1725e78ce..80e63a7e7b 100644 --- a/apps/web/app/s/[videoId]/page.tsx +++ b/apps/web/app/s/[videoId]/page.tsx @@ -280,6 +280,11 @@ export default async function ShareVideoPage(props: Props) { skipProcessing: videos.skipProcessing, transcriptionStatus: videos.transcriptionStatus, source: videos.source, + width: videos.width, + height: videos.height, + duration: videos.duration, + fps: videos.fps, + hasPassword: sql`IF(${videos.password} IS NULL, 0, 1)`, sharedOrganization: { organizationId: sharedVideos.organizationId, }, @@ -334,6 +339,7 @@ async function AuthorizedContent({ }: { video: Omit, "folderId" | "password"> & { sharedOrganization: { organizationId: string } | null; + hasPassword: number; }; searchParams: { [key: string]: string | string[] | undefined }; }) { @@ -490,7 +496,7 @@ async function AuthorizedContent({ !currentMetadata.aiProcessing && !currentMetadata.summary && !currentMetadata.chapters && - !currentMetadata.generationError && + // !currentMetadata.generationError && aiGenerationEnabled ) { try { @@ -640,11 +646,11 @@ async function AuthorizedContent({ const videoWithOrganizationInfo: VideoWithOrganization = { ...video, + hasPassword: video.hasPassword === 1, organizationMembers: membersList.map((member) => member.userId), organizationId: video.sharedOrganization?.organizationId ?? undefined, sharedOrganizations: sharedOrganizations, password: null, - hasPassword: video.password !== null, folderId: null, }; @@ -667,7 +673,6 @@ async function AuthorizedContent({ sharedSpaces={sharedSpaces} userOrganizations={userOrganizations} spacesData={spacesData} - NODE_ENV={process.env.NODE_ENV} /> = memo( {videoDuration && (

- {formatDuration(videoDuration.toString())} + {formatDuration(videoDuration)}

)} {imageUrl.data && ( diff --git a/apps/web/components/tools/types.ts b/apps/web/components/tools/types.ts index 6ddf48db2b..c8ca7dbbbf 100644 --- a/apps/web/components/tools/types.ts +++ b/apps/web/components/tools/types.ts @@ -1,11 +1,11 @@ export interface ToolPageContent { - slug: string; + slug?: string; title: string; description: string; - publishedAt: string; - category: string; - author: string; - tags: string[]; + publishedAt?: string; + category?: string; + author?: string; + tags?: string[]; cta: { title: string; diff --git a/apps/web/lib/effect-react-query.ts b/apps/web/lib/effect-react-query.ts index 9c47937840..f9d0d651fd 100644 --- a/apps/web/lib/effect-react-query.ts +++ b/apps/web/lib/effect-react-query.ts @@ -246,7 +246,7 @@ export function makeUseEffectMutation( const runtime = useEffectRuntime(); const baseResults = useMutation({ - ...options, + ...(options as any), mutationFn: typeof mutationFn === "function" ? async (variables: TVariables) => { diff --git a/apps/web/lib/folder.ts b/apps/web/lib/folder.ts index 907a8daea2..ce55abdd93 100644 --- a/apps/web/lib/folder.ts +++ b/apps/web/lib/folder.ts @@ -113,10 +113,9 @@ async function getSharedSpacesForVideos(videoIds: string[]) { // Add space-level sharing spaceSharing.forEach((space) => { - if (!sharedSpacesMap[space.videoId]) { - sharedSpacesMap[space.videoId] = []; - } - sharedSpacesMap[space.videoId].push({ + const spaces = sharedSpacesMap[space.videoId] ?? []; + sharedSpacesMap[space.videoId] = spaces; + spaces.push({ id: space.id, name: space.name, organizationId: space.organizationId, @@ -127,10 +126,10 @@ async function getSharedSpacesForVideos(videoIds: string[]) { // Add organization-level sharing orgSharing.forEach((org) => { - if (!sharedSpacesMap[org.videoId]) { - sharedSpacesMap[org.videoId] = []; - } - sharedSpacesMap[org.videoId].push({ + const spaces = sharedSpacesMap[org.videoId] ?? []; + sharedSpacesMap[org.videoId] = spaces; + + spaces.push({ id: org.id, name: org.name, organizationId: org.organizationId, diff --git a/apps/web/scripts/reset-ai-processing-flags.ts b/apps/web/scripts/reset-ai-processing-flags.ts index a550d04772..b3ec488366 100644 --- a/apps/web/scripts/reset-ai-processing-flags.ts +++ b/apps/web/scripts/reset-ai-processing-flags.ts @@ -12,7 +12,7 @@ async function resetStuckAiProcessingFlags() { .select() .from(videos) .where(sql` - (metadata->>'aiProcessing')::boolean = true + (metadata->>'aiProcessing')::boolean = true AND updated_at < ${tenMinutesAgo} `); @@ -32,7 +32,7 @@ async function resetStuckAiProcessingFlags() { metadata: { ...metadata, aiProcessing: false, - generationError: "AI processing was stuck and has been reset", + // generationError: "AI processing was stuck and has been reset", }, }) .where(sql`id = ${video.id}`); diff --git a/apps/web/utils/changelog.ts b/apps/web/utils/changelog.ts index 781fe20e65..1527f1f305 100644 --- a/apps/web/utils/changelog.ts +++ b/apps/web/utils/changelog.ts @@ -14,11 +14,12 @@ function parseFrontmatter(fileContent: string) { const match = frontmatterRegex.exec(fileContent); const frontMatterBlock = match![1]; const content = fileContent.replace(frontmatterRegex, "").trim(); - const frontMatterLines = frontMatterBlock.trim().split("\n"); + const frontMatterLines = frontMatterBlock!.trim().split("\n"); const metadata: Partial = {}; frontMatterLines.forEach((line) => { const [key, ...valueArr] = line.split(": "); + if (!key) return; let value = valueArr.join(": ").trim(); value = value.replace(/^['"](.*)['"]$/, "$1"); // Remove quotes metadata[key.trim() as keyof ChangelogMetadata] = value; diff --git a/packages/database/schema.ts b/packages/database/schema.ts index db44f12312..21afc96f28 100644 --- a/packages/database/schema.ts +++ b/packages/database/schema.ts @@ -1,4 +1,4 @@ -import type { Folder } from "@cap/web-domain"; +import type { Folder, Video } from "@cap/web-domain"; import { boolean, customType, @@ -231,7 +231,7 @@ export const folders = mysqlTable( export const videos = mysqlTable( "videos", { - id: nanoId("id").notNull().primaryKey().unique(), + id: nanoId("id").notNull().primaryKey().unique().$type(), ownerId: nanoId("ownerId").notNull(), name: varchar("name", { length: 255 }).notNull().default("My Video"), bucket: nanoIdNullable("bucket"), diff --git a/packages/ui/src/components/Dropdown.tsx b/packages/ui/src/components/Dropdown.tsx index 290a5c6f6a..b764298b0d 100644 --- a/packages/ui/src/components/Dropdown.tsx +++ b/packages/ui/src/components/Dropdown.tsx @@ -57,9 +57,13 @@ DropdownMenuSubContent.displayName = const DropdownMenuContent = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, sideOffset = 4, ...props }, ref) => ( - + React.ComponentPropsWithoutRef & { + container?: React.ComponentPropsWithoutRef< + typeof DropdownMenuPrimitive.Portal + >["container"]; + } +>(({ className, sideOffset = 4, container, ...props }, ref) => ( +