Commit 7bf0b268 by siigure Committed by GitHub

fix: update pro modal titles in multiple languages for consistency (#7107)

* fix: update pro modal titles in multiple languages for consistency

* feat: add commercial dataset type handling and pro modal integration

* perf: pro modal ui

---------

Co-authored-by: archer <545436317@qq.com>
parent b3ba5de1
...@@ -313,13 +313,6 @@ ...@@ -313,13 +313,6 @@
"plugin_cost_per_times": "{{cost}} points/time", "plugin_cost_per_times": "{{cost}} points/time",
"plugin_offline_tips": "Your system does not have direct access to plugin market data,\n\nPlease manually copy the URL and go to get more plugins", "plugin_offline_tips": "Your system does not have direct access to plugin market data,\n\nPlease manually copy the URL and go to get more plugins",
"plugin_offline_url": "URL", "plugin_offline_url": "URL",
"pro_modal_feature_1": "External organization structure integration and multi-tenancy",
"pro_modal_feature_2": "Team-exclusive application showcase page",
"pro_modal_feature_3": "Knowledge base enhanced indexing",
"pro_modal_later_button": "Maybe Later",
"pro_modal_subtitle": "Join the business edition now to unlock more premium features",
"pro_modal_title": "Business Edition Exclusive!",
"pro_modal_unlock_button": "Unlock Now",
"publish.chat_desc": "After logging into the portal, users can talk directly to the application", "publish.chat_desc": "After logging into the portal, users can talk directly to the application",
"publish.playground_link": "Redirect Link", "publish.playground_link": "Redirect Link",
"publish_channel": "Publish", "publish_channel": "Publish",
......
...@@ -226,6 +226,13 @@ ...@@ -226,6 +226,13 @@
"comfirn_create": "Confirm Creation", "comfirn_create": "Confirm Creation",
"commercial_function_tip": "Please Upgrade to the Commercial Version to Use This Feature: https://doc.fastgpt.cn/guide/version/commercial", "commercial_function_tip": "Please Upgrade to the Commercial Version to Use This Feature: https://doc.fastgpt.cn/guide/version/commercial",
"community_support": "community support", "community_support": "community support",
"pro_modal_feature_1": "External organization structure integration and multi-tenancy",
"pro_modal_feature_2": "Team-exclusive application showcase page",
"pro_modal_feature_3": "Knowledge base enhanced indexing",
"pro_modal_later_button": "Maybe Later",
"pro_modal_subtitle": "Join the business edition now to unlock more premium features",
"pro_modal_title": "Business Edition Exclusive",
"pro_modal_unlock_button": "Unlock Now",
"compliance.chat": "The content is generated by third-party AI and cannot be guaranteed to be true and accurate. It is for reference only.", "compliance.chat": "The content is generated by third-party AI and cannot be guaranteed to be true and accurate. It is for reference only.",
"compliance.dataset": "Please ensure that your content strictly complies with relevant laws and regulations and avoid containing any illegal or infringing content. \nPlease be careful when uploading materials that may contain sensitive information.", "compliance.dataset": "Please ensure that your content strictly complies with relevant laws and regulations and avoid containing any illegal or infringing content. \nPlease be careful when uploading materials that may contain sensitive information.",
"confirm_choice": "Confirm Choice", "confirm_choice": "Confirm Choice",
......
...@@ -313,13 +313,6 @@ ...@@ -313,13 +313,6 @@
"plugin_cost_per_times": "{{cost}} 积分/次", "plugin_cost_per_times": "{{cost}} 积分/次",
"plugin_offline_tips": "您的系统无法直接访问插件市场数据,\n请手动复制网址并前往,以获得更多插件", "plugin_offline_tips": "您的系统无法直接访问插件市场数据,\n请手动复制网址并前往,以获得更多插件",
"plugin_offline_url": "网址", "plugin_offline_url": "网址",
"pro_modal_feature_1": "外部组织架构接入与多租户",
"pro_modal_feature_2": "团队专属的应用展示页",
"pro_modal_feature_3": "知识库增强索引",
"pro_modal_later_button": "我再想想",
"pro_modal_subtitle": "即刻加入商业版,解锁更多高级功能",
"pro_modal_title": "商业版专享!",
"pro_modal_unlock_button": "去解锁",
"publish.chat_desc": "用户登录门户后可直接与应用对话", "publish.chat_desc": "用户登录门户后可直接与应用对话",
"publish.playground_link": "跳转链接", "publish.playground_link": "跳转链接",
"publish_channel": "发布渠道", "publish_channel": "发布渠道",
......
...@@ -226,6 +226,13 @@ ...@@ -226,6 +226,13 @@
"comfirn_create": "确认创建", "comfirn_create": "确认创建",
"commercial_function_tip": "请升级商业版后使用该功能:https://doc.fastgpt.cn/guide/version/commercial", "commercial_function_tip": "请升级商业版后使用该功能:https://doc.fastgpt.cn/guide/version/commercial",
"community_support": "社区支持", "community_support": "社区支持",
"pro_modal_feature_1": "外部组织架构接入与多租户",
"pro_modal_feature_2": "团队专属的应用展示页",
"pro_modal_feature_3": "知识库增强索引",
"pro_modal_later_button": "我再想想",
"pro_modal_subtitle": "即刻加入商业版,解锁更多高级功能",
"pro_modal_title": "商业版专享",
"pro_modal_unlock_button": "去解锁",
"compliance.chat": "内容由第三方 AI 生成,无法确保真实准确,仅供参考", "compliance.chat": "内容由第三方 AI 生成,无法确保真实准确,仅供参考",
"compliance.dataset": "请确保您的内容严格遵守相关法律法规,避免包含任何违法或侵权的内容。请谨慎上传可能涉及敏感信息的资料。", "compliance.dataset": "请确保您的内容严格遵守相关法律法规,避免包含任何违法或侵权的内容。请谨慎上传可能涉及敏感信息的资料。",
"confirm_choice": "确认选择", "confirm_choice": "确认选择",
......
...@@ -305,13 +305,6 @@ ...@@ -305,13 +305,6 @@
"plugin_cost_per_times": "{{cost}} 積分/次", "plugin_cost_per_times": "{{cost}} 積分/次",
"plugin_offline_tips": "您的系統無法直接訪問插件市場數據,\n請手動複製網址並前往,以獲得更多插件", "plugin_offline_tips": "您的系統無法直接訪問插件市場數據,\n請手動複製網址並前往,以獲得更多插件",
"plugin_offline_url": "網址", "plugin_offline_url": "網址",
"pro_modal_feature_1": "外部組織架構接入與多租戶",
"pro_modal_feature_2": "團隊專屬的應用展示頁",
"pro_modal_feature_3": "知識庫增強索引",
"pro_modal_later_button": "我再想想",
"pro_modal_subtitle": "即刻加入商業版,解鎖更多高級功能",
"pro_modal_title": "商業版專享!",
"pro_modal_unlock_button": "去解鎖",
"publish.chat_desc": "用戶登錄門戶後可直接與應用對話", "publish.chat_desc": "用戶登錄門戶後可直接與應用對話",
"publish.playground_link": "跳轉鏈接", "publish.playground_link": "跳轉鏈接",
"publish_channel": "發布通道", "publish_channel": "發布通道",
......
...@@ -224,6 +224,13 @@ ...@@ -224,6 +224,13 @@
"comfirn_create": "確認建立", "comfirn_create": "確認建立",
"commercial_function_tip": "請升級為商業版後使用此功能:https://doc.fastgpt.cn/guide/version/commercial", "commercial_function_tip": "請升級為商業版後使用此功能:https://doc.fastgpt.cn/guide/version/commercial",
"community_support": "社區支持", "community_support": "社區支持",
"pro_modal_feature_1": "外部組織架構接入與多租戶",
"pro_modal_feature_2": "團隊專屬的應用展示頁",
"pro_modal_feature_3": "知識庫增強索引",
"pro_modal_later_button": "我再想想",
"pro_modal_subtitle": "即刻加入商業版,解鎖更多高級功能",
"pro_modal_title": "商業版專享",
"pro_modal_unlock_button": "去解鎖",
"compliance.chat": "內容由第三方 AI 產生,無法保證其真實性與準確性,僅供參考。", "compliance.chat": "內容由第三方 AI 產生,無法保證其真實性與準確性,僅供參考。",
"compliance.dataset": "請確保您的內容嚴格遵守相關法律法規,避免包含任何違法或侵權的內容。\n在上傳可能涉及敏感資訊的資料時請務必謹慎。", "compliance.dataset": "請確保您的內容嚴格遵守相關法律法規,避免包含任何違法或侵權的內容。\n在上傳可能涉及敏感資訊的資料時請務必謹慎。",
"confirm_choice": "確認選擇", "confirm_choice": "確認選擇",
......
Subproject commit 8c76261acbe8a406cedd8c55e306cbac66b90b7e Subproject commit 336c7cc6988acea74d38f123b44680cff5064c27
...@@ -25,7 +25,11 @@ const ProModal = (props: { isOpen?: boolean; onClose?: () => void }) => { ...@@ -25,7 +25,11 @@ const ProModal = (props: { isOpen?: boolean; onClose?: () => void }) => {
> >
<ModalBody <ModalBody
userSelect={'none'} userSelect={'none'}
py={8} pt={0}
pb={8}
px={6}
position={'relative'}
overflow={'hidden'}
_before={{ _before={{
content: '""', content: '""',
position: 'absolute', position: 'absolute',
...@@ -34,68 +38,64 @@ const ProModal = (props: { isOpen?: boolean; onClose?: () => void }) => { ...@@ -34,68 +38,64 @@ const ProModal = (props: { isOpen?: boolean; onClose?: () => void }) => {
w: '100%', w: '100%',
h: '100%', h: '100%',
bgImage: 'url(/imgs/proModalBg.png)', bgImage: 'url(/imgs/proModalBg.png)',
bgSize: 'cover', bgSize: '100% auto',
bgPosition: 'center', bgPosition: 'top center',
bgRepeat: 'no-repeat', bgRepeat: 'no-repeat',
opacity: 0.48, opacity: 0.32,
zIndex: -10 zIndex: -10
}} }}
display={'flex'} display={'flex'}
justifyContent={'center'} justifyContent={'center'}
> >
<VStack gap={4} w={'300px'} px={1}> <VStack w={'full'} alignItems={'center'} textAlign={'center'} gap={0}>
<MyIcon name={'star'} w={8} /> <Flex h={'112px'} alignItems={'center'} justifyContent={'center'}>
<Box <MyIcon name={'star'} w={9} h={9} transform={'translateY(40%)'} />
color={'myGray.900'} </Flex>
fontSize="20px" <Box color={'myGray.900'} fontSize={'26px'} fontWeight={'bold'} lineHeight={'34px'}>
fontWeight={'medium'} {t('common:pro_modal_title')}
lineHeight="26px"
letterSpacing="0.15px"
>
{t('app:pro_modal_title')}
</Box>
<Box
color={'myGray.900'}
fontSize="18px"
fontWeight={'medium'}
lineHeight="26px"
letterSpacing="0.15px"
>
{t('app:pro_modal_subtitle')}
</Box> </Box>
<Flex <VStack
flexDirection={'column'}
gap={'10px'}
w={'full'} w={'full'}
color={'myGray.900'} color={'myGray.900'}
fontSize={'14px'} fontSize={'18px'}
alignItems={'center'}
gap={0}
mt={7}
> >
<Box>{t('app:pro_modal_feature_1')}</Box> <Box lineHeight={'26px'}>{t('common:pro_modal_subtitle')}</Box>
<Box>{t('app:pro_modal_feature_2')}</Box> <Box lineHeight={'26px'}>{t('common:pro_modal_feature_1')}</Box>
<Box>{t('app:pro_modal_feature_3')}</Box> <Box lineHeight={'26px'}>{t('common:pro_modal_feature_2')}</Box>
<Box> <Box lineHeight={'26px'}>{t('common:pro_modal_feature_3')}</Box>
<MyIcon name={'common/ellipsis'} w={'18px'} /> <Box color={'myGray.500'} letterSpacing={'2px'} lineHeight={'26px'}>
......
</Box> </Box>
</Flex> </VStack>
<Flex gap={'3'} flexDirection={'column'} w={'full'}> <Flex gap={3} flexDirection={'column'} w={'full'} mt={6}>
<Button <Button
w={'full'} w={'full'}
h={'48px'}
borderRadius={'10px'}
onClick={() => { onClick={() => {
window.open(getDocPath('/guide/version/commercial'), '_blank'); window.open(getDocPath('/guide/version/commercial'), '_blank');
}} }}
fontSize={'14px'} fontSize={'16px'}
fontWeight={'medium'}
> >
{t('app:pro_modal_unlock_button')} {t('common:pro_modal_unlock_button')}
</Button>
<Button
w={'full'}
h={'48px'}
borderRadius={'10px'}
variant={'whiteBase'}
fontSize={'16px'}
fontWeight={'medium'}
borderColor={'#E4E7ED'}
boxShadow={'0 2px 5px rgba(15, 23, 42, 0.06)'}
onClick={onClose}
>
{t('common:pro_modal_later_button')}
</Button> </Button>
</Flex>
<Flex
rounded={'md'}
fontSize={'12px'}
color={'myGray.600'}
cursor={'pointer'}
onClick={onClose}
>
{t('app:pro_modal_later_button')}
</Flex> </Flex>
</VStack> </VStack>
</ModalBody> </ModalBody>
......
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import type { CreateDatasetType } from './CreateModal';
/** Web 站点与第三方知识库仅商业版可创建;社区版在新建入口点击后弹出 ProModal。 */
export const commercialDatasetTypes: readonly CreateDatasetType[] = [
DatasetTypeEnum.websiteDataset,
DatasetTypeEnum.apiDataset,
DatasetTypeEnum.feishu,
DatasetTypeEnum.yuque,
DatasetTypeEnum.dingtalk
];
/** 判断是否为商业版专属知识库类型。 */
export const isCommercialDatasetType = (type: CreateDatasetType) =>
commercialDatasetTypes.includes(type);
export type DatasetCreateAction = 'create' | 'proModal';
/**
* 根据商业版状态与知识库类型,决定新建入口的下一步动作。
* 社区版点击 Web/第三方类型时返回 proModal,其余情况进入创建弹窗。
*/
export const resolveDatasetCreateAction = (
type: CreateDatasetType,
isPlus?: boolean
): DatasetCreateAction => {
if (!isPlus && isCommercialDatasetType(type)) {
return 'proModal';
}
return 'create';
};
...@@ -26,8 +26,8 @@ import { ...@@ -26,8 +26,8 @@ import {
} from '@/web/core/dataset/api/collaborator'; } from '@/web/core/dataset/api/collaborator';
import { useSystem } from '@fastgpt/web/hooks/useSystem'; import { useSystem } from '@fastgpt/web/hooks/useSystem';
import { type CreateDatasetType } from '@/pageComponents/dataset/list/CreateModal'; import { type CreateDatasetType } from '@/pageComponents/dataset/list/CreateModal';
import { resolveDatasetCreateAction } from '@/pageComponents/dataset/list/commercialDatasetTypes';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants'; import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { useToast } from '@fastgpt/web/hooks/useToast';
import MyBox from '@fastgpt/web/components/common/MyBox'; import MyBox from '@fastgpt/web/components/common/MyBox';
import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useSystemStore } from '@/web/common/system/useSystemStore';
import { import {
...@@ -36,6 +36,7 @@ import { ...@@ -36,6 +36,7 @@ import {
normalizeParentId normalizeParentId
} from '@fastgpt/global/common/parentFolder/depth'; } from '@fastgpt/global/common/parentFolder/depth';
import { ReadRoleVal } from '@fastgpt/global/support/permission/constant'; import { ReadRoleVal } from '@fastgpt/global/support/permission/constant';
import ProModal from '@/components/ProTip/ProModal';
const EditFolderModal = dynamic( const EditFolderModal = dynamic(
() => import('@fastgpt/web/components/common/MyModal/EditFolderModal') () => import('@fastgpt/web/components/common/MyModal/EditFolderModal')
...@@ -67,22 +68,20 @@ const Dataset = () => { ...@@ -67,22 +68,20 @@ const Dataset = () => {
const { feConfigs } = useSystemStore(); const { feConfigs } = useSystemStore();
const maxFolderDepth = feConfigs?.limit?.maxFolderDepth ?? DEFAULT_MAX_FOLDER_DEPTH; const maxFolderDepth = feConfigs?.limit?.maxFolderDepth ?? DEFAULT_MAX_FOLDER_DEPTH;
const canCreateFolder = canCreateSubFolder(parentId, paths, maxFolderDepth); const canCreateFolder = canCreateSubFolder(parentId, paths, maxFolderDepth);
const folderDepthLimitTip = t('common:folder_depth_limit_tip');
const { toast } = useToast();
const [editFolderData, setEditFolderData] = useState<EditFolderFormType>(); const [editFolderData, setEditFolderData] = useState<EditFolderFormType>();
const [createDatasetType, setCreateDatasetType] = useState<CreateDatasetType>(); const [createDatasetType, setCreateDatasetType] = useState<CreateDatasetType>();
const [proModalOpen, setProModalOpen] = useState(false);
const onSelectDatasetType = useCallback( const onSelectDatasetType = useCallback(
(e: CreateDatasetType) => { (type: CreateDatasetType) => {
if (!feConfigs?.isPlus && [DatasetTypeEnum.websiteDataset].includes(e)) { if (resolveDatasetCreateAction(type, feConfigs?.isPlus) === 'proModal') {
return toast({ setProModalOpen(true);
status: 'warning', return;
title: t('common:commercial_function_tip')
});
} }
setCreateDatasetType(e); setCreateDatasetType(type);
}, },
[t, toast, feConfigs] [feConfigs?.isPlus]
); );
const RenderSearchInput = useMemo( const RenderSearchInput = useMemo(
...@@ -227,7 +226,7 @@ const Dataset = () => { ...@@ -227,7 +226,7 @@ const Dataset = () => {
icon: FolderIcon, icon: FolderIcon,
label: t('common:Folder'), label: t('common:Folder'),
disabled: !canCreateFolder, disabled: !canCreateFolder,
disabledTip: folderDepthLimitTip, disabledTip: t('common:folder_depth_limit_tip'),
onClick: () => setEditFolderData({}) onClick: () => setEditFolderData({})
} }
] ]
...@@ -333,6 +332,9 @@ const Dataset = () => { ...@@ -333,6 +332,9 @@ const Dataset = () => {
parentId={parentId || undefined} parentId={parentId || undefined}
/> />
)} )}
{!feConfigs?.isPlus && (
<ProModal isOpen={proModalOpen} onClose={() => setProModalOpen(false)} />
)}
</MyBox> </MyBox>
); );
}; };
......
import { describe, expect, it } from 'vitest';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import {
commercialDatasetTypes,
isCommercialDatasetType,
resolveDatasetCreateAction
} from '@/pageComponents/dataset/list/commercialDatasetTypes';
import type { CreateDatasetType } from '@/pageComponents/dataset/list/CreateModal';
const expectedCommercialTypes: CreateDatasetType[] = [
DatasetTypeEnum.websiteDataset,
DatasetTypeEnum.apiDataset,
DatasetTypeEnum.feishu,
DatasetTypeEnum.yuque,
DatasetTypeEnum.dingtalk
];
describe('commercialDatasetTypes', () => {
it('should include all commercial-only dataset create types', () => {
expect([...commercialDatasetTypes]).toEqual(expectedCommercialTypes);
});
});
describe('isCommercialDatasetType', () => {
it.each(expectedCommercialTypes)('should mark %s as commercial-only', (type) => {
expect(isCommercialDatasetType(type)).toBe(true);
});
it('should not mark normal dataset as commercial-only', () => {
expect(isCommercialDatasetType(DatasetTypeEnum.dataset)).toBe(false);
});
});
describe('resolveDatasetCreateAction', () => {
it.each(expectedCommercialTypes)(
'should open ProModal for %s when team is not commercial edition',
(type) => {
expect(resolveDatasetCreateAction(type, false)).toBe('proModal');
}
);
it.each(expectedCommercialTypes)(
'should treat missing commercial edition flag as community edition for %s',
(type) => {
expect(resolveDatasetCreateAction(type, undefined)).toBe('proModal');
}
);
it.each(expectedCommercialTypes)(
'should allow creating %s when team is commercial edition',
(type) => {
expect(resolveDatasetCreateAction(type, true)).toBe('create');
}
);
it('should always allow creating normal dataset', () => {
expect(resolveDatasetCreateAction(DatasetTypeEnum.dataset, false)).toBe('create');
expect(resolveDatasetCreateAction(DatasetTypeEnum.dataset, true)).toBe('create');
expect(resolveDatasetCreateAction(DatasetTypeEnum.dataset, undefined)).toBe('create');
});
});
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