Merge remote-tracking branch 'origin/feat/fix-react-cve' into feat/agent-update

This commit is contained in:
charlesgauthereau
2026-02-11 19:42:57 +01:00
14 changed files with 1051 additions and 995 deletions
+9
View File
@@ -145,4 +145,13 @@
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
@apply font-title; @apply font-title;
} }
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
} }
+77 -77
View File
@@ -14,52 +14,52 @@
"auth:generate": "npx @better-auth/cli generate --config ./src/lib/auth/auth.ts" "auth:generate": "npx @better-auth/cli generate --config ./src/lib/auth/auth.ts"
}, },
"dependencies": { "dependencies": {
"@hookform/resolvers": "^5.0.1", "@hookform/resolvers": "^5.2.2",
"@radix-ui/react-accordion": "^1.2.10", "@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-alert-dialog": "^1.1.13", "@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-aspect-ratio": "^1.1.6", "@radix-ui/react-aspect-ratio": "^1.1.8",
"@radix-ui/react-avatar": "^1.1.9", "@radix-ui/react-avatar": "^1.1.11",
"@radix-ui/react-checkbox": "^1.3.1", "@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.10", "@radix-ui/react-collapsible": "^1.1.12",
"@radix-ui/react-context-menu": "^2.2.14", "@radix-ui/react-context-menu": "^2.2.16",
"@radix-ui/react-dialog": "^1.1.13", "@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.14", "@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-hover-card": "^1.1.13", "@radix-ui/react-hover-card": "^1.1.15",
"@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-label": "^2.1.6", "@radix-ui/react-label": "^2.1.8",
"@radix-ui/react-menubar": "^1.1.14", "@radix-ui/react-menubar": "^1.1.16",
"@radix-ui/react-navigation-menu": "^1.2.12", "@radix-ui/react-navigation-menu": "^1.2.14",
"@radix-ui/react-popover": "^1.1.13", "@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-progress": "^1.1.6", "@radix-ui/react-progress": "^1.1.8",
"@radix-ui/react-radio-group": "^1.3.6", "@radix-ui/react-radio-group": "^1.3.8",
"@radix-ui/react-scroll-area": "^1.2.8", "@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.2.4", "@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-separator": "^1.1.6", "@radix-ui/react-separator": "^1.1.8",
"@radix-ui/react-slider": "^1.3.4", "@radix-ui/react-slider": "^1.3.6",
"@radix-ui/react-slot": "^1.2.2", "@radix-ui/react-slot": "^1.2.4",
"@radix-ui/react-switch": "^1.2.4", "@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tabs": "^1.1.11", "@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-toast": "^1.2.13", "@radix-ui/react-toast": "^1.2.15",
"@radix-ui/react-toggle": "^1.1.8", "@radix-ui/react-toggle": "^1.1.10",
"@radix-ui/react-toggle-group": "^1.1.9", "@radix-ui/react-toggle-group": "^1.1.11",
"@radix-ui/react-tooltip": "^1.2.6", "@radix-ui/react-tooltip": "^1.2.8",
"@react-email/components": "^0.0.41", "@react-email/components": "^0.0.41",
"@t3-oss/env-nextjs": "^0.13.4", "@t3-oss/env-nextjs": "^0.13.10",
"@tanstack/react-query": "^5.76.1", "@tanstack/react-query": "^5.90.21",
"@tanstack/react-table": "^8.21.3", "@tanstack/react-table": "^8.21.3",
"@types/express": "^5.0.6", "@types/express": "^5.0.6",
"@types/nodemailer": "^6.4.17", "@types/nodemailer": "^6.4.22",
"@types/ws": "^8.18.1", "@types/ws": "^8.18.1",
"@zenstackhq/runtime": "2.14.2", "@zenstackhq/runtime": "2.14.2",
"argon2": "^0.43.0", "argon2": "^0.43.1",
"bcrypt": "^6.0.0", "bcrypt": "^6.0.0",
"better-auth": "1.4.5", "better-auth": "1.4.5",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cmdk": "^1.1.1", "cmdk": "^1.1.1",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"dockerode": "^4.0.6", "dockerode": "^4.0.9",
"dotenv": "^16.5.0", "dotenv": "^16.6.1",
"drizzle-orm": "^0.43.1", "drizzle-orm": "^0.43.1",
"drizzle-zod": "^0.7.1", "drizzle-zod": "^0.7.1",
"embla-carousel-react": "^8.6.0", "embla-carousel-react": "^8.6.0",
@@ -67,64 +67,64 @@
"googleapis": "^170.1.0", "googleapis": "^170.1.0",
"input-otp": "^1.4.2", "input-otp": "^1.4.2",
"lucide-react": "^0.553.0", "lucide-react": "^0.553.0",
"minio": "^8.0.5", "minio": "^8.0.6",
"motion": "^12.23.24", "motion": "^12.34.0",
"next": "16.1.5", "next": "16.1.5",
"next-safe-action": "^7.10.8", "next-safe-action": "^7.10.8",
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
"node-cron": "^4.2.1", "node-cron": "^4.2.1",
"node-forge": "^1.3.1", "node-forge": "^1.3.3",
"nodemailer": "^7.0.3", "nodemailer": "^7.0.13",
"npm-check-updates": "^18.0.1", "npm-check-updates": "^18.3.1",
"pg": "^8.16.0", "pg": "^8.18.0",
"prettier": "^3.8.0", "prettier": "^3.8.1",
"react": "^19.2.0", "react": "^19.2.4",
"react-day-picker": "9.7.0", "react-day-picker": "9.7.0",
"react-dom": "^19.2.0", "react-dom": "^19.2.4",
"react-dropzone": "^14.3.8", "react-dropzone": "^14.4.1",
"react-email": "^4.0.13", "react-email": "^4.3.2",
"react-hook-form": "^7.56.3", "react-hook-form": "^7.71.1",
"react-qr-code": "^2.0.18", "react-qr-code": "^2.0.18",
"react-resizable-panels": "^3.0.2", "react-resizable-panels": "^3.0.6",
"react-twc": "^1.4.2", "react-twc": "^1.5.1",
"react-use-measure": "^2.1.7", "react-use-measure": "^2.1.7",
"recharts": "^2.15.3", "recharts": "^2.15.4",
"sharp": "^0.34.5", "sharp": "^0.34.5",
"socket.io": "^4.8.1", "socket.io": "^4.8.3",
"socket.io-client": "^4.8.1", "socket.io-client": "^4.8.3",
"sonner": "^2.0.3", "sonner": "^2.0.7",
"swiper": "^12.0.3", "swiper": "^12.1.0",
"tailwind-merge": "^3.3.0", "tailwind-merge": "^3.4.0",
"uuid": "^11.1.0", "uuid": "^11.1.0",
"vaul": "^1.1.2", "vaul": "^1.1.2",
"ws": "^8.18.2", "ws": "^8.19.0",
"zod": "^3.24.4" "zod": "^3.25.76"
}, },
"devDependencies": { "devDependencies": {
"@iconify/react": "^6.0.0", "@iconify/react": "^6.0.2",
"@react-email/preview-server": "4.3.2", "@react-email/preview-server": "4.3.2",
"@react-email/render": "^2.0.1", "@react-email/render": "^2.0.4",
"@tailwindcss/postcss": "^4.1.7", "@tailwindcss/postcss": "^4.1.18",
"@types/eslint-plugin-tailwindcss": "^3.17.0", "@types/eslint-plugin-tailwindcss": "^3.17.0",
"@types/node": "^22.15.18", "@types/node": "^22.19.11",
"@types/node-forge": "^1", "@types/node-forge": "^1.3.14",
"@types/pg": "^8.15.2", "@types/pg": "^8.16.0",
"@types/react": "^19.1.4", "@types/react": "^19.2.14",
"@types/react-dom": "^19.1.5", "@types/react-dom": "^19.2.3",
"@zenstackhq/openapi": "^2.14.2", "@zenstackhq/openapi": "^2.22.1",
"@zenstackhq/tanstack-query": "^2.14.2", "@zenstackhq/tanstack-query": "^2.22.2",
"baseline-browser-mapping": "^2.9.19", "baseline-browser-mapping": "^2.9.19",
"drizzle-kit": "^0.31.1", "drizzle-kit": "^0.31.9",
"esbuild": "^0.27.2", "esbuild": "^0.27.3",
"eslint": "^9.39.0", "eslint": "^9.39.2",
"eslint-config-next": "^16.0.1", "eslint-config-next": "^16.1.6",
"eslint-plugin-tailwindcss": "^3.18.0", "eslint-plugin-tailwindcss": "^3.18.2",
"framer-motion": "^12.24.7", "framer-motion": "^12.34.0",
"postcss": "^8.5.3", "postcss": "^8.5.6",
"tailwindcss": "^4.1.7", "tailwindcss": "^4.1.18",
"tsx": "^4.19.4", "tsx": "^4.21.0",
"tw-animate-css": "^1.2.9", "tw-animate-css": "^1.4.0",
"typescript": "^5.8.3", "typescript": "^5.9.3",
"zenstack": "2.14.2" "zenstack": "2.14.2"
}, },
"packageManager": "pnpm@10.29.2+sha512.bef43fa759d91fd2da4b319a5a0d13ef7a45bb985a3d7342058470f9d2051a3ba8674e629672654686ef9443ad13a82da2beb9eeb3e0221c87b8154fff9d74b8" "packageManager": "pnpm@10.29.2+sha512.bef43fa759d91fd2da4b319a5a0d13ef7a45bb985a3d7342058470f9d2051a3ba8674e629672654686ef9443ad13a82da2beb9eeb3e0221c87b8154fff9d74b8"
+923 -861
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -7,7 +7,7 @@ import { motion, useInView, type SpringOptions, type UseInViewOptions } from 'mo
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
const githubButtonVariants = cva( const githubButtonVariants = cva(
'cursor-pointer relative overflow-hidden will-change-transform backface-visibility-hidden transform-gpu transition-transform duration-200 ease-out hover:scale-105 group whitespace-nowrap focus-visible:outline-hidden inline-flex items-center justify-center whitespace-nowrap font-medium ring-offset-background disabled:pointer-events-none disabled:opacity-60 [&_svg]:shrink-0', 'cursor-pointer relative overflow-hidden will-change-transform backface-visibility-hidden transform-gpu group whitespace-nowrap focus-visible:outline-hidden inline-flex items-center justify-center whitespace-nowrap font-medium ring-offset-background disabled:pointer-events-none disabled:opacity-60 [&_svg]:shrink-0',
{ {
variants: { variants: {
variant: { variant: {
+1 -1
View File
@@ -374,7 +374,7 @@ function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
data-slot="sidebar-content" data-slot="sidebar-content"
data-sidebar="content" data-sidebar="content"
className={cn( className={cn(
"flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden", "flex min-h-0 flex-1 flex-col gap-2 overflow-auto scrollbar-hide group-data-[collapsible=icon]:overflow-hidden",
className className
)} )}
{...props} {...props}
@@ -34,7 +34,7 @@ export const GitHubStarsButtonCustom = () => {
<GithubButton <GithubButton
initialStars={0} initialStars={0}
targetStars={stars} targetStars={stars}
label="Github Stars" label=""
size="sm" size="sm"
separator={true} separator={true}
roundStars={true} roundStars={true}
@@ -136,7 +136,7 @@ export const StorageGoogleDriveForm = ({form}: StorageGoogleDriveFormProps) => {
<input type="hidden" {...form.register("config.refreshToken")} /> <input type="hidden" {...form.register("config.refreshToken")} />
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Button type="button" onClick={handleConnect}> <Button type="button" variant={"secondary"} className="hover:cursor-pointer" onClick={handleConnect}>
{isConnected ? "Reconnect Google Drive" : "Connect Google Drive"} {isConnected ? "Reconnect Google Drive" : "Connect Google Drive"}
</Button> </Button>
@@ -69,7 +69,7 @@ export const AgentContentPage = ({edgeKey, agent: initialAgent}: AgentContentPag
<div className="space-y-6"> <div className="space-y-6">
<Accordion type="single" collapsible defaultValue={!agent.lastContact ? "registration" : undefined}> <Accordion type="single" collapsible defaultValue={!agent.lastContact ? "registration" : undefined}>
<AccordionItem value="registration" className="border rounded-xl px-6 bg-card shadow-sm overflow-hidden transition-all duration-300 data-[state=open]:ring-1 data-[state=open]:ring-primary/20"> <AccordionItem value="registration" className="border rounded-xl px-6 bg-card shadow-sm overflow-hidden transition-all duration-300">
<AccordionTrigger className="hover:no-underline py-4 group"> <AccordionTrigger className="hover:no-underline py-4 group">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<span className="text-xl font-bold tracking-tight">Registration & Setup</span> <span className="text-xl font-bold tracking-tight">Registration & Setup</span>
@@ -47,18 +47,11 @@ export const LoggedInDropdown = ({ user, sessions, currentSession, accounts, chi
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger> <DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger>
<DropdownMenuContent <DropdownMenuContent
className="min-w-[220px] rounded-xl border-2 border-border bg-popover shadow-none p-1" className="w-[var(--radix-popper-anchor-width)] rounded-xl border-2 border-border bg-popover shadow-none p-1"
align="start" align="start"
side="top" side="top"
sideOffset={8} sideOffset={8}
> >
<div className="flex flex-col space-y-1 p-2 mb-1">
<p className="text-sm font-semibold leading-none truncate">{user.name}</p>
<p className="text-xs leading-none text-muted-foreground truncate">
{user.email}
</p>
</div>
<DropdownMenuSeparator className="-mx-1 mb-1 bg-border/50" />
<DropdownMenuItem <DropdownMenuItem
onClick={() => setIsModalOpen(!isModalOpen)} onClick={() => setIsModalOpen(!isModalOpen)}
className="group gap-2 p-1 cursor-pointer rounded-lg mb-1 transition-colors focus:bg-accent hover:bg-accent/50 border border-transparent" className="group gap-2 p-1 cursor-pointer rounded-lg mb-1 transition-colors focus:bg-accent hover:bg-accent/50 border border-transparent"
@@ -1,12 +1,9 @@
import { import {
Sidebar, Sidebar,
SidebarContent, SidebarContent,
SidebarFooter,
SidebarHeader, SidebarHeader,
SidebarMenu, SidebarMenu,
SidebarMenuButton, SidebarMenuItem
SidebarMenuItem,
SidebarSeparator
} from "@/components/ui/sidebar"; } from "@/components/ui/sidebar";
import {SidebarLogo} from "@/components/wrappers/dashboard/common/sidebar/logo-sidebar"; import {SidebarLogo} from "@/components/wrappers/dashboard/common/sidebar/logo-sidebar";
import {SidebarMenuCustomMain} from "@/components/wrappers/dashboard/common/sidebar/menu-sidebar-main"; import {SidebarMenuCustomMain} from "@/components/wrappers/dashboard/common/sidebar/menu-sidebar-main";
@@ -15,7 +12,6 @@ import {OrganizationCombobox} from "@/components/wrappers/dashboard/organization
import {env} from "@/env.mjs"; import {env} from "@/env.mjs";
import {LoggedInButton} from "@/components/wrappers/dashboard/common/logged-in/logged-in-button.server"; import {LoggedInButton} from "@/components/wrappers/dashboard/common/logged-in/logged-in-button.server";
import {UpdateNotification} from "@/features/updates/components/update-notification"; import {UpdateNotification} from "@/features/updates/components/update-notification";
import {Book} from "lucide-react";
export function AppSidebar() { export function AppSidebar() {
const projectName = env.PROJECT_NAME; const projectName = env.PROJECT_NAME;
@@ -38,27 +34,12 @@ export function AppSidebar() {
<UpdateNotification /> <UpdateNotification />
<SidebarFooter> <SidebarMenu className="mb-2">
<SidebarSeparator /> <SidebarMenuItem className="p-2">
<div className="flex flex-col gap-1 p-2"> <LoggedInButton/>
<a </SidebarMenuItem>
href="https://portabase.io/docs" </SidebarMenu>
target="_blank" <SideBarFooterCredit/>
rel="noreferrer"
className="flex items-center gap-2 px-2 py-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors group-data-[collapsible=icon]:justify-center"
>
<Book className="size-4 shrink-0" />
<span className="group-data-[collapsible=icon]:hidden">Documentation</span>
</a>
</div>
<SidebarMenu className="mb-2">
<SidebarMenuItem className="p-2">
<LoggedInButton/>
</SidebarMenuItem>
</SidebarMenu>
<SideBarFooterCredit/>
</SidebarFooter>
</Sidebar> </Sidebar>
); );
} }
@@ -7,20 +7,17 @@ import {
Layers, Layers,
ChartArea, ChartArea,
ShieldHalf, ShieldHalf,
Building, UserRoundCog, Mail, PackageOpen, Logs, Megaphone, Blocks, Warehouse Building, UserRoundCog, Mail, PackageOpen, Logs, Megaphone, Blocks, Warehouse, BookOpen
} from "lucide-react"; } from "lucide-react";
import {SidebarGroupItem, SidebarMenuCustomBase} from "@/components/wrappers/dashboard/common/sidebar/menu-sidebar"; import {SidebarGroupItem, SidebarMenuCustomBase} from "@/components/wrappers/dashboard/common/sidebar/menu-sidebar";
import {authClient, useSession} from "@/lib/auth/auth-client"; import {authClient} from "@/lib/auth/auth-client";
export const SidebarMenuCustomMain = () => { export const SidebarMenuCustomMain = () => {
const BASE_URL = `/dashboard`; const BASE_URL = `/dashboard`;
const {data: activeOrganization} = authClient.useActiveOrganization();
const {data: organizations} = authClient.useListOrganizations();
const {data: session, isPending, error} = authClient.useSession(); const {data: session, isPending, error} = authClient.useSession();
const member = authClient.useActiveMember();
if (isPending) return null; if (isPending) return null;
@@ -50,6 +47,20 @@ export const SidebarMenuCustomMain = () => {
type: "list", type: "list",
group_content: groupContent, group_content: groupContent,
}, },
{
label: "Resources",
type: "list",
group_content: [
{
title: "Documentation",
url: "https://portabase.io/docs",
icon: BookOpen,
type: "item",
redirect: true,
not_from_base_url: true,
}
],
},
]; ];
@@ -18,7 +18,7 @@ import {Skeleton} from "@/components/ui/skeleton"
export function OrganizationCombobox() { export function OrganizationCombobox() {
const router = useRouter() const router = useRouter()
const {isMobile, state} = useSidebar() const {state} = useSidebar()
const {data: organizations, isPending: isPendingList, refetch} = authClient.useListOrganizations() const {data: organizations, isPending: isPendingList, refetch} = authClient.useListOrganizations()
const { const {
data: activeOrganization, data: activeOrganization,
@@ -95,7 +95,7 @@ export function OrganizationCombobox() {
</SidebarMenuButton> </SidebarMenuButton>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent <DropdownMenuContent
className="min-w-[var(--radix-popper-anchor-width)] rounded-xl border-2 border-border bg-popover shadow-none" className="w-[var(--radix-popper-anchor-width)] rounded-xl border-2 border-border bg-popover shadow-none"
align="start" align="start"
side="bottom" side="bottom"
sideOffset={4} sideOffset={4}
@@ -150,7 +150,7 @@ export function OrganizationCombobox() {
className="flex size-9 items-center justify-center rounded-md border border-dashed border-muted-foreground/30 bg-background transition-colors group-hover:border-primary/50 group-hover:bg-primary/5"> className="flex size-9 items-center justify-center rounded-md border border-dashed border-muted-foreground/30 bg-background transition-colors group-hover:border-primary/50 group-hover:bg-primary/5">
<Plus className="size-4"/> <Plus className="size-4"/>
</div> </div>
<div className="font-medium">Create new organization</div> <div className="font-medium">Create organization</div>
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
+6 -6
View File
@@ -24,13 +24,13 @@ export function ModeToggle() {
} }
return ( return (
<div className="flex items-center justify-center rounded-full bg-muted/50 p-1 border border-border/50 relative w-fit"> <div className="flex items-center justify-center rounded-full bg-muted/50 p-0.5 border border-border/50 relative w-fit">
<motion.div <motion.div
className="absolute h-7 w-8 rounded-full bg-background shadow-sm z-0 border border-border/20" className="absolute h-6 w-7 rounded-full bg-background shadow-sm z-0 border border-border/20"
initial={false} initial={false}
animate={{ x: activeIndex * 32 }} animate={{ x: activeIndex * 28 }}
transition={{ type: "spring", stiffness: 400, damping: 30 }} transition={{ type: "spring", stiffness: 400, damping: 30 }}
style={{ left: "4px" }} style={{ left: "2px" }}
/> />
<div className="flex gap-0 relative z-10"> <div className="flex gap-0 relative z-10">
@@ -43,12 +43,12 @@ export function ModeToggle() {
key={t.id} key={t.id}
onClick={() => handleThemeChange(t.id)} onClick={() => handleThemeChange(t.id)}
className={cn( className={cn(
"flex h-7 w-8 items-center justify-center rounded-full transition-colors duration-200 hover:text-foreground outline-none", "flex h-6 w-7 items-center justify-center rounded-full transition-colors duration-200 hover:text-foreground outline-none",
isActive ? "text-primary" : "text-muted-foreground" isActive ? "text-primary" : "text-muted-foreground"
)} )}
aria-label={t.label} aria-label={t.label}
> >
<Icon className="h-4 w-4" /> <Icon className="h-3.5 w-3.5" />
</button> </button>
) )
})} })}