mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-27 01:36:30 +02:00
Merge remote-tracking branch 'upstream/dev' into fix/chatpage-ux
This commit is contained in:
commit
ae4ee9ab70
36 changed files with 4225 additions and 3591 deletions
5981
surfsense_backend/uv.lock
generated
5981
surfsense_backend/uv.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import {
|
import {
|
||||||
Calendar as CalendarIcon,
|
Calendar as CalendarIcon,
|
||||||
Clock,
|
Clock,
|
||||||
|
|
@ -15,6 +16,12 @@ import { useParams, useRouter } from "next/navigation";
|
||||||
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 {
|
||||||
|
deleteConnectorMutationAtom,
|
||||||
|
indexConnectorMutationAtom,
|
||||||
|
updateConnectorMutationAtom,
|
||||||
|
} from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
|
import { connectorsAtom } from "@/atoms/connectors/connector-query.atoms";
|
||||||
import {
|
import {
|
||||||
AlertDialog,
|
AlertDialog,
|
||||||
AlertDialogAction,
|
AlertDialogAction,
|
||||||
|
|
@ -59,7 +66,6 @@ import {
|
||||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export default function ConnectorsPage() {
|
export default function ConnectorsPage() {
|
||||||
|
|
@ -84,8 +90,12 @@ export default function ConnectorsPage() {
|
||||||
const searchSpaceId = params.search_space_id as string;
|
const searchSpaceId = params.search_space_id as string;
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
|
|
||||||
const { connectors, isLoading, error, deleteConnector, indexConnector, updateConnector } =
|
const { data: connectors = [], isLoading, error } = useAtomValue(connectorsAtom);
|
||||||
useSearchSourceConnectors(false, parseInt(searchSpaceId));
|
|
||||||
|
const { mutateAsync: deleteConnector } = useAtomValue(deleteConnectorMutationAtom);
|
||||||
|
const { mutateAsync: indexConnector } = useAtomValue(indexConnectorMutationAtom);
|
||||||
|
const { mutateAsync: updateConnector } = useAtomValue(updateConnectorMutationAtom);
|
||||||
|
|
||||||
const [connectorToDelete, setConnectorToDelete] = useState<number | null>(null);
|
const [connectorToDelete, setConnectorToDelete] = useState<number | null>(null);
|
||||||
const [indexingConnectorId, setIndexingConnectorId] = useState<number | null>(null);
|
const [indexingConnectorId, setIndexingConnectorId] = useState<number | null>(null);
|
||||||
const [datePickerOpen, setDatePickerOpen] = useState(false);
|
const [datePickerOpen, setDatePickerOpen] = useState(false);
|
||||||
|
|
@ -117,11 +127,9 @@ export default function ConnectorsPage() {
|
||||||
if (connectorToDelete === null) return;
|
if (connectorToDelete === null) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await deleteConnector(connectorToDelete);
|
await deleteConnector({ id: connectorToDelete });
|
||||||
toast.success(t("delete_success"));
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error deleting connector:", error);
|
console.error("Error deleting connector:", error);
|
||||||
toast.error(t("delete_failed"));
|
|
||||||
} finally {
|
} finally {
|
||||||
setConnectorToDelete(null);
|
setConnectorToDelete(null);
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +152,14 @@ export default function ConnectorsPage() {
|
||||||
const startDateStr = startDate ? format(startDate, "yyyy-MM-dd") : undefined;
|
const startDateStr = startDate ? format(startDate, "yyyy-MM-dd") : undefined;
|
||||||
const endDateStr = endDate ? format(endDate, "yyyy-MM-dd") : undefined;
|
const endDateStr = endDate ? format(endDate, "yyyy-MM-dd") : undefined;
|
||||||
|
|
||||||
await indexConnector(selectedConnectorForIndexing, searchSpaceId, startDateStr, endDateStr);
|
await indexConnector({
|
||||||
|
connector_id: selectedConnectorForIndexing,
|
||||||
|
queryParams: {
|
||||||
|
search_space_id: searchSpaceId,
|
||||||
|
start_date: startDateStr,
|
||||||
|
end_date: endDateStr,
|
||||||
|
},
|
||||||
|
});
|
||||||
toast.success(t("indexing_started"));
|
toast.success(t("indexing_started"));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error indexing connector content:", error);
|
console.error("Error indexing connector content:", error);
|
||||||
|
|
@ -161,7 +176,12 @@ export default function ConnectorsPage() {
|
||||||
const handleQuickIndexConnector = async (connectorId: number) => {
|
const handleQuickIndexConnector = async (connectorId: number) => {
|
||||||
setIndexingConnectorId(connectorId);
|
setIndexingConnectorId(connectorId);
|
||||||
try {
|
try {
|
||||||
await indexConnector(connectorId, searchSpaceId);
|
await indexConnector({
|
||||||
|
connector_id: connectorId,
|
||||||
|
queryParams: {
|
||||||
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
toast.success(t("indexing_started"));
|
toast.success(t("indexing_started"));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error indexing connector content:", error);
|
console.error("Error indexing connector content:", error);
|
||||||
|
|
@ -221,9 +241,12 @@ export default function ConnectorsPage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateConnector(selectedConnectorForPeriodic, {
|
await updateConnector({
|
||||||
periodic_indexing_enabled: periodicEnabled,
|
id: selectedConnectorForPeriodic,
|
||||||
indexing_frequency_minutes: frequency,
|
data: {
|
||||||
|
periodic_indexing_enabled: periodicEnabled,
|
||||||
|
indexing_frequency_minutes: frequency,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
toast.success(
|
toast.success(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, Info, Loader2 } 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";
|
||||||
|
|
@ -8,6 +9,8 @@ import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { updateConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
|
import { connectorsAtom } from "@/atoms/connectors/connector-query.atoms";
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
|
@ -21,10 +24,8 @@ import {
|
||||||
FormMessage,
|
FormMessage,
|
||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import {
|
import type { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
type SearchSourceConnector,
|
import type { SearchSourceConnector } from "@/hooks/use-search-source-connectors";
|
||||||
useSearchSourceConnectors,
|
|
||||||
} from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
// Define the form schema with Zod
|
// Define the form schema with Zod
|
||||||
const apiConnectorFormSchema = z.object({
|
const apiConnectorFormSchema = z.object({
|
||||||
|
|
@ -85,7 +86,8 @@ export default function EditConnectorPage() {
|
||||||
const searchSpaceId = params.search_space_id as string;
|
const searchSpaceId = params.search_space_id as string;
|
||||||
const connectorId = parseInt(params.connector_id as string, 10);
|
const connectorId = parseInt(params.connector_id as string, 10);
|
||||||
|
|
||||||
const { connectors, updateConnector } = useSearchSourceConnectors(false, parseInt(searchSpaceId));
|
const { data: connectors = [] } = useAtomValue(connectorsAtom);
|
||||||
|
const { mutateAsync: updateConnector } = useAtomValue(updateConnectorMutationAtom);
|
||||||
const [connector, setConnector] = useState<SearchSourceConnector | null>(null);
|
const [connector, setConnector] = useState<SearchSourceConnector | null>(null);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
|
@ -99,14 +101,12 @@ export default function EditConnectorPage() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Find connector in the list
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const currentConnector = connectors.find((c) => c.id === connectorId);
|
const currentConnector = connectors.find((c) => c.id === connectorId);
|
||||||
|
|
||||||
if (currentConnector) {
|
if (currentConnector) {
|
||||||
setConnector(currentConnector);
|
setConnector(currentConnector);
|
||||||
|
|
||||||
// Check if connector type is supported
|
|
||||||
const apiKeyField = getApiKeyFieldName(currentConnector.connector_type);
|
const apiKeyField = getApiKeyFieldName(currentConnector.connector_type);
|
||||||
if (apiKeyField) {
|
if (apiKeyField) {
|
||||||
form.reset({
|
form.reset({
|
||||||
|
|
@ -114,14 +114,12 @@ export default function EditConnectorPage() {
|
||||||
api_key: currentConnector.config[apiKeyField] || "",
|
api_key: currentConnector.config[apiKeyField] || "",
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Redirect if not a supported connector type
|
|
||||||
toast.error("This connector type is not supported for editing");
|
toast.error("This connector type is not supported for editing");
|
||||||
router.push(`/dashboard/${searchSpaceId}/connectors`);
|
router.push(`/dashboard/${searchSpaceId}/connectors`);
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
} else if (!isLoading && connectors.length > 0) {
|
} else if (!isLoading && connectors.length > 0) {
|
||||||
// If connectors are loaded but this one isn't found
|
|
||||||
toast.error("Connector not found");
|
toast.error("Connector not found");
|
||||||
router.push(`/dashboard/${searchSpaceId}/connectors`);
|
router.push(`/dashboard/${searchSpaceId}/connectors`);
|
||||||
}
|
}
|
||||||
|
|
@ -135,18 +133,20 @@ export default function EditConnectorPage() {
|
||||||
try {
|
try {
|
||||||
const apiKeyField = getApiKeyFieldName(connector.connector_type);
|
const apiKeyField = getApiKeyFieldName(connector.connector_type);
|
||||||
|
|
||||||
// Only update the API key if a new one was provided
|
|
||||||
const updatedConfig = { ...connector.config };
|
const updatedConfig = { ...connector.config };
|
||||||
if (values.api_key) {
|
if (values.api_key) {
|
||||||
updatedConfig[apiKeyField] = values.api_key;
|
updatedConfig[apiKeyField] = values.api_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateConnector(connectorId, {
|
await updateConnector({
|
||||||
name: values.name,
|
id: connectorId,
|
||||||
connector_type: connector.connector_type,
|
data: {
|
||||||
config: updatedConfig,
|
name: values.name,
|
||||||
is_indexable: connector.is_indexable,
|
connector_type: connector.connector_type as EnumConnectorName,
|
||||||
last_indexed_at: connector.last_indexed_at,
|
config: updatedConfig,
|
||||||
|
is_indexable: connector.is_indexable,
|
||||||
|
last_indexed_at: connector.last_indexed_at,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
toast.success("Connector updated successfully!");
|
toast.success("Connector updated successfully!");
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, ExternalLink, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, ExternalLink, Loader2 } from "lucide-react";
|
||||||
import { motion } from "motion/react";
|
import { motion } from "motion/react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useParams, useRouter } from "next/navigation";
|
import { useParams, useRouter } from "next/navigation";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
import { connectorsAtom } from "@/atoms/connectors/connector-query.atoms";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
|
|
@ -18,11 +20,8 @@ import {
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
// import { IconBrandAirtable } from "@tabler/icons-react";
|
// import { IconBrandAirtable } from "@tabler/icons-react";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import {
|
|
||||||
type SearchSourceConnector,
|
|
||||||
useSearchSourceConnectors,
|
|
||||||
} from "@/hooks/use-search-source-connectors";
|
|
||||||
import { authenticatedFetch } from "@/lib/auth-utils";
|
import { authenticatedFetch } from "@/lib/auth-utils";
|
||||||
|
import { SearchSourceConnector } from "@/contracts/types/connector.types";
|
||||||
|
|
||||||
export default function AirtableConnectorPage() {
|
export default function AirtableConnectorPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -31,11 +30,12 @@ export default function AirtableConnectorPage() {
|
||||||
const [isConnecting, setIsConnecting] = useState(false);
|
const [isConnecting, setIsConnecting] = useState(false);
|
||||||
const [doesConnectorExist, setDoesConnectorExist] = useState(false);
|
const [doesConnectorExist, setDoesConnectorExist] = useState(false);
|
||||||
|
|
||||||
const { fetchConnectors } = useSearchSourceConnectors(true, parseInt(searchSpaceId));
|
const { refetch : fetchConnectors } = useAtomValue(connectorsAtom);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchConnectors(parseInt(searchSpaceId)).then((data) => {
|
fetchConnectors().then((data) => {
|
||||||
const connector = data.find(
|
const connectors = data.data || [];
|
||||||
|
const connector = connectors.find(
|
||||||
(c: SearchSourceConnector) => c.connector_type === EnumConnectorName.AIRTABLE_CONNECTOR
|
(c: SearchSourceConnector) => c.connector_type === EnumConnectorName.AIRTABLE_CONNECTOR
|
||||||
);
|
);
|
||||||
if (connector) {
|
if (connector) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, Info, Loader2 } 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";
|
||||||
|
|
@ -8,6 +9,7 @@ import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
|
|
@ -38,7 +40,6 @@ import {
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
// Define the form schema with Zod
|
// Define the form schema with Zod
|
||||||
const baiduSearchApiFormSchema = z.object({
|
const baiduSearchApiFormSchema = z.object({
|
||||||
|
|
@ -61,7 +62,7 @@ export default function BaiduSearchApiPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const searchSpaceId = params.search_space_id as string;
|
const searchSpaceId = params.search_space_id as string;
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const { createConnector } = useSearchSourceConnectors();
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
|
|
||||||
// Initialize the form
|
// Initialize the form
|
||||||
const form = useForm<BaiduSearchApiFormValues>({
|
const form = useForm<BaiduSearchApiFormValues>({
|
||||||
|
|
@ -95,8 +96,8 @@ export default function BaiduSearchApiPage() {
|
||||||
config.BAIDU_ENABLE_DEEP_SEARCH = values.enable_deep_search;
|
config.BAIDU_ENABLE_DEEP_SEARCH = values.enable_deep_search;
|
||||||
}
|
}
|
||||||
|
|
||||||
await createConnector(
|
await createConnector({
|
||||||
{
|
data: {
|
||||||
name: values.name,
|
name: values.name,
|
||||||
connector_type: EnumConnectorName.BAIDU_SEARCH_API,
|
connector_type: EnumConnectorName.BAIDU_SEARCH_API,
|
||||||
config,
|
config,
|
||||||
|
|
@ -106,8 +107,10 @@ export default function BaiduSearchApiPage() {
|
||||||
indexing_frequency_minutes: null,
|
indexing_frequency_minutes: null,
|
||||||
next_scheduled_at: null,
|
next_scheduled_at: null,
|
||||||
},
|
},
|
||||||
parseInt(searchSpaceId)
|
queryParams: {
|
||||||
);
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("Baidu Search connector created successfully!");
|
toast.success("Baidu Search connector created successfully!");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, Info, Loader2 } 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";
|
||||||
|
|
@ -8,6 +9,7 @@ import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
|
@ -24,7 +26,6 @@ import { Input } from "@/components/ui/input";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
// Define the form schema with Zod
|
// Define the form schema with Zod
|
||||||
const bookstackConnectorFormSchema = z.object({
|
const bookstackConnectorFormSchema = z.object({
|
||||||
|
|
@ -50,7 +51,7 @@ export default function BookStackConnectorPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const searchSpaceId = params.search_space_id as string;
|
const searchSpaceId = params.search_space_id as string;
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const { createConnector } = useSearchSourceConnectors();
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
|
|
||||||
// Initialize the form
|
// Initialize the form
|
||||||
const form = useForm<BookStackConnectorFormValues>({
|
const form = useForm<BookStackConnectorFormValues>({
|
||||||
|
|
@ -67,8 +68,8 @@ export default function BookStackConnectorPage() {
|
||||||
const onSubmit = async (values: BookStackConnectorFormValues) => {
|
const onSubmit = async (values: BookStackConnectorFormValues) => {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
try {
|
try {
|
||||||
await createConnector(
|
await createConnector({
|
||||||
{
|
data: {
|
||||||
name: values.name,
|
name: values.name,
|
||||||
connector_type: EnumConnectorName.BOOKSTACK_CONNECTOR,
|
connector_type: EnumConnectorName.BOOKSTACK_CONNECTOR,
|
||||||
config: {
|
config: {
|
||||||
|
|
@ -82,8 +83,10 @@ export default function BookStackConnectorPage() {
|
||||||
indexing_frequency_minutes: null,
|
indexing_frequency_minutes: null,
|
||||||
next_scheduled_at: null,
|
next_scheduled_at: null,
|
||||||
},
|
},
|
||||||
parseInt(searchSpaceId)
|
queryParams: {
|
||||||
);
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("BookStack connector created successfully!");
|
toast.success("BookStack connector created successfully!");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, ExternalLink, Eye, EyeOff } from "lucide-react";
|
import { ArrowLeft, ExternalLink, Eye, EyeOff } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useParams, useRouter } from "next/navigation";
|
import { useParams, useRouter } from "next/navigation";
|
||||||
|
|
@ -8,6 +9,7 @@ import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import {
|
import {
|
||||||
|
|
@ -22,7 +24,6 @@ import {
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
// Define the form schema with Zod
|
// Define the form schema with Zod
|
||||||
const clickupConnectorFormSchema = z.object({
|
const clickupConnectorFormSchema = z.object({
|
||||||
|
|
@ -41,7 +42,7 @@ export default function ClickUpConnectorPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const searchSpaceId = params.search_space_id as string;
|
const searchSpaceId = params.search_space_id as string;
|
||||||
const { createConnector } = useSearchSourceConnectors();
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [showApiToken, setShowApiToken] = useState(false);
|
const [showApiToken, setShowApiToken] = useState(false);
|
||||||
|
|
||||||
|
|
@ -59,20 +60,23 @@ export default function ClickUpConnectorPage() {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const connectorData = {
|
await createConnector({
|
||||||
name: values.name,
|
data: {
|
||||||
connector_type: EnumConnectorName.CLICKUP_CONNECTOR,
|
name: values.name,
|
||||||
is_indexable: true,
|
connector_type: EnumConnectorName.CLICKUP_CONNECTOR,
|
||||||
config: {
|
is_indexable: true,
|
||||||
CLICKUP_API_TOKEN: values.api_token,
|
config: {
|
||||||
|
CLICKUP_API_TOKEN: values.api_token,
|
||||||
|
},
|
||||||
|
last_indexed_at: null,
|
||||||
|
periodic_indexing_enabled: false,
|
||||||
|
indexing_frequency_minutes: null,
|
||||||
|
next_scheduled_at: null,
|
||||||
},
|
},
|
||||||
last_indexed_at: null,
|
queryParams: {
|
||||||
periodic_indexing_enabled: false,
|
search_space_id: searchSpaceId,
|
||||||
indexing_frequency_minutes: null,
|
},
|
||||||
next_scheduled_at: null,
|
});
|
||||||
};
|
|
||||||
|
|
||||||
await createConnector(connectorData, parseInt(searchSpaceId));
|
|
||||||
|
|
||||||
toast.success("ClickUp connector created successfully!");
|
toast.success("ClickUp connector created successfully!");
|
||||||
router.push(`/dashboard/${searchSpaceId}/connectors`);
|
router.push(`/dashboard/${searchSpaceId}/connectors`);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, Info, Loader2 } 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";
|
||||||
|
|
@ -8,6 +9,7 @@ import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
|
@ -24,7 +26,6 @@ import { Input } from "@/components/ui/input";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
// Define the form schema with Zod
|
// Define the form schema with Zod
|
||||||
const confluenceConnectorFormSchema = z.object({
|
const confluenceConnectorFormSchema = z.object({
|
||||||
|
|
@ -60,7 +61,7 @@ export default function ConfluenceConnectorPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const searchSpaceId = params.search_space_id as string;
|
const searchSpaceId = params.search_space_id as string;
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const { createConnector } = useSearchSourceConnectors();
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
|
|
||||||
// Initialize the form
|
// Initialize the form
|
||||||
const form = useForm<ConfluenceConnectorFormValues>({
|
const form = useForm<ConfluenceConnectorFormValues>({
|
||||||
|
|
@ -77,8 +78,8 @@ export default function ConfluenceConnectorPage() {
|
||||||
const onSubmit = async (values: ConfluenceConnectorFormValues) => {
|
const onSubmit = async (values: ConfluenceConnectorFormValues) => {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
try {
|
try {
|
||||||
await createConnector(
|
await createConnector({
|
||||||
{
|
data: {
|
||||||
name: values.name,
|
name: values.name,
|
||||||
connector_type: EnumConnectorName.CONFLUENCE_CONNECTOR,
|
connector_type: EnumConnectorName.CONFLUENCE_CONNECTOR,
|
||||||
config: {
|
config: {
|
||||||
|
|
@ -92,8 +93,10 @@ export default function ConfluenceConnectorPage() {
|
||||||
indexing_frequency_minutes: null,
|
indexing_frequency_minutes: null,
|
||||||
next_scheduled_at: null,
|
next_scheduled_at: null,
|
||||||
},
|
},
|
||||||
parseInt(searchSpaceId)
|
queryParams: {
|
||||||
);
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("Confluence connector created successfully!");
|
toast.success("Confluence connector created successfully!");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, Info, Loader2 } 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";
|
||||||
|
|
@ -8,6 +9,7 @@ import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionContent,
|
AccordionContent,
|
||||||
|
|
@ -37,7 +39,6 @@ import { Input } from "@/components/ui/input";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
// Define the form schema with Zod
|
// Define the form schema with Zod
|
||||||
const discordConnectorFormSchema = z.object({
|
const discordConnectorFormSchema = z.object({
|
||||||
|
|
@ -58,7 +59,7 @@ export default function DiscordConnectorPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const searchSpaceId = params.search_space_id as string;
|
const searchSpaceId = params.search_space_id as string;
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const { createConnector } = useSearchSourceConnectors();
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
|
|
||||||
// Initialize the form
|
// Initialize the form
|
||||||
const form = useForm<DiscordConnectorFormValues>({
|
const form = useForm<DiscordConnectorFormValues>({
|
||||||
|
|
@ -73,8 +74,8 @@ export default function DiscordConnectorPage() {
|
||||||
const onSubmit = async (values: DiscordConnectorFormValues) => {
|
const onSubmit = async (values: DiscordConnectorFormValues) => {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
try {
|
try {
|
||||||
await createConnector(
|
await createConnector({
|
||||||
{
|
data: {
|
||||||
name: values.name,
|
name: values.name,
|
||||||
connector_type: EnumConnectorName.DISCORD_CONNECTOR,
|
connector_type: EnumConnectorName.DISCORD_CONNECTOR,
|
||||||
config: {
|
config: {
|
||||||
|
|
@ -86,8 +87,10 @@ export default function DiscordConnectorPage() {
|
||||||
indexing_frequency_minutes: null,
|
indexing_frequency_minutes: null,
|
||||||
next_scheduled_at: null,
|
next_scheduled_at: null,
|
||||||
},
|
},
|
||||||
parseInt(searchSpaceId)
|
queryParams: {
|
||||||
);
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("Discord connector created successfully!");
|
toast.success("Discord connector created successfully!");
|
||||||
router.push(`/dashboard/${searchSpaceId}/connectors`);
|
router.push(`/dashboard/${searchSpaceId}/connectors`);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import * as RadioGroup from "@radix-ui/react-radio-group";
|
import * as RadioGroup from "@radix-ui/react-radio-group";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
|
||||||
import { motion } from "motion/react";
|
import { motion } from "motion/react";
|
||||||
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
||||||
|
|
@ -9,7 +10,7 @@ import { useId, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionContent,
|
AccordionContent,
|
||||||
|
|
@ -40,10 +41,8 @@ import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
// Define the form schema with Zod
|
// Define the form schema with Zod
|
||||||
const elasticsearchConnectorFormSchema = z
|
const elasticsearchConnectorFormSchema = z
|
||||||
|
|
@ -91,7 +90,7 @@ export default function ElasticsearchConnectorPage() {
|
||||||
const authBasicId = useId();
|
const authBasicId = useId();
|
||||||
const authApiKeyId = useId();
|
const authApiKeyId = useId();
|
||||||
|
|
||||||
const { createConnector } = useSearchSourceConnectors();
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
|
|
||||||
// Initialize the form
|
// Initialize the form
|
||||||
const form = useForm<ElasticsearchConnectorFormValues>({
|
const form = useForm<ElasticsearchConnectorFormValues>({
|
||||||
|
|
@ -173,19 +172,21 @@ export default function ElasticsearchConnectorPage() {
|
||||||
config.ELASTICSEARCH_MAX_DOCUMENTS = values.max_documents;
|
config.ELASTICSEARCH_MAX_DOCUMENTS = values.max_documents;
|
||||||
}
|
}
|
||||||
|
|
||||||
const connectorPayload = {
|
await createConnector({
|
||||||
name: values.name,
|
data: {
|
||||||
connector_type: EnumConnectorName.ELASTICSEARCH_CONNECTOR,
|
name: values.name,
|
||||||
is_indexable: true,
|
connector_type: EnumConnectorName.ELASTICSEARCH_CONNECTOR,
|
||||||
last_indexed_at: null,
|
is_indexable: true,
|
||||||
periodic_indexing_enabled: false,
|
last_indexed_at: null,
|
||||||
indexing_frequency_minutes: null,
|
periodic_indexing_enabled: false,
|
||||||
next_scheduled_at: null,
|
indexing_frequency_minutes: null,
|
||||||
config,
|
next_scheduled_at: null,
|
||||||
};
|
config,
|
||||||
|
},
|
||||||
// Use existing hook method
|
queryParams: {
|
||||||
await createConnector(connectorPayload, searchSpaceIdNum);
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("Elasticsearch connector created successfully!");
|
toast.success("Elasticsearch connector created successfully!");
|
||||||
router.push(`/dashboard/${searchSpaceId}/connectors`);
|
router.push(`/dashboard/${searchSpaceId}/connectors`);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, CircleAlert, Github, Info, ListChecks, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, CircleAlert, Github, Info, ListChecks, Loader2 } 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";
|
||||||
|
|
@ -8,6 +9,7 @@ import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionContent,
|
AccordionContent,
|
||||||
|
|
@ -38,8 +40,6 @@ import { Input } from "@/components/ui/input";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
// Assuming useSearchSourceConnectors hook exists and works similarly
|
|
||||||
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
|
|
||||||
import { authenticatedFetch, redirectToLogin } from "@/lib/auth-utils";
|
import { authenticatedFetch, redirectToLogin } from "@/lib/auth-utils";
|
||||||
|
|
||||||
// Define the form schema with Zod for GitHub PAT entry step
|
// Define the form schema with Zod for GitHub PAT entry step
|
||||||
|
|
@ -85,7 +85,7 @@ export default function GithubConnectorPage() {
|
||||||
const [connectorName, setConnectorName] = useState<string>("GitHub Connector");
|
const [connectorName, setConnectorName] = useState<string>("GitHub Connector");
|
||||||
const [validatedPat, setValidatedPat] = useState<string>(""); // Store the validated PAT
|
const [validatedPat, setValidatedPat] = useState<string>(""); // Store the validated PAT
|
||||||
|
|
||||||
const { createConnector } = useSearchSourceConnectors();
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
|
|
||||||
// Initialize the form for PAT entry
|
// Initialize the form for PAT entry
|
||||||
const form = useForm<GithubPatFormValues>({
|
const form = useForm<GithubPatFormValues>({
|
||||||
|
|
@ -141,8 +141,8 @@ export default function GithubConnectorPage() {
|
||||||
|
|
||||||
setIsCreatingConnector(true);
|
setIsCreatingConnector(true);
|
||||||
try {
|
try {
|
||||||
await createConnector(
|
await createConnector({
|
||||||
{
|
data: {
|
||||||
name: connectorName, // Use the stored name
|
name: connectorName, // Use the stored name
|
||||||
connector_type: EnumConnectorName.GITHUB_CONNECTOR,
|
connector_type: EnumConnectorName.GITHUB_CONNECTOR,
|
||||||
config: {
|
config: {
|
||||||
|
|
@ -155,8 +155,10 @@ export default function GithubConnectorPage() {
|
||||||
indexing_frequency_minutes: null,
|
indexing_frequency_minutes: null,
|
||||||
next_scheduled_at: null,
|
next_scheduled_at: null,
|
||||||
},
|
},
|
||||||
parseInt(searchSpaceId)
|
queryParams: {
|
||||||
);
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("GitHub connector created successfully!");
|
toast.success("GitHub connector created successfully!");
|
||||||
router.push(`/dashboard/${searchSpaceId}/connectors`);
|
router.push(`/dashboard/${searchSpaceId}/connectors`);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, ExternalLink, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, ExternalLink, Loader2 } from "lucide-react";
|
||||||
import { motion } from "motion/react";
|
import { motion } from "motion/react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
@ -9,6 +10,7 @@ import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { connectorsAtom } from "@/atoms/connectors/connector-query.atoms";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
|
|
@ -20,11 +22,8 @@ import {
|
||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import {
|
|
||||||
type SearchSourceConnector,
|
|
||||||
useSearchSourceConnectors,
|
|
||||||
} from "@/hooks/use-search-source-connectors";
|
|
||||||
import { authenticatedFetch } from "@/lib/auth-utils";
|
import { authenticatedFetch } from "@/lib/auth-utils";
|
||||||
|
import { SearchSourceConnector } from "@/contracts/types/connector.types";
|
||||||
|
|
||||||
export default function GoogleCalendarConnectorPage() {
|
export default function GoogleCalendarConnectorPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -33,13 +32,13 @@ export default function GoogleCalendarConnectorPage() {
|
||||||
const [isConnecting, setIsConnecting] = useState(false);
|
const [isConnecting, setIsConnecting] = useState(false);
|
||||||
const [doesConnectorExist, setDoesConnectorExist] = useState(false);
|
const [doesConnectorExist, setDoesConnectorExist] = useState(false);
|
||||||
|
|
||||||
const { fetchConnectors } = useSearchSourceConnectors(true, parseInt(searchSpaceId));
|
const { refetch : fetchConnectors } = useAtomValue(connectorsAtom);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchConnectors(parseInt(searchSpaceId)).then((data) => {
|
fetchConnectors().then((data) => {
|
||||||
const connector = data.find(
|
const connectors = data.data || [];
|
||||||
(c: SearchSourceConnector) =>
|
const connector = connectors.find(
|
||||||
c.connector_type === EnumConnectorName.GOOGLE_CALENDAR_CONNECTOR
|
(c: SearchSourceConnector) => c.connector_type === EnumConnectorName.GOOGLE_CALENDAR_CONNECTOR
|
||||||
);
|
);
|
||||||
if (connector) {
|
if (connector) {
|
||||||
setDoesConnectorExist(true);
|
setDoesConnectorExist(true);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, ExternalLink, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, ExternalLink, Loader2 } from "lucide-react";
|
||||||
import { motion } from "motion/react";
|
import { motion } from "motion/react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
@ -9,6 +10,7 @@ import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { connectorsAtom } from "@/atoms/connectors/connector-query.atoms";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
|
|
@ -20,11 +22,8 @@ import {
|
||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import {
|
|
||||||
type SearchSourceConnector,
|
|
||||||
useSearchSourceConnectors,
|
|
||||||
} from "@/hooks/use-search-source-connectors";
|
|
||||||
import { authenticatedFetch } from "@/lib/auth-utils";
|
import { authenticatedFetch } from "@/lib/auth-utils";
|
||||||
|
import { SearchSourceConnector } from "@/contracts/types/connector.types";
|
||||||
|
|
||||||
export default function GoogleGmailConnectorPage() {
|
export default function GoogleGmailConnectorPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -33,11 +32,12 @@ export default function GoogleGmailConnectorPage() {
|
||||||
const [isConnecting, setIsConnecting] = useState(false);
|
const [isConnecting, setIsConnecting] = useState(false);
|
||||||
const [doesConnectorExist, setDoesConnectorExist] = useState(false);
|
const [doesConnectorExist, setDoesConnectorExist] = useState(false);
|
||||||
|
|
||||||
const { fetchConnectors } = useSearchSourceConnectors(true, parseInt(searchSpaceId));
|
const { refetch : fetchConnectors } = useAtomValue(connectorsAtom);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchConnectors(parseInt(searchSpaceId)).then((data) => {
|
fetchConnectors().then((data) => {
|
||||||
const connector = data.find(
|
const connectors = data.data || [];
|
||||||
|
const connector = connectors.find(
|
||||||
(c: SearchSourceConnector) => c.connector_type === EnumConnectorName.GOOGLE_GMAIL_CONNECTOR
|
(c: SearchSourceConnector) => c.connector_type === EnumConnectorName.GOOGLE_GMAIL_CONNECTOR
|
||||||
);
|
);
|
||||||
if (connector) {
|
if (connector) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, Info, Loader2 } 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";
|
||||||
|
|
@ -8,6 +9,7 @@ import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionContent,
|
AccordionContent,
|
||||||
|
|
@ -37,7 +39,6 @@ import { Input } from "@/components/ui/input";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
// Define the form schema with Zod
|
// Define the form schema with Zod
|
||||||
const jiraConnectorFormSchema = z.object({
|
const jiraConnectorFormSchema = z.object({
|
||||||
|
|
@ -73,7 +74,7 @@ export default function JiraConnectorPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const searchSpaceId = params.search_space_id as string;
|
const searchSpaceId = params.search_space_id as string;
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const { createConnector } = useSearchSourceConnectors();
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
|
|
||||||
// Initialize the form
|
// Initialize the form
|
||||||
const form = useForm<JiraConnectorFormValues>({
|
const form = useForm<JiraConnectorFormValues>({
|
||||||
|
|
@ -90,8 +91,8 @@ export default function JiraConnectorPage() {
|
||||||
const onSubmit = async (values: JiraConnectorFormValues) => {
|
const onSubmit = async (values: JiraConnectorFormValues) => {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
try {
|
try {
|
||||||
await createConnector(
|
await createConnector({
|
||||||
{
|
data: {
|
||||||
name: values.name,
|
name: values.name,
|
||||||
connector_type: EnumConnectorName.JIRA_CONNECTOR,
|
connector_type: EnumConnectorName.JIRA_CONNECTOR,
|
||||||
config: {
|
config: {
|
||||||
|
|
@ -105,8 +106,10 @@ export default function JiraConnectorPage() {
|
||||||
indexing_frequency_minutes: null,
|
indexing_frequency_minutes: null,
|
||||||
next_scheduled_at: null,
|
next_scheduled_at: null,
|
||||||
},
|
},
|
||||||
parseInt(searchSpaceId)
|
queryParams: {
|
||||||
);
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("Jira connector created successfully!");
|
toast.success("Jira connector created successfully!");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, Info, Loader2 } 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";
|
||||||
|
|
@ -8,6 +9,7 @@ import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionContent,
|
AccordionContent,
|
||||||
|
|
@ -37,7 +39,6 @@ import { Input } from "@/components/ui/input";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
// Define the form schema with Zod
|
// Define the form schema with Zod
|
||||||
const linearConnectorFormSchema = z.object({
|
const linearConnectorFormSchema = z.object({
|
||||||
|
|
@ -62,7 +63,7 @@ export default function LinearConnectorPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const searchSpaceId = params.search_space_id as string;
|
const searchSpaceId = params.search_space_id as string;
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const { createConnector } = useSearchSourceConnectors();
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
|
|
||||||
// Initialize the form
|
// Initialize the form
|
||||||
const form = useForm<LinearConnectorFormValues>({
|
const form = useForm<LinearConnectorFormValues>({
|
||||||
|
|
@ -77,8 +78,8 @@ export default function LinearConnectorPage() {
|
||||||
const onSubmit = async (values: LinearConnectorFormValues) => {
|
const onSubmit = async (values: LinearConnectorFormValues) => {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
try {
|
try {
|
||||||
await createConnector(
|
await createConnector({
|
||||||
{
|
data: {
|
||||||
name: values.name,
|
name: values.name,
|
||||||
connector_type: EnumConnectorName.LINEAR_CONNECTOR,
|
connector_type: EnumConnectorName.LINEAR_CONNECTOR,
|
||||||
config: {
|
config: {
|
||||||
|
|
@ -90,8 +91,10 @@ export default function LinearConnectorPage() {
|
||||||
indexing_frequency_minutes: null,
|
indexing_frequency_minutes: null,
|
||||||
next_scheduled_at: null,
|
next_scheduled_at: null,
|
||||||
},
|
},
|
||||||
parseInt(searchSpaceId)
|
queryParams: {
|
||||||
);
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("Linear connector created successfully!");
|
toast.success("Linear connector created successfully!");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, Info, Loader2 } 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";
|
||||||
|
|
@ -8,6 +9,7 @@ import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
|
|
@ -30,7 +32,6 @@ import {
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
// Define the form schema with Zod
|
// Define the form schema with Zod
|
||||||
const linkupApiFormSchema = z.object({
|
const linkupApiFormSchema = z.object({
|
||||||
|
|
@ -50,7 +51,7 @@ export default function LinkupApiPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const searchSpaceId = params.search_space_id as string;
|
const searchSpaceId = params.search_space_id as string;
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const { createConnector } = useSearchSourceConnectors();
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
|
|
||||||
// Initialize the form
|
// Initialize the form
|
||||||
const form = useForm<LinkupApiFormValues>({
|
const form = useForm<LinkupApiFormValues>({
|
||||||
|
|
@ -65,8 +66,8 @@ export default function LinkupApiPage() {
|
||||||
const onSubmit = async (values: LinkupApiFormValues) => {
|
const onSubmit = async (values: LinkupApiFormValues) => {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
try {
|
try {
|
||||||
await createConnector(
|
await createConnector({
|
||||||
{
|
data: {
|
||||||
name: values.name,
|
name: values.name,
|
||||||
connector_type: EnumConnectorName.LINKUP_API,
|
connector_type: EnumConnectorName.LINKUP_API,
|
||||||
config: {
|
config: {
|
||||||
|
|
@ -78,8 +79,10 @@ export default function LinkupApiPage() {
|
||||||
indexing_frequency_minutes: null,
|
indexing_frequency_minutes: null,
|
||||||
next_scheduled_at: null,
|
next_scheduled_at: null,
|
||||||
},
|
},
|
||||||
parseInt(searchSpaceId)
|
queryParams: {
|
||||||
);
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("Linkup API connector created successfully!");
|
toast.success("Linkup API connector created successfully!");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, Key, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, Key, Loader2 } from "lucide-react";
|
||||||
import { motion } from "motion/react";
|
import { motion } from "motion/react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
@ -9,6 +10,8 @@ import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
|
import { connectorsAtom } from "@/atoms/connectors/connector-query.atoms";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
|
|
@ -30,10 +33,7 @@ import {
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import {
|
import { SearchSourceConnector } from "@/contracts/types/connector.types";
|
||||||
type SearchSourceConnector,
|
|
||||||
useSearchSourceConnectors,
|
|
||||||
} from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
// Define the form schema with Zod
|
// Define the form schema with Zod
|
||||||
const lumaConnectorFormSchema = z.object({
|
const lumaConnectorFormSchema = z.object({
|
||||||
|
|
@ -55,10 +55,8 @@ export default function LumaConnectorPage() {
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const [doesConnectorExist, setDoesConnectorExist] = useState(false);
|
const [doesConnectorExist, setDoesConnectorExist] = useState(false);
|
||||||
|
|
||||||
const { fetchConnectors, createConnector } = useSearchSourceConnectors(
|
const { data: connectors } = useAtomValue(connectorsAtom);
|
||||||
true,
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
parseInt(searchSpaceId)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Initialize the form
|
// Initialize the form
|
||||||
const form = useForm<LumaConnectorFormValues>({
|
const form = useForm<LumaConnectorFormValues>({
|
||||||
|
|
@ -69,29 +67,26 @@ export default function LumaConnectorPage() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { refetch : fetchConnectors } = useAtomValue(connectorsAtom);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchConnectors(parseInt(searchSpaceId))
|
fetchConnectors().then((data) => {
|
||||||
.then((data) => {
|
const connectors = data.data || [];
|
||||||
if (data && Array.isArray(data)) {
|
const connector = connectors.find(
|
||||||
const connector = data.find(
|
(c: SearchSourceConnector) => c.connector_type === EnumConnectorName.LUMA_CONNECTOR
|
||||||
(c: SearchSourceConnector) => c.connector_type === EnumConnectorName.LUMA_CONNECTOR
|
);
|
||||||
);
|
if (connector) {
|
||||||
if (connector) {
|
setDoesConnectorExist(true);
|
||||||
setDoesConnectorExist(true);
|
}
|
||||||
}
|
});
|
||||||
}
|
}, []);
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error fetching connectors:", error);
|
|
||||||
});
|
|
||||||
}, [fetchConnectors, searchSpaceId]);
|
|
||||||
|
|
||||||
// Handle form submission
|
// Handle form submission
|
||||||
const onSubmit = async (values: LumaConnectorFormValues) => {
|
const onSubmit = async (values: LumaConnectorFormValues) => {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
try {
|
try {
|
||||||
await createConnector(
|
await createConnector({
|
||||||
{
|
data: {
|
||||||
name: values.name,
|
name: values.name,
|
||||||
connector_type: EnumConnectorName.LUMA_CONNECTOR,
|
connector_type: EnumConnectorName.LUMA_CONNECTOR,
|
||||||
config: {
|
config: {
|
||||||
|
|
@ -103,8 +98,10 @@ export default function LumaConnectorPage() {
|
||||||
indexing_frequency_minutes: null,
|
indexing_frequency_minutes: null,
|
||||||
next_scheduled_at: null,
|
next_scheduled_at: null,
|
||||||
},
|
},
|
||||||
parseInt(searchSpaceId)
|
queryParams: {
|
||||||
);
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("Luma connector created successfully!");
|
toast.success("Luma connector created successfully!");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, Info, Loader2 } 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";
|
||||||
|
|
@ -8,6 +9,7 @@ import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionContent,
|
AccordionContent,
|
||||||
|
|
@ -37,7 +39,6 @@ import { Input } from "@/components/ui/input";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
// Define the form schema with Zod
|
// Define the form schema with Zod
|
||||||
const notionConnectorFormSchema = z.object({
|
const notionConnectorFormSchema = z.object({
|
||||||
|
|
@ -57,7 +58,7 @@ export default function NotionConnectorPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const searchSpaceId = params.search_space_id as string;
|
const searchSpaceId = params.search_space_id as string;
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const { createConnector } = useSearchSourceConnectors();
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
|
|
||||||
// Initialize the form
|
// Initialize the form
|
||||||
const form = useForm<NotionConnectorFormValues>({
|
const form = useForm<NotionConnectorFormValues>({
|
||||||
|
|
@ -72,8 +73,8 @@ export default function NotionConnectorPage() {
|
||||||
const onSubmit = async (values: NotionConnectorFormValues) => {
|
const onSubmit = async (values: NotionConnectorFormValues) => {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
try {
|
try {
|
||||||
await createConnector(
|
await createConnector({
|
||||||
{
|
data: {
|
||||||
name: values.name,
|
name: values.name,
|
||||||
connector_type: EnumConnectorName.NOTION_CONNECTOR,
|
connector_type: EnumConnectorName.NOTION_CONNECTOR,
|
||||||
config: {
|
config: {
|
||||||
|
|
@ -85,8 +86,10 @@ export default function NotionConnectorPage() {
|
||||||
indexing_frequency_minutes: null,
|
indexing_frequency_minutes: null,
|
||||||
next_scheduled_at: null,
|
next_scheduled_at: null,
|
||||||
},
|
},
|
||||||
parseInt(searchSpaceId)
|
queryParams: {
|
||||||
);
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("Notion connector created successfully!");
|
toast.success("Notion connector created successfully!");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, Info, Loader2 } 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";
|
||||||
|
|
@ -8,6 +9,7 @@ import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
|
|
@ -31,7 +33,6 @@ import { Input } from "@/components/ui/input";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
const searxngFormSchema = z.object({
|
const searxngFormSchema = z.object({
|
||||||
name: z.string().min(3, {
|
name: z.string().min(3, {
|
||||||
|
|
@ -67,7 +68,7 @@ export default function SearxngConnectorPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const searchSpaceId = params.search_space_id as string;
|
const searchSpaceId = params.search_space_id as string;
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const { createConnector } = useSearchSourceConnectors();
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
|
|
||||||
const form = useForm<SearxngFormValues>({
|
const form = useForm<SearxngFormValues>({
|
||||||
resolver: zodResolver(searxngFormSchema),
|
resolver: zodResolver(searxngFormSchema),
|
||||||
|
|
@ -115,8 +116,8 @@ export default function SearxngConnectorPage() {
|
||||||
config.SEARXNG_VERIFY_SSL = false;
|
config.SEARXNG_VERIFY_SSL = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
await createConnector(
|
await createConnector({
|
||||||
{
|
data: {
|
||||||
name: values.name,
|
name: values.name,
|
||||||
connector_type: EnumConnectorName.SEARXNG_API,
|
connector_type: EnumConnectorName.SEARXNG_API,
|
||||||
config,
|
config,
|
||||||
|
|
@ -126,8 +127,10 @@ export default function SearxngConnectorPage() {
|
||||||
indexing_frequency_minutes: null,
|
indexing_frequency_minutes: null,
|
||||||
next_scheduled_at: null,
|
next_scheduled_at: null,
|
||||||
},
|
},
|
||||||
parseInt(searchSpaceId)
|
queryParams: {
|
||||||
);
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("SearxNG connector created successfully!");
|
toast.success("SearxNG connector created successfully!");
|
||||||
router.push(`/dashboard/${searchSpaceId}/connectors`);
|
router.push(`/dashboard/${searchSpaceId}/connectors`);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, Info, Loader2 } 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";
|
||||||
|
|
@ -8,6 +9,7 @@ import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionContent,
|
AccordionContent,
|
||||||
|
|
@ -37,7 +39,6 @@ import { Input } from "@/components/ui/input";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
// Define the form schema with Zod
|
// Define the form schema with Zod
|
||||||
const slackConnectorFormSchema = z.object({
|
const slackConnectorFormSchema = z.object({
|
||||||
|
|
@ -57,7 +58,7 @@ export default function SlackConnectorPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const searchSpaceId = params.search_space_id as string;
|
const searchSpaceId = params.search_space_id as string;
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const { createConnector } = useSearchSourceConnectors();
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
|
|
||||||
// Initialize the form
|
// Initialize the form
|
||||||
const form = useForm<SlackConnectorFormValues>({
|
const form = useForm<SlackConnectorFormValues>({
|
||||||
|
|
@ -72,8 +73,8 @@ export default function SlackConnectorPage() {
|
||||||
const onSubmit = async (values: SlackConnectorFormValues) => {
|
const onSubmit = async (values: SlackConnectorFormValues) => {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
try {
|
try {
|
||||||
await createConnector(
|
await createConnector({
|
||||||
{
|
data: {
|
||||||
name: values.name,
|
name: values.name,
|
||||||
connector_type: EnumConnectorName.SLACK_CONNECTOR,
|
connector_type: EnumConnectorName.SLACK_CONNECTOR,
|
||||||
config: {
|
config: {
|
||||||
|
|
@ -85,8 +86,10 @@ export default function SlackConnectorPage() {
|
||||||
indexing_frequency_minutes: null,
|
indexing_frequency_minutes: null,
|
||||||
next_scheduled_at: null,
|
next_scheduled_at: null,
|
||||||
},
|
},
|
||||||
parseInt(searchSpaceId)
|
queryParams: {
|
||||||
);
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("Slack connector created successfully!");
|
toast.success("Slack connector created successfully!");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, Info, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, Info, Loader2 } 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";
|
||||||
|
|
@ -8,6 +9,7 @@ import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
|
|
@ -30,7 +32,6 @@ import {
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import { useSearchSourceConnectors } from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
// Define the form schema with Zod
|
// Define the form schema with Zod
|
||||||
const tavilyApiFormSchema = z.object({
|
const tavilyApiFormSchema = z.object({
|
||||||
|
|
@ -50,7 +51,7 @@ export default function TavilyApiPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const searchSpaceId = params.search_space_id as string;
|
const searchSpaceId = params.search_space_id as string;
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const { createConnector } = useSearchSourceConnectors();
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
|
|
||||||
// Initialize the form
|
// Initialize the form
|
||||||
const form = useForm<TavilyApiFormValues>({
|
const form = useForm<TavilyApiFormValues>({
|
||||||
|
|
@ -65,8 +66,8 @@ export default function TavilyApiPage() {
|
||||||
const onSubmit = async (values: TavilyApiFormValues) => {
|
const onSubmit = async (values: TavilyApiFormValues) => {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
try {
|
try {
|
||||||
await createConnector(
|
await createConnector({
|
||||||
{
|
data: {
|
||||||
name: values.name,
|
name: values.name,
|
||||||
connector_type: EnumConnectorName.TAVILY_API,
|
connector_type: EnumConnectorName.TAVILY_API,
|
||||||
config: {
|
config: {
|
||||||
|
|
@ -78,8 +79,10 @@ export default function TavilyApiPage() {
|
||||||
indexing_frequency_minutes: null,
|
indexing_frequency_minutes: null,
|
||||||
next_scheduled_at: null,
|
next_scheduled_at: null,
|
||||||
},
|
},
|
||||||
parseInt(searchSpaceId)
|
queryParams: {
|
||||||
);
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("Tavily API connector created successfully!");
|
toast.success("Tavily API connector created successfully!");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { ArrowLeft, Check, Globe, Loader2 } from "lucide-react";
|
import { ArrowLeft, Check, Globe, Loader2 } from "lucide-react";
|
||||||
import { motion } from "motion/react";
|
import { motion } from "motion/react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
@ -9,6 +10,8 @@ import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
import { createConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
|
import { connectorsAtom } from "@/atoms/connectors/connector-query.atoms";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
|
|
@ -31,10 +34,7 @@ import { Input } from "@/components/ui/input";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import { EnumConnectorName } from "@/contracts/enums/connector";
|
import { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
|
||||||
import {
|
import { SearchSourceConnector } from "@/contracts/types/connector.types";
|
||||||
type SearchSourceConnector,
|
|
||||||
useSearchSourceConnectors,
|
|
||||||
} from "@/hooks/use-search-source-connectors";
|
|
||||||
|
|
||||||
// Define the form schema with Zod
|
// Define the form schema with Zod
|
||||||
const webcrawlerConnectorFormSchema = z.object({
|
const webcrawlerConnectorFormSchema = z.object({
|
||||||
|
|
@ -55,10 +55,8 @@ export default function WebcrawlerConnectorPage() {
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const [doesConnectorExist, setDoesConnectorExist] = useState(false);
|
const [doesConnectorExist, setDoesConnectorExist] = useState(false);
|
||||||
|
|
||||||
const { fetchConnectors, createConnector } = useSearchSourceConnectors(
|
const { refetch : fetchConnectors } = useAtomValue(connectorsAtom);
|
||||||
true,
|
const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom);
|
||||||
parseInt(searchSpaceId)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Initialize the form
|
// Initialize the form
|
||||||
const form = useForm<WebcrawlerConnectorFormValues>({
|
const form = useForm<WebcrawlerConnectorFormValues>({
|
||||||
|
|
@ -71,22 +69,16 @@ export default function WebcrawlerConnectorPage() {
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchConnectors(parseInt(searchSpaceId))
|
fetchConnectors().then((data) => {
|
||||||
.then((data) => {
|
const connectors = data.data || [];
|
||||||
if (data && Array.isArray(data)) {
|
const connector = connectors.find(
|
||||||
const connector = data.find(
|
(c: SearchSourceConnector) => c.connector_type === EnumConnectorName.WEBCRAWLER_CONNECTOR
|
||||||
(c: SearchSourceConnector) =>
|
);
|
||||||
c.connector_type === EnumConnectorName.WEBCRAWLER_CONNECTOR
|
if (connector) {
|
||||||
);
|
setDoesConnectorExist(true);
|
||||||
if (connector) {
|
}
|
||||||
setDoesConnectorExist(true);
|
});
|
||||||
}
|
}, []);
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error fetching connectors:", error);
|
|
||||||
});
|
|
||||||
}, [fetchConnectors, searchSpaceId]);
|
|
||||||
|
|
||||||
// Handle form submission
|
// Handle form submission
|
||||||
const onSubmit = async (values: WebcrawlerConnectorFormValues) => {
|
const onSubmit = async (values: WebcrawlerConnectorFormValues) => {
|
||||||
|
|
@ -104,8 +96,8 @@ export default function WebcrawlerConnectorPage() {
|
||||||
config.INITIAL_URLS = values.initial_urls;
|
config.INITIAL_URLS = values.initial_urls;
|
||||||
}
|
}
|
||||||
|
|
||||||
await createConnector(
|
await createConnector({
|
||||||
{
|
data: {
|
||||||
name: values.name,
|
name: values.name,
|
||||||
connector_type: EnumConnectorName.WEBCRAWLER_CONNECTOR,
|
connector_type: EnumConnectorName.WEBCRAWLER_CONNECTOR,
|
||||||
config: config,
|
config: config,
|
||||||
|
|
@ -115,8 +107,10 @@ export default function WebcrawlerConnectorPage() {
|
||||||
indexing_frequency_minutes: null,
|
indexing_frequency_minutes: null,
|
||||||
next_scheduled_at: null,
|
next_scheduled_at: null,
|
||||||
},
|
},
|
||||||
parseInt(searchSpaceId)
|
queryParams: {
|
||||||
);
|
search_space_id: searchSpaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("Webcrawler connector created successfully!");
|
toast.success("Webcrawler connector created successfully!");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import {
|
||||||
useReactTable,
|
useReactTable,
|
||||||
type VisibilityState,
|
type VisibilityState,
|
||||||
} from "@tanstack/react-table";
|
} from "@tanstack/react-table";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import {
|
import {
|
||||||
Activity,
|
Activity,
|
||||||
AlertCircle,
|
AlertCircle,
|
||||||
|
|
@ -44,8 +45,13 @@ import {
|
||||||
import { AnimatePresence, motion, type Variants } from "motion/react";
|
import { AnimatePresence, motion, type Variants } from "motion/react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import React, { useContext, useId, useMemo, useRef, useState } from "react";
|
import React, { useCallback, useContext, useId, useMemo, useRef, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
import {
|
||||||
|
createLogMutationAtom,
|
||||||
|
deleteLogMutationAtom,
|
||||||
|
updateLogMutationAtom,
|
||||||
|
} from "@/atoms/logs/log-mutation.atoms";
|
||||||
import { JsonMetadataViewer } from "@/components/json-metadata-viewer";
|
import { JsonMetadataViewer } from "@/components/json-metadata-viewer";
|
||||||
import {
|
import {
|
||||||
AlertDialog,
|
AlertDialog,
|
||||||
|
|
@ -89,7 +95,8 @@ import {
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import { type Log, type LogLevel, type LogStatus, useLogs, useLogsSummary } from "@/hooks/use-logs";
|
import type { CreateLogRequest, Log, UpdateLogRequest } from "@/contracts/types/log.types";
|
||||||
|
import { type LogLevel, type LogStatus, useLogs, useLogsSummary } from "@/hooks/use-logs";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
// Define animation variants for reuse
|
// Define animation variants for reuse
|
||||||
|
|
@ -334,13 +341,50 @@ export default function LogsManagePage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const searchSpaceId = Number(params.search_space_id);
|
const searchSpaceId = Number(params.search_space_id);
|
||||||
|
|
||||||
const {
|
const { mutateAsync: deleteLogMutation } = useAtomValue(deleteLogMutationAtom);
|
||||||
logs,
|
const { mutateAsync: updateLogMutation } = useAtomValue(updateLogMutationAtom);
|
||||||
loading: logsLoading,
|
const { mutateAsync: createLogMutation } = useAtomValue(createLogMutationAtom);
|
||||||
error: logsError,
|
|
||||||
refreshLogs,
|
const createLog = useCallback(
|
||||||
deleteLog,
|
async (data: CreateLogRequest) => {
|
||||||
} = useLogs(searchSpaceId);
|
try {
|
||||||
|
await createLogMutation(data);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to create log:", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[createLogMutation]
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateLog = useCallback(
|
||||||
|
async (logId: number, data: UpdateLogRequest) => {
|
||||||
|
try {
|
||||||
|
await updateLogMutation({ logId, data });
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to update log:", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[updateLogMutation]
|
||||||
|
);
|
||||||
|
|
||||||
|
const deleteLog = useCallback(
|
||||||
|
async (id: number) => {
|
||||||
|
try {
|
||||||
|
await deleteLogMutation({ id });
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to delete log:", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[deleteLogMutation]
|
||||||
|
);
|
||||||
|
|
||||||
|
const { logs, loading: logsLoading, error: logsError, refreshLogs } = useLogs(searchSpaceId);
|
||||||
const {
|
const {
|
||||||
summary,
|
summary,
|
||||||
loading: summaryLoading,
|
loading: summaryLoading,
|
||||||
|
|
@ -408,7 +452,7 @@ export default function LogsManagePage() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const deletePromises = selectedRows.map((row) => deleteLog(row.original.id));
|
const deletePromises = selectedRows.map((row) => deleteLog(row.original.id)); // Already passes { id } via wrapper
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const results = await Promise.all(deletePromises);
|
const results = await Promise.all(deletePromises);
|
||||||
|
|
@ -437,7 +481,7 @@ export default function LogsManagePage() {
|
||||||
<LogsContext.Provider
|
<LogsContext.Provider
|
||||||
value={{
|
value={{
|
||||||
deleteLog: deleteLog || (() => Promise.resolve(false)),
|
deleteLog: deleteLog || (() => Promise.resolve(false)),
|
||||||
refreshLogs: refreshLogs || (() => Promise.resolve()),
|
refreshLogs: () => refreshLogs().then(() => void 0),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<motion.div
|
<motion.div
|
||||||
|
|
@ -524,7 +568,7 @@ export default function LogsManagePage() {
|
||||||
table={table}
|
table={table}
|
||||||
logs={logs}
|
logs={logs}
|
||||||
loading={logsLoading}
|
loading={logsLoading}
|
||||||
error={logsError}
|
error={logsError?.message ?? null}
|
||||||
onRefresh={refreshLogs}
|
onRefresh={refreshLogs}
|
||||||
id={id}
|
id={id}
|
||||||
t={t}
|
t={t}
|
||||||
|
|
|
||||||
100
surfsense_web/atoms/connectors/connector-mutation.atoms.ts
Normal file
100
surfsense_web/atoms/connectors/connector-mutation.atoms.ts
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
import { atomWithMutation } from "jotai-tanstack-query";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import type {
|
||||||
|
CreateConnectorRequest,
|
||||||
|
DeleteConnectorRequest,
|
||||||
|
GetConnectorsResponse,
|
||||||
|
IndexConnectorRequest,
|
||||||
|
IndexConnectorResponse,
|
||||||
|
UpdateConnectorRequest,
|
||||||
|
} from "@/contracts/types/connector.types";
|
||||||
|
import { connectorsApiService } from "@/lib/apis/connectors-api.service";
|
||||||
|
import { cacheKeys } from "@/lib/query-client/cache-keys";
|
||||||
|
import { queryClient } from "@/lib/query-client/client";
|
||||||
|
import { activeSearchSpaceIdAtom } from "../search-spaces/search-space-query.atoms";
|
||||||
|
|
||||||
|
export const createConnectorMutationAtom = atomWithMutation((get) => {
|
||||||
|
const searchSpaceId = get(activeSearchSpaceIdAtom);
|
||||||
|
|
||||||
|
return {
|
||||||
|
mutationKey: cacheKeys.connectors.all(searchSpaceId!),
|
||||||
|
enabled: !!searchSpaceId,
|
||||||
|
mutationFn: async (request: CreateConnectorRequest) => {
|
||||||
|
return connectorsApiService.createConnector(request);
|
||||||
|
},
|
||||||
|
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: cacheKeys.connectors.all(searchSpaceId!),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const updateConnectorMutationAtom = atomWithMutation((get) => {
|
||||||
|
const searchSpaceId = get(activeSearchSpaceIdAtom);
|
||||||
|
|
||||||
|
return {
|
||||||
|
mutationKey: cacheKeys.connectors.all(searchSpaceId!),
|
||||||
|
enabled: !!searchSpaceId,
|
||||||
|
mutationFn: async (request: UpdateConnectorRequest) => {
|
||||||
|
return connectorsApiService.updateConnector(request);
|
||||||
|
},
|
||||||
|
|
||||||
|
onSuccess: (_, request: UpdateConnectorRequest) => {
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: cacheKeys.connectors.all(searchSpaceId!),
|
||||||
|
});
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: cacheKeys.connectors.byId(String(request.id)),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const deleteConnectorMutationAtom = atomWithMutation((get) => {
|
||||||
|
const searchSpaceId = get(activeSearchSpaceIdAtom);
|
||||||
|
|
||||||
|
return {
|
||||||
|
mutationKey: cacheKeys.connectors.all(searchSpaceId!),
|
||||||
|
enabled: !!searchSpaceId,
|
||||||
|
mutationFn: async (request: DeleteConnectorRequest) => {
|
||||||
|
return connectorsApiService.deleteConnector(request);
|
||||||
|
},
|
||||||
|
|
||||||
|
onSuccess: (_, request: DeleteConnectorRequest) => {
|
||||||
|
queryClient.setQueryData(
|
||||||
|
cacheKeys.connectors.all(searchSpaceId!),
|
||||||
|
(oldData: GetConnectorsResponse | undefined) => {
|
||||||
|
if (!oldData) return oldData;
|
||||||
|
return oldData.filter((connector) => connector.id !== request.id);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: cacheKeys.connectors.byId(String(request.id)),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const indexConnectorMutationAtom = atomWithMutation((get) => {
|
||||||
|
const searchSpaceId = get(activeSearchSpaceIdAtom);
|
||||||
|
|
||||||
|
return {
|
||||||
|
mutationKey: cacheKeys.connectors.index(),
|
||||||
|
enabled: !!searchSpaceId,
|
||||||
|
mutationFn: async (request: IndexConnectorRequest) => {
|
||||||
|
return connectorsApiService.indexConnector(request);
|
||||||
|
},
|
||||||
|
|
||||||
|
onSuccess: (response: IndexConnectorResponse) => {
|
||||||
|
toast.success(response.message);
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: cacheKeys.connectors.all(searchSpaceId!),
|
||||||
|
});
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: cacheKeys.connectors.byId(String(response.connector_id)),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
21
surfsense_web/atoms/connectors/connector-query.atoms.ts
Normal file
21
surfsense_web/atoms/connectors/connector-query.atoms.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { atomWithQuery } from "jotai-tanstack-query";
|
||||||
|
import { connectorsApiService } from "@/lib/apis/connectors-api.service";
|
||||||
|
import { cacheKeys } from "@/lib/query-client/cache-keys";
|
||||||
|
import { activeSearchSpaceIdAtom } from "../search-spaces/search-space-query.atoms";
|
||||||
|
|
||||||
|
export const connectorsAtom = atomWithQuery((get) => {
|
||||||
|
const searchSpaceId = get(activeSearchSpaceIdAtom);
|
||||||
|
|
||||||
|
return {
|
||||||
|
queryKey: cacheKeys.connectors.all(searchSpaceId!),
|
||||||
|
enabled: !!searchSpaceId,
|
||||||
|
staleTime: 5 * 60 * 1000, // 5 minutes
|
||||||
|
queryFn: async () => {
|
||||||
|
return connectorsApiService.getConnectors({
|
||||||
|
queryParams: {
|
||||||
|
search_space_id: searchSpaceId!,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
7
surfsense_web/atoms/connectors/ui.atoms.ts
Normal file
7
surfsense_web/atoms/connectors/ui.atoms.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { atom } from "jotai";
|
||||||
|
import type { GetConnectorsRequest } from "@/contracts/types/connector.types";
|
||||||
|
|
||||||
|
export const globalConnectorsQueryParamsAtom = atom<GetConnectorsRequest["queryParams"]>({
|
||||||
|
skip: 0,
|
||||||
|
limit: 10,
|
||||||
|
});
|
||||||
68
surfsense_web/atoms/logs/log-mutation.atoms.ts
Normal file
68
surfsense_web/atoms/logs/log-mutation.atoms.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
import { atomWithMutation } from "jotai-tanstack-query";
|
||||||
|
import { activeSearchSpaceIdAtom } from "@/atoms/search-spaces/search-space-query.atoms";
|
||||||
|
import type {
|
||||||
|
CreateLogRequest,
|
||||||
|
DeleteLogRequest,
|
||||||
|
UpdateLogRequest,
|
||||||
|
} from "@/contracts/types/log.types";
|
||||||
|
import { logsApiService } from "@/lib/apis/logs-api.service";
|
||||||
|
import { cacheKeys } from "@/lib/query-client/cache-keys";
|
||||||
|
import { queryClient } from "@/lib/query-client/client";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Log Mutation
|
||||||
|
*/
|
||||||
|
export const createLogMutationAtom = atomWithMutation((get) => {
|
||||||
|
const searchSpaceId = get(activeSearchSpaceIdAtom);
|
||||||
|
return {
|
||||||
|
mutationKey: cacheKeys.logs.list(searchSpaceId ?? undefined),
|
||||||
|
enabled: !!searchSpaceId,
|
||||||
|
mutationFn: async (request: CreateLogRequest) => logsApiService.createLog(request),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: cacheKeys.logs.list(searchSpaceId ?? undefined) });
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: cacheKeys.logs.summary(searchSpaceId ?? undefined),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update Log Mutation
|
||||||
|
*/
|
||||||
|
export const updateLogMutationAtom = atomWithMutation((get) => {
|
||||||
|
const searchSpaceId = get(activeSearchSpaceIdAtom);
|
||||||
|
return {
|
||||||
|
mutationKey: cacheKeys.logs.list(searchSpaceId ?? undefined),
|
||||||
|
enabled: !!searchSpaceId,
|
||||||
|
mutationFn: async ({ logId, data }: { logId: number; data: UpdateLogRequest }) =>
|
||||||
|
logsApiService.updateLog(logId, data),
|
||||||
|
onSuccess: (_data, variables) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: cacheKeys.logs.detail(variables.logId) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: cacheKeys.logs.list(searchSpaceId ?? undefined) });
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: cacheKeys.logs.summary(searchSpaceId ?? undefined),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete Log Mutation
|
||||||
|
*/
|
||||||
|
export const deleteLogMutationAtom = atomWithMutation((get) => {
|
||||||
|
const searchSpaceId = get(activeSearchSpaceIdAtom);
|
||||||
|
return {
|
||||||
|
mutationKey: cacheKeys.logs.list(searchSpaceId ?? undefined),
|
||||||
|
enabled: !!searchSpaceId,
|
||||||
|
mutationFn: async (request: DeleteLogRequest) => logsApiService.deleteLog(request),
|
||||||
|
onSuccess: (_data, request) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: cacheKeys.logs.list(searchSpaceId ?? undefined) });
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: cacheKeys.logs.summary(searchSpaceId ?? undefined),
|
||||||
|
});
|
||||||
|
if (request?.id)
|
||||||
|
queryClient.invalidateQueries({ queryKey: cacheKeys.logs.detail(request.id) });
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
159
surfsense_web/contracts/types/connector.types.ts
Normal file
159
surfsense_web/contracts/types/connector.types.ts
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
import { z } from "zod";
|
||||||
|
import { paginationQueryParams } from ".";
|
||||||
|
|
||||||
|
export const searchSourceConnectorTypeEnum = z.enum([
|
||||||
|
"SERPER_API",
|
||||||
|
"TAVILY_API",
|
||||||
|
"SEARXNG_API",
|
||||||
|
"LINKUP_API",
|
||||||
|
"BAIDU_SEARCH_API",
|
||||||
|
"SLACK_CONNECTOR",
|
||||||
|
"NOTION_CONNECTOR",
|
||||||
|
"GITHUB_CONNECTOR",
|
||||||
|
"LINEAR_CONNECTOR",
|
||||||
|
"DISCORD_CONNECTOR",
|
||||||
|
"JIRA_CONNECTOR",
|
||||||
|
"CONFLUENCE_CONNECTOR",
|
||||||
|
"CLICKUP_CONNECTOR",
|
||||||
|
"GOOGLE_CALENDAR_CONNECTOR",
|
||||||
|
"GOOGLE_GMAIL_CONNECTOR",
|
||||||
|
"AIRTABLE_CONNECTOR",
|
||||||
|
"LUMA_CONNECTOR",
|
||||||
|
"ELASTICSEARCH_CONNECTOR",
|
||||||
|
"WEBCRAWLER_CONNECTOR",
|
||||||
|
"BOOKSTACK_CONNECTOR",
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const searchSourceConnector = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
name: z.string(),
|
||||||
|
connector_type: searchSourceConnectorTypeEnum,
|
||||||
|
is_indexable: z.boolean(),
|
||||||
|
last_indexed_at: z.string().nullable(),
|
||||||
|
config: z.record(z.string(), z.any()),
|
||||||
|
periodic_indexing_enabled: z.boolean(),
|
||||||
|
indexing_frequency_minutes: z.number().nullable(),
|
||||||
|
next_scheduled_at: z.string().nullable(),
|
||||||
|
search_space_id: z.number(),
|
||||||
|
user_id: z.string(),
|
||||||
|
created_at: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get connectors
|
||||||
|
*/
|
||||||
|
export const getConnectorsRequest = z.object({
|
||||||
|
queryParams: paginationQueryParams
|
||||||
|
.pick({ skip: true, limit: true })
|
||||||
|
.extend({
|
||||||
|
search_space_id: z.number().or(z.string()).nullish(),
|
||||||
|
})
|
||||||
|
.nullish(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getConnectorsResponse = z.array(searchSourceConnector);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get connector
|
||||||
|
*/
|
||||||
|
export const getConnectorRequest = searchSourceConnector.pick({ id: true });
|
||||||
|
|
||||||
|
export const getConnectorResponse = searchSourceConnector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create connector
|
||||||
|
*/
|
||||||
|
export const createConnectorRequest = z.object({
|
||||||
|
data: searchSourceConnector.pick({
|
||||||
|
name: true,
|
||||||
|
connector_type: true,
|
||||||
|
is_indexable: true,
|
||||||
|
last_indexed_at: true,
|
||||||
|
config: true,
|
||||||
|
periodic_indexing_enabled: true,
|
||||||
|
indexing_frequency_minutes: true,
|
||||||
|
next_scheduled_at: true,
|
||||||
|
}),
|
||||||
|
queryParams: z.object({
|
||||||
|
search_space_id: z.number().or(z.string()),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createConnectorResponse = searchSourceConnector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update connector
|
||||||
|
*/
|
||||||
|
export const updateConnectorRequest = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
data: searchSourceConnector
|
||||||
|
.pick({
|
||||||
|
name: true,
|
||||||
|
connector_type: true,
|
||||||
|
is_indexable: true,
|
||||||
|
last_indexed_at: true,
|
||||||
|
config: true,
|
||||||
|
periodic_indexing_enabled: true,
|
||||||
|
indexing_frequency_minutes: true,
|
||||||
|
next_scheduled_at: true,
|
||||||
|
})
|
||||||
|
.partial(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const updateConnectorResponse = searchSourceConnector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete connector
|
||||||
|
*/
|
||||||
|
export const deleteConnectorRequest = searchSourceConnector.pick({ id: true });
|
||||||
|
|
||||||
|
export const deleteConnectorResponse = z.object({
|
||||||
|
message: z.literal("Search source connector deleted successfully"),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index connector
|
||||||
|
*/
|
||||||
|
export const indexConnectorRequest = z.object({
|
||||||
|
connector_id: z.number(),
|
||||||
|
queryParams: z.object({
|
||||||
|
search_space_id: z.number().or(z.string()),
|
||||||
|
start_date: z.string().optional(),
|
||||||
|
end_date: z.string().optional(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const indexConnectorResponse = z.object({
|
||||||
|
message: z.string(),
|
||||||
|
connector_id: z.number(),
|
||||||
|
search_space_id: z.number(),
|
||||||
|
indexing_from: z.string(),
|
||||||
|
indexing_to: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List GitHub repositories
|
||||||
|
*/
|
||||||
|
export const listGitHubRepositoriesRequest = z.object({
|
||||||
|
github_pat: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const listGitHubRepositoriesResponse = z.array(z.record(z.string(), z.any()));
|
||||||
|
|
||||||
|
// Inferred types
|
||||||
|
export type SearchSourceConnectorType = z.infer<typeof searchSourceConnectorTypeEnum>;
|
||||||
|
export type SearchSourceConnector = z.infer<typeof searchSourceConnector>;
|
||||||
|
export type GetConnectorsRequest = z.infer<typeof getConnectorsRequest>;
|
||||||
|
export type GetConnectorsResponse = z.infer<typeof getConnectorsResponse>;
|
||||||
|
export type GetConnectorRequest = z.infer<typeof getConnectorRequest>;
|
||||||
|
export type GetConnectorResponse = z.infer<typeof getConnectorResponse>;
|
||||||
|
export type CreateConnectorRequest = z.infer<typeof createConnectorRequest>;
|
||||||
|
export type CreateConnectorResponse = z.infer<typeof createConnectorResponse>;
|
||||||
|
export type UpdateConnectorRequest = z.infer<typeof updateConnectorRequest>;
|
||||||
|
export type UpdateConnectorResponse = z.infer<typeof updateConnectorResponse>;
|
||||||
|
export type DeleteConnectorRequest = z.infer<typeof deleteConnectorRequest>;
|
||||||
|
export type DeleteConnectorResponse = z.infer<typeof deleteConnectorResponse>;
|
||||||
|
export type IndexConnectorRequest = z.infer<typeof indexConnectorRequest>;
|
||||||
|
export type IndexConnectorResponse = z.infer<typeof indexConnectorResponse>;
|
||||||
|
export type ListGitHubRepositoriesRequest = z.infer<typeof listGitHubRepositoriesRequest>;
|
||||||
|
export type ListGitHubRepositoriesResponse = z.infer<typeof listGitHubRepositoriesResponse>;
|
||||||
133
surfsense_web/contracts/types/log.types.ts
Normal file
133
surfsense_web/contracts/types/log.types.ts
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
import { z } from "zod";
|
||||||
|
import { paginationQueryParams } from ".";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ENUMS
|
||||||
|
*/
|
||||||
|
export const logLevelEnum = z.enum(["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]);
|
||||||
|
|
||||||
|
export const logStatusEnum = z.enum(["IN_PROGRESS", "SUCCESS", "FAILED"]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base log schema
|
||||||
|
*/
|
||||||
|
export const log = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
level: logLevelEnum,
|
||||||
|
status: logStatusEnum,
|
||||||
|
message: z.string(),
|
||||||
|
source: z.string().nullable().optional(),
|
||||||
|
log_metadata: z.record(z.string(), z.any()).nullable().optional(),
|
||||||
|
created_at: z.string(),
|
||||||
|
search_space_id: z.number(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const logBase = log.omit({ id: true, created_at: true });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create log
|
||||||
|
*/
|
||||||
|
export const createLogRequest = logBase.extend({ search_space_id: z.number() });
|
||||||
|
export const createLogResponse = log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update log
|
||||||
|
*/
|
||||||
|
export const updateLogRequest = logBase.partial();
|
||||||
|
export const updateLogResponse = log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete log
|
||||||
|
*/
|
||||||
|
export const deleteLogRequest = z.object({ id: z.number() });
|
||||||
|
export const deleteLogResponse = z.object({
|
||||||
|
message: z.string().default("Log deleted successfully"),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get logs (list)
|
||||||
|
*/
|
||||||
|
export const logFilters = z.object({
|
||||||
|
search_space_id: z.number().optional(),
|
||||||
|
level: logLevelEnum.optional(),
|
||||||
|
status: logStatusEnum.optional(),
|
||||||
|
source: z.string().optional(),
|
||||||
|
start_date: z.string().optional(),
|
||||||
|
end_date: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getLogsRequest = z.object({
|
||||||
|
queryParams: paginationQueryParams
|
||||||
|
.extend({
|
||||||
|
search_space_id: z.number().optional(),
|
||||||
|
level: logLevelEnum.optional(),
|
||||||
|
status: logStatusEnum.optional(),
|
||||||
|
source: z.string().optional(),
|
||||||
|
start_date: z.string().optional(),
|
||||||
|
end_date: z.string().optional(),
|
||||||
|
})
|
||||||
|
.nullish(),
|
||||||
|
});
|
||||||
|
export const getLogsResponse = z.array(log);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get single log
|
||||||
|
*/
|
||||||
|
export const getLogRequest = z.object({ id: z.number() });
|
||||||
|
export const getLogResponse = log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log summary (used for summary dashboard)
|
||||||
|
*/
|
||||||
|
export const logActiveTask = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
task_name: z.string(),
|
||||||
|
message: z.string(),
|
||||||
|
started_at: z.string(),
|
||||||
|
source: z.string().nullable().optional(),
|
||||||
|
});
|
||||||
|
export const logFailure = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
task_name: z.string(),
|
||||||
|
message: z.string(),
|
||||||
|
failed_at: z.string(),
|
||||||
|
source: z.string().nullable().optional(),
|
||||||
|
error_details: z.string().nullable().optional(),
|
||||||
|
});
|
||||||
|
export const logSummary = z.object({
|
||||||
|
total_logs: z.number(),
|
||||||
|
time_window_hours: z.number(),
|
||||||
|
by_status: z.record(z.string(), z.number()),
|
||||||
|
by_level: z.record(z.string(), z.number()),
|
||||||
|
by_source: z.record(z.string(), z.number()),
|
||||||
|
active_tasks: z.array(logActiveTask),
|
||||||
|
recent_failures: z.array(logFailure),
|
||||||
|
});
|
||||||
|
export const getLogSummaryRequest = z.object({
|
||||||
|
search_space_id: z.number(),
|
||||||
|
hours: z.number().optional(),
|
||||||
|
});
|
||||||
|
export const getLogSummaryResponse = logSummary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Typescript types
|
||||||
|
*/
|
||||||
|
export type Log = z.infer<typeof log>;
|
||||||
|
export type LogLevelEnum = z.infer<typeof logLevelEnum>;
|
||||||
|
export type LogStatusEnum = z.infer<typeof logStatusEnum>;
|
||||||
|
export type LogFilters = z.infer<typeof logFilters>;
|
||||||
|
export type CreateLogRequest = z.infer<typeof createLogRequest>;
|
||||||
|
export type CreateLogResponse = z.infer<typeof createLogResponse>;
|
||||||
|
export type UpdateLogRequest = z.infer<typeof updateLogRequest>;
|
||||||
|
export type UpdateLogResponse = z.infer<typeof updateLogResponse>;
|
||||||
|
export type DeleteLogRequest = z.infer<typeof deleteLogRequest>;
|
||||||
|
export type DeleteLogResponse = z.infer<typeof deleteLogResponse>;
|
||||||
|
export type GetLogsRequest = z.infer<typeof getLogsRequest>;
|
||||||
|
export type GetLogsResponse = z.infer<typeof getLogsResponse>;
|
||||||
|
export type GetLogRequest = z.infer<typeof getLogRequest>;
|
||||||
|
export type GetLogResponse = z.infer<typeof getLogResponse>;
|
||||||
|
export type LogSummary = z.infer<typeof logSummary>;
|
||||||
|
export type LogFailure = z.infer<typeof logFailure>;
|
||||||
|
export type LogActiveTask = z.infer<typeof logActiveTask>;
|
||||||
|
export type GetLogSummaryRequest = z.infer<typeof getLogSummaryRequest>;
|
||||||
|
export type GetLogSummaryResponse = z.infer<typeof getLogSummaryResponse>;
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
import { updateConnectorMutationAtom } from "@/atoms/connectors/connector-mutation.atoms";
|
||||||
|
import { connectorsAtom } from "@/atoms/connectors/connector-query.atoms";
|
||||||
import {
|
import {
|
||||||
type EditConnectorFormValues,
|
type EditConnectorFormValues,
|
||||||
type EditMode,
|
type EditMode,
|
||||||
|
|
@ -11,10 +14,8 @@ import {
|
||||||
type GithubRepo,
|
type GithubRepo,
|
||||||
githubPatSchema,
|
githubPatSchema,
|
||||||
} from "@/components/editConnector/types";
|
} from "@/components/editConnector/types";
|
||||||
import {
|
import type { EnumConnectorName } from "@/contracts/enums/connector";
|
||||||
type SearchSourceConnector,
|
import type { SearchSourceConnector } from "@/hooks/use-search-source-connectors";
|
||||||
useSearchSourceConnectors,
|
|
||||||
} from "@/hooks/use-search-source-connectors";
|
|
||||||
import { authenticatedFetch } from "@/lib/auth-utils";
|
import { authenticatedFetch } from "@/lib/auth-utils";
|
||||||
|
|
||||||
const normalizeListInput = (value: unknown): string[] => {
|
const normalizeListInput = (value: unknown): string[] => {
|
||||||
|
|
@ -51,11 +52,8 @@ const normalizeBoolean = (value: unknown): boolean | null => {
|
||||||
|
|
||||||
export function useConnectorEditPage(connectorId: number, searchSpaceId: string) {
|
export function useConnectorEditPage(connectorId: number, searchSpaceId: string) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const {
|
const { data: connectors = [], isLoading: connectorsLoading } = useAtomValue(connectorsAtom);
|
||||||
connectors,
|
const { mutateAsync: updateConnector } = useAtomValue(updateConnectorMutationAtom);
|
||||||
updateConnector,
|
|
||||||
isLoading: connectorsLoading,
|
|
||||||
} = useSearchSourceConnectors(false, parseInt(searchSpaceId));
|
|
||||||
|
|
||||||
// State managed by the hook
|
// State managed by the hook
|
||||||
const [connector, setConnector] = useState<SearchSourceConnector | null>(null);
|
const [connector, setConnector] = useState<SearchSourceConnector | null>(null);
|
||||||
|
|
@ -532,7 +530,13 @@ export function useConnectorEditPage(connectorId: number, searchSpaceId: string)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await updateConnector(connectorId, updatePayload);
|
await updateConnector({
|
||||||
|
id: connectorId,
|
||||||
|
data: {
|
||||||
|
...updatePayload,
|
||||||
|
connector_type: connector.connector_type as EnumConnectorName,
|
||||||
|
},
|
||||||
|
});
|
||||||
toast.success("Connector updated!");
|
toast.success("Connector updated!");
|
||||||
const newlySavedConfig = updatePayload.config || originalConfig;
|
const newlySavedConfig = updatePayload.config || originalConfig;
|
||||||
setOriginalConfig(newlySavedConfig);
|
setOriginalConfig(newlySavedConfig);
|
||||||
|
|
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
import { authenticatedFetch } from "@/lib/auth-utils";
|
|
||||||
|
|
||||||
// Types for connector API
|
|
||||||
export interface ConnectorConfig {
|
|
||||||
[key: string]: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Connector {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
connector_type: string;
|
|
||||||
config: ConnectorConfig;
|
|
||||||
created_at: string;
|
|
||||||
user_id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CreateConnectorRequest {
|
|
||||||
name: string;
|
|
||||||
connector_type: string;
|
|
||||||
config: ConnectorConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get connector type display name
|
|
||||||
export const getConnectorTypeDisplay = (type: string): string => {
|
|
||||||
const typeMap: Record<string, string> = {
|
|
||||||
TAVILY_API: "Tavily API",
|
|
||||||
SEARXNG_API: "SearxNG",
|
|
||||||
};
|
|
||||||
return typeMap[type] || type;
|
|
||||||
};
|
|
||||||
|
|
||||||
// API service for connectors
|
|
||||||
export const ConnectorService = {
|
|
||||||
// Create a new connector
|
|
||||||
async createConnector(data: CreateConnectorRequest): Promise<Connector> {
|
|
||||||
const response = await authenticatedFetch(
|
|
||||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/search-source-connectors`,
|
|
||||||
{
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json();
|
|
||||||
throw new Error(errorData.detail || "Failed to create connector");
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.json();
|
|
||||||
},
|
|
||||||
|
|
||||||
// Get all connectors
|
|
||||||
async getConnectors(skip = 0, limit = 100): Promise<Connector[]> {
|
|
||||||
const response = await authenticatedFetch(
|
|
||||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/search-source-connectors?skip=${skip}&limit=${limit}`,
|
|
||||||
{ method: "GET" }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json();
|
|
||||||
throw new Error(errorData.detail || "Failed to fetch connectors");
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.json();
|
|
||||||
},
|
|
||||||
|
|
||||||
// Get a specific connector
|
|
||||||
async getConnector(connectorId: number): Promise<Connector> {
|
|
||||||
const response = await authenticatedFetch(
|
|
||||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/search-source-connectors/${connectorId}`,
|
|
||||||
{ method: "GET" }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json();
|
|
||||||
throw new Error(errorData.detail || "Failed to fetch connector");
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.json();
|
|
||||||
},
|
|
||||||
|
|
||||||
// Update a connector
|
|
||||||
async updateConnector(connectorId: number, data: CreateConnectorRequest): Promise<Connector> {
|
|
||||||
const response = await authenticatedFetch(
|
|
||||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/search-source-connectors/${connectorId}`,
|
|
||||||
{
|
|
||||||
method: "PUT",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json();
|
|
||||||
throw new Error(errorData.detail || "Failed to update connector");
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.json();
|
|
||||||
},
|
|
||||||
|
|
||||||
// Delete a connector
|
|
||||||
async deleteConnector(connectorId: number): Promise<void> {
|
|
||||||
const response = await authenticatedFetch(
|
|
||||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/search-source-connectors/${connectorId}`,
|
|
||||||
{ method: "DELETE" }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json();
|
|
||||||
throw new Error(errorData.detail || "Failed to delete connector");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
"use client";
|
"use client";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { toast } from "sonner";
|
import { useCallback, useMemo } from "react";
|
||||||
import { authenticatedFetch } from "@/lib/auth-utils";
|
import { logsApiService } from "@/lib/apis/logs-api.service";
|
||||||
|
import { cacheKeys } from "@/lib/query-client/cache-keys";
|
||||||
|
|
||||||
export type LogLevel = "DEBUG" | "INFO" | "WARNING" | "ERROR" | "CRITICAL";
|
export type LogLevel = "DEBUG" | "INFO" | "WARNING" | "ERROR" | "CRITICAL";
|
||||||
export type LogStatus = "IN_PROGRESS" | "SUCCESS" | "FAILED";
|
export type LogStatus = "IN_PROGRESS" | "SUCCESS" | "FAILED";
|
||||||
|
|
@ -50,282 +51,89 @@ export interface LogSummary {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useLogs(searchSpaceId?: number, filters: LogFilters = {}) {
|
export function useLogs(searchSpaceId?: number, filters: LogFilters = {}) {
|
||||||
const [logs, setLogs] = useState<Log[]>([]);
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
const [error, setError] = useState<string | null>(null);
|
|
||||||
|
|
||||||
// Memoize filters to prevent infinite re-renders
|
// Memoize filters to prevent infinite re-renders
|
||||||
const memoizedFilters = useMemo(() => filters, [JSON.stringify(filters)]);
|
const memoizedFilters = useMemo(() => filters, [JSON.stringify(filters)]);
|
||||||
|
|
||||||
const buildQueryParams = useCallback(
|
const buildQueryParams = useCallback(
|
||||||
(customFilters: LogFilters = {}) => {
|
(customFilters: LogFilters = {}) => {
|
||||||
const params = new URLSearchParams();
|
const params: Record<string, string> = {};
|
||||||
|
|
||||||
const allFilters = { ...memoizedFilters, ...customFilters };
|
const allFilters = { ...memoizedFilters, ...customFilters };
|
||||||
|
|
||||||
if (allFilters.search_space_id) {
|
if (allFilters.search_space_id) {
|
||||||
params.append("search_space_id", allFilters.search_space_id.toString());
|
params["search_space_id"] = allFilters.search_space_id.toString();
|
||||||
}
|
}
|
||||||
if (allFilters.level) {
|
if (allFilters.level) {
|
||||||
params.append("level", allFilters.level);
|
params["level"] = allFilters.level;
|
||||||
}
|
}
|
||||||
if (allFilters.status) {
|
if (allFilters.status) {
|
||||||
params.append("status", allFilters.status);
|
params["status"] = allFilters.status;
|
||||||
}
|
}
|
||||||
if (allFilters.source) {
|
if (allFilters.source) {
|
||||||
params.append("source", allFilters.source);
|
params["source"] = allFilters.source;
|
||||||
}
|
}
|
||||||
if (allFilters.start_date) {
|
if (allFilters.start_date) {
|
||||||
params.append("start_date", allFilters.start_date);
|
params["start_date"] = allFilters.start_date;
|
||||||
}
|
}
|
||||||
if (allFilters.end_date) {
|
if (allFilters.end_date) {
|
||||||
params.append("end_date", allFilters.end_date);
|
params["end_date"] = allFilters.end_date;
|
||||||
}
|
}
|
||||||
|
|
||||||
return params.toString();
|
return params;
|
||||||
},
|
},
|
||||||
[memoizedFilters]
|
[memoizedFilters]
|
||||||
);
|
);
|
||||||
|
|
||||||
const fetchLogs = useCallback(
|
const {
|
||||||
async (customFilters: LogFilters = {}, options: { skip?: number; limit?: number } = {}) => {
|
data: logs,
|
||||||
try {
|
isLoading: loading,
|
||||||
setLoading(true);
|
error,
|
||||||
|
refetch,
|
||||||
const params = new URLSearchParams(buildQueryParams(customFilters));
|
} = useQuery({
|
||||||
if (options.skip !== undefined) params.append("skip", options.skip.toString());
|
queryKey: cacheKeys.logs.withQueryParams({
|
||||||
if (options.limit !== undefined) params.append("limit", options.limit.toString());
|
search_space_id: searchSpaceId,
|
||||||
|
skip: 0,
|
||||||
const response = await authenticatedFetch(
|
limit: 5,
|
||||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/logs?${params}`,
|
...buildQueryParams(filters ?? {}),
|
||||||
{ method: "GET" }
|
}),
|
||||||
);
|
queryFn: () =>
|
||||||
|
logsApiService.getLogs({
|
||||||
if (!response.ok) {
|
queryParams: {
|
||||||
const errorData = await response.json().catch(() => ({}));
|
search_space_id: searchSpaceId,
|
||||||
throw new Error(errorData.detail || "Failed to fetch logs");
|
skip: 0,
|
||||||
}
|
limit: 5,
|
||||||
|
...buildQueryParams(filters ?? {}),
|
||||||
const data = await response.json();
|
},
|
||||||
setLogs(data);
|
}),
|
||||||
setError(null);
|
enabled: !!searchSpaceId,
|
||||||
return data;
|
staleTime: 3 * 60 * 1000,
|
||||||
} catch (err: any) {
|
});
|
||||||
setError(err.message || "Failed to fetch logs");
|
|
||||||
console.error("Error fetching logs:", err);
|
|
||||||
throw err;
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[buildQueryParams]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Initial fetch
|
|
||||||
useEffect(() => {
|
|
||||||
const initialFilters = searchSpaceId
|
|
||||||
? { ...memoizedFilters, search_space_id: searchSpaceId }
|
|
||||||
: memoizedFilters;
|
|
||||||
fetchLogs(initialFilters);
|
|
||||||
}, [searchSpaceId, fetchLogs, memoizedFilters]);
|
|
||||||
|
|
||||||
// Function to refresh the logs list
|
|
||||||
const refreshLogs = useCallback(
|
|
||||||
async (customFilters: LogFilters = {}) => {
|
|
||||||
const finalFilters = searchSpaceId
|
|
||||||
? { ...customFilters, search_space_id: searchSpaceId }
|
|
||||||
: customFilters;
|
|
||||||
return await fetchLogs(finalFilters);
|
|
||||||
},
|
|
||||||
[searchSpaceId, fetchLogs]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Function to create a new log
|
|
||||||
// Use silent: true to suppress toast notifications (for internal/background operations)
|
|
||||||
const createLog = useCallback(
|
|
||||||
async (logData: Omit<Log, "id" | "created_at">, options?: { silent?: boolean }) => {
|
|
||||||
const { silent = false } = options || {};
|
|
||||||
try {
|
|
||||||
const response = await authenticatedFetch(
|
|
||||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/logs`,
|
|
||||||
{
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(logData),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(errorData.detail || "Failed to create log");
|
|
||||||
}
|
|
||||||
|
|
||||||
const newLog = await response.json();
|
|
||||||
setLogs((prevLogs) => [newLog, ...prevLogs]);
|
|
||||||
// Only show toast if not silent
|
|
||||||
if (!silent) {
|
|
||||||
toast.success("Log created successfully");
|
|
||||||
}
|
|
||||||
return newLog;
|
|
||||||
} catch (err: any) {
|
|
||||||
// Only show error toast if not silent
|
|
||||||
if (!silent) {
|
|
||||||
toast.error(err.message || "Failed to create log");
|
|
||||||
}
|
|
||||||
console.error("Error creating log:", err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Function to update a log
|
|
||||||
const updateLog = useCallback(
|
|
||||||
async (
|
|
||||||
logId: number,
|
|
||||||
updateData: Partial<Omit<Log, "id" | "created_at" | "search_space_id">>
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
const response = await authenticatedFetch(
|
|
||||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/logs/${logId}`,
|
|
||||||
{
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
method: "PUT",
|
|
||||||
body: JSON.stringify(updateData),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(errorData.detail || "Failed to update log");
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatedLog = await response.json();
|
|
||||||
setLogs((prevLogs) => prevLogs.map((log) => (log.id === logId ? updatedLog : log)));
|
|
||||||
toast.success("Log updated successfully");
|
|
||||||
return updatedLog;
|
|
||||||
} catch (err: any) {
|
|
||||||
toast.error(err.message || "Failed to update log");
|
|
||||||
console.error("Error updating log:", err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Function to delete a log
|
|
||||||
const deleteLog = useCallback(async (logId: number) => {
|
|
||||||
try {
|
|
||||||
const response = await authenticatedFetch(
|
|
||||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/logs/${logId}`,
|
|
||||||
{ method: "DELETE" }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(errorData.detail || "Failed to delete log");
|
|
||||||
}
|
|
||||||
|
|
||||||
setLogs((prevLogs) => prevLogs.filter((log) => log.id !== logId));
|
|
||||||
toast.success("Log deleted successfully");
|
|
||||||
return true;
|
|
||||||
} catch (err: any) {
|
|
||||||
toast.error(err.message || "Failed to delete log");
|
|
||||||
console.error("Error deleting log:", err);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Function to get a single log
|
|
||||||
const getLog = useCallback(async (logId: number) => {
|
|
||||||
try {
|
|
||||||
const response = await authenticatedFetch(
|
|
||||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/logs/${logId}`,
|
|
||||||
{ method: "GET" }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(errorData.detail || "Failed to fetch log");
|
|
||||||
}
|
|
||||||
|
|
||||||
return await response.json();
|
|
||||||
} catch (err: any) {
|
|
||||||
toast.error(err.message || "Failed to fetch log");
|
|
||||||
console.error("Error fetching log:", err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
logs,
|
logs: logs ?? [],
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
refreshLogs,
|
refreshLogs: refetch,
|
||||||
createLog,
|
|
||||||
updateLog,
|
|
||||||
deleteLog,
|
|
||||||
getLog,
|
|
||||||
fetchLogs,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Separate hook for log summary
|
// Separate hook for log summary
|
||||||
export function useLogsSummary(
|
export function useLogsSummary(searchSpaceId: number, hours: number = 24) {
|
||||||
searchSpaceId: number,
|
const {
|
||||||
hours: number = 24,
|
data: summary,
|
||||||
options: { refetchInterval?: number } = {}
|
isLoading: loading,
|
||||||
) {
|
error,
|
||||||
const [summary, setSummary] = useState<LogSummary | null>(null);
|
refetch,
|
||||||
const [loading, setLoading] = useState(true);
|
} = useQuery({
|
||||||
const [error, setError] = useState<string | null>(null);
|
queryKey: cacheKeys.logs.summary(searchSpaceId),
|
||||||
|
queryFn: () =>
|
||||||
|
logsApiService.getLogSummary({
|
||||||
|
search_space_id: searchSpaceId,
|
||||||
|
hours: hours,
|
||||||
|
}),
|
||||||
|
enabled: !!searchSpaceId,
|
||||||
|
staleTime: 3 * 60 * 1000,
|
||||||
|
});
|
||||||
|
|
||||||
const fetchSummary = useCallback(async () => {
|
return { summary, loading, error, refreshSummary: refetch };
|
||||||
if (!searchSpaceId) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
setLoading(true);
|
|
||||||
const response = await authenticatedFetch(
|
|
||||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/logs/search-space/${searchSpaceId}/summary?hours=${hours}`,
|
|
||||||
{ method: "GET" }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(errorData.detail || "Failed to fetch logs summary");
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
setSummary(data);
|
|
||||||
setError(null);
|
|
||||||
return data;
|
|
||||||
} catch (err: any) {
|
|
||||||
setError(err.message || "Failed to fetch logs summary");
|
|
||||||
console.error("Error fetching logs summary:", err);
|
|
||||||
throw err;
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}, [searchSpaceId, hours]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchSummary();
|
|
||||||
}, [fetchSummary]);
|
|
||||||
|
|
||||||
// Set up polling if refetchInterval is provided
|
|
||||||
useEffect(() => {
|
|
||||||
if (!options.refetchInterval || options.refetchInterval <= 0) return;
|
|
||||||
|
|
||||||
const intervalId = setInterval(() => {
|
|
||||||
fetchSummary();
|
|
||||||
}, options.refetchInterval);
|
|
||||||
|
|
||||||
return () => clearInterval(intervalId);
|
|
||||||
}, [fetchSummary, options.refetchInterval]);
|
|
||||||
|
|
||||||
const refreshSummary = useCallback(() => {
|
|
||||||
return fetchSummary();
|
|
||||||
}, [fetchSummary]);
|
|
||||||
|
|
||||||
return { summary, loading, error, refreshSummary };
|
|
||||||
}
|
}
|
||||||
|
|
@ -21,18 +21,23 @@ export type RequestOptions = {
|
||||||
};
|
};
|
||||||
|
|
||||||
class BaseApiService {
|
class BaseApiService {
|
||||||
bearerToken: string;
|
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
|
|
||||||
noAuthEndpoints: string[] = ["/auth/jwt/login", "/auth/register", "/auth/refresh"]; // Add more endpoints as needed
|
noAuthEndpoints: string[] = ["/auth/jwt/login", "/auth/register", "/auth/refresh"]; // Add more endpoints as needed
|
||||||
|
|
||||||
constructor(bearerToken: string, baseUrl: string) {
|
// Use a getter to always read fresh token from localStorage
|
||||||
this.bearerToken = bearerToken;
|
// This ensures the token is always up-to-date after login/logout
|
||||||
|
get bearerToken(): string {
|
||||||
|
return typeof window !== "undefined" ? getBearerToken() || "" : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(baseUrl: string) {
|
||||||
this.baseUrl = baseUrl;
|
this.baseUrl = baseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
setBearerToken(bearerToken: string) {
|
// Keep for backward compatibility, but token is now always read from localStorage
|
||||||
this.bearerToken = bearerToken;
|
setBearerToken(_bearerToken: string) {
|
||||||
|
// No-op: token is now always read fresh from localStorage via the getter
|
||||||
}
|
}
|
||||||
|
|
||||||
async request<T, R extends ResponseType = ResponseType.JSON>(
|
async request<T, R extends ResponseType = ResponseType.JSON>(
|
||||||
|
|
@ -293,7 +298,4 @@ class BaseApiService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const baseApiService = new BaseApiService(
|
export const baseApiService = new BaseApiService(process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL || "");
|
||||||
typeof window !== "undefined" ? getBearerToken() || "" : "",
|
|
||||||
process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL || ""
|
|
||||||
);
|
|
||||||
|
|
|
||||||
200
surfsense_web/lib/apis/connectors-api.service.ts
Normal file
200
surfsense_web/lib/apis/connectors-api.service.ts
Normal file
|
|
@ -0,0 +1,200 @@
|
||||||
|
import {
|
||||||
|
type CreateConnectorRequest,
|
||||||
|
createConnectorRequest,
|
||||||
|
createConnectorResponse,
|
||||||
|
type DeleteConnectorRequest,
|
||||||
|
deleteConnectorRequest,
|
||||||
|
deleteConnectorResponse,
|
||||||
|
type GetConnectorRequest,
|
||||||
|
type GetConnectorsRequest,
|
||||||
|
getConnectorRequest,
|
||||||
|
getConnectorResponse,
|
||||||
|
getConnectorsRequest,
|
||||||
|
getConnectorsResponse,
|
||||||
|
type IndexConnectorRequest,
|
||||||
|
indexConnectorRequest,
|
||||||
|
indexConnectorResponse,
|
||||||
|
type ListGitHubRepositoriesRequest,
|
||||||
|
listGitHubRepositoriesRequest,
|
||||||
|
listGitHubRepositoriesResponse,
|
||||||
|
type UpdateConnectorRequest,
|
||||||
|
updateConnectorRequest,
|
||||||
|
updateConnectorResponse,
|
||||||
|
} from "@/contracts/types/connector.types";
|
||||||
|
import { ValidationError } from "../error";
|
||||||
|
import { baseApiService } from "./base-api.service";
|
||||||
|
|
||||||
|
class ConnectorsApiService {
|
||||||
|
/**
|
||||||
|
* Get all connectors for a search space
|
||||||
|
*/
|
||||||
|
getConnectors = async (request: GetConnectorsRequest) => {
|
||||||
|
const parsedRequest = getConnectorsRequest.safeParse(request);
|
||||||
|
|
||||||
|
if (!parsedRequest.success) {
|
||||||
|
console.error("Invalid request:", parsedRequest.error);
|
||||||
|
|
||||||
|
const errorMessage = parsedRequest.error.errors.map((err) => err.message).join(", ");
|
||||||
|
throw new ValidationError(`Invalid request: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform query params to be string values
|
||||||
|
const transformedQueryParams = parsedRequest.data.queryParams
|
||||||
|
? Object.fromEntries(
|
||||||
|
Object.entries(parsedRequest.data.queryParams).map(([k, v]) => {
|
||||||
|
return [k, String(v)];
|
||||||
|
})
|
||||||
|
)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const queryParams = transformedQueryParams
|
||||||
|
? new URLSearchParams(transformedQueryParams).toString()
|
||||||
|
: "";
|
||||||
|
|
||||||
|
return baseApiService.get(
|
||||||
|
`/api/v1/search-source-connectors?${queryParams}`,
|
||||||
|
getConnectorsResponse
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a single connector by ID
|
||||||
|
*/
|
||||||
|
getConnector = async (request: GetConnectorRequest) => {
|
||||||
|
const parsedRequest = getConnectorRequest.safeParse(request);
|
||||||
|
|
||||||
|
if (!parsedRequest.success) {
|
||||||
|
console.error("Invalid request:", parsedRequest.error);
|
||||||
|
|
||||||
|
const errorMessage = parsedRequest.error.errors.map((err) => err.message).join(", ");
|
||||||
|
throw new ValidationError(`Invalid request: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseApiService.get(
|
||||||
|
`/api/v1/search-source-connectors/${request.id}`,
|
||||||
|
getConnectorResponse
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new connector
|
||||||
|
*/
|
||||||
|
createConnector = async (request: CreateConnectorRequest) => {
|
||||||
|
const parsedRequest = createConnectorRequest.safeParse(request);
|
||||||
|
|
||||||
|
if (!parsedRequest.success) {
|
||||||
|
console.error("Invalid request:", parsedRequest.error);
|
||||||
|
|
||||||
|
const errorMessage = parsedRequest.error.errors.map((err) => err.message).join(", ");
|
||||||
|
throw new ValidationError(`Invalid request: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data, queryParams } = parsedRequest.data;
|
||||||
|
|
||||||
|
// Transform query params to be string values
|
||||||
|
const transformedQueryParams = Object.fromEntries(
|
||||||
|
Object.entries(queryParams).map(([k, v]) => {
|
||||||
|
return [k, String(v)];
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const queryString = new URLSearchParams(transformedQueryParams).toString();
|
||||||
|
|
||||||
|
return baseApiService.post(
|
||||||
|
`/api/v1/search-source-connectors?${queryString}`,
|
||||||
|
createConnectorResponse,
|
||||||
|
{
|
||||||
|
body: data,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an existing connector
|
||||||
|
*/
|
||||||
|
updateConnector = async (request: UpdateConnectorRequest) => {
|
||||||
|
const parsedRequest = updateConnectorRequest.safeParse(request);
|
||||||
|
|
||||||
|
if (!parsedRequest.success) {
|
||||||
|
console.error("Invalid request:", parsedRequest.error);
|
||||||
|
|
||||||
|
const errorMessage = parsedRequest.error.errors.map((err) => err.message).join(", ");
|
||||||
|
throw new ValidationError(`Invalid request: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id, data } = parsedRequest.data;
|
||||||
|
|
||||||
|
return baseApiService.put(`/api/v1/search-source-connectors/${id}`, updateConnectorResponse, {
|
||||||
|
body: data,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a connector
|
||||||
|
*/
|
||||||
|
deleteConnector = async (request: DeleteConnectorRequest) => {
|
||||||
|
const parsedRequest = deleteConnectorRequest.safeParse(request);
|
||||||
|
|
||||||
|
if (!parsedRequest.success) {
|
||||||
|
console.error("Invalid request:", parsedRequest.error);
|
||||||
|
|
||||||
|
const errorMessage = parsedRequest.error.errors.map((err) => err.message).join(", ");
|
||||||
|
throw new ValidationError(`Invalid request: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseApiService.delete(
|
||||||
|
`/api/v1/search-source-connectors/${request.id}`,
|
||||||
|
deleteConnectorResponse
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index connector content
|
||||||
|
*/
|
||||||
|
indexConnector = async (request: IndexConnectorRequest) => {
|
||||||
|
const parsedRequest = indexConnectorRequest.safeParse(request);
|
||||||
|
|
||||||
|
if (!parsedRequest.success) {
|
||||||
|
console.error("Invalid request:", parsedRequest.error);
|
||||||
|
|
||||||
|
const errorMessage = parsedRequest.error.errors.map((err) => err.message).join(", ");
|
||||||
|
throw new ValidationError(`Invalid request: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { connector_id, queryParams } = parsedRequest.data;
|
||||||
|
|
||||||
|
// Transform query params to be string values
|
||||||
|
const transformedQueryParams = Object.fromEntries(
|
||||||
|
Object.entries(queryParams).map(([k, v]) => {
|
||||||
|
return [k, String(v)];
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const queryString = new URLSearchParams(transformedQueryParams).toString();
|
||||||
|
|
||||||
|
return baseApiService.post(
|
||||||
|
`/api/v1/search-source-connectors/${connector_id}/index?${queryString}`,
|
||||||
|
indexConnectorResponse
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List GitHub repositories using a Personal Access Token
|
||||||
|
*/
|
||||||
|
listGitHubRepositories = async (request: ListGitHubRepositoriesRequest) => {
|
||||||
|
const parsedRequest = listGitHubRepositoriesRequest.safeParse(request);
|
||||||
|
|
||||||
|
if (!parsedRequest.success) {
|
||||||
|
console.error("Invalid request:", parsedRequest.error);
|
||||||
|
|
||||||
|
const errorMessage = parsedRequest.error.errors.map((err) => err.message).join(", ");
|
||||||
|
throw new ValidationError(`Invalid request: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseApiService.post(`/api/v1/github/repositories`, listGitHubRepositoriesResponse, {
|
||||||
|
body: parsedRequest.data,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const connectorsApiService = new ConnectorsApiService();
|
||||||
128
surfsense_web/lib/apis/logs-api.service.ts
Normal file
128
surfsense_web/lib/apis/logs-api.service.ts
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
import {
|
||||||
|
type CreateLogRequest,
|
||||||
|
createLogRequest,
|
||||||
|
createLogResponse,
|
||||||
|
type DeleteLogRequest,
|
||||||
|
deleteLogRequest,
|
||||||
|
deleteLogResponse,
|
||||||
|
type GetLogRequest,
|
||||||
|
type GetLogSummaryRequest,
|
||||||
|
type GetLogsRequest,
|
||||||
|
getLogRequest,
|
||||||
|
getLogResponse,
|
||||||
|
getLogSummaryRequest,
|
||||||
|
getLogSummaryResponse,
|
||||||
|
getLogsRequest,
|
||||||
|
getLogsResponse,
|
||||||
|
type Log,
|
||||||
|
log,
|
||||||
|
type UpdateLogRequest,
|
||||||
|
updateLogRequest,
|
||||||
|
updateLogResponse,
|
||||||
|
} from "@/contracts/types/log.types";
|
||||||
|
import { ValidationError } from "../error";
|
||||||
|
import { baseApiService } from "./base-api.service";
|
||||||
|
|
||||||
|
class LogsApiService {
|
||||||
|
/**
|
||||||
|
* Get a list of logs with optional filtering and pagination
|
||||||
|
*/
|
||||||
|
getLogs = async (request: GetLogsRequest) => {
|
||||||
|
const parsedRequest = getLogsRequest.safeParse(request);
|
||||||
|
if (!parsedRequest.success) {
|
||||||
|
console.error("Invalid request:", parsedRequest.error);
|
||||||
|
const errorMessage = parsedRequest.error.issues.map((issue) => issue.message).join(", ");
|
||||||
|
throw new ValidationError(`Invalid request: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
// Transform query params to be string values
|
||||||
|
const transformedQueryParams = parsedRequest.data.queryParams
|
||||||
|
? Object.fromEntries(
|
||||||
|
Object.entries(parsedRequest.data.queryParams).map(([k, v]) => {
|
||||||
|
// Handle array values (document_type)
|
||||||
|
if (Array.isArray(v)) {
|
||||||
|
return [k, v.join(",")];
|
||||||
|
}
|
||||||
|
return [k, String(v)];
|
||||||
|
})
|
||||||
|
)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const queryParams = transformedQueryParams
|
||||||
|
? new URLSearchParams(transformedQueryParams).toString()
|
||||||
|
: "";
|
||||||
|
return baseApiService.get(`/api/v1/logs?${queryParams}`, getLogsResponse);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a single log by ID
|
||||||
|
*/
|
||||||
|
getLog = async (request: GetLogRequest) => {
|
||||||
|
const parsedRequest = getLogRequest.safeParse(request);
|
||||||
|
if (!parsedRequest.success) {
|
||||||
|
console.error("Invalid request:", parsedRequest.error);
|
||||||
|
const errorMessage = parsedRequest.error.issues.map((issue) => issue.message).join(", ");
|
||||||
|
throw new ValidationError(`Invalid request: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
return baseApiService.get(`/api/v1/logs/${request.id}`, getLogResponse);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a log entry
|
||||||
|
*/
|
||||||
|
createLog = async (request: CreateLogRequest) => {
|
||||||
|
const parsedRequest = createLogRequest.safeParse(request);
|
||||||
|
if (!parsedRequest.success) {
|
||||||
|
console.error("Invalid request:", parsedRequest.error);
|
||||||
|
const errorMessage = parsedRequest.error.issues.map((issue) => issue.message).join(", ");
|
||||||
|
throw new ValidationError(`Invalid request: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
return baseApiService.post(`/api/v1/logs`, createLogResponse, {
|
||||||
|
body: parsedRequest.data,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a log entry
|
||||||
|
*/
|
||||||
|
updateLog = async (logId: number, request: UpdateLogRequest) => {
|
||||||
|
const parsedRequest = updateLogRequest.safeParse(request);
|
||||||
|
if (!parsedRequest.success) {
|
||||||
|
console.error("Invalid request:", parsedRequest.error);
|
||||||
|
const errorMessage = parsedRequest.error.issues.map((issue) => issue.message).join(", ");
|
||||||
|
throw new ValidationError(`Invalid request: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
return baseApiService.put(`/api/v1/logs/${logId}`, updateLogResponse, {
|
||||||
|
body: parsedRequest.data,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a log entry
|
||||||
|
*/
|
||||||
|
deleteLog = async (request: DeleteLogRequest) => {
|
||||||
|
const parsedRequest = deleteLogRequest.safeParse(request);
|
||||||
|
if (!parsedRequest.success) {
|
||||||
|
console.error("Invalid request:", parsedRequest.error);
|
||||||
|
const errorMessage = parsedRequest.error.issues.map((issue) => issue.message).join(", ");
|
||||||
|
throw new ValidationError(`Invalid request: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
return baseApiService.delete(`/api/v1/logs/${parsedRequest.data.id}`, deleteLogResponse);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get summary for logs by search space
|
||||||
|
*/
|
||||||
|
getLogSummary = async (request: GetLogSummaryRequest) => {
|
||||||
|
const parsedRequest = getLogSummaryRequest.safeParse(request);
|
||||||
|
if (!parsedRequest.success) {
|
||||||
|
console.error("Invalid request:", parsedRequest.error);
|
||||||
|
const errorMessage = parsedRequest.error.issues.map((issue) => issue.message).join(", ");
|
||||||
|
throw new ValidationError(`Invalid request: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
const { search_space_id, hours } = parsedRequest.data;
|
||||||
|
const url = `/api/v1/logs/search-space/${search_space_id}/summary${hours ? `?hours=${hours}` : ""}`;
|
||||||
|
return baseApiService.get(url, getLogSummaryResponse);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const logsApiService = new LogsApiService();
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
|
import type { GetConnectorsRequest } from "@/contracts/types/connector.types";
|
||||||
import type { GetDocumentsRequest } from "@/contracts/types/document.types";
|
import type { GetDocumentsRequest } from "@/contracts/types/document.types";
|
||||||
|
import type { GetLogsRequest } from "@/contracts/types/log.types";
|
||||||
import type { GetSearchSpacesRequest } from "@/contracts/types/search-space.types";
|
import type { GetSearchSpacesRequest } from "@/contracts/types/search-space.types";
|
||||||
|
|
||||||
export const cacheKeys = {
|
export const cacheKeys = {
|
||||||
|
|
@ -18,6 +20,13 @@ export const cacheKeys = {
|
||||||
typeCounts: (searchSpaceId?: string) => ["documents", "type-counts", searchSpaceId] as const,
|
typeCounts: (searchSpaceId?: string) => ["documents", "type-counts", searchSpaceId] as const,
|
||||||
byChunk: (chunkId: string) => ["documents", "by-chunk", chunkId] as const,
|
byChunk: (chunkId: string) => ["documents", "by-chunk", chunkId] as const,
|
||||||
},
|
},
|
||||||
|
logs: {
|
||||||
|
list: (searchSpaceId?: number | string) => ["logs", "list", searchSpaceId] as const,
|
||||||
|
detail: (logId: number | string) => ["logs", "detail", logId] as const,
|
||||||
|
summary: (searchSpaceId?: number | string) => ["logs", "summary", searchSpaceId] as const,
|
||||||
|
withQueryParams: (queries: GetLogsRequest["queryParams"]) =>
|
||||||
|
["logs", "with-query-params", ...(queries ? Object.values(queries) : [])] as const,
|
||||||
|
},
|
||||||
newLLMConfigs: {
|
newLLMConfigs: {
|
||||||
all: (searchSpaceId: number) => ["new-llm-configs", searchSpaceId] as const,
|
all: (searchSpaceId: number) => ["new-llm-configs", searchSpaceId] as const,
|
||||||
byId: (configId: number) => ["new-llm-configs", "detail", configId] as const,
|
byId: (configId: number) => ["new-llm-configs", "detail", configId] as const,
|
||||||
|
|
@ -52,4 +61,11 @@ export const cacheKeys = {
|
||||||
all: (searchSpaceId: string) => ["invites", searchSpaceId] as const,
|
all: (searchSpaceId: string) => ["invites", searchSpaceId] as const,
|
||||||
info: (inviteCode: string) => ["invites", "info", inviteCode] as const,
|
info: (inviteCode: string) => ["invites", "info", inviteCode] as const,
|
||||||
},
|
},
|
||||||
|
connectors: {
|
||||||
|
all: (searchSpaceId: string) => ["connectors", searchSpaceId] as const,
|
||||||
|
withQueryParams: (queries: GetConnectorsRequest["queryParams"]) =>
|
||||||
|
["connectors", ...(queries ? Object.values(queries) : [])] as const,
|
||||||
|
byId: (connectorId: string) => ["connector", connectorId] as const,
|
||||||
|
index: () => ["connector", "index"] as const,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue