feat(ui): SearchTools/SearchTools to shadcn

- @tremor Button/Text/Title + antd Modal/Spin/Input + @ant-design
  LoadingOutlined \u2192 shadcn Button/Dialog/Input + lucide Loader2 +
  native headings.
- antd Form/Form.Item/Select/AntInput.Password/AntInput.TextArea
  preserved (form context + rules). antd Table kept.

Gates: TS \u2713 | Build \u2713.

Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
This commit is contained in:
Cursor Agent 2026-04-23 19:45:59 +00:00
parent facac907d1
commit 331a1fe752
No known key found for this signature in database

View file

@ -1,8 +1,20 @@
import { isAdminRole } from "@/utils/roles"; import { isAdminRole } from "@/utils/roles";
import { LoadingOutlined } from "@ant-design/icons";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { Button, Text, Title } from "@tremor/react"; import { Button } from "@/components/ui/button";
import { Form, Input, Modal, Select, Spin, Table } from "antd"; import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Loader2 } from "lucide-react";
import {
Form,
Input as AntInput,
Select,
Table,
} from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
import DeleteResourceModal from "../common_components/DeleteResourceModal"; import DeleteResourceModal from "../common_components/DeleteResourceModal";
import NotificationsManager from "../molecules/notifications_manager"; import NotificationsManager from "../molecules/notifications_manager";
@ -168,7 +180,7 @@ const SearchTools: React.FC<SearchToolsProps> = ({ accessToken, userRole, userID
label="Search Tool Name" label="Search Tool Name"
rules={[{ required: true, message: "Please enter a search tool name" }]} rules={[{ required: true, message: "Please enter a search tool name" }]}
> >
<Input placeholder="e.g., my-perplexity-search" /> <AntInput placeholder="e.g., my-perplexity-search" />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
@ -185,19 +197,29 @@ const SearchTools: React.FC<SearchToolsProps> = ({ accessToken, userRole, userID
</Select> </Select>
</Form.Item> </Form.Item>
<Form.Item name="api_key" label="API Key" extra="API key for the search provider"> <Form.Item
<Input.Password placeholder="Enter API key" /> name="api_key"
label="API Key"
extra="API key for the search provider"
>
<AntInput.Password placeholder="Enter API key" />
</Form.Item> </Form.Item>
<Form.Item name="description" label="Description"> <Form.Item name="description" label="Description">
<Input.TextArea rows={3} placeholder="Description of this search tool" /> <AntInput.TextArea
rows={3}
placeholder="Description of this search tool"
/>
</Form.Item> </Form.Item>
</Form> </Form>
); );
if (!accessToken || !userRole || !userID) { if (!accessToken || !userRole || !userID) {
console.log("Missing required authentication parameters", { accessToken, userRole, userID }); return (
return <div className="p-6 text-center text-gray-500">Missing required authentication parameters.</div>; <div className="p-6 text-center text-muted-foreground">
Missing required authentication parameters.
</div>
);
} }
const ToolsTab = () => const ToolsTab = () =>
@ -222,21 +244,25 @@ const SearchTools: React.FC<SearchToolsProps> = ({ accessToken, userRole, userID
availableProviders={availableProviders} availableProviders={availableProviders}
/> />
) : ( ) : (
<div className="w-full h-full"> <div className="w-full h-full relative">
<Spin spinning={isLoadingTools} indicator={<LoadingOutlined spin />} size="large"> {isLoadingTools && (
<Table <div className="absolute inset-0 flex items-center justify-center bg-background/50 z-10">
bordered <Loader2 className="h-8 w-8 animate-spin text-primary" />
dataSource={searchTools || []} </div>
columns={columns} )}
rowKey={(record) => record.search_tool_id || record.search_tool_name} <Table
pagination={false} bordered
locale={{ dataSource={searchTools || []}
emptyText: "No search tools configured", columns={columns}
}} rowKey={(record) =>
size="small" record.search_tool_id || record.search_tool_name
/> }
</Spin> pagination={false}
locale={{
emptyText: "No search tools configured",
}}
size="small"
/>
</div> </div>
); );
@ -274,24 +300,46 @@ const SearchTools: React.FC<SearchToolsProps> = ({ accessToken, userRole, userID
/> />
{/* Edit Modal */} {/* Edit Modal */}
<Modal <Dialog
title="Edit Search Tool"
open={isEditModalVisible} open={isEditModalVisible}
onOk={handleEditSubmit} onOpenChange={(o) => {
onCancel={() => { if (!o) {
setEditModalVisible(false); setEditModalVisible(false);
form.resetFields(); form.resetFields();
setSelectedToolId(null); setSelectedToolId(null);
}
}} }}
width={600}
> >
{renderEditForm()} <DialogContent className="max-w-[600px]">
</Modal> <DialogHeader>
<DialogTitle>Edit Search Tool</DialogTitle>
</DialogHeader>
{renderEditForm()}
<DialogFooter>
<Button
variant="outline"
onClick={() => {
setEditModalVisible(false);
form.resetFields();
setSelectedToolId(null);
}}
>
Cancel
</Button>
<Button onClick={handleEditSubmit}>OK</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Title>Search Tools</Title> <h1 className="text-2xl font-semibold">Search Tools</h1>
<Text className="text-tremor-content mt-2">Configure and manage your search providers</Text> <p className="text-muted-foreground mt-2">
Configure and manage your search providers
</p>
{isAdminRole(userRole) && ( {isAdminRole(userRole) && (
<Button className="mt-4 mb-4" onClick={() => setCreateModalVisible(true)}> <Button
className="mt-4 mb-4"
onClick={() => setCreateModalVisible(true)}
>
+ Add New Search Tool + Add New Search Tool
</Button> </Button>
)} )}