mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-07-22 00:44:26 +08:00
fix: show build app limit in app creation modal (#16940)
This commit is contained in:
parent
c7fcfc863d
commit
9feafb6dbd
@ -214,6 +214,7 @@ function CreateApp({ onClose, onSuccess, onCreateFromTemplate }: CreateAppProps)
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{isAppsFull && <AppsFull className='mt-4' loc='app-create' />}
|
||||||
<div className='flex items-center justify-between pb-10 pt-5'>
|
<div className='flex items-center justify-between pb-10 pt-5'>
|
||||||
<div className='system-xs-regular flex cursor-pointer items-center gap-1 text-text-tertiary' onClick={onCreateFromTemplate}>
|
<div className='system-xs-regular flex cursor-pointer items-center gap-1 text-text-tertiary' onClick={onCreateFromTemplate}>
|
||||||
<span>{t('app.newApp.noIdeaTip')}</span>
|
<span>{t('app.newApp.noIdeaTip')}</span>
|
||||||
@ -251,13 +252,6 @@ function CreateApp({ onClose, onSuccess, onCreateFromTemplate }: CreateAppProps)
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{
|
|
||||||
isAppsFull && (
|
|
||||||
<div className='px-8 py-2'>
|
|
||||||
<AppsFull loc='app-create' />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
type CreateAppDialogProps = CreateAppProps & {
|
type CreateAppDialogProps = CreateAppProps & {
|
||||||
|
@ -96,7 +96,7 @@ const DuplicateAppModal = ({
|
|||||||
className='h-10'
|
className='h-10'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{isAppsFull && <AppsFull loc='app-duplicate-create' />}
|
{isAppsFull && <AppsFull className='mt-4' loc='app-duplicate-create' />}
|
||||||
</div>
|
</div>
|
||||||
<div className='flex flex-row-reverse'>
|
<div className='flex flex-row-reverse'>
|
||||||
<Button disabled={isAppsFull} className='ml-2 w-24' variant='primary' onClick={submit}>{t('app.duplicate')}</Button>
|
<Button disabled={isAppsFull} className='ml-2 w-24' variant='primary' onClick={submit}>{t('app.duplicate')}</Button>
|
||||||
|
@ -3,35 +3,82 @@ import type { FC } from 'react'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import UpgradeBtn from '../upgrade-btn'
|
import UpgradeBtn from '../upgrade-btn'
|
||||||
import AppsInfo from '../usage-info/apps-info'
|
import ProgressBar from '@/app/components/billing/progress-bar'
|
||||||
|
import Button from '@/app/components/base/button'
|
||||||
|
import { mailToSupport } from '@/app/components/header/utils/util'
|
||||||
|
import { useProviderContext } from '@/context/provider-context'
|
||||||
|
import { useAppContext } from '@/context/app-context'
|
||||||
|
import { Plan } from '@/app/components/billing/type'
|
||||||
import s from './style.module.css'
|
import s from './style.module.css'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import GridMask from '@/app/components/base/grid-mask'
|
|
||||||
|
|
||||||
const AppsFull: FC<{ loc: string; className?: string }> = ({
|
const LOW = 50
|
||||||
|
const MIDDLE = 80
|
||||||
|
|
||||||
|
const AppsFull: FC<{ loc: string; className?: string; }> = ({
|
||||||
loc,
|
loc,
|
||||||
className,
|
className,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const { plan } = useProviderContext()
|
||||||
|
const { userProfile, langeniusVersionInfo } = useAppContext()
|
||||||
|
const isTeam = plan.type === Plan.team
|
||||||
|
const usage = plan.usage.buildApps
|
||||||
|
const total = plan.total.buildApps
|
||||||
|
const percent = usage / total * 100
|
||||||
|
const color = (() => {
|
||||||
|
if (percent < LOW)
|
||||||
|
return 'bg-components-progress-bar-progress-solid'
|
||||||
|
|
||||||
|
if (percent < MIDDLE)
|
||||||
|
return 'bg-components-progress-warning-progress'
|
||||||
|
|
||||||
|
return 'bg-components-progress-error-progress'
|
||||||
|
})()
|
||||||
return (
|
return (
|
||||||
<GridMask wrapperClassName='rounded-lg' canvasClassName='rounded-lg' gradientClassName='rounded-lg'>
|
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
'mt-6 flex cursor-pointer flex-col rounded-lg border-2 border-solid border-transparent px-3.5 py-4 shadow-md transition-all duration-200 ease-in-out',
|
'flex flex-col gap-3 rounded-xl border-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg p-4 shadow-xs backdrop-blur-sm',
|
||||||
className,
|
className,
|
||||||
)}>
|
)}>
|
||||||
<div className='flex items-center justify-between'>
|
<div className='flex justify-between'>
|
||||||
<div className={cn(s.textGradient, 'text-base font-semibold leading-[24px]')}>
|
{!isTeam && (
|
||||||
<div>{t('billing.apps.fullTipLine1')}</div>
|
<div>
|
||||||
<div>{t('billing.apps.fullTipLine2')}</div>
|
<div className={cn('title-xl-semi-bold mb-1', s.textGradient)}>
|
||||||
|
{t('billing.apps.fullTip1')}
|
||||||
</div>
|
</div>
|
||||||
<div className='flex'>
|
<div className='system-xs-regular text-text-tertiary'>{t('billing.apps.fullTip1des')}</div>
|
||||||
<UpgradeBtn loc={loc} />
|
</div>
|
||||||
|
)}
|
||||||
|
{isTeam && (
|
||||||
|
<div>
|
||||||
|
<div className={cn('title-xl-semi-bold mb-1', s.textGradient)}>
|
||||||
|
{t('billing.apps.fullTip2')}
|
||||||
|
</div>
|
||||||
|
<div className='system-xs-regular text-text-tertiary'>{t('billing.apps.fullTip2des')}</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{(plan.type === Plan.sandbox || plan.type === Plan.professional) && (
|
||||||
|
<UpgradeBtn isShort loc={loc} />
|
||||||
|
)}
|
||||||
|
{plan.type !== Plan.sandbox && plan.type !== Plan.professional && (
|
||||||
|
<Button variant='secondary-accent'>
|
||||||
|
<a target='_blank' rel='noopener noreferrer' href={mailToSupport(userProfile.email, plan.type, langeniusVersionInfo.current_version)}>
|
||||||
|
{t('billing.apps.contactUs')}
|
||||||
|
</a>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-col gap-2'>
|
||||||
|
<div className='system-xs-medium flex items-center justify-between text-text-secondary'>
|
||||||
|
<div>{t('billing.usagePage.buildApps')}</div>
|
||||||
|
<div>{usage}/{total}</div>
|
||||||
|
</div>
|
||||||
|
<ProgressBar
|
||||||
|
percent={percent}
|
||||||
|
color={color}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<AppsInfo className='mt-4' />
|
|
||||||
</div>
|
|
||||||
</GridMask>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
export default React.memo(AppsFull)
|
export default React.memo(AppsFull)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.textGradient {
|
.textGradient {
|
||||||
background: linear-gradient(92deg, #2250F2 -29.55%, #0EBCF3 75.22%);
|
background: linear-gradient(92deg, #0EBCF3 -29.55%, #2250F2 75.22%);
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
background-clip: text;
|
background-clip: text;
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
'use client'
|
|
||||||
import type { FC } from 'react'
|
|
||||||
import React from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import UpgradeBtn from '../upgrade-btn'
|
|
||||||
import s from './style.module.css'
|
|
||||||
import cn from '@/utils/classnames'
|
|
||||||
import GridMask from '@/app/components/base/grid-mask'
|
|
||||||
|
|
||||||
const AppsFull: FC = () => {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<GridMask wrapperClassName='rounded-lg' canvasClassName='rounded-lg' gradientClassName='rounded-lg'>
|
|
||||||
<div className='col-span-1 flex min-h-[160px] cursor-pointer flex-col rounded-lg border-2 border-solid border-transparent px-3.5 pt-3.5 shadow-xs transition-all duration-200 ease-in-out hover:shadow-lg'>
|
|
||||||
<div className={cn(s.textGradient, 'text-base font-semibold leading-[24px]')}>
|
|
||||||
<div>{t('billing.apps.fullTipLine1')}</div>
|
|
||||||
<div>{t('billing.apps.fullTipLine2')}</div>
|
|
||||||
</div>
|
|
||||||
<div className='mt-8 flex'>
|
|
||||||
<UpgradeBtn loc='app-create' />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</GridMask>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default React.memo(AppsFull)
|
|
@ -1,7 +0,0 @@
|
|||||||
.textGradient {
|
|
||||||
background: linear-gradient(92deg, #2250F2 -29.55%, #0EBCF3 75.22%);
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
background-clip: text;
|
|
||||||
text-fill-color: transparent;
|
|
||||||
}
|
|
@ -142,7 +142,7 @@ const CreateAppModal = ({
|
|||||||
<p className='body-xs-regular text-text-tertiary'>{t('app.answerIcon.descriptionInExplore')}</p>
|
<p className='body-xs-regular text-text-tertiary'>{t('app.answerIcon.descriptionInExplore')}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!isEditModal && isAppsFull && <AppsFull loc='app-explore-create' />}
|
{!isEditModal && isAppsFull && <AppsFull className='mt-4' loc='app-explore-create' />}
|
||||||
</div>
|
</div>
|
||||||
<div className='flex flex-row-reverse'>
|
<div className='flex flex-row-reverse'>
|
||||||
<Button disabled={!isEditModal && isAppsFull} className='ml-2 w-24' variant='primary' onClick={submit}>{!isEditModal ? t('common.operation.create') : t('common.operation.save')}</Button>
|
<Button disabled={!isEditModal && isAppsFull} className='ml-2 w-24' variant='primary' onClick={submit}>{!isEditModal ? t('common.operation.create') : t('common.operation.save')}</Button>
|
||||||
|
@ -170,8 +170,11 @@ const translation = {
|
|||||||
fullSolution: 'Upgrade your plan to get more space.',
|
fullSolution: 'Upgrade your plan to get more space.',
|
||||||
},
|
},
|
||||||
apps: {
|
apps: {
|
||||||
fullTipLine1: 'Upgrade your plan to',
|
fullTip1: 'Upgrade to create more apps',
|
||||||
fullTipLine2: 'build more apps.',
|
fullTip1des: 'You\'ve reached the limit of build apps on this plan',
|
||||||
|
fullTip2: 'Plan limit reached',
|
||||||
|
fullTip2des: 'It is recommended to clean up inactive applications to free up usage, or contact us.',
|
||||||
|
contactUs: 'Contact us',
|
||||||
},
|
},
|
||||||
annotatedResponse: {
|
annotatedResponse: {
|
||||||
fullTipLine1: 'Upgrade your plan to',
|
fullTipLine1: 'Upgrade your plan to',
|
||||||
|
@ -169,8 +169,11 @@ const translation = {
|
|||||||
fullSolution: '升级您的套餐以获得更多空间。',
|
fullSolution: '升级您的套餐以获得更多空间。',
|
||||||
},
|
},
|
||||||
apps: {
|
apps: {
|
||||||
fullTipLine1: '升级您的套餐以',
|
fullTip1: '升级以创建更多应用',
|
||||||
fullTipLine2: '构建更多的程序。',
|
fullTip1des: '您已达到此计划上构建应用的限制',
|
||||||
|
fullTip2: '计划限制已达到',
|
||||||
|
fullTip2des: '推荐您清理不活跃的应用或者联系我们',
|
||||||
|
contactUs: '联系我们',
|
||||||
},
|
},
|
||||||
annotatedResponse: {
|
annotatedResponse: {
|
||||||
fullTipLine1: '升级您的套餐以',
|
fullTipLine1: '升级您的套餐以',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user