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
9f5e1d08
authored
Apr 28, 2026
by
Archer
Committed by
GitHub
Apr 28, 2026
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
perf: template permission (#6848)
* perf: template permission * perf: action * doc
parent
aee6c0b1
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
66 additions
and
50 deletions
+66
-50
.github/workflows/preview-admin-build.yml
+1
-1
.github/workflows/test-fastgpt-pro.yaml
+1
-1
document/content/self-host/upgrading/4-15/4150.mdx
+2
-0
document/data/doc-last-modified.json
+3
-2
pro
+1
-1
projects/app/src/pageComponents/dashboard/Container.tsx
+52
-40
projects/app/src/pages/dashboard/agent/index.tsx
+6
-5
No files found.
.github/workflows/preview-admin-build.yml
View file @
9f5e1d08
...
@@ -25,7 +25,7 @@ permissions:
...
@@ -25,7 +25,7 @@ permissions:
jobs
:
jobs
:
build
:
build
:
if
:
${{
github.event.pull_request.author_association == 'MEMBER'
}}
if
:
${{
contains(fromJSON('["COLLABORATOR", "OWNER"]'), github.event.pull_request.author_association)
}}
runs-on
:
ubuntu-24.04
runs-on
:
ubuntu-24.04
steps
:
steps
:
...
...
.github/workflows/test-fastgpt-pro.yaml
View file @
9f5e1d08
...
@@ -20,7 +20,7 @@ concurrency:
...
@@ -20,7 +20,7 @@ concurrency:
jobs
:
jobs
:
test
:
test
:
if
:
${{ github.event_name != 'pull_request_target' ||
github.event.pull_request.author_association == 'MEMBER'
}}
if
:
${{ github.event_name != 'pull_request_target' ||
contains(fromJSON('["COLLABORATOR", "OWNER"]'), github.event.pull_request.author_association)
}}
runs-on
:
ubuntu-latest
runs-on
:
ubuntu-latest
permissions
:
permissions
:
...
...
document/content/self-host/upgrading/4-15/4150.mdx
View file @
9f5e1d08
...
@@ -13,6 +13,8 @@ description: 'FastGPT V4.15.0 更新说明'
...
@@ -13,6 +13,8 @@ description: 'FastGPT V4.15.0 更新说明'
1. 增加父子节点选中互斥功能,解决:同时选中父子节点时,移动节点会出现抖动。
1. 增加父子节点选中互斥功能,解决:同时选中父子节点时,移动节点会出现抖动。
2. 调整文件注入 messages 位置,从 system 调整至 user,便于命中缓存。
2. 调整文件注入 messages 位置,从 system 调整至 user,便于命中缓存。
3. 非管理员/访客,触发余额不足时候,提示优化。
4. 无创建权限时,隐藏模板功能。
## 🐛 修复
## 🐛 修复
...
...
document/data/doc-last-modified.json
View file @
9f5e1d08
...
@@ -231,6 +231,7 @@
...
@@ -231,6 +231,7 @@
"content/self-host/upgrading/4-14/41415.mdx"
:
"2026-04-26T21:28:27+08:00"
,
"content/self-host/upgrading/4-14/41415.mdx"
:
"2026-04-26T21:28:27+08:00"
,
"content/self-host/upgrading/4-14/41416.en.mdx"
:
"2026-04-26T21:28:27+08:00"
,
"content/self-host/upgrading/4-14/41416.en.mdx"
:
"2026-04-26T21:28:27+08:00"
,
"content/self-host/upgrading/4-14/41416.mdx"
:
"2026-04-26T22:41:57+08:00"
,
"content/self-host/upgrading/4-14/41416.mdx"
:
"2026-04-26T22:41:57+08:00"
,
"content/self-host/upgrading/4-14/41417.mdx"
:
"2026-04-28T18:03:38+08:00"
,
"content/self-host/upgrading/4-14/4142.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/4-14/4142.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/4-14/4142.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/4-14/4142.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/4-14/4143.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/4-14/4143.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
...
@@ -251,7 +252,7 @@
...
@@ -251,7 +252,7 @@
"content/self-host/upgrading/4-14/41481.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/4-14/41481.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/4-14/4149.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/4-14/4149.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/4-14/4149.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/4-14/4149.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/4-15/4150.mdx"
:
"2026-04-28T
15:10:52
+08:00"
,
"content/self-host/upgrading/4-15/4150.mdx"
:
"2026-04-28T
21:27:07
+08:00"
,
"content/self-host/upgrading/outdated/40.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/outdated/40.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/outdated/40.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/outdated/40.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/outdated/41.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/outdated/41.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
...
@@ -393,7 +394,7 @@
...
@@ -393,7 +394,7 @@
"content/self-host/upgrading/upgrade-intruction.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/upgrade-intruction.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/upgrade-intruction.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/self-host/upgrading/upgrade-intruction.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/toc.en.mdx"
:
"2026-04-26T21:28:27+08:00"
,
"content/toc.en.mdx"
:
"2026-04-26T21:28:27+08:00"
,
"content/toc.mdx"
:
"2026-04-2
6T21:28:27
+08:00"
,
"content/toc.mdx"
:
"2026-04-2
8T18:03:38
+08:00"
,
"content/use-cases/app-cases/dalle3.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/use-cases/app-cases/dalle3.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/use-cases/app-cases/dalle3.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/use-cases/app-cases/dalle3.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/use-cases/app-cases/english_essay_correction_bot.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
"content/use-cases/app-cases/english_essay_correction_bot.en.mdx"
:
"2026-04-26T21:08:47+08:00"
,
...
...
pro
@
70380fe5
Subproject commit
4aba60a7842c0a4b952ba35daf93b68fd520ff81
Subproject commit
70380fe53914fff72e256be0e3b4eb649ae1ad90
projects/app/src/pageComponents/dashboard/Container.tsx
View file @
9f5e1d08
import
{
Box
,
Divider
,
Flex
,
useDisclosure
}
from
'@chakra-ui/react'
;
import
{
Box
,
Divider
,
Flex
,
useDisclosure
}
from
'@chakra-ui/react'
;
import
{
useSystem
}
from
'@fastgpt/web/hooks/useSystem'
;
import
{
useSystem
}
from
'@fastgpt/web/hooks/useSystem'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
{
useMemo
}
from
'react'
;
import
{
use
Effect
,
use
Memo
}
from
'react'
;
import
{
AppTemplateTypeEnum
,
AppTypeEnum
}
from
'@fastgpt/global/core/app/constants'
;
import
{
AppTemplateTypeEnum
,
AppTypeEnum
}
from
'@fastgpt/global/core/app/constants'
;
import
{
useSystemStore
}
from
'@/web/common/system/useSystemStore'
;
import
{
useSystemStore
}
from
'@/web/common/system/useSystemStore'
;
import
{
useRouter
}
from
'next/router'
;
import
{
useRouter
}
from
'next/router'
;
...
@@ -36,11 +36,12 @@ const DashboardContainer = ({
...
@@ -36,11 +36,12 @@ const DashboardContainer = ({
})
=>
React
.
ReactNode
;
})
=>
React
.
ReactNode
;
})
=>
{
})
=>
{
const
router
=
useRouter
();
const
router
=
useRouter
();
const
{
t
,
i18n
}
=
useTranslation
();
const
{
t
}
=
useTranslation
();
const
{
isPc
}
=
useSystem
();
const
{
isPc
}
=
useSystem
();
const
{
feConfigs
}
=
useSystemStore
();
const
{
feConfigs
}
=
useSystemStore
();
const
{
isOpen
:
isOpenSidebar
,
onOpen
:
onOpenSidebar
,
onClose
:
onCloseSidebar
}
=
useDisclosure
();
const
{
isOpen
:
isOpenSidebar
,
onOpen
:
onOpenSidebar
,
onClose
:
onCloseSidebar
}
=
useDisclosure
();
const
{
userInfo
}
=
useUserStore
();
const
{
userInfo
}
=
useUserStore
();
const
hasAppCreatePer
=
!!
userInfo
?.
team
.
permission
.
hasAppCreatePer
;
// First tab
// First tab
const
currentTab
=
useMemo
(()
=>
{
const
currentTab
=
useMemo
(()
=>
{
...
@@ -56,10 +57,16 @@ const DashboardContainer = ({
...
@@ -56,10 +57,16 @@ const DashboardContainer = ({
appType
?:
AppTypeEnum
|
'all'
;
appType
?:
AppTypeEnum
|
'all'
;
};
};
useEffect
(()
=>
{
if
(
userInfo
&&
currentTab
===
TabEnum
.
app_templates
&&
!
hasAppCreatePer
)
{
router
.
replace
(
'/dashboard/agent'
);
}
},
[
currentTab
,
hasAppCreatePer
,
router
,
userInfo
]);
// Template market
// Template market
const
{
data
:
templateTags
=
[],
loading
:
isLoadingTemplatesTags
}
=
useRequest
(
const
{
data
:
templateTags
=
[],
loading
:
isLoadingTemplatesTags
}
=
useRequest
(
()
=>
()
=>
currentTab
===
TabEnum
.
app_templates
currentTab
===
TabEnum
.
app_templates
&&
hasAppCreatePer
?
getTemplateTagList
().
then
((
res
)
=>
[
?
getTemplateTagList
().
then
((
res
)
=>
[
{
{
typeId
:
AppTemplateTypeEnum
.
recommendation
,
typeId
:
AppTemplateTypeEnum
.
recommendation
,
...
@@ -73,20 +80,20 @@ const DashboardContainer = ({
...
@@ -73,20 +80,20 @@ const DashboardContainer = ({
:
Promise
.
resolve
([]),
:
Promise
.
resolve
([]),
{
{
manual
:
false
,
manual
:
false
,
refreshDeps
:
[
currentTab
]
refreshDeps
:
[
currentTab
,
hasAppCreatePer
,
userInfo
?.
team
.
isWecomTeam
]
}
}
);
);
const
{
data
:
templateData
,
loading
:
isLoadingTemplates
}
=
useRequest
(
const
{
data
:
templateData
,
loading
:
isLoadingTemplates
}
=
useRequest
(
()
=>
()
=>
currentTab
===
TabEnum
.
app_templates
currentTab
===
TabEnum
.
app_templates
&&
hasAppCreatePer
?
getTemplateMarketItemList
({
type
:
appType
})
?
getTemplateMarketItemList
({
type
:
appType
})
:
Promise
.
resolve
({
list
:
[],
total
:
0
}),
:
Promise
.
resolve
({
list
:
[],
total
:
0
}),
{
{
manual
:
false
,
manual
:
false
,
refreshDeps
:
[
currentTab
,
appType
]
refreshDeps
:
[
currentTab
,
appType
,
hasAppCreatePer
]
}
}
);
);
const
templateList
=
templateData
?.
list
||
[]
;
const
templateList
=
useMemo
(()
=>
templateData
?.
list
??
[],
[
templateData
?.
list
])
;
const
groupList
=
useMemo
<
const
groupList
=
useMemo
<
{
{
...
@@ -167,40 +174,44 @@ const DashboardContainer = ({
...
@@ -167,40 +174,44 @@ const DashboardContainer = ({
groupName
:
t
(
'common:system_tools'
),
groupName
:
t
(
'common:system_tools'
),
children
:
[]
children
:
[]
},
},
{
...(
hasAppCreatePer
groupId
:
TabEnum
.
app_templates
,
?
[
groupAvatar
:
'common/templateMarket'
,
{
groupName
:
t
(
'common:template_market'
),
groupId
:
TabEnum
.
app_templates
,
children
:
[
groupAvatar
:
'common/templateMarket'
,
...
templateTags
groupName
:
t
(
'common:template_market'
),
.
map
((
tag
)
=>
{
children
:
[
const
templates
=
templateList
.
filter
((
template
)
=>
...
templateTags
template
.
tags
.
includes
(
tag
.
typeId
)
.
map
((
tag
)
=>
{
);
const
templates
=
templateList
.
filter
((
template
)
=>
return
{
template
.
tags
.
includes
(
tag
.
typeId
)
...
tag
,
);
templates
return
{
};
...
tag
,
})
templates
.
filter
((
tag
)
=>
tag
.
templates
.
length
>
0
)
};
.
map
((
tag
,
index
)
=>
({
})
typeId
:
tag
.
typeId
,
.
filter
((
tag
)
=>
tag
.
templates
.
length
>
0
)
typeName
:
t
(
tag
.
typeName
as
any
),
.
map
((
tag
,
index
)
=>
({
isActive
:
index
===
0
&&
!
currentType
typeId
:
tag
.
typeId
,
})),
typeName
:
t
(
tag
.
typeName
as
any
),
...(
feConfigs
?.
appTemplateCourse
isActive
:
index
===
0
&&
!
currentType
?
[
})),
{
...(
feConfigs
?.
appTemplateCourse
typeId
:
AppTemplateTypeEnum
.
contribute
,
?
[
typeName
:
t
(
'common:contribute_app_template'
),
{
onClick
:
()
=>
{
typeId
:
AppTemplateTypeEnum
.
contribute
,
window
.
open
(
feConfigs
.
appTemplateCourse
);
typeName
:
t
(
'common:contribute_app_template'
),
}
onClick
:
()
=>
{
}
window
.
open
(
feConfigs
.
appTemplateCourse
);
}
}
]
:
[])
]
]
:
[])
}
]
]
}
,
:
[])
,
{
{
groupId
:
TabEnum
.
mcp_server
,
groupId
:
TabEnum
.
mcp_server
,
groupAvatar
:
'mcp'
,
groupAvatar
:
'mcp'
,
...
@@ -223,6 +234,7 @@ const DashboardContainer = ({
...
@@ -223,6 +234,7 @@ const DashboardContainer = ({
feConfigs
.
appTemplateCourse
,
feConfigs
.
appTemplateCourse
,
feConfigs
?.
isPlus
,
feConfigs
?.
isPlus
,
feConfigs
?.
show_skill
,
feConfigs
?.
show_skill
,
hasAppCreatePer
,
t
,
t
,
templateList
,
templateList
,
templateTags
templateTags
...
...
projects/app/src/pages/dashboard/agent/index.tsx
View file @
9f5e1d08
...
@@ -63,6 +63,10 @@ const MyApps = ({ MenuIcon }: { MenuIcon: JSX.Element }) => {
...
@@ -63,6 +63,10 @@ const MyApps = ({ MenuIcon }: { MenuIcon: JSX.Element }) => {
onOpen
:
onOpenJsonImportModal
,
onOpen
:
onOpenJsonImportModal
,
onClose
:
onCloseJsonImportModal
onClose
:
onCloseJsonImportModal
}
=
useDisclosure
();
}
=
useDisclosure
();
const
hasCreatePer
=
folderDetail
?
folderDetail
.
permission
.
hasWritePer
&&
folderDetail
?.
type
!==
AppTypeEnum
.
httpPlugin
:
userInfo
?.
team
.
permission
.
hasAppCreatePer
;
//if there is a workflow url in the session storage, open the json import modal and import the workflow
//if there is a workflow url in the session storage, open the json import modal and import the workflow
useMount
(()
=>
{
useMount
(()
=>
{
if
(
getUtmWorkflow
())
{
if
(
getUtmWorkflow
())
{
...
@@ -105,7 +109,7 @@ const MyApps = ({ MenuIcon }: { MenuIcon: JSX.Element }) => {
...
@@ -105,7 +109,7 @@ const MyApps = ({ MenuIcon }: { MenuIcon: JSX.Element }) => {
overflowX=
{
'hidden'
}
overflowX=
{
'hidden'
}
>
>
{
/* Only shown on pc root page */
}
{
/* Only shown on pc root page */
}
{
!
folderDetail
&&
isPc
&&
<
TemplateCreatePanel
type=
{
appType
}
/>
}
{
!
folderDetail
&&
isPc
&&
hasCreatePer
&&
<
TemplateCreatePanel
type=
{
appType
}
/>
}
<
Flex
alignItems=
{
'center'
}
>
<
Flex
alignItems=
{
'center'
}
>
{
!
isPc
?
(
{
!
isPc
?
(
MenuIcon
MenuIcon
...
@@ -143,10 +147,7 @@ const MyApps = ({ MenuIcon }: { MenuIcon: JSX.Element }) => {
...
@@ -143,10 +147,7 @@ const MyApps = ({ MenuIcon }: { MenuIcon: JSX.Element }) => {
/>
/>
)
}
)
}
{
(
folderDetail
{
hasCreatePer
&&
(
?
folderDetail
.
permission
.
hasWritePer
&&
folderDetail
?.
type
!==
AppTypeEnum
.
httpPlugin
:
userInfo
?.
team
.
permission
.
hasAppCreatePer
)
&&
(
<>
<>
<
Button
<
Button
variant=
{
'grayBase'
}
variant=
{
'grayBase'
}
...
...
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