Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
赵月辉
/
fastgpt-migrated
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
3e57c7f5
authored
Aug 23, 2024
by
Archer
Committed by
GitHub
Aug 23, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
perf: workflow code (#2492)
* perf: workflow code * perf: converpoints ui * perf: account page ui
parent
eaaf6f59
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
69 additions
and
50 deletions
+69
-50
docSite/content/zh-cn/docs/development/upgrading/4810.md
+17
-14
projects/app/src/pages/account/components/Info/ConversionModal.tsx
+23
-12
projects/app/src/pages/account/components/Info/OpenAIAccountModal.tsx
+0
-0
projects/app/src/pages/account/components/Info/UpdateNotificationModal.tsx
+0
-0
projects/app/src/pages/account/components/Info/UpdatePswModal.tsx
+0
-0
projects/app/src/pages/account/components/Info/index.tsx
+4
-8
projects/app/src/pages/account/components/Info/standardDetailModal.tsx
+2
-0
projects/app/src/pages/account/index.tsx
+1
-1
projects/app/src/pages/app/detail/components/Plugin/index.tsx
+2
-1
projects/app/src/pages/app/detail/components/Workflow/Header.tsx
+4
-0
projects/app/src/pages/app/detail/components/WorkflowComponents/context.tsx
+16
-14
No files found.
docSite/content/zh-cn/docs/development/upgrading/4810.md
View file @
3e57c7f5
...
@@ -28,17 +28,20 @@ STORE_LOG_LEVEL=warn
...
@@ -28,17 +28,20 @@ STORE_LOG_LEVEL=warn
1.
新增 - 模板市场
1.
新增 - 模板市场
2.
新增 - 工作流节点拖动自动对齐吸附
2.
新增 - 工作流节点拖动自动对齐吸附
3.
新增 - 用户选择节点(Debug 模式暂未支持)
3.
新增 - 用户选择节点(Debug 模式暂未支持)
4.
商业版新增 - 飞书机器人接入
4.
新增 - 工作流撤销和重做
5.
商业版新增 - 公众号接入接入
5.
新增 - 工作流本次编辑记录,取代自动保存
6.
商业版新增 - 自助开票申请
6.
新增 - 工作流版本支持重命名
7.
商业版新增 - SSO 定制
7.
商业版新增 - 飞书机器人接入
8.
优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。
8.
商业版新增 - 公众号接入接入
9.
优化 - 节点选择,避免切换 tab 时候,path 加载报错。
9.
商业版新增 - 自助开票申请
10.
优化 - 最新 React Markdown 组件,支持 Base64 图片。
10.
商业版新增 - SSO 定制
11.
优化 - 知识库列表 UI。
11.
优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。
12.
优化 - 支持无网络配置情况下运行。
12.
优化 - 节点选择,避免切换 tab 时候,path 加载报错。
13.
修复 - Prompt 模式调用工具,stream=false 模式下,会携带 0: 开头标记。
13.
优化 - 最新 React Markdown 组件,支持 Base64 图片。
14.
修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情。
14.
优化 - 知识库列表 UI。
15.
修复 - 选择 Milvus 部署时,无法导出知识库。
15.
优化 - 支持无网络配置情况下运行。
16.
修复 - 创建 APP 副本,无法复制系统配置。
16.
修复 - Prompt 模式调用工具,stream=false 模式下,会携带 0: 开头标记。
17.
修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。
17.
修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情。
18.
修复 - 选择 Milvus 部署时,无法导出知识库。
19.
修复 - 创建 APP 副本,无法复制系统配置。
20.
修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。
projects/app/src/pages/account/components/ConversionModal.tsx
→
projects/app/src/pages/account/components/
Info/
ConversionModal.tsx
View file @
3e57c7f5
import
React
from
'react'
;
import
React
,
{
useMemo
}
from
'react'
;
import
{
ModalBody
,
Box
,
Button
,
VStack
,
HStack
,
Link
}
from
'@chakra-ui/react'
;
import
{
ModalBody
,
Box
,
Button
,
VStack
,
HStack
,
Link
}
from
'@chakra-ui/react'
;
import
MyModal
from
'@fastgpt/web/components/common/MyModal'
;
import
MyModal
from
'@fastgpt/web/components/common/MyModal'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
{
useTranslation
}
from
'next-i18next'
;
...
@@ -6,22 +6,33 @@ import Icon from '@fastgpt/web/components/common/Icon';
...
@@ -6,22 +6,33 @@ import Icon from '@fastgpt/web/components/common/Icon';
import
Tag
from
'@fastgpt/web/components/common/Tag'
;
import
Tag
from
'@fastgpt/web/components/common/Tag'
;
import
{
useRequest2
}
from
'@fastgpt/web/hooks/useRequest'
;
import
{
useRequest2
}
from
'@fastgpt/web/hooks/useRequest'
;
import
{
balanceConversion
}
from
'@/web/support/wallet/bill/api'
;
import
{
balanceConversion
}
from
'@/web/support/wallet/bill/api'
;
import
Loading
from
'@fastgpt/web/components/common/MyLoading'
;
import
{
useUserStore
}
from
'@/web/support/user/useUserStore'
;
import
{
formatStorePrice2Read
}
from
'@fastgpt/global/support/wallet/usage/tools'
;
import
{
SUB_EXTRA_POINT_RATE
}
from
'@fastgpt/global/support/wallet/bill/constants'
;
import
{
useRouter
}
from
'next/router'
;
const
ConversionModal
=
({
const
ConversionModal
=
({
onClose
,
onClose
,
balance
,
tokens
,
onOpenContact
onOpenContact
}:
{
}:
{
onClose
:
()
=>
void
;
onClose
:
()
=>
void
;
balance
:
string
;
tokens
:
string
;
onOpenContact
:
()
=>
void
;
onOpenContact
:
()
=>
void
;
})
=>
{
})
=>
{
const
{
t
}
=
useTranslation
();
const
{
t
}
=
useTranslation
();
const
{
userInfo
}
=
useUserStore
();
const
router
=
useRouter
();
const
points
=
useMemo
(()
=>
{
if
(
!
userInfo
?.
team
?.
balance
)
return
0
;
const
balance
=
formatStorePrice2Read
(
userInfo
?.
team
?.
balance
);
return
Math
.
ceil
((
balance
/
15
)
*
SUB_EXTRA_POINT_RATE
);
},
[]);
const
{
runAsync
:
onConvert
,
loading
}
=
useRequest2
(
balanceConversion
,
{
const
{
runAsync
:
onConvert
,
loading
}
=
useRequest2
(
balanceConversion
,
{
onSuccess
()
{
router
.
reload
();
},
successToast
:
t
(
'user:bill.convert_success'
),
successToast
:
t
(
'user:bill.convert_success'
),
errorToast
:
t
(
'user:bill.convert_error'
)
errorToast
:
t
(
'user:bill.convert_error'
)
});
});
...
@@ -35,7 +46,6 @@ const ConversionModal = ({
...
@@ -35,7 +46,6 @@ const ConversionModal = ({
title=
{
t
(
'user:bill.use_balance'
)
}
title=
{
t
(
'user:bill.use_balance'
)
}
>
>
<
ModalBody
maxW=
{
'450px'
}
>
<
ModalBody
maxW=
{
'450px'
}
>
{
loading
&&
<
Loading
/>
}
<
VStack
px=
"2.25"
gap=
{
2
}
pb=
"6"
>
<
VStack
px=
"2.25"
gap=
{
2
}
pb=
"6"
>
<
HStack
px=
"4"
py=
"2"
color=
"primary.600"
bgColor=
"primary.50"
borderRadius=
"md"
>
<
HStack
px=
"4"
py=
"2"
color=
"primary.600"
bgColor=
"primary.50"
borderRadius=
"md"
>
<
Icon
name=
"common/info"
w=
"1rem"
mr=
"1"
/>
<
Icon
name=
"common/info"
w=
"1rem"
mr=
"1"
/>
...
@@ -43,10 +53,10 @@ const ConversionModal = ({
...
@@ -43,10 +53,10 @@ const ConversionModal = ({
</
HStack
>
</
HStack
>
<
VStack
mt=
{
6
}
>
<
VStack
mt=
{
6
}
>
<
Box
fontSize=
{
'sm'
}
color=
"myGray.600"
fontWeight=
"500"
>
<
Box
fontSize=
{
'sm'
}
color=
"myGray.600"
fontWeight=
"500"
>
{
t
(
'user:bill.price'
)
}
当前积分价格
</
Box
>
</
Box
>
<
Box
fontSize=
{
'xl'
}
fontWeight=
{
'700'
}
color=
"myGray.900"
>
<
Box
fontSize=
{
'xl'
}
fontWeight=
{
'700'
}
color=
"myGray.900"
>
¥15/1000
{
t
(
'user:bill.tokens'
)
}
¥15/1000
{
t
(
'user:bill.tokens'
)
}
/月
</
Box
>
</
Box
>
</
VStack
>
</
VStack
>
<
VStack
mt=
{
6
}
>
<
VStack
mt=
{
6
}
>
...
@@ -54,7 +64,7 @@ const ConversionModal = ({
...
@@ -54,7 +64,7 @@ const ConversionModal = ({
{
t
(
'user:bill.balance'
)
}
{
t
(
'user:bill.balance'
)
}
</
Box
>
</
Box
>
<
Box
fontSize=
{
'xl'
}
fontWeight=
{
'700'
}
color=
"myGray.900"
>
<
Box
fontSize=
{
'xl'
}
fontWeight=
{
'700'
}
color=
"myGray.900"
>
¥
{
balance
}
¥
{
formatStorePrice2Read
(
userInfo
?.
team
?.
balance
)?.
toFixed
(
2
)
}
</
Box
>
</
Box
>
</
VStack
>
</
VStack
>
<
VStack
mt=
{
6
}
>
<
VStack
mt=
{
6
}
>
...
@@ -62,9 +72,9 @@ const ConversionModal = ({
...
@@ -62,9 +72,9 @@ const ConversionModal = ({
{
t
(
'user:bill.you_can_convert'
)
}
{
t
(
'user:bill.you_can_convert'
)
}
</
Box
>
</
Box
>
<
Box
fontSize=
{
'xl'
}
fontWeight=
{
'700'
}
color=
"myGray.900"
>
<
Box
fontSize=
{
'xl'
}
fontWeight=
{
'700'
}
color=
"myGray.900"
>
{
token
s
}
{
t
(
'user:bill.tokens'
)
}
{
point
s
}
{
t
(
'user:bill.tokens'
)
}
</
Box
>
</
Box
>
<
Tag
>
{
t
(
'user:bill.token_expire_1year'
)
}
</
Tag
>
<
Tag
fontSize=
{
'lg'
}
>
{
t
(
'user:bill.token_expire_1year'
)
}
</
Tag
>
</
VStack
>
</
VStack
>
<
VStack
mt=
"6"
>
<
VStack
mt=
"6"
>
...
@@ -74,6 +84,7 @@ const ConversionModal = ({
...
@@ -74,6 +84,7 @@ const ConversionModal = ({
fontSize=
{
'sm'
}
fontSize=
{
'sm'
}
minW=
{
'10rem'
}
minW=
{
'10rem'
}
onClick=
{
onConvert
}
onClick=
{
onConvert
}
isLoading=
{
loading
}
>
>
{
t
(
'user:bill.conversion'
)
}
{
t
(
'user:bill.conversion'
)
}
</
Button
>
</
Button
>
...
...
projects/app/src/pages/account/components/OpenAIAccountModal.tsx
→
projects/app/src/pages/account/components/
Info/
OpenAIAccountModal.tsx
View file @
3e57c7f5
File moved
projects/app/src/pages/account/components/UpdateNotificationModal.tsx
→
projects/app/src/pages/account/components/
Info/
UpdateNotificationModal.tsx
View file @
3e57c7f5
File moved
projects/app/src/pages/account/components/UpdatePswModal.tsx
→
projects/app/src/pages/account/components/
Info/
UpdatePswModal.tsx
View file @
3e57c7f5
File moved
projects/app/src/pages/account/components/Info.tsx
→
projects/app/src/pages/account/components/Info
/index
.tsx
View file @
3e57c7f5
...
@@ -305,22 +305,18 @@ const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
...
@@ -305,22 +305,18 @@ const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
<
Box
flex=
{
1
}
>
<
Box
flex=
{
1
}
>
<
strong
>
{
formatStorePrice2Read
(
userInfo
?.
team
?.
balance
).
toFixed
(
3
)
}
</
strong
>
元
<
strong
>
{
formatStorePrice2Read
(
userInfo
?.
team
?.
balance
).
toFixed
(
3
)
}
</
strong
>
元
</
Box
>
</
Box
>
{
userInfo
?.
permission
.
hasManagePer
&&
!!
standardPlan
&&
(
{
/* TODO:暂时隐藏 */
}
{
/* {userInfo?.permission.hasManagePer && !!standardPlan && (
<Button variant={'primary'} size={'sm'} ml={5} onClick={onOpenConversionModal}>
<Button variant={'primary'} size={'sm'} ml={5} onClick={onOpenConversionModal}>
{t('user:bill.conversion')}
{t('user:bill.conversion')}
</Button>
</Button>
)
}
)}
*/
}
</
Flex
>
</
Flex
>
</
Box
>
</
Box
>
)
}
)
}
</
Box
>
</
Box
>
{
isOpenConversionModal
&&
(
{
isOpenConversionModal
&&
(
<
ConversionModal
<
ConversionModal
onClose=
{
onCloseConversionModal
}
onOpenContact=
{
onOpenContact
}
/>
onClose=
{
onCloseConversionModal
}
balance=
{
formatStorePrice2Read
(
userInfo
?.
team
?.
balance
).
toFixed
(
3
)
}
tokens=
{
String
((
userInfo
?.
team
?.
balance
??
0
)
/
15
/
10
)
}
onOpenContact=
{
onOpenContact
}
/>
)
}
)
}
{
isOpenUpdatePsw
&&
<
UpdatePswModal
onClose=
{
onCloseUpdatePsw
}
/>
}
{
isOpenUpdatePsw
&&
<
UpdatePswModal
onClose=
{
onCloseUpdatePsw
}
/>
}
{
isOpenUpdateNotification
&&
<
UpdateNotification
onClose=
{
onCloseUpdateNotification
}
/>
}
{
isOpenUpdateNotification
&&
<
UpdateNotification
onClose=
{
onCloseUpdateNotification
}
/>
}
...
...
projects/app/src/pages/account/components/standardDetailModal.tsx
→
projects/app/src/pages/account/components/
Info/
standardDetailModal.tsx
View file @
3e57c7f5
...
@@ -21,6 +21,7 @@ import { subTypeMap, standardSubLevelMap } from '@fastgpt/global/support/wallet/
...
@@ -21,6 +21,7 @@ import { subTypeMap, standardSubLevelMap } from '@fastgpt/global/support/wallet/
import
{
TeamSubSchema
}
from
'@fastgpt/global/support/wallet/sub/type'
;
import
{
TeamSubSchema
}
from
'@fastgpt/global/support/wallet/sub/type'
;
import
{
formatTime2YMDHM
}
from
'@fastgpt/global/common/string/time'
;
import
{
formatTime2YMDHM
}
from
'@fastgpt/global/common/string/time'
;
import
{
useSystemStore
}
from
'@/web/common/system/useSystemStore'
;
import
{
useSystemStore
}
from
'@/web/common/system/useSystemStore'
;
const
StandDetailModal
=
({
onClose
}:
{
onClose
:
()
=>
void
})
=>
{
const
StandDetailModal
=
({
onClose
}:
{
onClose
:
()
=>
void
})
=>
{
const
{
t
}
=
useTranslation
();
const
{
t
}
=
useTranslation
();
const
{
Loading
}
=
useLoading
();
const
{
Loading
}
=
useLoading
();
...
@@ -33,6 +34,7 @@ const StandDetailModal = ({ onClose }: { onClose: () => void }) => {
...
@@ -33,6 +34,7 @@ const StandDetailModal = ({ onClose }: { onClose: () => void }) => {
maxW=
{
[
'90vw'
,
'1200px'
]
}
maxW=
{
[
'90vw'
,
'1200px'
]
}
iconSrc=
"modal/teamPlans"
iconSrc=
"modal/teamPlans"
title=
{
t
(
'common:support.wallet.Standard Plan Detail'
)
}
title=
{
t
(
'common:support.wallet.Standard Plan Detail'
)
}
isCentered
>
>
<
ModalCloseButton
onClick=
{
onClose
}
/>
<
ModalCloseButton
onClick=
{
onClose
}
/>
<
ModalBody
>
<
ModalBody
>
...
...
projects/app/src/pages/account/index.tsx
View file @
3e57c7f5
...
@@ -8,7 +8,7 @@ import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
...
@@ -8,7 +8,7 @@ import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import
PageContainer
from
'@/components/PageContainer'
;
import
PageContainer
from
'@/components/PageContainer'
;
import
SideTabs
from
'@/components/SideTabs'
;
import
SideTabs
from
'@/components/SideTabs'
;
import
LightRowTabs
from
'@fastgpt/web/components/common/Tabs/LightRowTabs'
;
import
LightRowTabs
from
'@fastgpt/web/components/common/Tabs/LightRowTabs'
;
import
UserInfo
from
'./components/Info'
;
import
UserInfo
from
'./components/Info
/index
'
;
import
{
serviceSideProps
}
from
'@/web/common/utils/i18n'
;
import
{
serviceSideProps
}
from
'@/web/common/utils/i18n'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
Script
from
'next/script'
;
import
Script
from
'next/script'
;
...
...
projects/app/src/pages/app/detail/components/Plugin/index.tsx
View file @
3e57c7f5
...
@@ -38,7 +38,8 @@ const WorkflowEdit = () => {
...
@@ -38,7 +38,8 @@ const WorkflowEdit = () => {
cloneDeep
({
cloneDeep
({
nodes
:
appDetail
.
modules
||
[],
nodes
:
appDetail
.
modules
||
[],
edges
:
appDetail
.
edges
||
[]
edges
:
appDetail
.
edges
||
[]
})
}),
true
);
);
}
}
});
});
...
...
projects/app/src/pages/app/detail/components/Workflow/Header.tsx
View file @
3e57c7f5
...
@@ -61,6 +61,9 @@ const Header = () => {
...
@@ -61,6 +61,9 @@ const Header = () => {
}
=
useContextSelector
(
WorkflowContext
,
(
v
)
=>
v
);
}
=
useContextSelector
(
WorkflowContext
,
(
v
)
=>
v
);
const
isPublished
=
useMemo
(()
=>
{
const
isPublished
=
useMemo
(()
=>
{
/*
Find the last saved snapshot in the past and future snapshots
*/
const
savedSnapshot
=
const
savedSnapshot
=
future
.
findLast
((
snapshot
)
=>
snapshot
.
isSaved
)
||
past
.
find
((
snapshot
)
=>
snapshot
.
isSaved
);
future
.
findLast
((
snapshot
)
=>
snapshot
.
isSaved
)
||
past
.
find
((
snapshot
)
=>
snapshot
.
isSaved
);
...
@@ -97,6 +100,7 @@ const Header = () => {
...
@@ -97,6 +100,7 @@ const Header = () => {
//@ts-ignore
//@ts-ignore
version
:
'v2'
version
:
'v2'
});
});
// Mark the current snapshot as saved
setPast
((
prevPast
)
=>
setPast
((
prevPast
)
=>
prevPast
.
map
((
item
,
index
)
=>
prevPast
.
map
((
item
,
index
)
=>
index
===
prevPast
.
length
-
1
index
===
prevPast
.
length
-
1
...
...
projects/app/src/pages/app/detail/components/WorkflowComponents/context.tsx
View file @
3e57c7f5
...
@@ -424,7 +424,7 @@ const WorkflowContextProvider = ({
...
@@ -424,7 +424,7 @@ const WorkflowContextProvider = ({
const
onChangeNode
=
useMemoizedFn
((
props
:
FlowNodeChangeProps
)
=>
{
const
onChangeNode
=
useMemoizedFn
((
props
:
FlowNodeChangeProps
)
=>
{
const
{
nodeId
,
type
}
=
props
;
const
{
nodeId
,
type
}
=
props
;
setNodes
((
nodes
)
=>
{
setNodes
((
nodes
)
=>
{
const
newNodes
=
nodes
.
map
((
node
)
=>
{
return
nodes
.
map
((
node
)
=>
{
if
(
node
.
id
!==
nodeId
)
return
node
;
if
(
node
.
id
!==
nodeId
)
return
node
;
const
updateObj
=
cloneDeep
(
node
.
data
);
const
updateObj
=
cloneDeep
(
node
.
data
);
...
@@ -490,7 +490,6 @@ const WorkflowContextProvider = ({
...
@@ -490,7 +490,6 @@ const WorkflowContextProvider = ({
data
:
updateObj
data
:
updateObj
};
};
});
});
return
newNodes
;
});
});
});
});
const
getNodeDynamicInputs
=
useCallback
(
const
getNodeDynamicInputs
=
useCallback
(
...
@@ -532,6 +531,13 @@ const WorkflowContextProvider = ({
...
@@ -532,6 +531,13 @@ const WorkflowContextProvider = ({
const
initData
=
useMemoizedFn
(
const
initData
=
useMemoizedFn
(
async
(
e
:
Parameters
<
WorkflowContextType
[
'initData'
]
>
[
0
],
isInit
?:
boolean
)
=>
{
async
(
e
:
Parameters
<
WorkflowContextType
[
'initData'
]
>
[
0
],
isInit
?:
boolean
)
=>
{
/*
Refresh web page, load init
*/
if
(
isInit
&&
past
.
length
>
0
)
{
return
resetSnapshot
(
past
[
0
]);
}
setNodes
(
e
.
nodes
?.
map
((
item
)
=>
storeNode2FlowNode
({
item
}))
||
[]);
setNodes
(
e
.
nodes
?.
map
((
item
)
=>
storeNode2FlowNode
({
item
}))
||
[]);
setEdges
(
e
.
edges
?.
map
((
item
)
=>
storeEdgesRenderEdge
({
edge
:
item
}))
||
[]);
setEdges
(
e
.
edges
?.
map
((
item
)
=>
storeEdgesRenderEdge
({
edge
:
item
}))
||
[]);
...
@@ -544,19 +550,15 @@ const WorkflowContextProvider = ({
...
@@ -544,19 +550,15 @@ const WorkflowContextProvider = ({
}
}
// If it is the initial data, save the initial snapshot
// If it is the initial data, save the initial snapshot
if
(
!
isInit
)
return
;
if
(
isInit
)
{
// If it has been initialized, it will not be saved
saveSnapshot
({
if
(
past
.
length
>
0
)
{
pastNodes
:
e
.
nodes
?.
map
((
item
)
=>
storeNode2FlowNode
({
item
}))
||
[],
resetSnapshot
(
past
[
0
]);
pastEdges
:
e
.
edges
?.
map
((
item
)
=>
storeEdgesRenderEdge
({
edge
:
item
}))
||
[],
return
;
customTitle
:
t
(
`app:app.version_initial`
),
chatConfig
:
appDetail
.
chatConfig
,
isSaved
:
true
});
}
}
saveSnapshot
({
pastNodes
:
e
.
nodes
?.
map
((
item
)
=>
storeNode2FlowNode
({
item
}))
||
[],
pastEdges
:
e
.
edges
?.
map
((
item
)
=>
storeEdgesRenderEdge
({
edge
:
item
}))
||
[],
customTitle
:
t
(
`app:app.version_initial`
),
chatConfig
:
appDetail
.
chatConfig
,
isSaved
:
true
});
}
}
);
);
...
...
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