refactor & perf: import { noop } from 'lodash-es' across web (#17439)

This commit is contained in:
yusheng chen
2025-04-06 17:56:08 +08:00
committed by GitHub
parent 7016ccef10
commit c05e03fc09
87 changed files with 271 additions and 184 deletions

View File

@@ -15,6 +15,7 @@ import getCroppedImg from './utils'
import type { AppIconType, ImageFile } from '@/types/app'
import cn from '@/utils/classnames'
import { DISABLE_UPLOAD_IMAGE_AS_ICON } from '@/config'
import { noop } from 'lodash-es'
export type AppIconEmojiSelection = {
type: 'emoji'
@@ -107,7 +108,7 @@ const AppIconPicker: FC<AppIconPickerProps> = ({
}
return <Modal
onClose={() => { }}
onClose={noop}
isShow
closable={false}
wrapperClassName={className}

View File

@@ -15,6 +15,7 @@ import type {
AppMeta,
ConversationItem,
} from '@/models/share'
import { noop } from 'lodash-es'
export type ChatWithHistoryContextValue = {
appInfoError?: any
@@ -65,29 +66,29 @@ export const ChatWithHistoryContext = createContext<ChatWithHistoryContextValue>
conversationList: [],
newConversationInputs: {},
newConversationInputsRef: { current: {} },
handleNewConversationInputsChange: () => {},
handleNewConversationInputsChange: noop,
inputsForms: [],
handleNewConversation: () => {},
handleStartChat: () => {},
handleChangeConversation: () => {},
handlePinConversation: () => {},
handleUnpinConversation: () => {},
handleDeleteConversation: () => {},
handleNewConversation: noop,
handleStartChat: noop,
handleChangeConversation: noop,
handlePinConversation: noop,
handleUnpinConversation: noop,
handleDeleteConversation: noop,
conversationRenaming: false,
handleRenameConversation: () => {},
handleNewConversationCompleted: () => {},
handleRenameConversation: noop,
handleNewConversationCompleted: noop,
chatShouldReloadKey: '',
isMobile: false,
isInstalledApp: false,
handleFeedback: () => {},
currentChatInstanceRef: { current: { handleStop: () => {} } },
handleFeedback: noop,
currentChatInstanceRef: { current: { handleStop: noop } },
sidebarCollapseState: false,
handleSidebarCollapse: () => {},
handleSidebarCollapse: noop,
clearChatList: false,
setClearChatList: () => {},
setClearChatList: noop,
isResponding: false,
setIsResponding: () => {},
setIsResponding: noop,
currentConversationInputs: {},
setCurrentConversationInputs: () => {},
setCurrentConversationInputs: noop,
})
export const useChatWithHistoryContext = () => useContext(ChatWithHistoryContext)

View File

@@ -42,6 +42,7 @@ import { changeLanguage } from '@/i18n/i18next-config'
import { useAppFavicon } from '@/hooks/use-app-favicon'
import { InputVarType } from '@/app/components/workflow/types'
import { TransferMethod } from '@/types/app'
import { noop } from 'lodash-es'
function getFormattedChatList(messages: any[]) {
const newChatList: ChatItem[] = []
@@ -318,7 +319,7 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
callback?.()
}
}, [setShowNewConversationItemInList, checkInputsRequired])
const currentChatInstanceRef = useRef<{ handleStop: () => void }>({ handleStop: () => { } })
const currentChatInstanceRef = useRef<{ handleStop: () => void }>({ handleStop: noop })
const handleChangeConversation = useCallback((conversationId: string) => {
currentChatInstanceRef.current.handleStop()
setNewConversationId('')

View File

@@ -14,6 +14,7 @@ import type {
AppMeta,
ConversationItem,
} from '@/models/share'
import { noop } from 'lodash-es'
export type EmbeddedChatbotContextValue = {
appInfoError?: any
@@ -57,22 +58,22 @@ export const EmbeddedChatbotContext = createContext<EmbeddedChatbotContextValue>
conversationList: [],
newConversationInputs: {},
newConversationInputsRef: { current: {} },
handleNewConversationInputsChange: () => {},
handleNewConversationInputsChange: noop,
inputsForms: [],
handleNewConversation: () => {},
handleStartChat: () => {},
handleChangeConversation: () => {},
handleNewConversationCompleted: () => {},
handleNewConversation: noop,
handleStartChat: noop,
handleChangeConversation: noop,
handleNewConversationCompleted: noop,
chatShouldReloadKey: '',
isMobile: false,
isInstalledApp: false,
handleFeedback: () => {},
currentChatInstanceRef: { current: { handleStop: () => {} } },
handleFeedback: noop,
currentChatInstanceRef: { current: { handleStop: noop } },
clearChatList: false,
setClearChatList: () => {},
setClearChatList: noop,
isResponding: false,
setIsResponding: () => {},
setIsResponding: noop,
currentConversationInputs: {},
setCurrentConversationInputs: () => {},
setCurrentConversationInputs: noop,
})
export const useEmbeddedChatbotContext = () => useContext(EmbeddedChatbotContext)

View File

@@ -35,6 +35,7 @@ import { changeLanguage } from '@/i18n/i18next-config'
import { InputVarType } from '@/app/components/workflow/types'
import { TransferMethod } from '@/types/app'
import { addFileInfos, sortAgentSorts } from '@/app/components/tools/utils'
import { noop } from 'lodash-es'
function getFormattedChatList(messages: any[]) {
const newChatList: ChatItem[] = []
@@ -294,7 +295,7 @@ export const useEmbeddedChatbot = () => {
callback?.()
}
}, [setShowNewConversationItemInList, checkInputsRequired])
const currentChatInstanceRef = useRef<{ handleStop: () => void }>({ handleStop: () => { } })
const currentChatInstanceRef = useRef<{ handleStop: () => void }>({ handleStop: noop })
const handleChangeConversation = useCallback((conversationId: string) => {
currentChatInstanceRef.current.handleStop()
setNewConversationId('')

View File

@@ -7,6 +7,7 @@ import cn from '@/utils/classnames'
import Divider from '@/app/components/base/divider'
import Button from '@/app/components/base/button'
import Modal from '@/app/components/base/modal'
import { noop } from 'lodash-es'
type IEmojiPickerProps = {
isModal?: boolean
@@ -32,7 +33,7 @@ const EmojiPicker: FC<IEmojiPickerProps> = ({
return isModal
? <Modal
onClose={() => { }}
onClose={noop}
isShow
closable={false}
wrapperClassName={className}

View File

@@ -14,6 +14,7 @@ import type { PromptVariable } from '@/models/debug'
import type { InputVar } from '@/app/components/workflow/types'
import { getNewVar } from '@/utils/var'
import cn from '@/utils/classnames'
import { noop } from 'lodash-es'
type OpeningSettingModalProps = {
data: OpeningStatement
@@ -171,7 +172,7 @@ const OpeningSettingModal = ({
return (
<Modal
isShow
onClose={() => { }}
onClose={noop}
className='!mt-14 !w-[640px] !max-w-none !bg-components-panel-bg-blur !p-6'
>
<div className='mb-6 flex items-center justify-between'>

View File

@@ -24,6 +24,7 @@ import { InfoCircle } from '@/app/components/base/icons/src/vender/line/general'
import { useModalContext } from '@/context/modal-context'
import { CustomConfigurationStatusEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import cn from '@/utils/classnames'
import { noop } from 'lodash-es'
const systemTypes = ['openai_moderation', 'keywords', 'api']
@@ -239,7 +240,7 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
return (
<Modal
isShow
onClose={() => { }}
onClose={noop}
className='!mt-14 !w-[600px] !max-w-none !p-6'
>
<div className='flex items-center justify-between'>

View File

@@ -28,6 +28,7 @@ import type { FileUpload } from '@/app/components/base/features/types'
import { formatFileSize } from '@/utils/format'
import { uploadRemoteFileInfo } from '@/service/common'
import type { FileUploadConfigResponse } from '@/models/common'
import { noop } from 'lodash-es'
export const useFileSizeLimit = (fileUploadConfig?: FileUploadConfigResponse) => {
const imgSizeLimit = Number(fileUploadConfig?.image_file_size_limit) * 1024 * 1024 || IMG_SIZE_LIMIT
@@ -243,9 +244,9 @@ export const useFile = (fileConfig: FileUpload) => {
})
}, [checkSizeLimit, handleAddFile, handleUpdateFile, notify, t, handleRemoveFile, fileConfig?.allowed_file_types, fileConfig.allowed_file_extensions, startProgressTimer, params.token])
const handleLoadFileFromLinkSuccess = useCallback(() => { }, [])
const handleLoadFileFromLinkSuccess = useCallback(noop, [])
const handleLoadFileFromLinkError = useCallback(() => { }, [])
const handleLoadFileFromLinkError = useCallback(noop, [])
const handleClearFiles = useCallback(() => {
const {

View File

@@ -9,6 +9,7 @@ import { useHotkeys } from 'react-hotkeys-hook'
import Loading from '@/app/components/base/loading'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import Tooltip from '@/app/components/base/tooltip'
import { noop } from 'lodash-es'
type PdfPreviewProps = {
url: string
@@ -65,8 +66,8 @@ const PdfPreview: FC<PdfPreviewProps> = ({
<PdfHighlighter
pdfDocument={pdfDocument}
enableAreaSelection={event => event.altKey}
scrollRef={() => { }}
onScrollChange={() => { }}
scrollRef={noop}
onScrollChange={noop}
onSelectionFinished={() => null}
highlightTransform={() => { return <div/> }}
highlights={[]}

View File

@@ -1,6 +1,7 @@
import { Dialog, DialogPanel, Transition, TransitionChild } from '@headlessui/react'
import { RiCloseLargeLine } from '@remixicon/react'
import classNames from '@/utils/classnames'
import { noop } from 'lodash-es'
type IModal = {
className?: string
@@ -18,7 +19,7 @@ export default function FullScreenModal({
className,
wrapperClassName,
open,
onClose = () => { },
onClose = noop,
children,
closable = false,
overflowVisible = false,

View File

@@ -6,6 +6,7 @@ import { RiAddBoxLine, RiCloseLine, RiDownloadCloud2Line, RiFileCopyLine, RiZoom
import { useHotkeys } from 'react-hotkeys-hook'
import Tooltip from '@/app/components/base/tooltip'
import Toast from '@/app/components/base/toast'
import { noop } from 'lodash-es'
type ImagePreviewProps = {
url: string
@@ -198,8 +199,8 @@ const ImagePreview: FC<ImagePreviewProps> = ({
useHotkeys('esc', onCancel)
useHotkeys('up', zoomIn)
useHotkeys('down', zoomOut)
useHotkeys('left', onPrev || (() => { }))
useHotkeys('right', onNext || (() => { }))
useHotkeys('left', onPrev || noop)
useHotkeys('right', onNext || noop)
return createPortal(
<div className='image-preview-container fixed inset-0 z-[1000] flex items-center justify-center bg-black/80 p-8'

View File

@@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'
import { RiCloseCircleFill, RiErrorWarningLine, RiSearchLine } from '@remixicon/react'
import { type VariantProps, cva } from 'class-variance-authority'
import cn from '@/utils/classnames'
import { noop } from 'lodash-es'
export const inputVariants = cva(
'',
@@ -43,7 +44,7 @@ const Input = ({
styleCss,
value,
placeholder,
onChange = () => { },
onChange = noop,
unit,
...props
}: InputProps) => {

View File

@@ -2,6 +2,7 @@ import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from '@
import { Fragment } from 'react'
import { RiCloseLine } from '@remixicon/react'
import classNames from '@/utils/classnames'
import { noop } from 'lodash-es'
// https://headlessui.com/react/dialog
type IModal = {
@@ -20,7 +21,7 @@ export default function Modal({
className,
wrapperClassName,
isShow,
onClose = () => { },
onClose = noop,
title,
description,
children,

View File

@@ -6,6 +6,7 @@ import s from './index.module.css'
import type { NotionPage } from '@/models/common'
import cn from '@/utils/classnames'
import Modal from '@/app/components/base/modal'
import { noop } from 'lodash-es'
type NotionPageSelectorModalProps = {
isShow: boolean
@@ -36,7 +37,7 @@ const NotionPageSelectorModal = ({
<Modal
className={s.modal}
isShow={isShow}
onClose={() => { }}
onClose={noop}
>
<div className='mb-6 flex h-8 items-center justify-between'>
<div className='text-xl font-semibold text-gray-900'>{t('common.dataSource.notion.selector.addPages')}</div>

View File

@@ -14,12 +14,13 @@ import {
ContextBlockNode,
} from '../context-block/node'
import { CustomTextNode } from '../custom-text/node'
import { noop } from 'lodash-es'
const REGEX = new RegExp(CONTEXT_PLACEHOLDER_TEXT)
const ContextBlockReplacementBlock = ({
datasets = [],
onAddContext = () => {},
onAddContext = noop,
onInsert,
canNotAddContext,
}: ContextBlockType) => {

View File

@@ -14,6 +14,7 @@ import {
$createContextBlockNode,
ContextBlockNode,
} from './node'
import { noop } from 'lodash-es'
export const INSERT_CONTEXT_BLOCK_COMMAND = createCommand('INSERT_CONTEXT_BLOCK_COMMAND')
export const DELETE_CONTEXT_BLOCK_COMMAND = createCommand('DELETE_CONTEXT_BLOCK_COMMAND')
@@ -26,7 +27,7 @@ export type Dataset = {
const ContextBlock = memo(({
datasets = [],
onAddContext = () => {},
onAddContext = noop,
onInsert,
onDelete,
canNotAddContext,

View File

@@ -13,12 +13,13 @@ import {
HistoryBlockNode,
} from '../history-block/node'
import { CustomTextNode } from '../custom-text/node'
import { noop } from 'lodash-es'
const REGEX = new RegExp(HISTORY_PLACEHOLDER_TEXT)
const HistoryBlockReplacementBlock = ({
history = { user: '', assistant: '' },
onEditRole = () => {},
onEditRole = noop,
onInsert,
}: HistoryBlockType) => {
const [editor] = useLexicalComposerContext()

View File

@@ -14,6 +14,7 @@ import {
$createHistoryBlockNode,
HistoryBlockNode,
} from './node'
import { noop } from 'lodash-es'
export const INSERT_HISTORY_BLOCK_COMMAND = createCommand('INSERT_HISTORY_BLOCK_COMMAND')
export const DELETE_HISTORY_BLOCK_COMMAND = createCommand('DELETE_HISTORY_BLOCK_COMMAND')
@@ -32,7 +33,7 @@ export type HistoryBlockProps = {
const HistoryBlock = memo(({
history = { user: '', assistant: '' },
onEditRole = () => {},
onEditRole = noop,
onInsert,
onDelete,
}: HistoryBlockType) => {

View File

@@ -2,6 +2,7 @@
import type { FC } from 'react'
import React from 'react'
import cn from '@/utils/classnames'
import { noop } from 'lodash-es'
type Props = {
className?: string
@@ -23,7 +24,7 @@ const RadioCard: FC<Props> = ({
description,
noRadio,
isChosen,
onChosen = () => { },
onChosen = noop,
chosenConfig,
chosenConfigWrapClassName,
className,

View File

@@ -15,6 +15,7 @@ import type { Tag } from '@/app/components/base/tag-management/constant'
import Checkbox from '@/app/components/base/checkbox'
import { bindTag, createTag, fetchTagList, unBindTag } from '@/service/tag'
import { ToastContext } from '@/app/components/base/toast'
import { noop } from 'lodash-es'
type TagSelectorProps = {
targetID: string
@@ -161,7 +162,7 @@ const Panel = (props: PanelProps) => {
<Checkbox
className='shrink-0'
checked={selectedTagIDs.includes(tag.id)}
onCheck={() => { }}
onCheck={noop}
/>
<div title={tag.name} className='grow truncate text-sm leading-5 text-text-secondary'>{tag.name}</div>
</div>
@@ -175,7 +176,7 @@ const Panel = (props: PanelProps) => {
<Checkbox
className='shrink-0'
checked={selectedTagIDs.includes(tag.id)}
onCheck={() => { }}
onCheck={noop}
/>
<div title={tag.name} className='grow truncate text-sm leading-5 text-text-secondary'>{tag.name}</div>
</div>

View File

@@ -7,6 +7,7 @@ import Button from '@/app/components/base/button'
import Modal from '@/app/components/base/modal'
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
import type { Tag } from '@/app/components/base/tag-management/constant'
import { noop } from 'lodash-es'
type TagRemoveModalProps = {
show: boolean
@@ -22,7 +23,7 @@ const TagRemoveModal = ({ show, tag, onConfirm, onClose }: TagRemoveModalProps)
<Modal
className={cn('w-[480px] max-w-[480px] p-8')}
isShow={show}
onClose={() => { }}
onClose={noop}
>
<div className='absolute right-4 top-4 cursor-pointer p-2' onClick={onClose}>
<RiCloseLine className='h-4 w-4 text-text-tertiary' />

View File

@@ -2,6 +2,7 @@ import React from 'react'
import { act, render, screen, waitFor } from '@testing-library/react'
import Toast, { ToastProvider, useToastContext } from '.'
import '@testing-library/jest-dom'
import { noop } from 'lodash-es'
// Mock timers for testing timeouts
jest.useFakeTimers()
@@ -76,11 +77,11 @@ describe('Toast', () => {
test('does not render close button when close is undefined', () => {
// Create a modified context where close is undefined
const CustomToastContext = React.createContext({ notify: () => { }, close: undefined })
const CustomToastContext = React.createContext({ notify: noop, close: undefined })
// Create a wrapper component using the custom context
const Wrapper = ({ children }: any) => (
<CustomToastContext.Provider value={{ notify: () => { }, close: undefined }}>
<CustomToastContext.Provider value={{ notify: noop, close: undefined }}>
{children}
</CustomToastContext.Provider>
)

View File

@@ -12,6 +12,7 @@ import {
import { createContext, useContext } from 'use-context-selector'
import ActionButton from '@/app/components/base/action-button'
import classNames from '@/utils/classnames'
import { noop } from 'lodash-es'
export type IToastProps = {
type?: 'success' | 'error' | 'warning' | 'info'
@@ -134,7 +135,7 @@ Toast.notify = ({
root.render(
<ToastContext.Provider value={{
notify: () => { },
notify: noop,
close: () => {
if (holder) {
root.unmount()

View File

@@ -2,6 +2,7 @@ import { render, screen } from '@testing-library/react'
import '@testing-library/jest-dom'
import { z } from 'zod'
import withValidation from '.'
import { noop } from 'lodash-es'
describe('withValidation HOC', () => {
// schema for validation
@@ -16,7 +17,7 @@ describe('withValidation HOC', () => {
const WrappedComponent = withValidation(TestComponent, schema)
beforeAll(() => {
jest.spyOn(console, 'error').mockImplementation(() => { })
jest.spyOn(console, 'error').mockImplementation(noop)
})
afterAll(() => {