diff --git a/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout-main.tsx b/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout-main.tsx
index d70179266..f8189b0c8 100644
--- a/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout-main.tsx
+++ b/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout-main.tsx
@@ -4,7 +4,6 @@ import React, { useEffect, useMemo } from 'react'
import { usePathname } from 'next/navigation'
import useSWR from 'swr'
import { useTranslation } from 'react-i18next'
-import { useBoolean } from 'ahooks'
import {
RiEqualizer2Fill,
RiEqualizer2Line,
@@ -44,17 +43,12 @@ type IExtraInfoProps = {
}
const ExtraInfo = ({ isMobile, relatedApps, expand }: IExtraInfoProps) => {
- const [isShowTips, { toggle: toggleTips, set: setShowTips }] = useBoolean(!isMobile)
const { t } = useTranslation()
const docLink = useDocLink()
const hasRelatedApps = relatedApps?.data && relatedApps?.data?.length > 0
const relatedAppsTotal = relatedApps?.data?.length || 0
- useEffect(() => {
- setShowTips(!isMobile)
- }, [isMobile, setShowTips])
-
return
{/* Related apps for desktop */}
= ({
const { data: embeddingsModelList } = useModelList(ModelTypeEnum.textEmbedding)
const {
modelList: rerankModelList,
- defaultModel: rerankDefaultModel,
- currentModel: isRerankDefaultModelValid,
} = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank)
const { t } = useTranslation()
const docLink = useDocLink()
diff --git a/web/app/components/base/markdown-blocks/code-block.tsx b/web/app/components/base/markdown-blocks/code-block.tsx
index c88cfde9e..48de8bf4a 100644
--- a/web/app/components/base/markdown-blocks/code-block.tsx
+++ b/web/app/components/base/markdown-blocks/code-block.tsx
@@ -81,7 +81,6 @@ const CodeBlock: any = memo(({ inline, className, children = '', ...props }: any
const echartsRef = useRef
(null)
const contentRef = useRef('')
const processedRef = useRef(false) // Track if content was successfully processed
- const instanceIdRef = useRef(`chart-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`) // Unique ID for logging
const isInitialRenderRef = useRef(true) // Track if this is initial render
const chartInstanceRef = useRef(null) // Direct reference to ECharts instance
const resizeTimerRef = useRef(null) // For debounce handling
diff --git a/web/app/components/base/mermaid/index.tsx b/web/app/components/base/mermaid/index.tsx
index a953ef15a..80271bb29 100644
--- a/web/app/components/base/mermaid/index.tsx
+++ b/web/app/components/base/mermaid/index.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import React, { useCallback, useEffect, useRef, useState } from 'react'
import mermaid, { type MermaidConfig } from 'mermaid'
import { useTranslation } from 'react-i18next'
import { ExclamationTriangleIcon } from '@heroicons/react/24/outline'
@@ -122,14 +122,6 @@ const Flowchart = React.forwardRef((props: {
const renderTimeoutRef = useRef()
const [errMsg, setErrMsg] = useState('')
const [imagePreviewUrl, setImagePreviewUrl] = useState('')
- const [isCodeComplete, setIsCodeComplete] = useState(false)
- const codeCompletionCheckRef = useRef()
- const prevCodeRef = useRef()
-
- // Create cache key from code, style and theme
- const cacheKey = useMemo(() => {
- return `${props.PrimitiveCode}-${look}-${currentTheme}`
- }, [props.PrimitiveCode, look, currentTheme])
/**
* Renders Mermaid chart
@@ -537,11 +529,9 @@ const Flowchart = React.forwardRef((props: {
{isLoading && !svgString && (
- {!isCodeComplete && (
{t('common.wait_for_completion', 'Waiting for diagram code to complete...')}
- )}
)}
diff --git a/web/app/components/datasets/external-api/external-api-modal/Form.tsx b/web/app/components/datasets/external-api/external-api-modal/Form.tsx
index 8884cb787..5479f8147 100644
--- a/web/app/components/datasets/external-api/external-api-modal/Form.tsx
+++ b/web/app/components/datasets/external-api/external-api-modal/Form.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react'
+import React from 'react'
import type { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { RiBookOpenLine } from '@remixicon/react'
@@ -28,10 +28,8 @@ const Form: FC = React.memo(({
}) => {
const { t, i18n } = useTranslation()
const docLink = useDocLink()
- const [changeKey, setChangeKey] = useState('')
const handleFormChange = (key: string, val: string) => {
- setChangeKey(key)
if (key === 'name') {
onChange({ ...value, [key]: val })
}
diff --git a/web/app/components/datasets/rename-modal/index.tsx b/web/app/components/datasets/rename-modal/index.tsx
index dd53bafdd..c497dbb95 100644
--- a/web/app/components/datasets/rename-modal/index.tsx
+++ b/web/app/components/datasets/rename-modal/index.tsx
@@ -28,8 +28,8 @@ const RenameDatasetModal = ({ show, dataset, onSuccess, onClose }: RenameDataset
const [loading, setLoading] = useState(false)
const [name, setName] = useState(dataset.name)
const [description, setDescription] = useState(dataset.description)
- const [externalKnowledgeId, setExternalKnowledgeId] = useState(dataset.external_knowledge_info.external_knowledge_id)
- const [externalKnowledgeApiId, setExternalKnowledgeApiId] = useState(dataset.external_knowledge_info.external_knowledge_api_id)
+ const externalKnowledgeId = dataset.external_knowledge_info.external_knowledge_id
+ const externalKnowledgeApiId = dataset.external_knowledge_info.external_knowledge_api_id
const onConfirm: MouseEventHandler = async () => {
if (!name.trim()) {
diff --git a/web/app/components/explore/app-list/index.tsx b/web/app/components/explore/app-list/index.tsx
index 7e2d990bc..79cbff81c 100644
--- a/web/app/components/explore/app-list/index.tsx
+++ b/web/app/components/explore/app-list/index.tsx
@@ -51,7 +51,6 @@ const Apps = ({
handleSearch()
}
- const [currentType, setCurrentType] = useState('')
const [currCategory, setCurrCategory] = useTabSearchParams({
defaultTab: allCategoriesEn,
disableSearchParams: false,
@@ -74,28 +73,7 @@ const Apps = ({
},
)
- const filteredList = useMemo(() => {
- if (currCategory === allCategoriesEn) {
- if (!currentType)
- return allList
- else if (currentType === 'chatbot')
- return allList.filter(item => (item.app.mode === 'chat' || item.app.mode === 'advanced-chat'))
- else if (currentType === 'agent')
- return allList.filter(item => (item.app.mode === 'agent-chat'))
- else
- return allList.filter(item => (item.app.mode === 'workflow'))
- }
- else {
- if (!currentType)
- return allList.filter(item => item.category === currCategory)
- else if (currentType === 'chatbot')
- return allList.filter(item => (item.app.mode === 'chat' || item.app.mode === 'advanced-chat') && item.category === currCategory)
- else if (currentType === 'agent')
- return allList.filter(item => (item.app.mode === 'agent-chat') && item.category === currCategory)
- else
- return allList.filter(item => (item.app.mode === 'workflow') && item.category === currCategory)
- }
- }, [currentType, currCategory, allCategoriesEn, allList])
+ const filteredList = allList.filter(item => currCategory === allCategoriesEn || item.category === currCategory)
const searchFilteredList = useMemo(() => {
if (!searchKeywords || !filteredList || filteredList.length === 0)
diff --git a/web/app/components/explore/sidebar/index.tsx b/web/app/components/explore/sidebar/index.tsx
index 74c397f4f..c5866c31d 100644
--- a/web/app/components/explore/sidebar/index.tsx
+++ b/web/app/components/explore/sidebar/index.tsx
@@ -49,7 +49,6 @@ const SideBar: FC = ({
const segments = useSelectedLayoutSegments()
const lastSegment = segments.slice(-1)[0]
const isDiscoverySelected = lastSegment === 'apps'
- const isChatSelected = lastSegment === 'chat'
const { installedApps, setInstalledApps, setIsFetchingInstalledApps } = useContext(ExploreContext)
const { isFetching: isFetchingInstalledApps, data: ret, refetch: fetchInstalledAppList } = useGetInstalledApps()
const { mutateAsync: uninstallApp } = useUninstallApp()
diff --git a/web/app/components/header/account-setting/members-page/invited-modal/invitation-link.tsx b/web/app/components/header/account-setting/members-page/invited-modal/invitation-link.tsx
index 68a575f50..a94ef4584 100644
--- a/web/app/components/header/account-setting/members-page/invited-modal/invitation-link.tsx
+++ b/web/app/components/header/account-setting/members-page/invited-modal/invitation-link.tsx
@@ -1,11 +1,10 @@
'use client'
-import React, { useCallback, useEffect, useRef, useState } from 'react'
+import React, { useCallback, useEffect, useState } from 'react'
import { t } from 'i18next'
import copy from 'copy-to-clipboard'
import s from './index.module.css'
import type { SuccessInvitationResult } from '.'
import Tooltip from '@/app/components/base/tooltip'
-import { randomString } from '@/utils'
type IInvitationLinkProps = {
value: SuccessInvitationResult
@@ -15,7 +14,6 @@ const InvitationLink = ({
value,
}: IInvitationLinkProps) => {
const [isCopied, setIsCopied] = useState(false)
- const selector = useRef(`invite-link-${randomString(4)}`)
const copyHandle = useCallback(() => {
// No prefix is needed here because the backend has already processed it
diff --git a/web/app/components/header/account-setting/model-provider-page/model-parameter-modal/parameter-item.tsx b/web/app/components/header/account-setting/model-provider-page/model-parameter-modal/parameter-item.tsx
index 3e969d708..7cfb90620 100644
--- a/web/app/components/header/account-setting/model-provider-page/model-parameter-modal/parameter-item.tsx
+++ b/web/app/components/header/account-setting/model-provider-page/model-parameter-modal/parameter-item.tsx
@@ -1,7 +1,6 @@
import type { FC } from 'react'
import { useEffect, useRef, useState } from 'react'
import type { ModelParameterRule } from '../declarations'
-import { useLanguage } from '../hooks'
import { isNullOrUndefined } from '../utils'
import cn from '@/utils/classnames'
import Switch from '@/app/components/base/switch'
@@ -10,7 +9,6 @@ import Slider from '@/app/components/base/slider'
import Radio from '@/app/components/base/radio'
import { SimpleSelect } from '@/app/components/base/select'
import TagInput from '@/app/components/base/tag-input'
-import { useTranslation } from 'react-i18next'
export type ParameterValue = number | string | string[] | boolean | undefined
@@ -28,8 +26,6 @@ const ParameterItem: FC = ({
onSwitch,
isInWorkflow,
}) => {
- const { t } = useTranslation()
- const language = useLanguage()
const [localValue, setLocalValue] = useState(value)
const numberInputRef = useRef(null)
diff --git a/web/app/components/plugins/marketplace/search-box/tags-filter.tsx b/web/app/components/plugins/marketplace/search-box/tags-filter.tsx
index bae649172..12b84490a 100644
--- a/web/app/components/plugins/marketplace/search-box/tags-filter.tsx
+++ b/web/app/components/plugins/marketplace/search-box/tags-filter.tsx
@@ -30,7 +30,7 @@ const TagsFilter = ({
const { t } = useMixedTranslation(locale)
const [open, setOpen] = useState(false)
const [searchText, setSearchText] = useState('')
- const { tags: options, tagsMap } = useTags(t)
+ const { tags: options } = useTags(t)
const filteredOptions = options.filter(option => option.label.toLowerCase().includes(searchText.toLowerCase()))
const handleCheck = (id: string) => {
if (tags.includes(id))
@@ -38,7 +38,6 @@ const TagsFilter = ({
else
onTagsChange([...tags, id])
}
- const selectedTagsLength = tags.length
return (
{
}
export const getMarketplacePluginsByCollectionId = async (collectionId: string, query?: CollectionsAndPluginsSearchParams) => {
- let plugins = [] as Plugin[]
+ let plugins: Plugin[]
try {
const url = `${MARKETPLACE_API_PREFIX}/collections/${collectionId}/plugins`
diff --git a/web/app/components/share/text-generation/index.tsx b/web/app/components/share/text-generation/index.tsx
index 4a6d1c996..da5b09b06 100644
--- a/web/app/components/share/text-generation/index.tsx
+++ b/web/app/components/share/text-generation/index.tsx
@@ -151,10 +151,9 @@ const TextGeneration: FC = ({
const pendingTaskList = allTaskList.filter(task => task.status === TaskStatus.pending)
const noPendingTask = pendingTaskList.length === 0
const showTaskList = allTaskList.filter(task => task.status !== TaskStatus.pending)
- const [currGroupNum, doSetCurrGroupNum] = useState(0)
const currGroupNumRef = useRef(0)
+
const setCurrGroupNum = (num: number) => {
- doSetCurrGroupNum(num)
currGroupNumRef.current = num
}
const getCurrGroupNum = () => {
@@ -164,10 +163,8 @@ const TextGeneration: FC = ({
const allFailedTaskList = allTaskList.filter(task => task.status === TaskStatus.failed)
const allTasksFinished = allTaskList.every(task => task.status === TaskStatus.completed)
const allTasksRun = allTaskList.every(task => [TaskStatus.completed, TaskStatus.failed].includes(task.status))
- const [batchCompletionRes, doSetBatchCompletionRes] = useState>({})
const batchCompletionResRef = useRef>({})
const setBatchCompletionRes = (res: Record) => {
- doSetBatchCompletionRes(res)
batchCompletionResRef.current = res
}
const getBatchCompletionRes = () => batchCompletionResRef.current
diff --git a/web/app/components/workflow/block-selector/use-sticky-scroll.ts b/web/app/components/workflow/block-selector/use-sticky-scroll.ts
index 405ecdba7..c828e9ce9 100644
--- a/web/app/components/workflow/block-selector/use-sticky-scroll.ts
+++ b/web/app/components/workflow/block-selector/use-sticky-scroll.ts
@@ -23,7 +23,7 @@ const useStickyScroll = ({
return
const { height: wrapHeight, top: wrapTop } = wrapDom.getBoundingClientRect()
const { top: nextToStickyTop } = stickyDOM.getBoundingClientRect()
- let scrollPositionNew = ScrollPosition.belowTheWrap
+ let scrollPositionNew: ScrollPosition
if (nextToStickyTop - wrapTop >= wrapHeight)
scrollPositionNew = ScrollPosition.belowTheWrap
diff --git a/web/app/components/workflow/hooks/use-workflow.ts b/web/app/components/workflow/hooks/use-workflow.ts
index f9120f45b..a6435ec63 100644
--- a/web/app/components/workflow/hooks/use-workflow.ts
+++ b/web/app/components/workflow/hooks/use-workflow.ts
@@ -444,7 +444,7 @@ export const useFetchToolsData = () => {
workflowTools: workflowTools || [],
})
}
- if(type === 'mcp') {
+ if (type === 'mcp') {
const mcpTools = await fetchAllMCPTools()
workflowStore.setState({
@@ -500,18 +500,17 @@ export const useToolIcon = (data: Node['data']) => {
const mcpTools = useStore(s => s.mcpTools)
const toolIcon = useMemo(() => {
- if(!data)
+ if (!data)
return ''
if (data.type === BlockEnum.Tool) {
- let targetTools = buildInTools
+ let targetTools = workflowTools
if (data.provider_type === CollectionType.builtIn)
targetTools = buildInTools
else if (data.provider_type === CollectionType.custom)
targetTools = customTools
else if (data.provider_type === CollectionType.mcp)
targetTools = mcpTools
- else
- targetTools = workflowTools
+
return targetTools.find(toolWithProvider => canFindTool(toolWithProvider.id, data.provider_id))?.icon
}
}, [data, buildInTools, customTools, mcpTools, workflowTools])
diff --git a/web/app/components/workflow/nodes/_base/components/node-control.tsx b/web/app/components/workflow/nodes/_base/components/node-control.tsx
index 5b92b7b6b..0e3f54f10 100644
--- a/web/app/components/workflow/nodes/_base/components/node-control.tsx
+++ b/web/app/components/workflow/nodes/_base/components/node-control.tsx
@@ -11,7 +11,6 @@ import {
import {
useNodeDataUpdate,
useNodesInteractions,
- useNodesSyncDraft,
} from '../../../hooks'
import { type Node, NodeRunningStatus } from '../../../types'
import { canRunBySingle } from '../../../utils'
@@ -30,7 +29,6 @@ const NodeControl: FC = ({
const [open, setOpen] = useState(false)
const { handleNodeDataUpdate } = useNodeDataUpdate()
const { handleNodeSelect } = useNodesInteractions()
- const { handleSyncWorkflowDraft } = useNodesSyncDraft()
const isSingleRunning = data._singleRunningStatus === NodeRunningStatus.Running
const handleOpenChange = useCallback((newOpen: boolean) => {
setOpen(newOpen)
diff --git a/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx b/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx
index 93fab8317..4723b2dce 100644
--- a/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx
+++ b/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx
@@ -198,7 +198,6 @@ const BasePanel: FC = ({
isShowSingleRun,
hideSingleRun,
runningStatus,
- handleStop,
runInputData,
runInputDataRef,
runResult,
diff --git a/web/app/components/workflow/nodes/list-operator/use-config.ts b/web/app/components/workflow/nodes/list-operator/use-config.ts
index efbf32b8c..21e976172 100644
--- a/web/app/components/workflow/nodes/list-operator/use-config.ts
+++ b/web/app/components/workflow/nodes/list-operator/use-config.ts
@@ -36,6 +36,7 @@ const useConfig = (id: string, payload: ListFilterNodeType) => {
const { inputs, setInputs } = useNodeCrud(id, payload)
const { getCurrentVariableType } = useWorkflowVariables()
+
const getType = useCallback((variable?: ValueSelector) => {
const varType = getCurrentVariableType({
parentNode: isInIteration ? iterationNode : loopNode,
@@ -44,7 +45,7 @@ const useConfig = (id: string, payload: ListFilterNodeType) => {
isChatMode,
isConstant: false,
})
- let itemVarType = VarType.string
+ let itemVarType = varType
switch (varType) {
case VarType.arrayNumber:
itemVarType = VarType.number
@@ -58,8 +59,6 @@ const useConfig = (id: string, payload: ListFilterNodeType) => {
case VarType.arrayObject:
itemVarType = VarType.object
break
- default:
- itemVarType = varType
}
return { varType, itemVarType }
}, [availableNodes, getCurrentVariableType, inputs.variable, isChatMode, isInIteration, iterationNode, loopNode])
diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs
index dda2beff0..747c14ad6 100644
--- a/web/eslint.config.mjs
+++ b/web/eslint.config.mjs
@@ -163,7 +163,7 @@ export default combine(
'sonarjs/single-char-in-character-classes': 'off',
'sonarjs/anchor-precedence': 'warn',
'sonarjs/updated-loop-counter': 'off',
- 'sonarjs/no-dead-store': 'warn',
+ 'sonarjs/no-dead-store': 'error',
'sonarjs/no-duplicated-branches': 'warn',
'sonarjs/max-lines': 'warn', // max 1000 lines
'sonarjs/no-variable-usage-before-declaration': 'error',