Selaa lähdekoodia

Fix/application configuration preview style (#597)

zxhlyh 1 vuosi sitten
vanhempi
commit
753e5f1500

+ 3 - 3
web/app/components/app/configuration/config/index.tsx

@@ -40,7 +40,7 @@ const Config: FC = () => {
   } = useContext(ConfigContext)
   const isChatApp = mode === AppType.chat
   const { data: userInfo } = useSWR({ url: '/info' }, fetchTenantInfo)
-  const targetProvider = userInfo?.providers?.find(({ token_is_set, is_valid }) => token_is_set && is_valid)
+  const openaiProvider = userInfo?.providers?.find(({ token_is_set, is_valid, provider_name }) => token_is_set && is_valid && provider_name === 'openai')
 
   const promptTemplate = modelConfig.configs.prompt_template
   const promptVariables = modelConfig.configs.prompt_variables
@@ -92,7 +92,7 @@ const Config: FC = () => {
     },
   })
 
-  const hasChatConfig = isChatApp && (featureConfig.openingStatement || featureConfig.suggestedQuestionsAfterAnswer || (featureConfig.speechToText && targetProvider?.provider_name === 'openai'))
+  const hasChatConfig = isChatApp && (featureConfig.openingStatement || featureConfig.suggestedQuestionsAfterAnswer || (featureConfig.speechToText && openaiProvider))
   const hasToolbox = false
 
   const [showAutomatic, { setTrue: showAutomaticTrue, setFalse: showAutomaticFalse }] = useBoolean(false)
@@ -122,7 +122,7 @@ const Config: FC = () => {
             isChatApp={isChatApp}
             config={featureConfig}
             onChange={handleFeatureChange}
-            showSpeechToTextItem={targetProvider?.provider_name === 'openai'}
+            showSpeechToTextItem={!!openaiProvider}
           />
         )}
         {showAutomatic && (

+ 4 - 4
web/app/components/app/configuration/debug/index.tsx

@@ -116,22 +116,22 @@ const Debug: FC<IDebug> = ({
   }
 
   const checkCanSend = () => {
-    let hasEmptyInput = false
+    let hasEmptyInput = ''
     const requiredVars = modelConfig.configs.prompt_variables.filter(({ key, name, required }) => {
       const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null)
       return res
     }) // compatible with old version
     // debugger
-    requiredVars.forEach(({ key }) => {
+    requiredVars.forEach(({ key, name }) => {
       if (hasEmptyInput)
         return
 
       if (!inputs[key])
-        hasEmptyInput = true
+        hasEmptyInput = name
     })
 
     if (hasEmptyInput) {
-      logError(t('appDebug.errorMessage.valueOfVarRequired'))
+      logError(t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput }))
       return false
     }
     return !hasEmptyInput

+ 1 - 0
web/app/components/app/configuration/prompt-value-panel/index.tsx

@@ -122,6 +122,7 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
                           items={(options || []).map(i => ({ name: i, value: i }))}
                           allowSearch={false}
                           bgClassName='bg-gray-50'
+                          overlayClassName='z-[11]'
                         />
                       )
                       : (

+ 8 - 6
web/app/components/base/select/index.tsx

@@ -31,6 +31,7 @@ export type ISelectProps = {
   allowSearch?: boolean
   bgClassName?: string
   placeholder?: string
+  overlayClassName?: string
 }
 const Select: FC<ISelectProps> = ({
   className,
@@ -40,6 +41,7 @@ const Select: FC<ISelectProps> = ({
   onSelect,
   allowSearch = true,
   bgClassName = 'bg-gray-100',
+  overlayClassName,
 }) => {
   const [query, setQuery] = useState('')
   const [open, setOpen] = useState(false)
@@ -48,9 +50,9 @@ const Select: FC<ISelectProps> = ({
   useEffect(() => {
     let defaultSelect = null
     const existed = items.find((item: Item) => item.value === defaultValue)
-    if (existed) {
+    if (existed)
       defaultSelect = existed
-    }
+
     setSelectedItem(defaultSelect)
   }, [defaultValue])
 
@@ -104,7 +106,7 @@ const Select: FC<ISelectProps> = ({
         </div>
 
         {filteredItems.length > 0 && (
-          <Combobox.Options className="absolute z-10 mt-1 px-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg border-gray-200 border-[0.5px] focus:outline-none sm:text-sm">
+          <Combobox.Options className={`absolute z-10 mt-1 px-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg border-gray-200 border-[0.5px] focus:outline-none sm:text-sm ${overlayClassName}`}>
             {filteredItems.map((item: Item) => (
               <Combobox.Option
                 key={item.value}
@@ -155,9 +157,9 @@ const SimpleSelect: FC<ISelectProps> = ({
   useEffect(() => {
     let defaultSelect = null
     const existed = items.find((item: Item) => item.value === defaultValue)
-    if (existed) {
+    if (existed)
       defaultSelect = existed
-    }
+
     setSelectedItem(defaultSelect)
   }, [defaultValue])
 
@@ -173,7 +175,7 @@ const SimpleSelect: FC<ISelectProps> = ({
     >
       <div className={`relative h-9 ${wrapperClassName}`}>
         <Listbox.Button className={`w-full h-full rounded-lg border-0 bg-gray-100 py-1.5 pl-3 pr-10 shadow-sm sm:text-sm sm:leading-6 focus-visible:outline-none focus-visible:bg-gray-200 group-hover:bg-gray-200 cursor-pointer ${className}`}>
-          <span className={classNames("block truncate text-left", !selectedItem?.name && 'text-gray-400')}>{selectedItem?.name ?? localPlaceholder}</span>
+          <span className={classNames('block truncate text-left', !selectedItem?.name && 'text-gray-400')}>{selectedItem?.name ?? localPlaceholder}</span>
           <span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
             <ChevronDownIcon
               className="h-5 w-5 text-gray-400"

+ 4 - 4
web/app/components/share/chat/index.tsx

@@ -395,21 +395,21 @@ const Main: FC<IMainProps> = ({
     if (!inputs || !prompt_variables || prompt_variables?.length === 0)
       return true
 
-    let hasEmptyInput = false
+    let hasEmptyInput = ''
     const requiredVars = prompt_variables?.filter(({ key, name, required }) => {
       const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null)
       return res
     }) || [] // compatible with old version
-    requiredVars.forEach(({ key }) => {
+    requiredVars.forEach(({ key, name }) => {
       if (hasEmptyInput)
         return
 
       if (!inputs?.[key])
-        hasEmptyInput = true
+        hasEmptyInput = name
     })
 
     if (hasEmptyInput) {
-      logError(t('appDebug.errorMessage.valueOfVarRequired'))
+      logError(t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput }))
       return false
     }
     return !hasEmptyInput

+ 52 - 48
web/app/components/share/chat/welcome/index.tsx

@@ -1,16 +1,16 @@
 'use client'
 import type { FC } from 'react'
-import React, { useState, useEffect } from 'react'
+import React, { useEffect, useState } from 'react'
 import { useTranslation } from 'react-i18next'
 import { useContext } from 'use-context-selector'
+import TemplateVarPanel, { PanelTitle, VarOpBtnGroup } from '../value-panel'
 import s from './style.module.css'
+import { AppInfo, ChatBtn, EditBtn, FootLogo, PromptTemplate } from './massive-component'
 import type { SiteInfo } from '@/models/share'
 import type { PromptConfig } from '@/models/debug'
 import { ToastContext } from '@/app/components/base/toast'
 import Select from '@/app/components/base/select'
 import { DEFAULT_VALUE_MAX_LEN } from '@/config'
-import TemplateVarPanel, { PanelTitle, VarOpBtnGroup } from '../value-panel'
-import { AppInfo, PromptTemplate, ChatBtn, EditBtn, FootLogo } from './massive-component'
 
 // regex to match the {{}} and replace it with a span
 const regex = /\{\{([^}]+)\}\}/g
@@ -38,15 +38,15 @@ const Welcome: FC<IWelcomeProps> = ({
   onStartChat,
   canEidtInpus,
   savedInputs,
-  onInputsChange
+  onInputsChange,
 }) => {
   const { t } = useTranslation()
   const hasVar = promptConfig.prompt_variables.length > 0
   const [isFold, setIsFold] = useState<boolean>(true)
   const [inputs, setInputs] = useState<Record<string, any>>((() => {
-    if (hasSetInputs) {
+    if (hasSetInputs)
       return savedInputs
-    }
+
     const res: Record<string, any> = {}
     if (promptConfig) {
       promptConfig.prompt_variables.forEach((item) => {
@@ -65,7 +65,8 @@ const Welcome: FC<IWelcomeProps> = ({
         })
       }
       setInputs(res)
-    } else {
+    }
+    else {
       setInputs(savedInputs)
     }
   }, [savedInputs])
@@ -98,24 +99,26 @@ const Welcome: FC<IWelcomeProps> = ({
         {promptConfig.prompt_variables.map(item => (
           <div className='tablet:flex tablet:!h-9 mobile:space-y-2 tablet:space-y-0 mobile:text-xs tablet:text-sm' key={item.key}>
             <label className={`flex-shrink-0 flex items-center mobile:text-gray-700 tablet:text-gray-900 mobile:font-medium pc:font-normal ${s.formLabel}`}>{item.name}</label>
-            {item.type === 'select' ? (
-              <Select
-                className='w-full'
-                defaultValue={inputs?.[item.key]}
-                onSelect={(i) => { setInputs({ ...inputs, [item.key]: i.value }) }}
-                items={(item.options || []).map(i => ({ name: i, value: i }))}
-                allowSearch={false}
-                bgClassName='bg-gray-50'
-              />
-            ) : (
-              <input
-                placeholder={`${item.name}${!item.required ? `(${t('appDebug.variableTable.optional')})` : ''}`}
-                value={inputs?.[item.key] || ''}
-                onChange={(e) => { setInputs({ ...inputs, [item.key]: e.target.value }) }}
-                className={`w-full flex-grow py-2 pl-3 pr-3 box-border rounded-lg bg-gray-50`}
-                maxLength={item.max_length || DEFAULT_VALUE_MAX_LEN}
-              />
-            )}
+            {item.type === 'select'
+              ? (
+                <Select
+                  className='w-full'
+                  defaultValue={inputs?.[item.key]}
+                  onSelect={(i) => { setInputs({ ...inputs, [item.key]: i.value }) }}
+                  items={(item.options || []).map(i => ({ name: i, value: i }))}
+                  allowSearch={false}
+                  bgClassName='bg-gray-50'
+                />
+              )
+              : (
+                <input
+                  placeholder={`${item.name}${!item.required ? `(${t('appDebug.variableTable.optional')})` : ''}`}
+                  value={inputs?.[item.key] || ''}
+                  onChange={(e) => { setInputs({ ...inputs, [item.key]: e.target.value }) }}
+                  className={'w-full flex-grow py-2 pl-3 pr-3 box-border rounded-lg bg-gray-50'}
+                  maxLength={item.max_length || DEFAULT_VALUE_MAX_LEN}
+                />
+              )}
           </div>
         ))}
       </div>
@@ -124,34 +127,33 @@ const Welcome: FC<IWelcomeProps> = ({
 
   const canChat = () => {
     const prompt_variables = promptConfig?.prompt_variables
-    if (!inputs || !prompt_variables || prompt_variables?.length === 0) {
+    if (!inputs || !prompt_variables || prompt_variables?.length === 0)
       return true
-    }
-    let hasEmptyInput = false
+
+    let hasEmptyInput = ''
     const requiredVars = prompt_variables?.filter(({ key, name, required }) => {
       const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null)
       return res
     }) || [] // compatible with old version
-    requiredVars.forEach(({ key }) => {
-      if (hasEmptyInput) {
+    requiredVars.forEach(({ key, name }) => {
+      if (hasEmptyInput)
         return
-      }
-      if (!inputs?.[key]) {
-        hasEmptyInput = true
-      }
+
+      if (!inputs?.[key])
+        hasEmptyInput = name
     })
 
     if (hasEmptyInput) {
-      logError(t('appDebug.errorMessage.valueOfVarRequired'))
+      logError(t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput }))
       return false
     }
     return !hasEmptyInput
   }
 
   const handleChat = () => {
-    if (!canChat()) {
+    if (!canChat())
       return
-    }
+
     onStartChat(inputs)
   }
 
@@ -211,9 +213,9 @@ const Welcome: FC<IWelcomeProps> = ({
     return (
       <VarOpBtnGroup
         onConfirm={() => {
-          if (!canChat()) {
+          if (!canChat())
             return
-          }
+
           onInputsChange(inputs)
           setIsFold(true)
         }}
@@ -269,9 +271,9 @@ const Welcome: FC<IWelcomeProps> = ({
   }
 
   const renderHasSetInputsPrivate = () => {
-    if (!canEidtInpus || !hasVar) {
+    if (!canEidtInpus || !hasVar)
       return null
-    }
+
     return (
       <TemplateVarPanel
         isFold={isFold}
@@ -293,9 +295,9 @@ const Welcome: FC<IWelcomeProps> = ({
   }
 
   const renderHasSetInputs = () => {
-    if (!isPublicVersion && !canEidtInpus || !hasVar) {
+    if ((!isPublicVersion && !canEidtInpus) || !hasVar)
       return null
-    }
+
     return (
       <div
         className='pt-[88px] mb-5'
@@ -312,11 +314,13 @@ const Welcome: FC<IWelcomeProps> = ({
         {
           !hasSetInputs && (
             <div className='mobile:pt-[72px] tablet:pt-[128px] pc:pt-[200px]'>
-              {hasVar ? (
-                renderVarPanel()
-              ) : (
-                renderNoVarPanel()
-              )}
+              {hasVar
+                ? (
+                  renderVarPanel()
+                )
+                : (
+                  renderNoVarPanel()
+                )}
             </div>
           )
         }

+ 4 - 4
web/app/components/share/chatbot/index.tsx

@@ -390,21 +390,21 @@ const Main: FC<IMainProps> = ({
     if (!inputs || !prompt_variables || prompt_variables?.length === 0)
       return true
 
-    let hasEmptyInput = false
+    let hasEmptyInput = ''
     const requiredVars = prompt_variables?.filter(({ key, name, required }) => {
       const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null)
       return res
     }) || [] // compatible with old version
-    requiredVars.forEach(({ key }) => {
+    requiredVars.forEach(({ key, name }) => {
       if (hasEmptyInput)
         return
 
       if (!inputs?.[key])
-        hasEmptyInput = true
+        hasEmptyInput = name
     })
 
     if (hasEmptyInput) {
-      logError(t('appDebug.errorMessage.valueOfVarRequired'))
+      logError(t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput }))
       return false
     }
     return !hasEmptyInput

+ 4 - 4
web/app/components/share/chatbot/welcome/index.tsx

@@ -130,21 +130,21 @@ const Welcome: FC<IWelcomeProps> = ({
     if (!inputs || !prompt_variables || prompt_variables?.length === 0)
       return true
 
-    let hasEmptyInput = false
+    let hasEmptyInput = ''
     const requiredVars = prompt_variables?.filter(({ key, name, required }) => {
       const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null)
       return res
     }) || [] // compatible with old version
-    requiredVars.forEach(({ key }) => {
+    requiredVars.forEach(({ key, name }) => {
       if (hasEmptyInput)
         return
 
       if (!inputs?.[key])
-        hasEmptyInput = true
+        hasEmptyInput = name
     })
 
     if (hasEmptyInput) {
-      logError(t('appDebug.errorMessage.valueOfVarRequired'))
+      logError(t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput }))
       return false
     }
     return !hasEmptyInput

+ 4 - 4
web/app/components/share/text-generation/result/index.tsx

@@ -80,21 +80,21 @@ const Result: FC<IResultProps> = ({
     if (!prompt_variables || prompt_variables?.length === 0)
       return true
 
-    let hasEmptyInput = false
+    let hasEmptyInput = ''
     const requiredVars = prompt_variables?.filter(({ key, name, required }) => {
       const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null)
       return res
     }) || [] // compatible with old version
-    requiredVars.forEach(({ key }) => {
+    requiredVars.forEach(({ key, name }) => {
       if (hasEmptyInput)
         return
 
       if (!inputs[key])
-        hasEmptyInput = true
+        hasEmptyInput = name
     })
 
     if (hasEmptyInput) {
-      logError(t('appDebug.errorMessage.valueOfVarRequired'))
+      logError(t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput }))
       return false
     }
     return !hasEmptyInput

+ 1 - 1
web/i18n/lang/app-debug.en.ts

@@ -87,7 +87,7 @@ const translation = {
   },
   errorMessage: {
     nameOfKeyRequired: 'name of the key: {{key}} required',
-    valueOfVarRequired: 'Variables value can not be empty',
+    valueOfVarRequired: '{{key}} value can not be empty',
     queryRequired: 'Request text is required.',
     waitForResponse:
       'Please wait for the response to the previous message to complete.',

+ 1 - 1
web/i18n/lang/app-debug.zh.ts

@@ -86,7 +86,7 @@ const translation = {
   },
   errorMessage: {
     nameOfKeyRequired: '变量 {{key}} 对应的名称必填',
-    valueOfVarRequired: '变量值必填',
+    valueOfVarRequired: '{{key}}必填',
     queryRequired: '主要文本必填',
     waitForResponse: '请等待上条信息响应完成',
     waitForBatchResponse: '请等待批量任务完成',