mirror of https://github.com/langgenius/dify.git
Merge remote-tracking branch 'origin/feat/trigger' into feat/trigger
This commit is contained in:
commit
35d914e755
|
|
@ -1,4 +1,5 @@
|
|||
import type { Dayjs } from 'dayjs'
|
||||
import type { Placement } from '@floating-ui/react'
|
||||
|
||||
export enum ViewType {
|
||||
date = 'date',
|
||||
|
|
@ -65,6 +66,10 @@ export type TimePickerProps = {
|
|||
title?: string
|
||||
minuteFilter?: (minutes: string[]) => string[]
|
||||
popupClassName?: string
|
||||
notClearable?: boolean
|
||||
triggerFullWidth?: boolean
|
||||
showTimezone?: boolean
|
||||
placement?: Placement
|
||||
}
|
||||
|
||||
export type TimePickerFooterProps = {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ export const ALL_PLANS: Record<BasicPlan, PlanInfo> = {
|
|||
apiRateLimit: 5000,
|
||||
documentProcessingPriority: Priority.standard,
|
||||
messageRequest: 200,
|
||||
triggerEvents: 3000,
|
||||
annotatedResponse: 10,
|
||||
logHistory: 30,
|
||||
},
|
||||
|
|
@ -43,6 +44,7 @@ export const ALL_PLANS: Record<BasicPlan, PlanInfo> = {
|
|||
apiRateLimit: NUM_INFINITE,
|
||||
documentProcessingPriority: Priority.priority,
|
||||
messageRequest: 5000,
|
||||
triggerEvents: 20000,
|
||||
annotatedResponse: 2000,
|
||||
logHistory: NUM_INFINITE,
|
||||
},
|
||||
|
|
@ -60,6 +62,7 @@ export const ALL_PLANS: Record<BasicPlan, PlanInfo> = {
|
|||
apiRateLimit: NUM_INFINITE,
|
||||
documentProcessingPriority: Priority.topPriority,
|
||||
messageRequest: 10000,
|
||||
triggerEvents: NUM_INFINITE,
|
||||
annotatedResponse: 5000,
|
||||
logHistory: NUM_INFINITE,
|
||||
},
|
||||
|
|
@ -74,6 +77,8 @@ export const defaultPlan = {
|
|||
teamMembers: 1,
|
||||
annotatedResponse: 1,
|
||||
documentsUploadQuota: 0,
|
||||
apiRateLimit: 0,
|
||||
triggerEvents: 0,
|
||||
},
|
||||
total: {
|
||||
documents: 50,
|
||||
|
|
@ -82,5 +87,7 @@ export const defaultPlan = {
|
|||
teamMembers: 1,
|
||||
annotatedResponse: 10,
|
||||
documentsUploadQuota: 0,
|
||||
apiRateLimit: ALL_PLANS.sandbox.apiRateLimit,
|
||||
triggerEvents: ALL_PLANS.sandbox.triggerEvents,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ import { useRouter } from 'next/navigation'
|
|||
import {
|
||||
RiBook2Line,
|
||||
RiFileEditLine,
|
||||
RiFlashlightLine,
|
||||
RiGraduationCapLine,
|
||||
RiGroupLine,
|
||||
RiSpeedLine,
|
||||
} from '@remixicon/react'
|
||||
import { Plan, SelfHostedPlan } from '../type'
|
||||
import VectorSpaceInfo from '../usage-info/vector-space-info'
|
||||
|
|
@ -43,6 +45,8 @@ const PlanComp: FC<Props> = ({
|
|||
usage,
|
||||
total,
|
||||
} = plan
|
||||
const perMonthUnit = ` ${t('billing.usagePage.perMonth')}`
|
||||
const triggerEventUnit = plan.type === Plan.sandbox ? undefined : perMonthUnit
|
||||
|
||||
const [showModal, setShowModal] = React.useState(false)
|
||||
const { mutateAsync } = useEducationVerify()
|
||||
|
|
@ -119,6 +123,20 @@ const PlanComp: FC<Props> = ({
|
|||
usage={usage.annotatedResponse}
|
||||
total={total.annotatedResponse}
|
||||
/>
|
||||
<UsageInfo
|
||||
Icon={RiFlashlightLine}
|
||||
name={t('billing.usagePage.triggerEvents')}
|
||||
usage={usage.triggerEvents}
|
||||
total={total.triggerEvents}
|
||||
unit={triggerEventUnit}
|
||||
/>
|
||||
<UsageInfo
|
||||
Icon={RiSpeedLine}
|
||||
name={t('billing.plansCommon.apiRateLimit')}
|
||||
usage={usage.apiRateLimit}
|
||||
total={total.apiRateLimit}
|
||||
unit={perMonthUnit}
|
||||
/>
|
||||
|
||||
</div>
|
||||
<VerifyStateModal
|
||||
|
|
|
|||
|
|
@ -56,6 +56,31 @@ const List = ({
|
|||
<Item
|
||||
label={[t(`billing.plansCommon.priority.${planInfo.documentProcessingPriority}`), t('billing.plansCommon.documentProcessingPriority')].join('')}
|
||||
/>
|
||||
<Item
|
||||
label={
|
||||
planInfo.triggerEvents === NUM_INFINITE
|
||||
? t('billing.plansCommon.triggerEvents.unlimited')
|
||||
: plan === Plan.sandbox
|
||||
? t('billing.plansCommon.triggerEvents.sandbox', { count: planInfo.triggerEvents })
|
||||
: t('billing.plansCommon.triggerEvents.professional', { count: planInfo.triggerEvents })
|
||||
}
|
||||
/>
|
||||
<Item
|
||||
label={
|
||||
plan === Plan.sandbox
|
||||
? t('billing.plansCommon.workflowExecution.standard')
|
||||
: plan === Plan.professional
|
||||
? t('billing.plansCommon.workflowExecution.faster')
|
||||
: t('billing.plansCommon.workflowExecution.priority')
|
||||
}
|
||||
/>
|
||||
<Item
|
||||
label={
|
||||
plan === Plan.sandbox
|
||||
? t('billing.plansCommon.startNodes.limited', { count: 2 })
|
||||
: t('billing.plansCommon.startNodes.unlimited')
|
||||
}
|
||||
/>
|
||||
<Divider bgStyle='gradient' />
|
||||
<Item
|
||||
label={t('billing.plansCommon.annotatedResponse.title', { count: planInfo.annotatedResponse })}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ export type PlanInfo = {
|
|||
documentProcessingPriority: Priority
|
||||
logHistory: number
|
||||
messageRequest: number
|
||||
triggerEvents: number
|
||||
annotatedResponse: number
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +53,7 @@ export type SelfHostedPlanInfo = {
|
|||
annotatedResponse: number
|
||||
}
|
||||
|
||||
export type UsagePlanInfo = Pick<PlanInfo, 'buildApps' | 'teamMembers' | 'annotatedResponse' | 'documentsUploadQuota'> & { vectorSpace: number }
|
||||
export type UsagePlanInfo = Pick<PlanInfo, 'buildApps' | 'teamMembers' | 'annotatedResponse' | 'documentsUploadQuota' | 'apiRateLimit' | 'triggerEvents'> & { vectorSpace: number }
|
||||
|
||||
export enum DocumentProcessingPriority {
|
||||
standard = 'standard',
|
||||
|
|
@ -87,6 +88,14 @@ export type CurrentPlanInfoBackend = {
|
|||
size: number
|
||||
limit: number // total. 0 means unlimited
|
||||
}
|
||||
api_rate_limit?: {
|
||||
size: number
|
||||
limit: number // total. 0 means unlimited
|
||||
}
|
||||
trigger_events?: {
|
||||
size: number
|
||||
limit: number // total. 0 means unlimited
|
||||
}
|
||||
docs_processing: DocumentProcessingPriority
|
||||
can_replace_logo: boolean
|
||||
model_load_balancing_enabled: boolean
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ type Props = {
|
|||
usage: number
|
||||
total: number
|
||||
unit?: string
|
||||
unitPosition?: 'inline' | 'suffix'
|
||||
}
|
||||
|
||||
const LOW = 50
|
||||
|
|
@ -27,7 +28,8 @@ const UsageInfo: FC<Props> = ({
|
|||
tooltip,
|
||||
usage,
|
||||
total,
|
||||
unit = '',
|
||||
unit,
|
||||
unitPosition = 'suffix',
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
|
|
@ -41,6 +43,12 @@ const UsageInfo: FC<Props> = ({
|
|||
|
||||
return 'bg-components-progress-error-progress'
|
||||
})()
|
||||
const isUnlimited = total === NUM_INFINITE
|
||||
let totalDisplay: string | number = isUnlimited ? t('billing.plansCommon.unlimited') : total
|
||||
if (!isUnlimited && unit && unitPosition === 'inline')
|
||||
totalDisplay = `${total}${unit}`
|
||||
const showUnit = !!unit && !isUnlimited && unitPosition === 'suffix'
|
||||
|
||||
return (
|
||||
<div className={cn('flex flex-col gap-2 rounded-xl bg-components-panel-bg p-4', className)}>
|
||||
<Icon className='h-4 w-4 text-text-tertiary' />
|
||||
|
|
@ -56,10 +64,17 @@ const UsageInfo: FC<Props> = ({
|
|||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className='system-md-semibold flex items-center gap-1 text-text-primary'>
|
||||
{usage}
|
||||
<div className='system-md-regular text-text-quaternary'>/</div>
|
||||
<div>{total === NUM_INFINITE ? t('billing.plansCommon.unlimited') : `${total}${unit}`}</div>
|
||||
<div className='system-md-semibold flex items-center gap-1 text-text-primary'>
|
||||
<div className='flex items-center gap-1'>
|
||||
{usage}
|
||||
<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>
|
||||
)}
|
||||
</div>
|
||||
<ProgressBar
|
||||
percent={percent}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ const VectorSpaceInfo: FC<Props> = ({
|
|||
usage={usage.vectorSpace}
|
||||
total={total.vectorSpace}
|
||||
unit='MB'
|
||||
unitPosition='inline'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { CurrentPlanInfoBackend } from '../type'
|
||||
import { NUM_INFINITE } from '@/app/components/billing/config'
|
||||
import { ALL_PLANS, NUM_INFINITE } from '@/app/components/billing/config'
|
||||
|
||||
const parseLimit = (limit: number) => {
|
||||
if (limit === 0)
|
||||
|
|
@ -9,14 +9,23 @@ const parseLimit = (limit: number) => {
|
|||
}
|
||||
|
||||
export const parseCurrentPlan = (data: CurrentPlanInfoBackend) => {
|
||||
const planType = data.billing.subscription.plan
|
||||
const planPreset = ALL_PLANS[planType]
|
||||
const resolveLimit = (limit?: number, fallback?: number) => {
|
||||
const value = limit ?? fallback ?? 0
|
||||
return parseLimit(value)
|
||||
}
|
||||
|
||||
return {
|
||||
type: data.billing.subscription.plan,
|
||||
type: planType,
|
||||
usage: {
|
||||
vectorSpace: data.vector_space.size,
|
||||
buildApps: data.apps?.size || 0,
|
||||
teamMembers: data.members.size,
|
||||
annotatedResponse: data.annotation_quota_limit.size,
|
||||
documentsUploadQuota: data.documents_upload_quota.size,
|
||||
apiRateLimit: data.api_rate_limit?.size ?? 0,
|
||||
triggerEvents: data.trigger_events?.size ?? 0,
|
||||
},
|
||||
total: {
|
||||
vectorSpace: parseLimit(data.vector_space.limit),
|
||||
|
|
@ -24,6 +33,8 @@ export const parseCurrentPlan = (data: CurrentPlanInfoBackend) => {
|
|||
teamMembers: parseLimit(data.members.limit),
|
||||
annotatedResponse: parseLimit(data.annotation_quota_limit.limit),
|
||||
documentsUploadQuota: parseLimit(data.documents_upload_quota.limit),
|
||||
apiRateLimit: resolveLimit(data.api_rate_limit?.limit, planPreset?.apiRateLimit ?? NUM_INFINITE),
|
||||
triggerEvents: resolveLimit(data.trigger_events?.limit, planPreset?.triggerEvents),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@ export const EDUCATION_VERIFY_URL_SEARCHPARAMS_ACTION = 'getEducationVerify'
|
|||
export const EDUCATION_VERIFYING_LOCALSTORAGE_ITEM = 'educationVerifying'
|
||||
export const EDUCATION_PRICING_SHOW_ACTION = 'educationPricing'
|
||||
export const EDUCATION_RE_VERIFY_ACTION = 'educationReVerify'
|
||||
export const SHOW_PRICING_MODAL_ACTION = 'showPricing'
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import type { Dispatch, SetStateAction } from 'react'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { createContext, useContext, useContextSelector } from 'use-context-selector'
|
||||
import { useRouter, useSearchParams } from 'next/navigation'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import type {
|
||||
ConfigurationMethodEnum,
|
||||
Credential,
|
||||
|
|
@ -13,6 +13,7 @@ import type {
|
|||
} from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import {
|
||||
EDUCATION_VERIFYING_LOCALSTORAGE_ITEM,
|
||||
SHOW_PRICING_MODAL_ACTION,
|
||||
} from '@/app/education-apply/constants'
|
||||
import type { ModerationConfig, PromptVariable } from '@/models/debug'
|
||||
import type {
|
||||
|
|
@ -151,8 +152,9 @@ export const ModalContextProvider = ({
|
|||
const [showEducationExpireNoticeModal, setShowEducationExpireNoticeModal] = useState<ModalState<ExpireNoticeModalPayloadProps> | null>(null)
|
||||
|
||||
const searchParams = useSearchParams()
|
||||
const router = useRouter()
|
||||
const [showPricingModal, setShowPricingModal] = useState(searchParams.get('show-pricing') === '1')
|
||||
const [showPricingModal, setShowPricingModal] = useState(
|
||||
searchParams.get('action') === SHOW_PRICING_MODAL_ACTION,
|
||||
)
|
||||
const [showAnnotationFullModal, setShowAnnotationFullModal] = useState(false)
|
||||
const handleCancelAccountSettingModal = () => {
|
||||
const educationVerifying = localStorage.getItem(EDUCATION_VERIFYING_LOCALSTORAGE_ITEM)
|
||||
|
|
@ -308,8 +310,6 @@ export const ModalContextProvider = ({
|
|||
{
|
||||
!!showPricingModal && (
|
||||
<Pricing onCancel={() => {
|
||||
if (searchParams.get('show-pricing') === '1')
|
||||
router.push(location.pathname, { forceOptimisticNavigation: true } as any)
|
||||
removeSpecificQueryParam('action')
|
||||
setShowPricingModal(false)
|
||||
}} />
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ 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 { Plan, type UsagePlanInfo } from '@/app/components/billing/type'
|
||||
import type { Plan } 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'
|
||||
import { defaultPlan } from '@/app/components/billing/config'
|
||||
|
|
@ -70,23 +71,7 @@ const ProviderContext = createContext<ProviderContextState>({
|
|||
textGenerationModelList: [],
|
||||
supportRetrievalMethods: [],
|
||||
isAPIKeySet: true,
|
||||
plan: {
|
||||
type: Plan.sandbox,
|
||||
usage: {
|
||||
vectorSpace: 32,
|
||||
buildApps: 12,
|
||||
teamMembers: 1,
|
||||
annotatedResponse: 1,
|
||||
documentsUploadQuota: 50,
|
||||
},
|
||||
total: {
|
||||
vectorSpace: 200,
|
||||
buildApps: 50,
|
||||
teamMembers: 1,
|
||||
annotatedResponse: 10,
|
||||
documentsUploadQuota: 500,
|
||||
},
|
||||
},
|
||||
plan: defaultPlan,
|
||||
isFetchedPlan: false,
|
||||
enableBilling: false,
|
||||
onPlanInfoChanged: noop,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ const translation = {
|
|||
documentsUploadQuota: 'Documents Upload Quota',
|
||||
vectorSpace: 'Knowledge Data Storage',
|
||||
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',
|
||||
},
|
||||
teamMembers: 'Team Members',
|
||||
upgradeBtn: {
|
||||
|
|
@ -72,6 +74,20 @@ const translation = {
|
|||
'priority': 'Priority',
|
||||
'top-priority': 'Top Priority',
|
||||
},
|
||||
triggerEvents: {
|
||||
sandbox: '{{count,number}} Trigger Events',
|
||||
professional: '{{count,number}} Trigger Events/month',
|
||||
unlimited: 'Unlimited Trigger Events',
|
||||
},
|
||||
workflowExecution: {
|
||||
standard: 'Standard Workflow Execution',
|
||||
faster: 'Faster Workflow Execution',
|
||||
priority: 'Priority Workflow Execution',
|
||||
},
|
||||
startNodes: {
|
||||
limited: 'Up to {{count}} Start Nodes per Workflow',
|
||||
unlimited: 'Unlimited Start Nodes per Workflow',
|
||||
},
|
||||
logsHistory: '{{days}} Log history',
|
||||
customTools: 'Custom Tools',
|
||||
unavailable: 'Unavailable',
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ const translation = {
|
|||
documentsUploadQuota: 'ドキュメント・アップロード・クォータ',
|
||||
vectorSpace: 'ナレッジベースのデータストレージ',
|
||||
vectorSpaceTooltip: '高品質インデックスモードのドキュメントは、ナレッジベースのデータストレージのリソースを消費します。ナレッジベースのデータストレージの上限に達すると、新しいドキュメントはアップロードされません。',
|
||||
triggerEvents: 'トリガーイベント',
|
||||
perMonth: '月あたり',
|
||||
},
|
||||
upgradeBtn: {
|
||||
plain: 'プランをアップグレード',
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ const translation = {
|
|||
documentsUploadQuota: '文档上传配额',
|
||||
vectorSpace: '知识库数据存储空间',
|
||||
vectorSpaceTooltip: '采用高质量索引模式的文档会消耗知识数据存储资源。当知识数据存储达到限制时,将不会上传新文档。',
|
||||
triggerEvents: '触发事件',
|
||||
perMonth: '每月',
|
||||
},
|
||||
upgradeBtn: {
|
||||
plain: '查看套餐',
|
||||
|
|
@ -71,6 +73,20 @@ const translation = {
|
|||
'priority': '优先',
|
||||
'top-priority': '最高优先级',
|
||||
},
|
||||
triggerEvents: {
|
||||
sandbox: '{{count,number}} 触发事件',
|
||||
professional: '{{count,number}} 触发事件/月',
|
||||
unlimited: '无限制触发事件',
|
||||
},
|
||||
workflowExecution: {
|
||||
standard: '标准工作流执行',
|
||||
faster: '更快的工作流执行',
|
||||
priority: '优先工作流执行',
|
||||
},
|
||||
startNodes: {
|
||||
limited: '每个工作流最多 {{count}} 个起始节点',
|
||||
unlimited: '每个工作流无限制起始节点',
|
||||
},
|
||||
logsHistory: '{{days}}日志历史',
|
||||
customTools: '自定义工具',
|
||||
unavailable: '不可用',
|
||||
|
|
|
|||
Loading…
Reference in New Issue