mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-06 20:15:17 +02:00
refactor: enhance Circleback connector configuration and simplify sidebar components
- Introduced Zod schema for type-safe validation of Circleback webhook info, improving data handling in the CirclebackConfig component. - Updated the CirclebackConfig to utilize the new schema for fetching and setting webhook information. - Removed unnecessary state management related to source expansion in the sidebar components, streamlining the NavMain, NavChats, and NavNotes components. - Improved overall code clarity and maintainability by eliminating unused imports and props.
This commit is contained in:
parent
5f76844992
commit
f9a10c1e0d
5 changed files with 37 additions and 45 deletions
|
|
@ -3,6 +3,7 @@
|
|||
import { Copy, Webhook, Check, Info } from "lucide-react";
|
||||
import { useState, useEffect } from "react";
|
||||
import type { FC } from "react";
|
||||
import { z } from "zod";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
|
@ -14,13 +15,25 @@ export interface CirclebackConfigProps extends ConnectorConfigProps {
|
|||
onNameChange?: (name: string) => void;
|
||||
}
|
||||
|
||||
// Type-safe schema for webhook info response
|
||||
const circlebackWebhookInfoSchema = z.object({
|
||||
webhook_url: z.string(),
|
||||
search_space_id: z.number(),
|
||||
method: z.string(),
|
||||
content_type: z.string(),
|
||||
description: z.string(),
|
||||
note: z.string(),
|
||||
});
|
||||
|
||||
export type CirclebackWebhookInfo = z.infer<typeof circlebackWebhookInfoSchema>;
|
||||
|
||||
export const CirclebackConfig: FC<CirclebackConfigProps> = ({
|
||||
connector,
|
||||
onNameChange,
|
||||
}) => {
|
||||
const [name, setName] = useState<string>(connector.name || "");
|
||||
const [webhookUrl, setWebhookUrl] = useState<string>("");
|
||||
const [webhookInfo, setWebhookInfo] = useState<{ webhook_url: string; search_space_id: number; method: string; content_type: string; description: string; note: string } | null>(null);
|
||||
const [webhookInfo, setWebhookInfo] = useState<CirclebackWebhookInfo | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
|
|
@ -34,18 +47,30 @@ export const CirclebackConfig: FC<CirclebackConfigProps> = ({
|
|||
const fetchWebhookInfo = async () => {
|
||||
if (!connector.search_space_id) return;
|
||||
|
||||
const baseUrl = process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL;
|
||||
if (!baseUrl) {
|
||||
console.error("NEXT_PUBLIC_FASTAPI_BACKEND_URL is not configured");
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await authenticatedFetch(
|
||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/webhooks/circleback/${connector.search_space_id}/info`
|
||||
`${baseUrl}/api/v1/webhooks/circleback/${connector.search_space_id}/info`
|
||||
);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setWebhookInfo(data);
|
||||
setWebhookUrl(data.webhook_url || "");
|
||||
const data: unknown = await response.json();
|
||||
// Runtime validation with zod schema
|
||||
const validatedData = circlebackWebhookInfoSchema.parse(data);
|
||||
setWebhookInfo(validatedData);
|
||||
setWebhookUrl(validatedData.webhook_url);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch webhook info:", error);
|
||||
// Reset state on error
|
||||
setWebhookInfo(null);
|
||||
setWebhookUrl("");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -295,7 +295,6 @@ export const AppSidebar = memo(function AppSidebar({
|
|||
const { theme, setTheme } = useTheme();
|
||||
const { data: user, isPending: isLoadingUser } = useAtomValue(currentUserAtom);
|
||||
const [isClient, setIsClient] = useState(false);
|
||||
const [isSourcesExpanded, setIsSourcesExpanded] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsClient(true);
|
||||
|
|
@ -447,19 +446,17 @@ export const AppSidebar = memo(function AppSidebar({
|
|||
</SidebarHeader>
|
||||
|
||||
<SidebarContent className="gap-1">
|
||||
<NavMain items={processedNavMain} onSourcesExpandedChange={setIsSourcesExpanded} />
|
||||
<NavMain items={processedNavMain} />
|
||||
|
||||
<NavChats
|
||||
chats={processedRecentChats}
|
||||
searchSpaceId={searchSpaceId}
|
||||
isSourcesExpanded={isSourcesExpanded}
|
||||
/>
|
||||
|
||||
<NavNotes
|
||||
notes={processedRecentNotes}
|
||||
onAddNote={onAddNote}
|
||||
searchSpaceId={searchSpaceId}
|
||||
isSourcesExpanded={isSourcesExpanded}
|
||||
/>
|
||||
</SidebarContent>
|
||||
<SidebarFooter>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
} from "lucide-react";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
|
||||
import {
|
||||
|
|
@ -30,7 +30,6 @@ import {
|
|||
SidebarMenuItem,
|
||||
useSidebar,
|
||||
} from "@/components/ui/sidebar";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { AllChatsSidebar } from "./all-chats-sidebar";
|
||||
|
||||
|
|
@ -53,7 +52,6 @@ interface NavChatsProps {
|
|||
chats: ChatItem[];
|
||||
defaultOpen?: boolean;
|
||||
searchSpaceId?: string;
|
||||
isSourcesExpanded?: boolean;
|
||||
}
|
||||
|
||||
// Map of icon names to their components
|
||||
|
|
@ -68,24 +66,15 @@ export function NavChats({
|
|||
chats,
|
||||
defaultOpen = true,
|
||||
searchSpaceId,
|
||||
isSourcesExpanded = false,
|
||||
}: NavChatsProps) {
|
||||
const t = useTranslations("sidebar");
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const isMobile = useIsMobile();
|
||||
const { setOpenMobile } = useSidebar();
|
||||
const [isDeleting, setIsDeleting] = useState<number | null>(null);
|
||||
const [isOpen, setIsOpen] = useState(defaultOpen);
|
||||
const [isAllChatsSidebarOpen, setIsAllChatsSidebarOpen] = useState(false);
|
||||
|
||||
// Auto-collapse on smaller screens when Sources is expanded
|
||||
useEffect(() => {
|
||||
if (isSourcesExpanded && isMobile) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
}, [isSourcesExpanded, isMobile]);
|
||||
|
||||
// Handle chat deletion with loading state
|
||||
const handleDeleteChat = useCallback(async (chatId: number, deleteAction: () => void) => {
|
||||
setIsDeleting(chatId);
|
||||
|
|
|
|||
|
|
@ -31,10 +31,9 @@ interface NavItem {
|
|||
|
||||
interface NavMainProps {
|
||||
items: NavItem[];
|
||||
onSourcesExpandedChange?: (expanded: boolean) => void;
|
||||
}
|
||||
|
||||
export function NavMain({ items, onSourcesExpandedChange }: NavMainProps) {
|
||||
export function NavMain({ items }: NavMainProps) {
|
||||
const t = useTranslations("nav_menu");
|
||||
const pathname = usePathname();
|
||||
|
||||
|
|
@ -100,16 +99,9 @@ export function NavMain({ items, onSourcesExpandedChange }: NavMainProps) {
|
|||
});
|
||||
|
||||
// Handle collapsible state change
|
||||
const handleOpenChange = useCallback(
|
||||
(title: string, isOpen: boolean) => {
|
||||
setExpandedItems((prev) => ({ ...prev, [title]: isOpen }));
|
||||
// Notify parent when Sources is expanded/collapsed
|
||||
if (title === "Sources" && onSourcesExpandedChange) {
|
||||
onSourcesExpandedChange(isOpen);
|
||||
}
|
||||
},
|
||||
[onSourcesExpandedChange]
|
||||
);
|
||||
const handleOpenChange = useCallback((title: string, isOpen: boolean) => {
|
||||
setExpandedItems((prev) => ({ ...prev, [title]: isOpen }));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<SidebarGroup>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
} from "lucide-react";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
|
||||
import {
|
||||
|
|
@ -31,7 +31,6 @@ import {
|
|||
useSidebar,
|
||||
} from "@/components/ui/sidebar";
|
||||
import { useLogsSummary } from "@/hooks/use-logs";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { AllNotesSidebar } from "./all-notes-sidebar";
|
||||
|
||||
|
|
@ -55,7 +54,6 @@ interface NavNotesProps {
|
|||
onAddNote?: () => void;
|
||||
defaultOpen?: boolean;
|
||||
searchSpaceId?: string;
|
||||
isSourcesExpanded?: boolean;
|
||||
}
|
||||
|
||||
// Map of icon names to their components
|
||||
|
|
@ -70,12 +68,10 @@ export function NavNotes({
|
|||
onAddNote,
|
||||
defaultOpen = true,
|
||||
searchSpaceId,
|
||||
isSourcesExpanded = false,
|
||||
}: NavNotesProps) {
|
||||
const t = useTranslations("sidebar");
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const isMobile = useIsMobile();
|
||||
const { setOpenMobile } = useSidebar();
|
||||
const [isDeleting, setIsDeleting] = useState<number | null>(null);
|
||||
const [isOpen, setIsOpen] = useState(defaultOpen);
|
||||
|
|
@ -98,13 +94,6 @@ export function NavNotes({
|
|||
);
|
||||
}, [summary?.active_tasks]);
|
||||
|
||||
// Auto-collapse on smaller screens when Sources is expanded
|
||||
useEffect(() => {
|
||||
if (isSourcesExpanded && isMobile) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
}, [isSourcesExpanded, isMobile]);
|
||||
|
||||
// Handle note deletion with loading state
|
||||
const handleDeleteNote = useCallback(async (noteId: number, deleteAction: () => void) => {
|
||||
setIsDeleting(noteId);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue