diff --git a/ui/litellm-dashboard/src/components/SearchTools/SearchToolColumn.tsx b/ui/litellm-dashboard/src/components/SearchTools/SearchToolColumn.tsx index 78aa1094000..86b0bde4d04 100644 --- a/ui/litellm-dashboard/src/components/SearchTools/SearchToolColumn.tsx +++ b/ui/litellm-dashboard/src/components/SearchTools/SearchToolColumn.tsx @@ -1,78 +1,114 @@ -import { ColumnDef } from "@tanstack/react-table"; +import { ColumnsType } from "antd/es/table"; import { SearchTool } from "./types"; -import { Icon } from "@tremor/react"; -import { PencilAltIcon, TrashIcon } from "@heroicons/react/outline"; +import { Tag } from "antd"; +import TableIconActionButton from "../common_components/IconActionButton/TableIconActionButtons/TableIconActionButton"; export const searchToolColumns = ( onView: (searchToolId: string) => void, onEdit: (searchToolId: string) => void, onDelete: (searchToolId: string) => void, availableProviders: Array<{ provider_name: string; ui_friendly_name: string }>, -): ColumnDef[] => [ - { - accessorKey: "search_tool_id", - header: "Search Tool ID", - cell: ({ row }) => ( - - ), - }, - { - accessorKey: "search_tool_name", - header: "Name", - cell: ({ getValue }) => {getValue() as string}, - }, - { - id: "provider", - header: "Provider", - cell: ({ row }) => { - const provider = row.original.litellm_params.search_provider; - const providerInfo = availableProviders.find((p) => p.provider_name === provider); - const displayName = providerInfo?.ui_friendly_name || provider; +): ColumnsType => [ + { + title: "Search Tool ID", + dataIndex: "search_tool_id", + key: "search_tool_id", + render: (_, tool) => { + const isFromConfig = tool.is_from_config; - return {displayName}; + if (isFromConfig) { + return -; + } + + return ( + + ); + }, }, - }, - { - header: "Created At", - accessorKey: "created_at", - sortingFn: "datetime", - cell: ({ row }) => { - const tool = row.original; - return {tool.created_at ? new Date(tool.created_at).toLocaleDateString() : "-"}; + { + title: "Name", + dataIndex: "search_tool_name", + key: "search_tool_name", + render: (name: string) => {name}, }, - }, - { - header: "Updated At", - accessorKey: "updated_at", - sortingFn: "datetime", - cell: ({ row }) => { - const tool = row.original; - return {tool.updated_at ? new Date(tool.updated_at).toLocaleDateString() : "-"}; + { + title: "Provider", + key: "provider", + render: (_, tool) => { + const provider = tool.litellm_params.search_provider; + const providerInfo = availableProviders.find((p) => p.provider_name === provider); + const displayName = providerInfo?.ui_friendly_name || provider; + + return {displayName}; + }, }, - }, - { - id: "actions", - header: "Actions", - cell: ({ row }) => ( -
- onEdit(row.original.search_tool_id!)} - className="cursor-pointer" - /> - onDelete(row.original.search_tool_id!)} - className="cursor-pointer" - /> -
- ), - }, -]; + { + title: "Created At", + dataIndex: "created_at", + key: "created_at", + render: (_, tool) => { + return {tool.created_at ? new Date(tool.created_at).toLocaleDateString() : "-"}; + }, + }, + { + title: "Updated At", + dataIndex: "updated_at", + key: "updated_at", + render: (_, tool) => { + return {tool.updated_at ? new Date(tool.updated_at).toLocaleDateString() : "-"}; + }, + }, + { + title: "Source", + key: "source", + render: (_, tool) => { + const isFromConfig = tool.is_from_config ?? false; + + return ( + + {isFromConfig ? "Config" : "DB"} + + ); + }, + }, + { + title: "Actions", + key: "actions", + render: (_, tool) => { + const toolId = tool.search_tool_id; + const isFromConfig = tool.is_from_config ?? false; + + return ( +
+ { + if (toolId && !isFromConfig) { + onEdit(toolId); + } + }} + /> + { + if (toolId && !isFromConfig) { + onDelete(toolId); + } + }} + /> +
+ ); + }, + }, + ]; diff --git a/ui/litellm-dashboard/src/components/SearchTools/SearchTools.tsx b/ui/litellm-dashboard/src/components/SearchTools/SearchTools.tsx index be4c74099b0..ba42ea22cdc 100644 --- a/ui/litellm-dashboard/src/components/SearchTools/SearchTools.tsx +++ b/ui/litellm-dashboard/src/components/SearchTools/SearchTools.tsx @@ -1,8 +1,8 @@ import React, { useState } from "react"; import { useQuery } from "@tanstack/react-query"; -import { Modal, Form, Input, Select } from "antd"; -import { Button, Title, Text, Grid, Col } from "@tremor/react"; -import { DataTable } from "../view_logs/table"; +import { Modal, Form, Input, Select, Table, Spin } from "antd"; +import { LoadingOutlined } from "@ant-design/icons"; +import { Button, Title, Text } from "@tremor/react"; import { searchToolColumns } from "./SearchToolColumn"; import { fetchSearchTools, @@ -15,6 +15,7 @@ import { isAdminRole } from "@/utils/roles"; import NotificationsManager from "../molecules/notifications_manager"; import { SearchToolView } from "./SearchToolView"; import CreateSearchTool from "./CreateSearchTools"; +import DeleteResourceModal from "../common_components/DeleteResourceModal"; interface SearchToolsProps { accessToken: string | null; @@ -22,24 +23,6 @@ interface SearchToolsProps { userID: string | null; } -const DeleteModal: React.FC<{ - isModalOpen: boolean; - title: string; - confirmDelete: () => void; - cancelDelete: () => void; -}> = ({ isModalOpen, title, confirmDelete, cancelDelete }) => { - if (!isModalOpen) return null; - return ( - - - {title} - -

Are you sure you want to delete this search tool?

- -
-
- ); -}; const SearchTools: React.FC = ({ accessToken, userRole, userID }) => { const { @@ -72,6 +55,7 @@ const SearchTools: React.FC = ({ accessToken, userRole, userID // State const [toolIdToDelete, setToolToDelete] = useState(null); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [isDeleting, setIsDeleting] = useState(false); const [selectedToolId, setSelectedToolId] = useState(null); const [editTool, setEditTool] = useState(false); const [isCreateModalVisible, setCreateModalVisible] = useState(false); @@ -116,16 +100,19 @@ const SearchTools: React.FC = ({ accessToken, userRole, userID if (toolIdToDelete == null || accessToken == null) { return; } + setIsDeleting(true); try { await deleteSearchTool(accessToken, toolIdToDelete); NotificationsManager.success("Deleted search tool successfully"); + setIsDeleteModalOpen(false); + setToolToDelete(null); refetch(); } catch (error) { console.error("Error deleting the search tool:", error); NotificationsManager.error("Failed to delete search tool"); + } finally { + setIsDeleting(false); } - setIsDeleteModalOpen(false); - setToolToDelete(null); }; const cancelDelete = () => { @@ -133,6 +120,11 @@ const SearchTools: React.FC = ({ accessToken, userRole, userID setToolToDelete(null); }; + const toolToDelete = searchTools?.find((t) => t.search_tool_id === toolIdToDelete); + const providerInfo = toolToDelete + ? availableProviders.find((p) => p.provider_name === toolToDelete.litellm_params.search_provider) + : null; + const handleCreateSuccess = (newSearchTool: SearchTool) => { setCreateModalVisible(false); refetch(); @@ -231,26 +223,46 @@ const SearchTools: React.FC = ({ accessToken, userRole, userID /> ) : (
-
- } size="large"> +
} - getRowCanExpand={() => false} - isLoading={isLoadingTools} - noDataMessage="No search tools configured" + rowKey={(record) => record.search_tool_id || record.search_tool_name} + pagination={false} + locale={{ + emptyText: "No search tools configured", + }} + size="small" /> - + + ); return (
-