Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions app/(api)/api/blob/confirm/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import mime from "mime-types";
import { eq } from "drizzle-orm";
import mime from "mime-types";
import { type NextRequest, NextResponse } from "next/server";
import { blob } from "@/drizzle/schema";
import { headObject } from "@/lib/blobStore";
Expand All @@ -17,10 +17,7 @@ export async function POST(request: NextRequest) {
const { fileId } = body as { fileId: string };

if (!fileId) {
return NextResponse.json(
{ error: "Missing fileId" },
{ status: 400 },
);
return NextResponse.json({ error: "Missing fileId" }, { status: 400 });
}

const db = database();
Expand Down
5 changes: 4 additions & 1 deletion app/(api)/api/blob/presign/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ export async function POST(request: NextRequest) {
}

if (!ALLOWED_TYPES.includes(contentType)) {
return NextResponse.json({ error: "File type not allowed" }, { status: 400 });
return NextResponse.json(
{ error: "File type not allowed" },
{ status: 400 },
);
}

if (contentSize > MAX_FILE_SIZE) {
Expand Down
4 changes: 2 additions & 2 deletions app/(api)/api/calendar/[ownerId]/[projectId]/route.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { calendarEvent, project, task, taskList, user } from "@/drizzle/schema";
import { database } from "@/lib/utils/useDatabase";
import { and, desc, eq, lte } from "drizzle-orm";
import ical, { ICalCalendarMethod } from "ical-generator";
import type { NextRequest } from "next/server";
import { calendarEvent, project, task, taskList, user } from "@/drizzle/schema";
import { database } from "@/lib/utils/useDatabase";

export const revalidate = 0;
export const dynamic = "force-dynamic";
Expand Down
39 changes: 39 additions & 0 deletions app/(api)/api/cron/blob-cleanup/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { and, eq, lt } from "drizzle-orm";
import { type NextRequest, NextResponse } from "next/server";
import { blob } from "@/drizzle/schema";
import { deleteFile } from "@/lib/blobStore";
import { database } from "@/lib/utils/useDatabase";

export async function GET(request: NextRequest) {
const authHeader = request.headers.get("authorization");
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}

const db = database();
const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000);

const stalePending = await db
.select()
.from(blob)
.where(and(eq(blob.status, "pending"), lt(blob.createdAt, oneHourAgo)));

const results = await Promise.allSettled(
stalePending.map(async (b) => {
await deleteFile(b.key);
await db.delete(blob).where(eq(blob.id, b.id));
return b.id;
}),
);

const deletedCount = results.filter((r) => r.status === "fulfilled").length;
const errors = results
.filter((r): r is PromiseRejectedResult => r.status === "rejected")
.map((r, i) => `Failed to delete blob ${stalePending[i].id}: ${r.reason}`);

return NextResponse.json({
found: stalePending.length,
deleted: deletedCount,
errors: errors.length > 0 ? errors : undefined,
});
}
2 changes: 1 addition & 1 deletion app/(api)/api/trpc/[trpc]/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
import { createTRPCContext } from "@/trpc/init";
import { appRouter } from "@/trpc/routers/_app";
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";

export const maxDuration = 60;
export const dynamic = "force-dynamic";
Expand Down
6 changes: 3 additions & 3 deletions app/(auth)/accept-invite/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
"use client";

import { useRouter, useSearchParams } from "next/navigation";
import { useState } from "react";
import { useSearchParams, useRouter } from "next/navigation";
import { toast } from "sonner";
import { OtpVerificationForm } from "@/components/auth/otp-verification-form";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { authClient, useSession } from "@/lib/auth/client";
import { toast } from "sonner";
import { OtpVerificationForm } from "@/components/auth/otp-verification-form";

