Are you sure you want to delete this data source link?
`, - deleteSourceModalConfirmText: 'Comfirm', + deleteSourceModalConfirmText: 'Confirm', errorMsg: 'Error message', newDocs: 'New Docs', timeStarted: 'Time started', @@ -736,9 +739,15 @@ Example: https://fsn1.your-objectstorage.com`, google_drivePrimaryAdminTip: 'Email address that has access to the Drive content being synced.', google_driveMyDriveEmailsTip: - 'Comma-separated emails whose “My Drive” contents should be indexed (include the primary admin).', + 'Comma-separated emails whose "My Drive" contents should be indexed (include the primary admin).', google_driveSharedFoldersTip: 'Comma-separated Google Drive folder links to crawl.', + moodleDescription: + 'Connect to your Moodle LMS to sync course content, forums, and resources.', + moodleUrlTip: + 'The base URL of your Moodle instance (e.g., https://moodle.university.edu). Do not include /webservice or /login.', + moodleTokenTip: + 'Generate a web service token in Moodle: Go to Site administration → Server → Web services → Manage tokens. The user must be enrolled in the courses you want to sync.', jiraDescription: 'Connect your Jira workspace to sync issues, comments, and attachments.', jiraBaseUrlTip: @@ -1046,7 +1055,7 @@ Example: https://fsn1.your-objectstorage.com`, downloadFileType: 'Download file type', formatTypeError: 'Format or type error', variableNameMessage: - 'Variable name can only contain letters and underscores', + 'Variable name can only contain letters and underscores and numbers', variableDescription: 'Variable Description', defaultValue: 'Default Value', conversationVariable: 'Conversation variable', diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index 375b2fadc..d2f4b1d16 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -685,6 +685,8 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 tocEnhanceTip: `解析文档时生成了目录信息(见General方法的‘启用目录抽取’),让大模型返回和用户问题相关的目录项,从而利用目录项拿到相关chunk,对这些chunk在排序中进行加权。这种方法来源于模仿人类查询书本中知识的行为逻辑`, }, setting: { + modelEmptyTip: '暂无可用模型,请先在右侧面板添加模型。', + sourceEmptyTip: '暂未添加任何数据源,请从下方选择一个进行连接。', seconds: '秒', minutes: '分', edit: '编辑', @@ -980,7 +982,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 downloadFileTypeTip: '文件下载的类型', downloadFileType: '文件类型', formatTypeError: '格式或类型错误', - variableNameMessage: '名称只能包含字母和下划线', + variableNameMessage: '名称只能包含字母,数字和下划线', variableDescription: '变量的描述', defaultValue: '默认值', conversationVariable: '会话变量', diff --git a/web/src/pages/agent/gobal-variable-sheet/constant.ts b/web/src/pages/agent/gobal-variable-sheet/constant.ts index 935540c15..8470ffa86 100644 --- a/web/src/pages/agent/gobal-variable-sheet/constant.ts +++ b/web/src/pages/agent/gobal-variable-sheet/constant.ts @@ -18,7 +18,7 @@ export const GlobalFormFields = [ placeholder: t('common.namePlaceholder'), required: true, validation: { - pattern: /^[a-zA-Z_]+$/, + pattern: /^[a-zA-Z_0-9]+$/, message: t('flow.variableNameMessage'), }, type: FormFieldType.Text, diff --git a/web/src/pages/agent/gobal-variable-sheet/hooks/use-object-fields.tsx b/web/src/pages/agent/gobal-variable-sheet/hooks/use-object-fields.tsx index 7e60a7aec..c41e766f2 100644 --- a/web/src/pages/agent/gobal-variable-sheet/hooks/use-object-fields.tsx +++ b/web/src/pages/agent/gobal-variable-sheet/hooks/use-object-fields.tsx @@ -3,6 +3,7 @@ import { BlockButton, Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Segmented } from '@/components/ui/segmented'; import { t } from 'i18next'; +import { isEmpty } from 'lodash'; import { Trash2, X } from 'lucide-react'; import { useCallback } from 'react'; import { FieldValues } from 'react-hook-form'; @@ -36,14 +37,19 @@ export const useObjectFields = () => { path: (string | number)[] = [], ): Array<{ path: (string | number)[]; message: string }> => { const errors: Array<{ path: (string | number)[]; message: string }> = []; - - if (obj !== null && typeof obj === 'object' && !Array.isArray(obj)) { + if (typeof obj === 'object' && !Array.isArray(obj)) { + if (isEmpty(obj)) { + errors.push({ + path: [...path], + message: 'No empty parameters are allowed.', + }); + } for (const key in obj) { if (obj.hasOwnProperty(key)) { - if (!/^[a-zA-Z_]+$/.test(key)) { + if (!/^[a-zA-Z_0-9]+$/.test(key)) { errors.push({ path: [...path, key], - message: `Key "${key}" is invalid. Keys can only contain letters and underscores.`, + message: `Key "${key}" is invalid. Keys can only contain letters and underscores and numbers.`, }); } const nestedErrors = validateKeys(obj[key], [...path, key]); @@ -108,6 +114,21 @@ export const useObjectFields = () => { } }, []); + const arrayObjectValidate = useCallback((value: any) => { + try { + if (validateKeys(value, [])?.length > 0) { + throw new Error(t('flow.formatTypeError')); + } + if (value && typeof value === 'string' && !JSON.parse(value)) { + throw new Error(t('flow.formatTypeError')); + } + return true; + } catch (e) { + console.log('object-render-error', e, value); + throw new Error(t('flow.formatTypeError')); + } + }, []); + const arrayStringRender = useCallback((field: FieldValues, type = 'text') => { const values = Array.isArray(field.value) ? field.value @@ -253,8 +274,9 @@ export const useObjectFields = () => { const handleCustomValidate = (value: TypesWithArray) => { switch (value) { case TypesWithArray.Object: - case TypesWithArray.ArrayObject: return objectValidate; + case TypesWithArray.ArrayObject: + return arrayObjectValidate; case TypesWithArray.ArrayString: return arrayStringValidate; case TypesWithArray.ArrayNumber: @@ -284,6 +306,7 @@ export const useObjectFields = () => { return { objectRender, objectValidate, + arrayObjectValidate, arrayStringRender, arrayStringValidate, arrayNumberRender, diff --git a/web/src/pages/next-chats/chat/conversation-dropdown.tsx b/web/src/pages/next-chats/chat/conversation-dropdown.tsx index 83193f57c..27bed0a7e 100644 --- a/web/src/pages/next-chats/chat/conversation-dropdown.tsx +++ b/web/src/pages/next-chats/chat/conversation-dropdown.tsx @@ -14,16 +14,28 @@ import { useTranslation } from 'react-i18next'; export function ConversationDropdown({ children, conversation, + removeTemporaryConversation, }: PropsWithChildren & { conversation: IConversation; + removeTemporaryConversation?: (conversationId: string) => void; }) { const { t } = useTranslation(); const { removeConversation } = useRemoveConversation(); const handleDelete: MouseEventHandler