mirror of
https://gitee.com/dify_ai/dify.git
synced 2024-11-30 10:18:13 +08:00
feat: show more usage info in billing page (#4808)
This commit is contained in:
parent
11f173693b
commit
a7fb1ffcd8
@ -0,0 +1,6 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="file-upload">
|
||||
<path id="Icon" d="M20 10.5V6.8C20 5.11984 20 4.27976 19.673 3.63803C19.3854 3.07354 18.9265 2.6146 18.362 2.32698C17.7202 2 16.8802 2 15.2 2H8.8C7.11984 2 6.27976 2 5.63803 2.32698C5.07354 2.6146 4.6146 3.07354 4.32698 3.63803C4 4.27976 4 5.11984 4 6.8V17.2C4 18.8802 4 19.7202 4.32698 20.362C4.6146 20.9265 5.07354 21.3854 5.63803 21.673C6.27976 22 7.11984 22 8.8 22H12M14 11H8M10 15H8M16 7H8" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="Icon_2" d="M15 18L18 15M18 15L21 18M18 15L18 21" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 746 B |
@ -0,0 +1,52 @@
|
||||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "24",
|
||||
"height": "24",
|
||||
"viewBox": "0 0 24 24",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "file-upload"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Icon",
|
||||
"d": "M20 10.5V6.8C20 5.11984 20 4.27976 19.673 3.63803C19.3854 3.07354 18.9265 2.6146 18.362 2.32698C17.7202 2 16.8802 2 15.2 2H8.8C7.11984 2 6.27976 2 5.63803 2.32698C5.07354 2.6146 4.6146 3.07354 4.32698 3.63803C4 4.27976 4 5.11984 4 6.8V17.2C4 18.8802 4 19.7202 4.32698 20.362C4.6146 20.9265 5.07354 21.3854 5.63803 21.673C6.27976 22 7.11984 22 8.8 22H12M14 11H8M10 15H8M16 7H8",
|
||||
"stroke": "currentColor",
|
||||
"stroke-width": "2",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Icon_2",
|
||||
"d": "M15 18L18 15M18 15L21 18M18 15L18 21",
|
||||
"stroke": "currentColor",
|
||||
"stroke-width": "2",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "FileUpload"
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './FileUpload.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
|
||||
props,
|
||||
ref,
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />)
|
||||
|
||||
Icon.displayName = 'FileUpload'
|
||||
|
||||
export default Icon
|
@ -7,4 +7,5 @@ export { default as FileDownload02 } from './FileDownload02'
|
||||
export { default as FilePlus01 } from './FilePlus01'
|
||||
export { default as FilePlus02 } from './FilePlus02'
|
||||
export { default as FileText } from './FileText'
|
||||
export { default as FileUpload } from './FileUpload'
|
||||
export { default as Folder } from './Folder'
|
||||
|
@ -86,11 +86,13 @@ export const defaultPlan = {
|
||||
buildApps: 1,
|
||||
teamMembers: 1,
|
||||
annotatedResponse: 1,
|
||||
documentsUploadQuota: 1,
|
||||
},
|
||||
total: {
|
||||
vectorSpace: 10,
|
||||
buildApps: 10,
|
||||
teamMembers: 1,
|
||||
annotatedResponse: 10,
|
||||
documentsUploadQuota: 50,
|
||||
},
|
||||
}
|
||||
|
@ -7,7 +7,11 @@ import { Plan } from '../type'
|
||||
import VectorSpaceInfo from '../usage-info/vector-space-info'
|
||||
import AppsInfo from '../usage-info/apps-info'
|
||||
import UpgradeBtn from '../upgrade-btn'
|
||||
import { User01 } from '../../base/icons/src/vender/line/users'
|
||||
import { MessageFastPlus } from '../../base/icons/src/vender/line/communication'
|
||||
import { FileUpload } from '../../base/icons/src/vender/line/files'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import UsageInfo from '@/app/components/billing/usage-info'
|
||||
|
||||
const typeStyle = {
|
||||
[Plan.sandbox]: {
|
||||
@ -41,6 +45,11 @@ const PlanComp: FC<Props> = ({
|
||||
type,
|
||||
} = plan
|
||||
|
||||
const {
|
||||
usage,
|
||||
total,
|
||||
} = plan
|
||||
|
||||
const isInHeader = loc === 'header'
|
||||
|
||||
return (
|
||||
@ -76,8 +85,30 @@ const PlanComp: FC<Props> = ({
|
||||
|
||||
{/* Plan detail */}
|
||||
<div className='rounded-xl bg-white px-6 py-3'>
|
||||
<VectorSpaceInfo className='py-3' />
|
||||
|
||||
<UsageInfo
|
||||
className='py-3'
|
||||
Icon={User01}
|
||||
name={t('billing.plansCommon.teamMembers')}
|
||||
usage={usage.teamMembers}
|
||||
total={total.teamMembers}
|
||||
/>
|
||||
<AppsInfo className='py-3' />
|
||||
<VectorSpaceInfo className='py-3' />
|
||||
<UsageInfo
|
||||
className='py-3'
|
||||
Icon={MessageFastPlus}
|
||||
name={t('billing.plansCommon.annotationQuota')}
|
||||
usage={usage.annotatedResponse}
|
||||
total={total.annotatedResponse}
|
||||
/>
|
||||
<UsageInfo
|
||||
className='py-3'
|
||||
Icon={FileUpload}
|
||||
name={t('billing.plansCommon.documentsUploadQuota')}
|
||||
usage={usage.documentsUploadQuota}
|
||||
total={total.documentsUploadQuota}
|
||||
/>
|
||||
{isInHeader && type === Plan.sandbox && (
|
||||
<UpgradeBtn
|
||||
className='flex-shrink-0 my-3'
|
||||
|
@ -28,7 +28,7 @@ export type PlanInfo = {
|
||||
annotatedResponse: number
|
||||
}
|
||||
|
||||
export type UsagePlanInfo = Pick<PlanInfo, 'vectorSpace' | 'buildApps' | 'teamMembers' | 'annotatedResponse'>
|
||||
export type UsagePlanInfo = Pick<PlanInfo, 'vectorSpace' | 'buildApps' | 'teamMembers' | 'annotatedResponse' | 'documentsUploadQuota'>
|
||||
|
||||
export enum DocumentProcessingPriority {
|
||||
standard = 'standard',
|
||||
@ -59,6 +59,10 @@ export type CurrentPlanInfoBackend = {
|
||||
size: number
|
||||
limit: number // total. 0 means unlimited
|
||||
}
|
||||
documents_upload_quota: {
|
||||
size: number
|
||||
limit: number // total. 0 means unlimited
|
||||
}
|
||||
docs_processing: DocumentProcessingPriority
|
||||
can_replace_logo: boolean
|
||||
}
|
||||
|
@ -16,12 +16,14 @@ export const parseCurrentPlan = (data: CurrentPlanInfoBackend) => {
|
||||
buildApps: data.apps?.size || 0,
|
||||
teamMembers: data.members.size,
|
||||
annotatedResponse: data.annotation_quota_limit.size,
|
||||
documentsUploadQuota: data.documents_upload_quota.size,
|
||||
},
|
||||
total: {
|
||||
vectorSpace: parseLimit(data.vector_space.limit),
|
||||
buildApps: parseLimit(data.apps?.limit) || 0,
|
||||
teamMembers: parseLimit(data.members.limit),
|
||||
annotatedResponse: parseLimit(data.annotation_quota_limit.limit),
|
||||
documentsUploadQuota: parseLimit(data.documents_upload_quota.limit),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useCallback, useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { useBoolean, useClickAway } from 'ahooks'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { useSelectedLayoutSegment } from 'next/navigation'
|
||||
import { Bars3Icon } from '@heroicons/react/20/solid'
|
||||
import HeaderBillingBtn from '../billing/header-billing-btn'
|
||||
@ -15,9 +15,9 @@ import GithubStar from './github-star'
|
||||
import { WorkspaceProvider } from '@/context/workspace-context'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import LogoSite from '@/app/components/base/logo/logo-site'
|
||||
import PlanComp from '@/app/components/billing/plan'
|
||||
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { useModalContext } from '@/context/modal-context'
|
||||
|
||||
const navClassName = `
|
||||
flex items-center relative mr-0 sm:mr-3 px-3 h-8 rounded-xl
|
||||
@ -26,18 +26,21 @@ const navClassName = `
|
||||
`
|
||||
|
||||
const Header = () => {
|
||||
const { isCurrentWorkspaceManager, langeniusVersionInfo } = useAppContext()
|
||||
const [showUpgradePanel, setShowUpgradePanel] = useState(false)
|
||||
const upgradeBtnRef = useRef<HTMLElement>(null)
|
||||
useClickAway(() => {
|
||||
setShowUpgradePanel(false)
|
||||
}, upgradeBtnRef)
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
|
||||
const selectedSegment = useSelectedLayoutSegment()
|
||||
const media = useBreakpoints()
|
||||
const isMobile = media === MediaType.mobile
|
||||
const [isShowNavMenu, { toggle, setFalse: hideNavMenu }] = useBoolean(false)
|
||||
const { enableBilling } = useProviderContext()
|
||||
const { enableBilling, plan } = useProviderContext()
|
||||
const { setShowPricingModal, setShowAccountSettingModal } = useModalContext()
|
||||
const isFreePlan = plan.type === 'sandbox'
|
||||
const handlePlanClick = useCallback(() => {
|
||||
if (isFreePlan)
|
||||
setShowPricingModal()
|
||||
else
|
||||
setShowAccountSettingModal({ payload: 'billing' })
|
||||
}, [isFreePlan, setShowAccountSettingModal, setShowPricingModal])
|
||||
|
||||
useEffect(() => {
|
||||
hideNavMenu()
|
||||
@ -79,15 +82,7 @@ const Header = () => {
|
||||
<EnvNav />
|
||||
{enableBilling && (
|
||||
<div className='mr-3 select-none'>
|
||||
<HeaderBillingBtn onClick={() => setShowUpgradePanel(true)} />
|
||||
{showUpgradePanel && (
|
||||
<div
|
||||
ref={upgradeBtnRef as any}
|
||||
className='fixed z-10 top-12 right-1 w-[360px]'
|
||||
>
|
||||
<PlanComp loc='header' />
|
||||
</div>
|
||||
)}
|
||||
<HeaderBillingBtn onClick={handlePlanClick} />
|
||||
</div>
|
||||
)}
|
||||
<WorkspaceProvider>
|
||||
|
@ -40,7 +40,7 @@ const ModalContext = createContext<{
|
||||
setShowApiBasedExtensionModal: Dispatch<SetStateAction<ModalState<ApiBasedExtension> | null>>
|
||||
setShowModerationSettingModal: Dispatch<SetStateAction<ModalState<ModerationConfig> | null>>
|
||||
setShowExternalDataToolModal: Dispatch<SetStateAction<ModalState<ExternalDataTool> | null>>
|
||||
setShowPricingModal: Dispatch<SetStateAction<any>>
|
||||
setShowPricingModal: () => void
|
||||
setShowAnnotationFullModal: () => void
|
||||
setShowModelModal: Dispatch<SetStateAction<ModalState<ModelModalType> | null>>
|
||||
}>({
|
||||
@ -50,7 +50,7 @@ const ModalContext = createContext<{
|
||||
setShowExternalDataToolModal: () => { },
|
||||
setShowPricingModal: () => { },
|
||||
setShowAnnotationFullModal: () => { },
|
||||
setShowModelModal: () => {},
|
||||
setShowModelModal: () => { },
|
||||
})
|
||||
|
||||
export const useModalContext = () => useContext(ModalContext)
|
||||
|
@ -28,6 +28,7 @@ const translation = {
|
||||
talkToSales: 'Talk to Sales',
|
||||
modelProviders: 'Model Providers',
|
||||
teamMembers: 'Team Members',
|
||||
annotationQuota: 'Annotation Quota',
|
||||
buildApps: 'Build Apps',
|
||||
vectorSpace: 'Vector Space',
|
||||
vectorSpaceBillingTooltip: 'Each 1MB can store about 1.2million characters of vectorized data(estimated using OpenAI Embeddings, varies across models).',
|
||||
|
@ -29,6 +29,7 @@ const translation = {
|
||||
modelProviders: '支持的模型提供商',
|
||||
teamMembers: '团队成员',
|
||||
buildApps: '构建应用程序数',
|
||||
annotationQuota: '标注回复数',
|
||||
vectorSpace: '向量空间',
|
||||
vectorSpaceTooltip: '向量空间是 LLMs 理解您的数据所需的长期记忆系统。',
|
||||
vectorSpaceBillingTooltip: '向量存储是将知识库向量化处理后为让 LLMs 理解数据而使用的长期记忆存储,1MB 大约能满足1.2 million character 的向量化后数据存储(以 OpenAI Embedding 模型估算,不同模型计算方式有差异)。在向量化过程中,实际的压缩或尺寸减小取决于内容的复杂性和冗余性。',
|
||||
|
Loading…
Reference in New Issue
Block a user