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
bd6248ea
Commit
bd6248ea
authored
Jul 25, 2023
by
StyleZhang
Browse files
Options
Browse Files
Download
Plain Diff
merge main
parents
52cf3c98
dd1172b5
Changes
81
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
81 changed files
with
1226 additions
and
459 deletions
+1226
-459
Dockerfile
api/Dockerfile
+1
-1
commands.py
api/commands.py
+62
-4
config.py
api/config.py
+3
-1
datasets.py
api/controllers/console/datasets/datasets.py
+0
-1
azure_provider.py
api/core/llm/provider/azure_provider.py
+32
-44
Dockerfile
web/Dockerfile
+1
-1
layout.tsx
web/app/(commonLayout)/layout.tsx
+4
-1
index.tsx
web/app/components/app/configuration/config/index.tsx
+3
-3
index.tsx
web/app/components/app/configuration/debug/index.tsx
+4
-4
index.tsx
...components/app/configuration/prompt-value-panel/index.tsx
+1
-0
index.tsx
web/app/components/app/overview/embedded/index.tsx
+24
-3
index.tsx
web/app/components/base/avatar/index.tsx
+15
-13
dify.svg
web/app/components/base/icons/assets/public/common/dify.svg
+8
-0
github.svg
...app/components/base/icons/assets/public/common/github.svg
+5
-0
arrow-up-right.svg
...s/base/icons/assets/vender/line/arrows/arrow-up-right.svg
+5
-0
chevron-down.svg
...nts/base/icons/assets/vender/line/arrows/chevron-down.svg
+5
-0
chevron-right.svg
...ts/base/icons/assets/vender/line/arrows/chevron-right.svg
+5
-0
check.svg
...omponents/base/icons/assets/vender/line/general/check.svg
+5
-0
log-out-01.svg
...ents/base/icons/assets/vender/line/general/log-out-01.svg
+5
-0
terminal-square.svg
...icons/assets/vender/solid/development/terminal-square.svg
+5
-0
beaker-02.svg
...ts/base/icons/assets/vender/solid/education/beaker-02.svg
+5
-0
Dify.json
web/app/components/base/icons/src/public/common/Dify.json
+62
-0
Dify.tsx
web/app/components/base/icons/src/public/common/Dify.tsx
+14
-0
Github.json
web/app/components/base/icons/src/public/common/Github.json
+36
-0
Github.tsx
web/app/components/base/icons/src/public/common/Github.tsx
+14
-0
index.ts
web/app/components/base/icons/src/public/common/index.ts
+2
-0
ArrowUpRight.json
...nents/base/icons/src/vender/line/arrows/ArrowUpRight.json
+39
-0
ArrowUpRight.tsx
...onents/base/icons/src/vender/line/arrows/ArrowUpRight.tsx
+14
-0
ChevronDown.json
...onents/base/icons/src/vender/line/arrows/ChevronDown.json
+39
-0
ChevronDown.tsx
...ponents/base/icons/src/vender/line/arrows/ChevronDown.tsx
+14
-0
ChevronRight.json
...nents/base/icons/src/vender/line/arrows/ChevronRight.json
+39
-0
ChevronRight.tsx
...onents/base/icons/src/vender/line/arrows/ChevronRight.tsx
+14
-0
index.ts
...app/components/base/icons/src/vender/line/arrows/index.ts
+3
-0
Check.json
.../components/base/icons/src/vender/line/general/Check.json
+39
-0
Check.tsx
...p/components/base/icons/src/vender/line/general/Check.tsx
+14
-0
LogOut01.json
...mponents/base/icons/src/vender/line/general/LogOut01.json
+39
-0
LogOut01.tsx
...omponents/base/icons/src/vender/line/general/LogOut01.tsx
+14
-0
index.ts
...pp/components/base/icons/src/vender/line/general/index.ts
+2
-0
TerminalSquare.json
...se/icons/src/vender/solid/development/TerminalSquare.json
+38
-0
TerminalSquare.tsx
...ase/icons/src/vender/solid/development/TerminalSquare.tsx
+14
-0
index.ts
...mponents/base/icons/src/vender/solid/development/index.ts
+1
-0
Beaker02.json
...nents/base/icons/src/vender/solid/education/Beaker02.json
+38
-0
Beaker02.tsx
...onents/base/icons/src/vender/solid/education/Beaker02.tsx
+14
-0
index.ts
...components/base/icons/src/vender/solid/education/index.ts
+1
-0
utils.ts
web/app/components/base/icons/utils.ts
+1
-0
index.tsx
web/app/components/base/select/index.tsx
+8
-6
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
HeaderWrapper.tsx
web/app/components/header/HeaderWrapper.tsx
+34
-0
index.module.css
web/app/components/header/account-about/index.module.css
+1
-1
index.tsx
web/app/components/header/account-about/index.tsx
+8
-8
index.tsx
web/app/components/header/account-dropdown/index.tsx
+93
-92
index.tsx
...ents/header/account-dropdown/workplace-selector/index.tsx
+19
-18
invitation-link.tsx
...nt-setting/members-page/invited-modal/invitation-link.tsx
+5
-3
index.tsx
web/app/components/header/app-nav/index.tsx
+2
-0
beaker.svg
web/app/components/header/assets/beaker.svg
+0
-3
github-icon.svg
web/app/components/header/assets/github-icon.svg
+0
-3
index.tsx
web/app/components/header/dataset-nav/index.tsx
+2
-0
index.tsx
web/app/components/header/env-nav/index.tsx
+46
-0
index.tsx
web/app/components/header/explore-nav/index.tsx
+37
-0
index.tsx
web/app/components/header/github-star/index.tsx
+40
-0
index.module.css
web/app/components/header/index.module.css
+0
-15
index.tsx
web/app/components/header/index.tsx
+25
-120
index.tsx
web/app/components/header/plugin-nav/index.tsx
+37
-0
index.tsx
web/app/components/share/chat/index.tsx
+4
-4
index.tsx
web/app/components/share/chat/sidebar/list/index.tsx
+4
-1
index.tsx
web/app/components/share/chat/welcome/index.tsx
+52
-48
index.tsx
web/app/components/share/chatbot/index.tsx
+4
-4
index.tsx
web/app/components/share/chatbot/welcome/index.tsx
+4
-4
header.tsx
web/app/components/share/header.tsx
+40
-9
index.tsx
web/app/components/share/text-generation/result/index.tsx
+4
-4
installForm.tsx
web/app/install/installForm.tsx
+11
-1
app-context.tsx
web/context/app-context.tsx
+1
-1
use-copy-to-clipboard.ts
web/hooks/use-copy-to-clipboard.ts
+20
-18
app-debug.en.ts
web/i18n/lang/app-debug.en.ts
+1
-1
app-debug.zh.ts
web/i18n/lang/app-debug.zh.ts
+1
-1
common.zh.ts
web/i18n/lang/common.zh.ts
+1
-1
package.json
web/package.json
+1
-1
embed.js
web/public/embed.js
+2
-1
embed.min.js
web/public/embed.min.js
+2
-2
No files found.
api/Dockerfile
View file @
bd6248ea
...
...
@@ -27,4 +27,4 @@ RUN chmod +x /entrypoint.sh
ARG
COMMIT_SHA
ENV
COMMIT_SHA ${COMMIT_SHA}
ENTRYPOINT
["/entrypoint.sh"]
\ No newline at end of file
ENTRYPOINT
["/bin/bash", "/entrypoint.sh"]
\ No newline at end of file
api/commands.py
View file @
bd6248ea
...
...
@@ -2,6 +2,7 @@ import datetime
import
logging
import
random
import
string
import
time
import
click
from
flask
import
current_app
...
...
@@ -13,7 +14,7 @@ from libs.helper import email as email_validate
from
extensions.ext_database
import
db
from
libs.rsa
import
generate_key_pair
from
models.account
import
InvitationCode
,
Tenant
from
models.dataset
import
Dataset
from
models.dataset
import
Dataset
,
DatasetQuery
,
Document
,
DocumentSegment
from
models.model
import
Account
import
secrets
import
base64
...
...
@@ -172,7 +173,7 @@ def recreate_all_dataset_indexes():
page
=
1
while
True
:
try
:
datasets
=
db
.
session
.
query
(
Dataset
)
.
filter
(
Dataset
.
indexing_technique
==
'high_quality'
)
\
datasets
=
db
.
session
.
query
(
Dataset
)
.
filter
(
Dataset
.
indexing_technique
==
'high_quality'
)
\
.
order_by
(
Dataset
.
created_at
.
desc
())
.
paginate
(
page
=
page
,
per_page
=
50
)
except
NotFound
:
break
...
...
@@ -188,12 +189,66 @@ def recreate_all_dataset_indexes():
else
:
click
.
echo
(
'passed.'
)
except
Exception
as
e
:
click
.
echo
(
click
.
style
(
'Recreate dataset index error: {} {}'
.
format
(
e
.
__class__
.
__name__
,
str
(
e
)),
fg
=
'red'
))
click
.
echo
(
click
.
style
(
'Recreate dataset index error: {} {}'
.
format
(
e
.
__class__
.
__name__
,
str
(
e
)),
fg
=
'red'
))
continue
click
.
echo
(
click
.
style
(
'Congratulations! Recreate {} dataset indexes.'
.
format
(
recreate_count
),
fg
=
'green'
))
@
click
.
command
(
'clean-unused-dataset-indexes'
,
help
=
'Clean unused dataset indexes.'
)
def
clean_unused_dataset_indexes
():
click
.
echo
(
click
.
style
(
'Start clean unused dataset indexes.'
,
fg
=
'green'
))
clean_days
=
int
(
current_app
.
config
.
get
(
'CLEAN_DAY_SETTING'
))
start_at
=
time
.
perf_counter
()
thirty_days_ago
=
datetime
.
datetime
.
now
()
-
datetime
.
timedelta
(
days
=
clean_days
)
page
=
1
while
True
:
try
:
datasets
=
db
.
session
.
query
(
Dataset
)
.
filter
(
Dataset
.
created_at
<
thirty_days_ago
)
\
.
order_by
(
Dataset
.
created_at
.
desc
())
.
paginate
(
page
=
page
,
per_page
=
50
)
except
NotFound
:
break
page
+=
1
for
dataset
in
datasets
:
dataset_query
=
db
.
session
.
query
(
DatasetQuery
)
.
filter
(
DatasetQuery
.
created_at
>
thirty_days_ago
,
DatasetQuery
.
dataset_id
==
dataset
.
id
)
.
all
()
if
not
dataset_query
or
len
(
dataset_query
)
==
0
:
documents
=
db
.
session
.
query
(
Document
)
.
filter
(
Document
.
dataset_id
==
dataset
.
id
,
Document
.
indexing_status
==
'completed'
,
Document
.
enabled
==
True
,
Document
.
archived
==
False
,
Document
.
updated_at
>
thirty_days_ago
)
.
all
()
if
not
documents
or
len
(
documents
)
==
0
:
try
:
# remove index
vector_index
=
IndexBuilder
.
get_index
(
dataset
,
'high_quality'
)
kw_index
=
IndexBuilder
.
get_index
(
dataset
,
'economy'
)
# delete from vector index
if
vector_index
:
vector_index
.
delete
()
kw_index
.
delete
()
# update document
update_params
=
{
Document
.
enabled
:
False
}
Document
.
query
.
filter_by
(
dataset_id
=
dataset
.
id
)
.
update
(
update_params
)
db
.
session
.
commit
()
click
.
echo
(
click
.
style
(
'Cleaned unused dataset {} from db success!'
.
format
(
dataset
.
id
),
fg
=
'green'
))
except
Exception
as
e
:
click
.
echo
(
click
.
style
(
'clean dataset index error: {} {}'
.
format
(
e
.
__class__
.
__name__
,
str
(
e
)),
fg
=
'red'
))
end_at
=
time
.
perf_counter
()
click
.
echo
(
click
.
style
(
'Cleaned unused dataset from db success latency: {}'
.
format
(
end_at
-
start_at
),
fg
=
'green'
))
@
click
.
command
(
'sync-anthropic-hosted-providers'
,
help
=
'Sync anthropic hosted providers.'
)
def
sync_anthropic_hosted_providers
():
click
.
echo
(
click
.
style
(
'Start sync anthropic hosted providers.'
,
fg
=
'green'
))
...
...
@@ -218,7 +273,9 @@ def sync_anthropic_hosted_providers():
)
count
+=
1
except
Exception
as
e
:
click
.
echo
(
click
.
style
(
'Sync tenant anthropic hosted provider error: {} {}'
.
format
(
e
.
__class__
.
__name__
,
str
(
e
)),
fg
=
'red'
))
click
.
echo
(
click
.
style
(
'Sync tenant anthropic hosted provider error: {} {}'
.
format
(
e
.
__class__
.
__name__
,
str
(
e
)),
fg
=
'red'
))
continue
click
.
echo
(
click
.
style
(
'Congratulations! Synced {} anthropic hosted providers.'
.
format
(
count
),
fg
=
'green'
))
...
...
@@ -231,3 +288,4 @@ def register_commands(app):
app
.
cli
.
add_command
(
reset_encrypt_key_pair
)
app
.
cli
.
add_command
(
recreate_all_dataset_indexes
)
app
.
cli
.
add_command
(
sync_anthropic_hosted_providers
)
app
.
cli
.
add_command
(
clean_unused_dataset_indexes
)
api/config.py
View file @
bd6248ea
...
...
@@ -53,7 +53,8 @@ DEFAULTS = {
'DEFAULT_LLM_PROVIDER'
:
'openai'
,
'OPENAI_HOSTED_QUOTA_LIMIT'
:
200
,
'ANTHROPIC_HOSTED_QUOTA_LIMIT'
:
1000
,
'TENANT_DOCUMENT_COUNT'
:
100
'TENANT_DOCUMENT_COUNT'
:
100
,
'CLEAN_DAY_SETTING'
:
30
}
...
...
@@ -215,6 +216,7 @@ class Config:
self
.
NOTION_INTEGRATION_TOKEN
=
get_env
(
'NOTION_INTEGRATION_TOKEN'
)
self
.
TENANT_DOCUMENT_COUNT
=
get_env
(
'TENANT_DOCUMENT_COUNT'
)
self
.
CLEAN_DAY_SETTING
=
get_env
(
'CLEAN_DAY_SETTING'
)
class
CloudEditionConfig
(
Config
):
...
...
api/controllers/console/datasets/datasets.py
View file @
bd6248ea
...
...
@@ -3,7 +3,6 @@ from flask import request
from
flask_login
import
login_required
,
current_user
from
flask_restful
import
Resource
,
reqparse
,
fields
,
marshal
,
marshal_with
from
werkzeug.exceptions
import
NotFound
,
Forbidden
import
services
from
controllers.console
import
api
from
controllers.console.datasets.error
import
DatasetNameDuplicateError
...
...
api/core/llm/provider/azure_provider.py
View file @
bd6248ea
...
...
@@ -2,6 +2,7 @@ import json
import
logging
from
typing
import
Optional
,
Union
import
openai
import
requests
from
core.llm.provider.base
import
BaseProvider
...
...
@@ -11,30 +12,37 @@ from models.provider import ProviderName
class
AzureProvider
(
BaseProvider
):
def
get_models
(
self
,
model_id
:
Optional
[
str
]
=
None
,
credentials
:
Optional
[
dict
]
=
None
)
->
list
[
dict
]:
credentials
=
self
.
get_credentials
(
model_id
)
if
not
credentials
else
credentials
url
=
"{}/openai/deployments?api-version={}"
.
format
(
str
(
credentials
.
get
(
'openai_api_base'
)),
str
(
credentials
.
get
(
'openai_api_version'
))
)
headers
=
{
"api-key"
:
str
(
credentials
.
get
(
'openai_api_key'
))
,
"content-type"
:
"application/json; charset=utf-8"
}
response
=
requests
.
get
(
url
,
headers
=
headers
)
if
response
.
status_code
==
200
:
r
esult
=
response
.
json
(
)
return
[{
'id'
:
deployment
[
'id'
],
'
name'
:
'{} ({})'
.
format
(
deployment
[
'id'
],
deployment
[
'model'
]
)
}
for
deployment
in
result
[
'data'
]
if
deployment
[
'status'
]
==
'succeeded'
]
else
:
if
response
.
status_code
==
401
:
raise
AzureAuthenticationError
(
)
return
[]
def
check_embedding_model
(
self
,
credentials
:
Optional
[
dict
]
=
None
):
credentials
=
self
.
get_credentials
(
'text-embedding-ada-002'
)
if
not
credentials
else
credentials
try
:
result
=
openai
.
Embedding
.
create
(
input
=
[
'test'
],
engine
=
'text-embedding-ada-002'
,
timeout
=
60
,
api_key
=
str
(
credentials
.
get
(
'openai_api_key'
)),
api_base
=
str
(
credentials
.
get
(
'openai_api_base'
)),
api_type
=
'azure'
,
api_version
=
str
(
credentials
.
get
(
'openai_api_version'
)))[
"data"
][
0
][
"embedding"
]
except
openai
.
error
.
AuthenticationError
as
e
:
r
aise
AzureAuthenticationError
(
str
(
e
)
)
except
openai
.
error
.
APIConnectionError
as
e
:
raise
AzureRequestFailedError
(
'
Failed to request Azure OpenAI, please check your API Base Endpoint, The format is `https://xxx.openai.azure.com/`'
)
except
openai
.
error
.
InvalidRequestError
as
e
:
if
e
.
http_status
==
404
:
raise
AzureRequestFailedError
(
"Please check your 'gpt-3.5-turbo' or 'text-embedding-ada-002' "
"deployment name is exists in Azure AI"
)
else
:
raise
AzureRequestFailedError
(
'Failed to request Azure OpenAI. Status code: {}'
.
format
(
response
.
status_code
))
raise
AzureRequestFailedError
(
'Failed to request Azure OpenAI. cause: {}'
.
format
(
str
(
e
)))
except
openai
.
error
.
OpenAIError
as
e
:
raise
AzureRequestFailedError
(
'Failed to request Azure OpenAI. cause: {}'
.
format
(
str
(
e
)))
if
not
isinstance
(
result
,
list
):
raise
AzureRequestFailedError
(
'Failed to request Azure OpenAI.'
)
def
get_credentials
(
self
,
model_id
:
Optional
[
str
]
=
None
)
->
dict
:
"""
...
...
@@ -94,31 +102,11 @@ class AzureProvider(BaseProvider):
if
'openai_api_version'
not
in
config
:
config
[
'openai_api_version'
]
=
'2023-03-15-preview'
models
=
self
.
get_models
(
credentials
=
config
)
if
not
models
:
raise
ValidateFailedError
(
"Please add deployments for "
"'gpt-3.5-turbo', 'text-embedding-ada-002' (required) "
"and 'gpt-4', 'gpt-35-turbo-16k', 'text-davinci-003' (optional)."
)
fixed_model_ids
=
[
'gpt-35-turbo'
,
'text-embedding-ada-002'
]
current_model_ids
=
[
model
[
'id'
]
for
model
in
models
]
missing_model_ids
=
[
fixed_model_id
for
fixed_model_id
in
fixed_model_ids
if
fixed_model_id
not
in
current_model_ids
]
if
missing_model_ids
:
raise
ValidateFailedError
(
"Please add deployments for '{}'."
.
format
(
", "
.
join
(
missing_model_ids
)))
self
.
check_embedding_model
(
credentials
=
config
)
except
ValidateFailedError
as
e
:
raise
e
except
AzureAuthenticationError
:
raise
ValidateFailedError
(
'Validation failed, please check your API Key.'
)
except
(
requests
.
ConnectionError
,
requests
.
RequestException
):
raise
ValidateFailedError
(
'Validation failed, please check your API Base Endpoint.'
)
except
AzureRequestFailedError
as
ex
:
raise
ValidateFailedError
(
'Validation failed, error: {}.'
.
format
(
str
(
ex
)))
except
Exception
as
ex
:
...
...
web/Dockerfile
View file @
bd6248ea
...
...
@@ -26,4 +26,4 @@ RUN chmod +x /entrypoint.sh
ARG
COMMIT_SHA
ENV
COMMIT_SHA ${COMMIT_SHA}
ENTRYPOINT
["/entrypoint.sh"]
ENTRYPOINT
["/
bin/bash", "/
entrypoint.sh"]
web/app/(commonLayout)/layout.tsx
View file @
bd6248ea
...
...
@@ -3,6 +3,7 @@ import type { ReactNode } from 'react'
import
SwrInitor
from
'@/app/components/swr-initor'
import
{
AppContextProvider
}
from
'@/context/app-context'
import
GA
,
{
GaType
}
from
'@/app/components/base/ga'
import
HeaderWrapper
from
'@/app/components/header/HeaderWrapper'
import
Header
from
'@/app/components/header'
const
Layout
=
({
children
}:
{
children
:
ReactNode
})
=>
{
...
...
@@ -11,7 +12,9 @@ const Layout = ({ children }: { children: ReactNode }) => {
<
GA
gaType=
{
GaType
.
admin
}
/>
<
SwrInitor
>
<
AppContextProvider
>
<
Header
/>
<
HeaderWrapper
>
<
Header
/>
</
HeaderWrapper
>
{
children
}
</
AppContextProvider
>
</
SwrInitor
>
...
...
web/app/components/app/configuration/config/index.tsx
View file @
bd6248ea
...
...
@@ -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
&&
(
...
...
web/app/components/app/configuration/debug/index.tsx
View file @
bd6248ea
...
...
@@ -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
=
tru
e
hasEmptyInput
=
nam
e
})
if
(
hasEmptyInput
)
{
logError
(
t
(
'appDebug.errorMessage.valueOfVarRequired'
))
logError
(
t
(
'appDebug.errorMessage.valueOfVarRequired'
,
{
key
:
hasEmptyInput
}
))
return
false
}
return
!
hasEmptyInput
...
...
web/app/components/app/configuration/prompt-value-panel/index.tsx
View file @
bd6248ea
...
...
@@ -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]'
/>
)
:
(
...
...
web/app/components/app/overview/embedded/index.tsx
View file @
bd6248ea
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/avatar/index.tsx
View file @
bd6248ea
'use client'
import
cn
from
'classnames'
interface
IAvatarProps
{
type
AvatarProps
=
{
name
:
string
avatar
?:
string
size
?:
number
className
?:
string
textClassName
?:
string
}
const
Avatar
=
({
name
,
avatar
,
size
=
30
,
className
}:
IAvatarProps
)
=>
{
const
avatarClassName
=
`shrink-0 flex items-center rounded-full bg-primary-600`
const
style
=
{
width
:
`
${
size
}
px`
,
height
:
`
${
size
}
px`
,
fontSize
:
`
${
size
}
px`
,
lineHeight
:
`
${
size
}
px`
}
className
,
textClassName
,
}:
AvatarProps
)
=>
{
const
avatarClassName
=
'shrink-0 flex items-center rounded-full bg-primary-600'
const
style
=
{
width
:
`
${
size
}
px`
,
height
:
`
${
size
}
px`
,
fontSize
:
`
${
size
}
px`
,
lineHeight
:
`
${
size
}
px`
}
if
(
avatar
)
{
return
(
<
img
className=
{
cn
(
avatarClassName
,
className
)
}
<
img
className=
{
cn
(
avatarClassName
,
className
)
}
style=
{
style
}
alt=
{
name
}
alt=
{
name
}
src=
{
avatar
}
/>
)
}
return
(
<
div
className=
{
cn
(
avatarClassName
,
className
)
}
<
div
className=
{
cn
(
avatarClassName
,
className
)
}
style=
{
style
}
>
<
div
className=
{
`text-center text-white scale-[0.4]`
}
<
div
className=
{
cn
(
textClassName
,
'text-center text-white scale-[0.4]'
)
}
style=
{
style
}
>
{
name
[
0
].
toLocaleUpperCase
()
}
...
...
@@ -42,4 +44,4 @@ const Avatar = ({
)
}
export
default
Avatar
\ No newline at end of file
export
default
Avatar
web/app/components/base/icons/assets/public/common/dify.svg
0 → 100644
View file @
bd6248ea
<svg
width=
"50"
height=
"26"
viewBox=
"0 0 50 26"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"Dify"
>
<path
d=
"M6.61784 2.064C8.37784 2.064 9.92184 2.408 11.2498 3.096C12.5938 3.784 13.6258 4.768 14.3458 6.048C15.0818 7.312 15.4498 8.784 15.4498 10.464C15.4498 12.144 15.0818 13.616 14.3458 14.88C13.6258 16.128 12.5938 17.096 11.2498 17.784C9.92184 18.472 8.37784 18.816 6.61784 18.816H0.761841V2.064H6.61784ZM6.49784 15.96C8.25784 15.96 9.61784 15.48 10.5778 14.52C11.5378 13.56 12.0178 12.208 12.0178 10.464C12.0178 8.72 11.5378 7.36 10.5778 6.384C9.61784 5.392 8.25784 4.896 6.49784 4.896H4.12184V15.96H6.49784Z"
fill=
"#1D2939"
/>
<path
d=
"M20.869 3.936C20.277 3.936 19.781 3.752 19.381 3.384C18.997 3 18.805 2.528 18.805 1.968C18.805 1.408 18.997 0.944 19.381 0.576C19.781 0.192 20.277 0 20.869 0C21.461 0 21.949 0.192 22.333 0.576C22.733 0.944 22.933 1.408 22.933 1.968C22.933 2.528 22.733 3 22.333 3.384C21.949 3.752 21.461 3.936 20.869 3.936ZM22.525 5.52V18.816H19.165V5.52H22.525Z"
fill=
"#1D2939"
/>
<path
d=
"M33.1407 8.28H30.8127V18.816H27.4047V8.28H25.8927V5.52H27.4047V4.848C27.4047 3.216 27.8687 2.016 28.7967 1.248C29.7247 0.48 31.1247 0.12 32.9967 0.168001V3C32.1807 2.984 31.6127 3.12 31.2927 3.408C30.9727 3.696 30.8127 4.216 30.8127 4.968V5.52H33.1407V8.28Z"
fill=
"#1D2939"
/>
<path
d=
"M49.2381 5.52L41.0061 25.104H37.4301L40.3101 18.48L34.9821 5.52H38.7501L42.1821 14.808L45.6621 5.52H49.2381Z"
fill=
"#1D2939"
/>
</g>
</svg>
web/app/components/base/icons/assets/public/common/github.svg
0 → 100644
View file @
bd6248ea
<svg
width=
"18"
height=
"18"
viewBox=
"0 0 18 18"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"github"
>
<path
id=
"Vector"
d=
"M9 1.125C4.64906 1.125 1.125 4.64906 1.125 9C1.125 12.4847 3.37922 15.428 6.50953 16.4714C6.90328 16.5403 7.05094 16.3041 7.05094 16.0973C7.05094 15.9103 7.04109 15.2902 7.04109 14.6306C5.0625 14.9948 4.55062 14.1483 4.39312 13.7053C4.30453 13.4789 3.92063 12.78 3.58594 12.593C3.31031 12.4453 2.91656 12.0811 3.57609 12.0712C4.19625 12.0614 4.63922 12.6422 4.78688 12.8784C5.49563 14.0695 6.62766 13.7348 7.08047 13.5281C7.14938 13.0163 7.35609 12.6717 7.5825 12.4748C5.83031 12.278 3.99938 11.5987 3.99938 8.58656C3.99938 7.73016 4.30453 7.02141 4.80656 6.47016C4.72781 6.27328 4.45219 5.46609 4.88531 4.38328C4.88531 4.38328 5.54484 4.17656 7.05094 5.19047C7.68094 5.01328 8.35031 4.92469 9.01969 4.92469C9.68906 4.92469 10.3584 5.01328 10.9884 5.19047C12.4945 4.16672 13.1541 4.38328 13.1541 4.38328C13.5872 5.46609 13.3116 6.27328 13.2328 6.47016C13.7348 7.02141 14.04 7.72031 14.04 8.58656C14.04 11.6086 12.1992 12.278 10.447 12.4748C10.7325 12.7209 10.9786 13.1934 10.9786 13.9317C10.9786 14.985 10.9688 15.8316 10.9688 16.0973C10.9688 16.3041 11.1164 16.5502 11.5102 16.4714C13.0735 15.9436 14.432 14.9389 15.3943 13.5986C16.3567 12.2583 16.8746 10.65 16.875 9C16.875 4.64906 13.3509 1.125 9 1.125Z"
fill=
"#24292F"
/>
</g>
</svg>
web/app/components/base/icons/assets/vender/line/arrows/arrow-up-right.svg
0 → 100644
View file @
bd6248ea
<svg
width=
"14"
height=
"14"
viewBox=
"0 0 14 14"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"arrow-up-right"
>
<path
id=
"Icon"
d=
"M4.08325 9.91665L9.91659 4.08331M9.91659 4.08331H4.08325M9.91659 4.08331V9.91665"
stroke=
"#667085"
stroke-width=
"1.25"
stroke-linecap=
"round"
stroke-linejoin=
"round"
/>
</g>
</svg>
web/app/components/base/icons/assets/vender/line/arrows/chevron-down.svg
0 → 100644
View file @
bd6248ea
<svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"chevron-down"
>
<path
id=
"Icon"
d=
"M3 4.5L6 7.5L9 4.5"
stroke=
"#344054"
stroke-width=
"1.5"
stroke-linecap=
"round"
stroke-linejoin=
"round"
/>
</g>
</svg>
web/app/components/base/icons/assets/vender/line/arrows/chevron-right.svg
0 → 100644
View file @
bd6248ea
<svg
width=
"14"
height=
"14"
viewBox=
"0 0 14 14"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"chevron-right"
>
<path
id=
"Icon"
d=
"M5.25 10.5L8.75 7L5.25 3.5"
stroke=
"#667085"
stroke-width=
"1.25"
stroke-linecap=
"round"
stroke-linejoin=
"round"
/>
</g>
</svg>
web/app/components/base/icons/assets/vender/line/general/check.svg
0 → 100644
View file @
bd6248ea
<svg
width=
"16"
height=
"16"
viewBox=
"0 0 16 16"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"check"
>
<path
id=
"Icon"
d=
"M13.3334 4L6.00008 11.3333L2.66675 8"
stroke=
"#155EEF"
stroke-width=
"1.5"
stroke-linecap=
"round"
stroke-linejoin=
"round"
/>
</g>
</svg>
web/app/components/base/icons/assets/vender/line/general/log-out-01.svg
0 → 100644
View file @
bd6248ea
<svg
width=
"14"
height=
"14"
viewBox=
"0 0 14 14"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"log-out-01"
>
<path
id=
"Icon"
d=
"M9.33333 9.91667L12.25 7M12.25 7L9.33333 4.08333M12.25 7H5.25M5.25 1.75H4.55C3.56991 1.75 3.07986 1.75 2.70552 1.94074C2.37623 2.10852 2.10852 2.37623 1.94074 2.70552C1.75 3.07986 1.75 3.56991 1.75 4.55V9.45C1.75 10.4301 1.75 10.9201 1.94074 11.2945C2.10852 11.6238 2.37623 11.8915 2.70552 12.0593C3.07986 12.25 3.56991 12.25 4.55 12.25H5.25"
stroke=
"#667085"
stroke-width=
"1.25"
stroke-linecap=
"round"
stroke-linejoin=
"round"
/>
</g>
</svg>
web/app/components/base/icons/assets/vender/solid/development/terminal-square.svg
0 → 100644
View file @
bd6248ea
<svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"terminal-square"
>
<path
id=
"Solid"
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M8.91927 1H3.08073C2.81716 0.999992 2.58977 0.999984 2.40249 1.01529C2.20481 1.03144 2.00821 1.06709 1.81902 1.16349C1.53677 1.3073 1.3073 1.53677 1.16349 1.81902C1.06709 2.00821 1.03144 2.20481 1.01529 2.40249C0.999984 2.58977 0.999992 2.81714 1 3.08071V8.91927C0.999992 9.18284 0.999984 9.41023 1.01529 9.59752C1.03144 9.79519 1.06709 9.9918 1.16349 10.181C1.3073 10.4632 1.53677 10.6927 1.81902 10.8365C2.00821 10.9329 2.20481 10.9686 2.40249 10.9847C2.58977 11 2.81715 11 3.08072 11H8.91928C9.18285 11 9.41023 11 9.59752 10.9847C9.79519 10.9686 9.9918 10.9329 10.181 10.8365C10.4632 10.6927 10.6927 10.4632 10.8365 10.181C10.9329 9.9918 10.9686 9.79519 10.9847 9.59752C11 9.41023 11 9.18285 11 8.91928V3.08072C11 2.81715 11 2.58977 10.9847 2.40249C10.9686 2.20481 10.9329 2.00821 10.8365 1.81902C10.6927 1.53677 10.4632 1.3073 10.181 1.16349C9.9918 1.06709 9.79519 1.03144 9.59752 1.01529C9.41023 0.999984 9.18284 0.999992 8.91927 1ZM3.85355 4.14645C3.65829 3.95118 3.34171 3.95118 3.14645 4.14645C2.95118 4.34171 2.95118 4.65829 3.14645 4.85355L4.29289 6L3.14645 7.14645C2.95118 7.34171 2.95118 7.65829 3.14645 7.85355C3.34171 8.04882 3.65829 8.04882 3.85355 7.85355L5.35355 6.35355C5.54882 6.15829 5.54882 5.84171 5.35355 5.64645L3.85355 4.14645ZM6.5 7C6.22386 7 6 7.22386 6 7.5C6 7.77614 6.22386 8 6.5 8H8.5C8.77614 8 9 7.77614 9 7.5C9 7.22386 8.77614 7 8.5 7H6.5Z"
fill=
"#B54708"
/>
</g>
</svg>
web/app/components/base/icons/assets/vender/solid/education/beaker-02.svg
0 → 100644
View file @
bd6248ea
<svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"beaker-02"
>
<path
id=
"Solid"
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M4.13856 0.500003H7.8617C7.92126 0.49998 7.99238 0.499953 8.05504 0.505073C8.12765 0.511005 8.23165 0.526227 8.34062 0.581751C8.48174 0.653656 8.59648 0.768392 8.66838 0.909513C8.72391 1.01849 8.73913 1.12248 8.74506 1.19509C8.75018 1.25775 8.75015 1.32888 8.75013 1.38844V2.61157C8.75015 2.67113 8.75018 2.74226 8.74506 2.80492C8.73913 2.87753 8.72391 2.98153 8.66838 3.0905C8.59648 3.23162 8.48174 3.34636 8.34062 3.41826C8.23165 3.47379 8.12765 3.48901 8.05504 3.49494C8.03725 3.49639 8.01877 3.49743 8.00006 3.49817V5.2506C8.00006 5.55312 8.00408 5.61265 8.01723 5.66153C8.03245 5.71807 8.05747 5.7715 8.09117 5.81939C8.1203 5.86078 8.16346 5.90197 8.39586 6.09564L10.2807 7.66627C10.4566 7.81255 10.6116 7.94145 10.7267 8.10509C10.8278 8.24875 10.9029 8.40904 10.9486 8.57867C11.0005 8.7719 11.0003 8.97351 11.0001 9.2023C11.0001 9.39886 11.0002 9.59542 11.0002 9.79198C11.0003 9.98232 11.0005 10.1463 10.9713 10.2927C10.853 10.8877 10.3878 11.3529 9.7928 11.4712C9.64637 11.5003 9.48246 11.5002 9.29211 11.5001H2.70822C2.51787 11.5002 2.35396 11.5003 2.20753 11.4712C1.98473 11.4269 1.78014 11.334 1.60515 11.2038C1.42854 11.0725 1.28221 10.9034 1.17753 10.7077C1.10892 10.5796 1.05831 10.4401 1.02899 10.2927C0.999862 10.1463 0.999992 9.98233 1.00014 9.79199C1.00014 9.59542 1.00006 9.39886 1.00003 9.20229C0.999794 8.97351 0.999584 8.7719 1.05157 8.57867C1.09721 8.40904 1.17229 8.24875 1.27338 8.10509C1.38855 7.94145 1.54356 7.81255 1.71947 7.66627L3.60427 6.09564C3.83667 5.90197 3.87983 5.86078 3.90896 5.81939C3.94266 5.7715 3.96768 5.71807 3.9829 5.66153C3.99605 5.61265 4.00006 5.55312 4.00006 5.2506V3.49817C3.9814 3.49743 3.96297 3.49639 3.94521 3.49494C3.8726 3.48901 3.76861 3.47379 3.65964 3.41826C3.51851 3.34636 3.40378 3.23162 3.33187 3.0905C3.27635 2.98153 3.26113 2.87753 3.25519 2.80492C3.25008 2.74226 3.2501 2.67113 3.25013 2.61158V1.38844C3.2501 1.32888 3.25008 1.25775 3.25519 1.19509C3.26113 1.12248 3.27635 1.01849 3.33187 0.909513C3.40378 0.768392 3.51851 0.653656 3.65964 0.581751C3.76861 0.526227 3.8726 0.511005 3.94521 0.505073C4.00787 0.499953 4.079 0.49998 4.13856 0.500003ZM9.11909 8.00004H2.88104L4.28066 6.83373C4.45657 6.68745 4.61158 6.55855 4.72675 6.39491C4.82784 6.25125 4.90292 6.09096 4.94856 5.92133C5.00054 5.7281 5.00033 5.52649 5.0001 5.29771L5.00006 3.50001H7.00006L7.00003 5.29771C6.99979 5.52649 6.99958 5.7281 7.05157 5.92133C7.09721 6.09096 7.17229 6.25125 7.27338 6.39491C7.38855 6.55855 7.54356 6.68745 7.71947 6.83373L9.11909 8.00004Z"
fill=
"#0E7090"
/>
</g>
</svg>
web/app/components/base/icons/src/public/common/Dify.json
0 → 100644
View file @
bd6248ea
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"50"
,
"height"
:
"26"
,
"viewBox"
:
"0 0 50 26"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"id"
:
"Dify"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M6.61784 2.064C8.37784 2.064 9.92184 2.408 11.2498 3.096C12.5938 3.784 13.6258 4.768 14.3458 6.048C15.0818 7.312 15.4498 8.784 15.4498 10.464C15.4498 12.144 15.0818 13.616 14.3458 14.88C13.6258 16.128 12.5938 17.096 11.2498 17.784C9.92184 18.472 8.37784 18.816 6.61784 18.816H0.761841V2.064H6.61784ZM6.49784 15.96C8.25784 15.96 9.61784 15.48 10.5778 14.52C11.5378 13.56 12.0178 12.208 12.0178 10.464C12.0178 8.72 11.5378 7.36 10.5778 6.384C9.61784 5.392 8.25784 4.896 6.49784 4.896H4.12184V15.96H6.49784Z"
,
"fill"
:
"#1D2939"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M20.869 3.936C20.277 3.936 19.781 3.752 19.381 3.384C18.997 3 18.805 2.528 18.805 1.968C18.805 1.408 18.997 0.944 19.381 0.576C19.781 0.192 20.277 0 20.869 0C21.461 0 21.949 0.192 22.333 0.576C22.733 0.944 22.933 1.408 22.933 1.968C22.933 2.528 22.733 3 22.333 3.384C21.949 3.752 21.461 3.936 20.869 3.936ZM22.525 5.52V18.816H19.165V5.52H22.525Z"
,
"fill"
:
"#1D2939"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M33.1407 8.28H30.8127V18.816H27.4047V8.28H25.8927V5.52H27.4047V4.848C27.4047 3.216 27.8687 2.016 28.7967 1.248C29.7247 0.48 31.1247 0.12 32.9967 0.168001V3C32.1807 2.984 31.6127 3.12 31.2927 3.408C30.9727 3.696 30.8127 4.216 30.8127 4.968V5.52H33.1407V8.28Z"
,
"fill"
:
"#1D2939"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M49.2381 5.52L41.0061 25.104H37.4301L40.3101 18.48L34.9821 5.52H38.7501L42.1821 14.808L45.6621 5.52H49.2381Z"
,
"fill"
:
"#1D2939"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"Dify"
}
\ No newline at end of file
web/app/components/base/icons/src/public/common/Dify.tsx
0 → 100644
View file @
bd6248ea
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Dify.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
}
/>)
export
default
Icon
web/app/components/base/icons/src/public/common/Github.json
0 → 100644
View file @
bd6248ea
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"18"
,
"height"
:
"18"
,
"viewBox"
:
"0 0 18 18"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"id"
:
"github"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Vector"
,
"d"
:
"M9 1.125C4.64906 1.125 1.125 4.64906 1.125 9C1.125 12.4847 3.37922 15.428 6.50953 16.4714C6.90328 16.5403 7.05094 16.3041 7.05094 16.0973C7.05094 15.9103 7.04109 15.2902 7.04109 14.6306C5.0625 14.9948 4.55062 14.1483 4.39312 13.7053C4.30453 13.4789 3.92063 12.78 3.58594 12.593C3.31031 12.4453 2.91656 12.0811 3.57609 12.0712C4.19625 12.0614 4.63922 12.6422 4.78688 12.8784C5.49563 14.0695 6.62766 13.7348 7.08047 13.5281C7.14938 13.0163 7.35609 12.6717 7.5825 12.4748C5.83031 12.278 3.99938 11.5987 3.99938 8.58656C3.99938 7.73016 4.30453 7.02141 4.80656 6.47016C4.72781 6.27328 4.45219 5.46609 4.88531 4.38328C4.88531 4.38328 5.54484 4.17656 7.05094 5.19047C7.68094 5.01328 8.35031 4.92469 9.01969 4.92469C9.68906 4.92469 10.3584 5.01328 10.9884 5.19047C12.4945 4.16672 13.1541 4.38328 13.1541 4.38328C13.5872 5.46609 13.3116 6.27328 13.2328 6.47016C13.7348 7.02141 14.04 7.72031 14.04 8.58656C14.04 11.6086 12.1992 12.278 10.447 12.4748C10.7325 12.7209 10.9786 13.1934 10.9786 13.9317C10.9786 14.985 10.9688 15.8316 10.9688 16.0973C10.9688 16.3041 11.1164 16.5502 11.5102 16.4714C13.0735 15.9436 14.432 14.9389 15.3943 13.5986C16.3567 12.2583 16.8746 10.65 16.875 9C16.875 4.64906 13.3509 1.125 9 1.125Z"
,
"fill"
:
"#24292F"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"Github"
}
\ No newline at end of file
web/app/components/base/icons/src/public/common/Github.tsx
0 → 100644
View file @
bd6248ea
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Github.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
}
/>)
export
default
Icon
web/app/components/base/icons/src/public/common/index.ts
0 → 100644
View file @
bd6248ea
export
{
default
as
Dify
}
from
'./Dify'
export
{
default
as
Github
}
from
'./Github'
web/app/components/base/icons/src/vender/line/arrows/ArrowUpRight.json
0 → 100644
View file @
bd6248ea
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"14"
,
"height"
:
"14"
,
"viewBox"
:
"0 0 14 14"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"id"
:
"arrow-up-right"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Icon"
,
"d"
:
"M4.08325 9.91665L9.91659 4.08331M9.91659 4.08331H4.08325M9.91659 4.08331V9.91665"
,
"stroke"
:
"currentColor"
,
"stroke-width"
:
"1.25"
,
"stroke-linecap"
:
"round"
,
"stroke-linejoin"
:
"round"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"ArrowUpRight"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/line/arrows/ArrowUpRight.tsx
0 → 100644
View file @
bd6248ea
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./ArrowUpRight.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
}
/>)
export
default
Icon
web/app/components/base/icons/src/vender/line/arrows/ChevronDown.json
0 → 100644
View file @
bd6248ea
{
"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"
:
"chevron-down"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Icon"
,
"d"
:
"M3 4.5L6 7.5L9 4.5"
,
"stroke"
:
"currentColor"
,
"stroke-width"
:
"1.5"
,
"stroke-linecap"
:
"round"
,
"stroke-linejoin"
:
"round"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"ChevronDown"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/line/arrows/ChevronDown.tsx
0 → 100644
View file @
bd6248ea
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./ChevronDown.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
}
/>)
export
default
Icon
web/app/components/base/icons/src/vender/line/arrows/ChevronRight.json
0 → 100644
View file @
bd6248ea
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"14"
,
"height"
:
"14"
,
"viewBox"
:
"0 0 14 14"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"id"
:
"chevron-right"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Icon"
,
"d"
:
"M5.25 10.5L8.75 7L5.25 3.5"
,
"stroke"
:
"currentColor"
,
"stroke-width"
:
"1.25"
,
"stroke-linecap"
:
"round"
,
"stroke-linejoin"
:
"round"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"ChevronRight"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/line/arrows/ChevronRight.tsx
0 → 100644
View file @
bd6248ea
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./ChevronRight.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
}
/>)
export
default
Icon
web/app/components/base/icons/src/vender/line/arrows/index.ts
View file @
bd6248ea
export
{
default
as
ArrowNarrowLeft
}
from
'./ArrowNarrowLeft'
export
{
default
as
ArrowUpRight
}
from
'./ArrowUpRight'
export
{
default
as
ChevronDown
}
from
'./ChevronDown'
export
{
default
as
ChevronRight
}
from
'./ChevronRight'
export
{
default
as
RefreshCw05
}
from
'./RefreshCw05'
web/app/components/base/icons/src/vender/line/general/Check.json
0 → 100644
View file @
bd6248ea
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"16"
,
"height"
:
"16"
,
"viewBox"
:
"0 0 16 16"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"id"
:
"check"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Icon"
,
"d"
:
"M13.3334 4L6.00008 11.3333L2.66675 8"
,
"stroke"
:
"currentColor"
,
"stroke-width"
:
"1.5"
,
"stroke-linecap"
:
"round"
,
"stroke-linejoin"
:
"round"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"Check"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/line/general/Check.tsx
0 → 100644
View file @
bd6248ea
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Check.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
}
/>)
export
default
Icon
web/app/components/base/icons/src/vender/line/general/LogOut01.json
0 → 100644
View file @
bd6248ea
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"14"
,
"height"
:
"14"
,
"viewBox"
:
"0 0 14 14"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"id"
:
"log-out-01"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Icon"
,
"d"
:
"M9.33333 9.91667L12.25 7M12.25 7L9.33333 4.08333M12.25 7H5.25M5.25 1.75H4.55C3.56991 1.75 3.07986 1.75 2.70552 1.94074C2.37623 2.10852 2.10852 2.37623 1.94074 2.70552C1.75 3.07986 1.75 3.56991 1.75 4.55V9.45C1.75 10.4301 1.75 10.9201 1.94074 11.2945C2.10852 11.6238 2.37623 11.8915 2.70552 12.0593C3.07986 12.25 3.56991 12.25 4.55 12.25H5.25"
,
"stroke"
:
"currentColor"
,
"stroke-width"
:
"1.25"
,
"stroke-linecap"
:
"round"
,
"stroke-linejoin"
:
"round"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"LogOut01"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/line/general/LogOut01.tsx
0 → 100644
View file @
bd6248ea
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./LogOut01.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
}
/>)
export
default
Icon
web/app/components/base/icons/src/vender/line/general/index.ts
View file @
bd6248ea
export
{
default
as
Edit03
}
from
'./Edit03'
export
{
default
as
Check
}
from
'./Check'
export
{
default
as
Loading02
}
from
'./Loading02'
export
{
default
as
LogOut01
}
from
'./LogOut01'
export
{
default
as
Trash03
}
from
'./Trash03'
export
{
default
as
XClose
}
from
'./XClose'
export
{
default
as
X
}
from
'./X'
web/app/components/base/icons/src/vender/solid/development/TerminalSquare.json
0 → 100644
View file @
bd6248ea
{
"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"
:
"terminal-square"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Solid"
,
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M8.91927 1H3.08073C2.81716 0.999992 2.58977 0.999984 2.40249 1.01529C2.20481 1.03144 2.00821 1.06709 1.81902 1.16349C1.53677 1.3073 1.3073 1.53677 1.16349 1.81902C1.06709 2.00821 1.03144 2.20481 1.01529 2.40249C0.999984 2.58977 0.999992 2.81714 1 3.08071V8.91927C0.999992 9.18284 0.999984 9.41023 1.01529 9.59752C1.03144 9.79519 1.06709 9.9918 1.16349 10.181C1.3073 10.4632 1.53677 10.6927 1.81902 10.8365C2.00821 10.9329 2.20481 10.9686 2.40249 10.9847C2.58977 11 2.81715 11 3.08072 11H8.91928C9.18285 11 9.41023 11 9.59752 10.9847C9.79519 10.9686 9.9918 10.9329 10.181 10.8365C10.4632 10.6927 10.6927 10.4632 10.8365 10.181C10.9329 9.9918 10.9686 9.79519 10.9847 9.59752C11 9.41023 11 9.18285 11 8.91928V3.08072C11 2.81715 11 2.58977 10.9847 2.40249C10.9686 2.20481 10.9329 2.00821 10.8365 1.81902C10.6927 1.53677 10.4632 1.3073 10.181 1.16349C9.9918 1.06709 9.79519 1.03144 9.59752 1.01529C9.41023 0.999984 9.18284 0.999992 8.91927 1ZM3.85355 4.14645C3.65829 3.95118 3.34171 3.95118 3.14645 4.14645C2.95118 4.34171 2.95118 4.65829 3.14645 4.85355L4.29289 6L3.14645 7.14645C2.95118 7.34171 2.95118 7.65829 3.14645 7.85355C3.34171 8.04882 3.65829 8.04882 3.85355 7.85355L5.35355 6.35355C5.54882 6.15829 5.54882 5.84171 5.35355 5.64645L3.85355 4.14645ZM6.5 7C6.22386 7 6 7.22386 6 7.5C6 7.77614 6.22386 8 6.5 8H8.5C8.77614 8 9 7.77614 9 7.5C9 7.22386 8.77614 7 8.5 7H6.5Z"
,
"fill"
:
"currentColor"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"TerminalSquare"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/solid/development/TerminalSquare.tsx
0 → 100644
View file @
bd6248ea
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./TerminalSquare.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
}
/>)
export
default
Icon
web/app/components/base/icons/src/vender/solid/development/index.ts
View file @
bd6248ea
...
...
@@ -2,3 +2,4 @@ export { default as Container } from './Container'
export
{
default
as
Database02
}
from
'./Database02'
export
{
default
as
Database03
}
from
'./Database03'
export
{
default
as
PuzzlePiece01
}
from
'./PuzzlePiece01'
export
{
default
as
TerminalSquare
}
from
'./TerminalSquare'
web/app/components/base/icons/src/vender/solid/education/Beaker02.json
0 → 100644
View file @
bd6248ea
{
"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"
:
"beaker-02"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Solid"
,
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M4.13856 0.500003H7.8617C7.92126 0.49998 7.99238 0.499953 8.05504 0.505073C8.12765 0.511005 8.23165 0.526227 8.34062 0.581751C8.48174 0.653656 8.59648 0.768392 8.66838 0.909513C8.72391 1.01849 8.73913 1.12248 8.74506 1.19509C8.75018 1.25775 8.75015 1.32888 8.75013 1.38844V2.61157C8.75015 2.67113 8.75018 2.74226 8.74506 2.80492C8.73913 2.87753 8.72391 2.98153 8.66838 3.0905C8.59648 3.23162 8.48174 3.34636 8.34062 3.41826C8.23165 3.47379 8.12765 3.48901 8.05504 3.49494C8.03725 3.49639 8.01877 3.49743 8.00006 3.49817V5.2506C8.00006 5.55312 8.00408 5.61265 8.01723 5.66153C8.03245 5.71807 8.05747 5.7715 8.09117 5.81939C8.1203 5.86078 8.16346 5.90197 8.39586 6.09564L10.2807 7.66627C10.4566 7.81255 10.6116 7.94145 10.7267 8.10509C10.8278 8.24875 10.9029 8.40904 10.9486 8.57867C11.0005 8.7719 11.0003 8.97351 11.0001 9.2023C11.0001 9.39886 11.0002 9.59542 11.0002 9.79198C11.0003 9.98232 11.0005 10.1463 10.9713 10.2927C10.853 10.8877 10.3878 11.3529 9.7928 11.4712C9.64637 11.5003 9.48246 11.5002 9.29211 11.5001H2.70822C2.51787 11.5002 2.35396 11.5003 2.20753 11.4712C1.98473 11.4269 1.78014 11.334 1.60515 11.2038C1.42854 11.0725 1.28221 10.9034 1.17753 10.7077C1.10892 10.5796 1.05831 10.4401 1.02899 10.2927C0.999862 10.1463 0.999992 9.98233 1.00014 9.79199C1.00014 9.59542 1.00006 9.39886 1.00003 9.20229C0.999794 8.97351 0.999584 8.7719 1.05157 8.57867C1.09721 8.40904 1.17229 8.24875 1.27338 8.10509C1.38855 7.94145 1.54356 7.81255 1.71947 7.66627L3.60427 6.09564C3.83667 5.90197 3.87983 5.86078 3.90896 5.81939C3.94266 5.7715 3.96768 5.71807 3.9829 5.66153C3.99605 5.61265 4.00006 5.55312 4.00006 5.2506V3.49817C3.9814 3.49743 3.96297 3.49639 3.94521 3.49494C3.8726 3.48901 3.76861 3.47379 3.65964 3.41826C3.51851 3.34636 3.40378 3.23162 3.33187 3.0905C3.27635 2.98153 3.26113 2.87753 3.25519 2.80492C3.25008 2.74226 3.2501 2.67113 3.25013 2.61158V1.38844C3.2501 1.32888 3.25008 1.25775 3.25519 1.19509C3.26113 1.12248 3.27635 1.01849 3.33187 0.909513C3.40378 0.768392 3.51851 0.653656 3.65964 0.581751C3.76861 0.526227 3.8726 0.511005 3.94521 0.505073C4.00787 0.499953 4.079 0.49998 4.13856 0.500003ZM9.11909 8.00004H2.88104L4.28066 6.83373C4.45657 6.68745 4.61158 6.55855 4.72675 6.39491C4.82784 6.25125 4.90292 6.09096 4.94856 5.92133C5.00054 5.7281 5.00033 5.52649 5.0001 5.29771L5.00006 3.50001H7.00006L7.00003 5.29771C6.99979 5.52649 6.99958 5.7281 7.05157 5.92133C7.09721 6.09096 7.17229 6.25125 7.27338 6.39491C7.38855 6.55855 7.54356 6.68745 7.71947 6.83373L9.11909 8.00004Z"
,
"fill"
:
"currentColor"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"Beaker02"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/solid/education/Beaker02.tsx
0 → 100644
View file @
bd6248ea
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Beaker02.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
}
/>)
export
default
Icon
web/app/components/base/icons/src/vender/solid/education/index.ts
0 → 100644
View file @
bd6248ea
export
{
default
as
Beaker02
}
from
'./Beaker02'
web/app/components/base/icons/utils.ts
View file @
bd6248ea
...
...
@@ -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/base/select/index.tsx
View file @
bd6248ea
...
...
@@ -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"
...
...
web/app/components/develop/secret-key/input-copy.tsx
View file @
bd6248ea
'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 @
bd6248ea
...
...
@@ -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 @
bd6248ea
...
...
@@ -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/HeaderWrapper.tsx
0 → 100644
View file @
bd6248ea
'use client'
import
classNames
from
'classnames'
import
{
usePathname
}
from
'next/navigation'
import
s
from
'./index.module.css'
import
{
useAppContext
}
from
'@/context/app-context'
type
HeaderWrapperProps
=
{
children
:
React
.
ReactNode
}
const
HeaderWrapper
=
({
children
,
}:
HeaderWrapperProps
)
=>
{
const
pathname
=
usePathname
()
const
{
langeniusVersionInfo
}
=
useAppContext
()
const
isBordered
=
[
'/apps'
,
'/datasets'
].
includes
(
pathname
)
return
(
<
div
className=
{
classNames
(
'sticky top-0 left-0 right-0 z-20 flex bg-gray-100 grow-0 shrink-0 basis-auto h-14'
,
s
.
header
,
isBordered
?
'border-b border-gray-200'
:
''
,
)
}
>
<
div
className=
{
classNames
(
s
[
`header-${langeniusVersionInfo.current_env}`
],
'flex flex-1 items-center justify-between px-4'
,
)
}
>
{
children
}
</
div
>
</
div
>
)
}
export
default
HeaderWrapper
web/app/components/header/account-about/index.module.css
View file @
bd6248ea
.logo-icon
{
background
:
url(../assets/logo-icon.png)
center
center
no-repeat
;
background-size
:
32px
;
box-shadow
:
0px
4px
6px
-1px
rgba
(
0
,
0
,
0
,
0.05
),
0px
2px
4px
-2
px
rgba
(
0
,
0
,
0
,
0.05
);
box-shadow
:
0px
2px
4px
-2px
rgba
(
0
,
0
,
0
,
0.05
),
0px
4px
6px
-1
px
rgba
(
0
,
0
,
0
,
0.05
);
}
.logo-text
{
...
...
web/app/components/header/account-about/index.tsx
View file @
bd6248ea
'use client'
import
{
useTranslation
}
from
'react-i18next'
import
{
XMarkIcon
}
from
'@heroicons/react/24/outline'
import
classNames
from
'classnames'
import
Link
from
'next/link'
import
s
from
'./index.module.css'
import
Modal
from
'@/app/components/base/modal'
import
{
XClose
}
from
'@/app/components/base/icons/src/vender/line/general'
import
{
Dify
}
from
'@/app/components/base/icons/src/public/common'
import
type
{
LangGeniusVersionResponse
}
from
'@/models/common'
import
{
IS_CE_EDITION
}
from
'@/config'
...
...
@@ -30,16 +31,15 @@ export default function AccountAbout({
className=
{
s
.
modal
}
>
<
div
className=
'relative'
>
<
XMarkIcon
className=
'absolute top-0 -right-2 w-4 h-4 cursor-pointer'
onClick=
{
onCancel
}
/>
<
div
className=
'absolute -top-2 -right-4 flex justify-center items-center w-8 h-8 cursor-pointer'
onClick=
{
onCancel
}
>
<
XClose
className=
'w-4 h-4 text-gray-500'
/>
</
div
>
<
div
>
<
div
className=
{
classNames
(
s
[
'logo-icon'
],
'mx-auto mb-3 w-12 h-12 bg-white rounded-xl border border-gray-200'
,
)
}
/>
<
div
className=
{
classNames
(
s
[
'logo-text'
],
'mx-auto mb-2'
,
'mx-auto mb-3 w-12 h-12 bg-white rounded-xl border-[0.5px] border-gray-200'
,
)
}
/>
<
Dify
className=
'mx-auto mb-2'
/>
<
div
className=
'mb-3 text-center text-xs font-normal text-gray-500'
>
Version
{
langeniusVersionInfo
?.
current_version
}
</
div
>
<
div
className=
'mb-4 text-center text-xs font-normal text-gray-700'
>
<
div
>
© 2023 LangGenius, Inc., Contributors.
</
div
>
...
...
@@ -55,7 +55,7 @@ export default function AccountAbout({
</
div
>
</
div
>
</
div
>
<
div
className=
'mb-4
h-0 border-[0.5px] border
-gray-200'
/>
<
div
className=
'mb-4
-mx-8 h-[0.5px] bg
-gray-200'
/>
<
div
className=
'flex justify-between items-center'
>
<
div
className=
'text-xs font-medium text-gray-800'
>
{
...
...
web/app/components/header/account-dropdown/index.tsx
View file @
bd6248ea
This diff is collapsed.
Click to expand it.
web/app/components/header/account-dropdown/workplace-selector/index.tsx
View file @
bd6248ea
import
{
Fragment
}
from
'react'
import
{
switchWorkspace
}
from
'@/service/common'
import
{
Menu
,
Transition
}
from
'@headlessui/react'
import
{
ChevronRightIcon
,
CheckIcon
}
from
'@heroicons/react/24/outline'
import
cn
from
'classnames'
import
s
from
'./index.module.css'
import
{
useContext
}
from
'use-context-selector'
import
{
ToastContext
}
from
'@/app/components/base/toast'
import
{
useTranslation
}
from
'react-i18next'
import
{
useRouter
}
from
'next/navigation'
import
{
Menu
,
Transition
}
from
'@headlessui/react'
import
cn
from
'classnames'
import
s
from
'./index.module.css'
import
{
switchWorkspace
}
from
'@/service/common'
import
{
useWorkspacesContext
}
from
'@/context/workspace-context'
import
{
ChevronRight
}
from
'@/app/components/base/icons/src/vender/line/arrows'
import
{
Check
}
from
'@/app/components/base/icons/src/vender/line/general'
import
{
ToastContext
}
from
'@/app/components/base/toast'
const
itemClassName
=
`
flex items-center px-3 py-2 h-10 cursor-pointer
`
const
itemIconClassName
=
`
shrink-0 mr-2
w-6 h-6 bg-[#EFF4FF] rounded-md
shrink-0 mr-2
flex items-center justify-center w-6 h-6 bg-[#EFF4FF] rounded-md text-xs font-medium text-primary-600
`
const
itemNameClassName
=
`
grow mr-2 text-sm text-gray-700 text-left
...
...
@@ -32,12 +33,12 @@ const WorkplaceSelector = () => {
const
handleSwitchWorkspace
=
async
(
tenant_id
:
string
)
=>
{
try
{
await
switchWorkspace
({
url
:
`/workspaces/switch`
,
body
:
{
tenant_id
}
})
await
switchWorkspace
({
url
:
'/workspaces/switch'
,
body
:
{
tenant_id
}
})
notify
({
type
:
'success'
,
message
:
t
(
'common.actionMsg.modifiedSuccessfully'
)
})
router
.
replace
(
'/apps'
)
}
catch
(
e
)
{
}
catch
(
e
)
{
notify
({
type
:
'error'
,
message
:
t
(
'common.provider.saveFailed'
)
})
}
finally
{
}
}
...
...
@@ -49,12 +50,12 @@ const WorkplaceSelector = () => {
<
Menu
.
Button
className=
{
cn
(
`
${itemClassName} w-full
group hover:bg-gray-50 cursor-pointer ${open && 'bg-gray-50'}
`
group hover:bg-gray-50 cursor-pointer ${open && 'bg-gray-50'}
rounded-lg
`
,
)
}
>
<
div
className=
{
itemIconClassName
}
/
>
<
div
className=
{
itemIconClassName
}
>
{
currentWrokspace
?.
name
[
0
].
toLocaleUpperCase
()
}
</
div
>
<
div
className=
{
`${itemNameClassName} truncate`
}
>
{
currentWrokspace
?.
name
}
</
div
>
<
ChevronRight
Icon
className=
'shrink-0 w-[14px] h-[14px]
'
/>
<
ChevronRight
className=
'shrink-0 w-[14px] h-[14px] text-gray-500
'
/>
</
Menu
.
Button
>
<
Transition
as=
{
Fragment
}
...
...
@@ -71,16 +72,16 @@ const WorkplaceSelector = () => {
absolute top-[1px] min-w-[200px] z-10 bg-white border-[0.5px] border-gray-200
divide-y divide-gray-100 origin-top-right rounded-xl
`
,
s
.
popup
s
.
popup
,
)
}
>
<
div
className=
"px-1 py-1"
>
{
workspaces
.
map
(
workspace
=>
(
<
div
className=
{
itemClassName
}
key=
{
workspace
.
id
}
onClick=
{
()
=>
handleSwitchWorkspace
(
workspace
.
id
)
}
>
<
div
className=
{
itemIconClassName
}
/
>
<
div
className=
{
itemIconClassName
}
>
{
workspace
.
name
[
0
].
toLocaleUpperCase
()
}
</
div
>
<
div
className=
{
itemNameClassName
}
>
{
workspace
.
name
}
</
div
>
{
workspace
.
current
&&
<
Check
Icon
className=
{
itemCheckClassName
}
/>
}
{
workspace
.
current
&&
<
Check
className=
{
itemCheckClassName
}
/>
}
</
div
>
))
}
...
...
@@ -94,4 +95,4 @@ const WorkplaceSelector = () => {
)
}
export
default
WorkplaceSelector
\ No newline at end of file
export
default
WorkplaceSelector
web/app/components/header/account-setting/members-page/invited-modal/invitation-link.tsx
View file @
bd6248ea
'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/app/components/header/app-nav/index.tsx
View file @
bd6248ea
'use client'
import
{
useCallback
,
useState
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useParams
,
usePathname
}
from
'next/navigation'
...
...
web/app/components/header/assets/beaker.svg
deleted
100644 → 0
View file @
52cf3c98
<svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M4.13856 0.500003H7.8617C7.92126 0.49998 7.99238 0.499953 8.05504 0.505073C8.12765 0.511005 8.23165 0.526227 8.34062 0.581751C8.48174 0.653656 8.59648 0.768392 8.66838 0.909513C8.72391 1.01849 8.73913 1.12248 8.74506 1.19509C8.75018 1.25775 8.75015 1.32888 8.75013 1.38844V2.61157C8.75015 2.67113 8.75018 2.74226 8.74506 2.80492C8.73913 2.87753 8.72391 2.98153 8.66838 3.0905C8.59648 3.23162 8.48174 3.34636 8.34062 3.41826C8.23165 3.47379 8.12765 3.48901 8.05504 3.49494C8.03725 3.49639 8.01877 3.49743 8.00006 3.49817V5.2506C8.00006 5.55312 8.00408 5.61265 8.01723 5.66153C8.03245 5.71807 8.05747 5.7715 8.09117 5.81939C8.1203 5.86078 8.16346 5.90197 8.39586 6.09564L10.2807 7.66627C10.4566 7.81255 10.6116 7.94145 10.7267 8.10509C10.8278 8.24875 10.9029 8.40904 10.9486 8.57867C11.0005 8.7719 11.0003 8.97351 11.0001 9.2023C11.0001 9.39886 11.0002 9.59542 11.0002 9.79198C11.0003 9.98232 11.0005 10.1463 10.9713 10.2927C10.853 10.8877 10.3878 11.3529 9.7928 11.4712C9.64637 11.5003 9.48246 11.5002 9.29211 11.5001H2.70822C2.51787 11.5002 2.35396 11.5003 2.20753 11.4712C1.98473 11.4269 1.78014 11.334 1.60515 11.2038C1.42854 11.0725 1.28221 10.9034 1.17753 10.7077C1.10892 10.5796 1.05831 10.4401 1.02899 10.2927C0.999862 10.1463 0.999992 9.98233 1.00014 9.79199C1.00014 9.59542 1.00006 9.39886 1.00003 9.20229C0.999794 8.97351 0.999584 8.7719 1.05157 8.57867C1.09721 8.40904 1.17229 8.24875 1.27338 8.10509C1.38855 7.94145 1.54356 7.81255 1.71947 7.66627L3.60427 6.09564C3.83667 5.90197 3.87983 5.86078 3.90896 5.81939C3.94266 5.7715 3.96768 5.71807 3.9829 5.66153C3.99605 5.61265 4.00006 5.55312 4.00006 5.2506V3.49817C3.9814 3.49743 3.96297 3.49639 3.94521 3.49494C3.8726 3.48901 3.76861 3.47379 3.65964 3.41826C3.51851 3.34636 3.40378 3.23162 3.33187 3.0905C3.27635 2.98153 3.26113 2.87753 3.25519 2.80492C3.25008 2.74226 3.2501 2.67113 3.25013 2.61158V1.38844C3.2501 1.32888 3.25008 1.25775 3.25519 1.19509C3.26113 1.12248 3.27635 1.01849 3.33187 0.909513C3.40378 0.768392 3.51851 0.653656 3.65964 0.581751C3.76861 0.526227 3.8726 0.511005 3.94521 0.505073C4.00787 0.499953 4.079 0.49998 4.13856 0.500003ZM9.11909 8.00004H2.88104L4.28066 6.83373C4.45657 6.68745 4.61158 6.55855 4.72675 6.39491C4.82784 6.25125 4.90292 6.09096 4.94856 5.92133C5.00054 5.7281 5.00033 5.52649 5.0001 5.29771L5.00006 3.50001H7.00006L7.00003 5.29771C6.99979 5.52649 6.99958 5.7281 7.05157 5.92133C7.09721 6.09096 7.17229 6.25125 7.27338 6.39491C7.38855 6.55855 7.54356 6.68745 7.71947 6.83373L9.11909 8.00004Z"
fill=
"#0E7090"
/>
</svg>
web/app/components/header/assets/github-icon.svg
deleted
100644 → 0
View file @
52cf3c98
<svg
width=
"18"
height=
"18"
viewBox=
"0 0 18 18"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
d=
"M9 1.125C4.64906 1.125 1.125 4.64906 1.125 9C1.125 12.4847 3.37922 15.428 6.50953 16.4714C6.90328 16.5403 7.05094 16.3041 7.05094 16.0973C7.05094 15.9103 7.04109 15.2902 7.04109 14.6306C5.0625 14.9948 4.55062 14.1483 4.39312 13.7053C4.30453 13.4789 3.92062 12.78 3.58594 12.593C3.31031 12.4453 2.91656 12.0811 3.57609 12.0712C4.19625 12.0614 4.63922 12.6422 4.78688 12.8784C5.49563 14.0695 6.62766 13.7348 7.08047 13.5281C7.14937 13.0163 7.35609 12.6717 7.5825 12.4748C5.83031 12.278 3.99938 11.5988 3.99938 8.58656C3.99938 7.73016 4.30453 7.02141 4.80656 6.47016C4.72781 6.27328 4.45219 5.46609 4.88531 4.38328C4.88531 4.38328 5.54484 4.17656 7.05094 5.19047C7.68094 5.01328 8.35031 4.92469 9.01969 4.92469C9.68906 4.92469 10.3584 5.01328 10.9884 5.19047C12.4945 4.16672 13.1541 4.38328 13.1541 4.38328C13.5872 5.46609 13.3116 6.27328 13.2328 6.47016C13.7348 7.02141 14.04 7.72031 14.04 8.58656C14.04 11.6086 12.1992 12.278 10.447 12.4748C10.7325 12.7209 10.9786 13.1934 10.9786 13.9317C10.9786 14.985 10.9688 15.8316 10.9688 16.0973C10.9688 16.3041 11.1164 16.5502 11.5102 16.4714C13.0735 15.9436 14.432 14.9389 15.3943 13.5986C16.3567 12.2583 16.8746 10.65 16.875 9C16.875 4.64906 13.3509 1.125 9 1.125Z"
fill=
"#24292F"
/>
</svg>
web/app/components/header/dataset-nav/index.tsx
View file @
bd6248ea
'use client'
import
{
useCallback
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useParams
,
useRouter
}
from
'next/navigation'
...
...
web/app/components/header/env-nav/index.tsx
0 → 100644
View file @
bd6248ea
'use client'
import
{
useTranslation
}
from
'react-i18next'
import
{
useAppContext
}
from
'@/context/app-context'
import
{
Beaker02
}
from
'@/app/components/base/icons/src/vender/solid/education'
import
{
TerminalSquare
}
from
'@/app/components/base/icons/src/vender/solid/development'
const
headerEnvClassName
:
{
[
k
:
string
]:
string
}
=
{
DEVELOPMENT
:
'bg-[#FEC84B] border-[#FDB022] text-[#93370D]'
,
TESTING
:
'bg-[#A5F0FC] border-[#67E3F9] text-[#164C63]'
,
}
const
EnvNav
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
{
langeniusVersionInfo
}
=
useAppContext
()
const
showEnvTag
=
langeniusVersionInfo
.
current_env
===
'TESTING'
||
langeniusVersionInfo
.
current_env
===
'DEVELOPMENT'
if
(
!
showEnvTag
)
return
null
return
(
<
div
className=
{
`
flex items-center h-[22px] mr-4 rounded-md px-2 text-xs font-medium border
${headerEnvClassName[langeniusVersionInfo.current_env]}
`
}
>
{
langeniusVersionInfo
.
current_env
===
'TESTING'
&&
(
<>
<
Beaker02
className=
'w-3 h-3 mr-1'
/>
{
t
(
'common.environment.testing'
)
}
</>
)
}
{
langeniusVersionInfo
.
current_env
===
'DEVELOPMENT'
&&
(
<>
<
TerminalSquare
className=
'w-3 h-3 mr-1'
/>
{
t
(
'common.environment.development'
)
}
</>
)
}
</
div
>
)
}
export
default
EnvNav
web/app/components/header/explore-nav/index.tsx
0 → 100644
View file @
bd6248ea
'use client'
import
{
useTranslation
}
from
'react-i18next'
import
Link
from
'next/link'
import
{
useSelectedLayoutSegment
}
from
'next/navigation'
import
classNames
from
'classnames'
import
{
Grid01
}
from
'@/app/components/base/icons/src/vender/line/layout'
import
{
Grid01
as
Grid01Solid
}
from
'@/app/components/base/icons/src/vender/solid/layout'
type
ExploreNavProps
=
{
className
?:
string
}
const
ExploreNav
=
({
className
,
}:
ExploreNavProps
)
=>
{
const
{
t
}
=
useTranslation
()
const
selectedSegment
=
useSelectedLayoutSegment
()
const
actived
=
selectedSegment
===
'explore'
return
(
<
Link
href=
"/explore/apps"
className=
{
classNames
(
className
,
'group'
,
actived
&&
'bg-white shadow-[0_2px_5px_-1px_rgba(0,0,0,0.05),0_2px_4px_-2px_rgba(0,0,0,0.05)]'
,
actived
?
'text-primary-600'
:
'text-gray-500 hover:bg-gray-200'
,
)
}
>
{
actived
?
<
Grid01Solid
className=
'mr-2 w-4 h-4'
/>
:
<
Grid01
className=
'mr-2 w-4 h-4'
/>
}
{
t
(
'common.menus.explore'
)
}
</
Link
>
)
}
export
default
ExploreNav
web/app/components/header/github-star/index.tsx
0 → 100644
View file @
bd6248ea
import
{
Github
}
from
'@/app/components/base/icons/src/public/common'
import
type
{
GithubRepo
}
from
'@/models/common'
const
getStar
=
async
()
=>
{
const
res
=
await
fetch
(
'https://api.github.com/repos/langgenius/dify'
)
if
(
!
res
.
ok
)
throw
new
Error
(
'Failed to fetch data'
)
return
res
.
json
()
}
const
GithubStar
=
async
()
=>
{
let
githubRepo
:
GithubRepo
=
{
stargazers_count
:
0
}
if
(
process
.
env
.
NODE_ENV
===
'development'
)
return
null
try
{
githubRepo
=
await
getStar
()
}
catch
(
e
)
{
return
null
}
return
(
<
a
href=
'https://github.com/langgenius/dify'
target=
'_blank'
className=
'flex items-center leading-[18px] border border-gray-200 rounded-md text-xs text-gray-700 font-semibold overflow-hidden'
>
<
div
className=
'flex items-center px-2 py-1 bg-gray-100'
>
<
Github
className=
'mr-1 w-[18px] h-[18px]'
/>
Star
</
div
>
<
div
className=
'px-2 py-1 bg-white border-l border-gray-200'
>
{
`${githubRepo.stargazers_count}`
.
replace
(
/
\B(?=(\d
{3}
)
+
(?!\d))
/g
,
','
)
}
</
div
>
</
a
>
)
}
export
default
GithubStar
web/app/components/header/index.module.css
View file @
bd6248ea
...
...
@@ -15,23 +15,8 @@
background-size
:
contain
;
}
.github-icon
{
width
:
18px
;
height
:
18px
;
background
:
url(./assets/github-icon.svg)
center
center
no-repeat
;
background-size
:
contain
;
}
.alpha
{
width
:
12px
;
height
:
12px
;
background
:
url(./assets/alpha.svg)
center
center
no-repeat
;
}
.beaker-icon
{
width
:
12px
;
height
:
12px
;
margin-right
:
4px
;
background
:
url(./assets/beaker.svg)
center
center
no-repeat
;
background-size
:
contain
;
}
\ No newline at end of file
web/app/components/header/index.tsx
View file @
bd6248ea
'use client'
import
{
useEffect
,
useState
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
usePathname
,
useSelectedLayoutSegment
}
from
'next/navigation'
import
classNames
from
'classnames'
import
{
CommandLineIcon
}
from
'@heroicons/react/24/solid'
import
Link
from
'next/link'
import
AccountDropdown
from
'./account-dropdown'
import
AppNav
from
'./app-nav'
import
DatasetNav
from
'./dataset-nav'
import
EnvNav
from
'./env-nav'
import
ExploreNav
from
'./explore-nav'
import
GithubStar
from
'./github-star'
import
PluginNav
from
'./plugin-nav'
import
s
from
'./index.module.css'
import
type
{
GithubRepo
}
from
'@/models/common'
import
{
WorkspaceProvider
}
from
'@/context/workspace-context'
import
{
useAppContext
}
from
'@/context/app-context'
import
{
Grid01
}
from
'@/app/components/base/icons/src/vender/line/layout'
import
{
Grid01
as
Grid01Solid
}
from
'@/app/components/base/icons/src/vender/solid/layout'
import
{
PuzzlePiece01
}
from
'@/app/components/base/icons/src/vender/line/development'
import
{
PuzzlePiece01
as
PuzzlePiece01Solid
}
from
'@/app/components/base/icons/src/vender/solid/development'
const
navClassName
=
`
flex items-center relative mr-3 px-3 h-8 rounded-xl
font-medium text-sm
cursor-pointer
`
const
headerEnvClassName
:
{
[
k
:
string
]:
string
}
=
{
DEVELOPMENT
:
'bg-[#FEC84B] border-[#FDB022] text-[#93370D]'
,
TESTING
:
'bg-[#A5F0FC] border-[#67E3F9] text-[#164C63]'
,
}
const
Header
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
pathname
=
usePathname
()
const
{
userProfile
,
langeniusVersionInfo
}
=
useAppContext
()
const
showEnvTag
=
langeniusVersionInfo
.
current_env
===
'TESTING'
||
langeniusVersionInfo
.
current_env
===
'DEVELOPMENT'
const
selectedSegment
=
useSelectedLayoutSegment
()
const
isPluginsComingSoon
=
selectedSegment
===
'plugins-coming-soon'
const
isExplore
=
selectedSegment
===
'explore'
const
[
starCount
,
setStarCount
]
=
useState
(
0
)
const
isBordered
=
[
'/apps'
,
'/datasets'
].
includes
(
pathname
)
useEffect
(()
=>
{
globalThis
.
fetch
(
'https://api.github.com/repos/langgenius/dify'
).
then
(
res
=>
res
.
json
()).
then
((
data
:
GithubRepo
)
=>
{
setStarCount
(
data
.
stargazers_count
)
})
},
[])
const
Header
=
()
=>
{
return
(
<
div
className=
{
classNames
(
'sticky top-0 left-0 right-0 z-20 flex bg-gray-100 grow-0 shrink-0 basis-auto h-14'
,
s
.
header
,
isBordered
?
'border-b border-gray-200'
:
''
,
)
}
>
<
div
className=
{
classNames
(
s
[
`header-${langeniusVersionInfo.current_env}`
],
'flex flex-1 items-center justify-between px-4'
,
)
}
>
<
div
className=
'flex items-center'
>
<
Link
href=
"/apps"
className=
'flex items-center mr-4'
>
<
div
className=
{
s
.
logo
}
/>
</
Link
>
{
starCount
>
0
&&
(
<
Link
href=
'https://github.com/langgenius/dify'
target=
'_blank'
className=
'flex items-center leading-[18px] border border-gray-200 rounded-md text-xs text-gray-700 font-semibold overflow-hidden'
>
<
div
className=
'flex items-center px-2 py-1 bg-gray-100'
>
<
div
className=
{
`${s['github-icon']} mr-1 rounded-full`
}
/>
Star
</
div
>
<
div
className=
'px-2 py-1 bg-white border-l border-gray-200'
>
{
`${starCount}`
.
replace
(
/
\B(?=(\d
{3}
)
+
(?!\d))
/g
,
','
)
}
</
div
>
</
Link
>
)
}
</
div
>
<
div
className=
'flex items-center'
>
<
Link
href=
"/explore/apps"
className=
{
classNames
(
navClassName
,
'group'
,
isExplore
&&
'bg-white shadow-[0_2px_5px_-1px_rgba(0,0,0,0.05),0_2px_4px_-2px_rgba(0,0,0,0.05)]'
,
isExplore
?
'text-primary-600'
:
'text-gray-500 hover:bg-gray-200'
,
)
}
>
{
isExplore
?
<
Grid01Solid
className=
'mr-2 w-4 h-4'
/>
:
<
Grid01
className=
'mr-2 w-4 h-4'
/>
}
{
t
(
'common.menus.explore'
)
}
</
Link
>
<
AppNav
/>
<
Link
href=
"/plugins-coming-soon"
className=
{
classNames
(
navClassName
,
'group'
,
isPluginsComingSoon
&&
'bg-white shadow-[0_2px_5px_-1px_rgba(0,0,0,0.05),0_2px_4px_-2px_rgba(0,0,0,0.05)]'
,
isPluginsComingSoon
?
'text-primary-600'
:
'text-gray-500 hover:bg-gray-200'
,
)
}
>
{
isPluginsComingSoon
?
<
PuzzlePiece01Solid
className=
'mr-2 w-4 h-4'
/>
:
<
PuzzlePiece01
className=
'mr-2 w-4 h-4'
/>
}
{
t
(
'common.menus.plugins'
)
}
</
Link
>
<
DatasetNav
/>
</
div
>
<
div
className=
'flex items-center flex-shrink-0'
>
{
showEnvTag
&&
(
<
div
className=
{
`
flex items-center h-[22px] mr-4 rounded-md px-2 text-xs font-medium border
${headerEnvClassName[langeniusVersionInfo.current_env]}
`
}
>
{
langeniusVersionInfo
.
current_env
===
'TESTING'
&&
(
<>
<
div
className=
{
s
[
'beaker-icon'
]
}
/>
{
t
(
'common.environment.testing'
)
}
</>
)
}
{
langeniusVersionInfo
.
current_env
===
'DEVELOPMENT'
&&
(
<>
<
CommandLineIcon
className=
'w-3 h-3 mr-1'
/>
{
t
(
'common.environment.development'
)
}
</>
)
}
</
div
>
)
}
<
WorkspaceProvider
>
<
AccountDropdown
userProfile=
{
userProfile
}
langeniusVersionInfo=
{
langeniusVersionInfo
}
/>
</
WorkspaceProvider
>
</
div
>
<>
<
div
className=
'flex items-center'
>
<
Link
href=
"/apps"
className=
'flex items-center mr-4'
>
<
div
className=
{
s
.
logo
}
/>
</
Link
>
{
/* @ts-expect-error Async Server Component */
}
<
GithubStar
/>
</
div
>
<
div
className=
'flex items-center'
>
<
ExploreNav
className=
{
navClassName
}
/>
<
AppNav
/>
<
PluginNav
className=
{
navClassName
}
/>
<
DatasetNav
/>
</
div
>
<
div
className=
'flex items-center flex-shrink-0'
>
<
EnvNav
/>
<
WorkspaceProvider
>
<
AccountDropdown
/>
</
WorkspaceProvider
>
</
div
>
</
div
>
</>
)
}
export
default
Header
web/app/components/header/plugin-nav/index.tsx
0 → 100644
View file @
bd6248ea
'use client'
import
{
useTranslation
}
from
'react-i18next'
import
Link
from
'next/link'
import
{
useSelectedLayoutSegment
}
from
'next/navigation'
import
classNames
from
'classnames'
import
{
PuzzlePiece01
}
from
'@/app/components/base/icons/src/vender/line/development'
import
{
PuzzlePiece01
as
PuzzlePiece01Solid
}
from
'@/app/components/base/icons/src/vender/solid/development'
type
PluginNavProps
=
{
className
?:
string
}
const
PluginNav
=
({
className
,
}:
PluginNavProps
)
=>
{
const
{
t
}
=
useTranslation
()
const
selectedSegment
=
useSelectedLayoutSegment
()
const
isPluginsComingSoon
=
selectedSegment
===
'plugins-coming-soon'
return
(
<
Link
href=
"/plugins-coming-soon"
className=
{
classNames
(
className
,
'group'
,
isPluginsComingSoon
&&
'bg-white shadow-[0_2px_5px_-1px_rgba(0,0,0,0.05),0_2px_4px_-2px_rgba(0,0,0,0.05)]'
,
isPluginsComingSoon
?
'text-primary-600'
:
'text-gray-500 hover:bg-gray-200'
,
)
}
>
{
isPluginsComingSoon
?
<
PuzzlePiece01Solid
className=
'mr-2 w-4 h-4'
/>
:
<
PuzzlePiece01
className=
'mr-2 w-4 h-4'
/>
}
{
t
(
'common.menus.plugins'
)
}
</
Link
>
)
}
export
default
PluginNav
web/app/components/share/chat/index.tsx
View file @
bd6248ea
...
...
@@ -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
=
tru
e
hasEmptyInput
=
nam
e
})
if
(
hasEmptyInput
)
{
logError
(
t
(
'appDebug.errorMessage.valueOfVarRequired'
))
logError
(
t
(
'appDebug.errorMessage.valueOfVarRequired'
,
{
key
:
hasEmptyInput
}
))
return
false
}
return
!
hasEmptyInput
...
...
web/app/components/share/chat/sidebar/list/index.tsx
View file @
bd6248ea
...
...
@@ -48,7 +48,10 @@ const List: FC<IListProps> = ({
useInfiniteScroll
(
async
()
=>
{
if
(
!
isNoMore
)
{
const
lastId
=
!
isClearConversationList
?
list
[
list
.
length
-
1
]?.
id
:
undefined
let
lastId
=
!
isClearConversationList
?
list
[
list
.
length
-
1
]?.
id
:
undefined
if
(
lastId
===
'-1'
)
lastId
=
undefined
const
{
data
:
conversations
,
has_more
}:
any
=
await
fetchConversations
(
isInstalledApp
,
installedAppId
,
lastId
,
isPinned
)
onMoreLoaded
({
data
:
conversations
,
has_more
})
}
...
...
web/app/components/share/chat/welcome/index.tsx
View file @
bd6248ea
'use client'
import
type
{
FC
}
from
'react'
import
React
,
{
use
State
,
useEffect
}
from
'react'
import
React
,
{
use
Effect
,
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
>
)
}
...
...
web/app/components/share/chatbot/index.tsx
View file @
bd6248ea
...
...
@@ -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
=
tru
e
hasEmptyInput
=
nam
e
})
if
(
hasEmptyInput
)
{
logError
(
t
(
'appDebug.errorMessage.valueOfVarRequired'
))
logError
(
t
(
'appDebug.errorMessage.valueOfVarRequired'
,
{
key
:
hasEmptyInput
}
))
return
false
}
return
!
hasEmptyInput
...
...
web/app/components/share/chatbot/welcome/index.tsx
View file @
bd6248ea
...
...
@@ -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
=
tru
e
hasEmptyInput
=
nam
e
})
if
(
hasEmptyInput
)
{
logError
(
t
(
'appDebug.errorMessage.valueOfVarRequired'
))
logError
(
t
(
'appDebug.errorMessage.valueOfVarRequired'
,
{
key
:
hasEmptyInput
}
))
return
false
}
return
!
hasEmptyInput
...
...
web/app/components/share/header.tsx
View file @
bd6248ea
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
{
Bars3Icon
,
PencilSquareIcon
,
}
from
'@heroicons/react/24/solid'
import
AppIcon
from
'@/app/components/base/app-icon'
export
type
IHeaderProps
=
{
title
:
string
customerIcon
?:
React
.
ReactNode
...
...
@@ -8,6 +13,8 @@ export type IHeaderProps = {
icon_background
:
string
isMobile
?:
boolean
isEmbedScene
?:
boolean
onShowSideBar
?:
()
=>
void
onCreateNewChat
?:
()
=>
void
}
const
Header
:
FC
<
IHeaderProps
>
=
({
title
,
...
...
@@ -16,22 +23,25 @@ const Header: FC<IHeaderProps> = ({
icon
,
icon_background
,
isEmbedScene
=
false
,
onShowSideBar
,
onCreateNewChat
,
})
=>
{
return
!
isMobile
?
null
:
(
if
(
!
isMobile
)
return
null
if
(
isEmbedScene
)
{
return
(
<
div
className=
{
`shrink-0 flex items-center justify-between h-12 px-3 bg-gray-100 ${
isEmbedScene ? 'bg-gradient-to-r from-blue-600 to-sky-500' : ''
}`
}
className=
{
`
shrink-0 flex items-center justify-between h-12 px-3 bg-gray-100
bg-gradient-to-r from-blue-600 to-sky-500
`
}
>
<
div
></
div
>
<
div
className=
"flex items-center space-x-2"
>
{
customerIcon
||
<
AppIcon
size=
"small"
icon=
{
icon
}
background=
{
icon_background
}
/>
}
<
div
className=
{
`text-sm text-gray-800 font-bold ${
isEmbedScene ? 'text-white' : ''
}`
}
className=
{
'text-sm font-bold text-white'
}
>
{
title
}
</
div
>
...
...
@@ -39,6 +49,27 @@ const Header: FC<IHeaderProps> = ({
<
div
></
div
>
</
div
>
)
}
return
(
<
div
className=
"shrink-0 flex items-center justify-between h-12 px-3 bg-gray-100"
>
<
div
className=
'flex items-center justify-center h-8 w-8 cursor-pointer'
onClick=
{
()
=>
onShowSideBar
?.()
}
>
<
Bars3Icon
className=
"h-4 w-4 text-gray-500"
/>
</
div
>
<
div
className=
'flex items-center space-x-2'
>
<
AppIcon
size=
"small"
icon=
{
icon
}
background=
{
icon_background
}
/>
<
div
className=
" text-sm text-gray-800 font-bold"
>
{
title
}
</
div
>
</
div
>
<
div
className=
'flex items-center justify-center h-8 w-8 cursor-pointer'
onClick=
{
()
=>
onCreateNewChat
?.()
}
>
<
PencilSquareIcon
className=
"h-4 w-4 text-gray-500"
/>
</
div
>
</
div
>
)
}
export
default
React
.
memo
(
Header
)
web/app/components/share/text-generation/result/index.tsx
View file @
bd6248ea
...
...
@@ -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
=
tru
e
hasEmptyInput
=
nam
e
})
if
(
hasEmptyInput
)
{
logError
(
t
(
'appDebug.errorMessage.valueOfVarRequired'
))
logError
(
t
(
'appDebug.errorMessage.valueOfVarRequired'
,
{
key
:
hasEmptyInput
}
))
return
false
}
return
!
hasEmptyInput
...
...
web/app/install/installForm.tsx
View file @
bd6248ea
...
...
@@ -17,6 +17,7 @@ const InstallForm = () => {
const
[
email
,
setEmail
]
=
React
.
useState
(
''
)
const
[
name
,
setName
]
=
React
.
useState
(
''
)
const
[
password
,
setPassword
]
=
React
.
useState
(
''
)
const
[
showPassword
,
setShowPassword
]
=
React
.
useState
(
false
)
const
showErrorMessage
=
(
message
:
string
)
=>
{
Toast
.
notify
({
type
:
'error'
,
...
...
@@ -108,12 +109,21 @@ const InstallForm = () => {
<
div
className=
"mt-1 relative rounded-md shadow-sm"
>
<
input
id=
"password"
type=
'password'
type=
{
showPassword
?
'text'
:
'password'
}
value=
{
password
}
onChange=
{
e
=>
setPassword
(
e
.
target
.
value
)
}
placeholder=
{
t
(
'login.passwordPlaceholder'
)
||
''
}
className=
{
'appearance-none block w-full rounded-lg pl-[14px] px-3 py-2 border border-gray-200 hover:border-gray-300 hover:shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 placeholder-gray-400 caret-primary-600 sm:text-sm pr-10'
}
/>
<
div
className=
"absolute inset-y-0 right-0 flex items-center pr-3"
>
<
button
type=
"button"
onClick=
{
()
=>
setShowPassword
(
!
showPassword
)
}
className=
"text-gray-400 hover:text-gray-500 focus:outline-none focus:text-gray-500"
>
{
showPassword
?
'👀'
:
'😝'
}
</
button
>
</
div
>
</
div
>
<
div
className=
'mt-1 text-xs text-gray-500'
>
{
t
(
'login.error.passwordInvalid'
)
}
</
div
>
...
...
web/context/app-context.tsx
View file @
bd6248ea
...
...
@@ -67,7 +67,7 @@ export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) =>
const
result
=
await
userProfileResponse
.
json
()
setUserProfile
(
result
)
const
current_version
=
userProfileResponse
.
headers
.
get
(
'x-version'
)
const
current_env
=
userProfileResponse
.
headers
.
get
(
'x-env'
)
const
current_env
=
process
.
env
.
NODE_ENV
===
'development'
?
'DEVELOPMENT'
:
userProfileResponse
.
headers
.
get
(
'x-env'
)
const
versionData
=
await
fetchLanggeniusVersion
({
url
:
'/version'
,
params
:
{
current_version
}
})
setLangeniusVersionInfo
({
...
versionData
,
current_version
,
latest_version
:
versionData
.
version
,
current_env
})
}
...
...
web/hooks/use-copy-to-clipboard.ts
View file @
bd6248ea
import
{
useState
}
from
'react'
import
{
useCallback
,
useState
}
from
'react'
import
writeText
from
'copy-to-clipboard'
type
CopiedValue
=
string
|
null
type
CopyFn
=
(
text
:
string
)
=>
Promise
<
boolean
>
function
useCopyToClipboard
():
[
CopiedValue
,
CopyFn
]
{
const
[
copiedText
,
setCopiedText
]
=
useState
<
CopiedValue
>
(
null
)
const
[
copiedText
,
setCopiedText
]
=
useState
<
CopiedValue
>
(
null
)
const
copy
:
CopyFn
=
async
text
=>
{
if
(
!
navigator
?.
clipboard
)
{
console
.
warn
(
'Clipboard not supported'
)
return
false
}
const
copy
:
CopyFn
=
useCallback
(
async
(
text
:
string
)
=>
{
if
(
!
navigator
?.
clipboard
)
{
console
.
warn
(
'Clipboard not supported'
)
return
false
}
try
{
await
navigator
.
clipboard
.
writeText
(
text
)
setCopiedText
(
text
)
return
true
}
catch
(
error
)
{
console
.
warn
(
'Copy failed'
,
error
)
setCopiedText
(
null
)
return
false
}
try
{
writeText
(
text
)
setCopiedText
(
text
)
return
true
}
catch
(
error
)
{
console
.
warn
(
'Copy failed'
,
error
)
setCopiedText
(
null
)
return
false
}
},
[])
return
[
copiedText
,
copy
]
return
[
copiedText
,
copy
]
}
export
default
useCopyToClipboard
\ No newline at end of file
export
default
useCopyToClipboard
web/i18n/lang/app-debug.en.ts
View file @
bd6248ea
...
...
@@ -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.'
,
...
...
web/i18n/lang/app-debug.zh.ts
View file @
bd6248ea
...
...
@@ -86,7 +86,7 @@ const translation = {
},
errorMessage
:
{
nameOfKeyRequired
:
'变量 {{key}} 对应的名称必填'
,
valueOfVarRequired
:
'
变量值
必填'
,
valueOfVarRequired
:
'
{{key}}
必填'
,
queryRequired
:
'主要文本必填'
,
waitForResponse
:
'请等待上条信息响应完成'
,
waitForBatchResponse
:
'请等待批量任务完成'
,
...
...
web/i18n/lang/common.zh.ts
View file @
bd6248ea
...
...
@@ -43,7 +43,7 @@ const translation = {
'较高的 Temperature 设置将导致更多样和创造性的输出,而较低的 Temperature 将产生更保守的输出并且类似于训练数据。'
,
topP
:
'采样范围'
,
topPTip
:
'Top P值越
高,输出与训练文本越相似,Top P值越低
,输出越有创意和变化。它可用于使输出更适合特定用例。'
,
'Top P值越
低,输出与训练文本越相似,Top P值越高
,输出越有创意和变化。它可用于使输出更适合特定用例。'
,
presencePenalty
:
'词汇控制'
,
presencePenaltyTip
:
'Presence penalty 是根据新词是否出现在目前的文本中来对其进行惩罚。正值将降低模型谈论新话题的可能性。'
,
...
...
web/package.json
View file @
bd6248ea
...
...
@@ -54,7 +54,7 @@
"katex"
:
"^0.16.7"
,
"lodash-es"
:
"^4.17.21"
,
"negotiator"
:
"^0.6.3"
,
"next"
:
"
^13.4.7
"
,
"next"
:
"
13.3.0
"
,
"qs"
:
"^6.11.1"
,
"react"
:
"^18.2.0"
,
"react-dom"
:
"^18.2.0"
,
...
...
web/public/embed.js
View file @
bd6248ea
...
...
@@ -15,6 +15,7 @@ async function embedChatbot () {
return
;
}
const
isDev
=
!!
difyChatbotConfig
.
isDev
const
baseUrl
=
difyChatbotConfig
.
baseUrl
||
`https://
${
isDev
?
'dev.'
:
''
}
udify.app`
const
openIcon
=
`<svg
id="openIcon"
width="24"
...
...
@@ -53,7 +54,7 @@ async function embedChatbot () {
iframe
.
allow
=
"fullscreen;microphone"
iframe
.
title
=
"dify chatbot bubble window"
iframe
.
id
=
'dify-chatbot-bubble-window'
iframe
.
src
=
`
https://
${
isDev
?
'dev.'
:
''
}
udify.app/chatbot/
${
difyChatbotConfig
.
token
}
`
;
iframe
.
src
=
`
${
baseUrl
}
/chatbot/
${
difyChatbotConfig
.
token
}
`
iframe
.
style
.
cssText
=
'border: none; position: fixed; flex-direction: column; justify-content: space-between; box-shadow: rgba(150, 150, 150, 0.2) 0px 10px 30px 0px, rgba(150, 150, 150, 0.2) 0px 0px 0px 1px; bottom: 5rem; right: 1rem; width: 24rem; height: 40rem; border-radius: 0.75rem; display: flex; z-index: 2147483647; overflow: hidden; left: unset; background-color: #F3F4F6;'
document
.
body
.
appendChild
(
iframe
);
}
...
...
web/public/embed.min.js
View file @
bd6248ea
async
function
embedChatbot
(){
const
t
=
window
.
difyChatbotConfig
;
if
(
t
&&
t
.
token
){
const
o
=!!
t
.
isDev
,
n
=
`<svg
async
function
embedChatbot
(){
const
t
=
window
.
difyChatbotConfig
;
if
(
t
&&
t
.
token
){
var
e
=!!
t
.
isDev
;
const
o
=
t
.
baseUrl
||
`https://
${
e
?
"dev."
:
""
}
udify.app`
,
n
=
`<svg
id="openIcon"
width="24"
height="24"
...
...
@@ -27,4 +27,4 @@ async function embedChatbot(){const t=window.difyChatbotConfig;if(t&&t.token){co
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>`
;
if
(
!
document
.
getElementById
(
"dify-chatbot-bubble-button"
)){
var
e
=
document
.
createElement
(
"div"
);
e
.
id
=
"dify-chatbot-bubble-button"
,
e
.
style
.
cssText
=
"position: fixed; bottom: 1rem; right: 1rem; width: 50px; height: 50px; border-radius: 25px; background-color: #155EEF; box-shadow: rgba(0, 0, 0, 0.2) 0px 4px 8px 0px; cursor: pointer; z-index: 2147483647; transition: all 0.2s ease-in-out 0s; left: unset; transform: scale(1); :hover {transform: scale(1.1);}"
;
const
d
=
document
.
createElement
(
"div"
);
d
.
style
.
cssText
=
"display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; z-index: 2147483647;"
,
d
.
innerHTML
=
n
,
e
.
appendChild
(
d
),
document
.
body
.
appendChild
(
e
),
e
.
addEventListener
(
"click"
,
function
(){
var
e
=
document
.
getElementById
(
"dify-chatbot-bubble-window"
);
e
?
"none"
===
e
.
style
.
display
?(
e
.
style
.
display
=
"block"
,
d
.
innerHTML
=
i
):(
e
.
style
.
display
=
"none"
,
d
.
innerHTML
=
n
):((
e
=
document
.
createElement
(
"iframe"
)).
allow
=
"fullscreen;microphone"
,
e
.
title
=
"dify chatbot bubble window"
,
e
.
id
=
"dify-chatbot-bubble-window"
,
e
.
src
=
`https://
${
o
?
"dev."
:
""
}
udify.app/chatbot/`
+
t
.
token
,
e
.
style
.
cssText
=
"border: none; position: fixed; flex-direction: column; justify-content: space-between; box-shadow: rgba(150, 150, 150, 0.2) 0px 10px 30px 0px, rgba(150, 150, 150, 0.2) 0px 0px 0px 1px; bottom: 5rem; right: 1rem; width: 24rem; height: 40rem; border-radius: 0.75rem; display: flex; z-index: 2147483647; overflow: hidden; left: unset; background-color: #F3F4F6;"
,
document
.
body
.
appendChild
(
e
),
d
.
innerHTML
=
i
)})}}
else
console
.
error
(
"difyChatbotConfig is empty or token is not provided"
)}
document
.
body
.
onload
=
embedChatbot
;
\ No newline at end of file
</svg>`
;
if
(
!
document
.
getElementById
(
"dify-chatbot-bubble-button"
)){
e
=
document
.
createElement
(
"div"
);
e
.
id
=
"dify-chatbot-bubble-button"
,
e
.
style
.
cssText
=
"position: fixed; bottom: 1rem; right: 1rem; width: 50px; height: 50px; border-radius: 25px; background-color: #155EEF; box-shadow: rgba(0, 0, 0, 0.2) 0px 4px 8px 0px; cursor: pointer; z-index: 2147483647; transition: all 0.2s ease-in-out 0s; left: unset; transform: scale(1); :hover {transform: scale(1.1);}"
;
const
d
=
document
.
createElement
(
"div"
);
d
.
style
.
cssText
=
"display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; z-index: 2147483647;"
,
d
.
innerHTML
=
n
,
e
.
appendChild
(
d
),
document
.
body
.
appendChild
(
e
),
e
.
addEventListener
(
"click"
,
function
(){
var
e
=
document
.
getElementById
(
"dify-chatbot-bubble-window"
);
e
?
"none"
===
e
.
style
.
display
?(
e
.
style
.
display
=
"block"
,
d
.
innerHTML
=
i
):(
e
.
style
.
display
=
"none"
,
d
.
innerHTML
=
n
):((
e
=
document
.
createElement
(
"iframe"
)).
allow
=
"fullscreen;microphone"
,
e
.
title
=
"dify chatbot bubble window"
,
e
.
id
=
"dify-chatbot-bubble-window"
,
e
.
src
=
o
+
"/chatbot/"
+
t
.
token
,
e
.
style
.
cssText
=
"border: none; position: fixed; flex-direction: column; justify-content: space-between; box-shadow: rgba(150, 150, 150, 0.2) 0px 10px 30px 0px, rgba(150, 150, 150, 0.2) 0px 0px 0px 1px; bottom: 5rem; right: 1rem; width: 24rem; height: 40rem; border-radius: 0.75rem; display: flex; z-index: 2147483647; overflow: hidden; left: unset; background-color: #F3F4F6;"
,
document
.
body
.
appendChild
(
e
),
d
.
innerHTML
=
i
)})}}
else
console
.
error
(
"difyChatbotConfig is empty or token is not provided"
)}
document
.
body
.
onload
=
embedChatbot
;
\ No newline at end of file
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