Commit 9f5e1d08 by Archer Committed by GitHub

perf: template permission (#6848)

* perf: template permission

* perf: action

* doc
parent aee6c0b1
...@@ -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:
......
...@@ -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:
......
...@@ -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. 无创建权限时,隐藏模板功能。
## 🐛 修复 ## 🐛 修复
......
...@@ -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-28T15:10:52+08:00", "content/self-host/upgrading/4-15/4150.mdx": "2026-04-28T21: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-26T21:28:27+08:00", "content/toc.mdx": "2026-04-28T18: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",
......
Subproject commit 4aba60a7842c0a4b952ba35daf93b68fd520ff81 Subproject commit 70380fe53914fff72e256be0e3b4eb649ae1ad90
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 { useEffect, useMemo } 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,6 +174,8 @@ const DashboardContainer = ({ ...@@ -167,6 +174,8 @@ const DashboardContainer = ({
groupName: t('common:system_tools'), groupName: t('common:system_tools'),
children: [] children: []
}, },
...(hasAppCreatePer
? [
{ {
groupId: TabEnum.app_templates, groupId: TabEnum.app_templates,
groupAvatar: 'common/templateMarket', groupAvatar: 'common/templateMarket',
...@@ -200,7 +209,9 @@ const DashboardContainer = ({ ...@@ -200,7 +209,9 @@ const DashboardContainer = ({
] ]
: []) : [])
] ]
}, }
]
: []),
{ {
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
......
...@@ -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'}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment