feat: tools frontend and endpoints refactor

This commit is contained in:
Siddhant Rai
2024-12-18 22:48:40 +05:30
parent f87ae429f4
commit f9a7db11eb
23 changed files with 1069 additions and 168 deletions

View File

@@ -0,0 +1,136 @@
import React from 'react';
import userService from '../api/services/userService';
import Exit from '../assets/exit.svg';
import { ActiveState } from '../models/misc';
import { AvailableTool } from './types';
import ConfigToolModal from './ConfigToolModal';
export default function AddToolModal({
message,
modalState,
setModalState,
getUserTools,
}: {
message: string;
modalState: ActiveState;
setModalState: (state: ActiveState) => void;
getUserTools: () => void;
}) {
const [availableTools, setAvailableTools] = React.useState<AvailableTool[]>(
[],
);
const [selectedTool, setSelectedTool] = React.useState<AvailableTool | null>(
null,
);
const [configModalState, setConfigModalState] =
React.useState<ActiveState>('INACTIVE');
const getAvailableTools = () => {
userService
.getAvailableTools()
.then((res) => {
return res.json();
})
.then((data) => {
setAvailableTools(data.data);
});
};
const handleAddTool = (tool: AvailableTool) => {
if (Object.keys(tool.configRequirements).length === 0) {
userService
.createTool({
name: tool.name,
displayName: tool.displayName,
description: tool.description,
config: {},
actions: tool.actions,
status: true,
})
.then((res) => {
if (res.status === 200) {
getUserTools();
setModalState('INACTIVE');
}
});
} else {
setModalState('INACTIVE');
setConfigModalState('ACTIVE');
}
};
React.useEffect(() => {
if (modalState === 'ACTIVE') getAvailableTools();
}, [modalState]);
return (
<>
<div
className={`${
modalState === 'ACTIVE' ? 'visible' : 'hidden'
} fixed top-0 left-0 z-30 h-screen w-screen bg-gray-alpha flex items-center justify-center`}
>
<article className="flex h-[85vh] w-[90vw] md:w-[75vw] flex-col gap-4 rounded-2xl bg-[#FBFBFB] shadow-lg dark:bg-[#26272E]">
<div className="relative">
<button
className="absolute top-3 right-4 m-2 w-3"
onClick={() => {
setModalState('INACTIVE');
}}
>
<img className="filter dark:invert" src={Exit} />
</button>
<div className="p-6">
<h2 className="font-semibold text-xl text-jet dark:text-bright-gray px-3">
Select a tool to set up
</h2>
<div className="mt-5 grid grid-cols-3 gap-4 h-[73vh] overflow-auto px-3 py-px">
{availableTools.map((tool, index) => (
<div
role="button"
tabIndex={0}
key={index}
className="h-52 w-full p-6 border rounded-2xl border-silver dark:border-[#4D4E58] flex flex-col justify-between dark:bg-[#32333B] cursor-pointer"
onClick={() => {
setSelectedTool(tool);
handleAddTool(tool);
}}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
setSelectedTool(tool);
handleAddTool(tool);
}
}}
>
<div className="w-full">
<div className="px-1 w-full flex items-center justify-between">
<img
src={`/toolIcons/tool_${tool.name}.svg`}
className="h-8 w-8"
/>
</div>
<div className="mt-[9px]">
<p className="px-1 text-sm font-semibold text-eerie-black dark:text-white leading-relaxed capitalize">
{tool.displayName}
</p>
<p className="mt-1 px-1 h-24 overflow-auto text-sm text-gray-600 dark:text-[#8a8a8c] leading-relaxed">
{tool.description}
</p>
</div>
</div>
</div>
))}
</div>
</div>
</div>
</article>
</div>
<ConfigToolModal
modalState={configModalState}
setModalState={setConfigModalState}
tool={selectedTool}
getUserTools={getUserTools}
/>
</>
);
}

View File

@@ -0,0 +1,95 @@
import React from 'react';
import Exit from '../assets/exit.svg';
import Input from '../components/Input';
import { ActiveState } from '../models/misc';
import { AvailableTool } from './types';
import userService from '../api/services/userService';
export default function ConfigToolModal({
modalState,
setModalState,
tool,
getUserTools,
}: {
modalState: ActiveState;
setModalState: (state: ActiveState) => void;
tool: AvailableTool | null;
getUserTools: () => void;
}) {
const [authKey, setAuthKey] = React.useState<string>('');
const handleAddTool = (tool: AvailableTool) => {
userService
.createTool({
name: tool.name,
displayName: tool.displayName,
description: tool.description,
config: { token: authKey },
actions: tool.actions,
status: true,
})
.then(() => {
setModalState('INACTIVE');
getUserTools();
});
};
return (
<div
className={`${
modalState === 'ACTIVE' ? 'visible' : 'hidden'
} fixed top-0 left-0 z-30 h-screen w-screen bg-gray-alpha flex items-center justify-center`}
>
<article className="flex w-11/12 sm:w-[512px] flex-col gap-4 rounded-2xl bg-white shadow-lg dark:bg-[#26272E]">
<div className="relative">
<button
className="absolute top-3 right-4 m-2 w-3"
onClick={() => {
setModalState('INACTIVE');
}}
>
<img className="filter dark:invert" src={Exit} />
</button>
<div className="p-6">
<h2 className="font-semibold text-xl text-jet dark:text-bright-gray px-3">
Tool Config
</h2>
<p className="mt-5 text-sm text-gray-600 dark:text-gray-400 px-3">
Type: <span className="font-semibold">{tool?.name} </span>
</p>
<div className="mt-6 relative px-3">
<span className="absolute left-5 -top-2 bg-white px-2 text-xs text-gray-4000 dark:bg-[#26272E] dark:text-silver">
API Key / Oauth
</span>
<Input
type="text"
value={authKey}
onChange={(e) => setAuthKey(e.target.value)}
borderVariant="thin"
placeholder="Enter API Key / Oauth"
></Input>
</div>
<div className="mt-8 flex flex-row-reverse gap-1 px-3">
<button
onClick={() => {
handleAddTool(tool as AvailableTool);
}}
className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-[#6F3FD1]"
>
Add Tool
</button>
<button
onClick={() => {
setModalState('INACTIVE');
}}
className="cursor-pointer rounded-3xl px-5 py-2 text-sm font-medium hover:bg-gray-100 dark:bg-transparent dark:text-light-gray dark:hover:bg-[#767183]/50"
>
Close
</button>
</div>
</div>
</div>
</article>
</div>
);
}

View File

@@ -0,0 +1,11 @@
export type AvailableTool = {
name: string;
displayName: string;
description: string;
configRequirements: object;
actions: {
name: string;
description: string;
parameters: object;
}[];
};