From d24e534828e9c375f80aa7edf54f723ac3446c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20LAGACHE?= Date: Tue, 10 Feb 2026 17:02:06 +0100 Subject: [PATCH] update: ui --- app/providers.tsx | 1 - .../agent/agent-card-key/agent-card-key.tsx | 247 +++++++++++++----- .../common/logged-in/logged-in-dropdown.tsx | 99 ++++--- .../dashboard/common/sidebar/app-sidebar.tsx | 35 ++- .../dashboard/profile/profile-apperance.tsx | 1 - src/features/theme/mode-toggle.tsx | 83 +++--- 6 files changed, 330 insertions(+), 136 deletions(-) diff --git a/app/providers.tsx b/app/providers.tsx index 4c6dbe90..d4f513de 100644 --- a/app/providers.tsx +++ b/app/providers.tsx @@ -6,7 +6,6 @@ import {ThemeProvider} from "@/features/theme/theme-provider"; import {Toaster} from "@/components/ui/sonner"; import {QueryClient, QueryClientProvider} from "@tanstack/react-query"; import {ThemeMetaUpdaterRoot} from "@/features/browser/theme-meta-updater-root"; -import {BackupModalProvider} from "@/components/wrappers/dashboard/database/backup/backup-modal-context"; export type ProviderProps = PropsWithChildren<{}>; diff --git a/src/components/wrappers/dashboard/agent/agent-card-key/agent-card-key.tsx b/src/components/wrappers/dashboard/agent/agent-card-key/agent-card-key.tsx index 8936d7ab..4d9c1daa 100644 --- a/src/components/wrappers/dashboard/agent/agent-card-key/agent-card-key.tsx +++ b/src/components/wrappers/dashboard/agent/agent-card-key/agent-card-key.tsx @@ -1,11 +1,13 @@ "use client"; import {Input} from "@/components/ui/input"; -import {Label} from "@/components/ui/label"; import {Button} from "@/components/ui/button"; -import {Copy, Check} from "lucide-react"; +import {Copy, Check, Eye, EyeOff, Terminal, Key, Info} from "lucide-react"; import {useState} from "react"; import {copyToClipboardWithMeta} from "@/components/wrappers/common/button/copy-button"; +import {Tabs, TabsContent, TabsList, TabsTrigger} from "@/components/ui/tabs"; +import {Card, CardContent, CardDescription, CardHeader, CardTitle} from "@/components/ui/card"; +import { cn } from "@/lib/utils"; export type AgentCardKeyProps = { edgeKey: string; @@ -15,74 +17,199 @@ export type AgentCardKeyProps = { export const AgentCardKey = ({edgeKey, agentName}: AgentCardKeyProps) => { const [isCopiedKey, setIsCopiedKey] = useState(false); const [isCopiedCommand, setIsCopiedCommand] = useState(false); + const [isVisible, setIsVisible] = useState(false); const command = `portabase agent "${agentName}" --key ${edgeKey}`; + const maskedKey = "••••••••••••••••••••••••••••••••"; const handleCopy = async (text: string, setter: (v: boolean) => void) => { await copyToClipboardWithMeta(text); setter(true); - setTimeout(() => setter(false), 2000); - }; - - const handleFocus = (event: React.FocusEvent) => { - event.target.select(); }; return ( -
-
-
- -
- - -
-

- Use this key for manual configuration of your agent. -

-
+
+ + + + + Automatic + + + + Manual + + -
- -
- - -
-

- Run this command on your server to automatically register the agent. -

-
-
+ + + + + CLI Setup + + + Click the input below to reveal the key and copy it to your terminal. + + + +
+
+ { + setIsVisible(true); + handleCopy(command, setIsCopiedCommand); + e.currentTarget.select(); + }} + onClick={(e) => e.currentTarget.select()} + onBlur={() => { + setIsVisible(false); + setIsCopiedCommand(false); + }} + className="font-mono text-xs bg-muted/30 h-10 pr-10 cursor-pointer" + /> + +
+ +
+
+
+ +
+

CLI Installation

+

+ This command requires the portabase cli. If you haven't installed it yet, you can find the instructions at{" "} + + portabase.io/docs/cli + +

+
+
+
+
+
+
+ + + + + + Registration Key + + + Use this key to manually configure your agent in your configuration file. + + + +
+
+ { + setIsVisible(true); + handleCopy(edgeKey, setIsCopiedKey); + e.currentTarget.select(); + }} + onClick={(e) => e.currentTarget.select()} + onBlur={() => { + setIsVisible(false); + setIsCopiedKey(false); + }} + className="font-mono text-xs bg-muted/30 h-10 pr-10 cursor-pointer" + /> + +
+ +
+ +
+
+
+ +
+

Important Security Note

+

+ Never share this key. Anyone with access to it can register as this agent. +

+
+
+
+ +
+
+ +
+

Need help with manual setup?

+

+ Check out our guide for manual configuration and Docker deployment at{" "} + + portabase.io/docs/setup + +

+
+
+
+
+
+
+
+
); }; diff --git a/src/components/wrappers/dashboard/common/logged-in/logged-in-dropdown.tsx b/src/components/wrappers/dashboard/common/logged-in/logged-in-dropdown.tsx index 386fe156..fd340697 100644 --- a/src/components/wrappers/dashboard/common/logged-in/logged-in-dropdown.tsx +++ b/src/components/wrappers/dashboard/common/logged-in/logged-in-dropdown.tsx @@ -1,26 +1,36 @@ "use client"; import {PropsWithChildren, ReactNode, useState} from "react"; + import { useRouter } from "next/navigation"; -import { CircleUser, LogOut } from "lucide-react"; -import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; + +import { LogOut, User } from "lucide-react"; + +import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; + import { signOut } from "@/lib/auth/auth-client"; + import {ProfileModal} from "@/components/wrappers/dashboard/common/profile/profile-modal"; -import {Account, Session, User} from "@/db/schema/02_user"; + +import {Account, Session, User as UserType} from "@/db/schema/02_user"; + import {AuthProviderConfig} from "../../../../../../portabase.config"; export type LoggedInDropdownProps = PropsWithChildren<{ - user: User; + user: UserType; sessions: Session[]; currentSession: Session; accounts: Account[]; children: ReactNode; providers: AuthProviderConfig[] - }>; + + export const LoggedInDropdown = ({ user, sessions, currentSession, accounts, children, providers }: LoggedInDropdownProps) => { + const router = useRouter(); + const [isModalOpen, setIsModalOpen] = useState(false); return ( @@ -34,34 +44,57 @@ export const LoggedInDropdown = ({ user, sessions, currentSession, accounts, chi onOpenChange={setIsModalOpen} providers={providers} /> - - - {children} - - setIsModalOpen(!isModalOpen)}> -
- - Account -
-
- { - await signOut({ - fetchOptions: { - onSuccess: () => { - router.push("/login"); - }, - }, - }); - }} - > -
- - Logout -
-
-
-
+ + {children} + +
+

{user.name}

+

+ {user.email} +

+
+ + 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" + > +
+ +
+
+ Account Settings +
+
+ { + await signOut({ + fetchOptions: { + onSuccess: () => { + router.push("/login"); + }, + }, + }); + }} + > +
+ +
+
+ Logout +
+
+
+
+ ); + }; + + diff --git a/src/components/wrappers/dashboard/common/sidebar/app-sidebar.tsx b/src/components/wrappers/dashboard/common/sidebar/app-sidebar.tsx index 5394c2af..bf46af6c 100644 --- a/src/components/wrappers/dashboard/common/sidebar/app-sidebar.tsx +++ b/src/components/wrappers/dashboard/common/sidebar/app-sidebar.tsx @@ -1,9 +1,12 @@ import { Sidebar, SidebarContent, + SidebarFooter, SidebarHeader, SidebarMenu, - SidebarMenuItem + SidebarMenuButton, + SidebarMenuItem, + SidebarSeparator } from "@/components/ui/sidebar"; import {SidebarLogo} from "@/components/wrappers/dashboard/common/sidebar/logo-sidebar"; import {SidebarMenuCustomMain} from "@/components/wrappers/dashboard/common/sidebar/menu-sidebar-main"; @@ -12,6 +15,7 @@ import {OrganizationCombobox} from "@/components/wrappers/dashboard/organization import {env} from "@/env.mjs"; import {LoggedInButton} from "@/components/wrappers/dashboard/common/logged-in/logged-in-button.server"; import {UpdateNotification} from "@/features/updates/components/update-notification"; +import {Book} from "lucide-react"; export function AppSidebar() { const projectName = env.PROJECT_NAME; @@ -33,13 +37,28 @@ export function AppSidebar() { - - - - - - - + + + + + + + + + + + + ); } diff --git a/src/components/wrappers/dashboard/profile/profile-apperance.tsx b/src/components/wrappers/dashboard/profile/profile-apperance.tsx index 689c4eb1..e41a6b7c 100644 --- a/src/components/wrappers/dashboard/profile/profile-apperance.tsx +++ b/src/components/wrappers/dashboard/profile/profile-apperance.tsx @@ -39,7 +39,6 @@ function ThemeSelector() { isActive ? "border-primary bg-primary/5" : "border-muted/40" )} onClick={async () => { - // setTheme(item.value) await authClient.updateUser({theme: item.value}); }} > diff --git a/src/features/theme/mode-toggle.tsx b/src/features/theme/mode-toggle.tsx index 6b6b2d33..ccf2d818 100644 --- a/src/features/theme/mode-toggle.tsx +++ b/src/features/theme/mode-toggle.tsx @@ -1,41 +1,58 @@ "use client" -import * as React from "react" -import {Moon, Sun} from "lucide-react" -import {Button} from "@/components/ui/button" -import {DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger} from "@/components/ui/dropdown-menu" -import {authClient} from "@/lib/auth/auth-client"; -import {toast} from "sonner"; +import { Moon, Sun, Monitor } from "lucide-react" +import { authClient } from "@/lib/auth/auth-client" +import { motion } from "motion/react" +import { useTheme } from "next-themes" +import { cn } from "@/lib/utils" + +const themes = [ + { id: "light", icon: Sun, label: "Light" }, + { id: "system", icon: Monitor, label: "System" }, + { id: "dark", icon: Moon, label: "Dark" }, +] as const export function ModeToggle() { + const { theme } = useTheme() - const setTheme = async (theme: "light" | "dark" | "system") => { - toast.success("Your theme preference has been updated."); - await authClient.updateUser({theme: theme}); - }; + + const currentIndex = themes.findIndex((t) => t.id === theme) + const activeIndex = currentIndex === -1 ? 1 : currentIndex + + const handleThemeChange = async (newTheme: "light" | "system" | "dark") => { + await authClient.updateUser({ theme: newTheme }) + } return ( - - - - - - setTheme("light")}> - Light - - setTheme("dark")}> - Dark - - setTheme("system")}> - System - - - +
+ + +
+ {themes.map((t) => { + const Icon = t.icon + const isActive = theme === t.id + + return ( + + ) + })} +
+
) -} - - +} \ No newline at end of file