refact: format web project with biome

This commit is contained in:
CREDO23 2025-12-11 13:42:33 +02:00
parent be381c833e
commit 90f4ce61b5
10 changed files with 3007 additions and 2989 deletions

5667
surfsense_backend/uv.lock generated

File diff suppressed because it is too large Load diff

View file

@ -8,8 +8,8 @@ import { useTranslations } from "next-intl";
import type React from "react"; import type React from "react";
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import { activeChathatUIAtom, activeChatIdAtom } from "@/atoms/chats/ui.atoms"; import { activeChathatUIAtom, activeChatIdAtom } from "@/atoms/chats/ui.atoms";
import { activeSearchSpaceIdAtom } from "@/atoms/seach-spaces/seach-space-queries.atom";
import { llmPreferencesAtom } from "@/atoms/llm-config/llm-config-query.atoms"; import { llmPreferencesAtom } from "@/atoms/llm-config/llm-config-query.atoms";
import { activeSearchSpaceIdAtom } from "@/atoms/seach-spaces/seach-space-queries.atom";
import { ChatPanelContainer } from "@/components/chat/ChatPanel/ChatPanelContainer"; import { ChatPanelContainer } from "@/components/chat/ChatPanel/ChatPanelContainer";
import { DashboardBreadcrumb } from "@/components/dashboard-breadcrumb"; import { DashboardBreadcrumb } from "@/components/dashboard-breadcrumb";
import { LanguageSwitcher } from "@/components/LanguageSwitcher"; import { LanguageSwitcher } from "@/components/LanguageSwitcher";

View file

