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
0164dec4
Commit
0164dec4
authored
Mar 06, 2024
by
StyleZhang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
features
parent
4edaa95c
Changes
28
Show whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
404 additions
and
336 deletions
+404
-336
index.tsx
...nents/base/features/feature-choose/feature-item/index.tsx
+10
-3
feature-modal.tsx
...components/base/features/feature-choose/feature-modal.tsx
+48
-46
index.tsx
web/app/components/base/features/feature-panel/index.tsx
+12
-18
index.tsx
...mponents/base/features/feature-panel/moderation/index.tsx
+17
-5
index.tsx
...s/base/features/feature-panel/opening-statement/index.tsx
+31
-10
index.tsx
...ents/base/features/feature-panel/text-to-speech/index.tsx
+1
-1
store.ts
web/app/components/base/features/store.ts
+26
-51
types.ts
web/app/components/base/features/types.ts
+20
-0
play.svg
...s/base/icons/assets/vender/solid/mediaAndDevices/play.svg
+5
-0
Play.json
...nts/base/icons/src/vender/solid/mediaAndDevices/Play.json
+38
-0
Play.tsx
...ents/base/icons/src/vender/solid/mediaAndDevices/Play.tsx
+16
-0
index.ts
...ents/base/icons/src/vender/solid/mediaAndDevices/index.ts
+1
-0
features.tsx
web/app/components/workflow/features.tsx
+3
-1
editing-title.tsx
web/app/components/workflow/header/editing-title.tsx
+34
-0
index.tsx
web/app/components/workflow/header/index.tsx
+19
-28
publish.tsx
web/app/components/workflow/header/publish.tsx
+9
-7
run-and-history.tsx
web/app/components/workflow/header/run-and-history.tsx
+29
-13
running-title.tsx
web/app/components/workflow/header/running-title.tsx
+24
-0
index.tsx
web/app/components/workflow/index.tsx
+17
-1
panel.tsx
web/app/components/workflow/nodes/_base/panel.tsx
+1
-1
index.tsx
web/app/components/workflow/panel/index.tsx
+6
-6
run-history.tsx
web/app/components/workflow/panel/run-history.tsx
+15
-27
workflow-info.tsx
web/app/components/workflow/panel/workflow-info.tsx
+1
-1
store.ts
web/app/components/workflow/store.ts
+13
-6
types.ts
web/app/components/workflow/types.ts
+5
-0
zoom-in-out.tsx
web/app/components/workflow/zoom-in-out.tsx
+0
-110
workflow.ts
web/i18n/en-US/workflow.ts
+1
-0
workflow.ts
web/i18n/zh-Hans/workflow.ts
+2
-1
No files found.
web/app/components/base/features/feature-choose/feature-item/index.tsx
View file @
0164dec4
'use client'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
React
,
{
useCallback
}
from
'react'
import
cn
from
'classnames'
import
s
from
'./style.module.css'
import
Switch
from
'@/app/components/base/switch'
import
type
{
FeatureEnum
}
from
'@/app/components/base/features/types'
export
type
IFeatureItemProps
=
{
icon
:
React
.
ReactNode
...
...
@@ -11,7 +12,8 @@ export type IFeatureItemProps = {
title
:
string
description
:
string
value
:
boolean
onChange
:
(
value
:
boolean
)
=>
void
onChange
:
(
type
:
FeatureEnum
,
value
:
boolean
)
=>
void
type
:
FeatureEnum
}
const
FeatureItem
:
FC
<
IFeatureItemProps
>
=
({
...
...
@@ -21,7 +23,12 @@ const FeatureItem: FC<IFeatureItemProps> = ({
description
,
value
,
onChange
,
type
,
})
=>
{
const
handleChange
=
useCallback
((
newValue
:
boolean
)
=>
{
onChange
(
type
,
newValue
)
},
[
type
,
onChange
])
return
(
<
div
className=
{
cn
(
s
.
wrap
,
'relative flex justify-between p-3 rounded-xl border border-transparent bg-gray-50 hover:border-gray-200 cursor-pointer'
)
}
>
<
div
className=
'flex space-x-3 mr-2'
>
...
...
@@ -40,7 +47,7 @@ const FeatureItem: FC<IFeatureItemProps> = ({
</
div
>
</
div
>
<
Switch
onChange=
{
on
Change
}
defaultValue=
{
value
}
/>
<
Switch
onChange=
{
handle
Change
}
defaultValue=
{
value
}
/>
{
previewImgClassName
&&
(
<
div
className=
{
cn
(
s
.
preview
,
s
[
previewImgClassName
])
}
>
...
...
web/app/components/base/features/feature-choose/feature-modal.tsx
View file @
0164dec4
...
...
@@ -3,7 +3,10 @@ import type { FC } from 'react'
import
React
,
{
useCallback
}
from
'react'
import
produce
from
'immer'
import
{
useTranslation
}
from
'react-i18next'
import
{
useFeatures
}
from
'../hooks'
import
{
useFeatures
,
useFeaturesStore
,
}
from
'../hooks'
import
FeatureGroup
from
'./feature-group'
import
FeatureItem
from
'./feature-item'
import
Modal
from
'@/app/components/base/modal'
...
...
@@ -15,37 +18,43 @@ import {
MessageFast
,
MessageHeartCircle
,
}
from
'@/app/components/base/icons/src/vender/solid/communication'
import
{
FeatureEnum
}
from
'@/app/components/base/features/types'
import
type
{
Features
}
from
'@/app/components/base/features/types'
export
type
ChooseFeatureProps
=
{
export
type
FeatureModalProps
=
{
onChange
?:
(
features
:
Features
)
=>
void
showTextToSpeechItem
?:
boolean
showSpeechToTextItem
?:
boolean
}
const
ChooseFeature
:
FC
<
ChooseFeatureProps
>
=
({
const
FeatureModal
:
FC
<
FeatureModalProps
>
=
({
onChange
,
showTextToSpeechItem
,
showSpeechToTextItem
,
})
=>
{
const
{
t
}
=
useTranslation
()
const
featuresStore
=
useFeaturesStore
()
const
setShowFeaturesModal
=
useFeatures
(
s
=>
s
.
setShowFeaturesModal
)
const
openingStatement
=
useFeatures
(
s
=>
s
.
openingStatement
)
const
setOpeningStatement
=
useFeatures
(
s
=>
s
.
setOpeningStatement
)
const
suggestedQuestionsAfterAnswer
=
useFeatures
(
s
=>
s
.
suggestedQuestionsAfterAnswer
)
const
setSuggestedQuestionsAfterAnswer
=
useFeatures
(
s
=>
s
.
setSuggestedQuestionsAfterAnswer
)
const
textToSpeech
=
useFeatures
(
s
=>
s
.
textToSpeech
)
const
setTextToSpeech
=
useFeatures
(
s
=>
s
.
setTextToSpeech
)
const
speechToText
=
useFeatures
(
s
=>
s
.
speechToText
)
const
setSpeechToText
=
useFeatures
(
s
=>
s
.
setSpeechToText
)
const
citation
=
useFeatures
(
s
=>
s
.
citation
)
const
setCitation
=
useFeatures
(
s
=>
s
.
setCitation
)
const
moderation
=
useFeatures
(
s
=>
s
.
moderation
)
const
setModeration
=
useFeatures
(
s
=>
s
.
setModeration
)
const
annotation
=
useFeatures
(
s
=>
s
.
annotation
)
const
setAnnotation
=
useFeatures
(
s
=>
s
.
setAnnotation
)
const
features
=
useFeatures
(
s
=>
s
.
features
)
const
handleCancelModal
=
useCallback
(()
=>
{
setShowFeaturesModal
(
false
)
},
[
setShowFeaturesModal
])
const
handleChange
=
useCallback
((
type
:
FeatureEnum
,
enabled
:
boolean
)
=>
{
const
{
features
,
setFeatures
,
}
=
featuresStore
!
.
getState
()
const
newFeatures
=
produce
(
features
,
(
draft
)
=>
{
draft
[
type
].
enabled
=
enabled
})
setFeatures
(
newFeatures
)
if
(
onChange
)
onChange
(
newFeatures
)
},
[
featuresStore
,
onChange
])
return
(
<
Modal
isShow
...
...
@@ -67,20 +76,18 @@ const ChooseFeature: FC<ChooseFeatureProps> = ({
previewImgClassName=
'openingStatementPreview'
title=
{
t
(
'appDebug.feature.conversationOpener.title'
)
}
description=
{
t
(
'appDebug.feature.conversationOpener.description'
)
}
value=
{
openingStatement
.
enabled
}
onChange=
{
value
=>
setOpeningStatement
(
produce
(
openingStatement
,
(
draft
)
=>
{
draft
.
enabled
=
value
}))
}
value=
{
!!
features
.
opening
.
enabled
}
onChange=
{
handleChange
}
type=
{
FeatureEnum
.
opening
}
/>
<
FeatureItem
icon=
{
<
SuggestedQuestionsAfterAnswerIcon
/>
}
previewImgClassName=
'suggestedQuestionsAfterAnswerPreview'
title=
{
t
(
'appDebug.feature.suggestedQuestionsAfterAnswer.title'
)
}
description=
{
t
(
'appDebug.feature.suggestedQuestionsAfterAnswer.description'
)
}
value=
{
suggestedQuestionsAfterAnswer
.
enabled
}
onChange=
{
value
=>
setSuggestedQuestionsAfterAnswer
(
produce
(
suggestedQuestionsAfterAnswer
,
(
draft
)
=>
{
draft
.
enabled
=
value
}))
}
value=
{
!!
features
.
suggested
.
enabled
}
onChange=
{
handleChange
}
type=
{
FeatureEnum
.
suggested
}
/>
{
showTextToSpeechItem
&&
(
...
...
@@ -89,10 +96,9 @@ const ChooseFeature: FC<ChooseFeatureProps> = ({
previewImgClassName=
'textToSpeechPreview'
title=
{
t
(
'appDebug.feature.textToSpeech.title'
)
}
description=
{
t
(
'appDebug.feature.textToSpeech.description'
)
}
value=
{
textToSpeech
.
enabled
}
onChange=
{
value
=>
setTextToSpeech
(
produce
(
textToSpeech
,
(
draft
)
=>
{
draft
.
enabled
=
value
}))
}
value=
{
!!
features
.
text2speech
.
enabled
}
onChange=
{
handleChange
}
type=
{
FeatureEnum
.
text2speech
}
/>
)
}
...
...
@@ -103,10 +109,9 @@ const ChooseFeature: FC<ChooseFeatureProps> = ({
previewImgClassName=
'speechToTextPreview'
title=
{
t
(
'appDebug.feature.speechToText.title'
)
}
description=
{
t
(
'appDebug.feature.speechToText.description'
)
}
value=
{
speechToText
.
enabled
}
onChange=
{
value
=>
setSpeechToText
(
produce
(
speechToText
,
(
draft
)
=>
{
draft
.
enabled
=
value
}))
}
value=
{
!!
features
.
speech2text
.
enabled
}
onChange=
{
handleChange
}
type=
{
FeatureEnum
.
speech2text
}
/>
)
}
...
...
@@ -115,10 +120,9 @@ const ChooseFeature: FC<ChooseFeatureProps> = ({
previewImgClassName=
'citationPreview'
title=
{
t
(
'appDebug.feature.citation.title'
)
}
description=
{
t
(
'appDebug.feature.citation.description'
)
}
value=
{
citation
.
enabled
}
onChange=
{
value
=>
setCitation
(
produce
(
citation
,
(
draft
)
=>
{
draft
.
enabled
=
value
}))
}
value=
{
!!
features
.
citation
.
enabled
}
onChange=
{
handleChange
}
type=
{
FeatureEnum
.
citation
}
/>
</>
</
FeatureGroup
>
...
...
@@ -130,19 +134,17 @@ const ChooseFeature: FC<ChooseFeatureProps> = ({
previewImgClassName=
''
title=
{
t
(
'appDebug.feature.moderation.title'
)
}
description=
{
t
(
'appDebug.feature.moderation.description'
)
}
value=
{
moderation
.
enabled
}
onChange=
{
value
=>
setModeration
(
produce
(
moderation
,
(
draft
)
=>
{
draft
.
enabled
=
value
}))
}
value=
{
!!
features
.
moderation
.
enabled
}
onChange=
{
handleChange
}
type=
{
FeatureEnum
.
moderation
}
/>
<
FeatureItem
icon=
{
<
MessageFast
className=
'w-4 h-4 text-[#444CE7]'
/>
}
title=
{
t
(
'appDebug.feature.annotation.title'
)
}
description=
{
t
(
'appDebug.feature.annotation.description'
)
}
value=
{
annotation
.
enabled
}
onChange=
{
value
=>
setAnnotation
(
produce
(
annotation
,
(
draft
)
=>
{
draft
.
enabled
=
value
}))
}
value=
{
!!
features
.
annotation
.
enabled
}
onChange=
{
handleChange
}
type=
{
FeatureEnum
.
annotation
}
/>
</>
</
FeatureGroup
>
...
...
@@ -150,4 +152,4 @@ const ChooseFeature: FC<ChooseFeatureProps> = ({
</
Modal
>
)
}
export
default
React
.
memo
(
ChooseFeature
)
export
default
React
.
memo
(
FeatureModal
)
web/app/components/base/features/feature-panel/index.tsx
View file @
0164dec4
...
...
@@ -23,21 +23,15 @@ const FeaturePanel = ({
annotationProps
,
}:
FeaturePanelProps
)
=>
{
const
{
t
}
=
useTranslation
()
const
openingStatement
=
useFeatures
(
s
=>
s
.
openingStatement
)
const
suggestedQuestionsAfterAnswer
=
useFeatures
(
s
=>
s
.
suggestedQuestionsAfterAnswer
)
const
textToSpeech
=
useFeatures
(
s
=>
s
.
textToSpeech
)
const
speechToText
=
useFeatures
(
s
=>
s
.
speechToText
)
const
citation
=
useFeatures
(
s
=>
s
.
citation
)
const
moderation
=
useFeatures
(
s
=>
s
.
moderation
)
const
annotation
=
useFeatures
(
s
=>
s
.
annotation
)
const
features
=
useFeatures
(
s
=>
s
.
features
)
const
showAdvanceFeature
=
useMemo
(()
=>
{
return
openingStatement
.
enabled
||
suggestedQuestionsAfterAnswer
.
enabled
||
textToSpeech
.
enabled
||
speechToText
.
enabled
||
citation
.
enabled
},
[
openingStatement
,
suggestedQuestionsAfterAnswer
,
textToSpeech
,
speechToText
,
citation
])
return
features
.
opening
.
enabled
||
features
.
suggested
.
enabled
||
features
.
speech2text
.
enabled
||
features
.
text2speech
.
enabled
||
features
.
citation
.
enabled
},
[
features
])
const
showToolFeature
=
useMemo
(()
=>
{
return
moderation
.
enabled
||
annotation
.
enabled
},
[
moderation
,
annotation
])
return
features
.
moderation
.
enabled
||
features
.
annotation
.
enabled
},
[
features
])
return
(
<
div
className=
'space-y-3'
>
...
...
@@ -55,27 +49,27 @@ const FeaturePanel = ({
</
div
>
<
div
className=
'py-2 space-y-2'
>
{
openingStatement
.
enabled
&&
(
features
.
opening
.
enabled
&&
(
<
OpeningStatement
{
...
openingStatementProps
}
/>
)
}
{
suggestedQuestionsAfterAnswer
.
enabled
&&
(
features
.
suggested
.
enabled
&&
(
<
SuggestedQuestionsAfterAnswer
/>
)
}
{
textToS
peech
.
enabled
&&
(
features
.
text2s
peech
.
enabled
&&
(
<
TextToSpeech
/>
)
}
{
speechToT
ext
.
enabled
&&
(
features
.
speech2t
ext
.
enabled
&&
(
<
SpeechToText
/>
)
}
{
citation
.
enabled
&&
(
features
.
citation
.
enabled
&&
(
<
Citation
/>
)
}
...
...
@@ -97,12 +91,12 @@ const FeaturePanel = ({
</
div
>
<
div
className=
'py-2 space-y-2'
>
{
moderation
.
enabled
&&
(
features
.
moderation
.
enabled
&&
(
<
Moderation
/>
)
}
{
annotation
.
enabled
&&
(
features
.
annotation
.
enabled
&&
(
<
Annotation
{
...
annotationProps
}
/>
)
}
...
...
web/app/components/base/features/feature-panel/moderation/index.tsx
View file @
0164dec4
import
{
memo
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
useSWR
from
'swr'
import
produce
from
'immer'
import
{
useContext
}
from
'use-context-selector'
import
{
useFeatures
}
from
'../../hooks'
import
{
useFeatures
,
useFeaturesStore
,
}
from
'../../hooks'
import
{
FileSearch02
}
from
'@/app/components/base/icons/src/vender/solid/files'
import
{
Settings01
}
from
'@/app/components/base/icons/src/vender/line/general'
import
{
useModalContext
}
from
'@/context/modal-context'
...
...
@@ -13,8 +17,8 @@ const Moderation = () => {
const
{
t
}
=
useTranslation
()
const
{
setShowModerationSettingModal
}
=
useModalContext
()
const
{
locale
}
=
useContext
(
I18n
)
const
moderation
=
useFeatures
(
s
=>
s
.
moderation
)
const
setModeration
=
useFeatures
(
s
=>
s
.
setM
oderation
)
const
featuresStore
=
useFeaturesStore
(
)
const
moderation
=
useFeatures
(
s
=>
s
.
features
.
m
oderation
)
const
{
data
:
codeBasedExtensionList
}
=
useSWR
(
'/code-based-extension?module=moderation'
,
...
...
@@ -22,9 +26,17 @@ const Moderation = () => {
)
const
handleOpenModerationSettingModal
=
()
=>
{
const
{
features
,
setFeatures
,
}
=
featuresStore
!
.
getState
()
setShowModerationSettingModal
({
payload
:
moderation
,
onSaveCallback
:
setModeration
,
payload
:
moderation
as
any
,
onSaveCallback
:
(
newModeration
)
=>
{
setFeatures
(
produce
(
features
,
(
draft
)
=>
{
draft
.
moderation
=
newModeration
}))
},
})
}
...
...
web/app/components/base/features/feature-panel/opening-statement/index.tsx
View file @
0164dec4
...
...
@@ -7,7 +7,10 @@ import cn from 'classnames'
import
{
useTranslation
}
from
'react-i18next'
import
{
useBoolean
}
from
'ahooks'
import
{
ReactSortable
}
from
'react-sortablejs'
import
{
useFeatures
}
from
'../../hooks'
import
{
useFeatures
,
useFeaturesStore
,
}
from
'../../hooks'
import
Panel
from
'@/app/components/app/configuration/base/feature-panel'
import
Button
from
'@/app/components/base/button'
import
OperationBtn
from
'@/app/components/app/configuration/base/operation-btn'
...
...
@@ -35,8 +38,8 @@ const OpeningStatement: FC<OpeningStatementProps> = ({
onAutoAddPromptVariable
,
})
=>
{
const
{
t
}
=
useTranslation
()
const
openingStatement
=
useFeatures
(
s
=>
s
.
openingStatement
)
const
setOpeningStatement
=
useFeatures
(
s
=>
s
.
setOpeningStatement
)
const
featureStore
=
useFeaturesStore
(
)
const
openingStatement
=
useFeatures
(
s
=>
s
.
features
.
opening
)
const
value
=
openingStatement
.
opening_statement
||
''
const
suggestedQuestions
=
openingStatement
.
suggested_questions
||
[]
const
[
notIncludeKeys
,
setNotIncludeKeys
]
=
useState
<
string
[]
>
([])
...
...
@@ -103,23 +106,41 @@ const OpeningStatement: FC<OpeningStatementProps> = ({
return
}
setBlur
()
setOpeningStatement
(
produce
(
openingStatement
,
(
draft
)
=>
{
draft
.
opening_statement
=
tempValue
draft
.
suggested_questions
=
tempSuggestedQuestions
const
{
getState
}
=
featureStore
!
const
{
features
,
setFeatures
,
}
=
getState
()
setFeatures
(
produce
(
features
,
(
draft
)
=>
{
draft
.
opening
.
opening_statement
=
tempValue
draft
.
opening
.
suggested_questions
=
tempSuggestedQuestions
}))
}
const
cancelAutoAddVar
=
()
=>
{
setOpeningStatement
(
produce
(
openingStatement
,
(
draft
)
=>
{
draft
.
opening_statement
=
tempValue
const
{
getState
}
=
featureStore
!
const
{
features
,
setFeatures
,
}
=
getState
()
setFeatures
(
produce
(
features
,
(
draft
)
=>
{
draft
.
opening
.
opening_statement
=
tempValue
}))
hideConfirmAddVar
()
setBlur
()
}
const
autoAddVar
=
()
=>
{
setOpeningStatement
(
produce
(
openingStatement
,
(
draft
)
=>
{
draft
.
opening_statement
=
tempValue
const
{
getState
}
=
featureStore
!
const
{
features
,
setFeatures
,
}
=
getState
()
setFeatures
(
produce
(
features
,
(
draft
)
=>
{
draft
.
opening
.
opening_statement
=
tempValue
}))
onAutoAddPromptVariable
([...
notIncludeKeys
.
map
(
key
=>
getNewVar
(
key
,
'string'
))])
hideConfirmAddVar
()
...
...
web/app/components/base/features/feature-panel/text-to-speech/index.tsx
View file @
0164dec4
...
...
@@ -12,7 +12,7 @@ import AudioBtn from '@/app/components/base/audio-btn'
const
TextToSpeech
:
FC
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
textToSpeech
=
useFeatures
(
s
=>
s
.
textToS
peech
)
const
textToSpeech
=
useFeatures
(
s
=>
s
.
features
.
text2s
peech
)
const
pathname
=
usePathname
()
const
matched
=
pathname
.
match
(
/
\/
app
\/([^/]
+
)
/
)
...
...
web/app/components/base/features/store.ts
View file @
0164dec4
import
{
createStore
}
from
'zustand'
import
type
{
AnnotationReply
,
OpeningStatement
,
RetrieverResource
,
SensitiveWordAvoidance
,
SpeechToText
,
SuggestedQuestionsAfterAnswer
,
TextToSpeech
,
}
from
'./types'
import
type
{
Features
}
from
'./types'
export
type
FeaturesModal
=
{
showFeaturesModal
:
boolean
...
...
@@ -15,23 +7,11 @@ export type FeaturesModal = {
}
export
type
FeaturesState
=
{
openingStatement
:
OpeningStatement
suggestedQuestionsAfterAnswer
:
SuggestedQuestionsAfterAnswer
textToSpeech
:
TextToSpeech
speechToText
:
SpeechToText
citation
:
RetrieverResource
moderation
:
SensitiveWordAvoidance
annotation
:
AnnotationReply
features
:
Features
}
export
type
FeaturesAction
=
{
setOpeningStatement
:
(
openingStatement
:
OpeningStatement
)
=>
void
setSuggestedQuestionsAfterAnswer
:
(
suggestedQuestionsAfterAnswer
:
SuggestedQuestionsAfterAnswer
)
=>
void
setTextToSpeech
:
(
textToSpeech
:
TextToSpeech
)
=>
void
setSpeechToText
:
(
speechToText
:
SpeechToText
)
=>
void
setCitation
:
(
citation
:
RetrieverResource
)
=>
void
setModeration
:
(
moderation
:
SensitiveWordAvoidance
)
=>
void
setAnnotation
:
(
annotation
:
AnnotationReply
)
=>
void
setFeatures
:
(
features
:
Features
)
=>
void
}
export
type
FeatureStoreState
=
FeaturesState
&
FeaturesAction
&
FeaturesModal
...
...
@@ -40,16 +20,17 @@ export type FeaturesStore = ReturnType<typeof createFeaturesStore>
export
const
createFeaturesStore
=
(
initProps
?:
Partial
<
FeaturesState
>
)
=>
{
const
DEFAULT_PROPS
:
FeaturesState
=
{
openingStatement
:
{
features
:
{
opening
:
{
enabled
:
false
,
},
suggestedQuestionsAfterAnswer
:
{
suggested
:
{
enabled
:
false
,
},
textToS
peech
:
{
text2s
peech
:
{
enabled
:
false
,
},
speechToT
ext
:
{
speech2t
ext
:
{
enabled
:
false
,
},
citation
:
{
...
...
@@ -61,18 +42,12 @@ export const createFeaturesStore = (initProps?: Partial<FeaturesState>) => {
annotation
:
{
enabled
:
false
,
},
},
}
return
createStore
<
FeatureStoreState
>
()(
set
=>
({
...
DEFAULT_PROPS
,
...
initProps
,
setOpeningStatement
:
openingStatement
=>
set
(()
=>
({
openingStatement
})),
setSuggestedQuestionsAfterAnswer
:
suggestedQuestionsAfterAnswer
=>
set
(()
=>
({
suggestedQuestionsAfterAnswer
})),
setSpeechToText
:
speechToText
=>
set
(()
=>
({
speechToText
})),
setTextToSpeech
:
textToSpeech
=>
set
(()
=>
({
textToSpeech
})),
setCitation
:
citation
=>
set
(()
=>
({
citation
})),
setModeration
:
moderation
=>
set
(()
=>
({
moderation
})),
setAnnotation
:
annotation
=>
set
(()
=>
({
annotation
})),
setFeatures
:
features
=>
set
(()
=>
({
features
})),
showFeaturesModal
:
false
,
setShowFeaturesModal
:
showFeaturesModal
=>
set
(()
=>
({
showFeaturesModal
})),
}))
...
...
web/app/components/base/features/types.ts
View file @
0164dec4
...
...
@@ -31,3 +31,23 @@ export type AnnotationReply = EnabledOrDisabled & {
embedding_provider_name
:
string
}
}
export
enum
FeatureEnum
{
opening
=
'opening'
,
suggested
=
'suggested'
,
text2speech
=
'text2speech'
,
speech2text
=
'speech2text'
,
citation
=
'citation'
,
moderation
=
'moderation'
,
annotation
=
'annotation'
,
}
export
type
Features
=
{
[
FeatureEnum
.
opening
]:
OpeningStatement
[
FeatureEnum
.
suggested
]:
SuggestedQuestionsAfterAnswer
[
FeatureEnum
.
text2speech
]:
TextToSpeech
[
FeatureEnum
.
speech2text
]:
SpeechToText
[
FeatureEnum
.
citation
]:
RetrieverResource
[
FeatureEnum
.
moderation
]:
SensitiveWordAvoidance
[
FeatureEnum
.
annotation
]:
AnnotationReply
}
web/app/components/base/icons/assets/vender/solid/mediaAndDevices/play.svg
0 → 100644
View file @
0164dec4
<svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"play"
>
<path
id=
"Solid"
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M4.00312 1.40109C4.0091 1.40508 4.0151 1.40907 4.02111 1.41309L9.29548 4.92933C9.44809 5.03105 9.58959 5.12537 9.69827 5.21301C9.81168 5.30448 9.94538 5.43132 10.0223 5.61687C10.124 5.86212 10.124 6.13775 10.0223 6.38301C9.94538 6.56856 9.81168 6.6954 9.69827 6.78686C9.5896 6.8745 9.44811 6.96881 9.2955 7.07053L4.00314 10.5988C3.8166 10.7232 3.64886 10.835 3.50652 10.9121C3.36409 10.9893 3.16859 11.0775 2.9404 11.0639C2.64852 11.0465 2.3789 10.9022 2.20249 10.669C2.06458 10.4867 2.02952 10.2751 2.01474 10.1138C1.99997 9.95254 1.99999 9.75094 2 9.52674L2 2.49475C2 2.48752 2 2.48031 2 2.47313C1.99999 2.24893 1.99997 2.04733 2.01474 1.88612C2.02952 1.72479 2.06458 1.5132 2.20249 1.33089C2.3789 1.0977 2.64852 0.953401 2.9404 0.935973C3.16859 0.922349 3.36409 1.01055 3.50652 1.08774C3.64885 1.16488 3.81659 1.27672 4.00312 1.40109Z"
fill=
"#155EEF"
/>
</g>
</svg>
web/app/components/base/icons/src/vender/solid/mediaAndDevices/Play.json
0 → 100644
View file @
0164dec4
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"12"
,
"height"
:
"12"
,
"viewBox"
:
"0 0 12 12"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"id"
:
"play"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Solid"
,
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M4.00312 1.40109C4.0091 1.40508 4.0151 1.40907 4.02111 1.41309L9.29548 4.92933C9.44809 5.03105 9.58959 5.12537 9.69827 5.21301C9.81168 5.30448 9.94538 5.43132 10.0223 5.61687C10.124 5.86212 10.124 6.13775 10.0223 6.38301C9.94538 6.56856 9.81168 6.6954 9.69827 6.78686C9.5896 6.8745 9.44811 6.96881 9.2955 7.07053L4.00314 10.5988C3.8166 10.7232 3.64886 10.835 3.50652 10.9121C3.36409 10.9893 3.16859 11.0775 2.9404 11.0639C2.64852 11.0465 2.3789 10.9022 2.20249 10.669C2.06458 10.4867 2.02952 10.2751 2.01474 10.1138C1.99997 9.95254 1.99999 9.75094 2 9.52674L2 2.49475C2 2.48752 2 2.48031 2 2.47313C1.99999 2.24893 1.99997 2.04733 2.01474 1.88612C2.02952 1.72479 2.06458 1.5132 2.20249 1.33089C2.3789 1.0977 2.64852 0.953401 2.9404 0.935973C3.16859 0.922349 3.36409 1.01055 3.50652 1.08774C3.64885 1.16488 3.81659 1.27672 4.00312 1.40109Z"
,
"fill"
:
"currentColor"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"Play"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/solid/mediaAndDevices/Play.tsx
0 → 100644
View file @
0164dec4
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Play.json'
import
IconBase
from
'@/app/components/base/icons/IconBase'
import
type
{
IconBaseProps
,
IconData
}
from
'@/app/components/base/icons/IconBase'
const
Icon
=
React
.
forwardRef
<
React
.
MutableRefObject
<
SVGElement
>
,
Omit
<
IconBaseProps
,
'data'
>>
((
props
,
ref
,
)
=>
<
IconBase
{
...
props
}
ref=
{
ref
}
data=
{
data
as
IconData
}
/>)
Icon
.
displayName
=
'Play'
export
default
Icon
web/app/components/base/icons/src/vender/solid/mediaAndDevices/index.ts
View file @
0164dec4
...
...
@@ -2,6 +2,7 @@ export { default as MagicBox } from './MagicBox'
export
{
default
as
MagicEyes
}
from
'./MagicEyes'
export
{
default
as
MagicWand
}
from
'./MagicWand'
export
{
default
as
Microphone01
}
from
'./Microphone01'
export
{
default
as
Play
}
from
'./Play'
export
{
default
as
Robot
}
from
'./Robot'
export
{
default
as
Sliders02
}
from
'./Sliders02'
export
{
default
as
Speaker
}
from
'./Speaker'
...
...
web/app/components/workflow/features.tsx
View file @
0164dec4
import
{
memo
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useStore
}
from
'./store'
import
{
XClose
}
from
'@/app/components/base/icons/src/vender/line/general'
import
{
...
...
@@ -7,12 +8,13 @@ import {
}
from
'@/app/components/base/features'
const
Features
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
setShowFeaturesPanel
=
useStore
(
state
=>
state
.
setShowFeaturesPanel
)
return
(
<
div
className=
'fixed top-16 left-2 bottom-2 w-[600px] rounded-2xl border-[0.5px] border-gray-200 bg-white shadow-xl z-10'
>
<
div
className=
'flex items-center justify-between px-4 pt-3'
>
Features
{
t
(
'workflow.common.features'
)
}
<
div
className=
'flex items-center'
>
<
FeaturesChoose
/>
<
div
className=
'mx-3 w-[1px] h-[14px] bg-gray-200'
></
div
>
...
...
web/app/components/workflow/header/editing-title.tsx
0 → 100644
View file @
0164dec4
import
{
memo
}
from
'react'
import
dayjs
from
'dayjs'
import
{
useTranslation
}
from
'react-i18next'
import
{
Edit03
}
from
'@/app/components/base/icons/src/vender/solid/general'
import
{
useStore
}
from
'@/app/components/workflow/store'
const
EditingTitle
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
draftUpdatedAt
=
useStore
(
state
=>
state
.
draftUpdatedAt
)
const
publishedAt
=
useStore
(
state
=>
state
.
publishedAt
)
return
(
<
div
className=
'flex items-center h-[18px] text-xs text-gray-500'
>
<
Edit03
className=
'mr-1 w-3 h-3 text-gray-400'
/>
{
t
(
'workflow.common.editing'
)
}
{
draftUpdatedAt
&&
(
<>
<
span
className=
'flex items-center mx-1'
>
·
</
span
>
{
t
(
'workflow.common.autoSaved'
)
}
{
dayjs
(
draftUpdatedAt
).
format
(
'HH:mm:ss'
)
}
</>
)
}
<
span
className=
'flex items-center mx-1'
>
·
</
span
>
{
publishedAt
?
`${t('workflow.common.published')} ${dayjs(publishedAt).fromNow()}`
:
t
(
'workflow.common.unpublished'
)
}
</
div
>
)
}
export
default
memo
(
EditingTitle
)
web/app/components/workflow/header/index.tsx
View file @
0164dec4
...
...
@@ -3,26 +3,27 @@ import {
memo
,
useCallback
,
}
from
'react'
import
dayjs
from
'dayjs
'
import
{
useTranslation
}
from
'react-i18next
'
import
{
useStore
}
from
'../store'
import
RunAndHistory
from
'./run-and-history'
import
EditingTitle
from
'./editing-title'
import
RunningTitle
from
'./running-title'
import
Publish
from
'./publish'
import
{
Edit03
}
from
'@/app/components/base/icons/src/vender/solid/general'
import
{
Grid01
}
from
'@/app/components/base/icons/src/vender/line/layout'
import
Button
from
'@/app/components/base/button'
import
{
ArrowNarrowLeft
}
from
'@/app/components/base/icons/src/vender/line/arrows'
import
{
useStore
as
useAppStore
}
from
'@/app/components/app/store'
import
{
Mode
}
from
'@/app/components/workflow/types'
const
Header
:
FC
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
appDetail
=
useAppStore
(
state
=>
state
.
appDetail
)
const
setShowFeaturesPanel
=
useStore
(
state
=>
state
.
setShowFeaturesPanel
)
const
runStaus
=
useStore
(
state
=>
state
.
runStaus
)
const
setRunStaus
=
useStore
(
state
=>
state
.
setRunStaus
)
const
draftUpdatedAt
=
useStore
(
state
=>
state
.
draftUpdatedAt
)
const
mode
=
useStore
(
state
=>
state
.
mode
)
const
runTaskId
=
useStore
(
state
=>
state
.
runTaskId
)
const
handleShowFeatures
=
useCallback
(()
=>
{
setShowFeaturesPanel
(
true
)
},
[
setShowFeaturesPanel
])
useStore
.
setState
({
showFeaturesPanel
:
true
}
)
},
[])
return
(
<
div
...
...
@@ -33,35 +34,25 @@ const Header: FC = () => {
>
<
div
>
<
div
className=
'text-xs font-medium text-gray-700'
>
{
appDetail
?.
name
}
</
div
>
<
div
className=
'flex items-center'
>
<
div
className=
'flex items-center text-xs text-gray-500'
>
<
Edit03
className=
'mr-1 w-3 h-3 text-gray-400'
/>
Editing
{
draftUpdatedAt
&&
(
<>
<
span
className=
'flex items-center mx-1'
>
·
</
span
>
<
span
>
Auto-Saved
{
dayjs
(
draftUpdatedAt
).
format
(
'HH:mm:ss'
)
}
</
span
>
</>
)
mode
===
Mode
.
Editing
&&
!
runTaskId
&&
<
EditingTitle
/>
}
{
(
mode
===
Mode
.
Running
||
runTaskId
)
&&
<
RunningTitle
/>
}
</
div
>
</
div
>
</
div
>
<
div
className=
'flex items-center'
>
{
runStaus
&&
(
(
mode
===
Mode
.
Running
||
runTaskId
)
&&
(
<
Button
className=
{
`
mr-2 px-3 py-0 h-8 bg-white text-[13px] font-medium text-primary-600
border-[0.5px] border-gray-200 shadow-xs
`
}
onClick=
{
()
=>
setRunStaus
(
''
)
}
onClick=
{
()
=>
useStore
.
setState
({
mode
:
Mode
.
Editing
,
runTaskId
:
''
}
)
}
>
<
ArrowNarrowLeft
className=
'mr-1 w-4 h-4'
/>
Go back to editor
{
t
(
'workflow.common.goBackToEdit'
)
}
</
Button
>
)
}
...
...
@@ -77,7 +68,7 @@ const Header: FC = () => {
onClick=
{
handleShowFeatures
}
>
<
Grid01
className=
'mr-1 w-4 h-4 text-gray-500'
/>
Features
{
t
(
'workflow.common.features'
)
}
</
Button
>
)
}
...
...
web/app/components/workflow/header/publish.tsx
View file @
0164dec4
import
{
useState
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
Button
from
'@/app/components/base/button'
import
{
PortalToFollowElem
,
...
...
@@ -7,6 +8,7 @@ import {
}
from
'@/app/components/base/portal-to-follow-elem'
const
Publish
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
[
open
,
setOpen
]
=
useState
(
false
)
return
(
...
...
@@ -24,35 +26,35 @@ const Publish = () => {
type=
'primary'
className=
'px-3 py-0 h-8 text-[13px] font-medium'
>
publish
{
t
(
'workflow.common.publish'
)
}
</
Button
>
</
PortalToFollowElemTrigger
>
<
PortalToFollowElemContent
className=
'z-[11]'
>
<
div
className=
'w-[320px] bg-white rounded-2xl border-[0.5px] border-gray-200 shadow-xl'
>
<
div
className=
'p-4 pt-3'
>
<
div
className=
'flex items-center h-6 text-xs font-medium text-gray-500'
>
Current Draft
{
t
(
'workflow.common.currentDraft'
).
toLocaleUpperCase
()
}
</
div
>
<
div
className=
'flex items-center h-[18px] text-[13px] font-medium text-gray-700'
>
Auto-Saved
3 min ago · Evan
{
t
(
'workflow.common.autoSaved'
)
}
3 min ago · Evan
</
div
>
<
Button
type=
'primary'
className=
'mt-3 px-3 py-0 w-full h-8 border-[0.5px] border-primary-700 rounded-lg text-[13px] font-medium'
>
Publish
{
t
(
'workflow.common.publish'
)
}
</
Button
>
</
div
>
<
div
className=
'p-4 pt-3 border-t-[0.5px] border-t-black/5'
>
<
div
className=
'flex items-center h-6 text-xs font-medium text-gray-500'
>
Latest Published
{
t
(
'workflow.common.latestPublished'
).
toLocaleUpperCase
()
}
</
div
>
<
div
className=
'flex justify-between'
>
<
div
className=
'flex items-center mt-[3px] mb-[3px] leading-[18px] text-[13px] font-medium text-gray-700'
>
Auto-Saved
3 min ago · Evan
{
t
(
'workflow.common.autoSaved'
)
}
3 min ago · Evan
</
div
>
<
Button
className=
'ml-2 px-2 py-0 h-6 shadow-xs rounded-md text-xs font-medium text-gray-700 border-[0.5px] border-gray-200'
>
Restore
{
t
(
'workflow.common.restore'
)
}
</
Button
>
</
div
>
</
div
>
...
...
web/app/components/workflow/header/run-and-history.tsx
View file @
0164dec4
import
type
{
FC
}
from
'react'
import
{
memo
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useStore
}
from
'../store'
import
{
Play
}
from
'@/app/components/base/icons/src/vender/line/mediaAndDevices'
import
{
ClockPlay
}
from
'@/app/components/base/icons/src/vender/line/time'
import
TooltipPlus
from
'@/app/components/base/tooltip-plus'
import
{
Loading02
}
from
'@/app/components/base/icons/src/vender/line/general'
import
{
Mode
}
from
'@/app/components/workflow/types'
import
{
useStore
as
useAppStore
}
from
'@/app/components/app/store'
const
RunAndHistory
:
FC
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
appDetail
=
useAppStore
(
state
=>
state
.
appDetail
)
const
mode
=
useStore
(
state
=>
state
.
mode
)
const
showRunHistory
=
useStore
(
state
=>
state
.
showRunHistory
)
const
setShowRunHistory
=
useStore
(
state
=>
state
.
setShowRunHistory
)
const
runStaus
=
useStore
(
state
=>
state
.
runStaus
)
const
setRunStaus
=
useStore
(
state
=>
state
.
setRunStaus
)
return
(
<
div
className=
'flex items-center px-0.5 h-8 rounded-lg border-[0.5px] border-gray-200 bg-white shadow-xs'
>
...
...
@@ -18,38 +21,51 @@ const RunAndHistory: FC = () => {
className=
{
`
flex items-center px-1.5 h-7 rounded-md text-[13px] font-medium text-primary-600
hover:bg-primary-50 cursor-pointer
${runStaus === 'running' && 'bg-primary-50 !cursor-not-allowed'}
${mode === 'running' && 'bg-primary-50 !cursor-not-allowed'}
${mode === 'running' && appDetail?.mode !== 'workflow' && 'opacity-50'}
`
}
onClick=
{
()
=>
runStaus
!==
'running'
&&
setRunStaus
(
'running'
)
}
onClick=
{
()
=>
mode
!==
'running'
&&
useStore
.
setState
({
mode
:
Mode
.
Running
}
)
}
>
{
runStaus
===
'running'
mode
===
'running'
?
(
<>
{
appDetail
?.
mode
===
'workflow'
&&
(
<
Loading02
className=
'mr-1 w-4 h-4 animate-spin'
/>
Running
)
}
{
appDetail
?.
mode
===
'workflow'
?
t
(
'workflow.common.running'
)
:
t
(
'workflow.common.inPreview'
)
}
</>
)
:
(
<>
<
Play
className=
'mr-1 w-4 h-4'
/>
Run
{
appDetail
?.
mode
===
'workflow'
?
t
(
'workflow.common.run'
)
:
t
(
'workflow.common.preview'
)
}
</>
)
}
</
div
>
<
div
className=
'mx-0.5 w-[0.5px] h-8 bg-gray-200'
></
div
>
<
TooltipPlus
popupContent=
'View run history'
popupContent=
{
t
(
'workflow.common.viewRunHistory'
)
}
>
<
div
className=
{
`
flex items-center justify-center w-7 h-7 rounded-md hover:bg-black/5 cursor-pointer
${showRunHistory && 'bg-
black/5
'}
${showRunHistory && 'bg-
primary-50
'}
`
}
onClick=
{
()
=>
setShowRunHistory
(
true
)
}
onClick=
{
()
=>
useStore
.
setState
({
showRunHistory
:
true
}
)
}
>
<
ClockPlay
className=
'w-4 h-4 text-gray-500'
/>
<
ClockPlay
className=
{
`w-4 h-4 ${showRunHistory ? 'text-primary-600' : 'text-gray-500'}`
}
/>
</
div
>
</
TooltipPlus
>
</
div
>
...
...
web/app/components/workflow/header/running-title.tsx
0 → 100644
View file @
0164dec4
import
{
memo
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useStore
as
useAppStore
}
from
'@/app/components/app/store'
import
{
Play
}
from
'@/app/components/base/icons/src/vender/solid/mediaAndDevices'
const
RunningTitle
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
appDetail
=
useAppStore
(
state
=>
state
.
appDetail
)
return
(
<
div
className=
'flex items-center h-[18px] text-xs text-primary-600'
>
<
Play
className=
'mr-1 w-3 h-3'
/>
{
appDetail
?.
mode
===
'advanced-chat'
?
t
(
'workflow.common.inPreviewMode'
)
:
t
(
'workflow.common.inRunMode'
)
}
<
span
className=
'mx-1'
>
·
</
span
>
<
span
className=
'text-gray-500'
>
Test Run#2
</
span
>
</
div
>
)
}
export
default
memo
(
RunningTitle
)
web/app/components/workflow/index.tsx
View file @
0164dec4
...
...
@@ -40,6 +40,7 @@ import {
import
{
useStore
as
useAppStore
}
from
'@/app/components/app/store'
import
Loading
from
'@/app/components/base/loading'
import
{
FeaturesProvider
}
from
'@/app/components/base/features'
import
type
{
Features
as
FeaturesData
}
from
'@/app/components/base/features/types'
import
{
fetchCollectionList
}
from
'@/service/tools'
const
nodeTypes
=
{
...
...
@@ -205,9 +206,24 @@ const WorkflowWrap: FC<WorkflowProps> = ({
)
}
const
features
=
data
?.
features
||
{}
const
initialFeatures
:
FeaturesData
=
{
opening
:
{
enabled
:
!!
features
.
opening_statement
,
opening_statement
:
features
.
opening_statement
,
suggested_questions
:
features
.
suggested_questions
,
},
suggested
:
features
.
suggested_questions_after_answer
||
{
enabled
:
false
},
speech2text
:
features
.
speech_to_text
||
{
enabled
:
false
},
text2speech
:
features
.
text_to_speech
||
{
enabled
:
false
},
citation
:
features
.
retriever_resource
||
{
enabled
:
false
},
moderation
:
features
.
sensitive_word_avoidance
||
{
enabled
:
false
},
annotation
:
features
.
annotation_reply
||
{
enabled
:
false
},
}
return
(
<
ReactFlowProvider
>
<
FeaturesProvider
>
<
FeaturesProvider
features=
{
initialFeatures
}
>
<
Workflow
nodes=
{
nodesData
}
edges=
{
edgesData
}
...
...
web/app/components/workflow/nodes/_base/panel.tsx
View file @
0164dec4
...
...
@@ -48,7 +48,7 @@ const BasePanel: FC<BasePanelProps> = ({
},
[
handleNodeDataUpdate
,
id
,
data
])
return
(
<
div
className=
'
mr-2
w-[420px] h-full bg-white shadow-lg border-[0.5px] border-gray-200 rounded-2xl overflow-y-auto'
>
<
div
className=
'w-[420px] h-full bg-white shadow-lg border-[0.5px] border-gray-200 rounded-2xl overflow-y-auto'
>
<
div
className=
'sticky top-0 bg-white border-b-[0.5px] border-black/5 z-10'
>
<
div
className=
'flex items-center px-4 pt-4 pb-1'
>
{
...
...
web/app/components/workflow/panel/index.tsx
View file @
0164dec4
...
...
@@ -15,7 +15,7 @@ import { useStore as useAppStore } from '@/app/components/app/store'
const
Panel
:
FC
=
()
=>
{
const
appDetail
=
useAppStore
(
state
=>
state
.
appDetail
)
const
run
Staus
=
useStore
(
state
=>
state
.
runStaus
)
const
run
TaskId
=
useStore
(
state
=>
state
.
runTaskId
)
const
nodes
=
useNodes
<
CommonNodeType
>
()
const
selectedNode
=
nodes
.
find
(
node
=>
node
.
data
.
_selected
)
const
showRunHistory
=
useStore
(
state
=>
state
.
showRunHistory
)
...
...
@@ -25,16 +25,16 @@ const Panel: FC = () => {
showDebugAndPreviewPanel
,
}
=
useMemo
(()
=>
{
return
{
showWorkflowInfoPanel
:
appDetail
?.
mode
===
'workflow'
&&
!
selectedNode
,
showNodePanel
:
!!
selectedNode
,
showDebugAndPreviewPanel
:
appDetail
?.
mode
===
'advanced-chat'
&&
!
selectedNode
,
showWorkflowInfoPanel
:
appDetail
?.
mode
===
'workflow'
&&
!
selectedNode
&&
!
runTaskId
,
showNodePanel
:
!!
selectedNode
&&
!
runTaskId
,
showDebugAndPreviewPanel
:
appDetail
?.
mode
===
'advanced-chat'
&&
!
selectedNode
&&
!
runTaskId
,
}
},
[
selectedNode
,
appDetail
])
},
[
selectedNode
,
appDetail
,
runTaskId
])
return
(
<
div
className=
'absolute top-14 right-0 bottom-2 flex z-10'
>
{
run
Staus
&&
(
run
TaskId
&&
(
<
Record
/>
)
}
...
...
web/app/components/workflow/panel/run-history.tsx
View file @
0164dec4
import
{
useStore
}
from
'../store'
import
{
CheckCircle
,
XClose
,
}
from
'@/app/components/base/icons/src/vender/line/general'
import
{
memo
}
from
'react'
import
{
XClose
}
from
'@/app/components/base/icons/src/vender/line/general'
import
{
AlertCircle
}
from
'@/app/components/base/icons/src/vender/line/alertsAndFeedback'
import
{
useStore
}
from
'@/app/components/workflow/store'
import
{
useStore
as
useAppStore
}
from
'@/app/components/app/store'
const
RunHistory
=
()
=>
{
const
mode
=
useStore
(
state
=>
state
.
mode
)
const
setShowRunHistory
=
useStore
(
state
=>
state
.
setShowRunHistory
)
const
setRunStaus
=
useStore
(
state
=>
state
.
setRunStaus
)
const
appDetail
=
useAppStore
(
state
=>
state
.
appDetail
)
return
(
<
div
className=
'w-[200px] h-full bg-white border-[0.5px] border-gray-200 shadow-xl rounded-l-2xl'
>
<
div
className=
'
ml-2
w-[200px] h-full bg-white border-[0.5px] border-gray-200 shadow-xl rounded-l-2xl'
>
<
div
className=
'flex items-center justify-between px-4 pt-3 text-base font-semibold text-gray-900'
>
Run History
<
div
className=
'flex items-center justify-center w-6 h-6 cursor-pointer'
onClick=
{
()
=>
setShowRunHistory
(
false
)
}
onClick=
{
()
=>
useStore
.
setState
({
showRunHistory
:
false
}
)
}
>
<
XClose
className=
'w-4 h-4 text-gray-500'
/>
</
div
>
</
div
>
<
div
className=
'p-2'
>
{
mode
===
'workflow'
&&
(
<
div
className=
'flex mb-0.5 px-2 py-[7px] rounded-lg hover:bg-primary-50 cursor-pointer'
>
<
CheckCircle
className=
'mt-0.5 mr-1.5 w-3.5 h-3.5 text-[#12B76A]'
/>
<
div
>
<
div
className=
'flex items-center text-[13px] font-medium text-primary-600 leading-[18px]'
>
Test Run#7
</
div
>
<
div
className=
'flex items-center text-xs text-gray-500 leading-[18px]'
>
Evan · 2 min ago
</
div
>
</
div
>
</
div
>
)
}
<
div
className=
'flex px-2 py-[7px] rounded-lg hover:bg-primary-50 cursor-pointer'
onClick=
{
()
=>
setRunStaus
(
'finished'
)
}
className=
'flex
mb-0.5
px-2 py-[7px] rounded-lg hover:bg-primary-50 cursor-pointer'
onClick=
{
()
=>
useStore
.
setState
({
runTaskId
:
'1'
}
)
}
>
{
appDetail
?.
mode
===
'advanced-chat'
&&
(
<
AlertCircle
className=
'mt-0.5 mr-1.5 w-3.5 h-3.5 text-[#F79009]'
/>
)
}
<
div
>
<
div
className=
'flex items-center text-[13px] font-medium text-primary-600 leading-[18px]'
>
Test Run#6
</
div
>
<
div
className=
'flex items-center text-xs text-gray-500 leading-[18px]'
>
...
...
@@ -52,4 +40,4 @@ const RunHistory = () => {
)
}
export
default
RunHistory
export
default
memo
(
RunHistory
)
web/app/components/workflow/panel/workflow-info.tsx
View file @
0164dec4
...
...
@@ -14,7 +14,7 @@ const WorkflowInfo: FC = () => {
return
null
return
(
<
div
className=
'
mr-2
w-[420px] h-full bg-white shadow-lg border-[0.5px] border-gray-200 rounded-2xl overflow-y-auto'
>
<
div
className=
'w-[420px] h-full bg-white shadow-lg border-[0.5px] border-gray-200 rounded-2xl overflow-y-auto'
>
<
div
className=
'sticky top-0 bg-white border-b-[0.5px] border-black/5'
>
<
div
className=
'flex pt-4 px-4 pb-1'
>
<
AppIcon
...
...
web/app/components/workflow/store.ts
View file @
0164dec4
...
...
@@ -5,38 +5,43 @@ import type {
ToolInWorkflow
,
ToolsMap
,
}
from
'./block-selector/types'
import
{
Mode
}
from
'./types'
type
State
=
{
mode
:
string
mode
:
Mode
runTaskId
:
string
showRunHistory
:
boolean
showFeaturesPanel
:
boolean
runStaus
:
string
isDragging
:
boolean
helpLine
?:
HelpLinePosition
toolsets
:
CollectionWithExpanded
[]
toolsMap
:
ToolsMap
draftUpdatedAt
:
number
publishedAt
:
number
}
type
Action
=
{
setMode
:
(
mode
:
Mode
)
=>
void
setRunTaskId
:
(
runTaskId
:
string
)
=>
void
setShowRunHistory
:
(
showRunHistory
:
boolean
)
=>
void
setShowFeaturesPanel
:
(
showFeaturesPanel
:
boolean
)
=>
void
setRunStaus
:
(
runStaus
:
string
)
=>
void
setIsDragging
:
(
isDragging
:
boolean
)
=>
void
setHelpLine
:
(
helpLine
?:
HelpLinePosition
)
=>
void
setToolsets
:
(
toolsets
:
CollectionWithExpanded
[])
=>
void
setToolsMap
:
(
toolsMap
:
Record
<
string
,
ToolInWorkflow
[]
>
)
=>
void
setDraftUpdatedAt
:
(
draftUpdatedAt
:
number
)
=>
void
setPublishedAt
:
(
publishedAt
:
number
)
=>
void
}
export
const
useStore
=
create
<
State
&
Action
>
(
set
=>
({
mode
:
'workflow'
,
mode
:
Mode
.
Editing
,
runTaskId
:
''
,
setRunTaskId
:
runTaskId
=>
set
(()
=>
({
runTaskId
})),
setMode
:
mode
=>
set
(()
=>
({
mode
})),
showRunHistory
:
false
,
setShowRunHistory
:
showRunHistory
=>
set
(()
=>
({
showRunHistory
})),
showFeaturesPanel
:
false
,
setShowFeaturesPanel
:
showFeaturesPanel
=>
set
(()
=>
({
showFeaturesPanel
})),
runStaus
:
''
,
setRunStaus
:
runStaus
=>
set
(()
=>
({
runStaus
})),
isDragging
:
false
,
setIsDragging
:
isDragging
=>
set
(()
=>
({
isDragging
})),
helpLine
:
undefined
,
...
...
@@ -47,4 +52,6 @@ export const useStore = create<State & Action>(set => ({
setToolsMap
:
toolsMap
=>
set
(()
=>
({
toolsMap
})),
draftUpdatedAt
:
0
,
setDraftUpdatedAt
:
draftUpdatedAt
=>
set
(()
=>
({
draftUpdatedAt
})),
publishedAt
:
0
,
setPublishedAt
:
publishedAt
=>
set
(()
=>
({
publishedAt
})),
}))
web/app/components/workflow/types.ts
View file @
0164dec4
...
...
@@ -139,3 +139,8 @@ export type NodeDefault<T> = {
}
export
type
OnSelectBlock
=
(
type
:
BlockEnum
,
toolDefaultValue
?:
ToolDefaultValue
)
=>
void
export
enum
Mode
{
Editing
=
'editing'
,
Running
=
'running'
,
}
web/app/components/workflow/zoom-in-out.tsx
deleted
100644 → 0
View file @
4edaa95c
import
type
{
FC
}
from
'react'
import
{
Fragment
,
memo
,
useState
,
}
from
'react'
import
{
useReactFlow
}
from
'reactflow'
import
{
PortalToFollowElem
,
PortalToFollowElemContent
,
PortalToFollowElemTrigger
,
}
from
'@/app/components/base/portal-to-follow-elem'
import
{
SearchLg
}
from
'@/app/components/base/icons/src/vender/line/general'
import
{
ChevronDown
}
from
'@/app/components/base/icons/src/vender/line/arrows'
const
ZOOM_IN_OUT_OPTIONS
=
[
[
{
key
:
'in'
,
text
:
'Zoom In'
,
},
{
key
:
'out'
,
text
:
'Zoom Out'
,
},
],
[
{
key
:
'to50'
,
text
:
'Zoom to 50%'
,
},
{
key
:
'to100'
,
text
:
'Zoom to 100%'
,
},
],
[
{
key
:
'fit'
,
text
:
'Zoom to Fit'
,
},
],
]
const
ZoomInOut
:
FC
=
()
=>
{
const
reactFlow
=
useReactFlow
()
const
[
open
,
setOpen
]
=
useState
(
false
)
const
handleZoom
=
(
type
:
string
)
=>
{
if
(
type
===
'in'
)
reactFlow
.
zoomIn
()
if
(
type
===
'out'
)
reactFlow
.
zoomOut
()
if
(
type
===
'fit'
)
reactFlow
.
fitView
()
}
return
(
<
PortalToFollowElem
placement=
'top-start'
open=
{
open
}
onOpenChange=
{
setOpen
}
offset=
{
4
}
>
<
PortalToFollowElemTrigger
asChild
onClick=
{
()
=>
setOpen
(
v
=>
!
v
)
}
>
<
div
className=
{
`
absolute left-6 bottom-6
flex items-center px-2.5 h-9 cursor-pointer rounded-lg border-[0.5px] border-gray-100 bg-white shadow-lg
text-[13px] text-gray-500 z-10
`
}
>
<
SearchLg
className=
'mr-1 w-4 h-4'
/>
100%
<
ChevronDown
className=
'ml-1 w-4 h-4'
/>
</
div
>
</
PortalToFollowElemTrigger
>
<
PortalToFollowElemContent
>
<
div
className=
'w-[168px] rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg'
>
{
ZOOM_IN_OUT_OPTIONS
.
map
((
options
,
i
)
=>
(
<
Fragment
key=
{
i
}
>
{
i
!==
0
&&
(
<
div
className=
'h-[1px] bg-gray-100'
/>
)
}
<
div
className=
'p-1'
>
{
options
.
map
(
option
=>
(
<
div
key=
{
option
.
key
}
className=
'flex items-center px-3 h-8 rounded-lg hover:bg-gray-50 cursor-pointer text-sm text-gray-700'
onClick=
{
()
=>
handleZoom
(
option
.
key
)
}
>
{
option
.
text
}
</
div
>
))
}
</
div
>
</
Fragment
>
))
}
</
div
>
</
PortalToFollowElemContent
>
</
PortalToFollowElem
>
)
}
export
default
memo
(
ZoomInOut
)
web/i18n/en-US/workflow.ts
View file @
0164dec4
...
...
@@ -6,6 +6,7 @@ const translation = {
published
:
'Published'
,
publish
:
'Publish'
,
run
:
'Run'
,
running
:
'Running'
,
inRunMode
:
'In Run Mode'
,
inPreview
:
'In Preview'
,
inPreviewMode
:
'In Preview Mode'
,
...
...
web/i18n/zh-Hans/workflow.ts
View file @
0164dec4
...
...
@@ -6,7 +6,8 @@ const translation = {
published
:
'已发布'
,
publish
:
'发布'
,
run
:
'运行'
,
inRunMode
:
'运行中'
,
running
:
'运行中'
,
inRunMode
:
'在运行模式中'
,
inPreview
:
'预览中'
,
inPreviewMode
:
'预览中'
,
preview
:
'预览'
,
...
...
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