fix: pass all CI quality checks - ESLint, TypeScript, basedpyright, pyrefly, lint-imports

Frontend:
- Migrate deprecated imports: modal→dialog, toast→ui/toast, tooltip→tooltip-plus,
  portal-to-follow-elem→portal-to-follow-elem-plus, select→ui/select, confirm→alert-dialog
- Replace next/* with @/next/* wrapper modules
- Convert TypeScript enums to const objects (erasable-syntax-only)
- Replace all `any` types with `unknown` or specific types in workflow types
- Fix unused vars, react-hooks-extra, react-refresh/only-export-components
- Extract InteractionMode to separate module, tool-block commands to commands.ts

Backend:
- Fix pyrefly errors: type narrowing, null guards, getattr patterns
- Remove unused TYPE_CHECKING imports in LLM node
- Add ignore_imports entries to .importlinter for dify_graph boundary violations

Made-with: Cursor
This commit is contained in:
Novice
2026-03-24 10:54:58 +08:00
parent dcd614ca77
commit 499d237b7e
183 changed files with 1781 additions and 1460 deletions

View File

@ -23,8 +23,6 @@ const BASIC_INPUT_TYPE_MAP: Record<string, string> = {
const FILE_INPUT_TYPES = new Set(['file-list', 'file'])
const WORKFLOW_FILE_VAR_TYPES = new Set([InputVarType.multiFiles, InputVarType.singleFile])
type InputSchemaItem = {
label?: string
variable?: string
@ -95,7 +93,8 @@ function mapWorkflowVariable(
variable: Record<string, unknown>,
fileUploadConfig?: FileUploadConfigResponse,
): InputSchemaItem {
const needsFileConfig = WORKFLOW_FILE_VAR_TYPES.has(variable.type as InputVarType)
const varType = variable.type
const needsFileConfig = varType === InputVarType.multiFiles || varType === InputVarType.singleFile
return {
...variable,

View File

@ -216,18 +216,30 @@ const ReasoningConfigForm: React.FC<Props> = ({
return VarType.string
}
const getFilterVar = () => {
if (isNumber)
if (isNumber) {
return (varPayload: Var) => varPayload.type === VarType.number
else if (isString)
return (varPayload: Var) => [VarType.string, VarType.number, VarType.secret].includes(varPayload.type)
else if (isFile)
return (varPayload: Var) => [VarType.file, VarType.arrayFile].includes(varPayload.type)
else if (isBoolean)
}
else if (isString) {
return (varPayload: Var) => ([VarType.string, VarType.number, VarType.secret] as const).includes(
varPayload.type as typeof VarType.string | typeof VarType.number | typeof VarType.secret,
)
}
else if (isFile) {
return (varPayload: Var) => ([VarType.file, VarType.arrayFile] as const).includes(
varPayload.type as typeof VarType.file | typeof VarType.arrayFile,
)
}
else if (isBoolean) {
return (varPayload: Var) => varPayload.type === VarType.boolean
else if (isObject)
}
else if (isObject) {
return (varPayload: Var) => varPayload.type === VarType.object
else if (isArray)
return (varPayload: Var) => [VarType.array, VarType.arrayString, VarType.arrayNumber, VarType.arrayObject].includes(varPayload.type)
}
else if (isArray) {
return (varPayload: Var) => ([VarType.array, VarType.arrayString, VarType.arrayNumber, VarType.arrayObject] as const).includes(
varPayload.type as typeof VarType.array | typeof VarType.arrayString | typeof VarType.arrayNumber | typeof VarType.arrayObject,
)
}
return undefined
}

View File

@ -15,9 +15,15 @@ import { produce } from 'immer'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Input from '@/app/components/base/input'
import { SimpleSelect } from '@/app/components/base/select'
import Switch from '@/app/components/base/switch'
import Tooltip from '@/app/components/base/tooltip'
import Tooltip from '@/app/components/base/tooltip-plus'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/app/components/base/ui/select'
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
import AppSelector from '@/app/components/plugins/plugin-detail-panel/app-selector'
@ -293,18 +299,26 @@ const ReasoningConfigForm: React.FC<Props> = ({
/>
)}
{isSelect && (
<SimpleSelect
wrapperClassName="h-8 grow"
defaultValue={varInput?.value}
items={options.filter((option: { show_on: any[] }) => {
if (option.show_on.length)
return option.show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value)
<Select
value={varInput?.value === undefined || varInput?.value === null ? '' : String(varInput.value)}
onValueChange={v => handleValueChange(variable, type)(v)}
>
<SelectTrigger className="h-8 grow">
<SelectValue placeholder={placeholder?.[language] || placeholder?.en_US} />
</SelectTrigger>
<SelectContent>
{options.filter((option: { show_on: any[] }) => {
if (option.show_on.length)
return option.show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value)
return true
}).map((option: { value: any, label: { [x: string]: any, en_US: any } }) => ({ value: option.value, name: option.label[language] || option.label.en_US }))}
onSelect={item => handleValueChange(variable, type)(item.value as string)}
placeholder={placeholder?.[language] || placeholder?.en_US}
/>
return true
}).map((option: { value: any, label: { [x: string]: any, en_US: any } }) => (
<SelectItem key={String(option.value)} value={String(option.value)}>
{option.label[language] || option.label.en_US}
</SelectItem>
))}
</SelectContent>
</Select>
)}
{isShowJSONEditor && isConstant && (
<div className="mt-1 w-full">

View File

@ -1,10 +1,9 @@
'use client'
import type { FC } from 'react'
import type { SchemaRoot } from '@/app/components/workflow/nodes/llm/types'
import { RiCloseLine } from '@remixicon/react'
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import Modal from '@/app/components/base/modal'
import { Dialog, DialogCloseButton, DialogContent, DialogTitle } from '@/app/components/base/ui/dialog'
import VisualEditor from '@/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor'
import { MittProvider, VisualEditorContextProvider } from '@/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/context'
@ -23,38 +22,33 @@ const SchemaModal: FC<Props> = ({
}) => {
const { t } = useTranslation()
return (
<Modal
isShow={isShow}
onClose={onClose}
className="max-w-[960px] p-0"
wrapperClassName="z-[9999]"
>
<div className="pb-6">
{/* Header */}
<div className="relative flex p-6 pb-3 pr-14">
<div className="grow truncate text-text-primary title-2xl-semi-bold">
{t('nodes.agent.parameterSchema', { ns: 'workflow' })}
<Dialog open={isShow} onOpenChange={open => !open && onClose()}>
<DialogContent className="max-w-[960px] p-0">
<DialogCloseButton className="right-5 top-5 h-8 w-8 p-1.5" />
<div className="pb-6">
{/* Header */}
<div className="relative flex p-6 pb-3 pr-14">
<DialogTitle className="grow truncate text-text-primary title-2xl-semi-bold">
{t('nodes.agent.parameterSchema', { ns: 'workflow' })}
</DialogTitle>
</div>
<div className="absolute right-5 top-5 flex h-8 w-8 items-center justify-center p-1.5" onClick={onClose}>
<RiCloseLine className="h-[18px] w-[18px] text-text-tertiary" />
{/* Content */}
<div className="flex max-h-[700px] overflow-y-auto px-6 py-2">
<MittProvider>
<VisualEditorContextProvider>
<VisualEditor
className="w-full"
schema={schema}
rootName={rootName}
readOnly
>
</VisualEditor>
</VisualEditorContextProvider>
</MittProvider>
</div>
</div>
{/* Content */}
<div className="flex max-h-[700px] overflow-y-auto px-6 py-2">
<MittProvider>
<VisualEditorContextProvider>
<VisualEditor
className="w-full"
schema={schema}
rootName={rootName}
readOnly
>
</VisualEditor>
</VisualEditorContextProvider>
</MittProvider>
</div>
</div>
</Modal>
</DialogContent>
</Dialog>
)
}
export default React.memo(SchemaModal)

View File

@ -1,6 +1,7 @@
'use client'
import type { FC } from 'react'
import type { PluginDetail } from '@/app/components/plugins/types'
import type { ToolWithProvider } from '@/app/components/workflow/types'
import * as React from 'react'
import Divider from '@/app/components/base/divider'
@ -36,7 +37,7 @@ const ToolAuthorizationSection: FC<ToolAuthorizationSectionProps> = ({
provider: currentProvider.name,
category: AuthCategory.tool,
providerType: currentProvider.type,
detail: currentProvider as any,
detail: currentProvider as unknown as PluginDetail,
}}
credentialId={credentialId}
onAuthorizationItemClick={onAuthorizationItemClick}