chore: ran linting

This commit is contained in:
Anish Sarkar 2026-03-17 04:40:46 +05:30
parent bc1f31b481
commit ac0f2fa2eb
33 changed files with 688 additions and 661 deletions

View file

@ -419,19 +419,19 @@ export const ConnectorIndicator = forwardRef<ConnectorIndicatorHandle, Connector
: "You need to configure a Document Summary LLM before adding connectors. This LLM is used to process and summarize documents from your connected sources."}
</p>
<Button
size="sm"
variant="outline"
onClick={() => {
handleOpenChange(false);
setSearchSpaceSettingsDialog({
open: true,
initialTab: "models",
});
}}
>
<Settings className="mr-2 h-4 w-4" />
Go to Settings
</Button>
size="sm"
variant="outline"
onClick={() => {
handleOpenChange(false);
setSearchSpaceSettingsDialog({
open: true,
initialTab: "models",
});
}}
>
<Settings className="mr-2 h-4 w-4" />
Go to Settings
</Button>
</AlertDescription>
</Alert>
)}

View file

@ -159,19 +159,19 @@ const DocumentUploadPopupContent: FC<{
: "You need to configure a Document Summary LLM before uploading files. This LLM is used to process and summarize your uploaded documents."}
</p>
<Button
size="sm"
variant="outline"
onClick={() => {
onOpenChange(false);
setSearchSpaceSettingsDialog({
open: true,
initialTab: "models",
});
}}
>
<Settings className="mr-2 h-4 w-4" />
Go to Settings
</Button>
size="sm"
variant="outline"
onClick={() => {
onOpenChange(false);
setSearchSpaceSettingsDialog({
open: true,
initialTab: "models",
});
}}
>
<Settings className="mr-2 h-4 w-4" />
Go to Settings
</Button>
</AlertDescription>
</Alert>
) : (

View file

@ -233,7 +233,9 @@ const ThreadWelcome: FC = () => {
<div className="aui-thread-welcome-root mx-auto flex w-full max-w-(--thread-max-width) grow flex-col items-center px-4 relative">
{/* Greeting positioned above the composer */}
<div className="aui-thread-welcome-message absolute bottom-[calc(50%+5rem)] left-0 right-0 flex flex-col items-center text-center">
<h1 className="aui-thread-welcome-message-inner text-3xl md:text-5xl select-none">{greeting}</h1>
<h1 className="aui-thread-welcome-message-inner text-3xl md:text-5xl select-none">
{greeting}
</h1>
</div>
{/* Composer - top edge fixed, expands downward only */}
<div className="w-full flex items-start justify-center absolute top-[calc(50%-3.5rem)] left-0 right-0">
@ -283,7 +285,11 @@ const ConnectToolsBanner: FC = () => {
<span className="text-[13px] text-muted-foreground/80 flex-1">Connect your tools</span>
<AvatarGroup className="shrink-0">
{BANNER_CONNECTORS.map(({ type }, i) => (
<Avatar key={type} className="size-6" style={{ zIndex: BANNER_CONNECTORS.length - i }}>
<Avatar
key={type}
className="size-6"
style={{ zIndex: BANNER_CONNECTORS.length - i }}
>
<AvatarFallback className="bg-muted text-[10px]">
{getConnectorIcon(type, "size-3.5")}
</AvatarFallback>
@ -601,7 +607,10 @@ const ComposerAction: FC<ComposerActionProps> = ({ isBlockedByOtherUser = false
);
const filteredEnabledCount = useMemo(() => {
if (!filteredTools) return 0;
return filteredTools.length - disabledTools.filter((d) => filteredTools.some((t) => t.name === d)).length;
return (
filteredTools.length -
disabledTools.filter((d) => filteredTools.some((t) => t.name === d)).length
);
}, [filteredTools, disabledTools]);
useEffect(() => {
@ -775,8 +784,15 @@ const ComposerAction: FC<ComposerActionProps> = ({ isBlockedByOtherUser = false
)}
>
<motion.div
animate={{ rotate: isWebSearchEnabled ? 360 : 0, scale: isWebSearchEnabled ? 1.1 : 1 }}
whileHover={{ rotate: isWebSearchEnabled ? 360 : 15, scale: 1.1, transition: { type: "spring", stiffness: 300, damping: 10 } }}
animate={{
rotate: isWebSearchEnabled ? 360 : 0,
scale: isWebSearchEnabled ? 1.1 : 1,
}}
whileHover={{
rotate: isWebSearchEnabled ? 360 : 15,
scale: 1.1,
transition: { type: "spring", stiffness: 300, damping: 10 },
}}
transition={{ type: "spring", stiffness: 260, damping: 25 }}
>
<Globe className="size-4" />

View file

@ -286,9 +286,7 @@ export function LayoutShell({
<div
className={cn(
"relative hidden md:flex shrink-0 border bg-sidebar z-20 transition-[border-radius,border-color] duration-200",
anySlideOutOpen
? "rounded-l-xl border-r-0 delay-0"
: "rounded-xl delay-150"
anySlideOutOpen ? "rounded-l-xl border-r-0 delay-0" : "rounded-xl delay-150"
)}
>
<Sidebar

View file

@ -335,7 +335,10 @@ export function AllPrivateChatsSidebar({
{isLoading ? (
<div className="space-y-1">
{[75, 90, 55, 80, 65, 85].map((titleWidth) => (
<div key={`skeleton-${titleWidth}`} className="flex items-center gap-2 rounded-md px-2 py-1.5">
<div
key={`skeleton-${titleWidth}`}
className="flex items-center gap-2 rounded-md px-2 py-1.5"
>
<Skeleton className="h-4 w-4 shrink-0 rounded" />
<Skeleton className="h-4 rounded" style={{ width: `${titleWidth}%` }} />
</div>

View file

@ -335,7 +335,10 @@ export function AllSharedChatsSidebar({
{isLoading ? (
<div className="space-y-1">
{[75, 90, 55, 80, 65, 85].map((titleWidth) => (
<div key={`skeleton-${titleWidth}`} className="flex items-center gap-2 rounded-md px-2 py-1.5">
<div
key={`skeleton-${titleWidth}`}
className="flex items-center gap-2 rounded-md px-2 py-1.5"
>
<Skeleton className="h-4 w-4 shrink-0 rounded" />
<Skeleton className="h-4 rounded" style={{ width: `${titleWidth}%` }} />
</div>

View file

@ -73,10 +73,10 @@ export function NavSection({ items, onItemClick, isCollapsed = false }: NavSecti
const Icon = item.icon;
const indicator = item.statusIndicator;
const joyrideAttr =
item.title === "Inbox" || item.title.toLowerCase().includes("inbox")
? { "data-joyride": "inbox-sidebar" }
: {};
const joyrideAttr =
item.title === "Inbox" || item.title.toLowerCase().includes("inbox")
? { "data-joyride": "inbox-sidebar" }
: {};
if (isCollapsed) {
return (

View file

@ -39,30 +39,34 @@ export function SidebarSection({
className
)}
>
<div className="flex items-center group/section shrink-0 px-2 py-1.5">
<CollapsibleTrigger className="flex items-center gap-1.5 text-xs font-medium text-muted-foreground hover:text-foreground transition-colors min-w-0">
<span className="truncate">{title}</span>
<ChevronRight
className={cn(
"h-3.5 w-3.5 shrink-0 transition-transform duration-200",
isOpen && "rotate-90"
)}
/>
</CollapsibleTrigger>
<div className="flex items-center group/section shrink-0 px-2 py-1.5">
<CollapsibleTrigger className="flex items-center gap-1.5 text-xs font-medium text-muted-foreground hover:text-foreground transition-colors min-w-0">
<span className="truncate">{title}</span>
<ChevronRight
className={cn(
"h-3.5 w-3.5 shrink-0 transition-transform duration-200",
isOpen && "rotate-90"
)}
/>
</CollapsibleTrigger>
{action && (
<div className={cn(
"transition-opacity ml-1.5 flex items-center",
alwaysShowAction ? "opacity-100" : "opacity-100 md:opacity-0 md:group-hover/section:opacity-100"
)}>
{action}
</div>
)}
{action && (
<div
className={cn(
"transition-opacity ml-1.5 flex items-center",
alwaysShowAction
? "opacity-100"
: "opacity-100 md:opacity-0 md:group-hover/section:opacity-100"
)}
>
{action}
</div>
)}
{persistentAction && (
<div className="shrink-0 ml-auto flex items-center">{persistentAction}</div>
)}
</div>
{persistentAction && (
<div className="shrink-0 ml-auto flex items-center">{persistentAction}</div>
)}
</div>
<CollapsibleContent className={cn("overflow-hidden flex-1 flex flex-col min-h-0")}>
<div className={cn("px-2 pb-2 flex-1 flex flex-col min-h-0 overflow-hidden")}>

View file

@ -4,7 +4,6 @@ import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useAtomValue, useSetAtom } from "jotai";
import { Earth, User, Users } from "lucide-react";
import { useCallback, useMemo, useState } from "react";
import { toast } from "sonner";
import { currentThreadAtom, setThreadVisibilityAtom } from "@/atoms/chat/current-thread.atom";

View file

@ -237,7 +237,10 @@ export function ModelSelector({
size="sm"
role="combobox"
aria-expanded={open}
className={cn("h-8 gap-2 px-3 text-sm bg-main-panel hover:bg-accent/50 dark:hover:bg-white/[0.06] border border-border/40 select-none", className)}
className={cn(
"h-8 gap-2 px-3 text-sm bg-main-panel hover:bg-accent/50 dark:hover:bg-white/[0.06] border border-border/40 select-none",
className
)}
>
{isLoading ? (
<>
@ -281,9 +284,7 @@ export function ModelSelector({
)}
</>
)}
<ChevronDown
className="h-3.5 w-3.5 text-muted-foreground ml-1 shrink-0"
/>
<ChevronDown className="h-3.5 w-3.5 text-muted-foreground ml-1 shrink-0" />
</Button>
</PopoverTrigger>

View file

@ -58,52 +58,52 @@ export function PublicChatSnapshotRow({
<Card className="group relative overflow-hidden transition-all duration-200 border-border/60 hover:shadow-md h-full">
<CardContent className="p-4 flex flex-col gap-3 h-full">
{/* Header: Title + Actions */}
<div className="relative">
<div className="min-w-0 pr-16 sm:pr-0 sm:group-hover:pr-16">
<h4
className="text-sm font-semibold tracking-tight truncate"
title={snapshot.thread_title}
>
{snapshot.thread_title}
</h4>
</div>
<div className="flex items-center gap-0.5 shrink-0 sm:hidden sm:group-hover:flex absolute right-0 top-0">
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
asChild
className="h-7 w-7 text-muted-foreground hover:text-foreground"
>
<a href={snapshot.public_url} target="_blank" rel="noopener noreferrer">
<ExternalLink className="h-3 w-3" />
</a>
</Button>
</TooltipTrigger>
<TooltipContent>Open link</TooltipContent>
</Tooltip>
</TooltipProvider>
{canDelete && (
<div className="relative">
<div className="min-w-0 pr-16 sm:pr-0 sm:group-hover:pr-16">
<h4
className="text-sm font-semibold tracking-tight truncate"
title={snapshot.thread_title}
>
{snapshot.thread_title}
</h4>
</div>
<div className="flex items-center gap-0.5 shrink-0 sm:hidden sm:group-hover:flex absolute right-0 top-0">
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => onDelete(snapshot)}
disabled={isDeleting}
className="h-7 w-7 text-muted-foreground hover:text-destructive"
asChild
className="h-7 w-7 text-muted-foreground hover:text-foreground"
>
<Trash2 className="h-3 w-3" />
<a href={snapshot.public_url} target="_blank" rel="noopener noreferrer">
<ExternalLink className="h-3 w-3" />
</a>
</Button>
</TooltipTrigger>
<TooltipContent>Delete</TooltipContent>
<TooltipContent>Open link</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</div>
{canDelete && (
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => onDelete(snapshot)}
disabled={isDeleting}
className="h-7 w-7 text-muted-foreground hover:text-destructive"
>
<Trash2 className="h-3 w-3" />
</Button>
</TooltipTrigger>
<TooltipContent>Delete</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</div>
</div>
{/* Message count badge */}
@ -127,25 +127,25 @@ export function PublicChatSnapshotRow({
{snapshot.public_url}
</p>
</div>
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={handleCopyClick}
className="h-6 w-6 shrink-0 text-muted-foreground hover:text-foreground"
>
{copied ? (
<Check className="h-3 w-3 text-green-500" />
) : (
<Copy className="h-3 w-3" />
)}
</Button>
</TooltipTrigger>
<TooltipContent>{copied ? "Copied!" : "Copy link"}</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={handleCopyClick}
className="h-6 w-6 shrink-0 text-muted-foreground hover:text-foreground"
>
{copied ? (
<Check className="h-3 w-3 text-green-500" />
) : (
<Copy className="h-3 w-3" />
)}
</Button>
</TooltipTrigger>
<TooltipContent>{copied ? "Copied!" : "Copy link"}</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
{/* Footer: Date + Creator */}
@ -154,33 +154,33 @@ export function PublicChatSnapshotRow({
{member && (
<>
<span className="text-muted-foreground/30">·</span>
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<div className="flex items-center gap-1.5 cursor-default">
{member.avatarUrl ? (
<Image
src={member.avatarUrl}
alt={member.name}
width={18}
height={18}
className="h-4.5 w-4.5 rounded-full object-cover shrink-0"
/>
) : (
<div className="flex h-4.5 w-4.5 items-center justify-center rounded-full bg-gradient-to-br from-primary/20 to-primary/5 shrink-0">
<span className="text-[9px] font-semibold text-primary">
{getInitials(member.name)}
</span>
</div>
)}
<span className="text-[11px] text-muted-foreground/60 truncate max-w-[120px]">
{member.name}
</span>
</div>
</TooltipTrigger>
<TooltipContent side="bottom">{member.email || member.name}</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<div className="flex items-center gap-1.5 cursor-default">
{member.avatarUrl ? (
<Image
src={member.avatarUrl}
alt={member.name}
width={18}
height={18}
className="h-4.5 w-4.5 rounded-full object-cover shrink-0"
/>
) : (
<div className="flex h-4.5 w-4.5 items-center justify-center rounded-full bg-gradient-to-br from-primary/20 to-primary/5 shrink-0">
<span className="text-[9px] font-semibold text-primary">
{getInitials(member.name)}
</span>
</div>
)}
<span className="text-[11px] text-muted-foreground/60 truncate max-w-[120px]">
{member.name}
</span>
</div>
</TooltipTrigger>
<TooltipContent side="bottom">{member.email || member.name}</TooltipContent>
</Tooltip>
</TooltipProvider>
</>
)}
</div>

View file

@ -272,25 +272,25 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) {
<div className="space-y-4 md:space-y-6">
{/* Header */}
<div className="flex flex-col space-y-4 sm:flex-row sm:items-center sm:justify-between sm:space-y-0">
<Button
variant="secondary"
size="sm"
onClick={() => refreshConfigs()}
disabled={isLoading}
className="gap-2"
>
<RefreshCw className={cn("h-3.5 w-3.5", configsLoading && "animate-spin")} />
Refresh
</Button>
{canCreate && (
<Button
variant="outline"
onClick={openNewDialog}
className="gap-2 bg-white text-black hover:bg-neutral-100 dark:bg-white dark:text-black dark:hover:bg-neutral-200"
variant="secondary"
size="sm"
onClick={() => refreshConfigs()}
disabled={isLoading}
className="gap-2"
>
Add Image Model
<RefreshCw className={cn("h-3.5 w-3.5", configsLoading && "animate-spin")} />
Refresh
</Button>
)}
{canCreate && (
<Button
variant="outline"
onClick={openNewDialog}
className="gap-2 bg-white text-black hover:bg-neutral-100 dark:bg-white dark:text-black dark:hover:bg-neutral-200"
>
Add Image Model
</Button>
)}
</div>
{/* Errors */}
@ -420,114 +420,114 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) {
return (
<div key={config.id}>
<Card className="group relative overflow-hidden transition-all duration-200 border-border/60 hover:shadow-md h-full">
<CardContent className="p-4 flex flex-col gap-3 h-full">
{/* Header: Name + Actions */}
<div className="flex items-start justify-between gap-2">
<div className="min-w-0 flex-1">
<h4 className="text-sm font-semibold tracking-tight truncate">
{config.name}
</h4>
{config.description && (
<p className="text-[11px] text-muted-foreground/70 truncate mt-0.5">
{config.description}
</p>
)}
</div>
{(canUpdate || canDelete) && (
<div className="flex items-center gap-0.5 shrink-0 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity duration-150">
{canUpdate && (
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => openEditDialog(config)}
className="h-7 w-7 text-muted-foreground hover:text-foreground"
>
<Edit3 className="h-3 w-3" />
</Button>
</TooltipTrigger>
<TooltipContent>Edit</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
{canDelete && (
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => setConfigToDelete(config)}
className="h-7 w-7 text-muted-foreground hover:text-destructive"
>
<Trash2 className="h-3 w-3" />
</Button>
</TooltipTrigger>
<TooltipContent>Delete</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</div>
<Card className="group relative overflow-hidden transition-all duration-200 border-border/60 hover:shadow-md h-full">
<CardContent className="p-4 flex flex-col gap-3 h-full">
{/* Header: Name + Actions */}
<div className="flex items-start justify-between gap-2">
<div className="min-w-0 flex-1">
<h4 className="text-sm font-semibold tracking-tight truncate">
{config.name}
</h4>
{config.description && (
<p className="text-[11px] text-muted-foreground/70 truncate mt-0.5">
{config.description}
</p>
)}
</div>
{/* Provider + Model */}
<div className="flex items-center gap-2 flex-wrap">
{getProviderIcon(config.provider, { className: "size-3.5 shrink-0" })}
<code className="text-[11px] font-mono text-muted-foreground bg-muted/60 px-2 py-0.5 rounded-md truncate max-w-[160px]">
{config.model_name}
</code>
</div>
{/* Footer: Date + Creator */}
<div className="flex items-center gap-2 pt-2 border-t border-border/40 mt-auto">
<span className="text-[11px] text-muted-foreground/60">
{new Date(config.created_at).toLocaleDateString(undefined, {
year: "numeric",
month: "short",
day: "numeric",
})}
</span>
{member && (
<>
<span className="text-muted-foreground/30">·</span>
{(canUpdate || canDelete) && (
<div className="flex items-center gap-0.5 shrink-0 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity duration-150">
{canUpdate && (
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<div className="flex items-center gap-1.5 cursor-default">
{member.avatarUrl ? (
<Image
src={member.avatarUrl}
alt={member.name}
width={18}
height={18}
className="h-4.5 w-4.5 rounded-full object-cover shrink-0"
/>
) : (
<div className="flex h-4.5 w-4.5 items-center justify-center rounded-full bg-gradient-to-br from-primary/20 to-primary/5 shrink-0">
<span className="text-[9px] font-semibold text-primary">
{getInitials(member.name)}
</span>
</div>
)}
<span className="text-[11px] text-muted-foreground/60 truncate max-w-[120px]">
{member.name}
</span>
</div>
<Button
variant="ghost"
size="icon"
onClick={() => openEditDialog(config)}
className="h-7 w-7 text-muted-foreground hover:text-foreground"
>
<Edit3 className="h-3 w-3" />
</Button>
</TooltipTrigger>
<TooltipContent side="bottom">
{member.email || member.name}
</TooltipContent>
<TooltipContent>Edit</TooltipContent>
</Tooltip>
</TooltipProvider>
</>
)}
</div>
</CardContent>
</Card>
)}
{canDelete && (
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => setConfigToDelete(config)}
className="h-7 w-7 text-muted-foreground hover:text-destructive"
>
<Trash2 className="h-3 w-3" />
</Button>
</TooltipTrigger>
<TooltipContent>Delete</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</div>
)}
</div>
{/* Provider + Model */}
<div className="flex items-center gap-2 flex-wrap">
{getProviderIcon(config.provider, { className: "size-3.5 shrink-0" })}
<code className="text-[11px] font-mono text-muted-foreground bg-muted/60 px-2 py-0.5 rounded-md truncate max-w-[160px]">
{config.model_name}
</code>
</div>
{/* Footer: Date + Creator */}
<div className="flex items-center gap-2 pt-2 border-t border-border/40 mt-auto">
<span className="text-[11px] text-muted-foreground/60">
{new Date(config.created_at).toLocaleDateString(undefined, {
year: "numeric",
month: "short",
day: "numeric",
})}
</span>
{member && (
<>
<span className="text-muted-foreground/30">·</span>
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<div className="flex items-center gap-1.5 cursor-default">
{member.avatarUrl ? (
<Image
src={member.avatarUrl}
alt={member.name}
width={18}
height={18}
className="h-4.5 w-4.5 rounded-full object-cover shrink-0"
/>
) : (
<div className="flex h-4.5 w-4.5 items-center justify-center rounded-full bg-gradient-to-br from-primary/20 to-primary/5 shrink-0">
<span className="text-[9px] font-semibold text-primary">
{getInitials(member.name)}
</span>
</div>
)}
<span className="text-[11px] text-muted-foreground/60 truncate max-w-[120px]">
{member.name}
</span>
</div>
</TooltipTrigger>
<TooltipContent side="bottom">
{member.email || member.name}
</TooltipContent>
</Tooltip>
</TooltipProvider>
</>
)}
</div>
</CardContent>
</Card>
</div>
);
})}
@ -705,20 +705,20 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) {
</div>
)}
{/* Actions */}
<div className="flex justify-end gap-3 pt-4 border-t">
<Button
variant="secondary"
onClick={() => {
setIsDialogOpen(false);
setEditingConfig(null);
resetForm();
}}
>
Cancel
</Button>
<Button
onClick={handleFormSubmit}
{/* Actions */}
<div className="flex justify-end gap-3 pt-4 border-t">
<Button
variant="secondary"
onClick={() => {
setIsDialogOpen(false);
setEditingConfig(null);
resetForm();
}}
>
Cancel
</Button>
<Button
onClick={handleFormSubmit}
disabled={
isSubmitting ||
!formData.name ||

View file

@ -227,15 +227,15 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
<div className="space-y-5 md:space-y-6">
{/* Header actions */}
<div className="flex items-center justify-between">
<Button
variant="secondary"
size="sm"
onClick={() => refreshConfigs()}
disabled={isLoading}
className="gap-2"
>
<RefreshCw className="h-3.5 w-3.5" />
Refresh
<Button
variant="secondary"
size="sm"
onClick={() => refreshConfigs()}
disabled={isLoading}
className="gap-2"
>
<RefreshCw className="h-3.5 w-3.5" />
Refresh
</Button>
{isAssignmentComplete && !isLoading && !hasError && (
<Badge

View file

@ -180,24 +180,24 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) {
<div className="space-y-5 md:space-y-6">
{/* Header actions */}
<div className="flex items-center justify-between">
<Button
variant="secondary"
size="sm"
onClick={() => refreshConfigs()}
disabled={isLoading}
className="gap-2"
>
<RefreshCw className={cn("h-3.5 w-3.5", isLoading && "animate-spin")} />
Refresh
</Button>
{canCreate && (
<Button
variant="outline"
onClick={openNewDialog}
className="gap-2 bg-white text-black hover:bg-neutral-100 dark:bg-white dark:text-black dark:hover:bg-neutral-200"
variant="secondary"
size="sm"
onClick={() => refreshConfigs()}
disabled={isLoading}
className="gap-2"
>
Add Configuration
<RefreshCw className={cn("h-3.5 w-3.5", isLoading && "animate-spin")} />
Refresh
</Button>
{canCreate && (
<Button
variant="outline"
onClick={openNewDialog}
className="gap-2 bg-white text-black hover:bg-neutral-100 dark:bg-white dark:text-black dark:hover:bg-neutral-200"
>
Add Configuration
</Button>
)}
</div>
@ -330,140 +330,140 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) {
return (
<div key={config.id}>
<Card className="group relative overflow-hidden transition-all duration-200 border-border/60 hover:shadow-md h-full">
<CardContent className="p-4 flex flex-col gap-3 h-full">
{/* Header: Name + Actions */}
<div className="flex items-start justify-between gap-2">
<div className="min-w-0 flex-1">
<h4 className="text-sm font-semibold tracking-tight truncate">
{config.name}
</h4>
{config.description && (
<p className="text-[11px] text-muted-foreground/70 truncate mt-0.5">
{config.description}
</p>
)}
</div>
{(canUpdate || canDelete) && (
<div className="flex items-center gap-0.5 shrink-0 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity duration-150">
{canUpdate && (
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => openEditDialog(config)}
className="h-7 w-7 text-muted-foreground hover:text-foreground"
>
<Edit3 className="h-3 w-3" />
</Button>
</TooltipTrigger>
<TooltipContent>Edit</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
{canDelete && (
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => setConfigToDelete(config)}
className="h-7 w-7 text-muted-foreground hover:text-destructive"
>
<Trash2 className="h-3 w-3" />
</Button>
</TooltipTrigger>
<TooltipContent>Delete</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</div>
<Card className="group relative overflow-hidden transition-all duration-200 border-border/60 hover:shadow-md h-full">
<CardContent className="p-4 flex flex-col gap-3 h-full">
{/* Header: Name + Actions */}
<div className="flex items-start justify-between gap-2">
<div className="min-w-0 flex-1">
<h4 className="text-sm font-semibold tracking-tight truncate">
{config.name}
</h4>
{config.description && (
<p className="text-[11px] text-muted-foreground/70 truncate mt-0.5">
{config.description}
</p>
)}
</div>
{/* Provider + Model */}
<div className="flex items-center gap-2 flex-wrap">
{getProviderIcon(config.provider, { className: "size-3.5 shrink-0" })}
<code className="text-[11px] font-mono text-muted-foreground bg-muted/60 px-2 py-0.5 rounded-md truncate max-w-[160px]">
{config.model_name}
</code>
</div>
{/* Feature badges */}
<div className="flex items-center gap-1.5 flex-wrap">
{config.citations_enabled && (
<Badge
variant="outline"
className="text-[10px] px-1.5 py-0.5 border-emerald-500/30 text-emerald-700 dark:text-emerald-300 bg-emerald-500/5"
>
<MessageSquareQuote className="h-2.5 w-2.5 mr-1" />
Citations
</Badge>
)}
{!config.use_default_system_instructions &&
config.system_instructions && (
<Badge
variant="outline"
className="text-[10px] px-1.5 py-0.5 border-blue-500/30 text-blue-700 dark:text-blue-300 bg-blue-500/5"
>
<FileText className="h-2.5 w-2.5 mr-1" />
Custom
</Badge>
)}
</div>
{/* Footer: Date + Creator */}
<div className="flex items-center gap-2 pt-2 border-t border-border/40 mt-auto">
<span className="text-[11px] text-muted-foreground/60">
{new Date(config.created_at).toLocaleDateString(undefined, {
year: "numeric",
month: "short",
day: "numeric",
})}
</span>
{member && (
<>
<span className="text-muted-foreground/30">·</span>
{(canUpdate || canDelete) && (
<div className="flex items-center gap-0.5 shrink-0 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity duration-150">
{canUpdate && (
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<div className="flex items-center gap-1.5 cursor-default">
{member.avatarUrl ? (
<Image
src={member.avatarUrl}
alt={member.name}
width={18}
height={18}
className="h-4.5 w-4.5 rounded-full object-cover shrink-0"
/>
) : (
<div className="flex h-4.5 w-4.5 items-center justify-center rounded-full bg-gradient-to-br from-primary/20 to-primary/5 shrink-0">
<span className="text-[9px] font-semibold text-primary">
{getInitials(member.name)}
</span>
</div>
)}
<span className="text-[11px] text-muted-foreground/60 truncate max-w-[120px]">
{member.name}
</span>
</div>
<Button
variant="ghost"
size="icon"
onClick={() => openEditDialog(config)}
className="h-7 w-7 text-muted-foreground hover:text-foreground"
>
<Edit3 className="h-3 w-3" />
</Button>
</TooltipTrigger>
<TooltipContent side="bottom">
{member.email || member.name}
</TooltipContent>
<TooltipContent>Edit</TooltipContent>
</Tooltip>
</TooltipProvider>
</>
)}
{canDelete && (
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => setConfigToDelete(config)}
className="h-7 w-7 text-muted-foreground hover:text-destructive"
>
<Trash2 className="h-3 w-3" />
</Button>
</TooltipTrigger>
<TooltipContent>Delete</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</div>
)}
</div>
{/* Provider + Model */}
<div className="flex items-center gap-2 flex-wrap">
{getProviderIcon(config.provider, { className: "size-3.5 shrink-0" })}
<code className="text-[11px] font-mono text-muted-foreground bg-muted/60 px-2 py-0.5 rounded-md truncate max-w-[160px]">
{config.model_name}
</code>
</div>
{/* Feature badges */}
<div className="flex items-center gap-1.5 flex-wrap">
{config.citations_enabled && (
<Badge
variant="outline"
className="text-[10px] px-1.5 py-0.5 border-emerald-500/30 text-emerald-700 dark:text-emerald-300 bg-emerald-500/5"
>
<MessageSquareQuote className="h-2.5 w-2.5 mr-1" />
Citations
</Badge>
)}
{!config.use_default_system_instructions &&
config.system_instructions && (
<Badge
variant="outline"
className="text-[10px] px-1.5 py-0.5 border-blue-500/30 text-blue-700 dark:text-blue-300 bg-blue-500/5"
>
<FileText className="h-2.5 w-2.5 mr-1" />
Custom
</Badge>
)}
</div>
</CardContent>
</Card>
</div>
);
})}
</div>
{/* Footer: Date + Creator */}
<div className="flex items-center gap-2 pt-2 border-t border-border/40 mt-auto">
<span className="text-[11px] text-muted-foreground/60">
{new Date(config.created_at).toLocaleDateString(undefined, {
year: "numeric",
month: "short",
day: "numeric",
})}
</span>
{member && (
<>
<span className="text-muted-foreground/30">·</span>
<TooltipProvider>
<Tooltip open={isDesktop ? undefined : false}>
<TooltipTrigger asChild>
<div className="flex items-center gap-1.5 cursor-default">
{member.avatarUrl ? (
<Image
src={member.avatarUrl}
alt={member.name}
width={18}
height={18}
className="h-4.5 w-4.5 rounded-full object-cover shrink-0"
/>
) : (
<div className="flex h-4.5 w-4.5 items-center justify-center rounded-full bg-gradient-to-br from-primary/20 to-primary/5 shrink-0">
<span className="text-[9px] font-semibold text-primary">
{getInitials(member.name)}
</span>
</div>
)}
<span className="text-[11px] text-muted-foreground/60 truncate max-w-[120px]">
{member.name}
</span>
</div>
</TooltipTrigger>
<TooltipContent side="bottom">
{member.email || member.name}
</TooltipContent>
</Tooltip>
</TooltipProvider>
</>
)}
</div>
</CardContent>
</Card>
</div>
);
})}
</div>
)}
</div>

View file

@ -85,16 +85,16 @@ export function MorePagesContent() {
</div>
{isLoading ? (
<Card>
<CardContent className="flex items-center gap-3 p-3">
<Skeleton className="h-9 w-9 rounded-full bg-muted" />
<div className="flex-1 space-y-2">
<Skeleton className="h-4 w-3/4 bg-muted" />
<Skeleton className="h-3 w-1/4 bg-muted" />
</div>
<Skeleton className="h-8 w-16 bg-muted" />
</CardContent>
</Card>
<Card>
<CardContent className="flex items-center gap-3 p-3">
<Skeleton className="h-9 w-9 rounded-full bg-muted" />
<div className="flex-1 space-y-2">
<Skeleton className="h-4 w-3/4 bg-muted" />
<Skeleton className="h-3 w-1/4 bg-muted" />
</div>
<Skeleton className="h-8 w-16 bg-muted" />
</CardContent>
</Card>
) : (
<div className="space-y-2">
{data?.tasks.map((task) => (
@ -122,14 +122,14 @@ export function MorePagesContent() {
</p>
<p className="text-xs text-muted-foreground">+{task.pages_reward} pages</p>
</div>
<Button
variant="ghost"
size="sm"
disabled={task.completed || completeMutation.isPending}
onClick={() => handleTaskClick(task)}
asChild={!task.completed}
className="text-muted-foreground hover:text-foreground"
>
<Button
variant="ghost"
size="sm"
disabled={task.completed || completeMutation.isPending}
onClick={() => handleTaskClick(task)}
asChild={!task.completed}
className="text-muted-foreground hover:text-foreground"
>
{task.completed ? (
<span>Done</span>
) : (
@ -185,11 +185,7 @@ export function MorePagesContent() {
</DialogHeader>
<div className="flex flex-col gap-2">
<Button asChild>
<Link
href="https://cal.com/mod-rohan"
target="_blank"
rel="noopener noreferrer"
>
<Link href="https://cal.com/mod-rohan" target="_blank" rel="noopener noreferrer">
<IconCalendar className="h-4 w-4" />
Schedule a Meeting
</Link>

View file

@ -176,17 +176,17 @@ export function PromptConfigManager({ searchSpaceId }: PromptConfigManagerProps)
</CardContent>
</Card>
{/* Action Buttons */}
<div className="flex justify-end pt-3 md:pt-4">
<Button
variant="outline"
onClick={handleSave}
disabled={!hasChanges || saving}
className="gap-2 bg-white text-black hover:bg-neutral-100 dark:bg-white dark:text-black dark:hover:bg-neutral-200"
>
{saving ? "Saving" : "Save Instructions"}
</Button>
</div>
{/* Action Buttons */}
<div className="flex justify-end pt-3 md:pt-4">
<Button
variant="outline"
onClick={handleSave}
disabled={!hasChanges || saving}
className="gap-2 bg-white text-black hover:bg-neutral-100 dark:bg-white dark:text-black dark:hover:bg-neutral-200"
>
{saving ? "Saving" : "Save Instructions"}
</Button>
</div>
</div>
);
}

View file

@ -682,11 +682,11 @@ function PermissionsEditor({
return (
<div key={category} className="rounded-lg border border-border/60 overflow-hidden">
<button
type="button"
className="w-full flex items-center justify-between px-3 py-2.5 cursor-pointer hover:bg-muted/40 transition-colors"
onClick={() => toggleCategoryExpanded(category)}
>
<button
type="button"
className="w-full flex items-center justify-between px-3 py-2.5 cursor-pointer hover:bg-muted/40 transition-colors"
onClick={() => toggleCategoryExpanded(category)}
>
<div className="flex items-center gap-2.5">
<IconComponent className="h-4 w-4 text-muted-foreground shrink-0" />
<span className="font-medium text-sm">{config.label}</span>
@ -702,10 +702,7 @@ function PermissionsEditor({
aria-label={`Select all ${config.label} permissions`}
/>
<div
className={cn(
"transition-transform duration-200",
isExpanded && "rotate-180"
)}
className={cn("transition-transform duration-200", isExpanded && "rotate-180")}
>
<svg
className="h-4 w-4 text-muted-foreground"
@ -933,11 +930,11 @@ function CreateRoleDialog({
/>
</div>
</div>
<div className="flex items-center justify-end gap-3 px-5 py-3 shrink-0">
<Button variant="secondary" onClick={handleClose}>
Cancel
</Button>
<Button onClick={handleCreate} disabled={creating || !name.trim()}>
<div className="flex items-center justify-end gap-3 px-5 py-3 shrink-0">
<Button variant="secondary" onClick={handleClose}>
Cancel
</Button>
<Button onClick={handleCreate} disabled={creating || !name.trim()}>
{creating ? (
<>
<Spinner size="sm" className="mr-2" />
@ -1091,10 +1088,10 @@ function EditRoleDialog({
/>
</div>
</div>
<div className="flex items-center justify-end gap-3 px-5 py-3 border-t shrink-0">
<Button variant="secondary" onClick={() => onOpenChange(false)}>
Cancel
</Button>
<div className="flex items-center justify-end gap-3 px-5 py-3 border-t shrink-0">
<Button variant="secondary" onClick={() => onOpenChange(false)}>
Cancel
</Button>
<Button onClick={handleSave} disabled={saving || !name.trim()}>
{saving ? (
<>

View file

@ -60,11 +60,11 @@ export function SettingsDialog({
type="button"
onClick={() => onItemChange(item.value)}
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors text-left focus:outline-none focus-visible:outline-none",
activeItem === item.value
? "bg-accent text-accent-foreground"
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground"
)}
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors text-left focus:outline-none focus-visible:outline-none",
activeItem === item.value
? "bg-accent text-accent-foreground"
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground"
)}
>
{item.icon}
{item.label}
@ -94,11 +94,11 @@ export function SettingsDialog({
type="button"
onClick={() => handleItemChange(item.value)}
className={cn(
"flex items-center gap-2 whitespace-nowrap rounded-full px-3 py-1.5 text-xs font-medium transition-colors shrink-0 focus:outline-none focus-visible:outline-none",
activeItem === item.value
? "bg-accent text-accent-foreground"
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground"
)}
"flex items-center gap-2 whitespace-nowrap rounded-full px-3 py-1.5 text-xs font-medium transition-colors shrink-0 focus:outline-none focus-visible:outline-none",
activeItem === item.value
? "bg-accent text-accent-foreground"
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground"
)}
>
{item.icon}
{item.label}

View file

@ -562,17 +562,17 @@ export function LLMConfigForm({
compact ? "justify-end" : "justify-center sm:justify-end"
)}
>
{onCancel && (
<Button
type="button"
variant="secondary"
onClick={onCancel}
disabled={isSubmitting}
className="text-xs sm:text-sm h-9 sm:h-10"
>
Cancel
</Button>
)}
{onCancel && (
<Button
type="button"
variant="secondary"
onClick={onCancel}
disabled={isSubmitting}
className="text-xs sm:text-sm h-9 sm:h-10"
>
Cancel
</Button>
)}
<Button
type="submit"
disabled={isSubmitting}