mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-04 13:22:41 +02:00
chore: linting
This commit is contained in:
parent
5ae5a671e7
commit
17642493eb
43 changed files with 224 additions and 196 deletions
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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}")
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
||||||
|
|
|
||||||
|
|
@ -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."
|
||||||
|
|
|
||||||
|
|
@ -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}")
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -163,20 +160,17 @@ export function LocalLoginForm() {
|
||||||
placeholder="you@example.com"
|
placeholder="you@example.com"
|
||||||
value={username}
|
value={username}
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
className={`mt-1 block w-full rounded-md border px-3 py-1.5 md:py-2 shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 bg-background text-foreground transition-all ${
|
className={`mt-1 block w-full rounded-md border px-3 py-1.5 md:py-2 shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 bg-background text-foreground transition-all ${
|
||||||
error.title
|
error.title
|
||||||
? "border-destructive focus:border-destructive focus:ring-destructive"
|
? "border-destructive focus:border-destructive focus:ring-destructive"
|
||||||
: "border-border focus:border-primary focus:ring-primary"
|
: "border-border focus:border-primary focus:ring-primary"
|
||||||
}`}
|
}`}
|
||||||
disabled={isLoggingIn}
|
disabled={isLoggingIn}
|
||||||
/>
|
/>
|
||||||
</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>
|
||||||
|
|
|
||||||
|
|
@ -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 })),
|
||||||
|
|
|
||||||
|
|
@ -105,20 +105,20 @@ export function CommunityPromptsContent() {
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="shrink-0 gap-1.5"
|
className="shrink-0 gap-1.5"
|
||||||
disabled={copyingIds.has(prompt.id)}
|
disabled={copyingIds.has(prompt.id)}
|
||||||
onClick={() => handleCopy(prompt.id)}
|
onClick={() => handleCopy(prompt.id)}
|
||||||
>
|
>
|
||||||
{copyingIds.has(prompt.id) ? (
|
{copyingIds.has(prompt.id) ? (
|
||||||
<Spinner className="size-3" />
|
<Spinner className="size-3" />
|
||||||
) : (
|
) : (
|
||||||
<Copy className="size-3" />
|
<Copy className="size-3" />
|
||||||
)}
|
)}
|
||||||
Add to mine
|
Add to mine
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -286,21 +288,21 @@ export function PromptsContent() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="hidden group-hover:flex items-center gap-1 shrink-0">
|
<div className="hidden group-hover:flex items-center gap-1 shrink-0">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
title={prompt.is_public ? "Make private" : "Share with community"}
|
title={prompt.is_public ? "Make private" : "Share with community"}
|
||||||
onClick={() => handleTogglePublic(prompt)}
|
onClick={() => handleTogglePublic(prompt)}
|
||||||
disabled={togglingPublicIds.has(prompt.id)}
|
disabled={togglingPublicIds.has(prompt.id)}
|
||||||
className="flex items-center justify-center size-7 rounded-md text-muted-foreground hover:text-foreground hover:bg-accent transition-colors disabled:opacity-50 disabled:pointer-events-none"
|
className="flex items-center justify-center size-7 rounded-md text-muted-foreground hover:text-foreground hover:bg-accent transition-colors disabled:opacity-50 disabled:pointer-events-none"
|
||||||
>
|
>
|
||||||
{togglingPublicIds.has(prompt.id) ? (
|
{togglingPublicIds.has(prompt.id) ? (
|
||||||
<Spinner className="size-3.5" />
|
<Spinner className="size-3.5" />
|
||||||
) : prompt.is_public ? (
|
) : prompt.is_public ? (
|
||||||
<Lock className="size-3.5" />
|
<Lock className="size-3.5" />
|
||||||
) : (
|
) : (
|
||||||
<Globe className="size-3.5" />
|
<Globe className="size-3.5" />
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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";
|
||||||
|
|
|
||||||
|
|
@ -298,11 +298,11 @@ export const ConnectorIndicator = forwardRef<ConnectorIndicatorHandle, Connector
|
||||||
onBack={handleBackFromEdit}
|
onBack={handleBackFromEdit}
|
||||||
onQuickIndex={(() => {
|
onQuickIndex={(() => {
|
||||||
const cfg = connectorConfig || editingConnector.config;
|
const cfg = connectorConfig || editingConnector.config;
|
||||||
const isDriveOrOneDrive =
|
const isDriveOrOneDrive =
|
||||||
editingConnector.connector_type === "GOOGLE_DRIVE_CONNECTOR" ||
|
editingConnector.connector_type === "GOOGLE_DRIVE_CONNECTOR" ||
|
||||||
editingConnector.connector_type === "COMPOSIO_GOOGLE_DRIVE_CONNECTOR" ||
|
editingConnector.connector_type === "COMPOSIO_GOOGLE_DRIVE_CONNECTOR" ||
|
||||||
editingConnector.connector_type === "ONEDRIVE_CONNECTOR" ||
|
editingConnector.connector_type === "ONEDRIVE_CONNECTOR" ||
|
||||||
editingConnector.connector_type === "DROPBOX_CONNECTOR";
|
editingConnector.connector_type === "DROPBOX_CONNECTOR";
|
||||||
const hasDriveItems = isDriveOrOneDrive
|
const hasDriveItems = isDriveOrOneDrive
|
||||||
? ((cfg?.selected_folders as unknown[]) ?? []).length > 0 ||
|
? ((cfg?.selected_folders as unknown[]) ?? []).length > 0 ||
|
||||||
((cfg?.selected_files as unknown[]) ?? []).length > 0
|
((cfg?.selected_files as unknown[]) ?? []).length > 0
|
||||||
|
|
|
||||||
|
|
@ -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 ? (
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -287,47 +287,57 @@ 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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center justify-between pt-2 border-t border-slate-400/20">
|
<div className="flex items-center justify-between pt-2 border-t border-slate-400/20">
|
||||||
<div className="space-y-0.5">
|
<div className="space-y-0.5">
|
||||||
<Label htmlFor="db-incremental-sync" className="text-sm font-medium">
|
<Label htmlFor="db-incremental-sync" className="text-sm font-medium">
|
||||||
Incremental sync
|
Incremental sync
|
||||||
</Label>
|
</Label>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
Only sync changes since last index (faster). Disable for a full re-index.
|
Only sync changes since last index (faster). Disable for a full re-index.
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
|
<Switch
|
||||||
|
id="db-incremental-sync"
|
||||||
|
checked={indexingOptions.incremental_sync}
|
||||||
|
onCheckedChange={(checked) => handleIndexingOptionChange("incremental_sync", checked)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Switch
|
|
||||||
id="db-incremental-sync"
|
|
||||||
checked={indexingOptions.incremental_sync}
|
|
||||||
onCheckedChange={(checked) => handleIndexingOptionChange("incremental_sync", checked)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center justify-between pt-2 border-t border-slate-400/20">
|
<div className="flex items-center justify-between pt-2 border-t border-slate-400/20">
|
||||||
<div className="space-y-0.5">
|
<div className="space-y-0.5">
|
||||||
<Label htmlFor="db-include-subfolders" className="text-sm font-medium">
|
<Label htmlFor="db-include-subfolders" className="text-sm font-medium">
|
||||||
Include subfolders
|
Include subfolders
|
||||||
</Label>
|
</Label>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
Recursively index files in subfolders of selected folders
|
Recursively index files in subfolders of selected folders
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
|
<Switch
|
||||||
|
id="db-include-subfolders"
|
||||||
|
checked={indexingOptions.include_subfolders}
|
||||||
|
onCheckedChange={(checked) => handleIndexingOptionChange("include_subfolders", checked)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Switch
|
|
||||||
id="db-include-subfolders"
|
|
||||||
checked={indexingOptions.include_subfolders}
|
|
||||||
onCheckedChange={(checked) => handleIndexingOptionChange("include_subfolders", checked)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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 ? (
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"}
|
||||||
|
|
|
||||||
|
|
@ -158,13 +158,13 @@ export const IndexingConfigurationView: FC<IndexingConfigurationViewProps> = ({
|
||||||
{/* AI Summary toggle */}
|
{/* AI Summary toggle */}
|
||||||
<SummaryConfig enabled={enableSummary} onEnabledChange={onEnableSummaryChange} />
|
<SummaryConfig enabled={enableSummary} onEnabledChange={onEnableSummaryChange} />
|
||||||
|
|
||||||
{/* Date range selector - not shown for file-based connectors (Drive, Dropbox, OneDrive), Webcrawler, or GitHub (indexes full repo snapshots) */}
|
{/* Date range selector - not shown for file-based connectors (Drive, Dropbox, OneDrive), Webcrawler, or GitHub (indexes full repo snapshots) */}
|
||||||
{config.connectorType !== "GOOGLE_DRIVE_CONNECTOR" &&
|
{config.connectorType !== "GOOGLE_DRIVE_CONNECTOR" &&
|
||||||
config.connectorType !== "COMPOSIO_GOOGLE_DRIVE_CONNECTOR" &&
|
config.connectorType !== "COMPOSIO_GOOGLE_DRIVE_CONNECTOR" &&
|
||||||
config.connectorType !== "DROPBOX_CONNECTOR" &&
|
config.connectorType !== "DROPBOX_CONNECTOR" &&
|
||||||
config.connectorType !== "ONEDRIVE_CONNECTOR" &&
|
config.connectorType !== "ONEDRIVE_CONNECTOR" &&
|
||||||
config.connectorType !== "WEBCRAWLER_CONNECTOR" &&
|
config.connectorType !== "WEBCRAWLER_CONNECTOR" &&
|
||||||
config.connectorType !== "GITHUB_CONNECTOR" && (
|
config.connectorType !== "GITHUB_CONNECTOR" && (
|
||||||
<DateRangeSelector
|
<DateRangeSelector
|
||||||
startDate={startDate}
|
startDate={startDate}
|
||||||
endDate={endDate}
|
endDate={endDate}
|
||||||
|
|
@ -221,14 +221,14 @@ export const IndexingConfigurationView: FC<IndexingConfigurationViewProps> = ({
|
||||||
|
|
||||||
{/* Fixed Footer - Action buttons */}
|
{/* Fixed Footer - Action buttons */}
|
||||||
<div className="flex-shrink-0 flex items-center justify-end px-6 sm:px-12 py-6 bg-muted">
|
<div className="flex-shrink-0 flex items-center justify-end px-6 sm:px-12 py-6 bg-muted">
|
||||||
<Button
|
<Button
|
||||||
onClick={onStartIndexing}
|
onClick={onStartIndexing}
|
||||||
disabled={isStartingIndexing}
|
disabled={isStartingIndexing}
|
||||||
className="text-xs sm:text-sm relative"
|
className="text-xs sm:text-sm relative"
|
||||||
>
|
>
|
||||||
<span className={isStartingIndexing ? "opacity-0" : ""}>Start Indexing</span>
|
<span className={isStartingIndexing ? "opacity-0" : ""}>Start Indexing</span>
|
||||||
{isStartingIndexing && <Spinner size="sm" className="absolute" />}
|
{isStartingIndexing && <Spinner size="sm" className="absolute" />}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -780,12 +780,12 @@ export const useConnectorDialog = () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Google Drive / OneDrive / Dropbox folder selection (regular and Composio)
|
// Handle Google Drive / OneDrive / Dropbox folder selection (regular and Composio)
|
||||||
if (
|
if (
|
||||||
(indexingConfig.connectorType === "GOOGLE_DRIVE_CONNECTOR" ||
|
(indexingConfig.connectorType === "GOOGLE_DRIVE_CONNECTOR" ||
|
||||||
indexingConfig.connectorType === "COMPOSIO_GOOGLE_DRIVE_CONNECTOR" ||
|
indexingConfig.connectorType === "COMPOSIO_GOOGLE_DRIVE_CONNECTOR" ||
|
||||||
indexingConfig.connectorType === "ONEDRIVE_CONNECTOR" ||
|
indexingConfig.connectorType === "ONEDRIVE_CONNECTOR" ||
|
||||||
indexingConfig.connectorType === "DROPBOX_CONNECTOR") &&
|
indexingConfig.connectorType === "DROPBOX_CONNECTOR") &&
|
||||||
indexingConnectorConfig
|
indexingConnectorConfig
|
||||||
) {
|
) {
|
||||||
const selectedFolders = indexingConnectorConfig.selected_folders as
|
const selectedFolders = indexingConnectorConfig.selected_folders as
|
||||||
|
|
@ -1049,13 +1049,13 @@ export const useConnectorDialog = () => {
|
||||||
if (!editingConnector.is_indexable) {
|
if (!editingConnector.is_indexable) {
|
||||||
// Non-indexable connectors (like Tavily API) don't need re-indexing
|
// Non-indexable connectors (like Tavily API) don't need re-indexing
|
||||||
indexingDescription = "Settings saved.";
|
indexingDescription = "Settings saved.";
|
||||||
} else if (
|
} else if (
|
||||||
editingConnector.connector_type === "GOOGLE_DRIVE_CONNECTOR" ||
|
editingConnector.connector_type === "GOOGLE_DRIVE_CONNECTOR" ||
|
||||||
editingConnector.connector_type === "COMPOSIO_GOOGLE_DRIVE_CONNECTOR" ||
|
editingConnector.connector_type === "COMPOSIO_GOOGLE_DRIVE_CONNECTOR" ||
|
||||||
editingConnector.connector_type === "ONEDRIVE_CONNECTOR" ||
|
editingConnector.connector_type === "ONEDRIVE_CONNECTOR" ||
|
||||||
editingConnector.connector_type === "DROPBOX_CONNECTOR"
|
editingConnector.connector_type === "DROPBOX_CONNECTOR"
|
||||||
) {
|
) {
|
||||||
// Google Drive (both regular and Composio) / OneDrive / Dropbox uses folder selection from config, not date ranges
|
// Google Drive (both regular and Composio) / OneDrive / Dropbox uses folder selection from config, not date ranges
|
||||||
const selectedFolders = (connectorConfig || editingConnector.config)?.selected_folders as
|
const selectedFolders = (connectorConfig || editingConnector.config)?.selected_folders as
|
||||||
| Array<{ id: string; name: string }>
|
| Array<{ id: string; name: string }>
|
||||||
| undefined;
|
| undefined;
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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" />
|
||||||
|
|
|
||||||
|
|
@ -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";
|
||||||
|
|
|
||||||
|
|
@ -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";
|
||||||
|
|
|
||||||
|
|
@ -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"}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -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}`;
|
||||||
|
|
|
||||||
|
|
@ -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" : ""}>
|
||||||
|
|
|
||||||
|
|
@ -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" /> }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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({
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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";
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 = {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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" />
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
||||||
|
|
|
||||||
|
|
@ -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]);
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,19 +299,18 @@ 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
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue