Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
D
dify
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ai-tech
dify
Commits
c935edad
Commit
c935edad
authored
Jul 24, 2023
by
StyleZhang
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feat/application-config-user-input-field-collapse' into deploy/dev
parents
ab108d61
d2f5098a
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
131 additions
and
81 deletions
+131
-81
index.tsx
...components/app/configuration/prompt-value-panel/index.tsx
+86
-61
index.tsx
web/app/components/app/overview/embedded/index.tsx
+24
-3
utils.ts
web/app/components/base/icons/utils.ts
+1
-0
input-copy.tsx
web/app/components/develop/secret-key/input-copy.tsx
+7
-4
secret-key-generate.tsx
...app/components/develop/secret-key/secret-key-generate.tsx
+1
-1
secret-key-modal.tsx
web/app/components/develop/secret-key/secret-key-modal.tsx
+6
-8
invitation-link.tsx
...nt-setting/members-page/invited-modal/invitation-link.tsx
+5
-3
common.zh.ts
web/i18n/lang/common.zh.ts
+1
-1
No files found.
web/app/components/app/configuration/prompt-value-panel/index.tsx
View file @
c935edad
'use client'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
React
,
{
useState
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useContext
}
from
'use-context-selector'
import
{
...
...
@@ -13,6 +13,7 @@ import { AppType } from '@/types/app'
import
Select
from
'@/app/components/base/select'
import
{
DEFAULT_VALUE_MAX_LEN
}
from
'@/config'
import
Button
from
'@/app/components/base/button'
import
{
ChevronDown
,
ChevronRight
}
from
'@/app/components/base/icons/src/vender/line/arrows'
export
type
IPromptValuePanelProps
=
{
appType
:
AppType
...
...
@@ -37,6 +38,8 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
})
=>
{
const
{
t
}
=
useTranslation
()
const
{
modelConfig
,
inputs
,
setInputs
}
=
useContext
(
ConfigContext
)
const
[
promptPreviewCollapse
,
setPromptPreviewCollapse
]
=
useState
(
false
)
const
[
userInputFieldCollapse
,
setUserInputFieldCollapse
]
=
useState
(
false
)
const
promptTemplate
=
modelConfig
.
configs
.
prompt_template
const
promptVariables
=
modelConfig
.
configs
.
prompt_variables
.
filter
(({
key
,
name
})
=>
{
return
key
&&
key
?.
trim
()
&&
name
&&
name
?.
trim
()
...
...
@@ -63,93 +66,115 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
}
const
promptPreview
=
(
<
div
className=
'p
t-3 pb-4
rounded-t-xl bg-indigo-25'
>
<
div
className=
'p
y-3
rounded-t-xl bg-indigo-25'
>
<
div
className=
"px-4"
>
<
div
className=
"flex items-center space-x-1
"
>
<
div
className=
"flex items-center space-x-1
cursor-pointer"
onClick=
{
()
=>
setPromptPreviewCollapse
(
!
promptPreviewCollapse
)
}
>
{
starIcon
}
<
div
className=
"text-xs font-medium text-indigo-600 uppercase"
>
{
t
(
'appDebug.inputs.previewTitle'
)
}
</
div
>
</
div
>
<
div
className=
'mt-2 leading-normal'
>
{
(
promptTemplate
&&
promptTemplate
?.
trim
())
?
(
<
div
className=
"max-h-48 overflow-y-auto text-sm text-gray-700 break-all"
dangerouslySetInnerHTML=
{
{
__html
:
format
(
replaceStringWithValuesWithFormat
(
promptTemplate
.
replace
(
/</g
,
'<'
).
replace
(
/>/g
,
'>'
),
promptVariables
,
inputs
)),
}
}
>
</
div
>
)
:
(
<
div
className=
'text-xs text-gray-500'
>
{
t
(
'appDebug.inputs.noPrompt'
)
}
</
div
>
)
promptPreviewCollapse
?
<
ChevronRight
className=
'w-3 h-3 text-gray-700'
/>
:
<
ChevronDown
className=
'w-3 h-3 text-gray-700'
/>
}
</
div
>
{
!
promptPreviewCollapse
&&
(
<
div
className=
'mt-2 leading-normal'
>
{
(
promptTemplate
&&
promptTemplate
?.
trim
())
?
(
<
div
className=
"max-h-48 overflow-y-auto text-sm text-gray-700 break-all"
dangerouslySetInnerHTML=
{
{
__html
:
format
(
replaceStringWithValuesWithFormat
(
promptTemplate
.
replace
(
/</g
,
'<'
).
replace
(
/>/g
,
'>'
),
promptVariables
,
inputs
)),
}
}
>
</
div
>
)
:
(
<
div
className=
'text-xs text-gray-500'
>
{
t
(
'appDebug.inputs.noPrompt'
)
}
</
div
>
)
}
</
div
>
)
}
</
div
>
</
div
>
)
return
(
<
div
className=
"pb-
5
border border-gray-200 bg-white rounded-xl"
style=
{
{
<
div
className=
"pb-
3
border border-gray-200 bg-white rounded-xl"
style=
{
{
boxShadow
:
'0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06)'
,
}
}
>
{
promptPreview
}
<
div
className=
"mt-5 px-4"
>
<
div
className=
'mb-4 '
>
<
div
className=
'flex items-center space-x-1'
>
<
div
className=
{
'mt-3 px-4 bg-white'
}
>
<
div
className=
{
`${!userInputFieldCollapse && 'mb-2'}`
}
>
<
div
className=
'flex items-center space-x-1 cursor-pointer'
onClick=
{
()
=>
setUserInputFieldCollapse
(
!
userInputFieldCollapse
)
}
>
<
div
className=
'flex items-center justify-center w-4 h-4'
><
VarIcon
/></
div
>
<
div
className=
'text-sm font-semibold text-gray-800'
>
{
t
(
'appDebug.inputs.userInputField'
)
}
</
div
>
<
div
className=
'text-xs font-medium text-gray-800'
>
{
t
(
'appDebug.inputs.userInputField'
)
}
</
div
>
{
userInputFieldCollapse
?
<
ChevronRight
className=
'w-3 h-3 text-gray-700'
/>
:
<
ChevronDown
className=
'w-3 h-3 text-gray-700'
/>
}
</
div
>
{
appType
===
AppType
.
completion
&&
promptVariables
.
length
>
0
&&
(
{
appType
===
AppType
.
completion
&&
promptVariables
.
length
>
0
&&
!
userInputFieldCollapse
&&
(
<
div
className=
"mt-1 text-xs leading-normal text-gray-500"
>
{
t
(
'appDebug.inputs.completionVarTip'
)
}
</
div
>
)
}
</
div
>
{
promptVariables
.
length
>
0
?
(
<
div
className=
"space-y-3 "
>
{
promptVariables
.
map
(({
key
,
name
,
type
,
options
,
max_length
,
required
})
=>
(
<
div
key=
{
key
}
className=
"flex items-center justify-between"
>
<
div
className=
"mr-1 shrink-0 w-[120px] text-sm text-gray-900"
>
{
name
||
key
}
</
div
>
{
type
===
'select'
?
(
<
Select
className=
'w-full'
defaultValue=
{
inputs
[
key
]
as
string
}
onSelect=
{
(
i
)
=>
{
handleInputValueChange
(
key
,
i
.
value
as
string
)
}
}
items=
{
(
options
||
[]).
map
(
i
=>
({
name
:
i
,
value
:
i
}))
}
allowSearch=
{
false
}
bgClassName=
'bg-gray-50'
overlayClassName=
'z-[11]'
/>
)
:
(
<
input
className=
"w-full px-3 text-sm leading-9 text-gray-900 border-0 rounded-lg grow h-9 bg-gray-50 focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200"
placeholder=
{
`${name}${!required ? `
(
$
{
t
(
'appDebug.variableTable.optional'
)})
` : ''}`
}
type=
"text"
value=
{
inputs
[
key
]
?
`${inputs[key]}`
:
''
}
onChange=
{
(
e
)
=>
{
handleInputValueChange
(
key
,
e
.
target
.
value
)
}
}
maxLength=
{
max_length
||
DEFAULT_VALUE_MAX_LEN
}
/>
)
}
</
div
>
))
}
</
div
>
)
:
(
<
div
className=
'text-xs text-gray-500'
>
{
t
(
'appDebug.inputs.noVar'
)
}
</
div
>
)
!
userInputFieldCollapse
&&
(
<>
{
promptVariables
.
length
>
0
?
(
<
div
className=
"space-y-3 "
>
{
promptVariables
.
map
(({
key
,
name
,
type
,
options
,
max_length
,
required
})
=>
(
<
div
key=
{
key
}
className=
"flex items-center justify-between"
>
<
div
className=
"mr-1 shrink-0 w-[120px] text-sm text-gray-900"
>
{
name
||
key
}
</
div
>
{
type
===
'select'
?
(
<
Select
className=
'w-full'
defaultValue=
{
inputs
[
key
]
as
string
}
onSelect=
{
(
i
)
=>
{
handleInputValueChange
(
key
,
i
.
value
as
string
)
}
}
items=
{
(
options
||
[]).
map
(
i
=>
({
name
:
i
,
value
:
i
}))
}
allowSearch=
{
false
}
bgClassName=
'bg-gray-50'
overlayClassName=
'z-[11]'
/>
)
:
(
<
input
className=
"w-full px-3 text-sm leading-9 text-gray-900 border-0 rounded-lg grow h-9 bg-gray-50 focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200"
placeholder=
{
`${name}${!required ? `
(
$
{
t
(
'appDebug.variableTable.optional'
)})
` : ''}`
}
type=
"text"
value=
{
inputs
[
key
]
?
`${inputs[key]}`
:
''
}
onChange=
{
(
e
)
=>
{
handleInputValueChange
(
key
,
e
.
target
.
value
)
}
}
maxLength=
{
max_length
||
DEFAULT_VALUE_MAX_LEN
}
/>
)
}
</
div
>
))
}
</
div
>
)
:
(
<
div
className=
'text-xs text-gray-500'
>
{
t
(
'appDebug.inputs.noVar'
)
}
</
div
>
)
}
</>
)
}
</
div
>
{
appType
===
AppType
.
completion
&&
(
<
div
className=
'px-4'
>
<
div
className=
"mt-
5
border-b border-gray-100"
></
div
>
<
div
className=
"mt-
3
border-b border-gray-100"
></
div
>
<
div
className=
"mt-4"
>
<
div
>
<
div
className=
"text-[13px] text-gray-900 font-medium"
>
{
t
(
'appDebug.inputs.queryTitle'
)
}
</
div
>
...
...
web/app/components/app/overview/embedded/index.tsx
View file @
c935edad
import
React
,
{
useState
}
from
'react'
import
React
,
{
use
Effect
,
use
State
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
cn
from
'classnames'
import
style
from
'./style.module.css'
...
...
@@ -43,10 +43,15 @@ const prefixEmbedded = 'appOverview.overview.appInfo.embedded'
type
Option
=
keyof
typeof
OPTION_MAP
type
OptionStatus
=
{
iframe
:
boolean
scripts
:
boolean
}
const
Embedded
=
({
isShow
,
onClose
,
appBaseUrl
,
accessToken
}:
Props
)
=>
{
const
{
t
}
=
useTranslation
()
const
[
option
,
setOption
]
=
useState
<
Option
>
(
'iframe'
)
const
[
isCopied
,
setIsCopied
]
=
useState
({
iframe
:
false
,
scripts
:
false
})
const
[
isCopied
,
setIsCopied
]
=
useState
<
OptionStatus
>
({
iframe
:
false
,
scripts
:
false
})
const
[
_
,
copy
]
=
useCopyToClipboard
()
const
{
langeniusVersionInfo
}
=
useAppContext
()
...
...
@@ -56,6 +61,19 @@ const Embedded = ({ isShow, onClose, appBaseUrl, accessToken }: Props) => {
setIsCopied
({
...
isCopied
,
[
option
]:
true
})
}
// when toggle option, reset then copy status
const
resetCopyStatus
=
()
=>
{
const
cache
=
{
...
isCopied
}
Object
.
keys
(
cache
).
forEach
((
key
)
=>
{
cache
[
key
as
keyof
OptionStatus
]
=
false
})
setIsCopied
(
cache
)
}
useEffect
(()
=>
{
resetCopyStatus
()
},
[
isShow
])
return
(
<
Modal
title=
{
t
(
`${prefixEmbedded}.title`
)
}
...
...
@@ -77,7 +95,10 @@ const Embedded = ({ isShow, onClose, appBaseUrl, accessToken }: Props) => {
style
[
`${v}Icon`
],
option
===
v
&&
style
.
active
,
)
}
onClick=
{
()
=>
setOption
(
v
as
Option
)
}
onClick=
{
()
=>
{
setOption
(
v
as
Option
)
resetCopyStatus
()
}
}
></
div
>
)
})
}
...
...
web/app/components/base/icons/utils.ts
View file @
c935edad
...
...
@@ -15,6 +15,7 @@ export type Attrs = {
export
function
normalizeAttrs
(
attrs
:
Attrs
=
{}):
Attrs
{
return
Object
.
keys
(
attrs
).
reduce
((
acc
:
Attrs
,
key
)
=>
{
const
val
=
attrs
[
key
]
key
=
key
.
replace
(
/
([
-
]\w)
/g
,
(
g
:
string
)
=>
g
[
1
].
toUpperCase
())
switch
(
key
)
{
case
'class'
:
acc
.
className
=
val
...
...
web/app/components/develop/secret-key/input-copy.tsx
View file @
c935edad
'use client'
import
React
,
{
useEffect
,
useState
}
from
'react'
import
React
,
{
useEffect
,
use
Ref
,
use
State
}
from
'react'
import
copy
from
'copy-to-clipboard'
import
{
t
}
from
'i18next'
import
s
from
'./style.module.css'
import
{
randomString
}
from
'@/app/components/app-sidebar/basic'
import
Tooltip
from
'@/app/components/base/tooltip'
type
IInputCopyProps
=
{
...
...
@@ -13,13 +14,15 @@ type IInputCopyProps = {
}
const
InputCopy
=
({
value
,
value
=
''
,
className
,
readOnly
=
true
,
children
,
}:
IInputCopyProps
)
=>
{
const
[
isCopied
,
setIsCopied
]
=
useState
(
false
)
const
selector
=
useRef
(
`input-tooltip-
${
randomString
(
4
)}
`
)
useEffect
(()
=>
{
if
(
isCopied
)
{
const
timeout
=
setTimeout
(()
=>
{
...
...
@@ -38,7 +41,7 @@ const InputCopy = ({
{
children
}
<
div
className=
'flex-grow bg-gray-50 text-[13px] relative h-full'
>
<
Tooltip
selector=
"top-uniq"
selector=
{
selector
.
current
}
content=
{
isCopied
?
`${t('appApi.copied')}`
:
`${t('appApi.copy')}`
}
className=
'z-10'
>
...
...
@@ -50,7 +53,7 @@ const InputCopy = ({
</
div
>
<
div
className=
"flex-shrink-0 h-4 bg-gray-200 border"
/>
<
Tooltip
selector=
"top-uniq"
selector=
{
selector
.
current
}
content=
{
isCopied
?
`${t('appApi.copied')}`
:
`${t('appApi.copy')}`
}
className=
'z-10'
>
...
...
web/app/components/develop/secret-key/secret-key-generate.tsx
View file @
c935edad
...
...
@@ -18,7 +18,7 @@ const SecretKeyGenerateModal = ({
isShow
=
false
,
onClose
,
newKey
,
className
className
,
}:
ISecretKeyGenerateModalProps
)
=>
{
const
{
t
}
=
useTranslation
()
return
(
...
...
web/app/components/develop/secret-key/secret-key-modal.tsx
View file @
c935edad
...
...
@@ -6,6 +6,7 @@ import {
import
{
useTranslation
}
from
'react-i18next'
import
{
PlusIcon
,
XMarkIcon
}
from
'@heroicons/react/20/solid'
import
useSWR
,
{
useSWRConfig
}
from
'swr'
import
{
useContext
}
from
'use-context-selector'
import
SecretKeyGenerateModal
from
'./secret-key-generate'
import
s
from
'./style.module.css'
import
Modal
from
'@/app/components/base/modal'
...
...
@@ -16,7 +17,6 @@ import Tooltip from '@/app/components/base/tooltip'
import
Loading
from
'@/app/components/base/loading'
import
Confirm
from
'@/app/components/base/confirm'
import
useCopyToClipboard
from
'@/hooks/use-copy-to-clipboard'
import
{
useContext
}
from
'use-context-selector'
import
I18n
from
'@/context/i18n'
type
ISecretKeyModalProps
=
{
...
...
@@ -58,12 +58,11 @@ const SecretKeyModal = ({
}
},
[
copyValue
])
const
onDel
=
async
()
=>
{
setShowConfirmDelete
(
false
)
if
(
!
delKeyID
)
{
if
(
!
delKeyID
)
return
}
await
delApikey
({
url
:
`/apps/
${
appId
}
/api-keys/
${
delKeyID
}
`
,
params
:
{}
})
mutate
(
commonParams
)
}
...
...
@@ -80,11 +79,10 @@ const SecretKeyModal = ({
}
const
formatDate
=
(
timestamp
:
any
)
=>
{
if
(
locale
===
'en'
)
{
if
(
locale
===
'en'
)
return
new
Intl
.
DateTimeFormat
(
'en-US'
,
{
year
:
'numeric'
,
month
:
'long'
,
day
:
'numeric'
}).
format
((
+
timestamp
)
*
1000
)
}
else
{
else
return
new
Intl
.
DateTimeFormat
(
'fr-CA'
,
{
year
:
'numeric'
,
month
:
'2-digit'
,
day
:
'2-digit'
}).
format
((
+
timestamp
)
*
1000
)
}
}
return
(
...
...
@@ -111,7 +109,7 @@ const SecretKeyModal = ({
<
div
className=
'flex-shrink-0 px-3 truncate w-28'
>
{
api
.
last_used_at
?
formatDate
(
api
.
last_used_at
)
:
t
(
'appApi.never'
)
}
</
div
>
<
div
className=
'flex flex-grow px-3'
>
<
Tooltip
selector=
"top-uniq"
selector=
{
`key-${api.token}`
}
content=
{
copyValue
===
api
.
token
?
`${t('appApi.copied')}`
:
`${t('appApi.copy')}`
}
className=
'z-10'
>
...
...
web/app/components/header/account-setting/members-page/invited-modal/invitation-link.tsx
View file @
c935edad
'use client'
import
React
,
{
useCallback
,
useEffect
,
useState
}
from
'react'
import
React
,
{
useCallback
,
useEffect
,
use
Ref
,
use
State
}
from
'react'
import
{
t
}
from
'i18next'
import
s
from
'./index.module.css'
import
Tooltip
from
'@/app/components/base/tooltip'
import
useCopyToClipboard
from
'@/hooks/use-copy-to-clipboard'
import
{
randomString
}
from
'@/app/components/app-sidebar/basic'
type
IInvitationLinkProps
=
{
value
?:
string
...
...
@@ -13,6 +14,7 @@ const InvitationLink = ({
value
=
''
,
}:
IInvitationLinkProps
)
=>
{
const
[
isCopied
,
setIsCopied
]
=
useState
(
false
)
const
selector
=
useRef
(
`invite-link-
${
randomString
(
4
)}
`
)
const
[
_
,
copy
]
=
useCopyToClipboard
()
const
copyHandle
=
useCallback
(()
=>
{
...
...
@@ -37,7 +39,7 @@ const InvitationLink = ({
<
div
className=
"flex items-center flex-grow h-5"
>
<
div
className=
'flex-grow bg-gray-100 text-[13px] relative h-full'
>
<
Tooltip
selector=
"top-uniq"
selector=
{
selector
.
current
}
content=
{
isCopied
?
`${t('appApi.copied')}`
:
`${t('appApi.copy')}`
}
className=
'z-10'
>
...
...
@@ -46,7 +48,7 @@ const InvitationLink = ({
</
div
>
<
div
className=
"flex-shrink-0 h-4 bg-gray-200 border"
/>
<
Tooltip
selector=
"top-uniq"
selector=
{
selector
.
current
}
content=
{
isCopied
?
`${t('appApi.copied')}`
:
`${t('appApi.copy')}`
}
className=
'z-10'
>
...
...
web/i18n/lang/common.zh.ts
View file @
c935edad
...
...
@@ -43,7 +43,7 @@ const translation = {
'较高的 Temperature 设置将导致更多样和创造性的输出,而较低的 Temperature 将产生更保守的输出并且类似于训练数据。'
,
topP
:
'采样范围'
,
topPTip
:
'Top P值越
高,输出与训练文本越相似,Top P值越低
,输出越有创意和变化。它可用于使输出更适合特定用例。'
,
'Top P值越
低,输出与训练文本越相似,Top P值越高
,输出越有创意和变化。它可用于使输出更适合特定用例。'
,
presencePenalty
:
'词汇控制'
,
presencePenaltyTip
:
'Presence penalty 是根据新词是否出现在目前的文本中来对其进行惩罚。正值将降低模型谈论新话题的可能性。'
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment