mirror of
https://github.com/langgenius/dify.git
synced 2026-01-06 06:26:00 +00:00
feat: add resets time in billing usage info
This commit is contained in:
@@ -90,4 +90,8 @@ export const defaultPlan = {
|
||||
apiRateLimit: ALL_PLANS.sandbox.apiRateLimit,
|
||||
triggerEvents: ALL_PLANS.sandbox.triggerEvents,
|
||||
},
|
||||
reset: {
|
||||
apiRateLimit: null,
|
||||
triggerEvents: null,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
} from '@remixicon/react'
|
||||
import { Plan, SelfHostedPlan } from '../type'
|
||||
import { NUM_INFINITE } from '../config'
|
||||
import { getDaysUntilEndOfMonth } from '@/utils/time'
|
||||
import VectorSpaceInfo from '../usage-info/vector-space-info'
|
||||
import AppsInfo from '../usage-info/apps-info'
|
||||
import UpgradeBtn from '../upgrade-btn'
|
||||
@@ -44,7 +45,14 @@ const PlanComp: FC<Props> = ({
|
||||
const {
|
||||
usage,
|
||||
total,
|
||||
reset,
|
||||
} = plan
|
||||
const triggerEventsResetInDays = type === Plan.professional && total.triggerEvents !== NUM_INFINITE
|
||||
? reset.triggerEvents ?? undefined
|
||||
: undefined
|
||||
const apiRateLimitResetInDays = type === Plan.sandbox && total.apiRateLimit !== NUM_INFINITE
|
||||
? getDaysUntilEndOfMonth()
|
||||
: undefined
|
||||
|
||||
const [showModal, setShowModal] = React.useState(false)
|
||||
const { mutateAsync } = useEducationVerify()
|
||||
@@ -126,6 +134,7 @@ const PlanComp: FC<Props> = ({
|
||||
usage={usage.triggerEvents}
|
||||
total={total.triggerEvents}
|
||||
tooltip={t('billing.plansCommon.triggerEvents.tooltip') as string}
|
||||
resetInDays={triggerEventsResetInDays}
|
||||
/>
|
||||
<UsageInfo
|
||||
Icon={ApiAggregate}
|
||||
@@ -133,6 +142,7 @@ const PlanComp: FC<Props> = ({
|
||||
usage={usage.apiRateLimit}
|
||||
total={total.apiRateLimit}
|
||||
tooltip={total.apiRateLimit === NUM_INFINITE ? undefined : t('billing.plansCommon.apiRateLimitTooltip') as string}
|
||||
resetInDays={apiRateLimitResetInDays}
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -55,6 +55,11 @@ export type SelfHostedPlanInfo = {
|
||||
|
||||
export type UsagePlanInfo = Pick<PlanInfo, 'buildApps' | 'teamMembers' | 'annotatedResponse' | 'documentsUploadQuota' | 'apiRateLimit' | 'triggerEvents'> & { vectorSpace: number }
|
||||
|
||||
export type UsageResetInfo = {
|
||||
apiRateLimit?: number | null
|
||||
triggerEvents?: number | null
|
||||
}
|
||||
|
||||
export enum DocumentProcessingPriority {
|
||||
standard = 'standard',
|
||||
priority = 'priority',
|
||||
@@ -91,10 +96,12 @@ export type CurrentPlanInfoBackend = {
|
||||
api_rate_limit?: {
|
||||
size: number
|
||||
limit: number // total. 0 means unlimited
|
||||
reset_in_days?: number
|
||||
}
|
||||
trigger_events?: {
|
||||
size: number
|
||||
limit: number // total. 0 means unlimited
|
||||
reset_in_days?: number
|
||||
}
|
||||
docs_processing: DocumentProcessingPriority
|
||||
can_replace_logo: boolean
|
||||
|
||||
@@ -16,6 +16,8 @@ type Props = {
|
||||
total: number
|
||||
unit?: string
|
||||
unitPosition?: 'inline' | 'suffix'
|
||||
resetHint?: string
|
||||
resetInDays?: number
|
||||
}
|
||||
|
||||
const WARNING_THRESHOLD = 80
|
||||
@@ -29,6 +31,8 @@ const UsageInfo: FC<Props> = ({
|
||||
total,
|
||||
unit,
|
||||
unitPosition = 'suffix',
|
||||
resetHint,
|
||||
resetInDays,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
@@ -41,6 +45,18 @@ const UsageInfo: FC<Props> = ({
|
||||
if (!isUnlimited && unit && unitPosition === 'inline')
|
||||
totalDisplay = `${total}${unit}`
|
||||
const showUnit = !!unit && !isUnlimited && unitPosition === 'suffix'
|
||||
const resetText = resetHint ?? (typeof resetInDays === 'number' ? t('billing.usagePage.resetsIn', { count: resetInDays }) : undefined)
|
||||
const rightInfo = resetText
|
||||
? (
|
||||
<div className='system-xs-regular ml-auto flex-1 text-right text-text-tertiary'>
|
||||
{resetText}
|
||||
</div>
|
||||
)
|
||||
: (showUnit && (
|
||||
<div className='system-xs-medium ml-auto text-text-tertiary'>
|
||||
{unit}
|
||||
</div>
|
||||
))
|
||||
|
||||
return (
|
||||
<div className={cn('flex flex-col gap-2 rounded-xl bg-components-panel-bg p-4', className)}>
|
||||
@@ -63,11 +79,7 @@ const UsageInfo: FC<Props> = ({
|
||||
<div className='system-md-regular text-text-quaternary'>/</div>
|
||||
<div>{totalDisplay}</div>
|
||||
</div>
|
||||
{showUnit && (
|
||||
<div className='system-xs-medium ml-auto text-text-tertiary'>
|
||||
{unit}
|
||||
</div>
|
||||
)}
|
||||
{rightInfo}
|
||||
</div>
|
||||
<ProgressBar
|
||||
percent={percent}
|
||||
|
||||
@@ -36,5 +36,9 @@ export const parseCurrentPlan = (data: CurrentPlanInfoBackend) => {
|
||||
apiRateLimit: resolveLimit(data.api_rate_limit?.limit, planPreset?.apiRateLimit ?? NUM_INFINITE),
|
||||
triggerEvents: resolveLimit(data.trigger_events?.limit, planPreset?.triggerEvents),
|
||||
},
|
||||
reset: {
|
||||
apiRateLimit: data.api_rate_limit?.reset_in_days ?? null,
|
||||
triggerEvents: data.trigger_events?.reset_in_days ?? null,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
} from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import type { Model, ModelProvider } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import type { RETRIEVE_METHOD } from '@/types/app'
|
||||
import type { Plan } from '@/app/components/billing/type'
|
||||
import type { Plan, UsageResetInfo } from '@/app/components/billing/type'
|
||||
import type { UsagePlanInfo } from '@/app/components/billing/type'
|
||||
import { fetchCurrentPlanInfo } from '@/service/billing'
|
||||
import { parseCurrentPlan } from '@/app/components/billing/utils'
|
||||
@@ -40,6 +40,7 @@ type ProviderContextState = {
|
||||
type: Plan
|
||||
usage: UsagePlanInfo
|
||||
total: UsagePlanInfo
|
||||
reset: UsageResetInfo
|
||||
}
|
||||
isFetchedPlan: boolean
|
||||
enableBilling: boolean
|
||||
|
||||
@@ -9,6 +9,7 @@ const translation = {
|
||||
vectorSpaceTooltip: 'Documents with the High Quality indexing mode will consume Knowledge Data Storage resources. When Knowledge Data Storage reaches the limit, new documents will not be uploaded.',
|
||||
triggerEvents: 'Trigger Events',
|
||||
perMonth: 'per month',
|
||||
resetsIn: 'Resets in {{count,number}} days',
|
||||
},
|
||||
teamMembers: 'Team Members',
|
||||
upgradeBtn: {
|
||||
|
||||
@@ -9,6 +9,7 @@ const translation = {
|
||||
vectorSpaceTooltip: '高品質インデックスモードのドキュメントは、ナレッジベースのデータストレージのリソースを消費します。ナレッジベースのデータストレージの上限に達すると、新しいドキュメントはアップロードされません。',
|
||||
triggerEvents: 'トリガーイベント数',
|
||||
perMonth: '月あたり',
|
||||
resetsIn: '{{count,number}}日後にリセット',
|
||||
},
|
||||
upgradeBtn: {
|
||||
plain: 'プランをアップグレード',
|
||||
|
||||
@@ -9,6 +9,7 @@ const translation = {
|
||||
vectorSpaceTooltip: '采用高质量索引模式的文档会消耗知识数据存储资源。当知识数据存储达到限制时,将不会上传新文档。',
|
||||
triggerEvents: '触发器事件数',
|
||||
perMonth: '每月',
|
||||
resetsIn: '{{count,number}} 天后重置',
|
||||
},
|
||||
upgradeBtn: {
|
||||
plain: '查看套餐',
|
||||
|
||||
@@ -10,3 +10,10 @@ export const isAfter = (date: ConfigType, compare: ConfigType) => {
|
||||
export const formatTime = ({ date, dateFormat }: { date: ConfigType; dateFormat: string }) => {
|
||||
return dayjs(date).format(dateFormat)
|
||||
}
|
||||
|
||||
export const getDaysUntilEndOfMonth = (date: ConfigType = dayjs()) => {
|
||||
const current = dayjs(date).startOf('day')
|
||||
const endOfMonth = dayjs(date).endOf('month').startOf('day')
|
||||
const diff = endOfMonth.diff(current, 'day')
|
||||
return Math.max(diff, 0)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user