From a7d61b9d59388cd5bf4a5f79e1af8599e462babb Mon Sep 17 00:00:00 2001 From: Aqsa Aqeel <85514520+aqsaaqeel@users.noreply.github.com> Date: Fri, 31 Oct 2025 15:48:13 +0530 Subject: [PATCH] feat: implementing the new custom modal design (#2090) * feat: implementing the new custom modal design * feat: added tool variable dropdown * fix: ui fixes and link fixes * feat: implemented redisgn for edit prompt modal * (feat:prompts) matching figma * (fix:prompts) tool vars * (fix:promptsModal) responsive; disable save on text --------- Co-authored-by: Aqsa Aqeel Co-authored-by: ManishMadan2882 --- frontend/src/assets/book.svg | 3 + frontend/src/components/Dropdown.tsx | 2 +- frontend/src/components/Input.tsx | 3 +- frontend/src/components/types/index.ts | 1 + frontend/src/locale/en.json | 14 +- frontend/src/locale/es.json | 14 +- frontend/src/locale/jp.json | 22 +- frontend/src/locale/ru.json | 28 +- frontend/src/locale/zh-TW.json | 14 +- frontend/src/locale/zh.json | 14 +- frontend/src/preferences/PromptsModal.tsx | 493 ++++++++++++++++++---- 11 files changed, 518 insertions(+), 90 deletions(-) create mode 100644 frontend/src/assets/book.svg diff --git a/frontend/src/assets/book.svg b/frontend/src/assets/book.svg new file mode 100644 index 00000000..596b1114 --- /dev/null +++ b/frontend/src/assets/book.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/components/Dropdown.tsx b/frontend/src/components/Dropdown.tsx index 75bd6a0e..9a14ac27 100644 --- a/frontend/src/components/Dropdown.tsx +++ b/frontend/src/components/Dropdown.tsx @@ -60,7 +60,7 @@ function Dropdown({ }`} > {typeof selectedValue === 'string' ? ( - + {selectedValue} ) : ( diff --git a/frontend/src/components/Input.tsx b/frontend/src/components/Input.tsx index 8764564f..805f2762 100644 --- a/frontend/src/components/Input.tsx +++ b/frontend/src/components/Input.tsx @@ -20,6 +20,7 @@ const Input = ({ onChange, onPaste, onKeyDown, + edgeRoundness = 'rounded-full', }: InputProps) => { const colorStyles = { silver: 'border-silver dark:border-silver/40', @@ -43,7 +44,7 @@ const Input = ({
, ) => void; leftIcon?: React.ReactNode; + edgeRoundness?: string; }; export type MermaidRendererProps = { diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json index b8baa70f..a4ec2bde 100644 --- a/frontend/src/locale/en.json +++ b/frontend/src/locale/en.json @@ -386,8 +386,20 @@ "promptName": "Prompt Name", "promptText": "Prompt Text", "save": "Save", + "cancel": "Cancel", "nameExists": "Name already exists", - "deleteConfirmation": "Are you sure you want to delete the prompt '{{name}}'?" + "deleteConfirmation": "Are you sure you want to delete the prompt '{{name}}'?", + "placeholderText": "Type your prompt text here...", + "addExamplePlaceholder": "Please summarize this text:", + "variablesLabel": "Variables", + "variablesSubtext": "Click To Insert Into Prompt", + "variablesDescription": "Click to insert into prompt", + "systemVariables": "Click to insert into prompt", + "toolVariables": "Tool Variables", + "learnAboutPrompts": "Learn about Prompts →", + "publicPromptEditDisabled": "Public prompts cannot be edited", + "promptTypePublic": "public", + "promptTypePrivate": "private" }, "chunk": { "add": "Add Chunk", diff --git a/frontend/src/locale/es.json b/frontend/src/locale/es.json index ff539a2d..8bdc9b32 100644 --- a/frontend/src/locale/es.json +++ b/frontend/src/locale/es.json @@ -386,8 +386,20 @@ "promptName": "Nombre del Prompt", "promptText": "Texto del Prompt", "save": "Guardar", + "cancel": "Cancelar", "nameExists": "El nombre ya existe", - "deleteConfirmation": "¿Estás seguro de que deseas eliminar el prompt '{{name}}'?" + "deleteConfirmation": "¿Estás seguro de que deseas eliminar el prompt '{{name}}'?", + "placeholderText": "Escribe tu texto de prompt aquí...", + "addExamplePlaceholder": "Por favor, resume este texto:", + "variablesLabel": "Variables", + "variablesSubtext": "Haz clic para insertar en el prompt", + "variablesDescription": "Haz clic para insertar en el prompt", + "systemVariables": "Variables del sistema", + "toolVariables": "Variables de herramientas", + "learnAboutPrompts": "Aprende sobre los Prompts →", + "publicPromptEditDisabled": "Los prompts públicos no se pueden editar", + "promptTypePublic": "público", + "promptTypePrivate": "privado" }, "chunk": { "add": "Agregar Fragmento", diff --git a/frontend/src/locale/jp.json b/frontend/src/locale/jp.json index 50a94428..b3f885f7 100644 --- a/frontend/src/locale/jp.json +++ b/frontend/src/locale/jp.json @@ -380,14 +380,26 @@ }, "prompts": { "addPrompt": "プロンプトを追加", - "addDescription": "カスタムプロンプトを追加してDocsGPTに保存", + "addDescription": "カスタムプロンプトを追加して DocsGPT に保存します", "editPrompt": "プロンプトを編集", - "editDescription": "カスタムプロンプトを編集してDocsGPTに保存", + "editDescription": "カスタムプロンプトを編集して DocsGPT に保存します", "promptName": "プロンプト名", - "promptText": "プロンプトテキスト", + "promptText": "プロンプトのテキスト", "save": "保存", - "nameExists": "名前が既に存在します", - "deleteConfirmation": "プロンプト「{{name}}」を削除してもよろしいですか?" + "cancel": "キャンセル", + "nameExists": "この名前はすでに存在します", + "deleteConfirmation": "プロンプト『{{name}}』を削除してもよろしいですか?", + "placeholderText": "ここにプロンプトのテキストを入力してください…", + "addExamplePlaceholder": "このテキストを要約してください:", + "variablesLabel": "変数", + "variablesSubtext": "クリックしてプロンプトに挿入", + "variablesDescription": "クリックしてプロンプトに挿入", + "systemVariables": "システム変数", + "toolVariables": "ツール変数", + "learnAboutPrompts": "プロンプトについて学ぶ →", + "publicPromptEditDisabled": "公開プロンプトは編集できません", + "promptTypePublic": "公開", + "promptTypePrivate": "非公開" }, "chunk": { "add": "チャンクを追加", diff --git a/frontend/src/locale/ru.json b/frontend/src/locale/ru.json index 18d6ec05..aba8332f 100644 --- a/frontend/src/locale/ru.json +++ b/frontend/src/locale/ru.json @@ -379,15 +379,27 @@ "customNamePlaceholder": "Enter custom name (optional)" }, "prompts": { - "addPrompt": "Добавить подсказку", - "addDescription": "Добавить вашу пользовательскую подсказку и сохранить её в DocsGPT", - "editPrompt": "Редактировать подсказку", - "editDescription": "Редактировать вашу пользовательскую подсказку и сохранить её в DocsGPT", - "promptName": "Название подсказки", - "promptText": "Текст подсказки", + "addPrompt": "Добавить промпт", + "addDescription": "Добавьте свой собственный промпт и сохраните его в DocsGPT", + "editPrompt": "Редактировать промпт", + "editDescription": "Отредактируйте свой промпт и сохраните его в DocsGPT", + "promptName": "Название промпта", + "promptText": "Текст промпта", "save": "Сохранить", - "nameExists": "Название уже существует", - "deleteConfirmation": "Вы уверены, что хотите удалить подсказку «{{name}}»?" + "cancel": "Отмена", + "nameExists": "Имя уже существует", + "deleteConfirmation": "Вы уверены, что хотите удалить промпт «{{name}}»?", + "placeholderText": "Введите текст вашего промпта здесь...", + "addExamplePlaceholder": "Пожалуйста, кратко изложите этот текст:", + "variablesLabel": "Переменные", + "variablesSubtext": "Нажмите, чтобы вставить в промпт", + "variablesDescription": "Нажмите, чтобы вставить в промпт", + "systemVariables": "Системные переменные", + "toolVariables": "Переменные инструментов", + "learnAboutPrompts": "Узнать о промптах →", + "publicPromptEditDisabled": "Публичные промпты нельзя редактировать", + "promptTypePublic": "публичный", + "promptTypePrivate": "приватный" }, "chunk": { "add": "Добавить фрагмент", diff --git a/frontend/src/locale/zh-TW.json b/frontend/src/locale/zh-TW.json index f84cc65a..64f24074 100644 --- a/frontend/src/locale/zh-TW.json +++ b/frontend/src/locale/zh-TW.json @@ -386,8 +386,20 @@ "promptName": "提示名稱", "promptText": "提示文字", "save": "儲存", + "cancel": "取消", "nameExists": "名稱已存在", - "deleteConfirmation": "您確定要刪除提示「{{name}}」嗎?" + "deleteConfirmation": "您確定要刪除提示「{{name}}」嗎?", + "placeholderText": "在此輸入提示內容...", + "addExamplePlaceholder": "請總結此文本:", + "variablesLabel": "變數", + "variablesSubtext": "點擊以插入提示中", + "variablesDescription": "點擊以插入到提示中", + "systemVariables": "點擊以插入提示中", + "toolVariables": "工具變數", + "learnAboutPrompts": "了解提示 →", + "publicPromptEditDisabled": "公共提示無法編輯", + "promptTypePublic": "公共", + "promptTypePrivate": "私人" }, "chunk": { "add": "新增區塊", diff --git a/frontend/src/locale/zh.json b/frontend/src/locale/zh.json index 7b8e5bbf..d1eeb144 100644 --- a/frontend/src/locale/zh.json +++ b/frontend/src/locale/zh.json @@ -387,7 +387,19 @@ "promptText": "提示文本", "save": "保存", "nameExists": "名称已存在", - "deleteConfirmation": "您确定要删除提示'{{name}}'吗?" + "deleteConfirmation": "您确定要删除提示'{{name}}'吗?", + "cancel": "取消", + "placeholderText": "在此輸入提示內容...", + "addExamplePlaceholder": "請總結此文本:", + "variablesLabel": "變數", + "variablesSubtext": "點擊以插入提示中", + "variablesDescription": "點擊以插入到提示中", + "systemVariables": "點擊以插入提示中", + "toolVariables": "工具變數", + "learnAboutPrompts": "了解提示 →", + "publicPromptEditDisabled": "公共提示無法編輯", + "promptTypePublic": "公共", + "promptTypePrivate": "私人" }, "chunk": { "add": "添加块", diff --git a/frontend/src/preferences/PromptsModal.tsx b/frontend/src/preferences/PromptsModal.tsx index 42113475..72193852 100644 --- a/frontend/src/preferences/PromptsModal.tsx +++ b/frontend/src/preferences/PromptsModal.tsx @@ -1,8 +1,77 @@ import { ActiveState } from '../models/misc'; import Input from '../components/Input'; +import { Link } from 'react-router-dom'; + import React from 'react'; import { useTranslation } from 'react-i18next'; +import { useSelector } from 'react-redux'; import WrapperModal from '../modals/WrapperModal'; +import Dropdown from '../components/Dropdown'; +import BookIcon from '../assets/book.svg'; +import userService from '../api/services/userService'; +import { selectToken } from '../preferences/preferenceSlice'; +import { UserToolType } from '../settings/types'; + +// Custom hook for fetching tool variables +const useToolVariables = () => { + const token = useSelector(selectToken); + const [toolVariables, setToolVariables] = React.useState< + { label: string; value: string }[] + >([]); + + React.useEffect(() => { + const fetchToolVariables = async () => { + try { + const response = await userService.getUserTools(token); + const data = await response.json(); + + if (data.success && data.tools) { + const filteredActions: { label: string; value: string }[] = []; + + data.tools.forEach((tool: UserToolType) => { + if (tool.actions && tool.status) { + // Only include active tools + tool.actions.forEach((action: any) => { + if (action.active) { + const canUseAction = + !action.parameters?.properties || + Object.entries(action.parameters.properties).every( + ([paramName, param]: [string, any]) => { + // Parameter is usable if: + // 1. It's filled by LLM (true) OR + // 2. It has a value in the tool config + return ( + param.filled_by_llm === true || + (tool.config && + tool.config[paramName] && + tool.config[paramName] !== '') + ); + }, + ); + + if (canUseAction) { + filteredActions.push({ + label: `${action.name} (${tool.displayName || tool.name})`, + value: `tools.${tool.name}.${action.name}`, + }); + } + } + }); + } + }); + + setToolVariables(filteredActions); + } + } catch (error) { + console.error('Error fetching tool variables:', error); + } + }; + + fetchToolVariables(); + }, [token]); + + return toolVariables; +}; function AddPrompt({ setModalState, @@ -22,52 +91,188 @@ function AddPrompt({ disableSave: boolean; }) { const { t } = useTranslation(); + const toolVariables = useToolVariables(); return (
-

+

{t('modals.prompts.addPrompt')}

-

+

{t('modals.prompts.addDescription')}

setNewPromptName(e.target.value)} labelBgClassName="bg-white dark:bg-[#26272E]" - borderVariant="thin" + borderVariant="thick" /> -
- + +
+
-
- + +
+

