-
+
+
+
-
-
+
+
{t('billing.triggerLimitModal.title')}
-
+
{t('billing.triggerLimitModal.description')}
= ({
-
+
diff --git a/web/app/components/billing/upgrade-btn/index.tsx b/web/app/components/billing/upgrade-btn/index.tsx
index d576e07f3e..b70daeb2e6 100644
--- a/web/app/components/billing/upgrade-btn/index.tsx
+++ b/web/app/components/billing/upgrade-btn/index.tsx
@@ -11,7 +11,7 @@ type Props = {
className?: string
style?: CSSProperties
isFull?: boolean
- size?: 'md' | 'lg'
+ size?: 's' | 'm' | 'custom'
isPlain?: boolean
isShort?: boolean
onClick?: () => void
@@ -21,6 +21,7 @@ type Props = {
const UpgradeBtn: FC
= ({
className,
+ size = 'm',
style,
isPlain = false,
isShort = false,
@@ -62,7 +63,7 @@ const UpgradeBtn: FC = ({
return (
= plan.total.vectorSpace
const isShowVectorSpaceFull = (allFileLoaded || hasNotin) && isVectorSpaceFull && enableBilling
const supportBatchUpload = !enableBilling || plan.type !== 'sandbox'
+ const notSupportBatchUpload = !supportBatchUpload
+
+ const [isShowPlanUpgradeModal, {
+ setTrue: showPlanUpgradeModal,
+ setFalse: hidePlanUpgradeModal,
+ }] = useBoolean(false)
+ const onStepChange = useCallback(() => {
+ if (notSupportBatchUpload) {
+ let isMultiple = false
+ if (dataSourceType === DataSourceType.FILE && files.length > 1)
+ isMultiple = true
+
+ if (dataSourceType === DataSourceType.NOTION && notionPages.length > 1)
+ isMultiple = true
+
+ if (dataSourceType === DataSourceType.WEB && websitePages.length > 1)
+ isMultiple = true
+
+ if (isMultiple) {
+ showPlanUpgradeModal()
+ return
+ }
+ }
+ doOnStepChange()
+ }, [dataSourceType, doOnStepChange, files.length, notSupportBatchUpload, notionPages.length, showPlanUpgradeModal, websitePages.length])
+
const nextDisabled = useMemo(() => {
if (!files.length)
return true
@@ -331,6 +359,14 @@ const StepOne = ({
/>
)}
{currentWebsite && }
+ {isShowPlanUpgradeModal && (
+
+ )}
diff --git a/web/app/components/datasets/documents/detail/segment-add/index.tsx b/web/app/components/datasets/documents/detail/segment-add/index.tsx
index d41118ec02..22e4a478ef 100644
--- a/web/app/components/datasets/documents/detail/segment-add/index.tsx
+++ b/web/app/components/datasets/documents/detail/segment-add/index.tsx
@@ -1,6 +1,6 @@
'use client'
import type { FC } from 'react'
-import React, { useMemo } from 'react'
+import React, { useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import {
RiAddLine,
@@ -11,6 +11,9 @@ import {
import cn from '@/utils/classnames'
import { CheckCircle } from '@/app/components/base/icons/src/vender/solid/general'
import Popover from '@/app/components/base/popover'
+import { useBoolean } from 'ahooks'
+import { useProviderContext } from '@/context/provider-context'
+import PlanUpgradeModal from '@/app/components/billing/plan-upgrade-modal'
export type ISegmentAddProps = {
importStatus: ProcessStatus | string | undefined
@@ -35,6 +38,23 @@ const SegmentAdd: FC
= ({
embedding,
}) => {
const { t } = useTranslation()
+ const [isShowPlanUpgradeModal, {
+ setTrue: showPlanUpgradeModal,
+ setFalse: hidePlanUpgradeModal,
+ }] = useBoolean(false)
+ const { plan, enableBilling } = useProviderContext()
+ const { usage, total } = plan
+ const canAdd = enableBilling && (usage.vectorSpace < total.vectorSpace)
+
+ const withNeedUpgradeCheck = useCallback((fn: () => void) => {
+ return () => {
+ if (!canAdd) {
+ showPlanUpgradeModal()
+ return
+ }
+ fn()
+ }
+ }, [canAdd, showPlanUpgradeModal])
const textColor = useMemo(() => {
return embedding
? 'text-components-button-secondary-accent-text-disabled'
@@ -90,7 +110,7 @@ const SegmentAdd: FC = ({
type='button'
className={`inline-flex items-center rounded-l-lg border-r-[1px] border-r-divider-subtle px-2.5 py-2
hover:bg-state-base-hover disabled:cursor-not-allowed disabled:hover:bg-transparent`}
- onClick={showNewSegmentModal}
+ onClick={withNeedUpgradeCheck(showNewSegmentModal)}
disabled={embedding}
>
@@ -108,7 +128,7 @@ const SegmentAdd: FC = ({
@@ -116,7 +136,7 @@ const SegmentAdd: FC = ({
}
btnElement={
-
+
}
btnClassName={open => cn(
@@ -129,7 +149,16 @@ const SegmentAdd: FC = ({
className='h-fit min-w-[128px]'
disabled={embedding}
/>
+ {isShowPlanUpgradeModal && (
+
+ )}
+
)
}
export default React.memo(SegmentAdd)
diff --git a/web/context/hooks/use-trigger-events-limit-modal.ts b/web/context/hooks/use-trigger-events-limit-modal.ts
index b55501ffaf..ac02acc025 100644
--- a/web/context/hooks/use-trigger-events-limit-modal.ts
+++ b/web/context/hooks/use-trigger-events-limit-modal.ts
@@ -9,7 +9,6 @@ export type TriggerEventsLimitModalPayload = {
usage: number
total: number
resetInDays?: number
- planType: Plan
storageKey?: string
persistDismiss?: boolean
}
@@ -98,7 +97,6 @@ export const useTriggerEventsLimitModal = ({
payload: {
usage: usage.triggerEvents,
total: total.triggerEvents,
- planType: type,
resetInDays: triggerResetInDays,
storageKey,
persistDismiss,
diff --git a/web/context/modal-context.test.tsx b/web/context/modal-context.test.tsx
index f7e65bac6f..f929457180 100644
--- a/web/context/modal-context.test.tsx
+++ b/web/context/modal-context.test.tsx
@@ -31,7 +31,7 @@ const triggerEventsLimitModalMock = jest.fn((props: any) => {
latestTriggerEventsModalProps = props
return (
-
+
)
@@ -115,11 +115,10 @@ describe('ModalContextProvider trigger events limit modal', () => {
usage: 3000,
total: 3000,
resetInDays: 5,
- planType: Plan.professional,
})
act(() => {
- latestTriggerEventsModalProps.onDismiss()
+ latestTriggerEventsModalProps.onClose()
})
await waitFor(() => expect(screen.queryByTestId('trigger-limit-modal')).not.toBeInTheDocument())
@@ -149,7 +148,7 @@ describe('ModalContextProvider trigger events limit modal', () => {
await waitFor(() => expect(screen.getByTestId('trigger-limit-modal')).toBeInTheDocument())
act(() => {
- latestTriggerEventsModalProps.onDismiss()
+ latestTriggerEventsModalProps.onClose()
})
await waitFor(() => expect(screen.queryByTestId('trigger-limit-modal')).not.toBeInTheDocument())
@@ -177,7 +176,7 @@ describe('ModalContextProvider trigger events limit modal', () => {
await waitFor(() => expect(screen.getByTestId('trigger-limit-modal')).toBeInTheDocument())
act(() => {
- latestTriggerEventsModalProps.onDismiss()
+ latestTriggerEventsModalProps.onClose()
})
await waitFor(() => expect(screen.queryByTestId('trigger-limit-modal')).not.toBeInTheDocument())
diff --git a/web/context/modal-context.tsx b/web/context/modal-context.tsx
index 082b0f9c58..7f08045993 100644
--- a/web/context/modal-context.tsx
+++ b/web/context/modal-context.tsx
@@ -485,9 +485,8 @@ export const ModalContextProvider = ({
show
usage={showTriggerEventsLimitModal.payload.usage}
total={showTriggerEventsLimitModal.payload.total}
- planType={showTriggerEventsLimitModal.payload.planType}
resetInDays={showTriggerEventsLimitModal.payload.resetInDays}
- onDismiss={() => {
+ onClose={() => {
persistTriggerEventsLimitModalDismiss()
setShowTriggerEventsLimitModal(null)
}}
diff --git a/web/i18n/en-US/billing.ts b/web/i18n/en-US/billing.ts
index 2531e5831a..793e534e35 100644
--- a/web/i18n/en-US/billing.ts
+++ b/web/i18n/en-US/billing.ts
@@ -221,6 +221,16 @@ const translation = {
fullTipLine2: 'annotate more conversations.',
quotaTitle: 'Annotation Reply Quota',
},
+ upgrade: {
+ uploadMultiplePages: {
+ title: 'Upgrade to upload multiple pages at once',
+ description: 'You’ve reached the upload limit — only one page can be selected and uploaded at a time on your current plan.',
+ },
+ addChunks: {
+ title: 'Upgrade to continue adding chunks',
+ description: 'You’ve reached the limit of adding chunks for this plan. ',
+ },
+ },
}
export default translation
diff --git a/web/i18n/ja-JP/billing.ts b/web/i18n/ja-JP/billing.ts
index 97fa4eb0e6..a7dd695871 100644
--- a/web/i18n/ja-JP/billing.ts
+++ b/web/i18n/ja-JP/billing.ts
@@ -202,6 +202,16 @@ const translation = {
quotaTitle: '注釈返信クォータ',
},
teamMembers: 'チームメンバー',
+ upgrade: {
+ uploadMultiplePages: {
+ title: '複数ページを一度にアップロードするにはアップグレード',
+ description: '現在のプランではアップロード上限に達しています。1回の操作で選択・アップロードできるページは1つのみです。',
+ },
+ addChunks: {
+ title: 'アップグレードして、チャンクを引き続き追加できるようにしてください。',
+ description: 'このプランでは、チャンク追加の上限に達しています。 ',
+ },
+ },
}
export default translation
diff --git a/web/i18n/zh-Hans/billing.ts b/web/i18n/zh-Hans/billing.ts
index b404240b3d..6e0c97de71 100644
--- a/web/i18n/zh-Hans/billing.ts
+++ b/web/i18n/zh-Hans/billing.ts
@@ -202,6 +202,16 @@ const translation = {
quotaTitle: '标注的配额',
},
teamMembers: '团队成员',
+ upgrade: {
+ uploadMultiplePages: {
+ title: '升级以一次性上传多个页面',
+ description: '您已达到当前套餐的上传限制 —— 该套餐每次只能选择并上传 1 个页面。',
+ },
+ addChunks: {
+ title: '升级以继续添加分段',
+ description: '您已达到此计划的添加分段上限。',
+ },
+ },
}
export default translation