mirror of
https://github.com/arc53/DocsGPT.git
synced 2025-11-29 16:43:16 +00:00
Merge branch 'main' into fix/agents-bugs
This commit is contained in:
1948
docs/package-lock.json
generated
1948
docs/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@
|
||||
"dependencies": {
|
||||
"@vercel/analytics": "^1.1.1",
|
||||
"docsgpt-react": "^0.5.1",
|
||||
"next": "^14.2.26",
|
||||
"next": "^15.3.3",
|
||||
"nextra": "^2.13.2",
|
||||
"nextra-theme-docs": "^2.13.2",
|
||||
"react": "^18.2.0",
|
||||
|
||||
1039
extensions/react-widget/package-lock.json
generated
1039
extensions/react-widget/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
924
frontend/package-lock.json
generated
924
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -34,9 +34,9 @@
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-i18next": "^15.4.0",
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-redux": "^8.0.5",
|
||||
"react-router-dom": "^7.1.1",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-router-dom": "^7.6.1",
|
||||
"react-syntax-highlighter": "^15.6.1",
|
||||
"rehype-katex": "^7.0.1",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"remark-math": "^6.0.0"
|
||||
@@ -52,13 +52,13 @@
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-config-standard-with-typescript": "^34.0.0",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-n": "^15.7.0",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint-plugin-promise": "^6.6.0",
|
||||
"eslint-plugin-react": "^7.37.3",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"husky": "^8.0.0",
|
||||
"lint-staged": "^15.3.0",
|
||||
@@ -66,8 +66,8 @@
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.7.2",
|
||||
"vite": "^5.4.14",
|
||||
"vite-plugin-svgr": "^4.2.0"
|
||||
"typescript": "^5.8.3",
|
||||
"vite": "^6.3.5",
|
||||
"vite-plugin-svgr": "^4.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
//TODO - Add hyperlinks to text
|
||||
//TODO - Styling
|
||||
import DocsGPT3 from './assets/cute_docsgpt3.svg';
|
||||
|
||||
export default function About() {
|
||||
return (
|
||||
<div className="mx-5 grid min-h-screen md:mx-36">
|
||||
<article className="place-items-left mx-auto my-auto flex w-full max-w-6xl flex-col gap-4 rounded-3xl bg-gray-100 p-6 text-jet dark:bg-gun-metal dark:text-bright-gray lg:p-6 xl:p-10">
|
||||
<div className="flex items-center">
|
||||
<p className="mr-2 text-3xl">About DocsGPT</p>
|
||||
<img className="h14 mb-2" src={DocsGPT3} alt="DocsGPT" />
|
||||
</div>
|
||||
<p className="mt-4">
|
||||
Find the information in your documentation through AI-powered
|
||||
<a
|
||||
className="text-blue-500"
|
||||
href="https://github.com/arc53/DocsGPT"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{' '}
|
||||
open-source{' '}
|
||||
</a>
|
||||
chatbot. Powered by GPT-3, Faiss and LangChain.
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<p>
|
||||
If you want to add your own documentation, please follow the
|
||||
instruction below:
|
||||
</p>
|
||||
<p className="ml-2 mt-4">
|
||||
1. Navigate to{' '}
|
||||
<span className="bg-gray-200 italic dark:bg-outer-space">
|
||||
{' '}
|
||||
/application
|
||||
</span>{' '}
|
||||
folder
|
||||
</p>
|
||||
<p className="ml-2 mt-4">
|
||||
2. Install dependencies from{' '}
|
||||
<span className="bg-gray-200 italic dark:bg-outer-space">
|
||||
pip install -r requirements.txt
|
||||
</span>
|
||||
</p>
|
||||
<p className="ml-2 mt-4">
|
||||
3. Prepare a{' '}
|
||||
<span className="bg-gray-200 italic dark:bg-outer-space">.env</span>{' '}
|
||||
file. Copy{' '}
|
||||
<span className="bg-gray-200 italic dark:bg-outer-space">
|
||||
.env_sample
|
||||
</span>{' '}
|
||||
and create{' '}
|
||||
<span className="bg-gray-200 italic dark:bg-outer-space">.env</span>{' '}
|
||||
with your OpenAI API token
|
||||
</p>
|
||||
<p className="ml-2 mt-4">
|
||||
4. Run the app with{' '}
|
||||
<span className="bg-gray-200 italic dark:bg-outer-space">
|
||||
python app.py
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Currently It uses{' '}
|
||||
<span className="font-medium text-blue-950">DocsGPT</span>{' '}
|
||||
documentation, so it will respond to information relevant to{' '}
|
||||
<span className="font-medium text-blue-950">DocsGPT</span>. If you
|
||||
want to train it on different documentation - please follow
|
||||
<a
|
||||
className="text-blue-500"
|
||||
href="https://github.com/arc53/DocsGPT/wiki/How-to-train-on-other-documentation"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{' '}
|
||||
this guide
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
|
||||
<p className="mt-4 text-left">
|
||||
If you want to launch it on your own server - follow
|
||||
<a
|
||||
className="text-blue-500"
|
||||
href="https://github.com/arc53/DocsGPT/wiki/Hosting-the-app"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{' '}
|
||||
this guide
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</article>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -30,8 +30,8 @@ function AuthWrapper({ children }: { children: React.ReactNode }) {
|
||||
}
|
||||
|
||||
function MainLayout() {
|
||||
const { isMobile } = useMediaQuery();
|
||||
const [navOpen, setNavOpen] = useState(!isMobile);
|
||||
const { isMobile, isTablet } = useMediaQuery();
|
||||
const [navOpen, setNavOpen] = useState(!(isMobile || isTablet));
|
||||
|
||||
return (
|
||||
<div className="relative h-screen overflow-hidden dark:bg-raisin-black">
|
||||
@@ -39,7 +39,7 @@ function MainLayout() {
|
||||
<ActionButtons showNewChat={true} showShare={true} />
|
||||
<div
|
||||
className={`h-[calc(100dvh-64px)] overflow-auto lg:h-screen ${
|
||||
!isMobile
|
||||
!(isMobile || isTablet)
|
||||
? `ml-0 ${!navOpen ? 'lg:mx-auto' : 'lg:ml-72'}`
|
||||
: 'ml-0 lg:ml-16'
|
||||
}`}
|
||||
@@ -65,7 +65,6 @@ export default function App() {
|
||||
}
|
||||
>
|
||||
<Route index element={<Conversation />} />
|
||||
<Route path="/about" element={<About />} />
|
||||
<Route path="/settings/*" element={<Setting />} />
|
||||
<Route path="/agents/*" element={<Agents />} />
|
||||
</Route>
|
||||
|
||||
@@ -71,7 +71,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
const sharedAgents = useSelector(selectSharedAgents);
|
||||
const selectedAgent = useSelector(selectSelectedAgent);
|
||||
|
||||
const { isMobile } = useMediaQuery();
|
||||
const { isMobile, isTablet } = useMediaQuery();
|
||||
const [isDarkTheme] = useDarkTheme();
|
||||
const { showTokenModal, handleTokenSubmit } = useTokenAuth();
|
||||
|
||||
@@ -162,7 +162,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
const handleAgentClick = (agent: Agent) => {
|
||||
resetConversation();
|
||||
dispatch(setSelectedAgent(agent));
|
||||
if (isMobile) setNavOpen(!navOpen);
|
||||
if (isMobile || isTablet) setNavOpen(!navOpen);
|
||||
navigate('/');
|
||||
};
|
||||
|
||||
@@ -197,6 +197,9 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
query: { conversationId: index },
|
||||
}),
|
||||
);
|
||||
if (isMobile || isTablet) {
|
||||
setNavOpen(false);
|
||||
}
|
||||
if (data.agent_id) {
|
||||
if (data.is_shared_usage) {
|
||||
userService
|
||||
@@ -271,8 +274,8 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setNavOpen(!isMobile);
|
||||
}, [isMobile]);
|
||||
setNavOpen(!(isMobile || isTablet));
|
||||
}, [isMobile, isTablet]);
|
||||
|
||||
useDefaultDocument();
|
||||
return (
|
||||
@@ -352,7 +355,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
<NavLink
|
||||
to={'/'}
|
||||
onClick={() => {
|
||||
if (isMobile) {
|
||||
if (isMobile || isTablet) {
|
||||
setNavOpen(!navOpen);
|
||||
}
|
||||
resetConversation();
|
||||
@@ -415,7 +418,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className={`${isMobile ? 'flex' : 'invisible flex group-hover:visible'} items-center px-3`}
|
||||
className={`${isMobile || isTablet ? 'flex' : 'invisible flex group-hover:visible'} items-center px-3`}
|
||||
>
|
||||
<button
|
||||
className="rounded-full hover:opacity-75"
|
||||
@@ -437,6 +440,9 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
className="mx-4 my-auto mt-2 flex h-9 cursor-pointer items-center gap-2 rounded-3xl pl-4 hover:bg-bright-gray dark:hover:bg-dark-charcoal"
|
||||
onClick={() => {
|
||||
dispatch(setSelectedAgent(null));
|
||||
if (isMobile || isTablet) {
|
||||
setNavOpen(false);
|
||||
}
|
||||
navigate('/agents');
|
||||
}}
|
||||
>
|
||||
@@ -448,7 +454,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
/>
|
||||
</div>
|
||||
<p className="overflow-hidden overflow-ellipsis whitespace-nowrap text-sm leading-6 text-eerie-black dark:text-bright-gray">
|
||||
Manage Agents
|
||||
{t('manageAgents')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -456,7 +462,13 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
) : (
|
||||
<div
|
||||
className="mx-4 my-auto mt-2 flex h-9 cursor-pointer items-center gap-2 rounded-3xl pl-4 hover:bg-bright-gray dark:hover:bg-dark-charcoal"
|
||||
onClick={() => navigate('/agents')}
|
||||
onClick={() => {
|
||||
if (isMobile || isTablet) {
|
||||
setNavOpen(false);
|
||||
}
|
||||
dispatch(setSelectedAgent(null));
|
||||
navigate('/agents');
|
||||
}}
|
||||
>
|
||||
<div className="flex w-6 justify-center">
|
||||
<img
|
||||
@@ -466,7 +478,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
/>
|
||||
</div>
|
||||
<p className="overflow-hidden overflow-ellipsis whitespace-nowrap text-sm leading-6 text-eerie-black dark:text-bright-gray">
|
||||
Manage Agents
|
||||
{t('manageAgents')}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
@@ -502,8 +514,8 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
|
||||
<div className="flex flex-col gap-2 border-b-[1px] py-2 dark:border-b-purple-taupe">
|
||||
<NavLink
|
||||
onClick={() => {
|
||||
if (isMobile) {
|
||||
setNavOpen(!navOpen);
|
||||
if (isMobile || isTablet) {
|
||||
setNavOpen(false);
|
||||
}
|
||||
resetConversation();
|
||||
}}
|
||||
|
||||
@@ -30,7 +30,17 @@ export default function ContextMenu({
|
||||
offset = { x: 0, y: 8 },
|
||||
}: ContextMenuProps) {
|
||||
const menuRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen && menuRef.current) {
|
||||
const positionStyle = getMenuPosition();
|
||||
if (menuRef.current) {
|
||||
Object.assign(menuRef.current.style, {
|
||||
top: positionStyle.top,
|
||||
left: positionStyle.left,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [isOpen]);
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
@@ -61,20 +71,45 @@ export default function ContextMenu({
|
||||
let top = rect.bottom + scrollY + offset.y;
|
||||
let left = rect.right + scrollX + offset.x;
|
||||
|
||||
// Get menu dimensions (need ref to be available)
|
||||
const menuWidth = menuRef.current?.offsetWidth || 144; // Default min-width
|
||||
const menuHeight = menuRef.current?.offsetHeight || 0;
|
||||
|
||||
// Get viewport dimensions
|
||||
const viewportWidth = window.innerWidth;
|
||||
const viewportHeight = window.innerHeight;
|
||||
|
||||
// Adjust position based on specified position
|
||||
switch (position) {
|
||||
case 'bottom-left':
|
||||
left = rect.left + scrollX - offset.x;
|
||||
break;
|
||||
case 'top-right':
|
||||
top = rect.top + scrollY - offset.y;
|
||||
top = rect.top + scrollY - offset.y - menuHeight;
|
||||
break;
|
||||
case 'top-left':
|
||||
top = rect.top + scrollY - offset.y;
|
||||
top = rect.top + scrollY - offset.y - menuHeight;
|
||||
left = rect.left + scrollX - offset.x;
|
||||
break;
|
||||
// bottom-right is default
|
||||
}
|
||||
|
||||
if (left + menuWidth > viewportWidth) {
|
||||
left = Math.max(5, viewportWidth - menuWidth - 5);
|
||||
}
|
||||
|
||||
if (left < 5) {
|
||||
left = 5;
|
||||
}
|
||||
|
||||
if (top + menuHeight > viewportHeight + scrollY) {
|
||||
top = rect.top + scrollY - menuHeight - offset.y;
|
||||
}
|
||||
|
||||
if (top < scrollY + 5) {
|
||||
top = rect.bottom + scrollY + offset.y;
|
||||
}
|
||||
|
||||
return {
|
||||
position: 'fixed',
|
||||
top: `${top}px`,
|
||||
@@ -90,7 +125,7 @@ export default function ContextMenu({
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div
|
||||
className="flex w-32 flex-col rounded-xl bg-lotion text-sm shadow-xl dark:bg-charleston-green-2 md:w-36"
|
||||
className="flex flex-col rounded-xl bg-lotion text-sm shadow-xl dark:bg-charleston-green-2"
|
||||
style={{ minWidth: '144px' }}
|
||||
>
|
||||
{options.map((option, index) => (
|
||||
@@ -109,7 +144,7 @@ export default function ContextMenu({
|
||||
} `}
|
||||
>
|
||||
{option.icon && (
|
||||
<div className="flex w-4 justify-center">
|
||||
<div className="flex w-4 min-w-4 flex-shrink-0 justify-center">
|
||||
<img
|
||||
width={option.iconWidth || 16}
|
||||
height={option.iconHeight || 16}
|
||||
@@ -119,7 +154,7 @@ export default function ContextMenu({
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<span>{option.label}</span>
|
||||
<span className="hyphens-auto break-words">{option.label}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -60,7 +60,11 @@ const Input = ({
|
||||
{placeholder && (
|
||||
<label
|
||||
htmlFor={id}
|
||||
className={`absolute select-none ${hasValue ? '-top-2.5 left-3 text-xs' : ''} px-2 transition-all peer-placeholder-shown:left-3 peer-placeholder-shown:top-2.5 peer-placeholder-shown:${textSizeStyles[textSize]} pointer-events-none cursor-none text-gray-4000 peer-focus:-top-2.5 peer-focus:left-3 peer-focus:text-xs dark:text-gray-400 ${labelBgClassName}`}
|
||||
className={`absolute select-none ${
|
||||
hasValue ? '-top-2.5 left-3 text-xs' : ''
|
||||
} px-2 transition-all peer-placeholder-shown:left-3 peer-placeholder-shown:top-2.5 peer-placeholder-shown:${
|
||||
textSizeStyles[textSize]
|
||||
} pointer-events-none cursor-none text-gray-4000 peer-focus:-top-2.5 peer-focus:left-3 peer-focus:text-xs dark:text-gray-400 ${labelBgClassName} max-w-[calc(100%-24px)] overflow-hidden text-ellipsis whitespace-nowrap`}
|
||||
>
|
||||
{placeholder}
|
||||
{required && (
|
||||
|
||||
@@ -207,7 +207,7 @@ export default function SourcesPopup({
|
||||
className="inline-flex items-center gap-2 text-base font-medium text-violets-are-blue"
|
||||
onClick={onClose}
|
||||
>
|
||||
Go to Documents
|
||||
{t('settings.documents.goToDocuments')}
|
||||
<img src={RedirectIcon} alt="Redirect" className="h-3 w-3" />
|
||||
</a>
|
||||
</div>
|
||||
@@ -217,7 +217,7 @@ export default function SourcesPopup({
|
||||
onClick={handleUploadClick}
|
||||
className="w-auto rounded-full border border-violets-are-blue px-4 py-2 text-[14px] font-medium text-violets-are-blue transition-colors duration-200 hover:bg-violets-are-blue hover:text-white"
|
||||
>
|
||||
Upload new
|
||||
{t('settings.documents.uploadNew')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -35,21 +35,21 @@ export function useOutsideAlerter<T extends HTMLElement>(
|
||||
|
||||
export function useMediaQuery() {
|
||||
const mobileQuery = '(max-width: 768px)';
|
||||
const darkModeQuery = '(prefers-color-scheme: dark)'; // Detect dark mode
|
||||
const desktopQuery = '(min-width: 960px)';
|
||||
const tabletQuery = '(max-width: 1023px)';
|
||||
const desktopQuery = '(min-width: 1024px)';
|
||||
const [isMobile, setIsMobile] = useState(false);
|
||||
const [isTablet, setIsTablet] = useState(false);
|
||||
const [isDesktop, setIsDesktop] = useState(false);
|
||||
const [isDarkMode, setIsDarkMode] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const mobileMedia = window.matchMedia(mobileQuery);
|
||||
const tabletMedia = window.matchMedia(tabletQuery);
|
||||
const desktopMedia = window.matchMedia(desktopQuery);
|
||||
const darkModeMedia = window.matchMedia(darkModeQuery);
|
||||
|
||||
const updateMediaQueries = () => {
|
||||
setIsMobile(mobileMedia.matches);
|
||||
setIsTablet(tabletMedia.matches && !mobileMedia.matches); // Tablet but not mobile
|
||||
setIsDesktop(desktopMedia.matches);
|
||||
setIsDarkMode(darkModeMedia.matches);
|
||||
};
|
||||
|
||||
updateMediaQueries();
|
||||
@@ -60,9 +60,9 @@ export function useMediaQuery() {
|
||||
return () => {
|
||||
window.removeEventListener('resize', listener);
|
||||
};
|
||||
}, [mobileQuery, desktopQuery, darkModeQuery]);
|
||||
}, [mobileQuery, tabletQuery, desktopQuery]);
|
||||
|
||||
return { isMobile, isDesktop, isDarkMode };
|
||||
return { isMobile, isTablet, isDesktop };
|
||||
}
|
||||
|
||||
export function useDarkTheme() {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"help": "Help",
|
||||
"emailUs": "Email us",
|
||||
"documentation": "Documentation",
|
||||
"manageAgents": "Manage Agents",
|
||||
"demo": [
|
||||
{
|
||||
"header": "Learn about DocsGPT",
|
||||
@@ -72,7 +73,13 @@
|
||||
},
|
||||
"actions": "Actions",
|
||||
"view": "View",
|
||||
"deleteWarning": "Are you sure you want to delete \"{{name}}\"?"
|
||||
"deleteWarning": "Are you sure you want to delete \"{{name}}\"?",
|
||||
"backToAll": "Back to all documents",
|
||||
"chunks": "Chunks",
|
||||
"noChunks": "No chunks found",
|
||||
"noChunksAlt": "No chunks found",
|
||||
"goToDocuments": "Go to Documents",
|
||||
"uploadNew": "Upload new"
|
||||
},
|
||||
"apiKeys": {
|
||||
"label": "Chatbots",
|
||||
@@ -125,7 +132,36 @@
|
||||
"deleteWarning": "Are you sure you want to delete the tool \"{{toolName}}\" ?",
|
||||
"unsavedChanges": "You have unsaved changes that will be lost if you leave without saving.",
|
||||
"leaveWithoutSaving": "Leave without Saving",
|
||||
"saveAndLeave": "Save and Leave"
|
||||
"saveAndLeave": "Save and Leave",
|
||||
"customName": "Custom Name",
|
||||
"customNamePlaceholder": "Enter a custom name (optional)",
|
||||
"authentication": "Authentication",
|
||||
"actions": "Actions",
|
||||
"addAction": "Add action",
|
||||
"noActionsFound": "No actions found",
|
||||
"url": "URL",
|
||||
"urlPlaceholder": "Enter URL",
|
||||
"method": "Method",
|
||||
"description": "Description",
|
||||
"descriptionPlaceholder": "Enter description",
|
||||
"headers": "Headers",
|
||||
"queryParameters": "Query Parameters",
|
||||
"body": "Body",
|
||||
"deleteActionWarning": "Are you sure you want to delete the action \"{{name}}\"?",
|
||||
"backToAllTools": "Back to all tools",
|
||||
"save": "Save",
|
||||
"fieldName": "Field Name",
|
||||
"fieldType": "Field Type",
|
||||
"filledByLLM": "Filled by LLM",
|
||||
"fieldDescription": "Field description",
|
||||
"value": "Value",
|
||||
"addProperty": "Add property",
|
||||
"propertyName": "New property key",
|
||||
"add": "Add",
|
||||
"cancel": "Cancel",
|
||||
"addNew": "Add New",
|
||||
"name": "Name",
|
||||
"type": "Type"
|
||||
}
|
||||
},
|
||||
"modals": {
|
||||
@@ -210,6 +246,18 @@
|
||||
"promptText": "Prompt Text",
|
||||
"save": "Save",
|
||||
"nameExists": "Name already exists"
|
||||
},
|
||||
"chunk": {
|
||||
"add": "Add Chunk",
|
||||
"edit": "Edit Chunk",
|
||||
"title": "Title",
|
||||
"enterTitle": "Enter title",
|
||||
"bodyText": "Body text",
|
||||
"promptText": "Prompt Text",
|
||||
"update": "Update",
|
||||
"close": "Close",
|
||||
"delete": "Delete",
|
||||
"deleteConfirmation": "Are you sure you want to delete this chunk?"
|
||||
}
|
||||
},
|
||||
"sharedConv": {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"help": "Asistencia",
|
||||
"emailUs": "Envíanos un correo",
|
||||
"documentation": "Documentación",
|
||||
"manageAgents": "Administrar Agentes",
|
||||
"demo": [
|
||||
{
|
||||
"header": "Aprende sobre DocsGPT",
|
||||
@@ -48,7 +49,8 @@
|
||||
"medium": "Medio",
|
||||
"high": "Alto",
|
||||
"unlimited": "Ilimitado",
|
||||
"default": "Predeterminado"
|
||||
"default": "Predeterminado",
|
||||
"addNew": "Añadir Nuevo"
|
||||
},
|
||||
"documents": {
|
||||
"title": "Esta tabla contiene todos los documentos que están disponibles para ti y los que has subido",
|
||||
@@ -71,7 +73,13 @@
|
||||
},
|
||||
"actions": "Acciones",
|
||||
"view": "Ver",
|
||||
"deleteWarning": "¿Estás seguro de que deseas eliminar \"{{name}}\"?"
|
||||
"deleteWarning": "¿Estás seguro de que deseas eliminar \"{{name}}\"?",
|
||||
"backToAll": "Volver a todos los documentos",
|
||||
"chunks": "Fragmentos",
|
||||
"noChunks": "No se encontraron fragmentos",
|
||||
"noChunksAlt": "No se encontraron fragmentos",
|
||||
"goToDocuments": "Ir a Documentos",
|
||||
"uploadNew": "Subir nuevo"
|
||||
},
|
||||
"apiKeys": {
|
||||
"label": "Chatbots",
|
||||
@@ -116,8 +124,44 @@
|
||||
"noToolsFound": "No se encontraron herramientas",
|
||||
"selectToolSetup": "Seleccione una herramienta para configurar",
|
||||
"settingsIconAlt": "Icono de configuración",
|
||||
"configureToolAria": "Configurar {toolName}",
|
||||
"toggleToolAria": "Alternar {toolName}"
|
||||
"configureToolAria": "Configurar {{toolName}}",
|
||||
"toggleToolAria": "Alternar {{toolName}}",
|
||||
"manageTools": "Ir a Herramientas",
|
||||
"edit": "Editar",
|
||||
"delete": "Eliminar",
|
||||
"deleteWarning": "¿Estás seguro de que deseas eliminar la herramienta \"{{toolName}}\"?",
|
||||
"unsavedChanges": "Tienes cambios sin guardar que se perderán si sales sin guardar.",
|
||||
"leaveWithoutSaving": "Salir sin Guardar",
|
||||
"saveAndLeave": "Guardar y Salir",
|
||||
"customName": "Nombre Personalizado",
|
||||
"customNamePlaceholder": "Ingresa un nombre personalizado (opcional)",
|
||||
"authentication": "Autenticación",
|
||||
"actions": "Acciones",
|
||||
"addAction": "Agregar acción",
|
||||
"noActionsFound": "No se encontraron acciones",
|
||||
"url": "URL",
|
||||
"urlPlaceholder": "Ingresa url",
|
||||
"method": "Método",
|
||||
"description": "Descripción",
|
||||
"descriptionPlaceholder": "Ingresa descripción",
|
||||
"headers": "Encabezados",
|
||||
"queryParameters": "Parámetros de Consulta",
|
||||
"body": "Cuerpo",
|
||||
"deleteActionWarning": "¿Estás seguro de que deseas eliminar la acción \"{{name}}\"?",
|
||||
"save": "Guardar",
|
||||
"name": "Nombre",
|
||||
"type": "Tipo",
|
||||
"filledByLLM": "Completado por LLM",
|
||||
"value": "Valor",
|
||||
"addProperty": "Agregar propiedad",
|
||||
"propertyName": "Nueva clave de propiedad",
|
||||
"backToAllTools": "Volver a todas las herramientas",
|
||||
"fieldName": "Nombre del campo",
|
||||
"fieldType": "Tipo de campo",
|
||||
"fieldDescription": "Descripción del campo",
|
||||
"add": "Añadir",
|
||||
"cancel": "Cancelar",
|
||||
"addNew": "Añadir Nuevo"
|
||||
}
|
||||
},
|
||||
"modals": {
|
||||
@@ -202,6 +246,18 @@
|
||||
"promptText": "Texto del Prompt",
|
||||
"save": "Guardar",
|
||||
"nameExists": "El nombre ya existe"
|
||||
},
|
||||
"chunk": {
|
||||
"add": "Agregar Fragmento",
|
||||
"edit": "Editar Fragmento",
|
||||
"title": "Título",
|
||||
"enterTitle": "Ingresar título",
|
||||
"bodyText": "Texto del cuerpo",
|
||||
"promptText": "Texto del prompt",
|
||||
"update": "Actualizar",
|
||||
"close": "Cerrar",
|
||||
"delete": "Eliminar",
|
||||
"deleteConfirmation": "¿Estás seguro de que deseas eliminar este fragmento?"
|
||||
}
|
||||
},
|
||||
"sharedConv": {
|
||||
@@ -235,9 +291,9 @@
|
||||
},
|
||||
"sources": {
|
||||
"title": "Fuentes",
|
||||
"text": "Texto fuente",
|
||||
"link": "Enlace fuente",
|
||||
"view_more": "Ver {{count}} más fuentes"
|
||||
"view_more": "Ver {{count}} más fuentes",
|
||||
"text": "Elegir tus fuentes"
|
||||
},
|
||||
"attachments": {
|
||||
"attach": "Adjuntar",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"help": "ヘルプ",
|
||||
"emailUs": "メールを送る",
|
||||
"documentation": "ドキュメント",
|
||||
"manageAgents": "エージェント管理",
|
||||
"demo": [
|
||||
{
|
||||
"header": "DocsGPTについて学ぶ",
|
||||
@@ -52,6 +53,7 @@
|
||||
"add": "追加"
|
||||
},
|
||||
"documents": {
|
||||
"title": "この表には、利用可能なすべてのドキュメントとアップロードしたドキュメントが含まれています",
|
||||
"label": "ドキュメント",
|
||||
"name": "ドキュメント名",
|
||||
"date": "ベクトル日付",
|
||||
@@ -71,7 +73,13 @@
|
||||
},
|
||||
"actions": "アクション",
|
||||
"view": "表示",
|
||||
"deleteWarning": "\"{{name}}\"を削除してもよろしいですか?"
|
||||
"deleteWarning": "\"{{name}}\"を削除してもよろしいですか?",
|
||||
"backToAll": "すべてのドキュメントに戻る",
|
||||
"chunks": "チャンク",
|
||||
"noChunks": "チャンクが見つかりません",
|
||||
"noChunksAlt": "チャンクが見つかりません",
|
||||
"goToDocuments": "ドキュメントへ移動",
|
||||
"uploadNew": "新規アップロード"
|
||||
},
|
||||
"apiKeys": {
|
||||
"label": "チャットボット",
|
||||
@@ -96,7 +104,6 @@
|
||||
},
|
||||
"messages": "メッセージ",
|
||||
"tokenUsage": "トークン使用量",
|
||||
"feedback": "フィードバック",
|
||||
"filterPlaceholder": "フィルター",
|
||||
"none": "なし",
|
||||
"positiveFeedback": "肯定的なフィードバック",
|
||||
@@ -117,8 +124,44 @@
|
||||
"noToolsFound": "ツールが見つかりません",
|
||||
"selectToolSetup": "設定するツールを選択してください",
|
||||
"settingsIconAlt": "設定アイコン",
|
||||
"configureToolAria": "{toolName} を設定",
|
||||
"toggleToolAria": "{toolName} を切り替え"
|
||||
"configureToolAria": "{{toolName}}を設定",
|
||||
"toggleToolAria": "{{toolName}}を切り替え",
|
||||
"manageTools": "ツールへ移動",
|
||||
"edit": "編集",
|
||||
"delete": "削除",
|
||||
"deleteWarning": "ツール \"{{toolName}}\" を削除してもよろしいですか?",
|
||||
"unsavedChanges": "保存されていない変更があります。保存せずに離れると失われます。",
|
||||
"leaveWithoutSaving": "保存せずに離れる",
|
||||
"saveAndLeave": "保存して離れる",
|
||||
"customName": "カスタム名",
|
||||
"customNamePlaceholder": "カスタム名を入力(任意)",
|
||||
"authentication": "認証",
|
||||
"actions": "アクション",
|
||||
"addAction": "アクションを追加",
|
||||
"noActionsFound": "アクションが見つかりません",
|
||||
"url": "URL",
|
||||
"urlPlaceholder": "URLを入力",
|
||||
"method": "メソッド",
|
||||
"description": "説明",
|
||||
"descriptionPlaceholder": "説明を入力",
|
||||
"headers": "ヘッダー",
|
||||
"queryParameters": "クエリパラメータ",
|
||||
"body": "ボディ",
|
||||
"deleteActionWarning": "アクション \"{{name}}\" を削除してもよろしいですか?",
|
||||
"backToAllTools": "すべてのツールに戻る",
|
||||
"save": "保存",
|
||||
"fieldName": "フィールド名",
|
||||
"fieldType": "フィールドタイプ",
|
||||
"filledByLLM": "LLMによる入力",
|
||||
"fieldDescription": "フィールドの説明",
|
||||
"value": "値",
|
||||
"addProperty": "プロパティを追加",
|
||||
"propertyName": "新しいプロパティキー",
|
||||
"add": "追加",
|
||||
"cancel": "キャンセル",
|
||||
"addNew": "新規追加",
|
||||
"name": "名前",
|
||||
"type": "タイプ"
|
||||
}
|
||||
},
|
||||
"modals": {
|
||||
@@ -203,6 +246,18 @@
|
||||
"promptText": "プロンプトテキスト",
|
||||
"save": "保存",
|
||||
"nameExists": "名前が既に存在します"
|
||||
},
|
||||
"chunk": {
|
||||
"add": "チャンクを追加",
|
||||
"edit": "チャンクを編集",
|
||||
"title": "タイトル",
|
||||
"enterTitle": "タイトルを入力",
|
||||
"bodyText": "本文",
|
||||
"promptText": "プロンプトテキスト",
|
||||
"update": "更新",
|
||||
"close": "閉じる",
|
||||
"delete": "削除",
|
||||
"deleteConfirmation": "このチャンクを削除してもよろしいですか?"
|
||||
}
|
||||
},
|
||||
"sharedConv": {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"help": "Помощь",
|
||||
"emailUs": "Напишите нам",
|
||||
"documentation": "Документация",
|
||||
"manageAgents": "Управление агентами",
|
||||
"demo": [
|
||||
{
|
||||
"header": "Узнайте о DocsGPT",
|
||||
@@ -72,7 +73,13 @@
|
||||
},
|
||||
"actions": "Действия",
|
||||
"view": "Просмотр",
|
||||
"deleteWarning": "Вы уверены, что хотите удалить \"{{name}}\"?"
|
||||
"deleteWarning": "Вы уверены, что хотите удалить \"{{name}}\"?",
|
||||
"backToAll": "Вернуться ко всем документам",
|
||||
"chunks": "Фрагменты",
|
||||
"noChunks": "Фрагменты не найдены",
|
||||
"noChunksAlt": "Фрагменты не найдены",
|
||||
"goToDocuments": "Перейти к документам",
|
||||
"uploadNew": "Загрузить новый"
|
||||
},
|
||||
"apiKeys": {
|
||||
"label": "API ключи",
|
||||
@@ -116,9 +123,45 @@
|
||||
"addTool": "Добавить инструмент",
|
||||
"noToolsFound": "Инструменты не найдены",
|
||||
"selectToolSetup": "Выберите инструмент для настройки",
|
||||
"settingsIconAlt": "Иконка настроек",
|
||||
"configureToolAria": "Настроить {toolName}",
|
||||
"toggleToolAria": "Переключить {toolName}"
|
||||
"settingsIconAlt": "Значок настроек",
|
||||
"configureToolAria": "Настроить {{toolName}}",
|
||||
"toggleToolAria": "Переключить {{toolName}}",
|
||||
"manageTools": "Перейти к инструментам",
|
||||
"edit": "Редактировать",
|
||||
"delete": "Удалить",
|
||||
"deleteWarning": "Вы уверены, что хотите удалить инструмент \"{{toolName}}\"?",
|
||||
"unsavedChanges": "У вас есть несохраненные изменения, которые будут потеряны, если вы уйдете без сохранения.",
|
||||
"leaveWithoutSaving": "Уйти без сохранения",
|
||||
"saveAndLeave": "Сохранить и уйти",
|
||||
"customName": "Пользовательское имя",
|
||||
"customNamePlaceholder": "Введите пользовательское имя (необязательно)",
|
||||
"authentication": "Аутентификация",
|
||||
"actions": "Действия",
|
||||
"addAction": "Добавить действие",
|
||||
"noActionsFound": "Действия не найдены",
|
||||
"url": "URL",
|
||||
"urlPlaceholder": "Введите URL",
|
||||
"method": "Метод",
|
||||
"description": "Описание",
|
||||
"descriptionPlaceholder": "Введите описание",
|
||||
"headers": "Заголовки",
|
||||
"queryParameters": "Параметры запроса",
|
||||
"body": "Тело запроса",
|
||||
"deleteActionWarning": "Вы уверены, что хотите удалить действие \"{{name}}\"?",
|
||||
"backToAllTools": "Вернуться ко всем инструментам",
|
||||
"save": "Сохранить",
|
||||
"fieldName": "Имя поля",
|
||||
"fieldType": "Тип поля",
|
||||
"filledByLLM": "Заполняется LLM",
|
||||
"fieldDescription": "Описание поля",
|
||||
"value": "Значение",
|
||||
"addProperty": "Добавить свойство",
|
||||
"propertyName": "Новый ключ свойства",
|
||||
"add": "Добавить",
|
||||
"cancel": "Отмена",
|
||||
"addNew": "Добавить новое",
|
||||
"name": "Имя",
|
||||
"type": "Тип"
|
||||
}
|
||||
},
|
||||
"modals": {
|
||||
@@ -203,6 +246,18 @@
|
||||
"promptText": "Текст подсказки",
|
||||
"save": "Сохранить",
|
||||
"nameExists": "Название уже существует"
|
||||
},
|
||||
"chunk": {
|
||||
"add": "Добавить фрагмент",
|
||||
"edit": "Редактировать фрагмент",
|
||||
"title": "Заголовок",
|
||||
"enterTitle": "Введите заголовок",
|
||||
"bodyText": "Текст",
|
||||
"promptText": "Текст подсказки",
|
||||
"update": "Обновить",
|
||||
"close": "Закрыть",
|
||||
"delete": "Удалить",
|
||||
"deleteConfirmation": "Вы уверены, что хотите удалить этот фрагмент?"
|
||||
}
|
||||
},
|
||||
"sharedConv": {
|
||||
@@ -236,7 +291,7 @@
|
||||
},
|
||||
"sources": {
|
||||
"title": "Источники",
|
||||
"text": "Текст источника",
|
||||
"text": "Выберите ваши источники",
|
||||
"link": "Ссылка на источник",
|
||||
"view_more": "ещё {{count}} источников"
|
||||
},
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"help": "幫助",
|
||||
"emailUs": "給我們發電郵",
|
||||
"documentation": "文件",
|
||||
"manageAgents": "管理代理",
|
||||
"demo": [
|
||||
{
|
||||
"header": "了解 DocsGPT",
|
||||
@@ -72,7 +73,13 @@
|
||||
},
|
||||
"actions": "操作",
|
||||
"view": "查看",
|
||||
"deleteWarning": "您確定要刪除 \"{{name}}\" 嗎?"
|
||||
"deleteWarning": "您確定要刪除 \"{{name}}\" 嗎?",
|
||||
"backToAll": "返回所有文件",
|
||||
"chunks": "文本塊",
|
||||
"noChunks": "未找到文本塊",
|
||||
"noChunksAlt": "未找到文本塊",
|
||||
"goToDocuments": "前往文件",
|
||||
"uploadNew": "上傳新文件"
|
||||
},
|
||||
"apiKeys": {
|
||||
"label": "聊天機器人",
|
||||
@@ -112,13 +119,49 @@
|
||||
},
|
||||
"tools": {
|
||||
"label": "工具",
|
||||
"searchPlaceholder": "搜尋...",
|
||||
"searchPlaceholder": "搜尋工具...",
|
||||
"addTool": "新增工具",
|
||||
"noToolsFound": "找不到工具",
|
||||
"selectToolSetup": "選擇要設定的工具",
|
||||
"settingsIconAlt": "設定圖標",
|
||||
"configureToolAria": "配置 {toolName}",
|
||||
"toggleToolAria": "切換 {toolName}"
|
||||
"settingsIconAlt": "設定圖示",
|
||||
"configureToolAria": "設定 {{toolName}}",
|
||||
"toggleToolAria": "切換 {{toolName}}",
|
||||
"manageTools": "前往工具",
|
||||
"edit": "編輯",
|
||||
"delete": "刪除",
|
||||
"deleteWarning": "您確定要刪除工具 \"{{toolName}}\" 嗎?",
|
||||
"unsavedChanges": "您有未儲存的變更,如果不儲存就離開將會遺失。",
|
||||
"leaveWithoutSaving": "不儲存離開",
|
||||
"saveAndLeave": "儲存並離開",
|
||||
"customName": "自訂名稱",
|
||||
"customNamePlaceholder": "輸入自訂名稱(選填)",
|
||||
"authentication": "認證",
|
||||
"actions": "操作",
|
||||
"addAction": "新增操作",
|
||||
"noActionsFound": "找不到操作",
|
||||
"url": "URL",
|
||||
"urlPlaceholder": "輸入url",
|
||||
"method": "方法",
|
||||
"description": "描述",
|
||||
"descriptionPlaceholder": "輸入描述",
|
||||
"headers": "標頭",
|
||||
"queryParameters": "查詢參數",
|
||||
"body": "主體",
|
||||
"deleteActionWarning": "您確定要刪除操作 \"{{name}}\" 嗎?",
|
||||
"backToAllTools": "返回所有工具",
|
||||
"save": "儲存",
|
||||
"fieldName": "欄位名稱",
|
||||
"fieldType": "欄位類型",
|
||||
"filledByLLM": "由LLM填入",
|
||||
"fieldDescription": "欄位描述",
|
||||
"value": "值",
|
||||
"addProperty": "新增屬性",
|
||||
"propertyName": "新屬性鍵",
|
||||
"add": "新增",
|
||||
"cancel": "取消",
|
||||
"addNew": "新增",
|
||||
"name": "名稱",
|
||||
"type": "類型"
|
||||
}
|
||||
},
|
||||
"modals": {
|
||||
@@ -203,6 +246,18 @@
|
||||
"promptText": "提示文字",
|
||||
"save": "儲存",
|
||||
"nameExists": "名稱已存在"
|
||||
},
|
||||
"chunk": {
|
||||
"add": "新增區塊",
|
||||
"edit": "編輯區塊",
|
||||
"title": "標題",
|
||||
"enterTitle": "輸入標題",
|
||||
"bodyText": "內文",
|
||||
"promptText": "提示文字",
|
||||
"update": "更新",
|
||||
"close": "關閉",
|
||||
"delete": "刪除",
|
||||
"deleteConfirmation": "您確定要刪除此區塊嗎?"
|
||||
}
|
||||
},
|
||||
"sharedConv": {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"help": "帮助",
|
||||
"emailUs": "给我们发邮件",
|
||||
"documentation": "文档",
|
||||
"manageAgents": "管理代理",
|
||||
"demo": [
|
||||
{
|
||||
"header": "了解 DocsGPT",
|
||||
@@ -72,7 +73,13 @@
|
||||
},
|
||||
"actions": "操作",
|
||||
"view": "查看",
|
||||
"deleteWarning": "您确定要删除 \"{{name}}\" 吗?"
|
||||
"deleteWarning": "您确定要删除 \"{{name}}\" 吗?",
|
||||
"backToAll": "返回所有文档",
|
||||
"chunks": "文本块",
|
||||
"noChunks": "未找到文本块",
|
||||
"noChunksAlt": "未找到文本块",
|
||||
"goToDocuments": "前往文档",
|
||||
"uploadNew": "上传新文档"
|
||||
},
|
||||
"apiKeys": {
|
||||
"label": "聊天机器人",
|
||||
@@ -112,13 +119,49 @@
|
||||
},
|
||||
"tools": {
|
||||
"label": "工具",
|
||||
"searchPlaceholder": "搜索...",
|
||||
"searchPlaceholder": "搜索工具...",
|
||||
"addTool": "添加工具",
|
||||
"noToolsFound": "未找到工具",
|
||||
"selectToolSetup": "选择要设置的工具",
|
||||
"settingsIconAlt": "设置图标",
|
||||
"configureToolAria": "配置 {toolName}",
|
||||
"toggleToolAria": "切换 {toolName}"
|
||||
"configureToolAria": "配置 {{toolName}}",
|
||||
"toggleToolAria": "切换 {{toolName}}",
|
||||
"manageTools": "前往工具",
|
||||
"edit": "编辑",
|
||||
"delete": "删除",
|
||||
"deleteWarning": "您确定要删除工具 \"{{toolName}}\" 吗?",
|
||||
"unsavedChanges": "您有未保存的更改,如果不保存就离开将会丢失。",
|
||||
"leaveWithoutSaving": "不保存离开",
|
||||
"saveAndLeave": "保存并离开",
|
||||
"customName": "自定义名称",
|
||||
"customNamePlaceholder": "输入自定义名称(可选)",
|
||||
"authentication": "认证",
|
||||
"actions": "操作",
|
||||
"addAction": "添加操作",
|
||||
"noActionsFound": "未找到操作",
|
||||
"url": "URL",
|
||||
"urlPlaceholder": "输入url",
|
||||
"method": "方法",
|
||||
"description": "描述",
|
||||
"descriptionPlaceholder": "输入描述",
|
||||
"headers": "请求头",
|
||||
"queryParameters": "查询参数",
|
||||
"body": "请求体",
|
||||
"deleteActionWarning": "您确定要删除操作 \"{{name}}\" 吗?",
|
||||
"backToAllTools": "返回所有工具",
|
||||
"save": "保存",
|
||||
"fieldName": "字段名称",
|
||||
"fieldType": "字段类型",
|
||||
"filledByLLM": "由LLM填充",
|
||||
"fieldDescription": "字段描述",
|
||||
"value": "值",
|
||||
"addProperty": "添加属性",
|
||||
"propertyName": "新属性键",
|
||||
"add": "添加",
|
||||
"cancel": "取消",
|
||||
"addNew": "添加新的",
|
||||
"name": "名称",
|
||||
"type": "类型"
|
||||
}
|
||||
},
|
||||
"modals": {
|
||||
@@ -203,6 +246,18 @@
|
||||
"promptText": "提示文本",
|
||||
"save": "保存",
|
||||
"nameExists": "名称已存在"
|
||||
},
|
||||
"chunk": {
|
||||
"add": "添加块",
|
||||
"edit": "编辑块",
|
||||
"title": "标题",
|
||||
"enterTitle": "输入标题",
|
||||
"bodyText": "正文",
|
||||
"promptText": "提示文本",
|
||||
"update": "更新",
|
||||
"close": "关闭",
|
||||
"delete": "删除",
|
||||
"deleteConfirmation": "您确定要删除此块吗?"
|
||||
}
|
||||
},
|
||||
"sharedConv": {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import Exit from '../assets/exit.svg';
|
||||
import Input from '../components/Input';
|
||||
import { ActiveState } from '../models/misc';
|
||||
import ConfirmationModal from './ConfirmationModal';
|
||||
import WrapperModal from './WrapperModal';
|
||||
|
||||
export default function ChunkModal({
|
||||
type,
|
||||
@@ -22,6 +23,7 @@ export default function ChunkModal({
|
||||
originalText?: string;
|
||||
handleDelete?: () => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [title, setTitle] = React.useState('');
|
||||
const [chunkText, setChunkText] = React.useState('');
|
||||
const [deleteModal, setDeleteModal] = React.useState<ActiveState>('INACTIVE');
|
||||
@@ -30,157 +32,105 @@ export default function ChunkModal({
|
||||
setTitle(originalTitle || '');
|
||||
setChunkText(originalText || '');
|
||||
}, [originalTitle, originalText]);
|
||||
if (type === 'ADD') {
|
||||
return (
|
||||
<div
|
||||
className={`${
|
||||
modalState === 'ACTIVE' ? 'visible' : 'hidden'
|
||||
} fixed left-0 top-0 z-30 flex h-screen w-screen items-center justify-center bg-gray-alpha`}
|
||||
>
|
||||
<article className="flex w-11/12 flex-col gap-4 rounded-2xl bg-white shadow-lg dark:bg-[#26272E] sm:w-[620px]">
|
||||
<div className="relative">
|
||||
<button
|
||||
className="absolute right-4 top-3 m-2 w-3"
|
||||
onClick={() => {
|
||||
setModalState('INACTIVE');
|
||||
}}
|
||||
>
|
||||
<img className="filter dark:invert" src={Exit} />
|
||||
</button>
|
||||
<div className="p-6">
|
||||
<h2 className="px-3 text-xl font-semibold text-jet dark:text-bright-gray">
|
||||
Add Chunk
|
||||
</h2>
|
||||
<div className="relative mt-6 px-3">
|
||||
<span className="absolute -top-2 left-5 z-10 bg-white px-2 text-xs text-gray-4000 dark:bg-[#26272E] dark:text-silver">
|
||||
Title
|
||||
</span>
|
||||
<Input
|
||||
type="text"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
borderVariant="thin"
|
||||
placeholder={'Enter title'}
|
||||
labelBgClassName="bg-white dark:bg-charleston-green-2"
|
||||
></Input>
|
||||
</div>
|
||||
<div className="relative mt-6 px-3">
|
||||
<div className="rounded-lg border border-silver pb-1 pt-3 dark:border-silver/40">
|
||||
<span className="absolute -top-2 left-5 rounded-lg bg-white px-2 text-xs text-gray-4000 dark:bg-[#26272E] dark:text-silver">
|
||||
Body text
|
||||
</span>
|
||||
<textarea
|
||||
id="chunk-body-text"
|
||||
className="h-60 w-full px-3 outline-none dark:bg-transparent dark:text-white"
|
||||
value={chunkText}
|
||||
onChange={(e) => setChunkText(e.target.value)}
|
||||
aria-label="Prompt Text"
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-8 flex flex-row-reverse gap-1 px-3">
|
||||
<button
|
||||
onClick={() => {
|
||||
handleSubmit(title, chunkText);
|
||||
setModalState('INACTIVE');
|
||||
}}
|
||||
className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-violets-are-blue"
|
||||
>
|
||||
Add
|
||||
</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>
|
||||
|
||||
if (modalState !== 'ACTIVE') return null;
|
||||
|
||||
const content = (
|
||||
<div>
|
||||
<h2 className="px-3 text-xl font-semibold text-jet dark:text-bright-gray">
|
||||
{t(`modals.chunk.${type === 'ADD' ? 'add' : 'edit'}`)}
|
||||
</h2>
|
||||
<div className="relative mt-6 px-3">
|
||||
<Input
|
||||
type="text"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
borderVariant="thin"
|
||||
placeholder={t('modals.chunk.title')}
|
||||
labelBgClassName="bg-white dark:bg-charleston-green-2"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div
|
||||
className={`${
|
||||
modalState === 'ACTIVE' ? 'visible' : 'hidden'
|
||||
} fixed left-0 top-0 z-30 flex h-screen w-screen items-center justify-center bg-gray-alpha`}
|
||||
>
|
||||
<article className="flex w-11/12 flex-col gap-4 rounded-2xl bg-white shadow-lg dark:bg-[#26272E] sm:w-[620px]">
|
||||
<div className="relative">
|
||||
<div className="relative mt-6 px-3">
|
||||
<div className="rounded-lg border border-silver pb-1 pt-3 dark:border-silver/40">
|
||||
<span className="absolute -top-2 left-5 rounded-lg bg-white px-2 text-xs text-gray-4000 dark:bg-[#26272E] dark:text-silver">
|
||||
{t('modals.chunk.bodyText')}
|
||||
</span>
|
||||
<textarea
|
||||
id="chunk-body-text"
|
||||
className="h-60 max-h-60 w-full resize-none px-3 outline-none dark:bg-transparent dark:text-white"
|
||||
value={chunkText}
|
||||
onChange={(e) => setChunkText(e.target.value)}
|
||||
aria-label={t('modals.chunk.promptText')}
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{type === 'ADD' ? (
|
||||
<div className="mt-8 flex flex-row-reverse gap-1 px-3">
|
||||
<button
|
||||
onClick={() => {
|
||||
handleSubmit(title, chunkText);
|
||||
setModalState('INACTIVE');
|
||||
}}
|
||||
className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-violets-are-blue"
|
||||
>
|
||||
{t('modals.chunk.add')}
|
||||
</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"
|
||||
>
|
||||
{t('modals.chunk.close')}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-8 flex w-full items-center justify-between px-3">
|
||||
<button
|
||||
className="text-nowrap rounded-full border border-solid border-red-500 px-5 py-2 text-sm text-red-500 hover:bg-red-500 hover:text-white"
|
||||
onClick={() => {
|
||||
setDeleteModal('ACTIVE');
|
||||
}}
|
||||
>
|
||||
{t('modals.chunk.delete')}
|
||||
</button>
|
||||
<div className="flex flex-row-reverse gap-1">
|
||||
<button
|
||||
onClick={() => {
|
||||
handleSubmit(title, chunkText);
|
||||
setModalState('INACTIVE');
|
||||
}}
|
||||
className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-violets-are-blue"
|
||||
>
|
||||
{t('modals.chunk.update')}
|
||||
</button>
|
||||
<button
|
||||
className="absolute right-4 top-3 m-2 w-3"
|
||||
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"
|
||||
>
|
||||
<img className="filter dark:invert" src={Exit} />
|
||||
{t('modals.chunk.close')}
|
||||
</button>
|
||||
<div className="p-6">
|
||||
<h2 className="px-3 text-xl font-semibold text-jet dark:text-bright-gray">
|
||||
Edit Chunk
|
||||
</h2>
|
||||
<div className="relative mt-6 px-3">
|
||||
<Input
|
||||
type="text"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
borderVariant="thin"
|
||||
placeholder={'Enter title'}
|
||||
labelBgClassName="bg-white dark:bg-charleston-green-2"
|
||||
></Input>
|
||||
</div>
|
||||
<div className="relative mt-6 px-3">
|
||||
<div className="rounded-lg border border-silver pb-1 pt-3 dark:border-silver/40">
|
||||
<span className="absolute -top-2 left-5 rounded-lg bg-white px-2 text-xs text-gray-4000 dark:bg-[#26272E] dark:text-silver">
|
||||
Body text
|
||||
</span>
|
||||
<textarea
|
||||
id="chunk-body-text"
|
||||
className="h-60 w-full px-3 outline-none dark:bg-transparent dark:text-white"
|
||||
value={chunkText}
|
||||
onChange={(e) => setChunkText(e.target.value)}
|
||||
aria-label="Prompt Text"
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-8 flex w-full items-center justify-between px-3">
|
||||
<button
|
||||
className="text-nowrap rounded-full border border-solid border-red-500 px-5 py-2 text-sm text-red-500 hover:bg-red-500 hover:text-white"
|
||||
onClick={() => {
|
||||
setDeleteModal('ACTIVE');
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
<div className="flex flex-row-reverse gap-1">
|
||||
<button
|
||||
onClick={() => {
|
||||
handleSubmit(title, chunkText);
|
||||
setModalState('INACTIVE');
|
||||
}}
|
||||
className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:bg-violets-are-blue"
|
||||
>
|
||||
Update
|
||||
</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>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<WrapperModal
|
||||
close={() => setModalState('INACTIVE')}
|
||||
className="sm:w-[620px]"
|
||||
>
|
||||
{content}
|
||||
</WrapperModal>
|
||||
|
||||
{type === 'EDIT' && (
|
||||
<ConfirmationModal
|
||||
message="Are you sure you want to delete this chunk?"
|
||||
message={t('modals.chunk.deleteConfirmation')}
|
||||
modalState={deleteModal}
|
||||
setModalState={setDeleteModal}
|
||||
handleSubmit={
|
||||
@@ -190,9 +140,9 @@ export default function ChunkModal({
|
||||
/* no-op */
|
||||
}
|
||||
}
|
||||
submitLabel="Delete"
|
||||
submitLabel={t('modals.chunk.delete')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ function AddPrompt({
|
||||
</label>
|
||||
<textarea
|
||||
id="new-prompt-content"
|
||||
className="h-56 w-full rounded-lg border-2 border-silver px-3 py-2 outline-none dark:border-silver/40 dark:bg-transparent dark:text-white"
|
||||
className="h-56 w-full resize-none rounded-lg border-2 border-silver px-3 py-2 outline-none dark:border-silver/40 dark:bg-transparent dark:text-white"
|
||||
value={newPromptContent}
|
||||
onChange={(e) => setNewPromptContent(e.target.value)}
|
||||
aria-label="Prompt Text"
|
||||
@@ -123,7 +123,7 @@ function EditPrompt({
|
||||
</label>
|
||||
<textarea
|
||||
id="edit-prompt-content"
|
||||
className="h-56 w-full rounded-lg border-2 border-silver px-3 py-2 outline-none dark:border-silver/40 dark:bg-transparent dark:text-white"
|
||||
className="h-56 w-full resize-none rounded-lg border-2 border-silver px-3 py-2 outline-none dark:border-silver/40 dark:bg-transparent dark:text-white"
|
||||
value={editPromptContent}
|
||||
onChange={(e) => setEditPromptContent(e.target.value)}
|
||||
aria-label="Prompt Text"
|
||||
|
||||
@@ -312,7 +312,7 @@ export default function Documents({
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
className="flex h-[32px] w-[108px] items-center justify-center rounded-full bg-purple-30 text-sm text-white hover:bg-violets-are-blue"
|
||||
className="flex h-[32px] min-w-[108px] items-center justify-center whitespace-normal rounded-full bg-purple-30 px-4 text-sm text-white hover:bg-violets-are-blue"
|
||||
title={t('settings.documents.addNew')}
|
||||
onClick={() => {
|
||||
setIsOnboarding(false);
|
||||
@@ -450,7 +450,7 @@ export default function Documents({
|
||||
options={getActionOptions(index, document)}
|
||||
anchorRef={getMenuRef(docId)}
|
||||
position="bottom-left"
|
||||
offset={{ x: 48, y: -24 }}
|
||||
offset={{ x: 48, y: 0 }}
|
||||
className="z-50"
|
||||
/>
|
||||
</div>
|
||||
@@ -641,11 +641,11 @@ function DocumentChunks({
|
||||
>
|
||||
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
|
||||
</button>
|
||||
<p className="mt-px">Back to all documents</p>
|
||||
<p className="mt-px">{t('settings.documents.backToAll')}</p>
|
||||
</div>
|
||||
<div className="my-3 flex items-center justify-between gap-1">
|
||||
<div className="flex w-full items-center gap-2 text-eerie-black dark:text-bright-gray sm:w-auto">
|
||||
<p className="hidden text-2xl font-semibold sm:flex">{`${totalChunks} Chunks`}</p>
|
||||
<p className="hidden text-2xl font-semibold sm:flex">{`${totalChunks} ${t('settings.documents.chunks')}`}</p>
|
||||
<label htmlFor="chunk-search-input" className="sr-only">
|
||||
{t('settings.documents.searchPlaceholder')}
|
||||
</label>
|
||||
@@ -663,7 +663,7 @@ function DocumentChunks({
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
className="flex h-[32px] w-[108px] items-center justify-center rounded-full bg-purple-30 text-sm text-white hover:bg-violets-are-blue"
|
||||
className="flex h-[32px] min-w-[108px] items-center justify-center whitespace-normal rounded-full bg-purple-30 px-4 text-sm text-white hover:bg-violets-are-blue"
|
||||
title={t('settings.documents.addNew')}
|
||||
onClick={() => setAddModal('ACTIVE')}
|
||||
>
|
||||
@@ -687,10 +687,10 @@ function DocumentChunks({
|
||||
<div className="col-span-2 mt-24 text-center text-gray-500 dark:text-gray-400 lg:col-span-3">
|
||||
<img
|
||||
src={isDarkTheme ? NoFilesDarkIcon : NoFilesIcon}
|
||||
alt="No tools found"
|
||||
alt={t('settings.documents.noChunksAlt')}
|
||||
className="mx-auto mb-2 h-24 w-24"
|
||||
/>
|
||||
No chunks found
|
||||
{t('settings.documents.noChunks')}
|
||||
</div>
|
||||
) : (
|
||||
paginatedChunks
|
||||
|
||||
@@ -16,6 +16,9 @@ import { selectToken } from '../preferences/preferenceSlice';
|
||||
import { APIActionType, APIToolType, UserToolType } from './types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { areObjectsEqual } from '../utils/objectUtils';
|
||||
import { useDarkTheme } from '../hooks';
|
||||
import NoFilesIcon from '../assets/no-files.svg';
|
||||
import NoFilesDarkIcon from '../assets/no-files-dark.svg';
|
||||
|
||||
export default function ToolConfig({
|
||||
tool,
|
||||
@@ -44,6 +47,7 @@ export default function ToolConfig({
|
||||
const [hasUnsavedChanges, setHasUnsavedChanges] = React.useState(false);
|
||||
const [showUnsavedModal, setShowUnsavedModal] = React.useState(false);
|
||||
const { t } = useTranslation();
|
||||
const [isDarkTheme] = useDarkTheme();
|
||||
|
||||
const handleBackClick = () => {
|
||||
if (hasUnsavedChanges) {
|
||||
@@ -165,19 +169,19 @@ export default function ToolConfig({
|
||||
>
|
||||
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
|
||||
</button>
|
||||
<p className="mt-px">Back to all tools</p>
|
||||
<p className="mt-px">{t('settings.tools.backToAllTools')}</p>
|
||||
</div>
|
||||
<button
|
||||
className="text-nowrap rounded-full bg-purple-30 px-3 py-2 text-xs text-white hover:bg-violets-are-blue sm:px-4 sm:py-2"
|
||||
onClick={handleSaveChanges}
|
||||
>
|
||||
Save
|
||||
{t('settings.tools.save')}
|
||||
</button>
|
||||
</div>
|
||||
{/* Custom name section */}
|
||||
<div className="mt-1">
|
||||
<p className="text-sm font-semibold text-eerie-black dark:text-bright-gray">
|
||||
Custom Name
|
||||
{t('settings.tools.customName')}
|
||||
</p>
|
||||
<div className="relative mt-4 w-full max-w-96">
|
||||
<Input
|
||||
@@ -185,14 +189,14 @@ export default function ToolConfig({
|
||||
value={customName}
|
||||
onChange={(e) => setCustomName(e.target.value)}
|
||||
borderVariant="thin"
|
||||
placeholder="Enter a custom name (optional)"
|
||||
placeholder={t('settings.tools.customNamePlaceholder')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-1">
|
||||
{Object.keys(tool?.config).length !== 0 && tool.name !== 'api_tool' && (
|
||||
<p className="text-sm font-semibold text-eerie-black dark:text-bright-gray">
|
||||
Authentication
|
||||
{t('settings.tools.authentication')}
|
||||
</p>
|
||||
)}
|
||||
<div className="mt-4 flex flex-col items-start gap-2 sm:flex-row sm:items-center">
|
||||
@@ -211,201 +215,227 @@ export default function ToolConfig({
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="mx-1 my-2 h-[0.8px] w-full rounded-full bg-[#C4C4C4]/40 lg:w-[95%]"></div>
|
||||
<div className="mx-0 my-2 h-[0.8px] w-full rounded-full bg-[#C4C4C4]/40"></div>
|
||||
<div className="flex w-full flex-row items-center justify-between gap-2">
|
||||
<p className="text-base font-semibold text-eerie-black dark:text-bright-gray">
|
||||
Actions
|
||||
{t('settings.tools.actions')}
|
||||
</p>
|
||||
</div>
|
||||
{tool.name === 'api_tool' ? (
|
||||
<>
|
||||
<APIToolConfig tool={tool as APIToolType} setTool={setTool} />
|
||||
<div className="mt-4 flex justify-end">
|
||||
{tool.name === 'api_tool' &&
|
||||
(!tool.config.actions ||
|
||||
Object.keys(tool.config.actions).length === 0) && (
|
||||
<button
|
||||
onClick={() => setActionModalState('ACTIVE')}
|
||||
className="rounded-full border border-solid border-violets-are-blue px-5 py-1 text-sm text-violets-are-blue transition-colors hover:bg-violets-are-blue hover:text-white"
|
||||
>
|
||||
Add action
|
||||
{t('settings.tools.addAction')}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{tool.name === 'api_tool' ? (
|
||||
<>
|
||||
{tool.config.actions &&
|
||||
Object.keys(tool.config.actions).length > 0 ? (
|
||||
<APIToolConfig tool={tool as APIToolType} setTool={setTool} />
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center py-8">
|
||||
<img
|
||||
src={isDarkTheme ? NoFilesDarkIcon : NoFilesIcon}
|
||||
alt="No actions found"
|
||||
className="mx-auto mb-4 h-24 w-24"
|
||||
/>
|
||||
<p className="text-center text-gray-500 dark:text-gray-400">
|
||||
{t('settings.tools.noActionsFound')}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div className="flex flex-col gap-12">
|
||||
{'actions' in tool &&
|
||||
tool.actions.map((action, actionIndex) => {
|
||||
return (
|
||||
<div
|
||||
key={actionIndex}
|
||||
className="w-full rounded-xl border border-silver dark:border-silver/40"
|
||||
>
|
||||
<div className="flex h-10 flex-wrap items-center justify-between rounded-t-xl border-b border-silver bg-[#F9F9F9] px-5 dark:border-silver/40 dark:bg-[#28292D]">
|
||||
<p className="font-semibold text-eerie-black dark:text-bright-gray">
|
||||
{action.name}
|
||||
</p>
|
||||
<ToggleSwitch
|
||||
checked={action.active}
|
||||
onChange={(checked) => {
|
||||
setTool({
|
||||
...tool,
|
||||
actions: tool.actions.map((act, index) => {
|
||||
if (index === actionIndex) {
|
||||
return { ...act, active: checked };
|
||||
}
|
||||
return act;
|
||||
}),
|
||||
});
|
||||
}}
|
||||
size="small"
|
||||
id={`actionToggle-${actionIndex}`}
|
||||
/>
|
||||
</div>
|
||||
<div className="relative mt-5 w-full px-5">
|
||||
<Input
|
||||
type="text"
|
||||
className="w-full"
|
||||
placeholder="Enter description"
|
||||
value={action.description}
|
||||
onChange={(e) => {
|
||||
setTool({
|
||||
...tool,
|
||||
actions: tool.actions.map((act, index) => {
|
||||
if (index === actionIndex) {
|
||||
return {
|
||||
...act,
|
||||
description: e.target.value,
|
||||
};
|
||||
}
|
||||
return act;
|
||||
}),
|
||||
});
|
||||
}}
|
||||
borderVariant="thin"
|
||||
/>
|
||||
</div>
|
||||
<div className="px-5 py-4">
|
||||
<table className="table-default">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field Name</th>
|
||||
<th>Field Type</th>
|
||||
<th>Filled by LLM</th>
|
||||
<th>FIeld description</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{Object.entries(action.parameters?.properties).map(
|
||||
(param, index) => {
|
||||
const uniqueKey = `${actionIndex}-${param[0]}`;
|
||||
return (
|
||||
<tr
|
||||
key={index}
|
||||
className="text-nowrap font-normal"
|
||||
>
|
||||
<td>{param[0]}</td>
|
||||
<td>{param[1].type}</td>
|
||||
<td>
|
||||
<label
|
||||
htmlFor={uniqueKey}
|
||||
className="ml-[10px] flex cursor-pointer items-start gap-4"
|
||||
>
|
||||
<div className="flex items-center">
|
||||
​
|
||||
<input
|
||||
checked={param[1].filled_by_llm}
|
||||
id={uniqueKey}
|
||||
type="checkbox"
|
||||
className="size-4 rounded border-gray-300 bg-transparent"
|
||||
onChange={() =>
|
||||
handleCheckboxChange(
|
||||
actionIndex,
|
||||
param[0],
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
</td>
|
||||
<td className="w-10">
|
||||
<input
|
||||
key={uniqueKey}
|
||||
value={param[1].description}
|
||||
className="rounded-lg border border-silver bg-transparent px-2 py-1 text-sm outline-none dark:border-silver/40"
|
||||
onChange={(e) => {
|
||||
setTool({
|
||||
...tool,
|
||||
actions: tool.actions.map(
|
||||
(act, index) => {
|
||||
if (index === actionIndex) {
|
||||
return {
|
||||
...act,
|
||||
parameters: {
|
||||
...act.parameters,
|
||||
properties: {
|
||||
...act.parameters
|
||||
.properties,
|
||||
[param[0]]: {
|
||||
...act.parameters
|
||||
.properties[param[0]],
|
||||
description:
|
||||
e.target.value,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
return act;
|
||||
},
|
||||
),
|
||||
});
|
||||
}}
|
||||
></input>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
value={param[1].value}
|
||||
key={uniqueKey}
|
||||
disabled={param[1].filled_by_llm}
|
||||
className={`rounded-lg border border-silver bg-transparent px-2 py-1 text-sm outline-none dark:border-silver/40 ${param[1].filled_by_llm ? 'opacity-50' : ''}`}
|
||||
onChange={(e) => {
|
||||
setTool({
|
||||
...tool,
|
||||
actions: tool.actions.map(
|
||||
(act, index) => {
|
||||
if (index === actionIndex) {
|
||||
return {
|
||||
...act,
|
||||
parameters: {
|
||||
...act.parameters,
|
||||
properties: {
|
||||
...act.parameters
|
||||
.properties,
|
||||
[param[0]]: {
|
||||
...act.parameters
|
||||
.properties[param[0]],
|
||||
value: e.target.value,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
return act;
|
||||
},
|
||||
),
|
||||
});
|
||||
}}
|
||||
></input>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
},
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{'actions' in tool && tool.actions && tool.actions.length > 0 ? (
|
||||
tool.actions.map((action, actionIndex) => (
|
||||
<div
|
||||
key={actionIndex}
|
||||
className="w-full rounded-xl border border-silver dark:border-silver/40"
|
||||
>
|
||||
<div className="flex h-10 flex-wrap items-center justify-between rounded-t-xl border-b border-silver bg-[#F9F9F9] px-5 dark:border-silver/40 dark:bg-[#28292D]">
|
||||
<p className="font-semibold text-eerie-black dark:text-bright-gray">
|
||||
{action.name}
|
||||
</p>
|
||||
<ToggleSwitch
|
||||
checked={action.active}
|
||||
onChange={(checked) => {
|
||||
setTool({
|
||||
...tool,
|
||||
actions: tool.actions.map((act, index) => {
|
||||
if (index === actionIndex) {
|
||||
return { ...act, active: checked };
|
||||
}
|
||||
return act;
|
||||
}),
|
||||
});
|
||||
}}
|
||||
size="small"
|
||||
id={`actionToggle-${actionIndex}`}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<div className="relative mt-5 w-full px-5">
|
||||
<Input
|
||||
type="text"
|
||||
className="w-full"
|
||||
placeholder={t('settings.tools.descriptionPlaceholder')}
|
||||
value={action.description}
|
||||
onChange={(e) => {
|
||||
setTool({
|
||||
...tool,
|
||||
actions: tool.actions.map((act, index) => {
|
||||
if (index === actionIndex) {
|
||||
return {
|
||||
...act,
|
||||
description: e.target.value,
|
||||
};
|
||||
}
|
||||
return act;
|
||||
}),
|
||||
});
|
||||
}}
|
||||
borderVariant="thin"
|
||||
/>
|
||||
</div>
|
||||
<div className="px-5 py-4">
|
||||
<table className="table-default">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{t('settings.tools.fieldName')}</th>
|
||||
<th>{t('settings.tools.fieldType')}</th>
|
||||
<th>{t('settings.tools.filledByLLM')}</th>
|
||||
<th>{t('settings.tools.fieldDescription')}</th>
|
||||
<th>{t('settings.tools.value')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{Object.entries(action.parameters?.properties).map(
|
||||
(param, index) => {
|
||||
const uniqueKey = `${actionIndex}-${param[0]}`;
|
||||
return (
|
||||
<tr
|
||||
key={index}
|
||||
className="text-nowrap font-normal"
|
||||
>
|
||||
<td>{param[0]}</td>
|
||||
<td>{param[1].type}</td>
|
||||
<td>
|
||||
<label
|
||||
htmlFor={uniqueKey}
|
||||
className="ml-[10px] flex cursor-pointer items-start gap-4"
|
||||
>
|
||||
<div className="flex items-center">
|
||||
​
|
||||
<input
|
||||
checked={param[1].filled_by_llm}
|
||||
id={uniqueKey}
|
||||
type="checkbox"
|
||||
className="size-4 rounded border-gray-300 bg-transparent"
|
||||
onChange={() =>
|
||||
handleCheckboxChange(
|
||||
actionIndex,
|
||||
param[0],
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
</td>
|
||||
<td className="w-10">
|
||||
<input
|
||||
key={uniqueKey}
|
||||
value={param[1].description}
|
||||
className="rounded-lg border border-silver bg-transparent px-2 py-1 text-sm outline-none dark:border-silver/40"
|
||||
onChange={(e) => {
|
||||
setTool({
|
||||
...tool,
|
||||
actions: tool.actions.map(
|
||||
(act, index) => {
|
||||
if (index === actionIndex) {
|
||||
return {
|
||||
...act,
|
||||
parameters: {
|
||||
...act.parameters,
|
||||
properties: {
|
||||
...act.parameters
|
||||
.properties,
|
||||
[param[0]]: {
|
||||
...act.parameters
|
||||
.properties[param[0]],
|
||||
description:
|
||||
e.target.value,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
return act;
|
||||
},
|
||||
),
|
||||
});
|
||||
}}
|
||||
></input>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
value={param[1].value}
|
||||
key={uniqueKey}
|
||||
disabled={param[1].filled_by_llm}
|
||||
className={`rounded-lg border border-silver bg-transparent px-2 py-1 text-sm outline-none dark:border-silver/40 ${param[1].filled_by_llm ? 'opacity-50' : ''}`}
|
||||
onChange={(e) => {
|
||||
setTool({
|
||||
...tool,
|
||||
actions: tool.actions.map(
|
||||
(act, index) => {
|
||||
if (index === actionIndex) {
|
||||
return {
|
||||
...act,
|
||||
parameters: {
|
||||
...act.parameters,
|
||||
properties: {
|
||||
...act.parameters
|
||||
.properties,
|
||||
[param[0]]: {
|
||||
...act.parameters
|
||||
.properties[param[0]],
|
||||
value: e.target.value,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
return act;
|
||||
},
|
||||
),
|
||||
});
|
||||
}}
|
||||
></input>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
},
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center py-8">
|
||||
<img
|
||||
src={isDarkTheme ? NoFilesDarkIcon : NoFilesIcon}
|
||||
alt="No actions found"
|
||||
className="mx-auto mb-4 h-24 w-24"
|
||||
/>
|
||||
<p className="text-center text-gray-500 dark:text-gray-400">
|
||||
{t('settings.tools.noActionsFound')}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<AddActionModal
|
||||
@@ -415,15 +445,10 @@ export default function ToolConfig({
|
||||
/>
|
||||
{showUnsavedModal && (
|
||||
<ConfirmationModal
|
||||
message={t('settings.tools.unsavedChanges', {
|
||||
defaultValue:
|
||||
'You have unsaved changes that will be lost if you leave without saving.',
|
||||
})}
|
||||
message={t('settings.tools.unsavedChanges')}
|
||||
modalState="ACTIVE"
|
||||
setModalState={(state) => setShowUnsavedModal(state === 'ACTIVE')}
|
||||
submitLabel={t('settings.tools.saveAndLeave', {
|
||||
defaultValue: 'Save and Leave',
|
||||
})}
|
||||
submitLabel={t('settings.tools.saveAndLeave')}
|
||||
handleSubmit={() => {
|
||||
userService
|
||||
.updateTool(
|
||||
@@ -447,9 +472,7 @@ export default function ToolConfig({
|
||||
handleGoBack();
|
||||
});
|
||||
}}
|
||||
cancelLabel={t('settings.tools.leaveWithoutSaving', {
|
||||
defaultValue: 'Leave without Saving',
|
||||
})}
|
||||
cancelLabel={t('settings.tools.leaveWithoutSaving')}
|
||||
handleCancel={() => {
|
||||
setShowUnsavedModal(false);
|
||||
handleGoBack();
|
||||
@@ -567,41 +590,36 @@ function APIToolConfig({
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-8 px-5">
|
||||
<div className="relative w-full">
|
||||
<span className="absolute -top-2 left-5 z-10 bg-white px-2 text-xs text-gray-4000 dark:bg-raisin-black dark:text-silver">
|
||||
URL
|
||||
</span>
|
||||
<Input
|
||||
type="text"
|
||||
value={action.url}
|
||||
onChange={(e) => {
|
||||
setApiTool((prevApiTool) => {
|
||||
const updatedActions = {
|
||||
...prevApiTool.config.actions,
|
||||
};
|
||||
const updatedAction = {
|
||||
...updatedActions[actionName],
|
||||
};
|
||||
updatedAction.url = e.target.value;
|
||||
updatedActions[actionName] = updatedAction;
|
||||
return {
|
||||
...prevApiTool,
|
||||
config: {
|
||||
...prevApiTool.config,
|
||||
actions: updatedActions,
|
||||
},
|
||||
};
|
||||
});
|
||||
}}
|
||||
borderVariant="thin"
|
||||
placeholder="Enter url"
|
||||
></Input>
|
||||
</div>
|
||||
<Input
|
||||
type="text"
|
||||
value={action.url}
|
||||
onChange={(e) => {
|
||||
setApiTool((prevApiTool) => {
|
||||
const updatedActions = {
|
||||
...prevApiTool.config.actions,
|
||||
};
|
||||
const updatedAction = {
|
||||
...updatedActions[actionName],
|
||||
};
|
||||
updatedAction.url = e.target.value;
|
||||
updatedActions[actionName] = updatedAction;
|
||||
return {
|
||||
...prevApiTool,
|
||||
config: {
|
||||
...prevApiTool.config,
|
||||
actions: updatedActions,
|
||||
},
|
||||
};
|
||||
});
|
||||
}}
|
||||
borderVariant="thin"
|
||||
placeholder={t('settings.tools.urlPlaceholder')}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-4 px-5 py-2">
|
||||
<div className="relative w-full">
|
||||
<span className="absolute -top-2 left-5 z-10 bg-white px-2 text-xs text-gray-4000 dark:bg-raisin-black dark:text-silver">
|
||||
Method
|
||||
{t('settings.tools.method')}
|
||||
</span>
|
||||
<Dropdown
|
||||
options={['GET', 'POST', 'PUT', 'DELETE']}
|
||||
@@ -636,36 +654,31 @@ function APIToolConfig({
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 px-5 py-2">
|
||||
<div className="relative w-full">
|
||||
<span className="absolute -top-2 left-5 z-10 bg-white px-2 text-xs text-gray-4000 dark:bg-raisin-black dark:text-silver">
|
||||
Description
|
||||
</span>
|
||||
<Input
|
||||
type="text"
|
||||
value={action.description}
|
||||
onChange={(e) => {
|
||||
setApiTool((prevApiTool) => {
|
||||
const updatedActions = {
|
||||
...prevApiTool.config.actions,
|
||||
};
|
||||
const updatedAction = {
|
||||
...updatedActions[actionName],
|
||||
};
|
||||
updatedAction.description = e.target.value;
|
||||
updatedActions[actionName] = updatedAction;
|
||||
return {
|
||||
...prevApiTool,
|
||||
config: {
|
||||
...prevApiTool.config,
|
||||
actions: updatedActions,
|
||||
},
|
||||
};
|
||||
});
|
||||
}}
|
||||
borderVariant="thin"
|
||||
placeholder="Enter description"
|
||||
></Input>
|
||||
</div>
|
||||
<Input
|
||||
type="text"
|
||||
value={action.description}
|
||||
onChange={(e) => {
|
||||
setApiTool((prevApiTool) => {
|
||||
const updatedActions = {
|
||||
...prevApiTool.config.actions,
|
||||
};
|
||||
const updatedAction = {
|
||||
...updatedActions[actionName],
|
||||
};
|
||||
updatedAction.description = e.target.value;
|
||||
updatedActions[actionName] = updatedAction;
|
||||
return {
|
||||
...prevApiTool,
|
||||
config: {
|
||||
...prevApiTool.config,
|
||||
actions: updatedActions,
|
||||
},
|
||||
};
|
||||
});
|
||||
}}
|
||||
borderVariant="thin"
|
||||
placeholder={t('settings.tools.descriptionPlaceholder')}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-4 px-5 py-2">
|
||||
<APIActionTable
|
||||
@@ -682,7 +695,6 @@ function APIToolConfig({
|
||||
<ConfirmationModal
|
||||
message={t('settings.tools.deleteActionWarning', {
|
||||
name: actionToDelete,
|
||||
defaultValue: `Are you sure you want to delete the action "${actionToDelete}"?`,
|
||||
})}
|
||||
modalState={deleteModalState}
|
||||
setModalState={setDeleteModalState}
|
||||
@@ -709,6 +721,8 @@ function APIActionTable({
|
||||
updatedAction: APIActionType,
|
||||
) => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [action, setAction] = React.useState<APIActionType>(apiAction);
|
||||
const [newPropertyKey, setNewPropertyKey] = React.useState('');
|
||||
const [addingPropertySection, setAddingPropertySection] = React.useState<
|
||||
@@ -970,7 +984,7 @@ function APIActionTable({
|
||||
handleAddProperty();
|
||||
}
|
||||
}}
|
||||
placeholder="New property key"
|
||||
placeholder={t('settings.tools.propertyName')}
|
||||
className="flex w-full min-w-[130.5px] items-start rounded-lg border border-silver bg-transparent px-2 py-1 text-sm outline-none dark:border-silver/40"
|
||||
/>
|
||||
</td>
|
||||
@@ -979,15 +993,13 @@ function APIActionTable({
|
||||
onClick={handleAddProperty}
|
||||
className="mr-1 rounded-full bg-purple-30 px-5 py-[4px] text-sm text-white hover:bg-violets-are-blue"
|
||||
>
|
||||
{' '}
|
||||
Add{' '}
|
||||
{t('settings.tools.add')}
|
||||
</button>
|
||||
<button
|
||||
onClick={handleAddPropertyCancel}
|
||||
className="rounded-full border border-solid border-red-500 px-5 py-[4px] text-sm text-red-500 hover:bg-red-500 hover:text-white"
|
||||
>
|
||||
{' '}
|
||||
Cancel{' '}
|
||||
{t('settings.tools.cancel')}
|
||||
</button>
|
||||
</td>
|
||||
<td
|
||||
@@ -1006,7 +1018,7 @@ function APIActionTable({
|
||||
onClick={() => handleAddPropertyStart(section)}
|
||||
className="flex items-start text-nowrap rounded-full border border-solid border-violets-are-blue px-5 py-[4px] text-sm text-violets-are-blue transition-colors hover:bg-violets-are-blue hover:text-white"
|
||||
>
|
||||
Add New Field
|
||||
{t('settings.tools.addNew')}
|
||||
</button>
|
||||
</td>
|
||||
<td
|
||||
@@ -1026,16 +1038,26 @@ function APIActionTable({
|
||||
<div className="scrollbar-thin flex flex-col gap-6">
|
||||
<div>
|
||||
<h3 className="mb-1 text-base font-normal text-eerie-black dark:text-bright-gray">
|
||||
Headers
|
||||
{t('settings.tools.headers')}
|
||||
</h3>
|
||||
<table className="table-default">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Filled by LLM</th>
|
||||
<th>Description</th>
|
||||
<th>Value</th>
|
||||
<th className="px-2 py-1 text-left text-sm font-normal text-eerie-black dark:text-bright-gray">
|
||||
{t('settings.tools.name')}
|
||||
</th>
|
||||
<th className="px-2 py-1 text-left text-sm font-normal text-eerie-black dark:text-bright-gray">
|
||||
{t('settings.tools.type')}
|
||||
</th>
|
||||
<th className="px-2 py-1 text-left text-sm font-normal text-eerie-black dark:text-bright-gray">
|
||||
{t('settings.tools.filledByLLM')}
|
||||
</th>
|
||||
<th className="px-2 py-1 text-left text-sm font-normal text-eerie-black dark:text-bright-gray">
|
||||
{t('settings.tools.description')}
|
||||
</th>
|
||||
<th className="px-2 py-1 text-left text-sm font-normal text-eerie-black dark:text-bright-gray">
|
||||
{t('settings.tools.value')}
|
||||
</th>
|
||||
<th
|
||||
style={{
|
||||
width: '50px',
|
||||
@@ -1051,16 +1073,26 @@ function APIActionTable({
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="mb-1 text-base font-normal text-eerie-black dark:text-bright-gray">
|
||||
Query Parameters
|
||||
{t('settings.tools.queryParameters')}
|
||||
</h3>
|
||||
<table className="table-default">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Filled by LLM</th>
|
||||
<th>Description</th>
|
||||
<th>Value</th>
|
||||
<th className="px-2 py-1 text-left text-sm font-normal text-eerie-black dark:text-bright-gray">
|
||||
{t('settings.tools.name')}
|
||||
</th>
|
||||
<th className="px-2 py-1 text-left text-sm font-normal text-eerie-black dark:text-bright-gray">
|
||||
{t('settings.tools.type')}
|
||||
</th>
|
||||
<th className="px-2 py-1 text-left text-sm font-normal text-eerie-black dark:text-bright-gray">
|
||||
{t('settings.tools.filledByLLM')}
|
||||
</th>
|
||||
<th className="px-2 py-1 text-left text-sm font-normal text-eerie-black dark:text-bright-gray">
|
||||
{t('settings.tools.description')}
|
||||
</th>
|
||||
<th className="px-2 py-1 text-left text-sm font-normal text-eerie-black dark:text-bright-gray">
|
||||
{t('settings.tools.value')}
|
||||
</th>
|
||||
<th
|
||||
style={{
|
||||
width: '50px',
|
||||
@@ -1076,16 +1108,26 @@ function APIActionTable({
|
||||
</div>
|
||||
<div className="mb-6">
|
||||
<h3 className="mb-1 text-base font-normal text-eerie-black dark:text-bright-gray">
|
||||
Body
|
||||
{t('settings.tools.body')}
|
||||
</h3>
|
||||
<table className="table-default">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Filled by LLM</th>
|
||||
<th>Description</th>
|
||||
<th>Value</th>
|
||||
<th className="px-2 py-1 text-left text-sm font-normal text-eerie-black dark:text-bright-gray">
|
||||
{t('settings.tools.name')}
|
||||
</th>
|
||||
<th className="px-2 py-1 text-left text-sm font-normal text-eerie-black dark:text-bright-gray">
|
||||
{t('settings.tools.type')}
|
||||
</th>
|
||||
<th className="px-2 py-1 text-left text-sm font-normal text-eerie-black dark:text-bright-gray">
|
||||
{t('settings.tools.filledByLLM')}
|
||||
</th>
|
||||
<th className="px-2 py-1 text-left text-sm font-normal text-eerie-black dark:text-bright-gray">
|
||||
{t('settings.tools.description')}
|
||||
</th>
|
||||
<th className="px-2 py-1 text-left text-sm font-normal text-eerie-black dark:text-bright-gray">
|
||||
{t('settings.tools.value')}
|
||||
</th>
|
||||
<th
|
||||
style={{
|
||||
width: '50px',
|
||||
|
||||
@@ -157,11 +157,8 @@ export default function Tools() {
|
||||
) : (
|
||||
<div className="mt-8">
|
||||
<div className="relative flex flex-col">
|
||||
<div className="my-3 flex items-center justify-between gap-1">
|
||||
<div className="p-1">
|
||||
<label htmlFor="tool-search-input" className="sr-only">
|
||||
{t('settings.tools.searchPlaceholder')}
|
||||
</label>
|
||||
<div className="my-3 flex flex-col items-start gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div className="w-full sm:w-auto">
|
||||
<Input
|
||||
maxLength={256}
|
||||
placeholder={t('settings.tools.searchPlaceholder')}
|
||||
@@ -174,7 +171,7 @@ export default function Tools() {
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
className="flex h-[30px] w-[108px] items-center justify-center rounded-full bg-purple-30 text-sm text-white hover:bg-violets-are-blue"
|
||||
className="flex h-[32px] min-w-[108px] items-center justify-center whitespace-normal rounded-full bg-purple-30 px-4 text-sm text-white hover:bg-violets-are-blue"
|
||||
onClick={() => {
|
||||
setAddToolModalState('ACTIVE');
|
||||
}}
|
||||
@@ -236,7 +233,7 @@ export default function Tools() {
|
||||
}}
|
||||
options={getMenuOptions(tool)}
|
||||
anchorRef={menuRefs.current[tool.id]}
|
||||
position="top-right"
|
||||
position="bottom-right"
|
||||
offset={{ x: 0, y: 0 }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user