Biome: fixes for app/dashboard/search_pace_id pages

This commit is contained in:
Utkarsh-Patel-13 2025-07-27 11:46:34 -07:00
parent 07063a1a18
commit ecc4c11100
22 changed files with 472 additions and 480 deletions

View file

@ -1,25 +1,23 @@
"use client"; "use client";
import { useState, useEffect } from "react"; import { format } from "date-fns";
import { motion, AnimatePresence } from "framer-motion"; import { AnimatePresence, motion, type Variants } from "framer-motion";
import { useSearchParams } from "next/navigation";
import { import {
MessageCircleMore,
Search,
Calendar, Calendar,
Tag,
Trash2,
ExternalLink,
MoreHorizontal,
Radio,
CheckCircle, CheckCircle,
Circle, Circle,
ExternalLink,
MessageCircleMore,
MoreHorizontal,
Podcast, Podcast,
Search,
Tag,
Trash2,
} from "lucide-react"; } from "lucide-react";
import { format } from "date-fns"; import { useRouter, useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";
// UI Components import { toast } from "sonner";
import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {
Card, Card,
@ -29,22 +27,6 @@ import {
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "@/components/ui/card"; } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
DropdownMenuSeparator,
} from "@/components/ui/dropdown-menu";
import {
Pagination,
PaginationContent,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination";
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@ -53,6 +35,24 @@ import {
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
// UI Components
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Pagination,
PaginationContent,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination";
import { import {
Select, Select,
SelectContent, SelectContent,
@ -61,9 +61,6 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
import { toast } from "sonner";
interface Chat { interface Chat {
created_at: string; created_at: string;
@ -86,13 +83,13 @@ interface ChatsPageClientProps {
searchSpaceId: string; searchSpaceId: string;
} }
const pageVariants = { const pageVariants: Variants = {
initial: { opacity: 0 }, initial: { opacity: 0 },
enter: { opacity: 1, transition: { duration: 0.3, ease: "easeInOut" } }, enter: { opacity: 1, transition: { duration: 0.3, ease: "easeInOut" } },
exit: { opacity: 0, transition: { duration: 0.3, ease: "easeInOut" } }, exit: { opacity: 0, transition: { duration: 0.3, ease: "easeInOut" } },
}; };
const chatCardVariants = { const chatCardVariants: Variants = {
initial: { y: 20, opacity: 0 }, initial: { y: 20, opacity: 0 },
animate: { y: 0, opacity: 1 }, animate: { y: 0, opacity: 1 },
exit: { y: -20, opacity: 0 }, exit: { y: -20, opacity: 0 },
@ -101,6 +98,7 @@ const chatCardVariants = {
const MotionCard = motion(Card); const MotionCard = motion(Card);
export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps) { export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps) {
const router = useRouter();
const [chats, setChats] = useState<Chat[]>([]); const [chats, setChats] = useState<Chat[]>([]);
const [filteredChats, setFilteredChats] = useState<Chat[]>([]); const [filteredChats, setFilteredChats] = useState<Chat[]>([]);
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
@ -134,7 +132,7 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
const pageParam = searchParams.get("page"); const pageParam = searchParams.get("page");
if (pageParam) { if (pageParam) {
const pageNumber = parseInt(pageParam, 10); const pageNumber = parseInt(pageParam, 10);
if (!isNaN(pageNumber) && pageNumber > 0) { if (!Number.isNaN(pageNumber) && pageNumber > 0) {
setCurrentPage(pageNumber); setCurrentPage(pageNumber);
} }
} }
@ -318,7 +316,7 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
throw new Error(errorData.detail || "Failed to generate podcast"); throw new Error(errorData.detail || "Failed to generate podcast");
} }
const data = await response.json(); const _data = await response.json();
toast.success(`Podcast "${currentTitle}" generation started!`); toast.success(`Podcast "${currentTitle}" generation started!`);
// Move to the next chat or finish // Move to the next chat or finish
@ -636,7 +634,9 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
<DropdownMenuContent align="end"> <DropdownMenuContent align="end">
<DropdownMenuItem <DropdownMenuItem
onClick={() => onClick={() =>
(window.location.href = `/dashboard/${chat.search_space_id}/researcher/${chat.id}`) router.push(
`/dashboard/${chat.search_space_id}/researcher/${chat.id}`
)
} }
> >
<ExternalLink className="mr-2 h-4 w-4" /> <ExternalLink className="mr-2 h-4 w-4" />
@ -841,10 +841,7 @@ export default function ChatsPageClient({ searchSpaceId }: ChatsPageClientProps)
</span> </span>
</> </>
) : ( ) : (
<> "Create a podcast from this chat. The podcast will be available in the podcasts section once generated."
Create a podcast from this chat. The podcast will be available in the podcasts
section once generated.
</>
)} )}
</DialogDescription> </DialogDescription>
</DialogHeader> </DialogHeader>

View file

@ -1,10 +1,10 @@
"use client"; "use client";
import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar";
import { ThemeTogglerComponent } from "@/components/theme/theme-toggle";
import type React from "react"; import type React from "react";
import { Separator } from "@/components/ui/separator";
import { AppSidebarProvider } from "@/components/sidebar/AppSidebarProvider"; import { AppSidebarProvider } from "@/components/sidebar/AppSidebarProvider";
import { ThemeTogglerComponent } from "@/components/theme/theme-toggle";
import { Separator } from "@/components/ui/separator";
import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar";
export function DashboardClientLayout({ export function DashboardClientLayout({
children, children,

View file

@ -1,22 +1,12 @@
"use client"; "use client";
import { useState, useEffect } from "react"; import { format } from "date-fns";
import { useRouter, useParams } from "next/navigation";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { Calendar as CalendarIcon, Edit, Plus, RefreshCw, Trash2 } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { Edit, Plus, Trash2, RefreshCw, Calendar as CalendarIcon } from "lucide-react"; import { getConnectorIcon } from "@/components/chat";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { import {
AlertDialog, AlertDialog,
AlertDialogAction, AlertDialogAction,
@ -28,7 +18,9 @@ import {
AlertDialogTitle, AlertDialogTitle,
AlertDialogTrigger, AlertDialogTrigger,
} from "@/components/ui/alert-dialog"; } from "@/components/ui/alert-dialog";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@ -36,14 +28,20 @@ import {
DialogFooter, DialogFooter,
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { Calendar } from "@/components/ui/calendar";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { getConnectorIcon } from "@/components/chat"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { format } from "date-fns";
// Helper function to format date with time // Helper function to format date with time
const formatDateTime = (dateString: string | null): string => { const formatDateTime = (dateString: string | null): string => {

View file

@ -1,12 +1,15 @@
"use client"; "use client";
import React, { useEffect } from "react";
import { useRouter, useParams } from "next/navigation";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { ArrowLeft, Check, Loader2 } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useEffect } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { ArrowLeft, Check, Loader2, Github } from "lucide-react"; import { getConnectorIcon } from "@/components/chat";
import { EditConnectorLoadingSkeleton } from "@/components/editConnector/EditConnectorLoadingSkeleton";
import { Form } from "@/components/ui/form"; import { EditConnectorNameForm } from "@/components/editConnector/EditConnectorNameForm";
import { EditGitHubConnectorConfig } from "@/components/editConnector/EditGitHubConnectorConfig";
import { EditSimpleTokenForm } from "@/components/editConnector/EditSimpleTokenForm";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {
Card, Card,
@ -16,15 +19,10 @@ import {
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "@/components/ui/card"; } from "@/components/ui/card";
import { Form } from "@/components/ui/form";
import { useConnectorEditPage } from "@/hooks/useConnectorEditPage";
// Import Utils, Types, Hook, and Components // Import Utils, Types, Hook, and Components
import { getConnectorTypeDisplay } from "@/lib/connectors/utils"; import { getConnectorTypeDisplay } from "@/lib/connectors/utils";
import { useConnectorEditPage } from "@/hooks/useConnectorEditPage";
import { EditConnectorLoadingSkeleton } from "@/components/editConnector/EditConnectorLoadingSkeleton";
import { EditConnectorNameForm } from "@/components/editConnector/EditConnectorNameForm";
import { EditGitHubConnectorConfig } from "@/components/editConnector/EditGitHubConnectorConfig";
import { EditSimpleTokenForm } from "@/components/editConnector/EditSimpleTokenForm";
import { getConnectorIcon } from "@/components/chat";
export default function EditConnectorPage() { export default function EditConnectorPage() {
const router = useRouter(); const router = useRouter();
@ -58,7 +56,7 @@ export default function EditConnectorPage() {
// Redirect if connectorId is not a valid number after parsing // Redirect if connectorId is not a valid number after parsing
useEffect(() => { useEffect(() => {
if (isNaN(connectorId)) { if (Number.isNaN(connectorId)) {
toast.error("Invalid Connector ID."); toast.error("Invalid Connector ID.");
router.push(`/dashboard/${searchSpaceId}/connectors`); router.push(`/dashboard/${searchSpaceId}/connectors`);
} }
@ -67,7 +65,7 @@ export default function EditConnectorPage() {
// Loading State // Loading State
if (connectorsLoading || !connector) { if (connectorsLoading || !connector) {
// Handle NaN case before showing skeleton // Handle NaN case before showing skeleton
if (isNaN(connectorId)) return null; if (Number.isNaN(connectorId)) return null;
return <EditConnectorLoadingSkeleton />; return <EditConnectorLoadingSkeleton />;
} }

View file

@ -1,18 +1,16 @@
"use client"; "use client";
import { useState, useEffect } from "react";
import { useRouter, useParams } from "next/navigation";
import { motion } from "framer-motion";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form"; import { motion } from "framer-motion";
import * as z from "zod";
import { toast } from "sonner";
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react"; import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { import { useEffect, useState } from "react";
useSearchSourceConnectors, import { useForm } from "react-hook-form";
type SearchSourceConnector, import { toast } from "sonner";
} from "@/hooks/useSearchSourceConnectors"; import * as z from "zod";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { import {
Form, Form,
FormControl, FormControl,
@ -23,9 +21,10 @@ import {
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button"; import {
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; type SearchSourceConnector,
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; useSearchSourceConnectors,
} from "@/hooks/useSearchSourceConnectors";
// Define the form schema with Zod // Define the form schema with Zod
const apiConnectorFormSchema = z.object({ const apiConnectorFormSchema = z.object({
@ -57,6 +56,20 @@ const getConnectorTypeDisplay = (type: string): string => {
// Define the type for the form values // Define the type for the form values
type ApiConnectorFormValues = z.infer<typeof apiConnectorFormSchema>; type ApiConnectorFormValues = z.infer<typeof apiConnectorFormSchema>;
// Get API key field name based on connector type
const getApiKeyFieldName = (connectorType: string): string => {
const fieldMap: Record<string, string> = {
SERPER_API: "SERPER_API_KEY",
TAVILY_API: "TAVILY_API_KEY",
SLACK_CONNECTOR: "SLACK_BOT_TOKEN",
NOTION_CONNECTOR: "NOTION_INTEGRATION_TOKEN",
GITHUB_CONNECTOR: "GITHUB_PAT",
DISCORD_CONNECTOR: "DISCORD_BOT_TOKEN",
LINKUP_API: "LINKUP_API_KEY",
};
return fieldMap[connectorType] || "";
};
export default function EditConnectorPage() { export default function EditConnectorPage() {
const router = useRouter(); const router = useRouter();
const params = useParams(); const params = useParams();
@ -77,20 +90,6 @@ export default function EditConnectorPage() {
}, },
}); });
// Get API key field name based on connector type
const getApiKeyFieldName = (connectorType: string): string => {
const fieldMap: Record<string, string> = {
SERPER_API: "SERPER_API_KEY",
TAVILY_API: "TAVILY_API_KEY",
SLACK_CONNECTOR: "SLACK_BOT_TOKEN",
NOTION_CONNECTOR: "NOTION_INTEGRATION_TOKEN",
GITHUB_CONNECTOR: "GITHUB_PAT",
DISCORD_CONNECTOR: "DISCORD_BOT_TOKEN",
LINKUP_API: "LINKUP_API_KEY",
};
return fieldMap[connectorType] || "";
};
// Find connector in the list // Find connector in the list
useEffect(() => { useEffect(() => {
const currentConnector = connectors.find((c) => c.id === connectorId); const currentConnector = connectors.find((c) => c.id === connectorId);

View file

@ -1,15 +1,29 @@
"use client"; "use client";
import { useState } from "react";
import { useRouter, useParams } from "next/navigation";
import { motion } from "framer-motion";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form"; import { motion } from "framer-motion";
import * as z from "zod";
import { toast } from "sonner";
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react"; import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors"; import { useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import * as z from "zod";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { import {
Form, Form,
FormControl, FormControl,
@ -20,23 +34,8 @@ import {
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors";
// Define the form schema with Zod // Define the form schema with Zod
const discordConnectorFormSchema = z.object({ const discordConnectorFormSchema = z.object({

View file

@ -1,16 +1,30 @@
"use client"; "use client";
import { useState } from "react";
import { useRouter, useParams } from "next/navigation";
import { motion } from "framer-motion";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { motion } from "framer-motion";
import { ArrowLeft, Check, CircleAlert, Github, Info, ListChecks, Loader2 } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import * as z from "zod";
import { toast } from "sonner"; import { toast } from "sonner";
import { ArrowLeft, Check, Info, Loader2, Github, CircleAlert, ListChecks } from "lucide-react"; import * as z from "zod";
import {
// Assuming useSearchSourceConnectors hook exists and works similarly Accordion,
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors"; AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import { import {
Form, Form,
FormControl, FormControl,
@ -21,24 +35,9 @@ import {
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Checkbox } from "@/components/ui/checkbox"; // Assuming useSearchSourceConnectors hook exists and works similarly
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors";
// Define the form schema with Zod for GitHub PAT entry step // Define the form schema with Zod for GitHub PAT entry step
const githubPatFormSchema = z.object({ const githubPatFormSchema = z.object({

View file

@ -1,15 +1,29 @@
"use client"; "use client";
import { useState } from "react";
import { useRouter, useParams } from "next/navigation";
import { motion } from "framer-motion";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form"; import { motion } from "framer-motion";
import * as z from "zod";
import { toast } from "sonner";
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react"; import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors"; import { useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import * as z from "zod";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { import {
Form, Form,
FormControl, FormControl,
@ -20,23 +34,8 @@ import {
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors";
// Define the form schema with Zod // Define the form schema with Zod
const jiraConnectorFormSchema = z.object({ const jiraConnectorFormSchema = z.object({

View file

@ -1,15 +1,29 @@
"use client"; "use client";
import { useState } from "react";
import { useRouter, useParams } from "next/navigation";
import { motion } from "framer-motion";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form"; import { motion } from "framer-motion";
import * as z from "zod";
import { toast } from "sonner";
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react"; import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors"; import { useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import * as z from "zod";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { import {
Form, Form,
FormControl, FormControl,
@ -20,23 +34,8 @@ import {
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors";
// Define the form schema with Zod // Define the form schema with Zod
const linearConnectorFormSchema = z.object({ const linearConnectorFormSchema = z.object({

View file

@ -1,15 +1,23 @@
"use client"; "use client";
import { useState } from "react";
import { useRouter, useParams } from "next/navigation";
import { motion } from "framer-motion";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form"; import { motion } from "framer-motion";
import * as z from "zod";
import { toast } from "sonner";
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react"; import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors"; import { useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import * as z from "zod";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { import {
Form, Form,
FormControl, FormControl,
@ -20,16 +28,7 @@ import {
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button"; import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
// Define the form schema with Zod // Define the form schema with Zod
const linkupApiFormSchema = z.object({ const linkupApiFormSchema = z.object({

View file

@ -1,15 +1,29 @@
"use client"; "use client";
import { useState } from "react";
import { useRouter, useParams } from "next/navigation";
import { motion } from "framer-motion";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form"; import { motion } from "framer-motion";
import * as z from "zod";
import { toast } from "sonner";
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react"; import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors"; import { useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import * as z from "zod";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { import {
Form, Form,
FormControl, FormControl,
@ -20,23 +34,8 @@ import {
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors";
// Define the form schema with Zod // Define the form schema with Zod
const notionConnectorFormSchema = z.object({ const notionConnectorFormSchema = z.object({

View file

@ -1,8 +1,4 @@
"use client"; "use client";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardFooter, CardHeader } from "@/components/ui/card";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
import { import {
IconBrandDiscord, IconBrandDiscord,
IconBrandGithub, IconBrandGithub,
@ -12,16 +8,20 @@ import {
IconBrandZoom, IconBrandZoom,
IconChevronDown, IconChevronDown,
IconChevronRight, IconChevronRight,
IconMail,
IconWorldWww,
IconTicket,
IconLayoutKanban, IconLayoutKanban,
IconLinkPlus, IconLinkPlus,
IconMail,
IconTicket,
IconWorldWww,
} from "@tabler/icons-react"; } from "@tabler/icons-react";
import { AnimatePresence, motion } from "framer-motion"; import { AnimatePresence, motion } from "framer-motion";
import Link from "next/link"; import Link from "next/link";
import { useParams } from "next/navigation"; import { useParams } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardFooter, CardHeader } from "@/components/ui/card";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
// Define the Connector type // Define the Connector type
interface Connector { interface Connector {

View file

@ -1,15 +1,23 @@
"use client"; "use client";
import { useState } from "react";
import { useRouter, useParams } from "next/navigation";
import { motion } from "framer-motion";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form"; import { motion } from "framer-motion";
import * as z from "zod";
import { toast } from "sonner";
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react"; import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors"; import { useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import * as z from "zod";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { import {
Form, Form,
FormControl, FormControl,
@ -20,16 +28,7 @@ import {
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button"; import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
// Define the form schema with Zod // Define the form schema with Zod
const serperApiFormSchema = z.object({ const serperApiFormSchema = z.object({

View file

@ -1,15 +1,29 @@
"use client"; "use client";
import { useState } from "react";
import { useRouter, useParams } from "next/navigation";
import { motion } from "framer-motion";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form"; import { motion } from "framer-motion";
import * as z from "zod";
import { toast } from "sonner";
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react"; import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors"; import { useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import * as z from "zod";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { import {
Form, Form,
FormControl, FormControl,
@ -20,23 +34,8 @@ import {
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors";
// Define the form schema with Zod // Define the form schema with Zod
const slackConnectorFormSchema = z.object({ const slackConnectorFormSchema = z.object({

View file

@ -1,15 +1,23 @@
"use client"; "use client";
import { useState } from "react";
import { useRouter, useParams } from "next/navigation";
import { motion } from "framer-motion";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form"; import { motion } from "framer-motion";
import * as z from "zod";
import { toast } from "sonner";
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react"; import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors"; import { useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import * as z from "zod";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { import {
Form, Form,
FormControl, FormControl,
@ -20,16 +28,7 @@ import {
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button"; import { useSearchSourceConnectors } from "@/hooks/useSearchSourceConnectors";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
// Define the form schema with Zod // Define the form schema with Zod
const tavilyApiFormSchema = z.object({ const tavilyApiFormSchema = z.object({

View file

@ -1,5 +1,57 @@
"use client"; "use client";
import {
IconBrandDiscord,
IconBrandGithub,
IconBrandNotion,
IconBrandSlack,
IconBrandYoutube,
IconLayoutKanban,
IconTicket,
} from "@tabler/icons-react";
import {
type ColumnDef,
type ColumnFiltersState,
flexRender,
getCoreRowModel,
getFacetedUniqueValues,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
type PaginationState,
type Row,
type SortingState,
useReactTable,
type VisibilityState,
} from "@tanstack/react-table";
import { AnimatePresence, motion, type Variants } from "framer-motion";
import {
AlertCircle,
ChevronDown,
ChevronFirst,
ChevronLast,
ChevronLeft,
ChevronRight,
ChevronUp,
CircleAlert,
CircleX,
Columns3,
File,
FileX,
Filter,
Globe,
ListFilter,
MoreHorizontal,
Trash,
Webhook,
} from "lucide-react";
import { useParams } from "next/navigation";
import React, { useContext, useEffect, useId, useMemo, useRef, useState } from "react";
import ReactMarkdown from "react-markdown";
import rehypeRaw from "rehype-raw";
import rehypeSanitize from "rehype-sanitize";
import remarkGfm from "remark-gfm";
import { toast } from "sonner";
import { DocumentViewer } from "@/components/document-viewer"; import { DocumentViewer } from "@/components/document-viewer";
import { JsonMetadataViewer } from "@/components/json-metadata-viewer"; import { JsonMetadataViewer } from "@/components/json-metadata-viewer";
import { import {
@ -43,64 +95,12 @@ import {
TableHeader, TableHeader,
TableRow, TableRow,
} from "@/components/ui/table"; } from "@/components/ui/table";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { useDocuments } from "@/hooks/use-documents"; import { useDocuments } from "@/hooks/use-documents";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import {
IconBrandDiscord,
IconBrandGithub,
IconBrandNotion,
IconBrandSlack,
IconBrandYoutube,
IconLayoutKanban,
IconTicket,
} from "@tabler/icons-react";
import {
type ColumnDef,
type ColumnFiltersState,
type FilterFn,
type PaginationState,
type Row,
type SortingState,
type VisibilityState,
flexRender,
getCoreRowModel,
getFacetedUniqueValues,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { AnimatePresence, motion } from "framer-motion";
import {
AlertCircle,
ChevronDown,
ChevronFirst,
ChevronLast,
ChevronLeft,
ChevronRight,
ChevronUp,
CircleAlert,
CircleX,
Columns3,
File,
FileX,
Filter,
Globe,
ListFilter,
MoreHorizontal,
Trash,
Webhook,
} from "lucide-react";
import { useParams } from "next/navigation";
import React, { useContext, useEffect, useId, useMemo, useRef, useState } from "react";
import ReactMarkdown from "react-markdown";
import rehypeRaw from "rehype-raw";
import rehypeSanitize from "rehype-sanitize";
import remarkGfm from "remark-gfm";
import { toast } from "sonner";
// Define animation variants for reuse // Define animation variants for reuse
const fadeInScale = { const fadeInScale: Variants = {
hidden: { opacity: 0, scale: 0.95 }, hidden: { opacity: 0, scale: 0.95 },
visible: { visible: {
opacity: 1, opacity: 1,
@ -132,19 +132,6 @@ type Document = {
search_space_id: number; search_space_id: number;
}; };
// Custom filter function for multi-column searching
const multiColumnFilterFn: FilterFn<Document> = (row, columnId, filterValue) => {
const searchableRowContent = `${row.original.title}`.toLowerCase();
const searchTerm = (filterValue ?? "").toLowerCase();
return searchableRowContent.includes(searchTerm);
};
const statusFilterFn: FilterFn<Document> = (row, columnId, filterValue: string[]) => {
if (!filterValue?.length) return true;
const status = row.getValue(columnId) as string;
return filterValue.includes(status);
};
// Add document type icons mapping // Add document type icons mapping
const documentTypeIcons = { const documentTypeIcons = {
EXTENSION: Webhook, EXTENSION: Webhook,
@ -187,6 +174,8 @@ const columns: ColumnDef<Document>[] = [
accessorKey: "title", accessorKey: "title",
cell: ({ row }) => { cell: ({ row }) => {
const Icon = documentTypeIcons[row.original.document_type]; const Icon = documentTypeIcons[row.original.document_type];
const title = row.getValue("title") as string;
const truncatedTitle = title.length > 30 ? `${title.slice(0, 30)}...` : title;
return ( return (
<motion.div <motion.div
className="flex items-center gap-2 font-medium" className="flex items-center gap-2 font-medium"
@ -194,8 +183,17 @@ const columns: ColumnDef<Document>[] = [
transition={{ type: "spring", stiffness: 300 }} transition={{ type: "spring", stiffness: 300 }}
style={{ display: "flex" }} style={{ display: "flex" }}
> >
<Icon size={16} className="text-muted-foreground shrink-0" /> <Tooltip>
<span>{row.getValue("title")}</span> <TooltipTrigger asChild>
<span className="flex items-center gap-2">
<Icon size={16} className="text-muted-foreground shrink-0" />
<span>{truncatedTitle}</span>
</span>
</TooltipTrigger>
<TooltipContent>
<p>{title}</p>
</TooltipContent>
</Tooltip>
</motion.div> </motion.div>
); );
}, },
@ -231,7 +229,7 @@ const columns: ColumnDef<Document>[] = [
const title = row.getValue("title") as string; const title = row.getValue("title") as string;
// Create a truncated preview (first 150 characters) // Create a truncated preview (first 150 characters)
const previewContent = content.length > 150 ? content.substring(0, 150) + "..." : content; const previewContent = content.length > 150 ? `${content.substring(0, 150)}...` : content;
return ( return (
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
@ -336,7 +334,7 @@ export default function DocumentsTable() {
useEffect(() => { useEffect(() => {
if (documents) { if (documents) {
setData(documents); setData(documents as Document[]);
} }
}, [documents]); }, [documents]);
@ -408,19 +406,19 @@ export default function DocumentsTable() {
const values = Array.from(statusColumn.getFacetedUniqueValues().keys()); const values = Array.from(statusColumn.getFacetedUniqueValues().keys());
return values.sort(); return values.sort();
}, [table.getColumn("document_type")?.getFacetedUniqueValues()]); }, [table.getColumn]);
// Get counts for each status // Get counts for each status
const statusCounts = useMemo(() => { const statusCounts = useMemo(() => {
const statusColumn = table.getColumn("document_type"); const statusColumn = table.getColumn("document_type");
if (!statusColumn) return new Map(); if (!statusColumn) return new Map();
return statusColumn.getFacetedUniqueValues(); return statusColumn.getFacetedUniqueValues();
}, [table.getColumn("document_type")?.getFacetedUniqueValues()]); }, [table.getColumn]);
const selectedStatuses = useMemo(() => { const selectedStatuses = useMemo(() => {
const filterValue = table.getColumn("document_type")?.getFilterValue() as string[]; const filterValue = table.getColumn("document_type")?.getFilterValue() as string[];
return filterValue ?? []; return filterValue ?? [];
}, [table.getColumn("document_type")?.getFilterValue()]); }, [table.getColumn]);
const handleStatusChange = (checked: boolean, value: string) => { const handleStatusChange = (checked: boolean, value: string) => {
const filterValue = table.getColumn("document_type")?.getFilterValue() as string[]; const filterValue = table.getColumn("document_type")?.getFilterValue() as string[];
@ -722,7 +720,8 @@ export default function DocumentsTable() {
className="h-12 px-4 py-3" className="h-12 px-4 py-3"
> >
{header.isPlaceholder ? null : header.column.getCanSort() ? ( {header.isPlaceholder ? null : header.column.getCanSort() ? (
<div <Button
variant="ghost"
className={cn( className={cn(
header.column.getCanSort() && header.column.getCanSort() &&
"flex h-full cursor-pointer select-none items-center justify-between gap-2" "flex h-full cursor-pointer select-none items-center justify-between gap-2"
@ -759,7 +758,7 @@ export default function DocumentsTable() {
/> />
), ),
}[header.column.getIsSorted() as string] ?? null} }[header.column.getIsSorted() as string] ?? null}
</div> </Button>
) : ( ) : (
flexRender(header.column.columnDef.header, header.getContext()) flexRender(header.column.columnDef.header, header.getContext())
)} )}

View file

@ -1,12 +1,12 @@
"use client"; "use client";
import { useState, useCallback, useRef } from "react"; import { AnimatePresence, motion } from "framer-motion";
import { Calendar, CheckCircle2, FileType, Tag, Upload, X } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useCallback, useRef, useState } from "react";
import { useDropzone } from "react-dropzone"; import { useDropzone } from "react-dropzone";
import { Button } from "@/components/ui/button";
import { toast } from "sonner"; import { toast } from "sonner";
import { X, Upload, Tag, CheckCircle2, Calendar, FileType } from "lucide-react"; import { Button } from "@/components/ui/button";
import { useRouter, useParams } from "next/navigation";
import { motion, AnimatePresence } from "framer-motion";
// Grid pattern component inspired by Aceternity UI // Grid pattern component inspired by Aceternity UI
function GridPattern() { function GridPattern() {
@ -230,7 +230,7 @@ export default function FileUploader() {
const k = 1024; const k = 1024;
const sizes = ["Bytes", "KB", "MB", "GB", "TB"]; const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
const i = Math.floor(Math.log(bytes) / Math.log(k)); const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / k ** i).toFixed(2)) + " " + sizes[i]; return `${parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`;
}; };
const handleUpload = async () => { const handleUpload = async () => {

View file

@ -1,10 +1,11 @@
"use client"; "use client";
import { useState } from "react";
import { useParams, useRouter } from "next/navigation";
import { type Tag, TagInput } from "emblor"; import { type Tag, TagInput } from "emblor";
import { Globe, Loader2 } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { import {
Card, Card,
CardContent, CardContent,
@ -13,8 +14,7 @@ import {
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "@/components/ui/card"; } from "@/components/ui/card";
import { toast } from "sonner"; import { Label } from "@/components/ui/label";
import { Globe, Loader2 } from "lucide-react";
// URL validation regex // URL validation regex
const urlRegex = /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/; const urlRegex = /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/;

View file

@ -1,10 +1,13 @@
"use client"; "use client";
import { useState } from "react"; import { IconBrandYoutube } from "@tabler/icons-react";
import { useParams, useRouter } from "next/navigation";
import { type Tag, TagInput } from "emblor"; import { type Tag, TagInput } from "emblor";
import { motion, type Variants } from "framer-motion";
import { Loader2 } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { import {
Card, Card,
CardContent, CardContent,
@ -13,9 +16,7 @@ import {
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "@/components/ui/card"; } from "@/components/ui/card";
import { toast } from "sonner"; import { Label } from "@/components/ui/label";
import { Youtube, Loader2 } from "lucide-react";
import { motion } from "framer-motion";
// YouTube video ID validation regex // YouTube video ID validation regex
const youtubeRegex = const youtubeRegex =
@ -135,7 +136,7 @@ export default function YouTubeVideoAdder() {
}; };
// Animation variants // Animation variants
const containerVariants = { const containerVariants: Variants = {
hidden: { opacity: 0 }, hidden: { opacity: 0 },
visible: { visible: {
opacity: 1, opacity: 1,
@ -145,7 +146,7 @@ export default function YouTubeVideoAdder() {
}, },
}; };
const itemVariants = { const itemVariants: Variants = {
hidden: { y: 20, opacity: 0 }, hidden: { y: 20, opacity: 0 },
visible: { visible: {
y: 0, y: 0,
@ -165,7 +166,7 @@ export default function YouTubeVideoAdder() {
<motion.div variants={itemVariants}> <motion.div variants={itemVariants}>
<CardHeader> <CardHeader>
<CardTitle className="flex items-center gap-2"> <CardTitle className="flex items-center gap-2">
<Youtube className="h-5 w-5" /> <IconBrandYoutube className="h-5 w-5" />
Add YouTube Videos Add YouTube Videos
</CardTitle> </CardTitle>
<CardDescription> <CardDescription>
@ -282,7 +283,7 @@ export default function YouTubeVideoAdder() {
transition={{ delay: 0.2 }} transition={{ delay: 0.2 }}
className="mr-2" className="mr-2"
> >
<Youtube className="h-4 w-4" /> <IconBrandYoutube className="h-4 w-4" />
</motion.span> </motion.span>
Submit YouTube Videos Submit YouTube Videos
</> </>

View file

@ -1,5 +1,51 @@
"use client"; "use client";
import {
type ColumnDef,
type ColumnFiltersState,
flexRender,
getCoreRowModel,
getFacetedUniqueValues,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
type PaginationState,
type Row,
type SortingState,
useReactTable,
type VisibilityState,
} from "@tanstack/react-table";
import { AnimatePresence, motion, type Variants } from "framer-motion";
import {
Activity,
AlertCircle,
AlertTriangle,
Bug,
CheckCircle2,
ChevronDown,
ChevronFirst,
ChevronLast,
ChevronLeft,
ChevronRight,
ChevronUp,
CircleAlert,
CircleX,
Clock,
Columns3,
Filter,
Info,
ListFilter,
MoreHorizontal,
RefreshCw,
Terminal,
Trash,
X,
Zap,
} from "lucide-react";
import { useParams } from "next/navigation";
import React, { useContext, useId, useMemo, useRef, useState } from "react";
import { toast } from "sonner";
import { JsonMetadataViewer } from "@/components/json-metadata-viewer";
import { import {
AlertDialog, AlertDialog,
AlertDialogAction, AlertDialogAction,
@ -12,7 +58,7 @@ import {
AlertDialogTrigger, AlertDialogTrigger,
} from "@/components/ui/alert-dialog"; } from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox"; import { Checkbox } from "@/components/ui/checkbox";
import { import {
DropdownMenu, DropdownMenu,
@ -42,57 +88,11 @@ import {
TableHeader, TableHeader,
TableRow, TableRow,
} from "@/components/ui/table"; } from "@/components/ui/table";
import { JsonMetadataViewer } from "@/components/json-metadata-viewer"; import { type Log, type LogLevel, type LogStatus, useLogs, useLogsSummary } from "@/hooks/use-logs";
import { useLogs, useLogsSummary, type Log, type LogLevel, type LogStatus } from "@/hooks/use-logs";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import {
type ColumnDef,
type ColumnFiltersState,
type PaginationState,
type Row,
type SortingState,
type VisibilityState,
flexRender,
getCoreRowModel,
getFacetedUniqueValues,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { AnimatePresence, motion } from "framer-motion";
import {
Activity,
AlertCircle,
AlertTriangle,
Bug,
CheckCircle2,
ChevronDown,
ChevronFirst,
ChevronLast,
ChevronLeft,
ChevronRight,
ChevronUp,
CircleAlert,
CircleX,
Clock,
Columns3,
Filter,
Info,
ListFilter,
MoreHorizontal,
RefreshCw,
Terminal,
Trash,
X,
Zap,
} from "lucide-react";
import { useParams } from "next/navigation";
import React, { useContext, useEffect, useId, useMemo, useRef, useState } from "react";
import { toast } from "sonner";
// Define animation variants for reuse // Define animation variants for reuse
const fadeInScale = { const fadeInScale: Variants = {
hidden: { opacity: 0, scale: 0.95 }, hidden: { opacity: 0, scale: 0.95 },
visible: { visible: {
opacity: 1, opacity: 1,
@ -324,13 +324,13 @@ export default function LogsManagePage() {
const levelColumn = table.getColumn("level"); const levelColumn = table.getColumn("level");
if (!levelColumn) return []; if (!levelColumn) return [];
return Array.from(levelColumn.getFacetedUniqueValues().keys()).sort(); return Array.from(levelColumn.getFacetedUniqueValues().keys()).sort();
}, [table.getColumn("level")?.getFacetedUniqueValues()]); }, [table.getColumn]);
const uniqueStatuses = useMemo(() => { const uniqueStatuses = useMemo(() => {
const statusColumn = table.getColumn("status"); const statusColumn = table.getColumn("status");
if (!statusColumn) return []; if (!statusColumn) return [];
return Array.from(statusColumn.getFacetedUniqueValues().keys()).sort(); return Array.from(statusColumn.getFacetedUniqueValues().keys()).sort();
}, [table.getColumn("status")?.getFacetedUniqueValues()]); }, [table.getColumn]);
const handleDeleteRows = async () => { const handleDeleteRows = async () => {
const selectedRows = table.getSelectedRowModel().rows; const selectedRows = table.getSelectedRowModel().rows;
@ -631,15 +631,17 @@ function LogsFilters({
<ListFilter size={16} strokeWidth={2} /> <ListFilter size={16} strokeWidth={2} />
</div> </div>
{Boolean(table.getColumn("message")?.getFilterValue()) && ( {Boolean(table.getColumn("message")?.getFilterValue()) && (
<button <Button
className="absolute inset-y-0 end-0 flex h-full w-9 items-center justify-center rounded-e-lg text-muted-foreground/80 hover:text-foreground" className="absolute inset-y-0 end-0 flex h-full w-9 items-center justify-center rounded-e-lg text-muted-foreground/80 hover:text-foreground"
variant="ghost"
size="icon"
onClick={() => { onClick={() => {
table.getColumn("message")?.setFilterValue(""); table.getColumn("message")?.setFilterValue("");
inputRef.current?.focus(); inputRef.current?.focus();
}} }}
> >
<CircleX size={16} strokeWidth={2} /> <CircleX size={16} strokeWidth={2} />
</button> </Button>
)} )}
</motion.div> </motion.div>
@ -705,7 +707,7 @@ function FilterDropdown({
const selectedValues = useMemo(() => { const selectedValues = useMemo(() => {
const filterValue = column?.getFilterValue() as string[]; const filterValue = column?.getFilterValue() as string[];
return filterValue ?? []; return filterValue ?? [];
}, [column?.getFilterValue()]); }, [column?.getFilterValue]);
const handleValueChange = (checked: boolean, value: string) => { const handleValueChange = (checked: boolean, value: string) => {
const filterValue = column?.getFilterValue() as string[]; const filterValue = column?.getFilterValue() as string[];
@ -848,7 +850,9 @@ function LogsTable({
className="h-12 px-4 py-3" className="h-12 px-4 py-3"
> >
{header.isPlaceholder ? null : header.column.getCanSort() ? ( {header.isPlaceholder ? null : header.column.getCanSort() ? (
<div <Button
variant="ghost"
size="sm"
className={cn( className={cn(
"flex h-full cursor-pointer select-none items-center justify-between gap-2" "flex h-full cursor-pointer select-none items-center justify-between gap-2"
)} )}
@ -859,7 +863,7 @@ function LogsTable({
asc: <ChevronUp className="shrink-0 opacity-60" size={16} />, asc: <ChevronUp className="shrink-0 opacity-60" size={16} />,
desc: <ChevronDown className="shrink-0 opacity-60" size={16} />, desc: <ChevronDown className="shrink-0 opacity-60" size={16} />,
}[header.column.getIsSorted() as string] ?? null} }[header.column.getIsSorted() as string] ?? null}
</div> </Button>
) : ( ) : (
flexRender(header.column.columnDef.header, header.getContext()) flexRender(header.column.columnDef.header, header.getContext())
)} )}

View file

@ -1,7 +1,7 @@
"use client"; "use client";
import { format } from "date-fns"; import { format } from "date-fns";
import { AnimatePresence, motion } from "framer-motion"; import { AnimatePresence, motion, type Variants } from "framer-motion";
import { import {
Calendar, Calendar,
MoreHorizontal, MoreHorizontal,
@ -16,8 +16,9 @@ import {
VolumeX, VolumeX,
X, X,
} from "lucide-react"; } from "lucide-react";
import Image from "next/image";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { toast } from "sonner";
// UI Components // UI Components
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card"; import { Card } from "@/components/ui/card";
@ -45,7 +46,6 @@ import {
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Slider } from "@/components/ui/slider"; import { Slider } from "@/components/ui/slider";
import { toast } from "sonner";
interface PodcastItem { interface PodcastItem {
id: number; id: number;
@ -60,7 +60,7 @@ interface PodcastsPageClientProps {
searchSpaceId: string; searchSpaceId: string;
} }
const pageVariants = { const pageVariants: Variants = {
initial: { opacity: 0 }, initial: { opacity: 0 },
enter: { enter: {
opacity: 1, opacity: 1,
@ -69,7 +69,7 @@ const pageVariants = {
exit: { opacity: 0, transition: { duration: 0.3, ease: "easeInOut" } }, exit: { opacity: 0, transition: { duration: 0.3, ease: "easeInOut" } },
}; };
const podcastCardVariants = { const podcastCardVariants: Variants = {
initial: { scale: 0.95, y: 20, opacity: 0 }, initial: { scale: 0.95, y: 20, opacity: 0 },
animate: { animate: {
scale: 1, scale: 1,
@ -162,7 +162,7 @@ export default function PodcastsPageClient({ searchSpaceId }: PodcastsPageClient
}; };
fetchPodcasts(); fetchPodcasts();
}, [searchSpaceId]); }, []);
// Filter and sort podcasts based on search query and sort order // Filter and sort podcasts based on search query and sort order
useEffect(() => { useEffect(() => {
@ -540,11 +540,13 @@ export default function PodcastsPageClient({ searchSpaceId }: PodcastsPageClient
> >
<div className="relative w-full aspect-[16/10] mb-4 rounded-lg overflow-hidden"> <div className="relative w-full aspect-[16/10] mb-4 rounded-lg overflow-hidden">
{/* Podcast image with gradient overlay */} {/* Podcast image with gradient overlay */}
<img <Image
src={PODCAST_IMAGE_URL} src={PODCAST_IMAGE_URL}
alt="Podcast illustration" alt="Podcast illustration"
className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105 brightness-[0.85] contrast-[1.1]" className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105 brightness-[0.85] contrast-[1.1]"
loading="lazy" loading="lazy"
width={100}
height={100}
/> />
{/* Better overlay with gradient for improved text legibility */} {/* Better overlay with gradient for improved text legibility */}
@ -675,7 +677,8 @@ export default function PodcastsPageClient({ searchSpaceId }: PodcastsPageClient
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.1 }} transition={{ delay: 0.1 }}
> >
<div <Button
variant="ghost"
className="h-1.5 bg-muted rounded-full cursor-pointer group relative overflow-hidden" className="h-1.5 bg-muted rounded-full cursor-pointer group relative overflow-hidden"
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
@ -702,7 +705,7 @@ export default function PodcastsPageClient({ searchSpaceId }: PodcastsPageClient
whileHover={{ scale: 1.5 }} whileHover={{ scale: 1.5 }}
/> />
</motion.div> </motion.div>
</div> </Button>
<div className="flex justify-between mt-1.5 text-xs text-muted-foreground"> <div className="flex justify-between mt-1.5 text-xs text-muted-foreground">
<span>{formatTime(currentTime)}</span> <span>{formatTime(currentTime)}</span>
<span>{formatTime(duration)}</span> <span>{formatTime(duration)}</span>
@ -1024,7 +1027,9 @@ export default function PodcastsPageClient({ searchSpaceId }: PodcastsPageClient
// Reset playing state on error // Reset playing state on error
setIsPlaying(false); setIsPlaying(false);
}} }}
/> >
<track kind="captions" />
</audio>
</motion.div> </motion.div>
); );
} }

View file

@ -229,14 +229,14 @@ export function DocumentsDataTable({
if (hasChanges && Object.keys(initialRowSelection).length > 0) { if (hasChanges && Object.keys(initialRowSelection).length > 0) {
setRowSelection(initialRowSelection); setRowSelection(initialRowSelection);
} }
}, [initialRowSelection, rowSelection]); }, [initialRowSelection]);
// Initialize row selection on mount // Initialize row selection on mount
useEffect(() => { useEffect(() => {
if (Object.keys(rowSelection).length === 0 && Object.keys(initialRowSelection).length > 0) { if (Object.keys(rowSelection).length === 0 && Object.keys(initialRowSelection).length > 0) {
setRowSelection(initialRowSelection); setRowSelection(initialRowSelection);
} }
}, [initialRowSelection, rowSelection]); }, []);
const filteredDocuments = useMemo(() => { const filteredDocuments = useMemo(() => {
if (documentTypeFilter === "ALL") return documents; if (documentTypeFilter === "ALL") return documents;
@ -263,7 +263,7 @@ export function DocumentsDataTable({
const selectedRows = table.getFilteredSelectedRowModel().rows; const selectedRows = table.getFilteredSelectedRowModel().rows;
const selectedDocuments = selectedRows.map((row) => row.original); const selectedDocuments = selectedRows.map((row) => row.original);
onSelectionChange(selectedDocuments); onSelectionChange(selectedDocuments);
}, [onSelectionChange, table]); }, [rowSelection, onSelectionChange, table]);
const handleClearAll = () => setRowSelection({}); const handleClearAll = () => setRowSelection({});