chore: ran linting

This commit is contained in:
Anish Sarkar 2026-02-10 19:06:21 +05:30
parent b44b4497a6
commit f1ce17bde4
15 changed files with 285 additions and 338 deletions

View file

@ -141,4 +141,3 @@ def downgrade() -> None:
ALTER TABLE image_generation_configs DROP COLUMN IF EXISTS user_id; ALTER TABLE image_generation_configs DROP COLUMN IF EXISTS user_id;
""" """
) )

View file

@ -439,7 +439,9 @@ async def list_snapshots_for_search_space(
"message_count": len(s.message_ids) if s.message_ids else 0, "message_count": len(s.message_ids) if s.message_ids else 0,
"thread_id": s.thread_id, "thread_id": s.thread_id,
"thread_title": thread_titles.get(s.thread_id, "Untitled"), "thread_title": thread_titles.get(s.thread_id, "Untitled"),
"created_by_user_id": str(s.created_by_user_id) if s.created_by_user_id else None, "created_by_user_id": str(s.created_by_user_id)
if s.created_by_user_id
else None,
} }
for s in snapshots for s in snapshots
] ]

View file

@ -651,9 +651,7 @@ async def index_discord_messages(
# PHASE 2: Process each batch document one by one # PHASE 2: Process each batch document one by one
# Each document transitions: pending → processing → ready/failed # Each document transitions: pending → processing → ready/failed
# ======================================================================= # =======================================================================
logger.info( logger.info(f"Phase 2: Processing {len(batches_to_process)} batch documents")
f"Phase 2: Processing {len(batches_to_process)} batch documents"
)
for item in batches_to_process: for item in batches_to_process:
# Send heartbeat periodically # Send heartbeat periodically

View file

@ -357,9 +357,7 @@ async def index_slack_messages(
# Group messages into batches of SLACK_BATCH_SIZE # Group messages into batches of SLACK_BATCH_SIZE
# Each batch becomes a single document with conversation context # Each batch becomes a single document with conversation context
# ======================================================= # =======================================================
for batch_start in range( for batch_start in range(0, len(formatted_messages), SLACK_BATCH_SIZE):
0, len(formatted_messages), SLACK_BATCH_SIZE
):
batch = formatted_messages[ batch = formatted_messages[
batch_start : batch_start + SLACK_BATCH_SIZE batch_start : batch_start + SLACK_BATCH_SIZE
] ]
@ -377,9 +375,7 @@ async def index_slack_messages(
# channel_id + first message ts + last message ts # channel_id + first message ts + last message ts
first_msg_ts = batch[0].get("timestamp", "") first_msg_ts = batch[0].get("timestamp", "")
last_msg_ts = batch[-1].get("timestamp", "") last_msg_ts = batch[-1].get("timestamp", "")
unique_identifier = ( unique_identifier = f"{channel_id}_{first_msg_ts}_{last_msg_ts}"
f"{channel_id}_{first_msg_ts}_{last_msg_ts}"
)
unique_identifier_hash = generate_unique_identifier_hash( unique_identifier_hash = generate_unique_identifier_hash(
DocumentType.SLACK_CONNECTOR, DocumentType.SLACK_CONNECTOR,
unique_identifier, unique_identifier,
@ -392,11 +388,9 @@ async def index_slack_messages(
) )
# Check if document with this unique identifier already exists # Check if document with this unique identifier already exists
existing_document = ( existing_document = await check_document_by_unique_identifier(
await check_document_by_unique_identifier(
session, unique_identifier_hash session, unique_identifier_hash
) )
)
if existing_document: if existing_document:
# Document exists - check if content has changed # Document exists - check if content has changed
@ -405,9 +399,7 @@ async def index_slack_messages(
if not DocumentStatus.is_state( if not DocumentStatus.is_state(
existing_document.status, DocumentStatus.READY existing_document.status, DocumentStatus.READY
): ):
existing_document.status = ( existing_document.status = DocumentStatus.ready()
DocumentStatus.ready()
)
documents_skipped += 1 documents_skipped += 1
continue continue
@ -440,11 +432,9 @@ async def index_slack_messages(
# Document doesn't exist by unique_identifier_hash # Document doesn't exist by unique_identifier_hash
# Check if a document with the same content_hash exists (from another connector) # Check if a document with the same content_hash exists (from another connector)
with session.no_autoflush: with session.no_autoflush:
duplicate_by_content = ( duplicate_by_content = await check_duplicate_document_by_hash(
await check_duplicate_document_by_hash(
session, content_hash session, content_hash
) )
)
if duplicate_by_content: if duplicate_by_content:
logger.info( logger.info(
@ -496,12 +486,8 @@ async def index_slack_messages(
"channel_id": channel_id, "channel_id": channel_id,
"first_message_ts": first_msg_ts, "first_message_ts": first_msg_ts,
"last_message_ts": last_msg_ts, "last_message_ts": last_msg_ts,
"first_message_time": batch[0].get( "first_message_time": batch[0].get("datetime", "Unknown"),
"datetime", "Unknown" "last_message_time": batch[-1].get("datetime", "Unknown"),
),
"last_message_time": batch[-1].get(
"datetime", "Unknown"
),
"message_count": len(batch), "message_count": len(batch),
"start_date": start_date_str, "start_date": start_date_str,
"end_date": end_date_str, "end_date": end_date_str,
@ -538,9 +524,7 @@ async def index_slack_messages(
# PHASE 2: Process each batch document one by one # PHASE 2: Process each batch document one by one
# Each document transitions: pending → processing → ready/failed # Each document transitions: pending → processing → ready/failed
# ======================================================================= # =======================================================================
logger.info( logger.info(f"Phase 2: Processing {len(batches_to_process)} batch documents")
f"Phase 2: Processing {len(batches_to_process)} batch documents"
)
for item in batches_to_process: for item in batches_to_process:
# Send heartbeat periodically # Send heartbeat periodically
@ -621,9 +605,7 @@ async def index_slack_messages(
) )
try: try:
await session.commit() await session.commit()
logger.info( logger.info("Successfully committed all Slack document changes to database")
"Successfully committed all Slack document changes to database"
)
except Exception as e: except Exception as e:
# Handle any remaining integrity errors gracefully (race conditions, etc.) # Handle any remaining integrity errors gracefully (race conditions, etc.)
if ( if (

View file

@ -51,8 +51,7 @@ export function RowActions({
document.status?.state === "pending" || document.status?.state === "processing"; document.status?.state === "pending" || document.status?.state === "processing";
// FILE documents that failed processing cannot be edited // FILE documents that failed processing cannot be edited
const isFileFailed = const isFileFailed = document.document_type === "FILE" && document.status?.state === "failed";
document.document_type === "FILE" && document.status?.state === "failed";
// SURFSENSE_DOCS are system-managed and should not show delete at all // SURFSENSE_DOCS are system-managed and should not show delete at all
const shouldShowDelete = !NON_DELETABLE_DOCUMENT_TYPES.includes( const shouldShowDelete = !NON_DELETABLE_DOCUMENT_TYPES.includes(
@ -212,7 +211,8 @@ export function RowActions({
<AlertDialogHeader> <AlertDialogHeader>
<AlertDialogTitle>Delete document?</AlertDialogTitle> <AlertDialogTitle>Delete document?</AlertDialogTitle>
<AlertDialogDescription> <AlertDialogDescription>
This action cannot be undone. This will permanently delete this document from your search space. This action cannot be undone. This will permanently delete this document from your
search space.
</AlertDialogDescription> </AlertDialogDescription>
</AlertDialogHeader> </AlertDialogHeader>
<AlertDialogFooter> <AlertDialogFooter>

View file

@ -1,15 +1,7 @@
"use client"; "use client";
import { useAtomValue } from "jotai"; import { useAtomValue } from "jotai";
import { import { Bot, Check, ChevronDown, Edit3, ImageIcon, Plus, Zap } from "lucide-react";
Bot,
Check,
ChevronDown,
Edit3,
ImageIcon,
Plus,
Zap,
} from "lucide-react";
import { useCallback, useMemo, useState } from "react"; import { useCallback, useMemo, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { import {
@ -77,10 +69,10 @@ export function ModelSelector({
// Image data // Image data
const { data: imageGlobalConfigs, isLoading: imageGlobalLoading } = const { data: imageGlobalConfigs, isLoading: imageGlobalLoading } =
useAtomValue(globalImageGenConfigsAtom); useAtomValue(globalImageGenConfigsAtom);
const { data: imageUserConfigs, isLoading: imageUserLoading } = const { data: imageUserConfigs, isLoading: imageUserLoading } = useAtomValue(imageGenConfigsAtom);
useAtomValue(imageGenConfigsAtom);
const isLoading = llmUserLoading || llmGlobalLoading || prefsLoading || imageGlobalLoading || imageUserLoading; const isLoading =
llmUserLoading || llmGlobalLoading || prefsLoading || imageGlobalLoading || imageUserLoading;
// ─── LLM current config ─── // ─── LLM current config ───
const currentLLMConfig = useMemo(() => { const currentLLMConfig = useMemo(() => {
@ -108,7 +100,9 @@ export function ModelSelector({
}, [preferences, imageGlobalConfigs, imageUserConfigs]); }, [preferences, imageGlobalConfigs, imageUserConfigs]);
const isImageAutoMode = useMemo(() => { const isImageAutoMode = useMemo(() => {
return currentImageConfig && "is_auto_mode" in currentImageConfig && currentImageConfig.is_auto_mode; return (
currentImageConfig && "is_auto_mode" in currentImageConfig && currentImageConfig.is_auto_mode
);
}, [currentImageConfig]); }, [currentImageConfig]);
// ─── LLM filtering ─── // ─── LLM filtering ───
@ -244,7 +238,9 @@ export function ModelSelector({
{/* LLM section */} {/* LLM section */}
{currentLLMConfig ? ( {currentLLMConfig ? (
<> <>
{getProviderIcon(currentLLMConfig.provider, { isAutoMode: isLLMAutoMode ?? false })} {getProviderIcon(currentLLMConfig.provider, {
isAutoMode: isLLMAutoMode ?? false,
})}
<span className="max-w-[100px] md:max-w-[120px] truncate hidden md:inline"> <span className="max-w-[100px] md:max-w-[120px] truncate hidden md:inline">
{currentLLMConfig.name} {currentLLMConfig.name}
</span> </span>
@ -262,7 +258,9 @@ export function ModelSelector({
{/* Image section */} {/* Image section */}
{currentImageConfig ? ( {currentImageConfig ? (
<> <>
{getProviderIcon(currentImageConfig.provider, { isAutoMode: isImageAutoMode ?? false })} {getProviderIcon(currentImageConfig.provider, {
isAutoMode: isImageAutoMode ?? false,
})}
<span className="max-w-[80px] md:max-w-[100px] truncate hidden md:inline"> <span className="max-w-[80px] md:max-w-[100px] truncate hidden md:inline">
{currentImageConfig.name} {currentImageConfig.name}
</span> </span>
@ -373,7 +371,9 @@ export function ModelSelector({
Recommended Recommended
</Badge> </Badge>
)} )}
{isSelected && <Check className="size-3.5 text-primary shrink-0" />} {isSelected && (
<Check className="size-3.5 text-primary shrink-0" />
)}
</div> </div>
<div className="flex items-center gap-1.5 mt-0.5"> <div className="flex items-center gap-1.5 mt-0.5">
<span className="text-xs text-muted-foreground truncate"> <span className="text-xs text-muted-foreground truncate">
@ -436,7 +436,9 @@ export function ModelSelector({
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span className="font-medium truncate">{config.name}</span> <span className="font-medium truncate">{config.name}</span>
{isSelected && <Check className="size-3.5 text-primary shrink-0" />} {isSelected && (
<Check className="size-3.5 text-primary shrink-0" />
)}
</div> </div>
<div className="flex items-center gap-1.5 mt-0.5"> <div className="flex items-center gap-1.5 mt-0.5">
<span className="text-xs text-muted-foreground truncate"> <span className="text-xs text-muted-foreground truncate">
@ -489,7 +491,10 @@ export function ModelSelector({
{/* ─── Image Tab ─── */} {/* ─── Image Tab ─── */}
<TabsContent value="image" className="mt-0"> <TabsContent value="image" className="mt-0">
<Command shouldFilter={false} className="rounded-none rounded-b-lg [&_[data-slot=command-input-wrapper]]:border-0 [&_[data-slot=command-input-wrapper]]:px-0 [&_[data-slot=command-input-wrapper]]:gap-2"> <Command
shouldFilter={false}
className="rounded-none rounded-b-lg [&_[data-slot=command-input-wrapper]]:border-0 [&_[data-slot=command-input-wrapper]]:px-0 [&_[data-slot=command-input-wrapper]]:gap-2"
>
{totalImageModels > 3 && ( {totalImageModels > 3 && (
<div className="px-2 md:px-3 py-1.5 md:py-2"> <div className="px-2 md:px-3 py-1.5 md:py-2">
<CommandInput <CommandInput
@ -573,7 +578,9 @@ export function ModelSelector({
{/* User Image Configs */} {/* User Image Configs */}
{filteredImageUser.length > 0 && ( {filteredImageUser.length > 0 && (
<> <>
{filteredImageGlobal.length > 0 && <CommandSeparator className="my-1 mx-4 bg-border/60" />} {filteredImageGlobal.length > 0 && (
<CommandSeparator className="my-1 mx-4 bg-border/60" />
)}
<CommandGroup> <CommandGroup>
<div className="flex items-center gap-2 px-3 py-2 text-xs font-semibold text-muted-foreground tracking-wider"> <div className="flex items-center gap-2 px-3 py-2 text-xs font-semibold text-muted-foreground tracking-wider">
Your Image Models Your Image Models
@ -591,13 +598,13 @@ export function ModelSelector({
)} )}
> >
<div className="flex items-center gap-3 min-w-0 flex-1"> <div className="flex items-center gap-3 min-w-0 flex-1">
<div className="shrink-0"> <div className="shrink-0">{getProviderIcon(config.provider)}</div>
{getProviderIcon(config.provider)}
</div>
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span className="font-medium truncate">{config.name}</span> <span className="font-medium truncate">{config.name}</span>
{isSelected && <Check className="size-3.5 text-primary shrink-0" />} {isSelected && (
<Check className="size-3.5 text-primary shrink-0" />
)}
</div> </div>
<span className="text-xs text-muted-foreground truncate block"> <span className="text-xs text-muted-foreground truncate block">
{config.model_name} {config.model_name}

View file

@ -50,9 +50,7 @@ export function PublicChatSnapshotRow({
day: "numeric", day: "numeric",
}); });
const member = snapshot.created_by_user_id const member = snapshot.created_by_user_id ? memberMap.get(snapshot.created_by_user_id) : null;
? memberMap.get(snapshot.created_by_user_id)
: null;
return ( return (
<Card className="group relative overflow-hidden transition-all duration-200 border-border/60 hover:shadow-md h-full"> <Card className="group relative overflow-hidden transition-all duration-200 border-border/60 hover:shadow-md h-full">
@ -77,11 +75,7 @@ export function PublicChatSnapshotRow({
asChild asChild
className="h-7 w-7 text-muted-foreground hover:text-foreground" className="h-7 w-7 text-muted-foreground hover:text-foreground"
> >
<a <a href={snapshot.public_url} target="_blank" rel="noopener noreferrer">
href={snapshot.public_url}
target="_blank"
rel="noopener noreferrer"
>
<ExternalLink className="h-3 w-3" /> <ExternalLink className="h-3 w-3" />
</a> </a>
</Button> </Button>
@ -152,9 +146,7 @@ export function PublicChatSnapshotRow({
{/* Footer: Date + Creator */} {/* Footer: Date + Creator */}
<div className="flex items-center gap-2 pt-2 border-t border-border/40 mt-auto"> <div className="flex items-center gap-2 pt-2 border-t border-border/40 mt-auto">
<span className="text-[11px] text-muted-foreground/60"> <span className="text-[11px] text-muted-foreground/60">{formattedDate}</span>
{formattedDate}
</span>
{member && ( {member && (
<> <>
<span className="text-muted-foreground/30">·</span> <span className="text-muted-foreground/30">·</span>
@ -182,9 +174,7 @@ export function PublicChatSnapshotRow({
</span> </span>
</div> </div>
</TooltipTrigger> </TooltipTrigger>
<TooltipContent side="bottom"> <TooltipContent side="bottom">{member.email || member.name}</TooltipContent>
{member.email || member.name}
</TooltipContent>
</Tooltip> </Tooltip>
</TooltipProvider> </TooltipProvider>
</> </>

View file

@ -417,7 +417,11 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) {
: "No image models have been added to this space yet. Contact a space owner to add one."} : "No image models have been added to this space yet. Contact a space owner to add one."}
</p> </p>
{canCreate && ( {canCreate && (
<Button onClick={openNewDialog} size="lg" className="gap-2 text-xs md:text-sm h-9 md:h-10"> <Button
onClick={openNewDialog}
size="lg"
className="gap-2 text-xs md:text-sm h-9 md:h-10"
>
<Plus className="h-3 w-3 md:h-4 md:w-4" /> <Plus className="h-3 w-3 md:h-4 md:w-4" />
Add First Image Model Add First Image Model
</Button> </Button>
@ -507,14 +511,11 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) {
{/* Footer: Date + Creator */} {/* Footer: Date + Creator */}
<div className="flex items-center gap-2 pt-2 border-t border-border/40 mt-auto"> <div className="flex items-center gap-2 pt-2 border-t border-border/40 mt-auto">
<span className="text-[11px] text-muted-foreground/60"> <span className="text-[11px] text-muted-foreground/60">
{new Date(config.created_at).toLocaleDateString( {new Date(config.created_at).toLocaleDateString(undefined, {
undefined,
{
year: "numeric", year: "numeric",
month: "short", month: "short",
day: "numeric", day: "numeric",
} })}
)}
</span> </span>
{member && ( {member && (
<> <>
@ -578,9 +579,7 @@ export function ImageModelManager({ searchSpaceId }: ImageModelManagerProps) {
onOpenAutoFocus={(e) => e.preventDefault()} onOpenAutoFocus={(e) => e.preventDefault()}
> >
<DialogHeader> <DialogHeader>
<DialogTitle> <DialogTitle>{editingConfig ? "Edit Image Model" : "Add Image Model"}</DialogTitle>
{editingConfig ? "Edit Image Model" : "Add Image Model"}
</DialogTitle>
<DialogDescription> <DialogDescription>
{editingConfig {editingConfig
? "Update your image generation model" ? "Update your image generation model"

View file

@ -210,8 +210,18 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
...(userImageConfigs ?? []).filter((config) => config.id && config.id.toString().trim() !== ""), ...(userImageConfigs ?? []).filter((config) => config.id && config.id.toString().trim() !== ""),
]; ];
const isLoading = configsLoading || preferencesLoading || globalConfigsLoading || imageConfigsLoading || globalImageConfigsLoading; const isLoading =
const hasError = configsError || preferencesError || globalConfigsError || imageConfigsError || globalImageConfigsError; configsLoading ||
preferencesLoading ||
globalConfigsLoading ||
imageConfigsLoading ||
globalImageConfigsLoading;
const hasError =
configsError ||
preferencesError ||
globalConfigsError ||
imageConfigsError ||
globalImageConfigsError;
const hasAnyConfigs = allLLMConfigs.length > 0 || allImageConfigs.length > 0; const hasAnyConfigs = allLLMConfigs.length > 0 || allImageConfigs.length > 0;
return ( return (
@ -253,8 +263,7 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
<AlertDescription className="text-xs md:text-sm"> <AlertDescription className="text-xs md:text-sm">
{(configsError?.message ?? "Failed to load LLM configurations") || {(configsError?.message ?? "Failed to load LLM configurations") ||
(preferencesError?.message ?? "Failed to load preferences") || (preferencesError?.message ?? "Failed to load preferences") ||
(globalConfigsError?.message ?? (globalConfigsError?.message ?? "Failed to load global configurations")}
"Failed to load global configurations")}
</AlertDescription> </AlertDescription>
</Alert> </Alert>
</motion.div> </motion.div>
@ -305,8 +314,8 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
<Alert variant="destructive" className="py-3 md:py-4"> <Alert variant="destructive" className="py-3 md:py-4">
<AlertCircle className="h-3 w-3 md:h-4 md:w-4 shrink-0" /> <AlertCircle className="h-3 w-3 md:h-4 md:w-4 shrink-0" />
<AlertDescription className="text-xs md:text-sm"> <AlertDescription className="text-xs md:text-sm">
No configurations found. Please add at least one LLM provider or image model No configurations found. Please add at least one LLM provider or image model in the
in the respective settings tabs before assigning roles. respective settings tabs before assigning roles.
</AlertDescription> </AlertDescription>
</Alert> </Alert>
)} )}
@ -322,8 +331,7 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
{Object.entries(ROLE_DESCRIPTIONS).map(([key, role], index) => { {Object.entries(ROLE_DESCRIPTIONS).map(([key, role], index) => {
const IconComponent = role.icon; const IconComponent = role.icon;
const isImageRole = role.configType === "image"; const isImageRole = role.configType === "image";
const currentAssignment = const currentAssignment = assignments[role.prefKey as keyof typeof assignments];
assignments[role.prefKey as keyof typeof assignments];
// Pick the right config lists based on role type // Pick the right config lists based on role type
const roleGlobalConfigs = isImageRole ? globalImageConfigs : globalConfigs; const roleGlobalConfigs = isImageRole ? globalImageConfigs : globalConfigs;
@ -332,17 +340,13 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
: newLLMConfigs.filter((c) => c.id && c.id.toString().trim() !== ""); : newLLMConfigs.filter((c) => c.id && c.id.toString().trim() !== "");
const roleAllConfigs = isImageRole ? allImageConfigs : allLLMConfigs; const roleAllConfigs = isImageRole ? allImageConfigs : allLLMConfigs;
const assignedConfig = roleAllConfigs.find( const assignedConfig = roleAllConfigs.find((config) => config.id === currentAssignment);
(config) => config.id === currentAssignment
);
const isAssigned = const isAssigned =
currentAssignment !== "" && currentAssignment !== "" &&
currentAssignment !== null && currentAssignment !== null &&
currentAssignment !== undefined; currentAssignment !== undefined;
const isAutoMode = const isAutoMode =
assignedConfig && assignedConfig && "is_auto_mode" in assignedConfig && assignedConfig.is_auto_mode;
"is_auto_mode" in assignedConfig &&
assignedConfig.is_auto_mode;
return ( return (
<motion.div <motion.div
@ -362,14 +366,10 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
role.bgColor role.bgColor
)} )}
> >
<IconComponent <IconComponent className={cn("w-4 h-4", role.color)} />
className={cn("w-4 h-4", role.color)}
/>
</div> </div>
<div className="min-w-0"> <div className="min-w-0">
<h4 className="text-sm font-semibold tracking-tight"> <h4 className="text-sm font-semibold tracking-tight">{role.title}</h4>
{role.title}
</h4>
<p className="text-[11px] text-muted-foreground/70 mt-0.5"> <p className="text-[11px] text-muted-foreground/70 mt-0.5">
{role.description} {role.description}
</p> </p>
@ -389,9 +389,7 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
</Label> </Label>
<Select <Select
value={currentAssignment?.toString() || "unassigned"} value={currentAssignment?.toString() || "unassigned"}
onValueChange={(value) => onValueChange={(value) => handleRoleAssignment(role.prefKey, value)}
handleRoleAssignment(role.prefKey, value)
}
> >
<SelectTrigger className="w-full h-9 md:h-10 text-xs md:text-sm"> <SelectTrigger className="w-full h-9 md:h-10 text-xs md:text-sm">
<SelectValue placeholder="Select a configuration" /> <SelectValue placeholder="Select a configuration" />
@ -401,9 +399,7 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
value="unassigned" value="unassigned"
className="text-xs md:text-sm py-1.5 md:py-2" className="text-xs md:text-sm py-1.5 md:py-2"
> >
<span className="text-muted-foreground"> <span className="text-muted-foreground">Unassigned</span>
Unassigned
</span>
</SelectItem> </SelectItem>
{/* Global Configurations */} {/* Global Configurations */}
@ -413,9 +409,7 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
Global Configurations Global Configurations
</SelectLabel> </SelectLabel>
{roleGlobalConfigs.map((config) => { {roleGlobalConfigs.map((config) => {
const isAuto = const isAuto = "is_auto_mode" in config && config.is_auto_mode;
"is_auto_mode" in config &&
config.is_auto_mode;
return ( return (
<SelectItem <SelectItem
key={config.id} key={config.id}
@ -432,18 +426,16 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
AUTO AUTO
</Badge> </Badge>
) : ( ) : (
getProviderIcon(config.provider, { className: "size-3 md:size-3.5 shrink-0" }) getProviderIcon(config.provider, {
className: "size-3 md:size-3.5 shrink-0",
})
)} )}
<span className="truncate text-xs md:text-sm"> <span className="truncate text-xs md:text-sm">
{config.name} {config.name}
</span> </span>
{!isAuto && ( {!isAuto && (
<span className="text-muted-foreground text-[10px] md:text-[11px] truncate"> <span className="text-muted-foreground text-[10px] md:text-[11px] truncate">
( ({config.model_name})
{
config.model_name
}
)
</span> </span>
)} )}
{isAuto && ( {isAuto && (
@ -474,16 +466,14 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
className="text-xs md:text-sm py-1.5 md:py-2" className="text-xs md:text-sm py-1.5 md:py-2"
> >
<div className="flex items-center gap-1 md:gap-1.5 flex-wrap min-w-0"> <div className="flex items-center gap-1 md:gap-1.5 flex-wrap min-w-0">
{getProviderIcon(config.provider, { className: "size-3 md:size-3.5 shrink-0" })} {getProviderIcon(config.provider, {
className: "size-3 md:size-3.5 shrink-0",
})}
<span className="truncate text-xs md:text-sm"> <span className="truncate text-xs md:text-sm">
{config.name} {config.name}
</span> </span>
<span className="text-muted-foreground text-[10px] md:text-[11px] truncate"> <span className="text-muted-foreground text-[10px] md:text-[11px] truncate">
( ({config.model_name})
{
config.model_name
}
)
</span> </span>
</div> </div>
</SelectItem> </SelectItem>
@ -525,21 +515,17 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
<IconComponent className="w-3.5 h-3.5 shrink-0 mt-0.5 text-muted-foreground" /> <IconComponent className="w-3.5 h-3.5 shrink-0 mt-0.5 text-muted-foreground" />
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<div className="flex items-center gap-1.5 flex-wrap"> <div className="flex items-center gap-1.5 flex-wrap">
<span className="text-xs font-medium"> <span className="text-xs font-medium">{assignedConfig.name}</span>
{assignedConfig.name} {"is_global" in assignedConfig && assignedConfig.is_global && (
</span> <Badge variant="secondary" className="text-[9px] px-1.5 py-0">
{"is_global" in assignedConfig &&
assignedConfig.is_global && (
<Badge
variant="secondary"
className="text-[9px] px-1.5 py-0"
>
🌐 Global 🌐 Global
</Badge> </Badge>
)} )}
</div> </div>
<div className="flex items-center gap-1.5 mt-1"> <div className="flex items-center gap-1.5 mt-1">
{getProviderIcon(assignedConfig.provider, { className: "size-3 shrink-0" })} {getProviderIcon(assignedConfig.provider, {
className: "size-3 shrink-0",
})}
<code className="text-[10px] text-muted-foreground font-mono truncate"> <code className="text-[10px] text-muted-foreground font-mono truncate">
{assignedConfig.model_name} {assignedConfig.model_name}
</code> </code>
@ -572,9 +558,7 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
transition={{ duration: 0.2 }} transition={{ duration: 0.2 }}
className="flex items-center justify-between gap-3 rounded-lg border border-border bg-muted/50 p-3 md:p-4" className="flex items-center justify-between gap-3 rounded-lg border border-border bg-muted/50 p-3 md:p-4"
> >
<p className="text-xs md:text-sm text-muted-foreground"> <p className="text-xs md:text-sm text-muted-foreground">You have unsaved changes</p>
You have unsaved changes
</p>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Button <Button
variant="outline" variant="outline"

View file

@ -83,18 +83,15 @@ function getInitials(name: string): string {
export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) { export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) {
// Mutations // Mutations
const { const { mutateAsync: createConfig, isPending: isCreating } = useAtomValue(
mutateAsync: createConfig, createNewLLMConfigMutationAtom
isPending: isCreating, );
} = useAtomValue(createNewLLMConfigMutationAtom); const { mutateAsync: updateConfig, isPending: isUpdating } = useAtomValue(
const { updateNewLLMConfigMutationAtom
mutateAsync: updateConfig, );
isPending: isUpdating, const { mutateAsync: deleteConfig, isPending: isDeleting } = useAtomValue(
} = useAtomValue(updateNewLLMConfigMutationAtom); deleteNewLLMConfigMutationAtom
const { );
mutateAsync: deleteConfig,
isPending: isDeleting,
} = useAtomValue(deleteNewLLMConfigMutationAtom);
// Queries // Queries
const { const {
@ -453,14 +450,11 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) {
{/* Footer: Date + Creator */} {/* Footer: Date + Creator */}
<div className="flex items-center gap-2 pt-2 border-t border-border/40 mt-auto"> <div className="flex items-center gap-2 pt-2 border-t border-border/40 mt-auto">
<span className="text-[11px] text-muted-foreground/60"> <span className="text-[11px] text-muted-foreground/60">
{new Date(config.created_at).toLocaleDateString( {new Date(config.created_at).toLocaleDateString(undefined, {
undefined,
{
year: "numeric", year: "numeric",
month: "short", month: "short",
day: "numeric", day: "numeric",
} })}
)}
</span> </span>
{member && ( {member && (
<> <>

View file

@ -218,7 +218,9 @@ export const getImageGenConfigsResponse = z.array(imageGenerationConfig);
export const updateImageGenConfigRequest = z.object({ export const updateImageGenConfigRequest = z.object({
id: z.number(), id: z.number(),
data: imageGenerationConfig.omit({ id: true, created_at: true, search_space_id: true, user_id: true }).partial(), data: imageGenerationConfig
.omit({ id: true, created_at: true, search_space_id: true, user_id: true })
.partial(),
}); });
export const updateImageGenConfigResponse = imageGenerationConfig; export const updateImageGenConfigResponse = imageGenerationConfig;

View file

@ -1,7 +1,4 @@
import { import { Bot, Shuffle } from "lucide-react";
Bot,
Shuffle,
} from "lucide-react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Ai21Icon } from "@/components/icons/providers"; import { Ai21Icon } from "@/components/icons/providers";
import { AnthropicIcon } from "@/components/icons/providers"; import { AnthropicIcon } from "@/components/icons/providers";
@ -41,10 +38,7 @@ import { ZhipuIcon } from "@/components/icons/providers";
*/ */
export function getProviderIcon( export function getProviderIcon(
provider: string, provider: string,
{ { isAutoMode, className = "size-4" }: { isAutoMode?: boolean; className?: string } = {}
isAutoMode,
className = "size-4",
}: { isAutoMode?: boolean; className?: string } = {}
) { ) {
if (isAutoMode || provider?.toUpperCase() === "AUTO") { if (isAutoMode || provider?.toUpperCase() === "AUTO") {
return <Shuffle className={cn(className, "text-violet-800")} />; return <Shuffle className={cn(className, "text-violet-800")} />;
@ -123,4 +117,3 @@ export function getProviderIcon(
return <Bot className={cn(className, "text-muted-foreground")} />; return <Bot className={cn(className, "text-muted-foreground")} />;
} }
} }

View file

@ -41,9 +41,7 @@ const nextConfig: NextConfig = {
} }
// SVGR: import *.svg as React components // SVGR: import *.svg as React components
const fileLoaderRule = config.module.rules.find( const fileLoaderRule = config.module.rules.find((rule: any) => rule.test?.test?.(".svg"));
(rule: any) => rule.test?.test?.(".svg"),
);
config.module.rules.push( config.module.rules.push(
// Re-apply the existing file loader for *.svg?url imports // Re-apply the existing file loader for *.svg?url imports
{ {
@ -57,7 +55,7 @@ const nextConfig: NextConfig = {
issuer: fileLoaderRule.issuer, issuer: fileLoaderRule.issuer,
resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] },
use: ["@svgr/webpack"], use: ["@svgr/webpack"],
}, }
); );
fileLoaderRule.exclude = /\.svg$/i; fileLoaderRule.exclude = /\.svg$/i;

View file

@ -3,4 +3,3 @@ declare module "*.svg" {
const content: FC<SVGProps<SVGSVGElement>>; const content: FC<SVGProps<SVGSVGElement>>;
export default content; export default content;
} }