"use client"; import { useQuery } from "@tanstack/react-query"; import { useAtomValue } from "jotai"; import { useTranslations } from "next-intl"; import { useCallback, useEffect, useState } from "react"; import { toast } from "sonner"; import { updateWorkspaceApiAccessMutationAtom, updateWorkspaceMutationAtom, } from "@/atoms/workspaces/workspace-mutation.atoms"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Skeleton } from "@/components/ui/skeleton"; import { Switch } from "@/components/ui/switch"; import { workspacesApiService } from "@/lib/apis/workspaces-api.service"; import { authenticatedFetch } from "@/lib/auth-fetch"; import { buildBackendUrl } from "@/lib/env-config"; import { cacheKeys } from "@/lib/query-client/cache-keys"; import { Spinner } from "../ui/spinner"; interface GeneralSettingsManagerProps { workspaceId: number; } export function GeneralSettingsManager({ workspaceId }: GeneralSettingsManagerProps) { const t = useTranslations("workspaceSettings"); const tCommon = useTranslations("common"); const { data: workspace, isLoading: loading, isError, refetch: fetchWorkspace, } = useQuery({ queryKey: cacheKeys.workspaces.detail(workspaceId.toString()), queryFn: () => workspacesApiService.getWorkspace({ id: workspaceId }), enabled: !!workspaceId, }); const { mutateAsync: updateWorkspace } = useAtomValue(updateWorkspaceMutationAtom); const { mutateAsync: updateWorkspaceApiAccess } = useAtomValue( updateWorkspaceApiAccessMutationAtom ); const [name, setName] = useState(""); const [description, setDescription] = useState(""); const [saving, setSaving] = useState(false); const [savingApiAccess, setSavingApiAccess] = useState(false); const [isExporting, setIsExporting] = useState(false); const hasWorkspace = !!workspace; const workspaceName = workspace?.name; const workspaceDescription = workspace?.description; const handleExportKB = useCallback(async () => { if (isExporting) return; setIsExporting(true); try { const response = await authenticatedFetch( buildBackendUrl(`/api/v1/workspaces/${workspaceId}/export`), { method: "GET" } ); if (!response.ok) { const errorData = await response.json().catch(() => ({ detail: "Export failed" })); throw new Error(errorData.detail || "Export failed"); } const blob = await response.blob(); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = "knowledge-base.zip"; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); toast.success("Knowledge base exported"); } catch (err) { console.error("KB export failed:", err); toast.error(err instanceof Error ? err.message : "Export failed"); } finally { setIsExporting(false); } }, [workspaceId, isExporting]); // Initialize state from fetched workspace useEffect(() => { if (hasWorkspace) { setName(workspaceName || ""); setDescription(workspaceDescription || ""); } }, [hasWorkspace, workspaceName, workspaceDescription]); // Derive hasChanges during render const hasChanges = !!workspace && ((workspace.name || "") !== name || (workspace.description || "") !== description); const handleSave = async () => { try { setSaving(true); await updateWorkspace({ id: workspaceId, data: { name: name.trim(), description: description.trim() || undefined, }, }); await fetchWorkspace(); } catch (error: unknown) { console.error("Error saving workspace details:", error); toast.error(error instanceof Error ? error.message : "Failed to save workspace details"); } finally { setSaving(false); } }; const onSubmit = (e: React.FormEvent) => { e.preventDefault(); handleSave(); }; const handleApiAccessToggle = useCallback( async (enabled: boolean) => { try { setSavingApiAccess(true); await updateWorkspaceApiAccess({ id: workspaceId, api_access_enabled: enabled, }); await fetchWorkspace(); } catch (error) { console.error("Error updating API access:", error); toast.error(error instanceof Error ? error.message : "Failed to update API access"); } finally { setSavingApiAccess(false); } }, [fetchWorkspace, workspaceId, updateWorkspaceApiAccess] ); if (loading) { return (
Failed to load settings.
Allow API keys to access this workspace.
Download all documents in this workspace as a ZIP of markdown files.