@ -1,11 +1,18 @@
"use client"; "use client";
import { useAtomValue } from "jotai";
import { FileText, MessageSquare, UserPlus, Users } from "lucide-react"; import { FileText, MessageSquare, UserPlus, Users } from "lucide-react";
import { motion } from "motion/react"; import { motion } from "motion/react";
import { useParams, useRouter } from "next/navigation"; import { useParams, useRouter } from "next/navigation";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { updateLLMPreferencesMutationAtom } from "@/atoms/llm-config/llm-config-mutation.atoms";
import {
globalLLMConfigsAtom,
llmConfigsAtom,
llmPreferencesAtom,
} from "@/atoms/llm-config/llm-config-query.atoms";
import { OnboardActionCard } from "@/components/onboard/onboard-action-card"; import { OnboardActionCard } from "@/components/onboard/onboard-action-card";
import { OnboardAdvancedSettings } from "@/components/onboard/onboard-advanced-settings"; import { OnboardAdvancedSettings } from "@/components/onboard/onboard-advanced-settings";
import { OnboardHeader } from "@/components/onboard/onboard-header"; import { OnboardHeader } from "@/components/onboard/onboard-header";
@ -13,10 +20,6 @@ import { OnboardLLMSetup } from "@/components/onboard/onboard-llm-setup";
import { OnboardLoading } from "@/components/onboard/onboard-loading"; import { OnboardLoading } from "@/components/onboard/onboard-loading";
import { OnboardStats } from "@/components/onboard/onboard-stats"; import { OnboardStats } from "@/components/onboard/onboard-stats";
import { getBearerToken, redirectToLogin } from "@/lib/auth-utils"; import { getBearerToken, redirectToLogin } from "@/lib/auth-utils";
import { useAtomValue } from "jotai";
import { llmConfigsAtom, globalLLMConfigsAtom, llmPreferencesAtom } from "@/atoms/llm-config/llm-config-query.atoms";
import { updateLLMPreferencesMutationAtom } from "@/atoms/llm-config/llm-config-mutation.atoms";
import { useMemo } from "react";
const OnboardPage = () => { const OnboardPage = () => {
const t = useTranslations("onboard"); const t = useTranslations("onboard");
@ -24,18 +27,28 @@ const OnboardPage = () => {
const params = useParams(); const params = useParams();
const searchSpaceId = Number(params.search_space_id); const searchSpaceId = Number(params.search_space_id);
const { data: llmConfigs = [], isFetching: configsLoading, refetch: refreshConfigs } = useAtomValue(llmConfigsAtom); const {
const { data: globalConfigs = [], isFetching: globalConfigsLoading } = useAtomValue(globalLLMConfigsAtom); data: llmConfigs = [],
const { data: preferences = {}, isFetching: preferencesLoading, refetch: refreshPreferences } = useAtomValue(llmPreferencesAtom); isFetching: configsLoading,
refetch: refreshConfigs,
} = useAtomValue(llmConfigsAtom);
const { data: globalConfigs = [], isFetching: globalConfigsLoading } =
useAtomValue(globalLLMConfigsAtom);
const {
data: preferences = {},
isFetching: preferencesLoading,
refetch: refreshPreferences,
} = useAtomValue(llmPreferencesAtom);
const { mutateAsync: updatePreferences } = useAtomValue(updateLLMPreferencesMutationAtom); const { mutateAsync: updatePreferences } = useAtomValue(updateLLMPreferencesMutationAtom);
// Compute isOnboardingComplete // Compute isOnboardingComplete
const isOnboardingComplete = useMemo(() => { const isOnboardingComplete = useMemo(() => {
return () => !!( return () =>
preferences.long_context_llm_id && !!(
preferences.fast_llm_id && preferences.long_context_llm_id &&
preferences.strategic_llm_id preferences.fast_llm_id &&
); preferences.strategic_llm_id
);
}, [preferences]); }, [preferences]);
const [isAutoConfiguring, setIsAutoConfiguring] = useState(false); const [isAutoConfiguring, setIsAutoConfiguring] = useState(false);
@ -44,8 +57,8 @@ const OnboardPage = () => {
const [showPromptSettings, setShowPromptSettings] = useState(false); const [showPromptSettings, setShowPromptSettings] = useState(false);
const handleRefreshPreferences = useCallback(async () => { const handleRefreshPreferences = useCallback(async () => {
await refreshPreferences() await refreshPreferences();
},[]) }, []);
// Track if we've already attempted auto-configuration // Track if we've already attempted auto-configuration
const hasAttemptedAutoConfig = useRef(false); const hasAttemptedAutoConfig = useRef(false);
@ -121,16 +134,15 @@ const OnboardPage = () => {
strategic_llm_id: defaultConfigId, strategic_llm_id: defaultConfigId,
}; };
await updatePreferences({
await updatePreferences({ search_space_id: searchSpaceId,
search_space_id: searchSpaceId, data: newPreferences,
data: newPreferences });
}); await refreshPreferences();
await refreshPreferences(); setAutoConfigComplete(true);
setAutoConfigComplete(true); toast.success("AI models configured automatically!", {
toast.success("AI models configured automatically!", { description: "You can customize these in advanced settings.",
description: "You can customize these in advanced settings.", });
});
} catch (error) { } catch (error) {
console.error("Auto-configuration failed:", error); console.error("Auto-configuration failed:", error);
} finally { } finally {

View file

@ -3,11 +3,11 @@ import { toast } from "sonner";
import { activeSearchSpaceIdAtom } from "@/atoms/seach-spaces/seach-space-queries.atom"; import { activeSearchSpaceIdAtom } from "@/atoms/seach-spaces/seach-space-queries.atom";
import type { import type {
CreateLLMConfigRequest, CreateLLMConfigRequest,
UpdateLLMConfigRequest,
DeleteLLMConfigRequest, DeleteLLMConfigRequest,
GetLLMConfigsResponse, GetLLMConfigsResponse,
UpdateLLMPreferencesRequest, UpdateLLMConfigRequest,
UpdateLLMConfigResponse, UpdateLLMConfigResponse,
UpdateLLMPreferencesRequest,
} from "@/contracts/types/llm-config.types"; } from "@/contracts/types/llm-config.types";
import { llmConfigApiService } from "@/lib/apis/llm-config-api.service"; import { llmConfigApiService } from "@/lib/apis/llm-config-api.service";
import { cacheKeys } from "@/lib/query-client/cache-keys"; import { cacheKeys } from "@/lib/query-client/cache-keys";
@ -45,7 +45,7 @@ export const updateLLMConfigMutationAtom = atomWithMutation((get) => {
return llmConfigApiService.updateLLMConfig(request); return llmConfigApiService.updateLLMConfig(request);
}, },
onSuccess: (_: UpdateLLMConfigResponse , request: UpdateLLMConfigRequest) => { onSuccess: (_: UpdateLLMConfigResponse, request: UpdateLLMConfigRequest) => {
toast.success("LLM configuration updated successfully"); toast.success("LLM configuration updated successfully");
queryClient.invalidateQueries({ queryClient.invalidateQueries({
queryKey: cacheKeys.llmConfigs.all(searchSpaceId!), queryKey: cacheKeys.llmConfigs.all(searchSpaceId!),

View file

@ -39,7 +39,7 @@ export const llmPreferencesAtom = atomWithQuery((get) => {
staleTime: 5 * 60 * 1000, // 5 minutes staleTime: 5 * 60 * 1000, // 5 minutes
queryFn: async () => { queryFn: async () => {
return llmConfigApiService.getLLMPreferences({ return llmConfigApiService.getLLMPreferences({
search_space_id: Number(searchSpaceId), search_space_id: Number(searchSpaceId),
}); });
}, },
}; };

View file

@ -1,11 +1,17 @@
"use client"; "use client";
import { ChatInput } from "@llamaindex/chat-ui"; import { ChatInput } from "@llamaindex/chat-ui";
import { useAtom } from "jotai"; import { useAtom, useAtomValue } from "jotai";
import { Brain, Check, FolderOpen, Minus, Plus, PlusCircle, Zap } from "lucide-react"; import { Brain, Check, FolderOpen, Minus, Plus, PlusCircle, Zap } from "lucide-react";
import { useParams, useRouter } from "next/navigation"; import { useParams, useRouter } from "next/navigation";
import React, { Suspense, useCallback, useMemo, useState } from "react"; import React, { Suspense, useCallback, useMemo, useState } from "react";
import { documentTypeCountsAtom } from "@/atoms/documents/document-query.atoms"; import { documentTypeCountsAtom } from "@/atoms/documents/document-query.atoms";
import { updateLLMPreferencesMutationAtom } from "@/atoms/llm-config/llm-config-mutation.atoms";
import {
globalLLMConfigsAtom,
llmConfigsAtom,
llmPreferencesAtom,
} from "@/atoms/llm-config/llm-config-query.atoms";
import { DocumentsDataTable } from "@/components/chat/DocumentsDataTable"; import { DocumentsDataTable } from "@/components/chat/DocumentsDataTable";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
@ -27,11 +33,8 @@ import {
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { getConnectorIcon } from "@/contracts/enums/connectorIcons"; import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
import { Document } from "@/contracts/types/document.types"; import type { Document } from "@/contracts/types/document.types";
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors"; import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
import { useAtomValue } from "jotai";
import { llmConfigsAtom, globalLLMConfigsAtom, llmPreferencesAtom } from "@/atoms/llm-config/llm-config-query.atoms";
import { updateLLMPreferencesMutationAtom } from "@/atoms/llm-config/llm-config-mutation.atoms";
const DocumentSelector = React.memo( const DocumentSelector = React.memo(
({ ({
@ -541,11 +544,20 @@ const LLMSelector = React.memo(() => {
const { search_space_id } = useParams(); const { search_space_id } = useParams();
const searchSpaceId = Number(search_space_id); const searchSpaceId = Number(search_space_id);
const { data: llmConfigs = [], isFetching: llmLoading, isError: error } = useAtomValue(llmConfigsAtom); const {
const { data: globalConfigs = [], isFetching: globalConfigsLoading, isError: globalConfigsError } = useAtomValue(globalLLMConfigsAtom); data: llmConfigs = [],
isFetching: llmLoading,
isError: error,
} = useAtomValue(llmConfigsAtom);
const {
data: globalConfigs = [],
isFetching: globalConfigsLoading,
isError: globalConfigsError,
} = useAtomValue(globalLLMConfigsAtom);
// Replace useLLMPreferences with jotai atoms // Replace useLLMPreferences with jotai atoms
const { data: preferences = {}, isFetching: preferencesLoading } = useAtomValue(llmPreferencesAtom); const { data: preferences = {}, isFetching: preferencesLoading } =
useAtomValue(llmPreferencesAtom);
const { mutateAsync: updatePreferences } = useAtomValue(updateLLMPreferencesMutationAtom); const { mutateAsync: updatePreferences } = useAtomValue(updateLLMPreferencesMutationAtom);
const isLoading = llmLoading || preferencesLoading || globalConfigsLoading; const isLoading = llmLoading || preferencesLoading || globalConfigsLoading;
@ -571,7 +583,9 @@ const LLMSelector = React.memo(() => {
<span className="hidden sm:inline text-muted-foreground text-xs truncate max-w-[60px]"> <span className="hidden sm:inline text-muted-foreground text-xs truncate max-w-[60px]">
{selectedConfig.name} {selectedConfig.name}
</span> </span>
{"is_global" in selectedConfig && selectedConfig.is_global && <span className="text-xs">🌐</span>} {"is_global" in selectedConfig && selectedConfig.is_global && (
<span className="text-xs">🌐</span>
)}
</div> </div>
); );
}, [selectedConfig]); }, [selectedConfig]);
@ -581,7 +595,7 @@ const LLMSelector = React.memo(() => {
const llmId = value ? parseInt(value, 10) : undefined; const llmId = value ? parseInt(value, 10) : undefined;
updatePreferences({ updatePreferences({
search_space_id: searchSpaceId, search_space_id: searchSpaceId,
data: { fast_llm_id: llmId } data: { fast_llm_id: llmId },
}); });
}, },
[updatePreferences, searchSpaceId] [updatePreferences, searchSpaceId]

View file

@ -1,5 +1,6 @@
"use client"; "use client";
import { useAtomValue } from "jotai";
import { import {
AlertCircle, AlertCircle,
Bot, Bot,
@ -17,6 +18,16 @@ import { motion } from "motion/react";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import {
createLLMConfigMutationAtom,
deleteLLMConfigMutationAtom,
updateLLMPreferencesMutationAtom,
} from "@/atoms/llm-config/llm-config-mutation.atoms";
import {
globalLLMConfigsAtom,
llmConfigsAtom,
llmPreferencesAtom,
} from "@/atoms/llm-config/llm-config-query.atoms";
import { Alert, AlertDescription } from "@/components/ui/alert"; import { Alert, AlertDescription } from "@/components/ui/alert";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
@ -43,13 +54,9 @@ import { Separator } from "@/components/ui/separator";
import { LANGUAGES } from "@/contracts/enums/languages"; import { LANGUAGES } from "@/contracts/enums/languages";
import { getModelsByProvider } from "@/contracts/enums/llm-models"; import { getModelsByProvider } from "@/contracts/enums/llm-models";
import { LLM_PROVIDERS } from "@/contracts/enums/llm-providers"; import { LLM_PROVIDERS } from "@/contracts/enums/llm-providers";
import { type CreateLLMConfigRequest, LLMConfig } from "@/contracts/types/llm-config.types";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import InferenceParamsEditor from "../inference-params-editor"; import InferenceParamsEditor from "../inference-params-editor";
import { useAtomValue } from "jotai";
import { createLLMConfigMutationAtom, deleteLLMConfigMutationAtom, updateLLMPreferencesMutationAtom } from "@/atoms/llm-config/llm-config-mutation.atoms";
import { llmConfigsAtom, globalLLMConfigsAtom, llmPreferencesAtom } from "@/atoms/llm-config/llm-config-query.atoms";
import { CreateLLMConfigRequest, LLMConfig } from "@/contracts/types/llm-config.types";
interface SetupLLMStepProps { interface SetupLLMStepProps {
searchSpaceId: number; searchSpaceId: number;
@ -94,10 +101,12 @@ export function SetupLLMStep({
onConfigDeleted, onConfigDeleted,
onPreferencesUpdated, onPreferencesUpdated,
}: SetupLLMStepProps) { }: SetupLLMStepProps) {
const { mutateAsync : createLLMConfig, isPending : isCreatingLlmConfig } = useAtomValue(createLLMConfigMutationAtom); const { mutate: createLLMConfig, isPending: isCreatingLlmConfig } = useAtomValue(
createLLMConfigMutationAtom
);
const t = useTranslations("onboard"); const t = useTranslations("onboard");
const { mutateAsync : deleteLLMConfig } = useAtomValue(deleteLLMConfigMutationAtom); const { mutateAsync: deleteLLMConfig } = useAtomValue(deleteLLMConfigMutationAtom);
const { data : llmConfigs = []} = useAtomValue(llmConfigsAtom); const { data: llmConfigs = [] } = useAtomValue(llmConfigsAtom);
const { data: globalConfigs = [] } = useAtomValue(globalLLMConfigsAtom); const { data: globalConfigs = [] } = useAtomValue(globalLLMConfigsAtom);
const { data: preferences = {} } = useAtomValue(llmPreferencesAtom); const { data: preferences = {} } = useAtomValue(llmPreferencesAtom);
const { mutateAsync: updatePreferences } = useAtomValue(updateLLMPreferencesMutationAtom); const { mutateAsync: updatePreferences } = useAtomValue(updateLLMPreferencesMutationAtom);
@ -146,23 +155,32 @@ export function SetupLLMStep({
return; return;
} }
const result = await createLLMConfig(formData); createLLMConfig(formData, {
onError: (error) => {
if (result) { console.error("Error creating LLM config:", error);
setFormData({ if (error instanceof Error) {
name: "", toast.error(error?.message || "Failed to create LLM config");
provider: "" as CreateLLMConfigRequest["provider"], }
custom_provider: "", },
model_name: "", onSuccess: () => {
api_key: "", toast.success("LLM config created successfully");
api_base: "", setFormData({
language: "English", name: "",
litellm_params: {}, provider: "" as CreateLLMConfigRequest["provider"],
search_space_id: searchSpaceId, custom_provider: "",
}); model_name: "",
setIsAddingNew(false); api_key: "",
onConfigCreated?.(); api_base: "",
} language: "English",
litellm_params: {},
search_space_id: searchSpaceId,
});
onConfigCreated?.();
},
onSettled: () => {
setIsAddingNew(false);
},
});
}; };
const handleRoleAssignment = async (role: string, configId: string) => { const handleRoleAssignment = async (role: string, configId: string) => {
@ -193,16 +211,16 @@ export function SetupLLMStep({
typeof newAssignments.strategic_llm_id === "string" typeof newAssignments.strategic_llm_id === "string"
? parseInt(newAssignments.strategic_llm_id) ? parseInt(newAssignments.strategic_llm_id)
: newAssignments.strategic_llm_id, : newAssignments.strategic_llm_id,
}; };
await updatePreferences({ await updatePreferences({
search_space_id: searchSpaceId, search_space_id: searchSpaceId,
data: numericAssignments data: numericAssignments,
}); });
if (onPreferencesUpdated) { if (onPreferencesUpdated) {
await onPreferencesUpdated(); await onPreferencesUpdated();
} }
} }
}; };
@ -327,7 +345,7 @@ export function SetupLLMStep({
await deleteLLMConfig({ id: config.id }); await deleteLLMConfig({ id: config.id });
onConfigDeleted?.(); onConfigDeleted?.();
} catch (error) { } catch (error) {
console.error('Failed to delete config:', error); console.error("Failed to delete config:", error);
} }
}} }}
className="text-destructive hover:text-destructive" className="text-destructive hover:text-destructive"

View file

@ -1,5 +1,6 @@
"use client"; "use client";
import { useAtomValue } from "jotai";
import { import {
AlertCircle, AlertCircle,
Bot, Bot,
@ -15,6 +16,12 @@ import {
import { motion } from "motion/react"; import { motion } from "motion/react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { updateLLMPreferencesMutationAtom } from "@/atoms/llm-config/llm-config-mutation.atoms";
import {
globalLLMConfigsAtom,
llmConfigsAtom,
llmPreferencesAtom,
} from "@/atoms/llm-config/llm-config-query.atoms";
import { Alert, AlertDescription } from "@/components/ui/alert"; import { Alert, AlertDescription } from "@/components/ui/alert";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
@ -28,10 +35,6 @@ import {
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { useAtomValue } from "jotai";
import { llmConfigsAtom, globalLLMConfigsAtom, llmPreferencesAtom } from "@/atoms/llm-config/llm-config-query.atoms";
import { updateLLMPreferencesMutationAtom } from "@/atoms/llm-config/llm-config-mutation.atoms";
const ROLE_DESCRIPTIONS = { const ROLE_DESCRIPTIONS = {
long_context: { long_context: {
icon: Brain, icon: Brain,
@ -68,7 +71,7 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
data: llmConfigs = [], data: llmConfigs = [],
isFetching: configsLoading, isFetching: configsLoading,
error: configsError, error: configsError,
refetch: refreshConfigs refetch: refreshConfigs,
} = useAtomValue(llmConfigsAtom); } = useAtomValue(llmConfigsAtom);
const { const {
data: globalConfigs = [], data: globalConfigs = [],
@ -150,11 +153,11 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
? parseInt(assignments.strategic_llm_id) ? parseInt(assignments.strategic_llm_id)
: undefined : undefined
: assignments.strategic_llm_id, : assignments.strategic_llm_id,
}; };
await updatePreferences({ await updatePreferences({
search_space_id: searchSpaceId, search_space_id: searchSpaceId,
data: numericAssignments data: numericAssignments,
}); });
setHasChanges(false); setHasChanges(false);
@ -217,12 +220,12 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
<span className="sm:hidden">Configs</span> <span className="sm:hidden">Configs</span>
</Button> </Button>
<Button <Button
variant="outline" variant="outline"
size="sm" size="sm"
onClick={() => refreshPreferences()} onClick={() => refreshPreferences()}
disabled={isLoading} disabled={isLoading}
className="flex items-center gap-2" className="flex items-center gap-2"
> >
<RefreshCw className={`h-4 w-4 ${preferencesLoading ? "animate-spin" : ""}`} /> <RefreshCw className={`h-4 w-4 ${preferencesLoading ? "animate-spin" : ""}`} />
<span className="hidden sm:inline">Refresh Preferences</span> <span className="hidden sm:inline">Refresh Preferences</span>
<span className="sm:hidden">Prefs</span> <span className="sm:hidden">Prefs</span>
@ -233,13 +236,13 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
{/* Error Alert */} {/* Error Alert */}
{hasError && ( {hasError && (
<Alert variant="destructive"> <Alert variant="destructive">
<AlertCircle className="h-4 w-4" /> <AlertCircle className="h-4 w-4" />
<AlertDescription> <AlertDescription>
{(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 ?? "Failed to load global configurations")} (globalConfigsError?.message ?? "Failed to load global configurations")}
</AlertDescription> </AlertDescription>
</Alert> </Alert>
)} )}
{/* Loading State */} {/* Loading State */}

View file

@ -1,5 +1,6 @@
"use client"; "use client";
import { useAtomValue } from "jotai";
import { import {
AlertCircle, AlertCircle,
Bot, Bot,
@ -17,6 +18,12 @@ import {
import { AnimatePresence, motion } from "motion/react"; import { AnimatePresence, motion } from "motion/react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import {
createLLMConfigMutationAtom,
deleteLLMConfigMutationAtom,
updateLLMConfigMutationAtom,
} from "@/atoms/llm-config/llm-config-mutation.atoms";
import { globalLLMConfigsAtom, llmConfigsAtom } from "@/atoms/llm-config/llm-config-query.atoms";
import { Alert, AlertDescription } from "@/components/ui/alert"; import { Alert, AlertDescription } from "@/components/ui/alert";
import { import {
AlertDialog, AlertDialog,
@ -59,23 +66,42 @@ import {
import { LANGUAGES } from "@/contracts/enums/languages"; import { LANGUAGES } from "@/contracts/enums/languages";
import { getModelsByProvider } from "@/contracts/enums/llm-models"; import { getModelsByProvider } from "@/contracts/enums/llm-models";
import { LLM_PROVIDERS } from "@/contracts/enums/llm-providers"; import { LLM_PROVIDERS } from "@/contracts/enums/llm-providers";
import type {
CreateLLMConfigRequest,
CreateLLMConfigResponse,
LLMConfig,
UpdateLLMConfigResponse,
} from "@/contracts/types/llm-config.types";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import InferenceParamsEditor from "../inference-params-editor"; import InferenceParamsEditor from "../inference-params-editor";
import { useAtomValue } from "jotai";
import { createLLMConfigMutationAtom, deleteLLMConfigMutationAtom, updateLLMConfigMutationAtom } from "@/atoms/llm-config/llm-config-mutation.atoms";
import { CreateLLMConfigRequest, CreateLLMConfigResponse, LLMConfig, UpdateLLMConfigResponse } from "@/contracts/types/llm-config.types";
import { globalLLMConfigsAtom, llmConfigsAtom } from "@/atoms/llm-config/llm-config-query.atoms";
interface ModelConfigManagerProps { interface ModelConfigManagerProps {
searchSpaceId: number; searchSpaceId: number;
} }
export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) { export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) {
const { mutateAsync : createLLMConfig, isPending : isCreatingLLMConfig, error : createLLMConfigError, } = useAtomValue(createLLMConfigMutationAtom) const {
const { mutateAsync : updateLLMConfig, isPending : isUpdatingLLMConfig, error : updateLLMConfigError,} = useAtomValue(updateLLMConfigMutationAtom) mutateAsync: createLLMConfig,
const { mutateAsync : deleteLLMConfig, isPending : isDeletingLLMConfig, error : deleteLLMConfigError, } = useAtomValue(deleteLLMConfigMutationAtom) isPending: isCreatingLLMConfig,
const { data : llmConfigs, isFetching : isFetchingLLMConfigs, error : LLMConfigsFetchError, refetch : refreshConfigs} = useAtomValue(llmConfigsAtom) error: createLLMConfigError,
const { data : globalConfigs = [] } = useAtomValue(globalLLMConfigsAtom); } = useAtomValue(createLLMConfigMutationAtom);
const {
mutateAsync: updateLLMConfig,
isPending: isUpdatingLLMConfig,
error: updateLLMConfigError,
} = useAtomValue(updateLLMConfigMutationAtom);
const {
mutateAsync: deleteLLMConfig,
isPending: isDeletingLLMConfig,
error: deleteLLMConfigError,
} = useAtomValue(deleteLLMConfigMutationAtom);
const {
data: llmConfigs,
isFetching: isFetchingLLMConfigs,
error: LLMConfigsFetchError,
refetch: refreshConfigs,
} = useAtomValue(llmConfigsAtom);
const { data: globalConfigs = [] } = useAtomValue(globalLLMConfigsAtom);
const [isAddingNew, setIsAddingNew] = useState(false); const [isAddingNew, setIsAddingNew] = useState(false);
const [editingConfig, setEditingConfig] = useState<LLMConfig | null>(null); const [editingConfig, setEditingConfig] = useState<LLMConfig | null>(null);
const [formData, setFormData] = useState<CreateLLMConfigRequest>({ const [formData, setFormData] = useState<CreateLLMConfigRequest>({
@ -89,9 +115,14 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) {
litellm_params: {}, litellm_params: {},
search_space_id: searchSpaceId, search_space_id: searchSpaceId,
}); });
const isSubmitting = isCreatingLLMConfig || isUpdatingLLMConfig const isSubmitting = isCreatingLLMConfig || isUpdatingLLMConfig;
const errors = [createLLMConfigError, updateLLMConfigError, deleteLLMConfigError, LLMConfigsFetchError] as Error[] const errors = [
const isError = Boolean(errors.filter(Boolean).length) createLLMConfigError,
updateLLMConfigError,
deleteLLMConfigError,
LLMConfigsFetchError,
] as Error[];
const isError = Boolean(errors.filter(Boolean).length);
const [modelComboboxOpen, setModelComboboxOpen] = useState(false); const [modelComboboxOpen, setModelComboboxOpen] = useState(false);
const [configToDelete, setConfigToDelete] = useState<LLMConfig | null>(null); const [configToDelete, setConfigToDelete] = useState<LLMConfig | null>(null);
const [isDeleting, setIsDeleting] = useState(false); const [isDeleting, setIsDeleting] = useState(false);
@ -118,7 +149,7 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) {
}; };
// Handle provider change with auto-fill API Base URL and reset model / 处理 Provider 变更并自动填充 API Base URL 并重置模型 // Handle provider change with auto-fill API Base URL and reset model / 处理 Provider 变更并自动填充 API Base URL 并重置模型
const handleProviderChange = (providerValue : CreateLLMConfigRequest["provider"]) => { const handleProviderChange = (providerValue: CreateLLMConfigRequest["provider"]) => {
const provider = LLM_PROVIDERS.find((p) => p.value === providerValue); const provider = LLM_PROVIDERS.find((p) => p.value === providerValue);
setFormData((prev) => ({ setFormData((prev) => ({
...prev, ...prev,
@ -129,8 +160,6 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) {
})); }));
}; };
const handleSubmit = async (e: React.FormEvent) => { const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
if (!formData.name || !formData.provider || !formData.model_name || !formData.api_key) { if (!formData.name || !formData.provider || !formData.model_name || !formData.api_key) {
@ -141,7 +170,7 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) {
let result: CreateLLMConfigResponse | UpdateLLMConfigResponse | null = null; let result: CreateLLMConfigResponse | UpdateLLMConfigResponse | null = null;
if (editingConfig) { if (editingConfig) {
// Update existing config // Update existing config
result = await updateLLMConfig({id : editingConfig.id, data : formData}); result = await updateLLMConfig({ id: editingConfig.id, data: formData });
} else { } else {
// Create new config // Create new config
result = await createLLMConfig(formData); result = await createLLMConfig(formData);
@ -218,14 +247,15 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) {
</div> </div>
{/* Error Alert */} {/* Error Alert */}
{isError && errors.filter(Boolean).map(err => { {isError &&
return ( errors.filter(Boolean).map((err, i) => {
<Alert variant="destructive"> return (
<AlertCircle className="h-4 w-4" /> <Alert key={`err.message-${i}`} variant="destructive">
<AlertDescription>{err?.message ?? "Something went wrong"}</AlertDescription> <AlertCircle className="h-4 w-4" />
</Alert> <AlertDescription>{err?.message ?? "Something went wrong"}</AlertDescription>
) </Alert>
}) } );
})}
{/* Global Configs Info Alert */} {/* Global Configs Info Alert */}
{!isFetchingLLMConfigs && !isError && globalConfigs.length > 0 && ( {!isFetchingLLMConfigs && !isError && globalConfigs.length > 0 && (
@ -254,7 +284,7 @@ export function ModelConfigManager({ searchSpaceId }: ModelConfigManagerProps) {
)} )}
{/* Stats Overview */} {/* Stats Overview */}
{!isFetchingLLMConfigs && !isError&& ( {!isFetchingLLMConfigs && !isError && (
<div className="grid gap-3 grid-cols-3"> <div className="grid gap-3 grid-cols-3">
<Card className="overflow-hidden"> <Card className="overflow-hidden">
<div className="h-1 bg-blue-500" /> <div className="h-1 bg-blue-500" />

View file

@ -1,7 +1,7 @@
import type { GetChatsRequest } from "@/contracts/types/chat.types"; import type { GetChatsRequest } from "@/contracts/types/chat.types";
import type { GetDocumentsRequest } from "@/contracts/types/document.types"; import type { GetDocumentsRequest } from "@/contracts/types/document.types";
import type { GetPodcastsRequest } from "@/contracts/types/podcast.types";
import type { GetLLMConfigsRequest } from "@/contracts/types/llm-config.types"; import type { GetLLMConfigsRequest } from "@/contracts/types/llm-config.types";
import type { GetPodcastsRequest } from "@/contracts/types/podcast.types";
export const cacheKeys = { export const cacheKeys = {
chats: { chats: {