chore: linting

This commit is contained in:
DESKTOP-RTLN3BA\$punk 2026-03-31 14:45:46 -07:00
parent 5ae5a671e7
commit 17642493eb
43 changed files with 224 additions and 196 deletions

View file

@ -7,6 +7,7 @@ Revises: 112
from collections.abc import Sequence from collections.abc import Sequence
import sqlalchemy as sa import sqlalchemy as sa
from alembic import op from alembic import op
revision: str = "113" revision: str = "113"
@ -25,8 +26,7 @@ def upgrade() -> None:
" ON prompts (is_public) WHERE is_public = true" " ON prompts (is_public) WHERE is_public = true"
) )
op.execute( op.execute(
"ALTER TABLE prompts ADD COLUMN IF NOT EXISTS" "ALTER TABLE prompts ADD COLUMN IF NOT EXISTS default_prompt_slug VARCHAR(100)"
" default_prompt_slug VARCHAR(100)"
) )
op.execute( op.execute(
"CREATE INDEX IF NOT EXISTS ix_prompts_default_prompt_slug" "CREATE INDEX IF NOT EXISTS ix_prompts_default_prompt_slug"

View file

@ -145,8 +145,7 @@ def create_create_dropbox_file_tool(
"name": item["name"], "name": item["name"],
} }
for item in items for item in items
if item.get(".tag") == "folder" if item.get(".tag") == "folder" and item.get("name")
and item.get("name")
] ]
except Exception: except Exception:
logger.warning( logger.warning(
@ -239,12 +238,12 @@ def create_create_dropbox_file_tool(
client = DropboxClient(session=db_session, connector_id=connector.id) client = DropboxClient(session=db_session, connector_id=connector.id)
parent_path = final_parent_folder_path or "" parent_path = final_parent_folder_path or ""
file_path = f"{parent_path}/{final_name}" if parent_path else f"/{final_name}" file_path = (
f"{parent_path}/{final_name}" if parent_path else f"/{final_name}"
)
if final_file_type == "paper": if final_file_type == "paper":
created = await client.create_paper_doc( created = await client.create_paper_doc(file_path, final_content or "")
file_path, final_content or ""
)
file_id = created.get("file_id", "") file_id = created.get("file_id", "")
web_url = created.get("url", "") web_url = created.get("url", "")
else: else:
@ -255,9 +254,7 @@ def create_create_dropbox_file_tool(
file_id = created.get("id", "") file_id = created.get("id", "")
web_url = "" web_url = ""
logger.info( logger.info(f"Dropbox file created: id={file_id}, name={final_name}")
f"Dropbox file created: id={file_id}, name={final_name}"
)
kb_message_suffix = "" kb_message_suffix = ""
try: try:

View file

@ -248,9 +248,7 @@ def create_delete_dropbox_file_tool(
f"Deleting Dropbox file: path='{final_file_path}', connector={actual_connector_id}" f"Deleting Dropbox file: path='{final_file_path}', connector={actual_connector_id}"
) )
client = DropboxClient( client = DropboxClient(session=db_session, connector_id=actual_connector_id)
session=db_session, connector_id=actual_connector_id
)
await client.delete_file(final_file_path) await client.delete_file(final_file_path)
logger.info(f"Dropbox file deleted: path={final_file_path}") logger.info(f"Dropbox file deleted: path={final_file_path}")

View file

@ -225,18 +225,14 @@ class DropboxClient:
return all_items, None return all_items, None
async def get_metadata( async def get_metadata(self, path: str) -> tuple[dict[str, Any] | None, str | None]:
self, path: str
) -> tuple[dict[str, Any] | None, str | None]:
resp = await self._request("/2/files/get_metadata", {"path": path}) resp = await self._request("/2/files/get_metadata", {"path": path})
if resp.status_code != 200: if resp.status_code != 200:
return None, f"Failed to get metadata: {resp.status_code} - {resp.text}" return None, f"Failed to get metadata: {resp.status_code} - {resp.text}"
return resp.json(), None return resp.json(), None
async def download_file(self, path: str) -> tuple[bytes | None, str | None]: async def download_file(self, path: str) -> tuple[bytes | None, str | None]:
resp = await self._content_request( resp = await self._content_request("/2/files/download", {"path": path})
"/2/files/download", {"path": path}
)
if resp.status_code != 200: if resp.status_code != 200:
return None, f"Download failed: {resp.status_code}" return None, f"Download failed: {resp.status_code}"
return resp.content, None return resp.content, None

View file

@ -8,7 +8,6 @@ import contextlib
import logging import logging
import os import os
import tempfile import tempfile
from pathlib import Path
from typing import Any from typing import Any
from .client import DropboxClient from .client import DropboxClient

View file

@ -9,8 +9,8 @@ from .clickup_add_connector_route import router as clickup_add_connector_router
from .composio_routes import router as composio_router from .composio_routes import router as composio_router
from .confluence_add_connector_route import router as confluence_add_connector_router from .confluence_add_connector_route import router as confluence_add_connector_router
from .discord_add_connector_route import router as discord_add_connector_router from .discord_add_connector_route import router as discord_add_connector_router
from .dropbox_add_connector_route import router as dropbox_add_connector_router
from .documents_routes import router as documents_router from .documents_routes import router as documents_router
from .dropbox_add_connector_route import router as dropbox_add_connector_router
from .editor_routes import router as editor_router from .editor_routes import router as editor_router
from .folders_routes import router as folders_router from .folders_routes import router as folders_router
from .google_calendar_add_connector_route import ( from .google_calendar_add_connector_route import (

View file

@ -72,9 +72,7 @@ async def connect_dropbox(space_id: int, user: User = Depends(current_active_use
if not space_id: if not space_id:
raise HTTPException(status_code=400, detail="space_id is required") raise HTTPException(status_code=400, detail="space_id is required")
if not config.DROPBOX_APP_KEY: if not config.DROPBOX_APP_KEY:
raise HTTPException( raise HTTPException(status_code=500, detail="Dropbox OAuth not configured.")
status_code=500, detail="Dropbox OAuth not configured."
)
if not config.SECRET_KEY: if not config.SECRET_KEY:
raise HTTPException( raise HTTPException(
status_code=500, detail="SECRET_KEY not configured for OAuth security." status_code=500, detail="SECRET_KEY not configured for OAuth security."

View file

@ -466,7 +466,9 @@ async def index_dropbox_files(
folders = items_dict.get("folders", []) folders = items_dict.get("folders", [])
for folder in folders: for folder in folders:
folder_path = folder.get("path", folder.get("path_lower", folder.get("id", ""))) folder_path = folder.get(
"path", folder.get("path_lower", folder.get("id", ""))
)
folder_name = folder.get("name", "Root") folder_name = folder.get("name", "Root")
logger.info(f"Using full scan for folder {folder_name}") logger.info(f"Using full scan for folder {folder_name}")

View file

@ -150,10 +150,7 @@ export function LocalLoginForm() {
</AnimatePresence> </AnimatePresence>
<div> <div>
<label <label htmlFor="email" className="block text-sm font-medium text-foreground">
htmlFor="email"
className="block text-sm font-medium text-foreground"
>
{t("email")} {t("email")}
</label> </label>
<input <input
@ -173,10 +170,7 @@ export function LocalLoginForm() {
</div> </div>
<div> <div>
<label <label htmlFor="password" className="block text-sm font-medium text-foreground">
htmlFor="password"
className="block text-sm font-medium text-foreground"
>
{t("password")} {t("password")}
</label> </label>
<div className="relative"> <div className="relative">
@ -223,10 +217,7 @@ export function LocalLoginForm() {
<div className="mt-4 text-center text-sm"> <div className="mt-4 text-center text-sm">
<p className="text-muted-foreground"> <p className="text-muted-foreground">
{t("dont_have_account")}{" "} {t("dont_have_account")}{" "}
<Link <Link href="/register" className="font-medium text-primary hover:text-primary/90">
href="/register"
className="font-medium text-primary hover:text-primary/90"
>
{t("sign_up")} {t("sign_up")}
</Link> </Link>
</p> </p>

View file

@ -3,8 +3,8 @@
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useEffect } from "react"; import { useEffect } from "react";
import { getBearerToken } from "@/lib/auth-utils";
import { HeroSection } from "@/components/homepage/hero-section"; import { HeroSection } from "@/components/homepage/hero-section";
import { getBearerToken } from "@/lib/auth-utils";
const FeaturesCards = dynamic( const FeaturesCards = dynamic(
() => import("@/components/homepage/features-card").then((m) => ({ default: m.FeaturesCards })), () => import("@/components/homepage/features-card").then((m) => ({ default: m.FeaturesCards })),

View file

@ -230,7 +230,9 @@ export function PromptsContent() {
Cancel Cancel
</Button> </Button>
<Button size="sm" onClick={handleSave} disabled={isSaving} className="relative"> <Button size="sm" onClick={handleSave} disabled={isSaving} className="relative">
<span className={isSaving ? "opacity-0" : ""}>{editingId !== null ? "Update" : "Create"}</span> <span className={isSaving ? "opacity-0" : ""}>
{editingId !== null ? "Update" : "Create"}
</span>
{isSaving && <Spinner className="size-3.5 absolute" />} {isSaving && <Spinner className="size-3.5 absolute" />}
</Button> </Button>
</div> </div>
@ -323,7 +325,10 @@ export function PromptsContent() {
</div> </div>
)} )}
<AlertDialog open={deleteTarget !== null} onOpenChange={(open) => !open && setDeleteTarget(null)}> <AlertDialog
open={deleteTarget !== null}
onOpenChange={(open) => !open && setDeleteTarget(null)}
>
<AlertDialogContent> <AlertDialogContent>
<AlertDialogHeader> <AlertDialogHeader>
<AlertDialogTitle>Delete prompt</AlertDialogTitle> <AlertDialogTitle>Delete prompt</AlertDialogTitle>

View file

@ -6,7 +6,6 @@ import {
useAui, useAui,
useAuiState, useAuiState,
} from "@assistant-ui/react"; } from "@assistant-ui/react";
import dynamic from "next/dynamic";
import { useAtomValue } from "jotai"; import { useAtomValue } from "jotai";
import { import {
CheckIcon, CheckIcon,
@ -18,6 +17,7 @@ import {
MessageSquare, MessageSquare,
RefreshCwIcon, RefreshCwIcon,
} from "lucide-react"; } from "lucide-react";
import dynamic from "next/dynamic";
import type { FC } from "react"; import type { FC } from "react";
import { useEffect, useMemo, useRef, useState } from "react"; import { useEffect, useMemo, useRef, useState } from "react";
import { commentsEnabledAtom, targetCommentIdAtom } from "@/atoms/chat/current-thread.atom"; import { commentsEnabledAtom, targetCommentIdAtom } from "@/atoms/chat/current-thread.atom";
@ -37,6 +37,7 @@ import {
DeleteConfluencePageToolUI, DeleteConfluencePageToolUI,
UpdateConfluencePageToolUI, UpdateConfluencePageToolUI,
} from "@/components/tool-ui/confluence"; } from "@/components/tool-ui/confluence";
import { CreateDropboxFileToolUI, DeleteDropboxFileToolUI } from "@/components/tool-ui/dropbox";
import { GenerateImageToolUI } from "@/components/tool-ui/generate-image"; import { GenerateImageToolUI } from "@/components/tool-ui/generate-image";
import { GeneratePodcastToolUI } from "@/components/tool-ui/generate-podcast"; import { GeneratePodcastToolUI } from "@/components/tool-ui/generate-podcast";
import { GenerateReportToolUI } from "@/components/tool-ui/generate-report"; import { GenerateReportToolUI } from "@/components/tool-ui/generate-report";
@ -70,7 +71,6 @@ import {
DeleteNotionPageToolUI, DeleteNotionPageToolUI,
UpdateNotionPageToolUI, UpdateNotionPageToolUI,
} from "@/components/tool-ui/notion"; } from "@/components/tool-ui/notion";
import { CreateDropboxFileToolUI, DeleteDropboxFileToolUI } from "@/components/tool-ui/dropbox";
import { CreateOneDriveFileToolUI, DeleteOneDriveFileToolUI } from "@/components/tool-ui/onedrive"; import { CreateOneDriveFileToolUI, DeleteOneDriveFileToolUI } from "@/components/tool-ui/onedrive";
import { SandboxExecuteToolUI } from "@/components/tool-ui/sandbox-execute"; import { SandboxExecuteToolUI } from "@/components/tool-ui/sandbox-execute";
import { import {
@ -78,7 +78,13 @@ import {
resolveSafeNavigationHref, resolveSafeNavigationHref,
} from "@/components/tool-ui/shared/media"; } from "@/components/tool-ui/shared/media";
import { RecallMemoryToolUI, SaveMemoryToolUI } from "@/components/tool-ui/user-memory"; import { RecallMemoryToolUI, SaveMemoryToolUI } from "@/components/tool-ui/user-memory";
import { Drawer, DrawerContent, DrawerHandle, DrawerHeader, DrawerTitle } from "@/components/ui/drawer"; import {
Drawer,
DrawerContent,
DrawerHandle,
DrawerHeader,
DrawerTitle,
} from "@/components/ui/drawer";
import { useComments } from "@/hooks/use-comments"; import { useComments } from "@/hooks/use-comments";
import { useMediaQuery } from "@/hooks/use-media-query"; import { useMediaQuery } from "@/hooks/use-media-query";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";

View file

@ -243,7 +243,7 @@ export const MCPConnectForm: FC<ConnectFormProps> = ({ onSubmit, isSubmitting })
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
setShowDetails(prev => !prev); setShowDetails((prev) => !prev);
}} }}
> >
{showDetails ? ( {showDetails ? (

View file

@ -239,7 +239,7 @@ export const ComposioDriveConfig: FC<ConnectorConfigProps> = ({ connector, onCon
<div className="space-y-2"> <div className="space-y-2">
<button <button
type="button" type="button"
onClick={() => setIsFolderTreeOpen(prev => !prev)} onClick={() => setIsFolderTreeOpen((prev) => !prev)}
className="flex items-center gap-2 text-xs sm:text-sm text-muted-foreground hover:text-foreground transition-colors w-fit" className="flex items-center gap-2 text-xs sm:text-sm text-muted-foreground hover:text-foreground transition-colors w-fit"
> >
Change Selection Change Selection

View file

@ -287,11 +287,21 @@ export const DropboxConfig: FC<ConnectorConfigProps> = ({ connector, onConfigCha
<SelectValue placeholder="Select limit" /> <SelectValue placeholder="Select limit" />
</SelectTrigger> </SelectTrigger>
<SelectContent className="z-[100]"> <SelectContent className="z-[100]">
<SelectItem value="50" className="text-xs sm:text-sm">50 files</SelectItem> <SelectItem value="50" className="text-xs sm:text-sm">
<SelectItem value="100" className="text-xs sm:text-sm">100 files</SelectItem> 50 files
<SelectItem value="250" className="text-xs sm:text-sm">250 files</SelectItem> </SelectItem>
<SelectItem value="500" className="text-xs sm:text-sm">500 files</SelectItem> <SelectItem value="100" className="text-xs sm:text-sm">
<SelectItem value="1000" className="text-xs sm:text-sm">1000 files</SelectItem> 100 files
</SelectItem>
<SelectItem value="250" className="text-xs sm:text-sm">
250 files
</SelectItem>
<SelectItem value="500" className="text-xs sm:text-sm">
500 files
</SelectItem>
<SelectItem value="1000" className="text-xs sm:text-sm">
1000 files
</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>

View file

@ -248,7 +248,7 @@ export const MCPConfig: FC<MCPConfigProps> = ({ connector, onConfigChange, onNam
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
setShowDetails(prev => !prev); setShowDetails((prev) => !prev);
}} }}
> >
{showDetails ? ( {showDetails ? (

View file

@ -220,7 +220,7 @@ export const OneDriveConfig: FC<ConnectorConfigProps> = ({ connector, onConfigCh
<div className="space-y-2"> <div className="space-y-2">
<button <button
type="button" type="button"
onClick={() => setIsFolderTreeOpen(prev => !prev)} onClick={() => setIsFolderTreeOpen((prev) => !prev)}
className="flex items-center gap-2 text-xs sm:text-sm text-muted-foreground hover:text-foreground transition-colors w-fit" className="flex items-center gap-2 text-xs sm:text-sm text-muted-foreground hover:text-foreground transition-colors w-fit"
> >
Change Selection Change Selection

View file

@ -78,7 +78,7 @@ export const WebcrawlerConfig: FC<ConnectorConfigProps> = ({ connector, onConfig
type="button" type="button"
variant="ghost" variant="ghost"
size="sm" size="sm"
onClick={() => setShowApiKey(prev => !prev)} onClick={() => setShowApiKey((prev) => !prev)}
className="absolute right-1 top-1/2 -translate-y-1/2 h-7 px-2 text-xs text-muted-foreground hover:text-foreground" className="absolute right-1 top-1/2 -translate-y-1/2 h-7 px-2 text-xs text-muted-foreground hover:text-foreground"
> >
{showApiKey ? "Hide" : "Show"} {showApiKey ? "Hide" : "Show"}

View file

@ -69,7 +69,7 @@ export const ThinkingStepsDisplay: FC<{ steps: ThinkingStep[]; isThreadRunning?:
<div className="rounded-lg"> <div className="rounded-lg">
<button <button
type="button" type="button"
onClick={() => setIsOpen(prev => !prev)} onClick={() => setIsOpen((prev) => !prev)}
className={cn( className={cn(
"flex w-full items-center gap-1.5 text-left text-sm transition-colors", "flex w-full items-center gap-1.5 text-left text-sm transition-colors",
"text-muted-foreground hover:text-foreground" "text-muted-foreground hover:text-foreground"

View file

@ -45,7 +45,7 @@ export const ToolFallback: ToolCallMessagePartComponent = ({
> >
<button <button
type="button" type="button"
onClick={() => setIsExpanded(prev => !prev)} onClick={() => setIsExpanded((prev) => !prev)}
className="flex w-full items-center gap-3 px-5 py-4 text-left transition-colors hover:bg-muted/50 focus:outline-none focus-visible:outline-none" className="flex w-full items-center gap-3 px-5 py-4 text-left transition-colors hover:bg-muted/50 focus:outline-none focus-visible:outline-none"
> >
<div <div

View file

@ -93,7 +93,7 @@ export function CommentThread({
variant="ghost" variant="ghost"
size="sm" size="sm"
className="h-6 px-2 text-xs text-muted-foreground hover:text-foreground" className="h-6 px-2 text-xs text-muted-foreground hover:text-foreground"
onClick={() => setIsRepliesExpanded(prev => !prev)} onClick={() => setIsRepliesExpanded((prev) => !prev)}
> >
{isRepliesExpanded ? ( {isRepliesExpanded ? (
<ChevronDown className="mr-1 size-3" /> <ChevronDown className="mr-1 size-3" />

View file

@ -1,8 +1,8 @@
"use client"; "use client";
import dynamic from "next/dynamic";
import { useAtomValue, useSetAtom } from "jotai"; import { useAtomValue, useSetAtom } from "jotai";
import { AlertCircle, XIcon } from "lucide-react"; import { AlertCircle, XIcon } from "lucide-react";
import dynamic from "next/dynamic";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { closeEditorPanelAtom, editorPanelAtom } from "@/atoms/editor/editor-panel.atom"; import { closeEditorPanelAtom, editorPanelAtom } from "@/atoms/editor/editor-panel.atom";

View file

@ -1,10 +1,10 @@
"use client"; "use client";
import dynamic from "next/dynamic";
import { format } from "date-fns"; import { format } from "date-fns";
import { TagInput, type Tag as TagType } from "emblor"; import { TagInput, type Tag as TagType } from "emblor";
import { useAtomValue, useSetAtom } from "jotai"; import { useAtomValue, useSetAtom } from "jotai";
import { CalendarIcon, XIcon } from "lucide-react"; import { CalendarIcon, XIcon } from "lucide-react";
import dynamic from "next/dynamic";
import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import type { ExtraField } from "@/atoms/chat/hitl-edit-panel.atom"; import type { ExtraField } from "@/atoms/chat/hitl-edit-panel.atom";
import { closeHitlEditPanelAtom, hitlEditPanelAtom } from "@/atoms/chat/hitl-edit-panel.atom"; import { closeHitlEditPanelAtom, hitlEditPanelAtom } from "@/atoms/chat/hitl-edit-panel.atom";

View file

@ -162,7 +162,7 @@ const MobileNav = ({ navItems, isScrolled, scrolledBgClassName }: any) => {
</Link> </Link>
<button <button
type="button" type="button"
onClick={() => setOpen(prev => !prev)} onClick={() => setOpen((prev) => !prev)}
className="relative z-50 flex items-center justify-center p-2 -mr-2 rounded-lg hover:bg-gray-100 dark:hover:bg-neutral-800 transition-colors touch-manipulation" className="relative z-50 flex items-center justify-center p-2 -mr-2 rounded-lg hover:bg-gray-100 dark:hover:bg-neutral-800 transition-colors touch-manipulation"
aria-label={open ? "Close menu" : "Open menu"} aria-label={open ? "Close menu" : "Open menu"}
> >

View file

@ -37,7 +37,7 @@ export function useSidebarState(defaultCollapsed = false): UseSidebarStateReturn
}, []); }, []);
const toggleCollapsed = useCallback(() => { const toggleCollapsed = useCallback(() => {
setIsCollapsedState(prev => { setIsCollapsedState((prev) => {
const next = !prev; const next = !prev;
try { try {
document.cookie = `${SIDEBAR_COOKIE_NAME}=${next}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`; document.cookie = `${SIDEBAR_COOKIE_NAME}=${next}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;

View file

@ -837,7 +837,9 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid
</Button> </Button>
<Button <Button
onClick={confirmRenameChat} onClick={confirmRenameChat}
disabled={isRenamingChat || !newChatTitle.trim() || newChatTitle.trim() === chatToRename?.name} disabled={
isRenamingChat || !newChatTitle.trim() || newChatTitle.trim() === chatToRename?.name
}
className="relative" className="relative"
> >
<span className={isRenamingChat ? "opacity-0" : ""}> <span className={isRenamingChat ? "opacity-0" : ""}>

View file

@ -1,8 +1,8 @@
"use client"; "use client";
import dynamic from "next/dynamic";
import { useAtom, useAtomValue, useSetAtom } from "jotai"; import { useAtom, useAtomValue, useSetAtom } from "jotai";
import { PanelRight, PanelRightClose } from "lucide-react"; import { PanelRight, PanelRightClose } from "lucide-react";
import dynamic from "next/dynamic";
import { startTransition, useEffect } from "react"; import { startTransition, useEffect } from "react";
import { closeHitlEditPanelAtom, hitlEditPanelAtom } from "@/atoms/chat/hitl-edit-panel.atom"; import { closeHitlEditPanelAtom, hitlEditPanelAtom } from "@/atoms/chat/hitl-edit-panel.atom";
import { closeReportPanelAtom, reportPanelAtom } from "@/atoms/chat/report-panel.atom"; import { closeReportPanelAtom, reportPanelAtom } from "@/atoms/chat/report-panel.atom";
@ -15,17 +15,26 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip
import { DocumentsSidebar } from "../sidebar"; import { DocumentsSidebar } from "../sidebar";
const EditorPanelContent = dynamic( const EditorPanelContent = dynamic(
() => import("@/components/editor-panel/editor-panel").then((m) => ({ default: m.EditorPanelContent })), () =>
import("@/components/editor-panel/editor-panel").then((m) => ({
default: m.EditorPanelContent,
})),
{ ssr: false, loading: () => <Skeleton className="h-96 w-full" /> } { ssr: false, loading: () => <Skeleton className="h-96 w-full" /> }
); );
const HitlEditPanelContent = dynamic( const HitlEditPanelContent = dynamic(
() => import("@/components/hitl-edit-panel/hitl-edit-panel").then((m) => ({ default: m.HitlEditPanelContent })), () =>
import("@/components/hitl-edit-panel/hitl-edit-panel").then((m) => ({
default: m.HitlEditPanelContent,
})),
{ ssr: false, loading: () => <Skeleton className="h-96 w-full" /> } { ssr: false, loading: () => <Skeleton className="h-96 w-full" /> }
); );
const ReportPanelContent = dynamic( const ReportPanelContent = dynamic(
() => import("@/components/report-panel/report-panel").then((m) => ({ default: m.ReportPanelContent })), () =>
import("@/components/report-panel/report-panel").then((m) => ({
default: m.ReportPanelContent,
})),
{ ssr: false, loading: () => <Skeleton className="h-96 w-full" /> } { ssr: false, loading: () => <Skeleton className="h-96 w-full" /> }
); );

View file

@ -72,12 +72,7 @@ export function TabBar({ onTabSwitch, onNewChat, rightActions, className }: TabB
if (tabs.length <= 1) return null; if (tabs.length <= 1) return null;
return ( return (
<div <div className={cn("mb-2 flex h-9 items-center shrink-0 px-1 gap-0.5", className)}>
className={cn(
"mb-2 flex h-9 items-center shrink-0 px-1 gap-0.5",
className
)}
>
<div <div
ref={scrollRef} ref={scrollRef}
className="flex h-full items-center flex-1 gap-0.5 overflow-x-auto overflow-y-hidden scrollbar-hide [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden py-1" className="flex h-full items-center flex-1 gap-0.5 overflow-x-auto overflow-y-hidden scrollbar-hide [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden py-1"

View file

@ -55,8 +55,8 @@ interface ChunkCardProps {
disableLayoutAnimation?: boolean; disableLayoutAnimation?: boolean;
} }
const ChunkCard = memo(forwardRef<HTMLDivElement, ChunkCardProps>( const ChunkCard = memo(
({ chunk, index, totalChunks, isCited }, ref) => { forwardRef<HTMLDivElement, ChunkCardProps>(({ chunk, index, totalChunks, isCited }, ref) => {
return ( return (
<div <div
ref={ref} ref={ref}
@ -100,8 +100,8 @@ const ChunkCard = memo(forwardRef<HTMLDivElement, ChunkCardProps>(
</div> </div>
</div> </div>
); );
} })
)); );
ChunkCard.displayName = "ChunkCard"; ChunkCard.displayName = "ChunkCard";
export function SourceDetailPanel({ export function SourceDetailPanel({

View file

@ -668,7 +668,7 @@ export function OnboardingTour() {
const handleNext = useCallback(() => { const handleNext = useCallback(() => {
retryCountRef.current = 0; retryCountRef.current = 0;
setShouldAnimate(true); setShouldAnimate(true);
setStepIndex(prev => { setStepIndex((prev) => {
if (prev < TOUR_STEPS.length - 1) { if (prev < TOUR_STEPS.length - 1) {
return prev + 1; return prev + 1;
} else { } else {
@ -686,7 +686,7 @@ export function OnboardingTour() {
const handlePrev = useCallback(() => { const handlePrev = useCallback(() => {
retryCountRef.current = 0; retryCountRef.current = 0;
setShouldAnimate(true); setShouldAnimate(true);
setStepIndex(prev => { setStepIndex((prev) => {
if (prev > 0) { if (prev > 0) {
return prev - 1; return prev - 1;
} }

View file

@ -1,8 +1,8 @@
"use client"; "use client";
import dynamic from "next/dynamic";
import { useAtomValue, useSetAtom } from "jotai"; import { useAtomValue, useSetAtom } from "jotai";
import { ChevronDownIcon, XIcon } from "lucide-react"; import { ChevronDownIcon, XIcon } from "lucide-react";
import dynamic from "next/dynamic";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
@ -12,13 +12,13 @@ import { MarkdownViewer } from "@/components/markdown-viewer";
import { EXPORT_FILE_EXTENSIONS, ExportDropdownItems } from "@/components/shared/ExportMenuItems"; import { EXPORT_FILE_EXTENSIONS, ExportDropdownItems } from "@/components/shared/ExportMenuItems";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Drawer, DrawerContent, DrawerHandle, DrawerTitle } from "@/components/ui/drawer"; import { Drawer, DrawerContent, DrawerHandle, DrawerTitle } from "@/components/ui/drawer";
import { Skeleton } from "@/components/ui/skeleton";
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
DropdownMenuItem, DropdownMenuItem,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import { Skeleton } from "@/components/ui/skeleton";
import { useMediaQuery } from "@/hooks/use-media-query"; import { useMediaQuery } from "@/hooks/use-media-query";
import { baseApiService } from "@/lib/apis/base-api.service"; import { baseApiService } from "@/lib/apis/base-api.service";
import { authenticatedFetch } from "@/lib/auth-utils"; import { authenticatedFetch } from "@/lib/auth-utils";

View file

@ -50,7 +50,9 @@ export function GeneralSettingsManager({ searchSpaceId }: GeneralSettingsManager
}, [searchSpace?.name, searchSpace?.description]); }, [searchSpace?.name, searchSpace?.description]);
// Derive hasChanges during render // Derive hasChanges during render
const hasChanges = !!searchSpace && ((searchSpace.name || "") !== name || (searchSpace.description || "") !== description); const hasChanges =
!!searchSpace &&
((searchSpace.name || "") !== name || (searchSpace.description || "") !== description);
const handleSave = async () => { const handleSave = async () => {
try { try {

View file

@ -129,7 +129,11 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
}; };
setAssignments(newAssignments); setAssignments(newAssignments);
setHasChanges(false); setHasChanges(false);
}, [preferences?.agent_llm_id, preferences?.document_summary_llm_id, preferences?.image_generation_config_id]); }, [
preferences?.agent_llm_id,
preferences?.document_summary_llm_id,
preferences?.image_generation_config_id,
]);
const handleRoleAssignment = (prefKey: string, configId: string) => { const handleRoleAssignment = (prefKey: string, configId: string) => {
const newAssignments = { const newAssignments = {

View file

@ -41,7 +41,8 @@ export function PromptConfigManager({ searchSpaceId }: PromptConfigManagerProps)
}, [searchSpace?.qna_custom_instructions]); }, [searchSpace?.qna_custom_instructions]);
// Derive hasChanges during render // Derive hasChanges during render
const hasChanges = !!searchSpace && (searchSpace.qna_custom_instructions || "") !== customInstructions; const hasChanges =
!!searchSpace && (searchSpace.qna_custom_instructions || "") !== customInstructions;
const handleSave = async () => { const handleSave = async () => {
try { try {

View file

@ -235,7 +235,13 @@ export function Audio({ id, src, title, durationMs, className }: AudioProps) {
</Button> </Button>
<div className="group/volume flex items-center gap-1 sm:gap-1.5"> <div className="group/volume flex items-center gap-1 sm:gap-1.5">
<Button variant="ghost" size="icon" onClick={toggleMute} className="size-7 sm:size-8" aria-label={isMuted ? "Unmute" : "Mute"}> <Button
variant="ghost"
size="icon"
onClick={toggleMute}
className="size-7 sm:size-8"
aria-label={isMuted ? "Unmute" : "Mute"}
>
{isMuted ? ( {isMuted ? (
<VolumeXIcon className="size-3.5 sm:size-4" /> <VolumeXIcon className="size-3.5 sm:size-4" />
) : ( ) : (

View file

@ -150,7 +150,8 @@ function ApprovalCard({
const allowedDecisions = reviewConfig?.allowed_decisions ?? ["approve", "reject"]; const allowedDecisions = reviewConfig?.allowed_decisions ?? ["approve", "reject"];
const canEdit = allowedDecisions.includes("edit"); const canEdit = allowedDecisions.includes("edit");
const fileTypeLabel = supportedTypes.find((t) => t.value === selectedFileType)?.label ?? selectedFileType; const fileTypeLabel =
supportedTypes.find((t) => t.value === selectedFileType)?.label ?? selectedFileType;
const handleApprove = useCallback(() => { const handleApprove = useCallback(() => {
if (phase !== "pending" || isPanelOpen || !canApprove) return; if (phase !== "pending" || isPanelOpen || !canApprove) return;
@ -450,7 +451,10 @@ function SuccessCard({ result }: { result: SuccessResult }) {
export const CreateDropboxFileToolUI = ({ export const CreateDropboxFileToolUI = ({
args, args,
result, result,
}: ToolCallMessagePartProps<{ name: string; file_type?: string; content?: string }, CreateDropboxFileResult>) => { }: ToolCallMessagePartProps<
{ name: string; file_type?: string; content?: string },
CreateDropboxFileResult
>) => {
if (!result) return null; if (!result) return null;
if (isInterruptResult(result)) { if (isInterruptResult(result)) {
return ( return (

View file

@ -116,7 +116,11 @@ function ApprovalCard({
type: "approve", type: "approve",
edited_action: { edited_action: {
name: interruptData.action_requests[0].name, name: interruptData.action_requests[0].name,
args: { file_path: file?.file_path, connector_id: account?.id, delete_from_kb: deleteFromKb }, args: {
file_path: file?.file_path,
connector_id: account?.id,
delete_from_kb: deleteFromKb,
},
}, },
}); });
}, [phase, setProcessing, onDecision, interruptData, file?.file_path, account?.id, deleteFromKb]); }, [phase, setProcessing, onDecision, interruptData, file?.file_path, account?.id, deleteFromKb]);

View file

@ -7,6 +7,7 @@
*/ */
export { Audio } from "./audio"; export { Audio } from "./audio";
export { CreateDropboxFileToolUI, DeleteDropboxFileToolUI } from "./dropbox";
export { export {
type GenerateImageArgs, type GenerateImageArgs,
GenerateImageArgsSchema, GenerateImageArgsSchema,
@ -32,7 +33,6 @@ export {
UpdateLinearIssueToolUI, UpdateLinearIssueToolUI,
} from "./linear"; } from "./linear";
export { CreateNotionPageToolUI, DeleteNotionPageToolUI, UpdateNotionPageToolUI } from "./notion"; export { CreateNotionPageToolUI, DeleteNotionPageToolUI, UpdateNotionPageToolUI } from "./notion";
export { CreateDropboxFileToolUI, DeleteDropboxFileToolUI } from "./dropbox";
export { CreateOneDriveFileToolUI, DeleteOneDriveFileToolUI } from "./onedrive"; export { CreateOneDriveFileToolUI, DeleteOneDriveFileToolUI } from "./onedrive";
export { export {
Plan, Plan,

View file

@ -185,7 +185,7 @@ export const useSearchSourceConnectors = (lazy: boolean = false, searchSpaceId?:
} }
const newConnector = await response.json(); const newConnector = await response.json();
setConnectors(prev => { setConnectors((prev) => {
const updated = [...prev, newConnector]; const updated = [...prev, newConnector];
updateConnectorSourceItems(updated); updateConnectorSourceItems(updated);
return updated; return updated;
@ -221,8 +221,8 @@ export const useSearchSourceConnectors = (lazy: boolean = false, searchSpaceId?:
} }
const updatedConnector = await response.json(); const updatedConnector = await response.json();
setConnectors(prev => { setConnectors((prev) => {
const updated = prev.map(c => c.id === connectorId ? updatedConnector : c); const updated = prev.map((c) => (c.id === connectorId ? updatedConnector : c));
updateConnectorSourceItems(updated); updateConnectorSourceItems(updated);
return updated; return updated;
}); });
@ -250,8 +250,8 @@ export const useSearchSourceConnectors = (lazy: boolean = false, searchSpaceId?:
throw new Error(`Failed to delete connector: ${response.statusText}`); throw new Error(`Failed to delete connector: ${response.statusText}`);
} }
setConnectors(prev => { setConnectors((prev) => {
const updated = prev.filter(c => c.id !== connectorId); const updated = prev.filter((c) => c.id !== connectorId);
updateConnectorSourceItems(updated); updateConnectorSourceItems(updated);
return updated; return updated;
}); });
@ -299,10 +299,9 @@ export const useSearchSourceConnectors = (lazy: boolean = false, searchSpaceId?:
const result = await response.json(); const result = await response.json();
// Update the connector's last_indexed_at timestamp // Update the connector's last_indexed_at timestamp
setConnectors(prev => setConnectors((prev) =>
prev.map(c => c.id === connectorId prev.map((c) =>
? { ...c, last_indexed_at: new Date().toISOString() } c.id === connectorId ? { ...c, last_indexed_at: new Date().toISOString() } : c
: c
) )
); );
@ -311,7 +310,7 @@ export const useSearchSourceConnectors = (lazy: boolean = false, searchSpaceId?:
console.error("Error indexing connector content:", err); console.error("Error indexing connector content:", err);
throw err; throw err;
} }
}; };
/** /**
* Get connector source items - memoized to prevent unnecessary re-renders * Get connector source items - memoized to prevent unnecessary re-renders