diff --git a/web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/index.tsx b/web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/index.tsx index cc8e125e6b..bc181c8248 100644 --- a/web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/index.tsx +++ b/web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/index.tsx @@ -3,13 +3,13 @@ import s from './style.module.css' import cn from '@/utils/classnames' type ISliderProps = { - className?: string - value: number - max?: number - min?: number - step?: number - disabled?: boolean - onChange: (value: number) => void + readonly className?: string + readonly value: number + readonly max?: number + readonly min?: number + readonly step?: number + readonly disabled?: boolean + readonly onChange: (value: number) => void } const Slider: React.FC = ({ className, max, min, step, value, disabled, onChange }) => { diff --git a/web/app/components/base/input/index.tsx b/web/app/components/base/input/index.tsx index 881aa1d610..1b83f7ffec 100644 --- a/web/app/components/base/input/index.tsx +++ b/web/app/components/base/input/index.tsx @@ -21,7 +21,7 @@ export const inputVariants = cva( }, ) -export type InputProps = { +type BaseInputProps = { showLeftIcon?: boolean showClearIcon?: boolean onClear?: () => void @@ -31,28 +31,31 @@ export type InputProps = { styleCss?: CSSProperties unit?: string ref?: React.Ref -} & Omit, 'size'> & VariantProps +} + +export type InputProps = Readonly & Omit, 'size'> & VariantProps const removeLeadingZeros = (value: string) => value.replace(/^(-?)0+(?=\d)/, '$1') -const Input = ({ - size, - disabled, - destructive, - showLeftIcon, - showClearIcon, - onClear, - wrapperClassName, - className, - styleCss, - value, - placeholder, - onChange = noop, - onBlur = noop, - unit, - ref, - ...props -}: InputProps) => { +const Input: React.FC = (props: Readonly) => { + const { + size, + disabled, + destructive, + showLeftIcon, + showClearIcon, + onClear, + wrapperClassName, + className, + styleCss, + value, + placeholder, + onChange = noop, + onBlur = noop, + unit, + ref, + ...restProps + } = props const { t } = useTranslation() const handleNumberChange: ChangeEventHandler = (e) => { if (value === 0) { @@ -102,10 +105,10 @@ const Input = ({ ? (t('common.operation.search') || '') : (t('common.placeholder.input') || ''))} value={value} - onChange={props.type === 'number' ? handleNumberChange : onChange} - onBlur={props.type === 'number' ? handleNumberBlur : onBlur} + onChange={restProps.type === 'number' ? handleNumberChange : onChange} + onBlur={restProps.type === 'number' ? handleNumberBlur : onBlur} disabled={disabled} - {...props} + {...restProps} /> {showClearIcon && value && !disabled && !destructive && (
diff --git a/web/app/components/datasets/documents/detail/completed/common/tag.tsx b/web/app/components/datasets/documents/detail/completed/common/tag.tsx index 914f8dc61c..d595f2cbb9 100644 --- a/web/app/components/datasets/documents/detail/completed/common/tag.tsx +++ b/web/app/components/datasets/documents/detail/completed/common/tag.tsx @@ -1,7 +1,7 @@ import React from 'react' import cn from '@/utils/classnames' -const Tag = ({ text, className }: { text: string; className?: string }) => { +const Tag = ({ text, className }: { readonly text: string; readonly className?: string }) => { return (
# diff --git a/web/app/components/header/account-about/index.tsx b/web/app/components/header/account-about/index.tsx index 975558cae7..cdb3d134a8 100644 --- a/web/app/components/header/account-about/index.tsx +++ b/web/app/components/header/account-about/index.tsx @@ -12,8 +12,8 @@ import DifyLogo from '@/app/components/base/logo/dify-logo' import { useGlobalPublicStore } from '@/context/global-public-context' type IAccountSettingProps = { - langGeniusVersionInfo: LangGeniusVersionResponse - onCancel: () => void + readonly langGeniusVersionInfo: LangGeniusVersionResponse + readonly onCancel: () => void } export default function AccountAbout({ diff --git a/web/app/components/workflow/custom-edge-linear-gradient-render.tsx b/web/app/components/workflow/custom-edge-linear-gradient-render.tsx index b799bb36b2..beb24ecc8b 100644 --- a/web/app/components/workflow/custom-edge-linear-gradient-render.tsx +++ b/web/app/components/workflow/custom-edge-linear-gradient-render.tsx @@ -1,12 +1,12 @@ type CustomEdgeLinearGradientRenderProps = { - id: string - startColor: string - stopColor: string - position: { - x1: number - x2: number - y1: number - y2: number + readonly id: string + readonly startColor: string + readonly stopColor: string + readonly position: { + readonly x1: number + readonly x2: number + readonly y1: number + readonly y2: number } } const CustomEdgeLinearGradientRender = ({ diff --git a/web/app/components/workflow/custom-edge.tsx b/web/app/components/workflow/custom-edge.tsx index c38b0ef47d..1f5792365f 100644 --- a/web/app/components/workflow/custom-edge.tsx +++ b/web/app/components/workflow/custom-edge.tsx @@ -28,6 +28,7 @@ import CustomEdgeLinearGradientRender from './custom-edge-linear-gradient-render import cn from '@/utils/classnames' import { ErrorHandleTypeEnum } from '@/app/components/workflow/nodes/_base/components/error-handle/types' +// eslint-disable-next-line @eslint-react/prefer-read-only-props const CustomEdge = ({ id, data, diff --git a/web/app/components/workflow/nodes/_base/components/readonly-input-with-select-var.tsx b/web/app/components/workflow/nodes/_base/components/readonly-input-with-select-var.tsx index c1927011dc..aa5c3784f1 100644 --- a/web/app/components/workflow/nodes/_base/components/readonly-input-with-select-var.tsx +++ b/web/app/components/workflow/nodes/_base/components/readonly-input-with-select-var.tsx @@ -9,9 +9,9 @@ import { VariableLabelInText, } from '@/app/components/workflow/nodes/_base/components/variable/variable-label' type Props = { - nodeId: string - value: string - className?: string + readonly nodeId: string + readonly value: string + readonly className?: string } const VAR_PLACEHOLDER = '@#!@#!' diff --git a/web/app/components/workflow/nodes/agent/components/tool-icon.tsx b/web/app/components/workflow/nodes/agent/components/tool-icon.tsx index 8e6993a78d..57ebab7aea 100644 --- a/web/app/components/workflow/nodes/agent/components/tool-icon.tsx +++ b/web/app/components/workflow/nodes/agent/components/tool-icon.tsx @@ -11,8 +11,8 @@ import AppIcon from '@/app/components/base/app-icon' type Status = 'not-installed' | 'not-authorized' | undefined export type ToolIconProps = { - id: string - providerName: string + readonly id: string + readonly providerName: string } export const ToolIcon = memo(({ providerName }: ToolIconProps) => { diff --git a/web/app/components/workflow/operator/add-block.tsx b/web/app/components/workflow/operator/add-block.tsx index 3c11dbac32..4dbafd78e7 100644 --- a/web/app/components/workflow/operator/add-block.tsx +++ b/web/app/components/workflow/operator/add-block.tsx @@ -29,8 +29,8 @@ import { } from '@/app/components/workflow/types' type AddBlockProps = { - renderTrigger?: (open: boolean) => React.ReactNode - offset?: OffsetOptions + readonly renderTrigger?: (open: boolean) => React.ReactNode + readonly offset?: OffsetOptions } const AddBlock = ({ renderTrigger, diff --git a/web/app/components/workflow/operator/index.tsx b/web/app/components/workflow/operator/index.tsx index 1100a7a905..1780af4efb 100644 --- a/web/app/components/workflow/operator/index.tsx +++ b/web/app/components/workflow/operator/index.tsx @@ -7,8 +7,8 @@ import VariableInspectPanel from '../variable-inspect' import { useStore } from '../store' export type OperatorProps = { - handleUndo: () => void - handleRedo: () => void + readonly handleUndo: () => void + readonly handleRedo: () => void } const Operator = ({ handleUndo, handleRedo }: OperatorProps) => { diff --git a/web/app/components/workflow/operator/tip-popup.tsx b/web/app/components/workflow/operator/tip-popup.tsx index 3721ed8118..6db862de35 100644 --- a/web/app/components/workflow/operator/tip-popup.tsx +++ b/web/app/components/workflow/operator/tip-popup.tsx @@ -3,9 +3,9 @@ import ShortcutsName from '../shortcuts-name' import Tooltip from '@/app/components/base/tooltip' type TipPopupProps = { - title: string - children: React.ReactNode - shortcuts?: string[] + readonly title: string + readonly children: React.ReactNode + readonly shortcuts?: string[] } const TipPopup = ({ title, diff --git a/web/app/components/workflow/shortcuts-name.tsx b/web/app/components/workflow/shortcuts-name.tsx index e7122c5ad5..8b4d8be0ac 100644 --- a/web/app/components/workflow/shortcuts-name.tsx +++ b/web/app/components/workflow/shortcuts-name.tsx @@ -3,8 +3,8 @@ import { getKeyboardKeyNameBySystem } from './utils' import cn from '@/utils/classnames' type ShortcutsNameProps = { - keys: string[] - className?: string + readonly keys: string[] + readonly className?: string } const ShortcutsName = ({ keys, diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs index 67b561cec0..897813276a 100644 --- a/web/eslint.config.mjs +++ b/web/eslint.config.mjs @@ -10,6 +10,7 @@ import reactHooks from 'eslint-plugin-react-hooks' import sonar from 'eslint-plugin-sonarjs' import oxlint from 'eslint-plugin-oxlint' import next from '@next/eslint-plugin-next' +import eslintReact from '@eslint-react/eslint-plugin' // import reactRefresh from 'eslint-plugin-react-refresh' @@ -144,6 +145,22 @@ export default combine( 'react-hooks': reactHooks, }, }, + // eslint-react + { + files: ['**/*.{ts,tsx}'], + plugins: { + '@eslint-react': eslintReact, + }, + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + }, + rules: { + '@eslint-react/prefer-read-only-props': 'error', + }, + }, // sonar { rules: {