+ + {t('modals.prompts.variablesLabel')} + + + {t('modals.prompts.variablesDescription')} + +

+ +
+ { + const textarea = document.getElementById( + 'new-prompt-content', + ) as HTMLTextAreaElement; + if (textarea) { + const cursorPosition = textarea.selectionStart; + const textBefore = newPromptContent.slice(0, cursorPosition); + const textAfter = newPromptContent.slice(cursorPosition); + + // Add leading space if needed + const needsSpace = + cursorPosition > 0 && + newPromptContent.charAt(cursorPosition - 1) !== ' '; + + const newText = + textBefore + + (needsSpace ? ' ' : '') + + `{${option.value}}` + + textAfter; + setNewPromptContent(newText); + + setTimeout(() => { + textarea.focus(); + textarea.setSelectionRange( + cursorPosition + + option.value.length + + 2 + + (needsSpace ? 1 : 0), + cursorPosition + + option.value.length + + 2 + + (needsSpace ? 1 : 0), + ); + }, 0); + } + }} + placeholder="System Variables" + size="w-[140px] sm:w-[185px]" + rounded="3xl" + border="border" + contentSize="text-[12px] sm:text-[14px]" + /> + + { + const textarea = document.getElementById( + 'new-prompt-content', + ) as HTMLTextAreaElement; + if (textarea) { + const cursorPosition = textarea.selectionStart; + const textBefore = newPromptContent.slice(0, cursorPosition); + const textAfter = newPromptContent.slice(cursorPosition); + + // Add leading space if needed + const needsSpace = + cursorPosition > 0 && + newPromptContent.charAt(cursorPosition - 1) !== ' '; + + const newText = + textBefore + + (needsSpace ? ' ' : '') + + `{{ ${option.value} }}` + + textAfter; + setNewPromptContent(newText); + setTimeout(() => { + textarea.focus(); + textarea.setSelectionRange( + cursorPosition + + option.value.length + + 6 + + (needsSpace ? 1 : 0), + cursorPosition + + option.value.length + + 6 + + (needsSpace ? 1 : 0), + ); + }, 0); + } + }} + placeholder="Tool Variables" + size="w-[140px] sm:w-[171px]" + rounded="3xl" + border="border" + contentSize="text-[12px] sm:text-[14px]" + /> +
+
+
+
+ + + + {t('modals.prompts.learnAboutPrompts')} + + +
+ +
+ + + +
); @@ -93,54 +298,191 @@ function EditPrompt({ disableSave: boolean; }) { const { t } = useTranslation(); + const toolVariables = useToolVariables(); return (
-
-

- {t('modals.prompts.editPrompt')} -

-

- {t('modals.prompts.editDescription')} -

-
- setEditPromptName(e.target.value)} - labelBgClassName="bg-white dark:bg-charleston-green-2" - borderVariant="thin" - /> -
- - {t('modals.prompts.promptText')} - -
- +

+ {t('modals.prompts.editPrompt')} +

+

+ {t('modals.prompts.editDescription')} +

+
+ setEditPromptName(e.target.value)} + labelBgClassName="bg-white dark:bg-[#26272E]" + borderVariant="thick" + /> + +
+ /> +
-
+
+ +
+

+ + {t('modals.prompts.variablesLabel')} + + + {t('modals.prompts.variablesDescription')} + +

+ +
+ { + const textarea = document.getElementById( + 'edit-prompt-content', + ) as HTMLTextAreaElement; + if (textarea) { + const cursorPosition = textarea.selectionStart; + const textBefore = editPromptContent.slice(0, cursorPosition); + const textAfter = editPromptContent.slice(cursorPosition); + + // Add leading space if needed + const needsSpace = + cursorPosition > 0 && + editPromptContent.charAt(cursorPosition - 1) !== ' '; + + const newText = + textBefore + + (needsSpace ? ' ' : '') + + `{${option.value}}` + + textAfter; + setEditPromptContent(newText); + + setTimeout(() => { + textarea.focus(); + textarea.setSelectionRange( + cursorPosition + + option.value.length + + 2 + + (needsSpace ? 1 : 0), + cursorPosition + + option.value.length + + 2 + + (needsSpace ? 1 : 0), + ); + }, 0); + } + }} + placeholder="System Variables" + size="w-[140px] sm:w-[185px]" + rounded="3xl" + border="border" + contentSize="text-[12px] sm:text-[14px]" + /> + + { + const textarea = document.getElementById( + 'edit-prompt-content', + ) as HTMLTextAreaElement; + if (textarea) { + const cursorPosition = textarea.selectionStart; + const textBefore = editPromptContent.slice(0, cursorPosition); + const textAfter = editPromptContent.slice(cursorPosition); + + // Add leading space if needed + const needsSpace = + cursorPosition > 0 && + editPromptContent.charAt(cursorPosition - 1) !== ' '; + + const newText = + textBefore + + (needsSpace ? ' ' : '') + + `{{ ${option.value} }}` + + textAfter; + setEditPromptContent(newText); + setTimeout(() => { + textarea.focus(); + textarea.setSelectionRange( + cursorPosition + + option.value.length + + 6 + + (needsSpace ? 1 : 0), + cursorPosition + + option.value.length + + 6 + + (needsSpace ? 1 : 0), + ); + }, 0); + } + }} + placeholder="Tool Variables" + size="w-[140px] sm:w-[171px]" + rounded="3xl" + border="border" + contentSize="text-[12px] sm:text-[14px]" + /> +
+
+
+
+ + + + {t('modals.prompts.learnAboutPrompts')} + + +
+ +
+ +