=> ({ current: value })
@@ -28,6 +36,7 @@ describe('UploadDropzone', () => {
beforeEach(() => {
vi.clearAllMocks()
+ mockEnableBilling = false
})
describe('rendering', () => {
@@ -50,7 +59,7 @@ describe('UploadDropzone', () => {
it('should render upload icon', () => {
render()
- const icon = document.querySelector('svg')
+ const icon = document.querySelector('.i-ri-upload-cloud-2-line')
expect(icon).toBeInTheDocument()
})
@@ -73,6 +82,51 @@ describe('UploadDropzone', () => {
})
})
+ describe('tip rendering by billing state', () => {
+ it('should render tip without total count limit when billing is disabled', () => {
+ mockEnableBilling = false
+
+ render()
+
+ const tipWithoutTotal = screen.getByText(/datasetCreation\.stepOne\.uploader\.tip(?!WithTotalLimit)/)
+ expect(tipWithoutTotal).toBeInTheDocument()
+ expect(screen.queryByText(/datasetCreation\.stepOne\.uploader\.tipWithTotalLimit/)).not.toBeInTheDocument()
+ })
+
+ it('should render tip with total count limit when billing is enabled', () => {
+ mockEnableBilling = true
+
+ render()
+
+ expect(screen.getByText(/datasetCreation\.stepOne\.uploader\.tipWithTotalLimit/)).toBeInTheDocument()
+ expect(screen.queryByText(/datasetCreation\.stepOne\.uploader\.tip(?!WithTotalLimit)/)).not.toBeInTheDocument()
+ })
+
+ it('should pass file size, batch count and supported types to tip when billing is disabled', () => {
+ mockEnableBilling = false
+
+ render()
+
+ const tipText = screen.getByText(/datasetCreation\.stepOne\.uploader\.tip/).textContent ?? ''
+ expect(tipText).toContain('"size":15')
+ expect(tipText).toContain('"batchCount":5')
+ expect(tipText).toContain('"supportTypes":"PDF, DOCX, TXT"')
+ expect(tipText).not.toContain('"totalCount"')
+ })
+
+ it('should additionally pass total count to tip when billing is enabled', () => {
+ mockEnableBilling = true
+
+ render()
+
+ const tipText = screen.getByText(/datasetCreation\.stepOne\.uploader\.tipWithTotalLimit/).textContent ?? ''
+ expect(tipText).toContain('"size":15')
+ expect(tipText).toContain('"batchCount":5')
+ expect(tipText).toContain('"supportTypes":"PDF, DOCX, TXT"')
+ expect(tipText).toContain('"totalCount":10')
+ })
+ })
+
describe('file input configuration', () => {
it('should allow multiple files when supportBatchUpload is true', () => {
render()
diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/components/upload-dropzone.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/components/upload-dropzone.tsx
index 32aee588df..eab0dd4ce0 100644
--- a/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/components/upload-dropzone.tsx
+++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/components/upload-dropzone.tsx
@@ -1,7 +1,7 @@
import type { ChangeEvent, RefObject } from 'react'
import { cn } from '@langgenius/dify-ui/cn'
-import { RiUploadCloud2Line } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
+import { useProviderContextSelector } from '@/context/provider-context'
type FileUploadConfig = {
file_size_limit: number
@@ -37,6 +37,7 @@ const UploadDropzone = ({
allowedExtensions,
}: UploadDropzoneProps) => {
const { t } = useTranslation()
+ const enableBilling = useProviderContextSelector(state => state.enableBilling)
return (
<>
@@ -57,7 +58,7 @@ const UploadDropzone = ({
)}
>
-
+
{supportBatchUpload ? t('stepOne.uploader.button', { ns: 'datasetCreation' }) : t('stepOne.uploader.buttonSingleFile', { ns: 'datasetCreation' })}
{allowedExtensions.length > 0 && (
@@ -66,13 +67,20 @@ const UploadDropzone = ({
- {t('stepOne.uploader.tip', {
- ns: 'datasetCreation',
- size: fileUploadConfig.file_size_limit,
- supportTypes: supportTypesShowNames,
- batchCount: fileUploadConfig.batch_count_limit,
- totalCount: fileUploadConfig.file_upload_limit,
- })}
+ {enableBilling
+ ? t('stepOne.uploader.tipWithTotalLimit', {
+ ns: 'datasetCreation',
+ size: fileUploadConfig.file_size_limit,
+ supportTypes: supportTypesShowNames,
+ batchCount: fileUploadConfig.batch_count_limit,
+ totalCount: fileUploadConfig.file_upload_limit,
+ })
+ : t('stepOne.uploader.tip', {
+ ns: 'datasetCreation',
+ size: fileUploadConfig.file_size_limit,
+ supportTypes: supportTypesShowNames,
+ batchCount: fileUploadConfig.batch_count_limit,
+ })}
{dragging && }
diff --git a/web/app/components/datasets/documents/detail/completed/segment-list-context.ts b/web/app/components/datasets/documents/detail/completed/segment-list-context.ts
index 3ce9f8b987..b81a305614 100644
--- a/web/app/components/datasets/documents/detail/completed/segment-list-context.ts
+++ b/web/app/components/datasets/documents/detail/completed/segment-list-context.ts
@@ -2,13 +2,13 @@ import type { ChildChunkDetail, SegmentDetailModel } from '@/models/datasets'
import { noop } from 'es-toolkit/function'
import { createContext, useContextSelector } from 'use-context-selector'
-export type CurrSegmentType = {
+type CurrSegmentType = {
segInfo?: SegmentDetailModel
showModal: boolean
isEditMode?: boolean
}
-export type CurrChildChunkType = {
+type CurrChildChunkType = {
childChunkInfo?: ChildChunkDetail
showModal: boolean
}
diff --git a/web/app/components/datasets/documents/hooks/use-document-list-query-state.ts b/web/app/components/datasets/documents/hooks/use-document-list-query-state.ts
index 60717d532c..d06ffe767c 100644
--- a/web/app/components/datasets/documents/hooks/use-document-list-query-state.ts
+++ b/web/app/components/datasets/documents/hooks/use-document-list-query-state.ts
@@ -49,7 +49,7 @@ const parseAsDocSort = createParser({
const parseAsKeyword = parseAsString.withDefault('')
-export const documentListParsers = {
+const documentListParsers = {
page: parseAsPage,
limit: parseAsLimit,
keyword: parseAsKeyword,
diff --git a/web/app/components/goto-anything/actions/types.ts b/web/app/components/goto-anything/actions/types.ts
index 7d1ddfd4e1..da3ca8eb62 100644
--- a/web/app/components/goto-anything/actions/types.ts
+++ b/web/app/components/goto-anything/actions/types.ts
@@ -5,9 +5,9 @@ import type { CommonNodeType } from '../../workflow/types'
import type { DataSet } from '@/models/datasets'
import type { App } from '@/types/app'
-export type SearchResultType = 'app' | 'knowledge' | 'plugin' | 'workflow-node' | 'command' | 'recent'
+type SearchResultType = 'app' | 'knowledge' | 'plugin' | 'workflow-node' | 'command' | 'recent'
-export type BaseSearchResult = {
+type BaseSearchResult = {
id: string
title: string
description?: string
@@ -29,7 +29,7 @@ export type KnowledgeSearchResult = {
type: 'knowledge'
} & BaseSearchResult
-export type WorkflowNodeSearchResult = {
+type WorkflowNodeSearchResult = {
type: 'workflow-node'
metadata?: {
nodeId: string
diff --git a/web/app/components/header/account-setting/model-provider-page/declarations.ts b/web/app/components/header/account-setting/model-provider-page/declarations.ts
index cc700fe5c6..fc18f019a0 100644
--- a/web/app/components/header/account-setting/model-provider-page/declarations.ts
+++ b/web/app/components/header/account-setting/model-provider-page/declarations.ts
@@ -92,7 +92,7 @@ export enum CustomConfigurationStatusEnum {
noConfigure = 'no-configure',
}
-export type FormShowOnObject = {
+type FormShowOnObject = {
variable: string
value: string
}
@@ -155,7 +155,7 @@ export enum QuotaUnitEnum {
times = 'times',
}
-export type QuotaConfiguration = {
+type QuotaConfiguration = {
quota_type: CurrentSystemQuotaTypeEnum
quota_unit: QuotaUnitEnum
quota_limit: number
diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/components/reasoning-config-form.helpers.ts b/web/app/components/plugins/plugin-detail-panel/tool-selector/components/reasoning-config-form.helpers.ts
index 6316441f1c..a07d3de500 100644
--- a/web/app/components/plugins/plugin-detail-panel/tool-selector/components/reasoning-config-form.helpers.ts
+++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/components/reasoning-config-form.helpers.ts
@@ -7,13 +7,13 @@ import { FormTypeEnum } from '@/app/components/header/account-setting/model-prov
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
import { VarType } from '@/app/components/workflow/types'
-export type ReasoningConfigInputValue = {
+type ReasoningConfigInputValue = {
type?: VarKindType
value?: unknown
[key: string]: unknown
} | null
-export type ReasoningConfigInput = {
+type ReasoningConfigInput = {
value: ReasoningConfigInputValue
auto?: 0 | 1
}
diff --git a/web/app/components/plugins/types.ts b/web/app/components/plugins/types.ts
index bcffad06e0..0f03e17a05 100644
--- a/web/app/components/plugins/types.ts
+++ b/web/app/components/plugins/types.ts
@@ -22,7 +22,7 @@ export enum PluginSource {
debugging = 'remote',
}
-export type PluginToolDeclaration = {
+type PluginToolDeclaration = {
identity: {
author: string
name: string
@@ -34,12 +34,12 @@ export type PluginToolDeclaration = {
credentials_schema: ToolCredential[] // TODO
}
-export type PluginEndpointDeclaration = {
+type PluginEndpointDeclaration = {
settings: ToolCredential[]
endpoints: EndpointItem[]
}
-export type EndpointItem = {
+type EndpointItem = {
path: string
method: string
hidden?: boolean
@@ -60,7 +60,7 @@ export type EndpointListItem = {
hook_id: string
}
-export type PluginDeclarationMeta = {
+type PluginDeclarationMeta = {
version: string
minimum_dify_version?: string
}
@@ -96,14 +96,14 @@ export type PluginTriggerSubscriptionConstructor = {
parameters: ParametersSchema[]
}
-export type PluginTriggerDefinition = {
+type PluginTriggerDefinition = {
events: TriggerEvent[]
identity: Identity
subscription_constructor: PluginTriggerSubscriptionConstructor
subscription_schema: ParametersSchema[]
}
-export type CredentialsSchema = {
+type CredentialsSchema = {
name: string
label: Record
description: Record
@@ -117,7 +117,7 @@ export type CredentialsSchema = {
placeholder: Record
}
-export type OauthSchema = {
+type OauthSchema = {
client_schema: CredentialsSchema[]
credentials_schema: CredentialsSchema[]
}
@@ -352,7 +352,7 @@ export enum InstallStep {
installFailed = 'failed',
}
-export type GitHubAsset = {
+type GitHubAsset = {
id: number
name: string
browser_download_url: string
@@ -496,7 +496,7 @@ export type PackageDependency = {
export type Dependency = GitHubItemAndMarketPlaceDependency | PackageDependency
-export type Version = {
+type Version = {
plugin_org: string
plugin_name: string
version: string
@@ -554,7 +554,7 @@ export type StrategyDetail = {
features: AgentFeature[]
}
-export type Identity = {
+type Identity = {
author: string
name: string
label: Record
@@ -564,7 +564,7 @@ export type Identity = {
tags: string[]
}
-export type StrategyDeclaration = {
+type StrategyDeclaration = {
identity: Identity
plugin_id: string
strategies: StrategyDetail[]
diff --git a/web/app/components/tools/types.ts b/web/app/components/tools/types.ts
index c7fb9eec2a..1e799c7307 100644
--- a/web/app/components/tools/types.ts
+++ b/web/app/components/tools/types.ts
@@ -100,7 +100,7 @@ export type ToolParameter = {
max?: number
}
-export type TriggerParameter = {
+type TriggerParameter = {
name: string
label: LocalizedText
human_description: LocalizedText
@@ -165,7 +165,7 @@ export type CustomCollectionBackend = {
labels: string[]
}
-export type ParamItem = {
+type ParamItem = {
name: string
label: LocalizedText
human_description: LocalizedText
diff --git a/web/app/components/workflow-app/hooks/use-workflow-run-utils.ts b/web/app/components/workflow-app/hooks/use-workflow-run-utils.ts
index fd5669f80a..764687fcbb 100644
--- a/web/app/components/workflow-app/hooks/use-workflow-run-utils.ts
+++ b/web/app/components/workflow-app/hooks/use-workflow-run-utils.ts
@@ -10,7 +10,7 @@ import { handleStream, post } from '@/service/base'
import { ContentType } from '@/service/fetch'
import { AppModeEnum } from '@/types/app'
-export type HandleRunMode = TriggerType
+type HandleRunMode = TriggerType
export type HandleRunOptions = {
mode?: HandleRunMode
scheduleNodeId?: string
diff --git a/web/app/components/workflow/block-selector/types.ts b/web/app/components/workflow/block-selector/types.ts
index dc6551c45c..500ca60fdf 100644
--- a/web/app/components/workflow/block-selector/types.ts
+++ b/web/app/components/workflow/block-selector/types.ts
@@ -124,7 +124,7 @@ export type DataSourceItem = {
is_authorized: boolean
}
-export type TriggerCredentialField = {
+type TriggerCredentialField = {
type: 'secret-input' | 'text-input' | 'select' | 'boolean'
| 'app-selector' | 'model-selector' | 'tools-selector'
name: string
@@ -226,14 +226,14 @@ export type TriggerLogEntity = {
created_at: string
}
-export type LogRequest = {
+type LogRequest = {
method: string
url: string
headers: LogRequestHeaders
data: string
}
-export type LogRequestHeaders = {
+type LogRequestHeaders = {
'Host': string
'User-Agent': string
'Content-Length': string
@@ -251,13 +251,13 @@ export type LogRequestHeaders = {
[key: string]: string
}
-export type LogResponse = {
+type LogResponse = {
status_code: number
headers: LogResponseHeaders
data: string
}
-export type LogResponseHeaders = {
+type LogResponseHeaders = {
'Content-Type': string
'Content-Length': string
[key: string]: string
diff --git a/web/app/components/workflow/collaboration/types/collaboration.ts b/web/app/components/workflow/collaboration/types/collaboration.ts
index ae355a7b51..3a5b71e2d1 100644
--- a/web/app/components/workflow/collaboration/types/collaboration.ts
+++ b/web/app/components/workflow/collaboration/types/collaboration.ts
@@ -22,7 +22,7 @@ export type NodePanelPresenceUser = {
avatar?: string | null
}
-export type NodePanelPresenceInfo = NodePanelPresenceUser & {
+type NodePanelPresenceInfo = NodePanelPresenceUser & {
clientId: string
timestamp: number
}
@@ -39,7 +39,7 @@ export type CollaborationState = {
error?: string
}
-export type CollaborationEventType
+type CollaborationEventType
= | 'mouse_move'
| 'vars_and_features_update'
| 'sync_request'
diff --git a/web/app/components/workflow/collaboration/types/websocket.ts b/web/app/components/workflow/collaboration/types/websocket.ts
index dd89df323f..053c655939 100644
--- a/web/app/components/workflow/collaboration/types/websocket.ts
+++ b/web/app/components/workflow/collaboration/types/websocket.ts
@@ -4,7 +4,7 @@ export type WebSocketConfig = {
withCredentials?: boolean
}
-export type ConnectionInfo = {
+type ConnectionInfo = {
connected: boolean
connecting: boolean
socketId?: string
diff --git a/web/app/components/workflow/hooks-store/store.ts b/web/app/components/workflow/hooks-store/store.ts
index a9d5003fb3..376bec635c 100644
--- a/web/app/components/workflow/hooks-store/store.ts
+++ b/web/app/components/workflow/hooks-store/store.ts
@@ -27,7 +27,7 @@ export type SyncDraftCallback = {
onError?: () => void
onSettled?: () => void
}
-export type CommonHooksFnMap = {
+type CommonHooksFnMap = {
doSyncWorkflowDraft: (
notRefreshWhenSyncError?: boolean,
callback?: SyncDraftCallback,
diff --git a/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-picker.helpers.spec.ts b/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-picker.helpers.spec.ts
index 7cef3ddde4..6b9ec7a642 100644
--- a/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-picker.helpers.spec.ts
+++ b/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-reference-picker.helpers.spec.ts
@@ -182,6 +182,16 @@ describe('var-reference-picker.helpers', () => {
maxVarNameWidth: expect.any(Number),
})
+ expect(getWidthAllocations(240, '', 'sys.user_id', 'String')).toEqual({
+ maxNodeNameWidth: 0,
+ maxTypeWidth: 64,
+ maxVarNameWidth: 119,
+ })
+
+ expect(getWidthAllocations(240, 'User Input', 'aa', 'String')).toMatchObject({
+ maxVarNameWidth: 16,
+ })
+
expect(getTooltipContent(true, true, true)).toBe('full-path')
expect(getTooltipContent(true, false, false)).toBe('invalid-variable')
expect(getTooltipContent(false, false, true)).toBeNull()
diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.helpers.ts b/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.helpers.ts
index 6cdcb916e6..f29e99cc37 100644
--- a/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.helpers.ts
+++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.helpers.ts
@@ -168,11 +168,15 @@ export const getWidthAllocations = (
) => {
const availableWidth = triggerWidth - 56
const totalTextLength = (nodeTitle + varName + type).length || 1
- const priorityWidth = 15
+ const priorityWidth = nodeTitle ? 15 : 0
+ const minVarNameWidth = varName ? 16 : 0
return {
maxNodeNameWidth: priorityWidth + Math.floor(nodeTitle.length / totalTextLength * availableWidth),
maxTypeWidth: Math.floor(type.length / totalTextLength * availableWidth),
- maxVarNameWidth: -priorityWidth + Math.floor(varName.length / totalTextLength * availableWidth),
+ maxVarNameWidth: Math.max(
+ minVarNameWidth,
+ -priorityWidth + Math.floor(varName.length / totalTextLength * availableWidth),
+ ),
}
}
diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx
index 7e99988ae8..c2645ee870 100644
--- a/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx
+++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx
@@ -279,13 +279,15 @@ const VarReferencePicker: FC = ({
[outputVarNode?.type, varName],
)
const showErrorIcon = hasValue && !isValidVar
+ const shouldShowNodeName = isShowNodeName && !isEnv && !isChatVar && !isGlobal && !isRagVar
+ const visibleNodeTitle = shouldShowNodeName ? outputVarNode?.title || '' : ''
// 8(left/right-padding) + 14(icon) + 4 + 14 + 2 = 42 + 17 buff
const {
maxNodeNameWidth,
maxTypeWidth,
maxVarNameWidth,
- } = getWidthAllocations(triggerWidth, outputVarNode?.title || '', varName || '', type || '')
+ } = getWidthAllocations(triggerWidth, visibleNodeTitle, varName || '', type || '')
const hoverPopup = useMemo(() => {
const tooltipType = getTooltipContent(hasValue, isShowAPart, isValidVar)
@@ -380,7 +382,7 @@ const VarReferencePicker: FC = ({
isJustShowValue={isJustShowValue}
isLoading={isLoading}
isShowAPart={isShowAPart}
- isShowNodeName={isShowNodeName && !isEnv && !isChatVar && !isGlobal && !isRagVar}
+ isShowNodeName={shouldShowNodeName}
isSupportConstantValue={isSupportConstantValue}
maxNodeNameWidth={maxNodeNameWidth}
maxTypeWidth={maxTypeWidth}
diff --git a/web/app/components/workflow/nodes/knowledge-base/types.ts b/web/app/components/workflow/nodes/knowledge-base/types.ts
index dbcc926ee3..afe7370ba6 100644
--- a/web/app/components/workflow/nodes/knowledge-base/types.ts
+++ b/web/app/components/workflow/nodes/knowledge-base/types.ts
@@ -32,7 +32,7 @@ export type WeightedScore = {
}
}
-export type RetrievalSetting = {
+type RetrievalSetting = {
search_method?: RETRIEVE_METHOD
reranking_enable?: boolean
reranking_model?: RerankingModel
diff --git a/web/app/components/workflow/nodes/loop/types.ts b/web/app/components/workflow/nodes/loop/types.ts
index 3e91506c47..066f0fcbe3 100644
--- a/web/app/components/workflow/nodes/loop/types.ts
+++ b/web/app/components/workflow/nodes/loop/types.ts
@@ -83,8 +83,8 @@ export type LoopNodeType = CommonNodeType & {
loop_variables?: LoopVariable[]
}
-export type HandleUpdateLoopVariable = (id: string, updateData: Partial) => void
-export type HandleRemoveLoopVariable = (id: string) => void
+type HandleUpdateLoopVariable = (id: string, updateData: Partial) => void
+type HandleRemoveLoopVariable = (id: string) => void
export type LoopVariablesComponentShape = {
nodeId: string
diff --git a/web/app/components/workflow/nodes/trigger-schedule/types.ts b/web/app/components/workflow/nodes/trigger-schedule/types.ts
index 3d82709199..9bcecdda82 100644
--- a/web/app/components/workflow/nodes/trigger-schedule/types.ts
+++ b/web/app/components/workflow/nodes/trigger-schedule/types.ts
@@ -4,7 +4,7 @@ export type ScheduleMode = 'visual' | 'cron'
export type ScheduleFrequency = 'hourly' | 'daily' | 'weekly' | 'monthly'
-export type VisualConfig = {
+type VisualConfig = {
time?: string
weekdays?: string[]
on_minute?: number
diff --git a/web/app/components/workflow/nodes/trigger-webhook/components/generic-table.tsx b/web/app/components/workflow/nodes/trigger-webhook/components/generic-table.tsx
index 438cf154ba..a14a642c40 100644
--- a/web/app/components/workflow/nodes/trigger-webhook/components/generic-table.tsx
+++ b/web/app/components/workflow/nodes/trigger-webhook/components/generic-table.tsx
@@ -16,9 +16,9 @@ const isPresent = (v: unknown): boolean => {
return !(v === '' || v === null || v === undefined || v === false)
}
// Column configuration types for table components
-export type ColumnType = 'input' | 'select' | 'switch' | 'custom'
+type ColumnType = 'input' | 'select' | 'switch' | 'custom'
-export type SelectOption = {
+type SelectOption = {
name: string
value: string
}
diff --git a/web/app/components/workflow/types.ts b/web/app/components/workflow/types.ts
index efd21e099c..fa1b26074e 100644
--- a/web/app/components/workflow/types.ts
+++ b/web/app/components/workflow/types.ts
@@ -498,7 +498,7 @@ export type ChildNodeTypeCount = {
[key: string]: number
}
-export const TRIGGER_NODE_TYPES = [
+const TRIGGER_NODE_TYPES = [
BlockEnum.TriggerSchedule,
BlockEnum.TriggerWebhook,
BlockEnum.TriggerPlugin,
diff --git a/web/app/components/workflow/workflow-history-store.tsx b/web/app/components/workflow/workflow-history-store.tsx
index efab0dd067..97c9f2ac33 100644
--- a/web/app/components/workflow/workflow-history-store.tsx
+++ b/web/app/components/workflow/workflow-history-store.tsx
@@ -98,14 +98,14 @@ function createStore({
return store
}
-export type WorkflowHistoryStore = {
+type WorkflowHistoryStore = {
nodes: Node[]
edges: Edge[]
workflowHistoryEvent: WorkflowHistoryEventT | undefined
workflowHistoryEventMeta?: WorkflowHistoryEventMeta
}
-export type WorkflowHistoryActions = {
+type WorkflowHistoryActions = {
setNodes?: (nodes: Node[]) => void
setEdges?: (edges: Edge[]) => void
}
diff --git a/web/app/education-apply/__tests__/search-input.spec.tsx b/web/app/education-apply/__tests__/search-input.spec.tsx
index bb3cd8cc84..ae9b678add 100644
--- a/web/app/education-apply/__tests__/search-input.spec.tsx
+++ b/web/app/education-apply/__tests__/search-input.spec.tsx
@@ -1,4 +1,3 @@
-import type { ReactNode } from 'react'
import { fireEvent, render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { useState } from 'react'
@@ -23,73 +22,6 @@ vi.mock('react-i18next', () => ({
}),
}))
-vi.mock('@/app/components/base/input', () => ({
- default: ({
- value,
- onChange,
- placeholder,
- className,
- }: {
- value?: string
- onChange: (event: { target: { value: string } }) => void
- placeholder?: string
- className?: string
- }) => (
- onChange({ target: { value: e.target.value } })}
- />
- ),
-}))
-
-vi.mock('@langgenius/dify-ui/popover', async () => {
- const React = await import('react')
- const PopoverContext = React.createContext({
- open: false,
- setOpen: (_open: boolean) => {},
- })
-
- const Popover = ({
- children,
- open: controlledOpen,
- onOpenChange,
- }: {
- children: ReactNode
- open?: boolean
- onOpenChange?: (open: boolean) => void
- }) => {
- const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false)
- const isControlled = controlledOpen !== undefined
- const open = isControlled ? !!controlledOpen : uncontrolledOpen
- const setOpen = (nextOpen: boolean) => {
- if (!isControlled)
- setUncontrolledOpen(nextOpen)
- onOpenChange?.(nextOpen)
- }
-
- return (
-
- {children}
-
- )
- }
-
- const PopoverTrigger = ({ render }: { render: ReactNode }) => <>{render}>
-
- const PopoverContent = ({ children }: { children: ReactNode }) => {
- const { open } = React.useContext(PopoverContext)
- return open ? {children}
: null
- }
-
- return {
- Popover,
- PopoverTrigger,
- PopoverContent,
- }
-})
-
const ControlledSearchInput = () => {
const [value, setValue] = useState('')
return
@@ -102,27 +34,38 @@ describe('education-apply/search-input', () => {
educationMocks.hasNext = false
})
- it('opens the popover, queries schools, and closes after selection', async () => {
+ it('keeps the search field editable when used as the popover trigger', async () => {
+ const user = userEvent.setup()
+ educationMocks.schools = []
+
+ render()
+
+ const input = screen.getByPlaceholderText('form.schoolName.placeholder') as HTMLInputElement
+ expect(input.type).toBe('text')
+
+ await user.type(input, 'Alpha')
+
+ expect(input).toHaveValue('Alpha')
+ expect(educationMocks.setSchools).toHaveBeenCalledWith([])
+ expect(educationMocks.querySchoolsWithDebounced).toHaveBeenLastCalledWith({
+ keywords: 'Alpha',
+ page: 0,
+ })
+ })
+
+ it('closes the popover after selecting a school', async () => {
const user = userEvent.setup()
render()
- const input = screen.getByPlaceholderText('form.schoolName.placeholder')
- await user.type(input, 'A')
+ await user.type(screen.getByPlaceholderText('form.schoolName.placeholder'), 'A')
- expect(educationMocks.setSchools).toHaveBeenCalledWith([])
- expect(educationMocks.querySchoolsWithDebounced).toHaveBeenLastCalledWith({
- keywords: 'A',
- page: 0,
- })
-
- expect(screen.getByTestId('education-search-popover')).toBeInTheDocument()
expect(screen.getByText('Alpha University')).toBeInTheDocument()
await user.click(screen.getByText('Beta College'))
expect(screen.getByDisplayValue('Beta College')).toBeInTheDocument()
- expect(screen.queryByTestId('education-search-popover')).not.toBeInTheDocument()
+ expect(screen.queryByText('Alpha University')).not.toBeInTheDocument()
})
it('loads the next page when the dropdown is scrolled to the bottom', async () => {
diff --git a/web/app/education-apply/search-input.tsx b/web/app/education-apply/search-input.tsx
index 4f930eb3eb..5125eba439 100644
--- a/web/app/education-apply/search-input.tsx
+++ b/web/app/education-apply/search-input.tsx
@@ -77,6 +77,7 @@ const SearchInput = ({
return (
)}
/>
- {!!schools.length && !!value && (
+ {open && !!schools.length && !!value && (
& {
dataset_id: string
}
-export type DataSource = {
+type DataSource = {
type: DataSourceType
info_list: {
data_source_type: DataSourceType
@@ -513,7 +510,7 @@ export type FullDocumentDetail = SimpleDocumentDetail & {
[key: string]: any
}
-export type DocMetadata = {
+type DocMetadata = {
title: string
language: string
author: string
@@ -534,16 +531,13 @@ export const CUSTOMIZABLE_DOC_TYPES = [
'im_chat_log',
] as const
-export const FIXED_DOC_TYPES = ['synced_from_github', 'synced_from_notion', 'wikipedia_entry'] as const
-
-export type CustomizableDocType = typeof CUSTOMIZABLE_DOC_TYPES[number]
-export type FixedDocType = typeof FIXED_DOC_TYPES[number]
+type CustomizableDocType = typeof CUSTOMIZABLE_DOC_TYPES[number]
+type FixedDocType = 'synced_from_github' | 'synced_from_notion' | 'wikipedia_entry'
export type DocType = CustomizableDocType | FixedDocType
export type DocumentDetailResponse = FullDocumentDetail
-export const SEGMENT_STATUS_LIST = ['waiting', 'completed', 'error', 'indexing']
-export type SegmentStatus = typeof SEGMENT_STATUS_LIST[number]
+type SegmentStatus = 'waiting' | 'completed' | 'error' | 'indexing'
export type Attachment = {
id: string
@@ -634,7 +628,7 @@ export type ExternalKnowledgeBaseHitTesting = {
}
}
-export type Segment = {
+type Segment = {
id: string
document: Document
content: string
@@ -648,7 +642,7 @@ export type Segment = {
answer: string
}
-export type Document = {
+type Document = {
id: string
data_source_type: string
name: string
@@ -663,7 +657,7 @@ export type HitTestingRecordsResponse = {
page: number
}
-export type TsnePosition = {
+type TsnePosition = {
x: number
y: number
}
@@ -750,7 +744,7 @@ export const DEFAULT_WEIGHTED_SCORE = {
},
}
-export type ChildChunkType = 'automatic' | 'customized'
+type ChildChunkType = 'automatic' | 'customized'
export type ChildChunkDetail = {
id: string
diff --git a/web/models/debug.ts b/web/models/debug.ts
index 0714372d94..a0dc9831ee 100644
--- a/web/models/debug.ts
+++ b/web/models/debug.ts
@@ -114,7 +114,7 @@ export type ModerationConfig = MoreLikeThisConfig & {
} & Partial>
}
-export type RetrieverResourceConfig = MoreLikeThisConfig
+type RetrieverResourceConfig = MoreLikeThisConfig
export type AgentConfig = {
enabled: boolean
strategy: AgentStrategy
diff --git a/web/models/explore.ts b/web/models/explore.ts
index bca92abee5..c05dd1eca1 100644
--- a/web/models/explore.ts
+++ b/web/models/explore.ts
@@ -1,6 +1,6 @@
import type { AppIconType, AppModeEnum } from '@/types/app'
-export type AppBasicInfo = {
+type AppBasicInfo = {
id: string
mode: AppModeEnum
icon_type: AppIconType | null
diff --git a/web/models/log.ts b/web/models/log.ts
index f9cb13ab8e..e3828d4b78 100644
--- a/web/models/log.ts
+++ b/web/models/log.ts
@@ -6,7 +6,7 @@ import type {
} from '@/app/components/workflow/types'
import type { VisionFile } from '@/types/app'
-export type CompletionParamsType = {
+type CompletionParamsType = {
max_tokens: number
temperature: number
top_p: number
@@ -15,13 +15,13 @@ export type CompletionParamsType = {
frequency_penalty: number
}
-export type LogModelConfig = {
+type LogModelConfig = {
name: string
provider: string
completion_params: CompletionParamsType
}
-export type ModelConfigDetail = {
+type ModelConfigDetail = {
introduction: string
prompt_template: string
prompt_variables: Array<{
@@ -53,7 +53,7 @@ export type Annotation = {
created_at?: number
}
-export type MessageContent = {
+type MessageContent = {
id: string
conversation_id: string
query: string
@@ -186,8 +186,7 @@ export type ChatMessagesResponse = {
limit: number
}
-export const MessageRatings = ['like', 'dislike', null] as const
-export type MessageRating = typeof MessageRatings[number]
+export type MessageRating = 'like' | 'dislike' | null
export type LogMessageFeedbacksRequest = {
message_id: string
@@ -229,7 +228,7 @@ export type TriggerMetadata = {
icon_dark?: string | null
}
-export type WorkflowLogDetails = {
+type WorkflowLogDetails = {
trigger_metadata?: TriggerMetadata
}
@@ -246,12 +245,12 @@ export type WorkflowRunDetail = {
total_steps: number
finished_at: number
}
-export type AccountInfo = {
+type AccountInfo = {
id: string
name: string
email: string
}
-export type EndUserInfo = {
+type EndUserInfo = {
id: string
type: 'browser' | 'service_api'
is_anonymous: boolean
@@ -303,7 +302,7 @@ export type WorkflowRunDetailResponse = {
exceptions_count?: number
}
-export type AgentLogMeta = {
+type AgentLogMeta = {
status: string
executor: string
start_time: string
@@ -338,7 +337,7 @@ export type AgentIteration = {
}
}
-export type AgentLogFile = {
+type AgentLogFile = {
id: string
type: string
url: string
@@ -357,7 +356,7 @@ export type AgentLogDetailResponse = {
files: AgentLogFile[]
}
-export type PauseType = {
+type PauseType = {
type: 'human_input'
form_id: string
backstage_input_url: string
@@ -365,7 +364,7 @@ export type PauseType = {
type: 'breakpoint'
}
-export type PauseDetail = {
+type PauseDetail = {
node_id: string
node_title: string
pause_type: PauseType
diff --git a/web/scripts/gen-doc-paths.ts b/web/scripts/gen-doc-paths.ts
index fd9cdea02a..c972a33a08 100644
--- a/web/scripts/gen-doc-paths.ts
+++ b/web/scripts/gen-doc-paths.ts
@@ -275,7 +275,7 @@ function generateTypeDefinitions(
typeNames.push(typeName)
lines.push(`// ${sectionToTypeName(section)} paths`)
- lines.push(`export type ${typeName} =`)
+ lines.push(`type ${typeName} =`)
for (const p of paths) {
lines.push(` | '/${p}'`)
@@ -297,7 +297,7 @@ function generateTypeDefinitions(
if (apiReferencePaths.length > 0) {
const sortedPaths = [...apiReferencePaths].sort()
lines.push('// API Reference paths (English, use apiReferencePathTranslations for other languages)')
- lines.push('export type ApiReferencePath =')
+ lines.push('type ApiReferencePath =')
for (const p of sortedPaths) {
lines.push(` | '${p}'`)
}
@@ -307,7 +307,7 @@ function generateTypeDefinitions(
// Generate base combined type
lines.push('// Base path without language prefix')
- lines.push('export type DocPathWithoutLangBase =')
+ lines.push('type DocPathWithoutLangBase =')
for (const typeName of typeNames) {
lines.push(` | ${typeName}`)
}
diff --git a/web/service/base.ts b/web/service/base.ts
index d1ef06c314..ac7ab895a8 100644
--- a/web/service/base.ts
+++ b/web/service/base.ts
@@ -47,39 +47,39 @@ export type IOnDataMoreInfo = {
}
export type IOnData = (message: string, isFirstMessage: boolean, moreInfo: IOnDataMoreInfo) => void
-export type IOnThought = (though: ThoughtItem) => void
-export type IOnFile = (file: VisionFile) => void
-export type IOnMessageEnd = (messageEnd: MessageEnd) => void
+type IOnThought = (though: ThoughtItem) => void
+type IOnFile = (file: VisionFile) => void
+type IOnMessageEnd = (messageEnd: MessageEnd) => void
export type IOnMessageReplace = (messageReplace: MessageReplace) => void
export type IOnCompleted = (hasError?: boolean, errorMessage?: string) => void
export type IOnError = (msg: string, code?: string) => void
-export type IOnWorkflowStarted = (workflowStarted: WorkflowStartedResponse) => void
-export type IOnWorkflowFinished = (workflowFinished: WorkflowFinishedResponse) => void
-export type IOnNodeStarted = (nodeStarted: NodeStartedResponse) => void
-export type IOnNodeFinished = (nodeFinished: NodeFinishedResponse) => void
-export type IOnIterationStarted = (workflowStarted: IterationStartedResponse) => void
-export type IOnIterationNext = (workflowStarted: IterationNextResponse) => void
-export type IOnNodeRetry = (nodeFinished: NodeFinishedResponse) => void
-export type IOnIterationFinished = (workflowFinished: IterationFinishedResponse) => void
-export type IOnParallelBranchStarted = (parallelBranchStarted: ParallelBranchStartedResponse) => void
-export type IOnParallelBranchFinished = (parallelBranchFinished: ParallelBranchFinishedResponse) => void
-export type IOnTextChunk = (textChunk: TextChunkResponse) => void
-export type IOnTTSChunk = (messageId: string, audioStr: string, audioType?: string) => void
-export type IOnTTSEnd = (messageId: string, audioStr: string, audioType?: string) => void
-export type IOnTextReplace = (textReplace: TextReplaceResponse) => void
-export type IOnLoopStarted = (workflowStarted: LoopStartedResponse) => void
-export type IOnLoopNext = (workflowStarted: LoopNextResponse) => void
-export type IOnLoopFinished = (workflowFinished: LoopFinishedResponse) => void
-export type IOnAgentLog = (agentLog: AgentLogResponse) => void
+type IOnWorkflowStarted = (workflowStarted: WorkflowStartedResponse) => void
+type IOnWorkflowFinished = (workflowFinished: WorkflowFinishedResponse) => void
+type IOnNodeStarted = (nodeStarted: NodeStartedResponse) => void
+type IOnNodeFinished = (nodeFinished: NodeFinishedResponse) => void
+type IOnIterationStarted = (workflowStarted: IterationStartedResponse) => void
+type IOnIterationNext = (workflowStarted: IterationNextResponse) => void
+type IOnNodeRetry = (nodeFinished: NodeFinishedResponse) => void
+type IOnIterationFinished = (workflowFinished: IterationFinishedResponse) => void
+type IOnParallelBranchStarted = (parallelBranchStarted: ParallelBranchStartedResponse) => void
+type IOnParallelBranchFinished = (parallelBranchFinished: ParallelBranchFinishedResponse) => void
+type IOnTextChunk = (textChunk: TextChunkResponse) => void
+type IOnTTSChunk = (messageId: string, audioStr: string, audioType?: string) => void
+type IOnTTSEnd = (messageId: string, audioStr: string, audioType?: string) => void
+type IOnTextReplace = (textReplace: TextReplaceResponse) => void
+type IOnLoopStarted = (workflowStarted: LoopStartedResponse) => void
+type IOnLoopNext = (workflowStarted: LoopNextResponse) => void
+type IOnLoopFinished = (workflowFinished: LoopFinishedResponse) => void
+type IOnAgentLog = (agentLog: AgentLogResponse) => void
-export type IOHumanInputRequired = (humanInputRequired: HumanInputRequiredResponse) => void
-export type IOnHumanInputFormFilled = (humanInputFormFilled: HumanInputFormFilledResponse) => void
-export type IOnHumanInputFormTimeout = (humanInputFormTimeout: HumanInputFormTimeoutResponse) => void
-export type IOWorkflowPaused = (workflowPaused: WorkflowPausedResponse) => void
-export type IOnDataSourceNodeProcessing = (dataSourceNodeProcessing: DataSourceNodeProcessingResponse) => void
-export type IOnDataSourceNodeCompleted = (dataSourceNodeCompleted: DataSourceNodeCompletedResponse) => void
-export type IOnDataSourceNodeError = (dataSourceNodeError: DataSourceNodeErrorResponse) => void
+type IOHumanInputRequired = (humanInputRequired: HumanInputRequiredResponse) => void
+type IOnHumanInputFormFilled = (humanInputFormFilled: HumanInputFormFilledResponse) => void
+type IOnHumanInputFormTimeout = (humanInputFormTimeout: HumanInputFormTimeoutResponse) => void
+type IOWorkflowPaused = (workflowPaused: WorkflowPausedResponse) => void
+type IOnDataSourceNodeProcessing = (dataSourceNodeProcessing: DataSourceNodeProcessingResponse) => void
+type IOnDataSourceNodeCompleted = (dataSourceNodeCompleted: DataSourceNodeCompletedResponse) => void
+type IOnDataSourceNodeError = (dataSourceNodeError: DataSourceNodeErrorResponse) => void
export type IOtherOptions = {
isPublicAPI?: boolean
diff --git a/web/types/app.ts b/web/types/app.ts
index bd10da42d3..ecd4630363 100644
--- a/web/types/app.ts
+++ b/web/types/app.ts
@@ -50,8 +50,7 @@ export const AppModes = [AppModeEnum.COMPLETION, AppModeEnum.WORKFLOW, AppModeEn
/**
* Variable type
*/
-export const VariableTypes = ['string', 'number', 'select'] as const
-export type VariableType = typeof VariableTypes[number]
+type VariableType = 'string' | 'number' | 'select'
/**
* Prompt variable parameter
@@ -69,7 +68,7 @@ export type PromptVariable = {
max_length?: number
}
-export type TextTypeFormItem = {
+type TextTypeFormItem = {
default: string
label: string
variable: string
@@ -78,7 +77,7 @@ export type TextTypeFormItem = {
hide: boolean
}
-export type SelectTypeFormItem = {
+type SelectTypeFormItem = {
default: string
label: string
variable: string
diff --git a/web/types/doc-paths.ts b/web/types/doc-paths.ts
index 3f030a2733..f97883d4d4 100644
--- a/web/types/doc-paths.ts
+++ b/web/types/doc-paths.ts
@@ -8,7 +8,7 @@
export type DocLanguage = 'en' | 'zh' | 'ja'
// UseDify paths
-export type UseDifyPath =
+type UseDifyPath =
| '/use-dify/build/additional-features'
| '/use-dify/build/goto-anything'
| '/use-dify/build/mcp'
@@ -121,7 +121,7 @@ type ExtractNodesPath = T extends `/use-dify/nodes/${infer Path}` ? Path : ne
export type UseDifyNodesPath = ExtractNodesPath
// SelfHost paths
-export type SelfHostPath =
+type SelfHostPath =
| '/self-host/advanced-deployments/local-source-code'
| '/self-host/advanced-deployments/start-the-frontend-docker-container'
| '/self-host/configuration/environments'
@@ -136,7 +136,7 @@ export type SelfHostPath =
| '/self-host/troubleshooting/weaviate-v4-migration'
// DevelopPlugin paths
-export type DevelopPluginPath =
+type DevelopPluginPath =
| '/develop-plugin/dev-guides-and-walkthroughs/agent-strategy-plugin'
| '/develop-plugin/dev-guides-and-walkthroughs/cheatsheet'
| '/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider'
@@ -178,7 +178,7 @@ export type DevelopPluginPath =
| '/develop-plugin/publishing/standards/third-party-signature-verification'
// API Reference paths (English, use apiReferencePathTranslations for other languages)
-export type ApiReferencePath =
+type ApiReferencePath =
| '/api-reference/annotations/configure-annotation-reply'
| '/api-reference/annotations/create-annotation'
| '/api-reference/annotations/delete-annotation'
@@ -261,7 +261,7 @@ export type ApiReferencePath =
| '/api-reference/workflows/stop-workflow-task'
// Base path without language prefix
-export type DocPathWithoutLangBase =
+type DocPathWithoutLangBase =
| UseDifyPath
| SelfHostPath
| DevelopPluginPath
diff --git a/web/types/pipeline.tsx b/web/types/pipeline.tsx
index f101853c6c..9377868db7 100644
--- a/web/types/pipeline.tsx
+++ b/web/types/pipeline.tsx
@@ -6,7 +6,7 @@ export type DataSourceNodeProcessingResponse = {
completed: number
}
-export type OnlineDriveFile = {
+type OnlineDriveFile = {
id: string
name: string
size: number
diff --git a/web/types/workflow.ts b/web/types/workflow.ts
index 4036a40cb9..4bcd9fec45 100644
--- a/web/types/workflow.ts
+++ b/web/types/workflow.ts
@@ -460,7 +460,7 @@ export const VarInInspectType = {
} as const
export type VarInInspectType = typeof VarInInspectType[keyof typeof VarInInspectType]
-export type FullContent = {
+type FullContent = {
size_bytes: number
download_url: string
}