Compare commits

...

5 Commits

Author SHA1 Message Date
Asuka Minato
4df2d70d65 Merge branch 'main' into copilot/fix-fc039c44-aa24-4844-82b2-e9ac237a13e9 2025-10-11 03:01:39 +09:00
copilot-swe-agent[bot]
fdce781a11 Changes before error encountered
Co-authored-by: asukaminato0721 <30024051+asukaminato0721@users.noreply.github.com>
2025-09-27 18:36:13 +09:00
copilot-swe-agent[bot]
b81cafa6c3 Changes before error encountered
Co-authored-by: asukaminato0721 <30024051+asukaminato0721@users.noreply.github.com>
2025-09-27 18:36:13 +09:00
copilot-swe-agent[bot]
a259800fe4 Fix additional prefer-read-only-props violations in workflow and header components
Co-authored-by: asukaminato0721 <30024051+asukaminato0721@users.noreply.github.com>
2025-09-27 18:36:13 +09:00
copilot-swe-agent[bot]
d3554b76e9 Changes before error encountered
Co-authored-by: asukaminato0721 <30024051+asukaminato0721@users.noreply.github.com>
2025-09-27 18:36:13 +09:00
45 changed files with 163 additions and 140 deletions

View File

@@ -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<ISliderProps> = ({ className, max, min, step, value, disabled, onChange }) => {

View File

@@ -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<HTMLInputElement>
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> & VariantProps<typeof inputVariants>
}
export type InputProps = Readonly<BaseInputProps> & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> & VariantProps<typeof inputVariants>
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<InputProps> = (props: Readonly<InputProps>) => {
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<HTMLInputElement> = (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 && (
<div className={cn('group absolute right-2 top-1/2 -translate-y-1/2 cursor-pointer p-[1px]')} onClick={onClear}>

View File

@@ -10,8 +10,8 @@ import cn from '@/utils/classnames'
import GridMask from '@/app/components/base/grid-mask'
type Props = {
show: boolean
onHide: () => void
readonly show: boolean
readonly onHide: () => void
}
const AnnotationFullModal: FC<Props> = ({
show,

View File

@@ -7,7 +7,7 @@ import UsageInfo from '../usage-info'
import { useProviderContext } from '@/context/provider-context'
type Props = {
className?: string
readonly className?: string
}
const Usage: FC<Props> = ({

View File

@@ -15,7 +15,7 @@ import cn from '@/utils/classnames'
const LOW = 50
const MIDDLE = 80
const AppsFull: FC<{ loc: string; className?: string; }> = ({
const AppsFull: FC<{ readonly loc: string; readonly className?: string }> = ({
loc,
className,
}) => {

View File

@@ -7,8 +7,8 @@ import cn from '@/utils/classnames'
import { useProviderContext } from '@/context/provider-context'
type Props = {
onClick?: () => void
isDisplayOnly?: boolean
readonly onClick?: () => void
readonly isDisplayOnly?: boolean
}
const HeaderBillingBtn: FC<Props> = ({

View File

@@ -24,7 +24,7 @@ import { useModalContextSelector } from '@/context/modal-context'
import { Enterprise, Professional, Sandbox, Team } from './assets'
type Props = {
loc: string
readonly loc: string
}
const PlanComp: FC<Props> = ({

View File

@@ -1,5 +1,5 @@
type CloudProps = {
isActive: boolean
readonly isActive: boolean
}
const Cloud = ({

View File

@@ -1,5 +1,5 @@
type SelfHostedProps = {
isActive: boolean
readonly isActive: boolean
}
const SelfHosted = ({

View File

@@ -6,8 +6,8 @@ import { type Category, CategoryEnum } from '.'
import cn from '@/utils/classnames'
type FooterProps = {
pricingPageURL: string
currentCategory: Category
readonly pricingPageURL: string
readonly currentCategory: Category
}
const Footer = ({

View File

@@ -9,10 +9,10 @@ import type { PlanRange } from './plan-range-switcher'
import PlanRangeSwitcher from './plan-range-switcher'
type PlanSwitcherProps = {
currentCategory: Category
currentPlanRange: PlanRange
onChangeCategory: (category: Category) => void
onChangePlanRange: (value: PlanRange) => void
readonly currentCategory: Category
readonly currentPlanRange: PlanRange
readonly onChangeCategory: (category: Category) => void
readonly onChangePlanRange: (value: PlanRange) => void
}
const PlanSwitcher: FC<PlanSwitcherProps> = ({

View File

@@ -10,8 +10,8 @@ export enum PlanRange {
}
type PlanRangeSwitcherProps = {
value: PlanRange
onChange: (value: PlanRange) => void
readonly value: PlanRange
readonly onChange: (value: PlanRange) => void
}
const PlanRangeSwitcher: FC<PlanRangeSwitcherProps> = ({

View File

@@ -3,8 +3,8 @@ import { SelectionMod } from '../base/icons/src/public/knowledge'
import type { QA } from '@/models/datasets'
export type ChunkLabelProps = {
label: string
characterCount: number
readonly label: string
readonly characterCount: number
}
export const ChunkLabel: FC<ChunkLabelProps> = (props) => {

View File

@@ -6,8 +6,8 @@ import Badge from '@/app/components/base/badge'
import { GeneralChunk, ParentChildChunk } from '@/app/components/base/icons/src/vender/knowledge'
type Props = {
isGeneralMode: boolean
isQAMode: boolean
readonly isGeneralMode: boolean
readonly isQAMode: boolean
}
const ChunkingModeLabel: FC<Props> = ({

View File

@@ -2,10 +2,10 @@ import cn from '@/utils/classnames'
import React, { useCallback, useMemo, useState } from 'react'
type CredentialIconProps = {
avatar_url?: string
name: string
size?: number
className?: string
readonly avatar_url?: string
readonly name: string
readonly size?: number
readonly className?: string
}
const ICON_BG_COLORS = [

View File

@@ -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 (
<div className={cn('inline-flex items-center gap-x-0.5', className)}>
<span className='text-xs font-medium text-text-quaternary'>#</span>

View File

@@ -6,8 +6,8 @@ import CopyFeedback from '@/app/components/base/copy-feedback'
import SecretKeyButton from '@/app/components/develop/secret-key/secret-key-button'
type ApiServerProps = {
apiBaseUrl: string
appId?: string
readonly apiBaseUrl: string
readonly appId?: string
}
const ApiServer: FC<ApiServerProps> = ({
apiBaseUrl,

View File

@@ -3,18 +3,18 @@ import type { PropsWithChildren } from 'react'
import classNames from '@/utils/classnames'
type IChildrenProps = {
children: React.ReactNode
id?: string
tag?: any
label?: any
anchor: boolean
readonly children: React.ReactNode
readonly id?: string
readonly tag?: any
readonly label?: any
readonly anchor: boolean
}
type IHeaderingProps = {
url: string
method: 'PUT' | 'DELETE' | 'GET' | 'POST' | 'PATCH'
title: string
name: string
readonly url: string
readonly method: 'PUT' | 'DELETE' | 'GET' | 'POST' | 'PATCH'
readonly title: string
readonly name: string
}
export const Heading = function H2({
@@ -66,7 +66,7 @@ export function Row({ children }: IChildrenProps) {
}
type IColProps = IChildrenProps & {
sticky: boolean
readonly sticky: boolean
}
export function Col({ children, sticky = false }: IColProps) {
return (
@@ -95,8 +95,8 @@ export function Properties({ children }: IChildrenProps) {
}
type IProperty = IChildrenProps & {
name: string
type: string
readonly name: string
readonly type: string
}
export function Property({ name, type, children }: IProperty) {
return (
@@ -120,8 +120,8 @@ export function Property({ name, type, children }: IProperty) {
}
type ISubProperty = IChildrenProps & {
name: string
type: string
readonly name: string
readonly type: string
}
export function SubProperty({ name, type, children }: ISubProperty) {
return (
@@ -144,7 +144,7 @@ export function SubProperty({ name, type, children }: ISubProperty) {
)
}
export function PropertyInstruction({ children }: PropsWithChildren<{}>) {
export function PropertyInstruction({ children }: Readonly<PropsWithChildren<{}>>) {
return (
<li className="m-0 px-0 py-4 italic first:pt-0">{children}</li>
)

View File

@@ -6,9 +6,9 @@ import Tooltip from '@/app/components/base/tooltip'
import CopyFeedback from '@/app/components/base/copy-feedback'
type IInputCopyProps = {
value?: string
className?: string
children?: React.ReactNode
readonly value?: string
readonly className?: string
readonly children?: React.ReactNode
}
const InputCopy = ({

View File

@@ -6,9 +6,9 @@ import Button from '@/app/components/base/button'
import SecretKeyModal from '@/app/components/develop/secret-key/secret-key-modal'
type ISecretKeyButtonProps = {
className?: string
appId?: string
textCls?: string
readonly className?: string
readonly appId?: string
readonly textCls?: string
}
const SecretKeyButton = ({ className, appId, textCls }: ISecretKeyButtonProps) => {

View File

@@ -41,9 +41,9 @@ const valueColorMap = {
} as { [key: string]: string }
type ITagProps = {
children: string
color?: string
variant?: string
readonly children: string
readonly color?: string
readonly variant?: string
}
export function Tag({

View File

@@ -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({

View File

@@ -26,7 +26,7 @@ enum DocName {
}
type UpgradeOrDownloadProps = {
doc_name: DocName
readonly doc_name: DocName
}
const UpgradeOrDownload: FC<UpgradeOrDownloadProps> = ({ doc_name }) => {
const { t } = useTranslation()

View File

@@ -7,7 +7,7 @@ import classNames from '@/utils/classnames'
import type { AppDetailResponse } from '@/models/app'
type IAppBackProps = {
curApp: AppDetailResponse
readonly curApp: AppDetailResponse
}
export default function AppBack({ curApp }: IAppBackProps) {
const { t } = useTranslation()

View File

@@ -12,8 +12,8 @@ import { useAppContext } from '@/context/app-context'
import { noop } from 'lodash-es'
type IAppSelectorProps = {
appItems: AppDetailResponse[]
curApp: AppDetailResponse
readonly appItems: AppDetailResponse[]
readonly curApp: AppDetailResponse
}
export default function AppSelector({ appItems, curApp }: IAppSelectorProps) {

View File

@@ -6,7 +6,7 @@ import { useEventEmitterContextContext } from '@/context/event-emitter'
import classNames from '@/utils/classnames'
type HeaderWrapperProps = {
children: React.ReactNode
readonly children: React.ReactNode
}
const HeaderWrapper = ({

View File

@@ -3,8 +3,8 @@
import classNames from '@/utils/classnames'
export type IndicatorProps = {
color?: 'green' | 'orange' | 'red' | 'blue' | 'yellow' | 'gray'
className?: string
readonly color?: 'green' | 'orange' | 'red' | 'blue' | 'yellow' | 'gray'
readonly className?: string
}
export type ColorMap = {

View File

@@ -9,10 +9,10 @@ import PremiumBadge from '../../base/premium-badge'
import { Plan } from '../../billing/type'
type PlanBadgeProps = {
plan: Plan
allowHover?: boolean
sandboxAsUpgrade?: boolean
onClick?: () => void
readonly plan: Plan
readonly allowHover?: boolean
readonly sandboxAsUpgrade?: boolean
readonly onClick?: () => void
}
const PlanBadge: FC<PlanBadgeProps> = ({ plan, allowHover, sandboxAsUpgrade = false, onClick }) => {

View File

@@ -10,7 +10,7 @@ import type { ToolWithProvider } from '@/app/components/workflow/types'
import cn from '@/utils/classnames'
type Props = {
searchText: string
readonly searchText: string
}
function renderDefaultCard() {

View File

@@ -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 = ({

View File

@@ -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,

View File

@@ -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 = '@#!@#!'

View File

@@ -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) => {

View File

@@ -11,6 +11,7 @@ import { FormTypeEnum } from '@/app/components/header/account-setting/model-prov
import { useRenderI18nObject } from '@/hooks/use-i18n'
import { ModelBar } from './components/model-bar'
// eslint-disable-next-line @eslint-react/prefer-read-only-props
const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => {
const { inputs, currentStrategy, currentStrategyStatus, pluginDetail } = useConfig(props.id, props.data)
const renderI18nObject = useRenderI18nObject()

View File

@@ -25,6 +25,7 @@ export function strategyParamToCredientialForm(param: StrategyParamItem): Creden
}
}
// eslint-disable-next-line @eslint-react/prefer-read-only-props
const AgentPanel: FC<NodePanelProps<AgentNodeType>> = (props) => {
const {
inputs,

View File

@@ -2,10 +2,10 @@ import React, { type FC } from 'react'
import { useTranslation } from 'react-i18next'
type CardProps = {
name: string
type: string
required: boolean
description?: string
readonly name: string
readonly type: string
readonly required: boolean
readonly description?: string
}
const Card: FC<CardProps> = ({

View File

@@ -13,13 +13,13 @@ import AddField from './add-field'
import { JSON_SCHEMA_MAX_DEPTH } from '@/config'
type SchemaNodeProps = {
name: string
required: boolean
schema: Field
path: string[]
parentPath?: string[]
depth: number
readOnly?: boolean
readonly name: string
readonly required: boolean
readonly schema: Field
readonly path: string[]
readonly parentPath?: string[]
readonly depth: number
readonly readOnly?: boolean
}
// Support 10 levels of indentation

View File

@@ -12,12 +12,12 @@ import type { ModelConfig } from '@/app/components/workflow/types'
import { useHooksStore } from '../../../hooks-store'
type Props = {
className?: string
onGenerated?: (prompt: string) => void
modelConfig?: ModelConfig
nodeId: string
editorId?: string
currentPrompt?: string
readonly className?: string
readonly onGenerated?: (prompt: string) => void
readonly modelConfig?: ModelConfig
readonly nodeId: string
readonly editorId?: string
readonly currentPrompt?: string
}
const PromptGeneratorBtn: FC<Props> = ({

View File

@@ -5,9 +5,9 @@ import Field from '@/app/components/workflow/nodes/_base/components/field'
import Switch from '@/app/components/base/switch'
type ReasoningFormatConfigProps = {
value?: 'tagged' | 'separated'
onChange: (value: 'tagged' | 'separated') => void
readonly?: boolean
readonly value?: 'tagged' | 'separated'
readonly onChange: (value: 'tagged' | 'separated') => void
readonly readonly?: boolean
}
const ReasoningFormatConfig: FC<ReasoningFormatConfigProps> = ({

View File

@@ -8,8 +8,8 @@ import { Resolution } from '@/types/app'
const i18nPrefix = 'workflow.nodes.llm'
type Props = {
value: Resolution
onChange: (value: Resolution) => void
readonly value: Resolution
readonly onChange: (value: Resolution) => void
}
const ResolutionPicker: FC<Props> = ({

View File

@@ -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,

View File

@@ -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) => {

View File

@@ -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,

View File

@@ -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,

View File

@@ -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: {