export default function AcceptInvitePage() {
const router = useRouter();
Expand Down
12 changes: 6 additions & 6 deletions app/(auth)/sign-in/page.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
"use client";

import { Loader2, Mail } from "lucide-react";
import { useRouter, useSearchParams } from "next/navigation";
import { useState } from "react";
import { useSearchParams, useRouter } from "next/navigation";
import { toast } from "sonner";
import { OtpVerificationForm } from "@/components/auth/otp-verification-form";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { authClient } from "@/lib/auth/client";
import { toast } from "sonner";
import { Loader2, Mail } from "lucide-react";
import { OtpVerificationForm } from "@/components/auth/otp-verification-form";

export default function SignInPage() {
const router = useRouter();
Expand Down
4 changes: 2 additions & 2 deletions app/(dashboard)/[tenant]/projects/[projectId]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"use client";

import { TaskListsProvider } from "@/hooks/use-tasklist";
import { useProjectPrefetch } from "@/hooks/use-project-prefetch";
import { useParams } from "next/navigation";
import { useProjectPrefetch } from "@/hooks/use-project-prefetch";
import { TaskListsProvider } from "@/hooks/use-tasklist";

export default function Layout({ children }: { children: React.ReactNode }) {
const params = useParams();
Expand Down
10 changes: 5 additions & 5 deletions app/(dashboard)/[tenant]/projects/[projectId]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
"use client";

import { useMutation, useQueries, useQueryClient } from "@tanstack/react-query";
import { CalendarIcon, ListIcon } from "lucide-react";
import Link from "next/link";
import { useParams, useRouter } from "next/navigation";
import EmptyState from "@/components/core/empty-state";
import { PageLoading } from "@/components/core/loaders";
import PageSection from "@/components/core/section";
Expand All @@ -11,14 +15,10 @@ import { CommentsSection } from "@/components/project/comment/comments-section";
import WeekCalendar from "@/components/project/events/week-calendar";
import { TaskListHeader } from "@/components/project/tasklist/tasklist-header";
import { buttonVariants } from "@/components/ui/button";
import { TaskStatus } from "@/drizzle/types";
import { toStartOfDay } from "@/lib/utils/date";
import { displayMutationError } from "@/lib/utils/error";
import { useTRPC } from "@/trpc/client";
import { useMutation, useQueries, useQueryClient } from "@tanstack/react-query";
import { CalendarIcon, ListIcon } from "lucide-react";
import Link from "next/link";
import { useParams, useRouter } from "next/navigation";
import { TaskStatus } from "@/drizzle/types";

export default function ProjectDetails() {
const router = useRouter();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
"use client";

import { useQuery } from "@tanstack/react-query";
import { Settings2, Shield } from "lucide-react";
import { useParams } from "next/navigation";
import { PageLoading } from "@/components/core/loaders";
import PermissionsManagement from "@/components/core/permissions-management";
import PageSection from "@/components/core/section";
import PageTitle from "@/components/layout/page-title";
import { useTRPC } from "@/trpc/client";
import { useQuery } from "@tanstack/react-query";
import { Shield, Settings2 } from "lucide-react";
import { useParams } from "next/navigation";

export default function ProjectSettings() {
const params = useParams();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
"use client";

import { useQueries } from "@tanstack/react-query";
import { useParams } from "next/navigation";
import { parseAsBoolean, useQueryState } from "nuqs";
import { PageLoading } from "@/components/core/loaders";
import PageSection from "@/components/core/section";
import { ConfirmButton } from "@/components/form/button";
Expand All @@ -13,9 +16,6 @@ import { useTaskLists } from "@/hooks/use-tasklist";
import { TasksProvider } from "@/hooks/use-tasks";
import { toStartOfDay } from "@/lib/utils/date";
import { useTRPC } from "@/trpc/client";
import { useQueries } from "@tanstack/react-query";
import { useParams } from "next/navigation";
import { parseAsBoolean, useQueryState } from "nuqs";

export default function TaskLists() {
const { projectId, tasklistId } = useParams();
Expand Down
10 changes: 5 additions & 5 deletions app/(dashboard)/[tenant]/projects/[projectId]/tasklists/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
"use client";

import { Title } from "@radix-ui/react-dialog";
import { useQuery } from "@tanstack/react-query";
import Link from "next/link";
import { useParams } from "next/navigation";
import { parseAsBoolean, useQueryState } from "nuqs";
import EmptyState from "@/components/core/empty-state";
import { Panel } from "@/components/core/panel";
import PageSection from "@/components/core/section";
Expand All @@ -12,11 +17,6 @@ import { TaskListStatus } from "@/drizzle/types";
import { useTaskLists } from "@/hooks/use-tasklist";
import { TasksProvider } from "@/hooks/use-tasks";
import { useTRPC } from "@/trpc/client";
import { Title } from "@radix-ui/react-dialog";
import { useQuery } from "@tanstack/react-query";
import Link from "next/link";
import { useParams } from "next/navigation";
import { parseAsBoolean, useQueryState } from "nuqs";

export default function TaskLists() {
const { projectId, tenant } = useParams();
Expand Down
2 changes: 1 addition & 1 deletion app/api/auth/[...all]/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";
import { auth } from "@/lib/auth";

export const { GET, POST } = toNextJsHandler(auth);
12 changes: 2 additions & 10 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,7 @@ export default async function Home() {
href="https://railway.com/deploy/manage"
className="inline-flex items-center gap-2 px-6 py-3 rounded-full text-lg font-semibold bg-violet-600 text-white shadow-sm shadow-violet-600/25 border-b-4 border-violet-700 hover:bg-violet-500 hover:border-violet-600 active:border-violet-600 active:shadow-sm active:translate-y-0.5 transition-all duration-150"
>
<svg
className="w-5 h-5"
viewBox="0 0 1024 1024"
fill="none"
>
<svg className="w-5 h-5" viewBox="0 0 1024 1024" fill="none">
<path
d="M4.756 438.175A520.713 520.713 0 0 0 0 489.735h777.799c-2.716-5.306-6.365-10.09-10.045-14.772-132.97-171.791-204.498-156.896-306.819-161.26-34.114-1.403-57.249-1.967-193.037-1.967-72.677 0-151.688.185-228.628.39-9.96 26.884-19.566 52.942-24.243 74.14h398.571v51.909H4.756ZM783.93 541.696H.399c.82 13.851 2.112 27.517 3.978 40.999h723.39c32.248 0 50.299-18.297 56.162-40.999ZM45.017 724.306S164.941 1018.77 511.46 1024c207.112 0 385.071-123.006 465.907-299.694H45.017Z"
fill="currentColor"
Expand Down Expand Up @@ -309,11 +305,7 @@ export default async function Home() {
href="https://railway.com/deploy/manage"
className="inline-flex items-center gap-2 px-6 py-3 rounded-full font-semibold bg-violet-600 text-white shadow-sm shadow-violet-600/25 border-b-4 border-violet-700 hover:bg-violet-500 hover:border-violet-600 active:border-violet-600 active:shadow-sm active:translate-y-0.5 transition-all duration-150"
>
<svg
className="w-5 h-5"
viewBox="0 0 1024 1024"
fill="none"
>
<svg className="w-5 h-5" viewBox="0 0 1024 1024" fill="none">
<path
d="M4.756 438.175A520.713 520.713 0 0 0 0 489.735h777.799c-2.716-5.306-6.365-10.09-10.045-14.772-132.97-171.791-204.498-156.896-306.819-161.26-34.114-1.403-57.249-1.967-193.037-1.967-72.677 0-151.688.185-228.628.39-9.96 26.884-19.566 52.942-24.243 74.14h398.571v51.909H4.756ZM783.93 541.696H.399c.82 13.851 2.112 27.517 3.978 40.999h723.39c32.248 0 50.299-18.297 56.162-40.999ZM45.017 724.306S164.941 1018.77 511.46 1024c207.112 0 385.071-123.006 465.907-299.694H45.017Z"
fill="currentColor"
Expand Down
4 changes: 2 additions & 2 deletions components/auth/otp-verification-form.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
"use client";

import { useState } from "react";
import { Button } from "@/components/ui/button";
import { authClient } from "@/lib/auth/client";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import {
InputOTP,
InputOTPGroup,
InputOTPSlot,
} from "@/components/ui/input-otp";
import { authClient } from "@/lib/auth/client";

interface OtpVerificationFormProps {
email: string;
Expand Down
2 changes: 1 addition & 1 deletion components/core/cmd-menu.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"use client";

import { useTRPC } from "@/trpc/client";
import { useQueries } from "@tanstack/react-query";
import { Calendar, Menu, Plus, Settings } from "lucide-react";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { useTRPC } from "@/trpc/client";
import { Button } from "../ui/button";
import {
CommandDialog,
Expand Down
2 changes: 1 addition & 1 deletion components/core/search-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { useRouter } from "next/navigation";
import { useCallback, useEffect, useState } from "react";
import { useDebounce } from "use-debounce";
import { HtmlPreview } from "@/components/core/html-view";
import { Panel } from "@/components/core/panel";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Expand All @@ -30,7 +31,6 @@ import {
import { Input } from "@/components/ui/input";
import { cn } from "@/lib/utils";
import { useTRPC } from "@/trpc/client";
import { Panel } from "@/components/core/panel";

interface SearchResult {
id: string;
Expand Down
2 changes: 1 addition & 1 deletion components/editor/mention-suggestion-menu.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { UserAvatar } from "@/components/core/user-avatar";
import type {
DefaultReactSuggestionItem,
SuggestionMenuProps,
} from "@blocknote/react";
import { UserAvatar } from "@/components/core/user-avatar";

interface User {
id: string;
Expand Down
2 changes: 1 addition & 1 deletion components/form/editable-date.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"use client";

import { toDateStringWithDay } from "@/lib/utils/date";
import { Check, ClockIcon, TrashIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { toDateStringWithDay } from "@/lib/utils/date";
import { DateTimePicker } from "../project/events/date-time-picker";

export default function EditableDate({
Expand Down
10 changes: 5 additions & 5 deletions components/form/event.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
"use client";

import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useParams } from "next/navigation";
import { parseAsBoolean, useQueryState } from "nuqs";
import { type Dispatch, memo, type SetStateAction, useState } from "react";
import { type Frequency, RRule, rrulestr } from "rrule";
import { Input } from "@/components/ui/input";
import type { EventWithCreator } from "@/drizzle/types";
import { toStartOfHour } from "@/lib/utils/date";
import { displayMutationError } from "@/lib/utils/error";
import { useTRPC } from "@/trpc/client";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useParams } from "next/navigation";
import { parseAsBoolean, useQueryState } from "nuqs";
import { type Dispatch, type SetStateAction, memo, useState } from "react";
import { type Frequency, RRule, rrulestr } from "rrule";
import Editor from "../editor";
import { DateTimePicker } from "../project/events/date-time-picker";
import { Button } from "../ui/button";
Expand Down
10 changes: 9 additions & 1 deletion components/form/notes-form.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use client";

import type { PartialBlock } from "@blocknote/core";
import { Edit } from "lucide-react";
import { useEffect, useState } from "react";
import { useFormStatus } from "react-dom";
Expand All @@ -11,9 +12,11 @@ import { Spinner } from "../core/loaders";
export default function NotesForm({
value,
name,
metadata,
}: {
value: string | null | undefined;
name: string;
metadata?: PartialBlock[] | undefined;
}) {
const { pending } = useFormStatus();
const [isEditing, setIsEditing] = useState(false);
Expand All @@ -27,7 +30,12 @@ export default function NotesForm({
if (isEditing)
return (
<div className="flex-grow">
<Editor defaultValue={value ?? ""} name={name} allowImageUpload />
<Editor
defaultValue={value ?? ""}
name={name}
metadata={metadata}
allowImageUpload
/>
<div className="mt-2">
<Button
type="button"
Expand Down
2 changes: 1 addition & 1 deletion components/form/shared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export default function SharedForm({
<div className="mt-2 max-w-xs sm:col-span-2 sm:mt-0">
<DateTimePicker
name="dueDate"
// @ts-ignore
// @ts-expect-error
defaultValue={item?.dueDate}
dateOnly
/>
Expand Down
Loading