diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml index dbced47988..97027c2218 100644 --- a/.github/workflows/autofix.yml +++ b/.github/workflows/autofix.yml @@ -13,12 +13,28 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + + - name: Check Docker Compose inputs + id: docker-compose-changes + uses: tj-actions/changed-files@v46 + with: + files: | + docker/generate_docker_compose + docker/.env.example + docker/docker-compose-template.yaml + docker/docker-compose.yaml - uses: actions/setup-python@v5 with: python-version: "3.11" - uses: astral-sh/setup-uv@v6 + - name: Generate Docker Compose + if: steps.docker-compose-changes.outputs.any_changed == 'true' + run: | + cd docker + ./generate_docker_compose + - run: | cd api uv sync --dev diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index 2fb8121f74..8710f422fc 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -108,36 +108,6 @@ jobs: working-directory: ./web run: pnpm run type-check:tsgo - docker-compose-template: - name: Docker Compose Template - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Check changed files - id: changed-files - uses: tj-actions/changed-files@v46 - with: - files: | - docker/generate_docker_compose - docker/.env.example - docker/docker-compose-template.yaml - docker/docker-compose.yaml - - - name: Generate Docker Compose - if: steps.changed-files.outputs.any_changed == 'true' - run: | - cd docker - ./generate_docker_compose - - - name: Check for changes - if: steps.changed-files.outputs.any_changed == 'true' - run: git diff --exit-code - superlinter: name: SuperLinter runs-on: ubuntu-latest diff --git a/api/controllers/common/file_response.py b/api/controllers/common/file_response.py new file mode 100644 index 0000000000..ca8ea3d52e --- /dev/null +++ b/api/controllers/common/file_response.py @@ -0,0 +1,57 @@ +import os +from email.message import Message +from urllib.parse import quote + +from flask import Response + +HTML_MIME_TYPES = frozenset({"text/html", "application/xhtml+xml"}) +HTML_EXTENSIONS = frozenset({"html", "htm"}) + + +def _normalize_mime_type(mime_type: str | None) -> str: + if not mime_type: + return "" + message = Message() + message["Content-Type"] = mime_type + return message.get_content_type().strip().lower() + + +def _is_html_extension(extension: str | None) -> bool: + if not extension: + return False + return extension.lstrip(".").lower() in HTML_EXTENSIONS + + +def is_html_content(mime_type: str | None, filename: str | None, extension: str | None = None) -> bool: + normalized_mime_type = _normalize_mime_type(mime_type) + if normalized_mime_type in HTML_MIME_TYPES: + return True + + if _is_html_extension(extension): + return True + + if filename: + return _is_html_extension(os.path.splitext(filename)[1]) + + return False + + +def enforce_download_for_html( + response: Response, + *, + mime_type: str | None, + filename: str | None, + extension: str | None = None, +) -> bool: + if not is_html_content(mime_type, filename, extension): + return False + + if filename: + encoded_filename = quote(filename) + response.headers["Content-Disposition"] = f"attachment; filename*=UTF-8''{encoded_filename}" + else: + response.headers["Content-Disposition"] = "attachment" + + response.headers["Content-Type"] = "application/octet-stream" + response.headers["X-Content-Type-Options"] = "nosniff" + return True diff --git a/api/controllers/files/image_preview.py b/api/controllers/files/image_preview.py index 64f47f426a..04db1c67cb 100644 --- a/api/controllers/files/image_preview.py +++ b/api/controllers/files/image_preview.py @@ -7,6 +7,7 @@ from werkzeug.exceptions import NotFound import services from controllers.common.errors import UnsupportedFileTypeError +from controllers.common.file_response import enforce_download_for_html from controllers.files import files_ns from extensions.ext_database import db from services.account_service import TenantService @@ -138,6 +139,13 @@ class FilePreviewApi(Resource): response.headers["Content-Disposition"] = f"attachment; filename*=UTF-8''{encoded_filename}" response.headers["Content-Type"] = "application/octet-stream" + enforce_download_for_html( + response, + mime_type=upload_file.mime_type, + filename=upload_file.name, + extension=upload_file.extension, + ) + return response diff --git a/api/controllers/files/tool_files.py b/api/controllers/files/tool_files.py index c487a0a915..89aa472015 100644 --- a/api/controllers/files/tool_files.py +++ b/api/controllers/files/tool_files.py @@ -6,6 +6,7 @@ from pydantic import BaseModel, Field from werkzeug.exceptions import Forbidden, NotFound from controllers.common.errors import UnsupportedFileTypeError +from controllers.common.file_response import enforce_download_for_html from controllers.files import files_ns from core.tools.signature import verify_tool_file_signature from core.tools.tool_file_manager import ToolFileManager @@ -78,4 +79,11 @@ class ToolFileApi(Resource): encoded_filename = quote(tool_file.name) response.headers["Content-Disposition"] = f"attachment; filename*=UTF-8''{encoded_filename}" + enforce_download_for_html( + response, + mime_type=tool_file.mimetype, + filename=tool_file.name, + extension=extension, + ) + return response diff --git a/api/controllers/service_api/app/file_preview.py b/api/controllers/service_api/app/file_preview.py index 60f422b88e..f853a124ef 100644 --- a/api/controllers/service_api/app/file_preview.py +++ b/api/controllers/service_api/app/file_preview.py @@ -5,6 +5,7 @@ from flask import Response, request from flask_restx import Resource from pydantic import BaseModel, Field +from controllers.common.file_response import enforce_download_for_html from controllers.common.schema import register_schema_model from controllers.service_api import service_api_ns from controllers.service_api.app.error import ( @@ -183,6 +184,13 @@ class FilePreviewApi(Resource): # Override content-type for downloads to force download response.headers["Content-Type"] = "application/octet-stream" + enforce_download_for_html( + response, + mime_type=upload_file.mime_type, + filename=upload_file.name, + extension=upload_file.extension, + ) + # Add caching headers for performance response.headers["Cache-Control"] = "public, max-age=3600" # Cache for 1 hour diff --git a/api/core/tools/entities/tool_entities.py b/api/core/tools/entities/tool_entities.py index 353f3a646a..583a3584f7 100644 --- a/api/core/tools/entities/tool_entities.py +++ b/api/core/tools/entities/tool_entities.py @@ -153,11 +153,11 @@ class ToolInvokeMessage(BaseModel): @classmethod def transform_variable_value(cls, values): """ - Only basic types and lists are allowed. + Only basic types, lists, and None are allowed. """ value = values.get("variable_value") - if not isinstance(value, dict | list | str | int | float | bool): - raise ValueError("Only basic types and lists are allowed.") + if value is not None and not isinstance(value, dict | list | str | int | float | bool): + raise ValueError("Only basic types, lists, and None are allowed.") # if stream is true, the value must be a string if values.get("stream"): diff --git a/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py b/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py index 93db417b15..08e0542d61 100644 --- a/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py +++ b/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py @@ -281,7 +281,7 @@ class ParameterExtractorNode(Node[ParameterExtractorNodeData]): # handle invoke result - text = invoke_result.message.content or "" + text = invoke_result.message.get_text_content() if not isinstance(text, str): raise InvalidTextContentTypeError(f"Invalid text content type: {type(text)}. Expected str.") diff --git a/api/tests/unit_tests/controllers/common/test_file_response.py b/api/tests/unit_tests/controllers/common/test_file_response.py new file mode 100644 index 0000000000..2487c362bd --- /dev/null +++ b/api/tests/unit_tests/controllers/common/test_file_response.py @@ -0,0 +1,46 @@ +from flask import Response + +from controllers.common.file_response import enforce_download_for_html, is_html_content + + +class TestFileResponseHelpers: + def test_is_html_content_detects_mime_type(self): + mime_type = "text/html; charset=UTF-8" + + result = is_html_content(mime_type, filename="file.txt", extension="txt") + + assert result is True + + def test_is_html_content_detects_extension(self): + result = is_html_content("text/plain", filename="report.html", extension=None) + + assert result is True + + def test_enforce_download_for_html_sets_headers(self): + response = Response("payload", mimetype="text/html") + + updated = enforce_download_for_html( + response, + mime_type="text/html", + filename="unsafe.html", + extension="html", + ) + + assert updated is True + assert "attachment" in response.headers["Content-Disposition"] + assert response.headers["Content-Type"] == "application/octet-stream" + assert response.headers["X-Content-Type-Options"] == "nosniff" + + def test_enforce_download_for_html_no_change_for_non_html(self): + response = Response("payload", mimetype="text/plain") + + updated = enforce_download_for_html( + response, + mime_type="text/plain", + filename="notes.txt", + extension="txt", + ) + + assert updated is False + assert "Content-Disposition" not in response.headers + assert "X-Content-Type-Options" not in response.headers diff --git a/api/tests/unit_tests/controllers/service_api/app/test_file_preview.py b/api/tests/unit_tests/controllers/service_api/app/test_file_preview.py index acff191c79..1bdcd0f1a3 100644 --- a/api/tests/unit_tests/controllers/service_api/app/test_file_preview.py +++ b/api/tests/unit_tests/controllers/service_api/app/test_file_preview.py @@ -41,6 +41,7 @@ class TestFilePreviewApi: upload_file = Mock(spec=UploadFile) upload_file.id = str(uuid.uuid4()) upload_file.name = "test_file.jpg" + upload_file.extension = "jpg" upload_file.mime_type = "image/jpeg" upload_file.size = 1024 upload_file.key = "storage/key/test_file.jpg" @@ -210,6 +211,19 @@ class TestFilePreviewApi: assert mock_upload_file.name in response.headers["Content-Disposition"] assert response.headers["Content-Type"] == "application/octet-stream" + def test_build_file_response_html_forces_attachment(self, file_preview_api, mock_upload_file): + """Test HTML files are forced to download""" + mock_generator = Mock() + mock_upload_file.mime_type = "text/html" + mock_upload_file.name = "unsafe.html" + mock_upload_file.extension = "html" + + response = file_preview_api._build_file_response(mock_generator, mock_upload_file, False) + + assert "attachment" in response.headers["Content-Disposition"] + assert response.headers["Content-Type"] == "application/octet-stream" + assert response.headers["X-Content-Type-Options"] == "nosniff" + def test_build_file_response_audio_video(self, file_preview_api, mock_upload_file): """Test file response building for audio/video files""" mock_generator = Mock() diff --git a/web/__mocks__/provider-context.ts b/web/__mocks__/provider-context.ts index 3ecb4e9c0e..c69a2ad1d2 100644 --- a/web/__mocks__/provider-context.ts +++ b/web/__mocks__/provider-context.ts @@ -1,6 +1,6 @@ import type { Plan, UsagePlanInfo } from '@/app/components/billing/type' import type { ProviderContextState } from '@/context/provider-context' -import { merge, noop } from 'lodash-es' +import { merge, noop } from 'es-toolkit/compat' import { defaultPlan } from '@/app/components/billing/config' // Avoid being mocked in tests diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/time-range-picker/date-picker.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/time-range-picker/date-picker.tsx index ab39846a36..004f83afc5 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/time-range-picker/date-picker.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/time-range-picker/date-picker.tsx @@ -4,7 +4,7 @@ import type { FC } from 'react' import type { TriggerProps } from '@/app/components/base/date-and-time-picker/types' import { RiCalendarLine } from '@remixicon/react' import dayjs from 'dayjs' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useCallback } from 'react' import Picker from '@/app/components/base/date-and-time-picker/date-picker' diff --git a/web/app/(shareLayout)/webapp-reset-password/page.tsx b/web/app/(shareLayout)/webapp-reset-password/page.tsx index 92c39eb729..108bd4b22e 100644 --- a/web/app/(shareLayout)/webapp-reset-password/page.tsx +++ b/web/app/(shareLayout)/webapp-reset-password/page.tsx @@ -1,6 +1,6 @@ 'use client' import { RiArrowLeftLine, RiLockPasswordLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import Link from 'next/link' import { useRouter, useSearchParams } from 'next/navigation' import { useState } from 'react' diff --git a/web/app/(shareLayout)/webapp-signin/components/mail-and-code-auth.tsx b/web/app/(shareLayout)/webapp-signin/components/mail-and-code-auth.tsx index 9020858347..8b611b9eea 100644 --- a/web/app/(shareLayout)/webapp-signin/components/mail-and-code-auth.tsx +++ b/web/app/(shareLayout)/webapp-signin/components/mail-and-code-auth.tsx @@ -1,4 +1,4 @@ -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useRouter, useSearchParams } from 'next/navigation' import { useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/(shareLayout)/webapp-signin/components/mail-and-password-auth.tsx b/web/app/(shareLayout)/webapp-signin/components/mail-and-password-auth.tsx index 67e4bf7af2..46645ed68c 100644 --- a/web/app/(shareLayout)/webapp-signin/components/mail-and-password-auth.tsx +++ b/web/app/(shareLayout)/webapp-signin/components/mail-and-password-auth.tsx @@ -1,5 +1,5 @@ 'use client' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import Link from 'next/link' import { useRouter, useSearchParams } from 'next/navigation' import { useCallback, useState } from 'react' diff --git a/web/app/account/(commonLayout)/account-page/email-change-modal.tsx b/web/app/account/(commonLayout)/account-page/email-change-modal.tsx index 99b4f5c686..655452ea24 100644 --- a/web/app/account/(commonLayout)/account-page/email-change-modal.tsx +++ b/web/app/account/(commonLayout)/account-page/email-change-modal.tsx @@ -1,6 +1,6 @@ import type { ResponseError } from '@/service/fetch' import { RiCloseLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useRouter } from 'next/navigation' import * as React from 'react' import { useState } from 'react' diff --git a/web/app/components/app/annotation/batch-add-annotation-modal/index.tsx b/web/app/components/app/annotation/batch-add-annotation-modal/index.tsx index 7fbb745c48..7289ed384d 100644 --- a/web/app/components/app/annotation/batch-add-annotation-modal/index.tsx +++ b/web/app/components/app/annotation/batch-add-annotation-modal/index.tsx @@ -1,7 +1,7 @@ 'use client' import type { FC } from 'react' import { RiCloseLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/app/configuration/base/operation-btn/index.tsx b/web/app/components/app/configuration/base/operation-btn/index.tsx index b9f55de26b..6a22dc6d3b 100644 --- a/web/app/components/app/configuration/base/operation-btn/index.tsx +++ b/web/app/components/app/configuration/base/operation-btn/index.tsx @@ -4,7 +4,7 @@ import { RiAddLine, RiEditLine, } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useTranslation } from 'react-i18next' import { cn } from '@/utils/classnames' diff --git a/web/app/components/app/configuration/config-prompt/simple-prompt-input.tsx b/web/app/components/app/configuration/config-prompt/simple-prompt-input.tsx index 9b558b58c1..3f39828e79 100644 --- a/web/app/components/app/configuration/config-prompt/simple-prompt-input.tsx +++ b/web/app/components/app/configuration/config-prompt/simple-prompt-input.tsx @@ -4,8 +4,8 @@ import type { ExternalDataTool } from '@/models/common' import type { PromptVariable } from '@/models/debug' import type { GenRes } from '@/service/debug' import { useBoolean } from 'ahooks' +import { noop } from 'es-toolkit/compat' import { produce } from 'immer' -import { noop } from 'lodash-es' import * as React from 'react' import { useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/app/configuration/config/agent/prompt-editor.tsx b/web/app/components/app/configuration/config/agent/prompt-editor.tsx index 0a09609cca..7399aaeac9 100644 --- a/web/app/components/app/configuration/config/agent/prompt-editor.tsx +++ b/web/app/components/app/configuration/config/agent/prompt-editor.tsx @@ -2,7 +2,7 @@ import type { FC } from 'react' import type { ExternalDataTool } from '@/models/common' import copy from 'copy-to-clipboard' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useTranslation } from 'react-i18next' import { useContext } from 'use-context-selector' diff --git a/web/app/components/app/configuration/dataset-config/index.spec.tsx b/web/app/components/app/configuration/dataset-config/index.spec.tsx index acccdec98e..e3791db9c0 100644 --- a/web/app/components/app/configuration/dataset-config/index.spec.tsx +++ b/web/app/components/app/configuration/dataset-config/index.spec.tsx @@ -52,7 +52,7 @@ vi.mock('../debug/hooks', () => ({ useFormattingChangedDispatcher: vi.fn(() => vi.fn()), })) -vi.mock('lodash-es', () => ({ +vi.mock('es-toolkit/compat', () => ({ intersectionBy: vi.fn((...arrays) => { // Mock realistic intersection behavior based on metadata name const validArrays = arrays.filter(Array.isArray) diff --git a/web/app/components/app/configuration/dataset-config/index.tsx b/web/app/components/app/configuration/dataset-config/index.tsx index 9ac1729590..2fc82c82b6 100644 --- a/web/app/components/app/configuration/dataset-config/index.tsx +++ b/web/app/components/app/configuration/dataset-config/index.tsx @@ -8,8 +8,8 @@ import type { MetadataFilteringModeEnum, } from '@/app/components/workflow/nodes/knowledge-retrieval/types' import type { DataSet } from '@/models/datasets' +import { intersectionBy } from 'es-toolkit/compat' import { produce } from 'immer' -import { intersectionBy } from 'lodash-es' import * as React from 'react' import { useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx b/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx index ad5199fd55..f7aadc0c3f 100644 --- a/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx +++ b/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx @@ -1,6 +1,7 @@ 'use client' import type { FC } from 'react' +import type { ModelParameterModalProps } from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal' import type { ModelConfig } from '@/app/components/workflow/types' import type { DataSet, @@ -8,7 +9,6 @@ import type { import type { DatasetConfigs, } from '@/models/debug' -import { noop } from 'lodash-es' import { memo, useCallback, useEffect, useMemo } from 'react' import { useTranslation } from 'react-i18next' import Divider from '@/app/components/base/divider' @@ -33,17 +33,20 @@ type Props = { selectedDatasets?: DataSet[] isInWorkflow?: boolean singleRetrievalModelConfig?: ModelConfig - onSingleRetrievalModelChange?: (config: ModelConfig) => void - onSingleRetrievalModelParamsChange?: (config: ModelConfig) => void + onSingleRetrievalModelChange?: ModelParameterModalProps['setModel'] + onSingleRetrievalModelParamsChange?: ModelParameterModalProps['onCompletionParamsChange'] } +const noopModelChange: ModelParameterModalProps['setModel'] = () => {} +const noopParamsChange: ModelParameterModalProps['onCompletionParamsChange'] = () => {} + const ConfigContent: FC = ({ datasetConfigs, onChange, isInWorkflow, singleRetrievalModelConfig: singleRetrievalConfig = {} as ModelConfig, - onSingleRetrievalModelChange = noop, - onSingleRetrievalModelParamsChange = noop, + onSingleRetrievalModelChange = noopModelChange, + onSingleRetrievalModelParamsChange = noopParamsChange, selectedDatasets = [], }) => { const { t } = useTranslation() diff --git a/web/app/components/app/configuration/dataset-config/params-config/weighted-score.tsx b/web/app/components/app/configuration/dataset-config/params-config/weighted-score.tsx index 77f3ac0eb8..3a62a66525 100644 --- a/web/app/components/app/configuration/dataset-config/params-config/weighted-score.tsx +++ b/web/app/components/app/configuration/dataset-config/params-config/weighted-score.tsx @@ -1,4 +1,4 @@ -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { memo } from 'react' import { useTranslation } from 'react-i18next' import Slider from '@/app/components/base/slider' diff --git a/web/app/components/app/configuration/dataset-config/settings-modal/index.tsx b/web/app/components/app/configuration/dataset-config/settings-modal/index.tsx index 243aafdbdd..0d8a0934e5 100644 --- a/web/app/components/app/configuration/dataset-config/settings-modal/index.tsx +++ b/web/app/components/app/configuration/dataset-config/settings-modal/index.tsx @@ -3,7 +3,7 @@ import type { Member } from '@/models/common' import type { DataSet } from '@/models/datasets' import type { RetrievalConfig } from '@/types/app' import { RiCloseLine } from '@remixicon/react' -import { isEqual } from 'lodash-es' +import { isEqual } from 'es-toolkit/compat' import { useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' diff --git a/web/app/components/app/configuration/debug/debug-with-multiple-model/context.tsx b/web/app/components/app/configuration/debug/debug-with-multiple-model/context.tsx index 9d058186cf..3f0381074f 100644 --- a/web/app/components/app/configuration/debug/debug-with-multiple-model/context.tsx +++ b/web/app/components/app/configuration/debug/debug-with-multiple-model/context.tsx @@ -1,7 +1,7 @@ 'use client' import type { ModelAndParameter } from '../types' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { createContext, useContext } from 'use-context-selector' export type DebugWithMultipleModelContextType = { diff --git a/web/app/components/app/configuration/debug/debug-with-multiple-model/text-generation-item.tsx b/web/app/components/app/configuration/debug/debug-with-multiple-model/text-generation-item.tsx index 8dda5b3879..9113f782d9 100644 --- a/web/app/components/app/configuration/debug/debug-with-multiple-model/text-generation-item.tsx +++ b/web/app/components/app/configuration/debug/debug-with-multiple-model/text-generation-item.tsx @@ -4,7 +4,7 @@ import type { OnSend, TextGenerationConfig, } from '@/app/components/base/text-generation/types' -import { cloneDeep, noop } from 'lodash-es' +import { cloneDeep, noop } from 'es-toolkit/compat' import { memo } from 'react' import TextGeneration from '@/app/components/app/text-generate/item' import { TransferMethod } from '@/app/components/base/chat/types' diff --git a/web/app/components/app/configuration/debug/hooks.tsx b/web/app/components/app/configuration/debug/hooks.tsx index 786d43bdb9..e66185e284 100644 --- a/web/app/components/app/configuration/debug/hooks.tsx +++ b/web/app/components/app/configuration/debug/hooks.tsx @@ -6,7 +6,7 @@ import type { ChatConfig, ChatItem, } from '@/app/components/base/chat/types' -import cloneDeep from 'lodash-es/cloneDeep' +import { cloneDeep } from 'es-toolkit/compat' import { useCallback, useRef, diff --git a/web/app/components/app/configuration/debug/index.tsx b/web/app/components/app/configuration/debug/index.tsx index fe1c6550f5..140f9421c9 100644 --- a/web/app/components/app/configuration/debug/index.tsx +++ b/web/app/components/app/configuration/debug/index.tsx @@ -11,9 +11,8 @@ import { RiSparklingFill, } from '@remixicon/react' import { useBoolean } from 'ahooks' +import { cloneDeep, noop } from 'es-toolkit/compat' import { produce, setAutoFreeze } from 'immer' -import { noop } from 'lodash-es' -import cloneDeep from 'lodash-es/cloneDeep' import * as React from 'react' import { useCallback, useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/app/configuration/hooks/use-advanced-prompt-config.ts b/web/app/components/app/configuration/hooks/use-advanced-prompt-config.ts index 63603033d3..3e8f7c5b3a 100644 --- a/web/app/components/app/configuration/hooks/use-advanced-prompt-config.ts +++ b/web/app/components/app/configuration/hooks/use-advanced-prompt-config.ts @@ -1,7 +1,7 @@ import type { FormValue } from '@/app/components/header/account-setting/model-provider-page/declarations' import type { ChatPromptConfig, CompletionPromptConfig, ConversationHistoriesRole, PromptItem } from '@/models/debug' +import { clone } from 'es-toolkit/compat' import { produce } from 'immer' -import { clone } from 'lodash-es' import { useState } from 'react' import { checkHasContextBlock, checkHasHistoryBlock, checkHasQueryBlock, PRE_PROMPT_PLACEHOLDER_TEXT } from '@/app/components/base/prompt-editor/constants' import { DEFAULT_CHAT_PROMPT_CONFIG, DEFAULT_COMPLETION_PROMPT_CONFIG } from '@/config' diff --git a/web/app/components/app/configuration/index.tsx b/web/app/components/app/configuration/index.tsx index eb7a9f5a32..4b5bcafc9b 100644 --- a/web/app/components/app/configuration/index.tsx +++ b/web/app/components/app/configuration/index.tsx @@ -20,8 +20,8 @@ import type { import type { ModelConfig as BackendModelConfig, UserInputFormItem, VisionSettings } from '@/types/app' import { CodeBracketIcon } from '@heroicons/react/20/solid' import { useBoolean, useGetState } from 'ahooks' +import { clone, isEqual } from 'es-toolkit/compat' import { produce } from 'immer' -import { clone, isEqual } from 'lodash-es' import { usePathname } from 'next/navigation' import * as React from 'react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' diff --git a/web/app/components/app/configuration/tools/external-data-tool-modal.tsx b/web/app/components/app/configuration/tools/external-data-tool-modal.tsx index 74f436289f..ccd0b1288e 100644 --- a/web/app/components/app/configuration/tools/external-data-tool-modal.tsx +++ b/web/app/components/app/configuration/tools/external-data-tool-modal.tsx @@ -3,7 +3,7 @@ import type { CodeBasedExtensionItem, ExternalDataTool, } from '@/models/common' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useState } from 'react' import { useTranslation } from 'react-i18next' import { useContext } from 'use-context-selector' diff --git a/web/app/components/app/create-from-dsl-modal/index.tsx b/web/app/components/app/create-from-dsl-modal/index.tsx index 3d6cabedf6..809859d3ad 100644 --- a/web/app/components/app/create-from-dsl-modal/index.tsx +++ b/web/app/components/app/create-from-dsl-modal/index.tsx @@ -3,7 +3,7 @@ import type { MouseEventHandler } from 'react' import { RiCloseLine, RiCommandLine, RiCornerDownLeftLine } from '@remixicon/react' import { useDebounceFn, useKeyPress } from 'ahooks' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useRouter } from 'next/navigation' import { useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/app/duplicate-modal/index.tsx b/web/app/components/app/duplicate-modal/index.tsx index 420a6b159a..f670b37076 100644 --- a/web/app/components/app/duplicate-modal/index.tsx +++ b/web/app/components/app/duplicate-modal/index.tsx @@ -1,7 +1,7 @@ 'use client' import type { AppIconType } from '@/types/app' import { RiCloseLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/app/log/index.tsx b/web/app/components/app/log/index.tsx index 0e6e4bba2d..52485f5dd2 100644 --- a/web/app/components/app/log/index.tsx +++ b/web/app/components/app/log/index.tsx @@ -3,7 +3,7 @@ import type { FC } from 'react' import type { App } from '@/types/app' import { useDebounce } from 'ahooks' import dayjs from 'dayjs' -import { omit } from 'lodash-es' +import { omit } from 'es-toolkit/compat' import { usePathname, useRouter, useSearchParams } from 'next/navigation' import * as React from 'react' import { useCallback, useEffect, useState } from 'react' diff --git a/web/app/components/app/log/list.tsx b/web/app/components/app/log/list.tsx index 2b13a09b3a..cf10cff327 100644 --- a/web/app/components/app/log/list.tsx +++ b/web/app/components/app/log/list.tsx @@ -12,7 +12,7 @@ import { RiCloseLine, RiEditFill } from '@remixicon/react' import dayjs from 'dayjs' import timezone from 'dayjs/plugin/timezone' import utc from 'dayjs/plugin/utc' -import { get, noop } from 'lodash-es' +import { get, noop } from 'es-toolkit/compat' import { usePathname, useRouter, useSearchParams } from 'next/navigation' import * as React from 'react' import { useCallback, useEffect, useRef, useState } from 'react' diff --git a/web/app/components/app/overview/apikey-info-panel/apikey-info-panel.test-utils.tsx b/web/app/components/app/overview/apikey-info-panel/apikey-info-panel.test-utils.tsx index 0e8f82b00d..5cffa1143b 100644 --- a/web/app/components/app/overview/apikey-info-panel/apikey-info-panel.test-utils.tsx +++ b/web/app/components/app/overview/apikey-info-panel/apikey-info-panel.test-utils.tsx @@ -2,7 +2,7 @@ import type { RenderOptions } from '@testing-library/react' import type { Mock, MockedFunction } from 'vitest' import type { ModalContextState } from '@/context/modal-context' import { fireEvent, render } from '@testing-library/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { defaultPlan } from '@/app/components/billing/config' import { useModalContext as actualUseModalContext } from '@/context/modal-context' diff --git a/web/app/components/app/overview/app-chart.tsx b/web/app/components/app/overview/app-chart.tsx index d876dbda27..114ef7d5db 100644 --- a/web/app/components/app/overview/app-chart.tsx +++ b/web/app/components/app/overview/app-chart.tsx @@ -6,7 +6,7 @@ import type { AppDailyConversationsResponse, AppDailyEndUsersResponse, AppDailyM import dayjs from 'dayjs' import Decimal from 'decimal.js' import ReactECharts from 'echarts-for-react' -import { get } from 'lodash-es' +import { get } from 'es-toolkit/compat' import * as React from 'react' import { useTranslation } from 'react-i18next' import Basic from '@/app/components/app-sidebar/basic' diff --git a/web/app/components/app/switch-app-modal/index.tsx b/web/app/components/app/switch-app-modal/index.tsx index 257f7b6788..83f2efc49d 100644 --- a/web/app/components/app/switch-app-modal/index.tsx +++ b/web/app/components/app/switch-app-modal/index.tsx @@ -2,7 +2,7 @@ import type { App } from '@/types/app' import { RiCloseLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useRouter } from 'next/navigation' import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/app/workflow-log/index.tsx b/web/app/components/app/workflow-log/index.tsx index 12438d6d17..5aa467d03d 100644 --- a/web/app/components/app/workflow-log/index.tsx +++ b/web/app/components/app/workflow-log/index.tsx @@ -5,7 +5,7 @@ import { useDebounce } from 'ahooks' import dayjs from 'dayjs' import timezone from 'dayjs/plugin/timezone' import utc from 'dayjs/plugin/utc' -import { omit } from 'lodash-es' +import { omit } from 'es-toolkit/compat' import * as React from 'react' import { useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/base/agent-log-modal/detail.tsx b/web/app/components/base/agent-log-modal/detail.tsx index 5451126c9e..0b8dc302fb 100644 --- a/web/app/components/base/agent-log-modal/detail.tsx +++ b/web/app/components/base/agent-log-modal/detail.tsx @@ -2,7 +2,7 @@ import type { FC } from 'react' import type { IChatItem } from '@/app/components/base/chat/chat/type' import type { AgentIteration, AgentLogDetailResponse } from '@/models/log' -import { flatten, uniq } from 'lodash-es' +import { flatten, uniq } from 'es-toolkit/compat' import * as React from 'react' import { useCallback, useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/base/app-icon-picker/index.tsx b/web/app/components/base/app-icon-picker/index.tsx index ce73af36a2..99ba7eb544 100644 --- a/web/app/components/base/app-icon-picker/index.tsx +++ b/web/app/components/base/app-icon-picker/index.tsx @@ -3,7 +3,7 @@ import type { Area } from 'react-easy-crop' import type { OnImageInput } from './ImageInput' import type { AppIconType, ImageFile } from '@/types/app' import { RiImageCircleAiLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import { DISABLE_UPLOAD_IMAGE_AS_ICON } from '@/config' diff --git a/web/app/components/base/badge/index.spec.tsx b/web/app/components/base/badge/index.spec.tsx new file mode 100644 index 0000000000..74162841cf --- /dev/null +++ b/web/app/components/base/badge/index.spec.tsx @@ -0,0 +1,360 @@ +import { fireEvent, render, screen } from '@testing-library/react' +import Badge, { BadgeState, BadgeVariants } from './index' + +describe('Badge', () => { + describe('Rendering', () => { + it('should render as a div element with badge class', () => { + render(Test Badge) + + const badge = screen.getByText('Test Badge') + expect(badge).toHaveClass('badge') + expect(badge.tagName).toBe('DIV') + }) + + it.each([ + { children: undefined, label: 'no children' }, + { children: '', label: 'empty string' }, + ])('should render correctly when provided $label', ({ children }) => { + const { container } = render({children}) + + expect(container.firstChild).toHaveClass('badge') + }) + + it('should render React Node children correctly', () => { + render( + + 🔔 + , + ) + + expect(screen.getByTestId('badge-with-icon')).toBeInTheDocument() + expect(screen.getByTestId('custom-icon')).toBeInTheDocument() + }) + }) + + describe('size prop', () => { + it.each([ + { size: undefined, label: 'medium (default)' }, + { size: 's', label: 'small' }, + { size: 'm', label: 'medium' }, + { size: 'l', label: 'large' }, + ] as const)('should render with $label size', ({ size }) => { + render(Test) + + const expectedSize = size || 'm' + expect(screen.getByText('Test')).toHaveClass('badge', `badge-${expectedSize}`) + }) + }) + + describe('state prop', () => { + it.each([ + { state: BadgeState.Warning, label: 'warning', expectedClass: 'badge-warning' }, + { state: BadgeState.Accent, label: 'accent', expectedClass: 'badge-accent' }, + ])('should render with $label state', ({ state, expectedClass }) => { + render(State Test) + + expect(screen.getByText('State Test')).toHaveClass(expectedClass) + }) + + it.each([ + { state: undefined, label: 'default (undefined)' }, + { state: BadgeState.Default, label: 'default (explicit)' }, + ])('should use default styles when state is $label', ({ state }) => { + render(State Test) + + const badge = screen.getByText('State Test') + expect(badge).not.toHaveClass('badge-warning', 'badge-accent') + }) + }) + + describe('iconOnly prop', () => { + it.each([ + { size: 's', iconOnly: false, label: 'small with text' }, + { size: 's', iconOnly: true, label: 'small icon-only' }, + { size: 'm', iconOnly: false, label: 'medium with text' }, + { size: 'm', iconOnly: true, label: 'medium icon-only' }, + { size: 'l', iconOnly: false, label: 'large with text' }, + { size: 'l', iconOnly: true, label: 'large icon-only' }, + ] as const)('should render correctly for $label', ({ size, iconOnly }) => { + const { container } = render(🔔) + const badge = screen.getByText('🔔') + + // Verify badge renders with correct size + expect(badge).toHaveClass('badge', `badge-${size}`) + + // Verify the badge is in the DOM and contains the content + expect(badge).toBeInTheDocument() + expect(container.firstChild).toBe(badge) + }) + + it('should apply icon-only padding when iconOnly is true', () => { + render(🔔) + + // When iconOnly is true, the badge should have uniform padding (all sides equal) + const badge = screen.getByText('🔔') + expect(badge).toHaveClass('p-1') + }) + + it('should apply asymmetric padding when iconOnly is false', () => { + render(Badge) + + // When iconOnly is false, the badge should have different horizontal and vertical padding + const badge = screen.getByText('Badge') + expect(badge).toHaveClass('px-[5px]', 'py-[2px]') + }) + }) + + describe('uppercase prop', () => { + it.each([ + { uppercase: undefined, label: 'default (undefined)', expected: 'system-2xs-medium' }, + { uppercase: false, label: 'explicitly false', expected: 'system-2xs-medium' }, + { uppercase: true, label: 'true', expected: 'system-2xs-medium-uppercase' }, + ])('should apply $expected class when uppercase is $label', ({ uppercase, expected }) => { + render(Text) + + expect(screen.getByText('Text')).toHaveClass(expected) + }) + }) + + describe('styleCss prop', () => { + it('should apply custom inline styles correctly', () => { + const customStyles = { + backgroundColor: 'rgb(0, 0, 255)', + color: 'rgb(255, 255, 255)', + padding: '10px', + } + render(Styled Badge) + + expect(screen.getByText('Styled Badge')).toHaveStyle(customStyles) + }) + + it('should apply inline styles without overriding core classes', () => { + render(Custom) + + const badge = screen.getByText('Custom') + expect(badge).toHaveStyle({ backgroundColor: 'rgb(255, 0, 0)', margin: '5px' }) + expect(badge).toHaveClass('badge') + }) + }) + + describe('className prop', () => { + it.each([ + { + props: { className: 'custom-badge' }, + expected: ['badge', 'custom-badge'], + label: 'single custom class', + }, + { + props: { className: 'custom-class another-class', size: 'l' as const }, + expected: ['badge', 'badge-l', 'custom-class', 'another-class'], + label: 'multiple classes with size variant', + }, + ])('should merge $label with default classes', ({ props, expected }) => { + render(Test) + + expect(screen.getByText('Test')).toHaveClass(...expected) + }) + }) + + describe('HTML attributes passthrough', () => { + it.each([ + { attr: 'data-testid', value: 'custom-badge-id', label: 'data attribute' }, + { attr: 'id', value: 'unique-badge', label: 'id attribute' }, + { attr: 'aria-label', value: 'Notification badge', label: 'aria-label' }, + { attr: 'title', value: 'Hover tooltip', label: 'title attribute' }, + { attr: 'role', value: 'status', label: 'ARIA role' }, + ])('should pass through $label correctly', ({ attr, value }) => { + render(Test) + + expect(screen.getByText('Test')).toHaveAttribute(attr, value) + }) + + it('should support multiple HTML attributes simultaneously', () => { + render( + + Test + , + ) + + const badge = screen.getByTestId('multi-attr-badge') + expect(badge).toHaveAttribute('id', 'badge-123') + expect(badge).toHaveAttribute('aria-label', 'Status indicator') + expect(badge).toHaveAttribute('title', 'Current status') + }) + }) + + describe('Event handlers', () => { + it.each([ + { handler: 'onClick', trigger: fireEvent.click, label: 'click' }, + { handler: 'onMouseEnter', trigger: fireEvent.mouseEnter, label: 'mouse enter' }, + { handler: 'onMouseLeave', trigger: fireEvent.mouseLeave, label: 'mouse leave' }, + ])('should trigger $handler when $label occurs', ({ handler, trigger }) => { + const mockHandler = vi.fn() + render(Badge) + + trigger(screen.getByText('Badge')) + + expect(mockHandler).toHaveBeenCalledTimes(1) + }) + + it('should handle user interaction flow with multiple events', () => { + const handlers = { + onClick: vi.fn(), + onMouseEnter: vi.fn(), + onMouseLeave: vi.fn(), + } + render(Interactive) + + const badge = screen.getByText('Interactive') + fireEvent.mouseEnter(badge) + fireEvent.click(badge) + fireEvent.mouseLeave(badge) + + expect(handlers.onMouseEnter).toHaveBeenCalledTimes(1) + expect(handlers.onClick).toHaveBeenCalledTimes(1) + expect(handlers.onMouseLeave).toHaveBeenCalledTimes(1) + }) + + it('should pass event object to handler with correct properties', () => { + const handleClick = vi.fn() + render(Event Badge) + + fireEvent.click(screen.getByText('Event Badge')) + + expect(handleClick).toHaveBeenCalledWith(expect.objectContaining({ + type: 'click', + })) + }) + }) + + describe('Combined props', () => { + it('should correctly apply all props when used together', () => { + render( + + Full Featured + , + ) + + const badge = screen.getByTestId('combined-badge') + expect(badge).toHaveClass('badge', 'badge-l', 'badge-warning', 'system-2xs-medium-uppercase', 'custom-badge') + expect(badge).toHaveStyle({ backgroundColor: 'rgb(0, 0, 255)' }) + expect(badge).toHaveTextContent('Full Featured') + }) + + it.each([ + { + props: { size: 'l' as const, state: BadgeState.Accent }, + expected: ['badge', 'badge-l', 'badge-accent'], + label: 'size and state variants', + }, + { + props: { iconOnly: true, uppercase: true }, + expected: ['badge', 'system-2xs-medium-uppercase'], + label: 'iconOnly and uppercase', + }, + ])('should combine $label correctly', ({ props, expected }) => { + render(Test) + + expect(screen.getByText('Test')).toHaveClass(...expected) + }) + + it('should handle event handlers with combined props', () => { + const handleClick = vi.fn() + render( + + Test + , + ) + + const badge = screen.getByText('Test') + expect(badge).toHaveClass('badge', 'badge-s', 'badge-warning', 'interactive') + + fireEvent.click(badge) + expect(handleClick).toHaveBeenCalledTimes(1) + }) + }) + + describe('Edge cases', () => { + it.each([ + { children: 42, text: '42', label: 'numeric value' }, + { children: 0, text: '0', label: 'zero' }, + ])('should render $label correctly', ({ children, text }) => { + render({children}) + + expect(screen.getByText(text)).toBeInTheDocument() + }) + + it.each([ + { children: null, label: 'null' }, + { children: false, label: 'boolean false' }, + ])('should handle $label children without errors', ({ children }) => { + const { container } = render({children}) + + expect(container.firstChild).toHaveClass('badge') + }) + + it('should render complex nested content correctly', () => { + render( + + 🔔 + 5 + , + ) + + expect(screen.getByTestId('icon')).toBeInTheDocument() + expect(screen.getByTestId('count')).toBeInTheDocument() + }) + }) + + describe('Component metadata and exports', () => { + it('should have correct displayName for debugging', () => { + expect(Badge.displayName).toBe('Badge') + }) + + describe('BadgeState enum', () => { + it.each([ + { key: 'Warning', value: 'warning' }, + { key: 'Accent', value: 'accent' }, + { key: 'Default', value: '' }, + ])('should export $key state with value "$value"', ({ key, value }) => { + expect(BadgeState[key as keyof typeof BadgeState]).toBe(value) + }) + }) + + describe('BadgeVariants utility', () => { + it('should be a function', () => { + expect(typeof BadgeVariants).toBe('function') + }) + + it('should generate base badge class with default medium size', () => { + const result = BadgeVariants({}) + + expect(result).toContain('badge') + expect(result).toContain('badge-m') + }) + + it.each([ + { size: 's' }, + { size: 'm' }, + { size: 'l' }, + ] as const)('should generate correct classes for size=$size', ({ size }) => { + const result = BadgeVariants({ size }) + + expect(result).toContain('badge') + expect(result).toContain(`badge-${size}`) + }) + }) + }) +}) diff --git a/web/app/components/base/chat/__tests__/utils.spec.ts b/web/app/components/base/chat/__tests__/utils.spec.ts index 2e86e13733..d3e77732a5 100644 --- a/web/app/components/base/chat/__tests__/utils.spec.ts +++ b/web/app/components/base/chat/__tests__/utils.spec.ts @@ -1,5 +1,5 @@ import type { ChatItemInTree } from '../types' -import { get } from 'lodash-es' +import { get } from 'es-toolkit/compat' import { buildChatItemTree, getThreadMessages } from '../utils' import branchedTestMessages from './branchedTestMessages.json' import legacyTestMessages from './legacyTestMessages.json' diff --git a/web/app/components/base/chat/chat-with-history/context.tsx b/web/app/components/base/chat/chat-with-history/context.tsx index 120b6ed4bd..d1496f8278 100644 --- a/web/app/components/base/chat/chat-with-history/context.tsx +++ b/web/app/components/base/chat/chat-with-history/context.tsx @@ -14,7 +14,7 @@ import type { AppMeta, ConversationItem, } from '@/models/share' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { createContext, useContext } from 'use-context-selector' export type ChatWithHistoryContextValue = { diff --git a/web/app/components/base/chat/chat-with-history/hooks.tsx b/web/app/components/base/chat/chat-with-history/hooks.tsx index 67c46b2d10..3acc480518 100644 --- a/web/app/components/base/chat/chat-with-history/hooks.tsx +++ b/web/app/components/base/chat/chat-with-history/hooks.tsx @@ -10,8 +10,8 @@ import type { ConversationItem, } from '@/models/share' import { useLocalStorageState } from 'ahooks' +import { noop } from 'es-toolkit/compat' import { produce } from 'immer' -import { noop } from 'lodash-es' import { useCallback, useEffect, diff --git a/web/app/components/base/chat/chat/hooks.ts b/web/app/components/base/chat/chat/hooks.ts index 739fe644fe..64ba5f0aec 100644 --- a/web/app/components/base/chat/chat/hooks.ts +++ b/web/app/components/base/chat/chat/hooks.ts @@ -8,8 +8,8 @@ import type { InputForm } from './type' import type AudioPlayer from '@/app/components/base/audio-btn/audio' import type { FileEntity } from '@/app/components/base/file-uploader/types' import type { Annotation } from '@/models/log' +import { noop, uniqBy } from 'es-toolkit/compat' import { produce, setAutoFreeze } from 'immer' -import { noop, uniqBy } from 'lodash-es' import { useParams, usePathname } from 'next/navigation' import { useCallback, diff --git a/web/app/components/base/chat/chat/index.tsx b/web/app/components/base/chat/chat/index.tsx index 5f5faab240..9c27b61e1f 100644 --- a/web/app/components/base/chat/chat/index.tsx +++ b/web/app/components/base/chat/chat/index.tsx @@ -13,7 +13,7 @@ import type { import type { InputForm } from './type' import type { Emoji } from '@/app/components/tools/types' import type { AppData } from '@/models/share' -import { debounce } from 'lodash-es' +import { debounce } from 'es-toolkit/compat' import { memo, useCallback, diff --git a/web/app/components/base/chat/embedded-chatbot/context.tsx b/web/app/components/base/chat/embedded-chatbot/context.tsx index 2738d25c75..97d3dd53cf 100644 --- a/web/app/components/base/chat/embedded-chatbot/context.tsx +++ b/web/app/components/base/chat/embedded-chatbot/context.tsx @@ -13,7 +13,7 @@ import type { AppMeta, ConversationItem, } from '@/models/share' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { createContext, useContext } from 'use-context-selector' export type EmbeddedChatbotContextValue = { diff --git a/web/app/components/base/chat/embedded-chatbot/hooks.tsx b/web/app/components/base/chat/embedded-chatbot/hooks.tsx index 3c7fd576a3..9e9125fc45 100644 --- a/web/app/components/base/chat/embedded-chatbot/hooks.tsx +++ b/web/app/components/base/chat/embedded-chatbot/hooks.tsx @@ -9,8 +9,8 @@ import type { ConversationItem, } from '@/models/share' import { useLocalStorageState } from 'ahooks' +import { noop } from 'es-toolkit/compat' import { produce } from 'immer' -import { noop } from 'lodash-es' import { useCallback, useEffect, diff --git a/web/app/components/base/chip/index.spec.tsx b/web/app/components/base/chip/index.spec.tsx new file mode 100644 index 0000000000..c19cc77b39 --- /dev/null +++ b/web/app/components/base/chip/index.spec.tsx @@ -0,0 +1,394 @@ +import type { Item } from './index' +import { cleanup, fireEvent, render, screen } from '@testing-library/react' +import * as React from 'react' +import Chip from './index' + +afterEach(cleanup) + +// Test data factory +const createTestItems = (): Item[] => [ + { value: 'all', name: 'All Items' }, + { value: 'active', name: 'Active' }, + { value: 'archived', name: 'Archived' }, +] + +describe('Chip', () => { + // Shared test props + let items: Item[] + let onSelect: (item: Item) => void + let onClear: () => void + + beforeEach(() => { + vi.clearAllMocks() + items = createTestItems() + onSelect = vi.fn() + onClear = vi.fn() + }) + + // Helper function to render Chip with default props + const renderChip = (props: Partial> = {}) => { + return render( + , + ) + } + + // Helper function to get the trigger element + const getTrigger = (container: HTMLElement) => { + return container.querySelector('[data-state]') + } + + // Helper function to open dropdown panel + const openPanel = (container: HTMLElement) => { + const trigger = getTrigger(container) + if (trigger) + fireEvent.click(trigger) + } + + describe('Rendering', () => { + it('should render without crashing', () => { + renderChip() + + expect(screen.getByText('All Items')).toBeInTheDocument() + }) + + it('should display current selected item name', () => { + renderChip({ value: 'active' }) + + expect(screen.getByText('Active')).toBeInTheDocument() + }) + + it('should display empty content when value does not match any item', () => { + const { container } = renderChip({ value: 'nonexistent' }) + + // When value doesn't match, no text should be displayed in trigger + const trigger = getTrigger(container) + // Check that there's no item name text (only icons should be present) + expect(trigger?.textContent?.trim()).toBeFalsy() + }) + }) + + describe('Props', () => { + it('should update displayed item name when value prop changes', () => { + const { rerender } = renderChip({ value: 'all' }) + expect(screen.getByText('All Items')).toBeInTheDocument() + + rerender( + , + ) + expect(screen.getByText('Archived')).toBeInTheDocument() + }) + + it('should show left icon by default', () => { + const { container } = renderChip() + + // The filter icon should be visible + const svg = container.querySelector('svg') + expect(svg).toBeInTheDocument() + }) + + it('should hide left icon when showLeftIcon is false', () => { + renderChip({ showLeftIcon: false }) + + // When showLeftIcon is false, there should be no filter icon before the text + const textElement = screen.getByText('All Items') + const parent = textElement.closest('div[data-state]') + const icons = parent?.querySelectorAll('svg') + + // Should only have the arrow icon, not the filter icon + expect(icons?.length).toBe(1) + }) + + it('should render custom left icon', () => { + const CustomIcon = () => ★ + + renderChip({ leftIcon: }) + + expect(screen.getByTestId('custom-icon')).toBeInTheDocument() + }) + + it('should apply custom className to trigger', () => { + const customClass = 'custom-chip-class' + + const { container } = renderChip({ className: customClass }) + + const chipElement = container.querySelector(`.${customClass}`) + expect(chipElement).toBeInTheDocument() + }) + + it('should apply custom panelClassName to dropdown panel', () => { + const customPanelClass = 'custom-panel-class' + + const { container } = renderChip({ panelClassName: customPanelClass }) + openPanel(container) + + // Panel is rendered in a portal, so check document.body + const panel = document.body.querySelector(`.${customPanelClass}`) + expect(panel).toBeInTheDocument() + }) + }) + + describe('State Management', () => { + it('should toggle dropdown panel on trigger click', () => { + const { container } = renderChip() + + // Initially closed - check data-state attribute + const trigger = getTrigger(container) + expect(trigger).toHaveAttribute('data-state', 'closed') + + // Open panel + openPanel(container) + expect(trigger).toHaveAttribute('data-state', 'open') + // Panel items should be visible + expect(screen.getAllByText('All Items').length).toBeGreaterThan(1) + + // Close panel + if (trigger) + fireEvent.click(trigger) + expect(trigger).toHaveAttribute('data-state', 'closed') + }) + + it('should close panel after selecting an item', () => { + const { container } = renderChip() + + openPanel(container) + const trigger = getTrigger(container) + expect(trigger).toHaveAttribute('data-state', 'open') + + // Click on an item in the dropdown panel + const activeItems = screen.getAllByText('Active') + // The second one should be in the dropdown + fireEvent.click(activeItems[activeItems.length - 1]) + + expect(trigger).toHaveAttribute('data-state', 'closed') + }) + }) + + describe('Event Handlers', () => { + it('should call onSelect with correct item when item is clicked', () => { + const { container } = renderChip() + + openPanel(container) + // Get all "Active" texts and click the one in the dropdown (should be the last one) + const activeItems = screen.getAllByText('Active') + fireEvent.click(activeItems[activeItems.length - 1]) + + expect(onSelect).toHaveBeenCalledTimes(1) + expect(onSelect).toHaveBeenCalledWith(items[1]) + }) + + it('should call onClear when clear button is clicked', () => { + const { container } = renderChip({ value: 'active' }) + + // Find the close icon (last SVG in the trigger) and click its parent + const trigger = getTrigger(container) + const svgs = trigger?.querySelectorAll('svg') + // The close icon should be the last SVG element + const closeIcon = svgs?.[svgs.length - 1] + const clearButton = closeIcon?.parentElement + + expect(clearButton).toBeInTheDocument() + if (clearButton) + fireEvent.click(clearButton) + + expect(onClear).toHaveBeenCalledTimes(1) + }) + + it('should stop event propagation when clear button is clicked', () => { + const { container } = renderChip({ value: 'active' }) + + const trigger = getTrigger(container) + expect(trigger).toHaveAttribute('data-state', 'closed') + + // Find the close icon (last SVG) and click its parent + const svgs = trigger?.querySelectorAll('svg') + const closeIcon = svgs?.[svgs.length - 1] + const clearButton = closeIcon?.parentElement + + if (clearButton) + fireEvent.click(clearButton) + + // Panel should remain closed + expect(trigger).toHaveAttribute('data-state', 'closed') + expect(onClear).toHaveBeenCalledTimes(1) + }) + + it('should handle multiple rapid clicks on trigger', () => { + const { container } = renderChip() + + const trigger = getTrigger(container) + + // Click 1: open + if (trigger) + fireEvent.click(trigger) + expect(trigger).toHaveAttribute('data-state', 'open') + + // Click 2: close + if (trigger) + fireEvent.click(trigger) + expect(trigger).toHaveAttribute('data-state', 'closed') + + // Click 3: open again + if (trigger) + fireEvent.click(trigger) + expect(trigger).toHaveAttribute('data-state', 'open') + }) + }) + + describe('Conditional Rendering', () => { + it('should show arrow down icon when no value is selected', () => { + const { container } = renderChip({ value: '' }) + + // Should have SVG icons (filter icon and arrow down icon) + const svgs = container.querySelectorAll('svg') + expect(svgs.length).toBeGreaterThan(0) + }) + + it('should show clear button when value is selected', () => { + const { container } = renderChip({ value: 'active' }) + + // When value is selected, there should be an icon (the close icon) + const svgs = container.querySelectorAll('svg') + expect(svgs.length).toBeGreaterThan(0) + }) + + it('should not show clear button when no value is selected', () => { + const { container } = renderChip({ value: '' }) + + const trigger = getTrigger(container) + + // When value is empty, the trigger should only have 2 SVGs (filter icon + arrow) + // When value is selected, it would have 2 SVGs (filter icon + close icon) + const svgs = trigger?.querySelectorAll('svg') + // Arrow icon should be present, close icon should not + expect(svgs?.length).toBe(2) + + // Verify onClear hasn't been called + expect(onClear).not.toHaveBeenCalled() + }) + + it('should show dropdown content only when panel is open', () => { + const { container } = renderChip() + + const trigger = getTrigger(container) + + // Closed by default + expect(trigger).toHaveAttribute('data-state', 'closed') + + openPanel(container) + expect(trigger).toHaveAttribute('data-state', 'open') + // Items should be duplicated (once in trigger, once in panel) + expect(screen.getAllByText('All Items').length).toBeGreaterThan(1) + }) + + it('should show check icon on selected item in dropdown', () => { + const { container } = renderChip({ value: 'active' }) + + openPanel(container) + + // Find the dropdown panel items + const allActiveTexts = screen.getAllByText('Active') + // The dropdown item should be the last one + const dropdownItem = allActiveTexts[allActiveTexts.length - 1] + const parentContainer = dropdownItem.parentElement + + // The check icon should be a sibling within the parent + const checkIcon = parentContainer?.querySelector('svg') + expect(checkIcon).toBeInTheDocument() + }) + + it('should render all items in dropdown when open', () => { + const { container } = renderChip() + + openPanel(container) + + // Each item should appear at least twice (once in potential selected state, once in dropdown) + // Use getAllByText to handle multiple occurrences + expect(screen.getAllByText('All Items').length).toBeGreaterThan(0) + expect(screen.getAllByText('Active').length).toBeGreaterThan(0) + expect(screen.getAllByText('Archived').length).toBeGreaterThan(0) + }) + }) + + describe('Edge Cases', () => { + it('should handle empty items array', () => { + const { container } = renderChip({ items: [], value: '' }) + + // Trigger should still render + const trigger = container.querySelector('[data-state]') + expect(trigger).toBeInTheDocument() + }) + + it('should handle value not in items list', () => { + const { container } = renderChip({ value: 'nonexistent' }) + + const trigger = getTrigger(container) + expect(trigger).toBeInTheDocument() + + // The trigger should not display any item name text + expect(trigger?.textContent?.trim()).toBeFalsy() + }) + + it('should allow selecting already selected item', () => { + const { container } = renderChip({ value: 'active' }) + + openPanel(container) + + // Click on the already selected item in the dropdown + const activeItems = screen.getAllByText('Active') + fireEvent.click(activeItems[activeItems.length - 1]) + + expect(onSelect).toHaveBeenCalledTimes(1) + expect(onSelect).toHaveBeenCalledWith(items[1]) + }) + + it('should handle numeric values', () => { + const numericItems: Item[] = [ + { value: 1, name: 'First' }, + { value: 2, name: 'Second' }, + { value: 3, name: 'Third' }, + ] + + const { container } = renderChip({ value: 2, items: numericItems }) + + expect(screen.getByText('Second')).toBeInTheDocument() + + // Open panel and select Third + openPanel(container) + + const thirdItems = screen.getAllByText('Third') + fireEvent.click(thirdItems[thirdItems.length - 1]) + + expect(onSelect).toHaveBeenCalledWith(numericItems[2]) + }) + + it('should handle items with additional properties', () => { + const itemsWithExtra: Item[] = [ + { value: 'a', name: 'Item A', customProp: 'extra1' }, + { value: 'b', name: 'Item B', customProp: 'extra2' }, + ] + + const { container } = renderChip({ value: 'a', items: itemsWithExtra }) + + expect(screen.getByText('Item A')).toBeInTheDocument() + + // Open panel and select Item B + openPanel(container) + + const itemBs = screen.getAllByText('Item B') + fireEvent.click(itemBs[itemBs.length - 1]) + + expect(onSelect).toHaveBeenCalledWith(itemsWithExtra[1]) + }) + }) +}) diff --git a/web/app/components/base/copy-feedback/index.tsx b/web/app/components/base/copy-feedback/index.tsx index bf809a2d18..bb71d62c11 100644 --- a/web/app/components/base/copy-feedback/index.tsx +++ b/web/app/components/base/copy-feedback/index.tsx @@ -4,7 +4,7 @@ import { RiClipboardLine, } from '@remixicon/react' import copy from 'copy-to-clipboard' -import { debounce } from 'lodash-es' +import { debounce } from 'es-toolkit/compat' import * as React from 'react' import { useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/base/copy-icon/index.tsx b/web/app/components/base/copy-icon/index.tsx index 935444a3c1..73a0d80b45 100644 --- a/web/app/components/base/copy-icon/index.tsx +++ b/web/app/components/base/copy-icon/index.tsx @@ -1,6 +1,6 @@ 'use client' import copy from 'copy-to-clipboard' -import { debounce } from 'lodash-es' +import { debounce } from 'es-toolkit/compat' import * as React from 'react' import { useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/base/emoji-picker/index.tsx b/web/app/components/base/emoji-picker/index.tsx index 53bef278f6..4fc146ab59 100644 --- a/web/app/components/base/emoji-picker/index.tsx +++ b/web/app/components/base/emoji-picker/index.tsx @@ -1,6 +1,6 @@ 'use client' import type { FC } from 'react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/base/features/new-feature-panel/conversation-opener/modal.tsx b/web/app/components/base/features/new-feature-panel/conversation-opener/modal.tsx index a1b66ae0fc..361f24465f 100644 --- a/web/app/components/base/features/new-feature-panel/conversation-opener/modal.tsx +++ b/web/app/components/base/features/new-feature-panel/conversation-opener/modal.tsx @@ -3,8 +3,8 @@ import type { InputVar } from '@/app/components/workflow/types' import type { PromptVariable } from '@/models/debug' import { RiAddLine, RiAsterisk, RiCloseLine, RiDeleteBinLine, RiDraggable } from '@remixicon/react' import { useBoolean } from 'ahooks' +import { noop } from 'es-toolkit/compat' import { produce } from 'immer' -import { noop } from 'lodash-es' import * as React from 'react' import { useCallback, useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/base/features/new-feature-panel/moderation/moderation-setting-modal.tsx b/web/app/components/base/features/new-feature-panel/moderation/moderation-setting-modal.tsx index d1e6aba6b7..7de0119e59 100644 --- a/web/app/components/base/features/new-feature-panel/moderation/moderation-setting-modal.tsx +++ b/web/app/components/base/features/new-feature-panel/moderation/moderation-setting-modal.tsx @@ -2,7 +2,7 @@ import type { ChangeEvent, FC } from 'react' import type { CodeBasedExtensionItem } from '@/models/common' import type { ModerationConfig, ModerationContentConfig } from '@/models/debug' import { RiCloseLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useState } from 'react' import { useTranslation } from 'react-i18next' import { useContext } from 'use-context-selector' diff --git a/web/app/components/base/file-uploader/hooks.ts b/web/app/components/base/file-uploader/hooks.ts index e62addee2d..6678368462 100644 --- a/web/app/components/base/file-uploader/hooks.ts +++ b/web/app/components/base/file-uploader/hooks.ts @@ -2,8 +2,8 @@ import type { ClipboardEvent } from 'react' import type { FileEntity } from './types' import type { FileUpload } from '@/app/components/base/features/types' import type { FileUploadConfigResponse } from '@/models/common' +import { noop } from 'es-toolkit/compat' import { produce } from 'immer' -import { noop } from 'lodash-es' import { useParams } from 'next/navigation' import { useCallback, diff --git a/web/app/components/base/file-uploader/pdf-preview.tsx b/web/app/components/base/file-uploader/pdf-preview.tsx index 04a90a414c..b4f057e91e 100644 --- a/web/app/components/base/file-uploader/pdf-preview.tsx +++ b/web/app/components/base/file-uploader/pdf-preview.tsx @@ -1,7 +1,7 @@ import type { FC } from 'react' import { RiCloseLine, RiZoomInLine, RiZoomOutLine } from '@remixicon/react' +import { noop } from 'es-toolkit/compat' import { t } from 'i18next' -import { noop } from 'lodash-es' import * as React from 'react' import { useState } from 'react' import { createPortal } from 'react-dom' diff --git a/web/app/components/base/file-uploader/store.tsx b/web/app/components/base/file-uploader/store.tsx index db3e3622f9..2172733f20 100644 --- a/web/app/components/base/file-uploader/store.tsx +++ b/web/app/components/base/file-uploader/store.tsx @@ -1,7 +1,7 @@ import type { FileEntity, } from './types' -import { isEqual } from 'lodash-es' +import { isEqual } from 'es-toolkit/compat' import { createContext, useContext, diff --git a/web/app/components/base/fullscreen-modal/index.tsx b/web/app/components/base/fullscreen-modal/index.tsx index b822d21921..cad91b2452 100644 --- a/web/app/components/base/fullscreen-modal/index.tsx +++ b/web/app/components/base/fullscreen-modal/index.tsx @@ -1,6 +1,6 @@ import { Dialog, DialogPanel, Transition, TransitionChild } from '@headlessui/react' import { RiCloseLargeLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { cn } from '@/utils/classnames' type IModal = { diff --git a/web/app/components/base/icons/script.mjs b/web/app/components/base/icons/script.mjs index 1cee66d1db..81566cc4cf 100644 --- a/web/app/components/base/icons/script.mjs +++ b/web/app/components/base/icons/script.mjs @@ -2,7 +2,7 @@ import { access, appendFile, mkdir, open, readdir, rm, writeFile } from 'node:fs import path from 'node:path' import { fileURLToPath } from 'node:url' import { parseXml } from '@rgrove/parse-xml' -import { camelCase, template } from 'lodash-es' +import { camelCase, template } from 'es-toolkit/compat' const __dirname = path.dirname(fileURLToPath(import.meta.url)) diff --git a/web/app/components/base/image-uploader/image-preview.tsx b/web/app/components/base/image-uploader/image-preview.tsx index bfabe5e247..519bed4d25 100644 --- a/web/app/components/base/image-uploader/image-preview.tsx +++ b/web/app/components/base/image-uploader/image-preview.tsx @@ -1,7 +1,7 @@ import type { FC } from 'react' import { RiAddBoxLine, RiCloseLine, RiDownloadCloud2Line, RiFileCopyLine, RiZoomInLine, RiZoomOutLine } from '@remixicon/react' +import { noop } from 'es-toolkit/compat' import { t } from 'i18next' -import { noop } from 'lodash-es' import * as React from 'react' import { useCallback, useEffect, useRef, useState } from 'react' import { createPortal } from 'react-dom' diff --git a/web/app/components/base/input-with-copy/index.spec.tsx b/web/app/components/base/input-with-copy/index.spec.tsx index 782b2bab25..a5fde4ea44 100644 --- a/web/app/components/base/input-with-copy/index.spec.tsx +++ b/web/app/components/base/input-with-copy/index.spec.tsx @@ -25,8 +25,8 @@ vi.mock('react-i18next', () => ({ }), })) -// Mock lodash-es debounce -vi.mock('lodash-es', () => ({ +// Mock es-toolkit/compat debounce +vi.mock('es-toolkit/compat', () => ({ debounce: (fn: any) => fn, })) diff --git a/web/app/components/base/input-with-copy/index.tsx b/web/app/components/base/input-with-copy/index.tsx index 151fa435e7..41bb8f3dec 100644 --- a/web/app/components/base/input-with-copy/index.tsx +++ b/web/app/components/base/input-with-copy/index.tsx @@ -2,7 +2,7 @@ import type { InputProps } from '../input' import { RiClipboardFill, RiClipboardLine } from '@remixicon/react' import copy from 'copy-to-clipboard' -import { debounce } from 'lodash-es' +import { debounce } from 'es-toolkit/compat' import * as React from 'react' import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/base/input/index.tsx b/web/app/components/base/input/index.tsx index 6c6a0c6a75..db7d1f0990 100644 --- a/web/app/components/base/input/index.tsx +++ b/web/app/components/base/input/index.tsx @@ -2,7 +2,7 @@ import type { VariantProps } from 'class-variance-authority' import type { ChangeEventHandler, CSSProperties, FocusEventHandler } from 'react' import { RiCloseCircleFill, RiErrorWarningLine, RiSearchLine } from '@remixicon/react' import { cva } from 'class-variance-authority' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useTranslation } from 'react-i18next' import { cn } from '@/utils/classnames' diff --git a/web/app/components/base/markdown/index.tsx b/web/app/components/base/markdown/index.tsx index e698f3bebe..c487b20550 100644 --- a/web/app/components/base/markdown/index.tsx +++ b/web/app/components/base/markdown/index.tsx @@ -1,5 +1,5 @@ import type { ReactMarkdownWrapperProps, SimplePluginInfo } from './react-markdown-wrapper' -import { flow } from 'lodash-es' +import { flow } from 'es-toolkit/compat' import dynamic from 'next/dynamic' import { cn } from '@/utils/classnames' import { preprocessLaTeX, preprocessThinkTag } from './markdown-utils' diff --git a/web/app/components/base/markdown/markdown-utils.ts b/web/app/components/base/markdown/markdown-utils.ts index 59326a7a19..94ad31d1de 100644 --- a/web/app/components/base/markdown/markdown-utils.ts +++ b/web/app/components/base/markdown/markdown-utils.ts @@ -3,7 +3,7 @@ * These functions were extracted from the main markdown renderer for better separation of concerns. * Includes preprocessing for LaTeX and custom "think" tags. */ -import { flow } from 'lodash-es' +import { flow } from 'es-toolkit/compat' import { ALLOW_UNSAFE_DATA_SCHEME } from '@/config' export const preprocessLaTeX = (content: string) => { diff --git a/web/app/components/base/modal/index.tsx b/web/app/components/base/modal/index.tsx index 1b0ff22873..7270af1c77 100644 --- a/web/app/components/base/modal/index.tsx +++ b/web/app/components/base/modal/index.tsx @@ -1,6 +1,6 @@ import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from '@headlessui/react' import { RiCloseLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { Fragment } from 'react' import { cn } from '@/utils/classnames' // https://headlessui.com/react/dialog diff --git a/web/app/components/base/modal/modal.tsx b/web/app/components/base/modal/modal.tsx index 69bca1ccbb..6fa44d42d0 100644 --- a/web/app/components/base/modal/modal.tsx +++ b/web/app/components/base/modal/modal.tsx @@ -1,6 +1,6 @@ import type { ButtonProps } from '@/app/components/base/button' import { RiCloseLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { memo } from 'react' import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' diff --git a/web/app/components/base/pagination/pagination.tsx b/web/app/components/base/pagination/pagination.tsx index 25bdf5a31b..dafe0e4ab9 100644 --- a/web/app/components/base/pagination/pagination.tsx +++ b/web/app/components/base/pagination/pagination.tsx @@ -4,7 +4,7 @@ import type { IPaginationProps, PageButtonProps, } from './type' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { cn } from '@/utils/classnames' import usePagination from './hook' diff --git a/web/app/components/base/prompt-editor/plugins/context-block/context-block-replacement-block.tsx b/web/app/components/base/prompt-editor/plugins/context-block/context-block-replacement-block.tsx index 2d2a0b6263..c4a246c40d 100644 --- a/web/app/components/base/prompt-editor/plugins/context-block/context-block-replacement-block.tsx +++ b/web/app/components/base/prompt-editor/plugins/context-block/context-block-replacement-block.tsx @@ -1,8 +1,8 @@ import type { ContextBlockType } from '../../types' import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext' import { mergeRegister } from '@lexical/utils' +import { noop } from 'es-toolkit/compat' import { $applyNodeReplacement } from 'lexical' -import { noop } from 'lodash-es' import { memo, useCallback, diff --git a/web/app/components/base/prompt-editor/plugins/context-block/index.tsx b/web/app/components/base/prompt-editor/plugins/context-block/index.tsx index 9f2102bc62..ce3ed4c210 100644 --- a/web/app/components/base/prompt-editor/plugins/context-block/index.tsx +++ b/web/app/components/base/prompt-editor/plugins/context-block/index.tsx @@ -1,12 +1,12 @@ import type { ContextBlockType } from '../../types' import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext' import { mergeRegister } from '@lexical/utils' +import { noop } from 'es-toolkit/compat' import { $insertNodes, COMMAND_PRIORITY_EDITOR, createCommand, } from 'lexical' -import { noop } from 'lodash-es' import { memo, useEffect, diff --git a/web/app/components/base/prompt-editor/plugins/history-block/history-block-replacement-block.tsx b/web/app/components/base/prompt-editor/plugins/history-block/history-block-replacement-block.tsx index ba695ec95d..f62fb6886b 100644 --- a/web/app/components/base/prompt-editor/plugins/history-block/history-block-replacement-block.tsx +++ b/web/app/components/base/prompt-editor/plugins/history-block/history-block-replacement-block.tsx @@ -1,8 +1,8 @@ import type { HistoryBlockType } from '../../types' import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext' import { mergeRegister } from '@lexical/utils' +import { noop } from 'es-toolkit/compat' import { $applyNodeReplacement } from 'lexical' -import { noop } from 'lodash-es' import { useCallback, useEffect, diff --git a/web/app/components/base/prompt-editor/plugins/history-block/index.tsx b/web/app/components/base/prompt-editor/plugins/history-block/index.tsx index a853de5162..dc75fc230d 100644 --- a/web/app/components/base/prompt-editor/plugins/history-block/index.tsx +++ b/web/app/components/base/prompt-editor/plugins/history-block/index.tsx @@ -1,12 +1,12 @@ import type { HistoryBlockType } from '../../types' import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext' import { mergeRegister } from '@lexical/utils' +import { noop } from 'es-toolkit/compat' import { $insertNodes, COMMAND_PRIORITY_EDITOR, createCommand, } from 'lexical' -import { noop } from 'lodash-es' import { memo, useEffect, diff --git a/web/app/components/base/radio-card/index.tsx b/web/app/components/base/radio-card/index.tsx index ae8bb00099..678d5b6dee 100644 --- a/web/app/components/base/radio-card/index.tsx +++ b/web/app/components/base/radio-card/index.tsx @@ -1,6 +1,6 @@ 'use client' import type { FC } from 'react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { cn } from '@/utils/classnames' diff --git a/web/app/components/base/tag-management/panel.tsx b/web/app/components/base/tag-management/panel.tsx index 854de012a5..0023a003c5 100644 --- a/web/app/components/base/tag-management/panel.tsx +++ b/web/app/components/base/tag-management/panel.tsx @@ -3,7 +3,7 @@ import type { HtmlContentProps } from '@/app/components/base/popover' import type { Tag } from '@/app/components/base/tag-management/constant' import { RiAddLine, RiPriceTag3Line } from '@remixicon/react' import { useUnmount } from 'ahooks' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/base/tag-management/tag-remove-modal.tsx b/web/app/components/base/tag-management/tag-remove-modal.tsx index 8e796f8e0f..8061cde5c1 100644 --- a/web/app/components/base/tag-management/tag-remove-modal.tsx +++ b/web/app/components/base/tag-management/tag-remove-modal.tsx @@ -2,7 +2,7 @@ import type { Tag } from '@/app/components/base/tag-management/constant' import { RiCloseLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback' diff --git a/web/app/components/base/toast/index.spec.tsx b/web/app/components/base/toast/index.spec.tsx index d32619f59a..59314063dd 100644 --- a/web/app/components/base/toast/index.spec.tsx +++ b/web/app/components/base/toast/index.spec.tsx @@ -1,6 +1,6 @@ import type { ReactNode } from 'react' import { act, render, screen, waitFor } from '@testing-library/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import Toast, { ToastProvider, useToastContext } from '.' diff --git a/web/app/components/base/toast/index.tsx b/web/app/components/base/toast/index.tsx index a016778996..cf9e1cd909 100644 --- a/web/app/components/base/toast/index.tsx +++ b/web/app/components/base/toast/index.tsx @@ -7,7 +7,7 @@ import { RiErrorWarningFill, RiInformation2Fill, } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useEffect, useState } from 'react' import { createRoot } from 'react-dom/client' diff --git a/web/app/components/base/with-input-validation/index.spec.tsx b/web/app/components/base/with-input-validation/index.spec.tsx index c1a9d55f0a..b2e67ce056 100644 --- a/web/app/components/base/with-input-validation/index.spec.tsx +++ b/web/app/components/base/with-input-validation/index.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { z } from 'zod' import withValidation from '.' diff --git a/web/app/components/datasets/common/document-status-with-action/index-failed.tsx b/web/app/components/datasets/common/document-status-with-action/index-failed.tsx index 1635720037..f685eb1f2e 100644 --- a/web/app/components/datasets/common/document-status-with-action/index-failed.tsx +++ b/web/app/components/datasets/common/document-status-with-action/index-failed.tsx @@ -1,7 +1,7 @@ 'use client' import type { FC } from 'react' import type { IndexingStatusResponse } from '@/models/datasets' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useEffect, useReducer } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/index.tsx b/web/app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/index.tsx index d5955d9bc6..b8c413ba8f 100644 --- a/web/app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/index.tsx +++ b/web/app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/index.tsx @@ -1,6 +1,6 @@ 'use client' import { useDebounceFn, useKeyPress } from 'ahooks' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useRouter } from 'next/navigation' import { useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/datasets/create/step-two/index.tsx b/web/app/components/datasets/create/step-two/index.tsx index 981b6c5a8f..e0a330507c 100644 --- a/web/app/components/datasets/create/step-two/index.tsx +++ b/web/app/components/datasets/create/step-two/index.tsx @@ -9,7 +9,7 @@ import { RiArrowLeftLine, RiSearchEyeLine, } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import Image from 'next/image' import Link from 'next/link' import * as React from 'react' diff --git a/web/app/components/datasets/documents/detail/batch-modal/index.tsx b/web/app/components/datasets/documents/detail/batch-modal/index.tsx index 091d5c493e..0d7199c6c6 100644 --- a/web/app/components/datasets/documents/detail/batch-modal/index.tsx +++ b/web/app/components/datasets/documents/detail/batch-modal/index.tsx @@ -2,7 +2,7 @@ import type { FC } from 'react' import type { ChunkingMode, FileItem } from '@/models/datasets' import { RiCloseLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/datasets/documents/detail/completed/common/full-screen-drawer.tsx b/web/app/components/datasets/documents/detail/completed/common/full-screen-drawer.tsx index 5f62bf0185..73b5cbdef9 100644 --- a/web/app/components/datasets/documents/detail/completed/common/full-screen-drawer.tsx +++ b/web/app/components/datasets/documents/detail/completed/common/full-screen-drawer.tsx @@ -1,4 +1,4 @@ -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { cn } from '@/utils/classnames' import Drawer from './drawer' diff --git a/web/app/components/datasets/documents/detail/completed/common/regeneration-modal.tsx b/web/app/components/datasets/documents/detail/completed/common/regeneration-modal.tsx index 4957104e25..114d713170 100644 --- a/web/app/components/datasets/documents/detail/completed/common/regeneration-modal.tsx +++ b/web/app/components/datasets/documents/detail/completed/common/regeneration-modal.tsx @@ -1,7 +1,7 @@ import type { FC } from 'react' import { RiLoader2Line } from '@remixicon/react' import { useCountDown } from 'ahooks' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useRef, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/datasets/documents/detail/completed/index.tsx b/web/app/components/datasets/documents/detail/completed/index.tsx index 1b4aadfa50..e149125865 100644 --- a/web/app/components/datasets/documents/detail/completed/index.tsx +++ b/web/app/components/datasets/documents/detail/completed/index.tsx @@ -4,7 +4,7 @@ import type { Item } from '@/app/components/base/select' import type { FileEntity } from '@/app/components/datasets/common/image-uploader/types' import type { ChildChunkDetail, SegmentDetailModel, SegmentUpdater } from '@/models/datasets' import { useDebounceFn } from 'ahooks' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { usePathname } from 'next/navigation' import * as React from 'react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' diff --git a/web/app/components/datasets/documents/detail/metadata/index.tsx b/web/app/components/datasets/documents/detail/metadata/index.tsx index 87d136c3fe..dbae76491e 100644 --- a/web/app/components/datasets/documents/detail/metadata/index.tsx +++ b/web/app/components/datasets/documents/detail/metadata/index.tsx @@ -4,7 +4,7 @@ import type { inputType, metadataType } from '@/hooks/use-metadata' import type { CommonResponse } from '@/models/common' import type { DocType, FullDocumentDetail } from '@/models/datasets' import { PencilIcon } from '@heroicons/react/24/outline' -import { get } from 'lodash-es' +import { get } from 'es-toolkit/compat' import * as React from 'react' import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/datasets/documents/detail/settings/pipeline-settings/index.tsx b/web/app/components/datasets/documents/detail/settings/pipeline-settings/index.tsx index 2d71fa9e7d..2eac6b788d 100644 --- a/web/app/components/datasets/documents/detail/settings/pipeline-settings/index.tsx +++ b/web/app/components/datasets/documents/detail/settings/pipeline-settings/index.tsx @@ -1,7 +1,7 @@ import type { NotionPage } from '@/models/common' import type { CrawlResultItem, CustomFile, FileIndexingEstimateResponse } from '@/models/datasets' import type { OnlineDriveFile, PublishedPipelineRunPreviewResponse } from '@/models/pipeline' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useRouter } from 'next/navigation' import { useCallback, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/datasets/documents/list.tsx b/web/app/components/datasets/documents/list.tsx index 0b06d5fe15..670cdd659c 100644 --- a/web/app/components/datasets/documents/list.tsx +++ b/web/app/components/datasets/documents/list.tsx @@ -9,7 +9,7 @@ import { RiGlobalLine, } from '@remixicon/react' import { useBoolean } from 'ahooks' -import { pick, uniq } from 'lodash-es' +import { pick, uniq } from 'es-toolkit/compat' import { useRouter } from 'next/navigation' import * as React from 'react' import { useCallback, useEffect, useMemo, useState } from 'react' diff --git a/web/app/components/datasets/documents/operations.tsx b/web/app/components/datasets/documents/operations.tsx index 825a315178..038a89b56e 100644 --- a/web/app/components/datasets/documents/operations.tsx +++ b/web/app/components/datasets/documents/operations.tsx @@ -11,7 +11,7 @@ import { RiPlayCircleLine, } from '@remixicon/react' import { useBoolean, useDebounceFn } from 'ahooks' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useRouter } from 'next/navigation' import * as React from 'react' import { useCallback, useState } from 'react' diff --git a/web/app/components/datasets/metadata/hooks/use-metadata-document.ts b/web/app/components/datasets/metadata/hooks/use-metadata-document.ts index 66dfc0384f..4de18f6e50 100644 --- a/web/app/components/datasets/metadata/hooks/use-metadata-document.ts +++ b/web/app/components/datasets/metadata/hooks/use-metadata-document.ts @@ -1,6 +1,6 @@ import type { BuiltInMetadataItem, MetadataItemWithValue } from '../types' import type { FullDocumentDetail } from '@/models/datasets' -import { get } from 'lodash-es' +import { get } from 'es-toolkit/compat' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import Toast from '@/app/components/base/toast' diff --git a/web/app/components/datasets/metadata/metadata-dataset/create-content.tsx b/web/app/components/datasets/metadata/metadata-dataset/create-content.tsx index d31e9d7957..85fd01b2bb 100644 --- a/web/app/components/datasets/metadata/metadata-dataset/create-content.tsx +++ b/web/app/components/datasets/metadata/metadata-dataset/create-content.tsx @@ -1,7 +1,7 @@ 'use client' import type { FC } from 'react' import { RiArrowLeftLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/datasets/rename-modal/index.tsx b/web/app/components/datasets/rename-modal/index.tsx index 8b152b8f02..ef988fc9bc 100644 --- a/web/app/components/datasets/rename-modal/index.tsx +++ b/web/app/components/datasets/rename-modal/index.tsx @@ -4,7 +4,7 @@ import type { MouseEventHandler } from 'react' import type { AppIconSelection } from '../../base/app-icon-picker' import type { DataSet } from '@/models/datasets' import { RiCloseLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useCallback, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' diff --git a/web/app/components/explore/create-app-modal/index.tsx b/web/app/components/explore/create-app-modal/index.tsx index dac89bc776..b05188fe4d 100644 --- a/web/app/components/explore/create-app-modal/index.tsx +++ b/web/app/components/explore/create-app-modal/index.tsx @@ -2,7 +2,7 @@ import type { AppIconType } from '@/types/app' import { RiCloseLine, RiCommandLine, RiCornerDownLeftLine } from '@remixicon/react' import { useDebounceFn, useKeyPress } from 'ahooks' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/header/account-setting/api-based-extension-page/modal.tsx b/web/app/components/header/account-setting/api-based-extension-page/modal.tsx index d1f64f0d59..f691044bd3 100644 --- a/web/app/components/header/account-setting/api-based-extension-page/modal.tsx +++ b/web/app/components/header/account-setting/api-based-extension-page/modal.tsx @@ -1,6 +1,6 @@ import type { FC } from 'react' import type { ApiBasedExtension } from '@/models/common' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useState } from 'react' import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' diff --git a/web/app/components/header/account-setting/data-source-page/data-source-notion/index.tsx b/web/app/components/header/account-setting/data-source-page/data-source-notion/index.tsx index d139ab39df..2766dc016c 100644 --- a/web/app/components/header/account-setting/data-source-page/data-source-notion/index.tsx +++ b/web/app/components/header/account-setting/data-source-page/data-source-notion/index.tsx @@ -1,7 +1,7 @@ 'use client' import type { FC } from 'react' import type { DataSourceNotion as TDataSourceNotion } from '@/models/common' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/header/account-setting/data-source-page/panel/config-item.tsx b/web/app/components/header/account-setting/data-source-page/panel/config-item.tsx index b98dd7933d..c57ef96bf9 100644 --- a/web/app/components/header/account-setting/data-source-page/panel/config-item.tsx +++ b/web/app/components/header/account-setting/data-source-page/panel/config-item.tsx @@ -3,7 +3,7 @@ import type { FC } from 'react' import { RiDeleteBinLine, } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useTranslation } from 'react-i18next' import { cn } from '@/utils/classnames' diff --git a/web/app/components/header/account-setting/key-validator/hooks.ts b/web/app/components/header/account-setting/key-validator/hooks.ts index eeb7b63955..4d4cf8d8a4 100644 --- a/web/app/components/header/account-setting/key-validator/hooks.ts +++ b/web/app/components/header/account-setting/key-validator/hooks.ts @@ -1,4 +1,4 @@ -import type { DebouncedFunc } from 'lodash-es' +import type { DebouncedFunc } from 'es-toolkit/compat' import type { ValidateCallback, ValidatedStatusState, ValidateValue } from './declarations' import { useDebounceFn } from 'ahooks' import { useState } from 'react' diff --git a/web/app/components/header/account-setting/members-page/edit-workspace-modal/index.tsx b/web/app/components/header/account-setting/members-page/edit-workspace-modal/index.tsx index 7d609dba68..31f3fc0afe 100644 --- a/web/app/components/header/account-setting/members-page/edit-workspace-modal/index.tsx +++ b/web/app/components/header/account-setting/members-page/edit-workspace-modal/index.tsx @@ -1,6 +1,6 @@ 'use client' import { RiCloseLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useState } from 'react' import { useTranslation } from 'react-i18next' import { useContext } from 'use-context-selector' diff --git a/web/app/components/header/account-setting/members-page/invite-modal/index.tsx b/web/app/components/header/account-setting/members-page/invite-modal/index.tsx index 9b80cd343d..93d88fc4ea 100644 --- a/web/app/components/header/account-setting/members-page/invite-modal/index.tsx +++ b/web/app/components/header/account-setting/members-page/invite-modal/index.tsx @@ -2,7 +2,7 @@ import type { InvitationResult } from '@/models/common' import { RiCloseLine, RiErrorWarningFill } from '@remixicon/react' import { useBoolean } from 'ahooks' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useCallback, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { ReactMultiEmail } from 'react-multi-email' diff --git a/web/app/components/header/account-setting/members-page/invited-modal/index.tsx b/web/app/components/header/account-setting/members-page/invited-modal/index.tsx index 5fb6c410c4..829eb364a4 100644 --- a/web/app/components/header/account-setting/members-page/invited-modal/index.tsx +++ b/web/app/components/header/account-setting/members-page/invited-modal/index.tsx @@ -2,7 +2,7 @@ import type { InvitationResult } from '@/models/common' import { XMarkIcon } from '@heroicons/react/24/outline' import { CheckCircleIcon } from '@heroicons/react/24/solid' import { RiQuestionLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useMemo } from 'react' import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' diff --git a/web/app/components/header/account-setting/members-page/transfer-ownership-modal/index.tsx b/web/app/components/header/account-setting/members-page/transfer-ownership-modal/index.tsx index 2c6a33dc1f..323e8f300c 100644 --- a/web/app/components/header/account-setting/members-page/transfer-ownership-modal/index.tsx +++ b/web/app/components/header/account-setting/members-page/transfer-ownership-modal/index.tsx @@ -1,5 +1,5 @@ import { RiCloseLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useState } from 'react' import { Trans, useTranslation } from 'react-i18next' diff --git a/web/app/components/header/account-setting/menu-dialog.tsx b/web/app/components/header/account-setting/menu-dialog.tsx index 0b2d2208cd..cc5adbc18f 100644 --- a/web/app/components/header/account-setting/menu-dialog.tsx +++ b/web/app/components/header/account-setting/menu-dialog.tsx @@ -1,6 +1,6 @@ import type { ReactNode } from 'react' import { Dialog, DialogPanel, Transition, TransitionChild } from '@headlessui/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { Fragment, useCallback, useEffect } from 'react' import { cn } from '@/utils/classnames' diff --git a/web/app/components/header/app-nav/index.tsx b/web/app/components/header/app-nav/index.tsx index ab567540d4..34d192de41 100644 --- a/web/app/components/header/app-nav/index.tsx +++ b/web/app/components/header/app-nav/index.tsx @@ -5,8 +5,8 @@ import { RiRobot2Fill, RiRobot2Line, } from '@remixicon/react' +import { flatten } from 'es-toolkit/compat' import { produce } from 'immer' -import { flatten } from 'lodash-es' import { useParams } from 'next/navigation' import { useCallback, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/header/app-selector/index.tsx b/web/app/components/header/app-selector/index.tsx index c15ed3e79c..a9aab59356 100644 --- a/web/app/components/header/app-selector/index.tsx +++ b/web/app/components/header/app-selector/index.tsx @@ -2,7 +2,7 @@ import type { AppDetailResponse } from '@/models/app' import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react' import { ChevronDownIcon, PlusIcon } from '@heroicons/react/24/solid' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useRouter } from 'next/navigation' import { Fragment, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/header/dataset-nav/index.tsx b/web/app/components/header/dataset-nav/index.tsx index e1943a4ec2..4cdc259d67 100644 --- a/web/app/components/header/dataset-nav/index.tsx +++ b/web/app/components/header/dataset-nav/index.tsx @@ -6,7 +6,7 @@ import { RiBook2Fill, RiBook2Line, } from '@remixicon/react' -import { flatten } from 'lodash-es' +import { flatten } from 'es-toolkit/compat' import { useParams, useRouter } from 'next/navigation' import { useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/header/nav/nav-selector/index.tsx b/web/app/components/header/nav/nav-selector/index.tsx index 905597f021..c12be7e035 100644 --- a/web/app/components/header/nav/nav-selector/index.tsx +++ b/web/app/components/header/nav/nav-selector/index.tsx @@ -6,7 +6,7 @@ import { RiArrowDownSLine, RiArrowRightSLine, } from '@remixicon/react' -import { debounce } from 'lodash-es' +import { debounce } from 'es-toolkit/compat' import { useRouter } from 'next/navigation' import { Fragment, useCallback } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/plugins/base/deprecation-notice.tsx b/web/app/components/plugins/base/deprecation-notice.tsx index 76d64a45f4..efdd903883 100644 --- a/web/app/components/plugins/base/deprecation-notice.tsx +++ b/web/app/components/plugins/base/deprecation-notice.tsx @@ -1,6 +1,6 @@ import type { FC } from 'react' import { RiAlertFill } from '@remixicon/react' -import { camelCase } from 'lodash-es' +import { camelCase } from 'es-toolkit/compat' import Link from 'next/link' import * as React from 'react' import { useMemo } from 'react' diff --git a/web/app/components/plugins/install-plugin/utils.ts b/web/app/components/plugins/install-plugin/utils.ts index 32d3e54225..549bdc6241 100644 --- a/web/app/components/plugins/install-plugin/utils.ts +++ b/web/app/components/plugins/install-plugin/utils.ts @@ -1,6 +1,6 @@ import type { Plugin, PluginDeclaration, PluginManifestInMarket } from '../types' import type { GitHubUrlInfo } from '@/app/components/plugins/types' -import { isEmpty } from 'lodash-es' +import { isEmpty } from 'es-toolkit/compat' export const pluginManifestToCardPluginProps = (pluginManifest: PluginDeclaration): Plugin => { return { diff --git a/web/app/components/plugins/marketplace/context.tsx b/web/app/components/plugins/marketplace/context.tsx index ec76d3440f..4053c4a556 100644 --- a/web/app/components/plugins/marketplace/context.tsx +++ b/web/app/components/plugins/marketplace/context.tsx @@ -10,7 +10,7 @@ import type { SearchParams, SearchParamsFromCollection, } from './types' -import { debounce, noop } from 'lodash-es' +import { debounce, noop } from 'es-toolkit/compat' import { useCallback, useEffect, diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.tsx index b0625d1e82..d0326f6b43 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.tsx @@ -3,7 +3,7 @@ import type { FormRefObject } from '@/app/components/base/form/types' import type { TriggerSubscriptionBuilder } from '@/app/components/workflow/block-selector/types' import type { BuildTriggerSubscriptionPayload } from '@/service/use-triggers' import { RiLoader2Line } from '@remixicon/react' -import { debounce } from 'lodash-es' +import { debounce } from 'es-toolkit/compat' import * as React from 'react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/edit/apikey-edit-modal.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/edit/apikey-edit-modal.tsx index 18bebf8d95..539544f435 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/edit/apikey-edit-modal.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/edit/apikey-edit-modal.tsx @@ -2,7 +2,7 @@ import type { FormRefObject, FormSchema } from '@/app/components/base/form/types' import type { ParametersSchema, PluginDetail } from '@/app/components/plugins/types' import type { TriggerSubscription } from '@/app/components/workflow/block-selector/types' -import { isEqual } from 'lodash-es' +import { isEqual } from 'es-toolkit/compat' import { useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { EncryptedBottom } from '@/app/components/base/encrypted-bottom' diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/edit/manual-edit-modal.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/edit/manual-edit-modal.tsx index 96c1b6e278..404766ae43 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/edit/manual-edit-modal.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/edit/manual-edit-modal.tsx @@ -2,7 +2,7 @@ import type { FormRefObject, FormSchema } from '@/app/components/base/form/types' import type { ParametersSchema, PluginDetail } from '@/app/components/plugins/types' import type { TriggerSubscription } from '@/app/components/workflow/block-selector/types' -import { isEqual } from 'lodash-es' +import { isEqual } from 'es-toolkit/compat' import { useMemo, useRef } from 'react' import { useTranslation } from 'react-i18next' import { BaseForm } from '@/app/components/base/form/components/base' diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/edit/oauth-edit-modal.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/edit/oauth-edit-modal.tsx index 9adee6cc34..53bb6aa69d 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/edit/oauth-edit-modal.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/edit/oauth-edit-modal.tsx @@ -2,7 +2,7 @@ import type { FormRefObject, FormSchema } from '@/app/components/base/form/types' import type { ParametersSchema, PluginDetail } from '@/app/components/plugins/types' import type { TriggerSubscription } from '@/app/components/workflow/block-selector/types' -import { isEqual } from 'lodash-es' +import { isEqual } from 'es-toolkit/compat' import { useMemo, useRef } from 'react' import { useTranslation } from 'react-i18next' import { BaseForm } from '@/app/components/base/form/components/base' diff --git a/web/app/components/plugins/plugin-page/context.tsx b/web/app/components/plugins/plugin-page/context.tsx index 8a560ac90a..146353da4f 100644 --- a/web/app/components/plugins/plugin-page/context.tsx +++ b/web/app/components/plugins/plugin-page/context.tsx @@ -2,7 +2,7 @@ import type { ReactNode, RefObject } from 'react' import type { FilterState } from './filter-management' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useMemo, useRef, diff --git a/web/app/components/plugins/plugin-page/empty/index.tsx b/web/app/components/plugins/plugin-page/empty/index.tsx index 4d8904d293..90854bda5d 100644 --- a/web/app/components/plugins/plugin-page/empty/index.tsx +++ b/web/app/components/plugins/plugin-page/empty/index.tsx @@ -1,5 +1,5 @@ 'use client' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/plugins/plugin-page/index.tsx b/web/app/components/plugins/plugin-page/index.tsx index 2c6f90caa5..afa85d7010 100644 --- a/web/app/components/plugins/plugin-page/index.tsx +++ b/web/app/components/plugins/plugin-page/index.tsx @@ -7,7 +7,7 @@ import { RiEqualizer2Line, } from '@remixicon/react' import { useBoolean } from 'ahooks' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import Link from 'next/link' import { useRouter, diff --git a/web/app/components/plugins/plugin-page/install-plugin-dropdown.tsx b/web/app/components/plugins/plugin-page/install-plugin-dropdown.tsx index 60c18dca12..22ed35e95b 100644 --- a/web/app/components/plugins/plugin-page/install-plugin-dropdown.tsx +++ b/web/app/components/plugins/plugin-page/install-plugin-dropdown.tsx @@ -1,7 +1,7 @@ 'use client' import { RiAddLine, RiArrowDownSLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' diff --git a/web/app/components/rag-pipeline/components/panel/input-field/field-list/field-list-container.tsx b/web/app/components/rag-pipeline/components/panel/input-field/field-list/field-list-container.tsx index 3c4faad439..108f3a642f 100644 --- a/web/app/components/rag-pipeline/components/panel/input-field/field-list/field-list-container.tsx +++ b/web/app/components/rag-pipeline/components/panel/input-field/field-list/field-list-container.tsx @@ -1,6 +1,6 @@ import type { SortableItem } from './types' import type { InputVar } from '@/models/pipeline' -import { isEqual } from 'lodash-es' +import { isEqual } from 'es-toolkit/compat' import { memo, useCallback, diff --git a/web/app/components/rag-pipeline/components/publish-as-knowledge-pipeline-modal.tsx b/web/app/components/rag-pipeline/components/publish-as-knowledge-pipeline-modal.tsx index b11bae2449..303a8caaf5 100644 --- a/web/app/components/rag-pipeline/components/publish-as-knowledge-pipeline-modal.tsx +++ b/web/app/components/rag-pipeline/components/publish-as-knowledge-pipeline-modal.tsx @@ -2,7 +2,7 @@ import type { AppIconSelection } from '@/app/components/base/app-icon-picker' import type { IconInfo } from '@/models/datasets' import { RiCloseLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import AppIcon from '@/app/components/base/app-icon' diff --git a/web/app/components/rag-pipeline/hooks/use-pipeline.tsx b/web/app/components/rag-pipeline/hooks/use-pipeline.tsx index 779a38df99..c84bba660d 100644 --- a/web/app/components/rag-pipeline/hooks/use-pipeline.tsx +++ b/web/app/components/rag-pipeline/hooks/use-pipeline.tsx @@ -1,6 +1,6 @@ import type { DataSourceNodeType } from '../../workflow/nodes/data-source/types' import type { Node, ValueSelector } from '../../workflow/types' -import { uniqBy } from 'lodash-es' +import { uniqBy } from 'es-toolkit/compat' import { useCallback } from 'react' import { getOutgoers, useStoreApi } from 'reactflow' import { findUsedVarNodes, updateNodeVars } from '../../workflow/nodes/_base/components/variable/utils' diff --git a/web/app/components/tools/labels/selector.tsx b/web/app/components/tools/labels/selector.tsx index e3afea41a8..43143e5a05 100644 --- a/web/app/components/tools/labels/selector.tsx +++ b/web/app/components/tools/labels/selector.tsx @@ -2,7 +2,7 @@ import type { FC } from 'react' import type { Label } from '@/app/components/tools/labels/constant' import { RiArrowDownSLine } from '@remixicon/react' import { useDebounceFn } from 'ahooks' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import Checkbox from '@/app/components/base/checkbox' diff --git a/web/app/components/tools/mcp/modal.tsx b/web/app/components/tools/mcp/modal.tsx index eb8f280484..c5cde65674 100644 --- a/web/app/components/tools/mcp/modal.tsx +++ b/web/app/components/tools/mcp/modal.tsx @@ -5,7 +5,7 @@ import type { ToolWithProvider } from '@/app/components/workflow/types' import type { AppIconType } from '@/types/app' import { RiCloseLine, RiEditLine } from '@remixicon/react' import { useHover } from 'ahooks' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useCallback, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/tools/setting/build-in/config-credentials.tsx b/web/app/components/tools/setting/build-in/config-credentials.tsx index 43383cdb51..033052e8a1 100644 --- a/web/app/components/tools/setting/build-in/config-credentials.tsx +++ b/web/app/components/tools/setting/build-in/config-credentials.tsx @@ -1,7 +1,7 @@ 'use client' import type { FC } from 'react' import type { Collection } from '../../types' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/tools/workflow-tool/confirm-modal/index.tsx b/web/app/components/tools/workflow-tool/confirm-modal/index.tsx index f90774cb32..e1a7dff113 100644 --- a/web/app/components/tools/workflow-tool/confirm-modal/index.tsx +++ b/web/app/components/tools/workflow-tool/confirm-modal/index.tsx @@ -1,7 +1,7 @@ 'use client' import { RiCloseLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback' diff --git a/web/app/components/workflow-app/hooks/use-workflow-run.ts b/web/app/components/workflow-app/hooks/use-workflow-run.ts index 16c7bab6d4..031e2949cb 100644 --- a/web/app/components/workflow-app/hooks/use-workflow-run.ts +++ b/web/app/components/workflow-app/hooks/use-workflow-run.ts @@ -2,8 +2,8 @@ import type AudioPlayer from '@/app/components/base/audio-btn/audio' import type { Node } from '@/app/components/workflow/types' import type { IOtherOptions } from '@/service/base' import type { VersionHistory } from '@/types/workflow' +import { noop } from 'es-toolkit/compat' import { produce } from 'immer' -import { noop } from 'lodash-es' import { usePathname } from 'next/navigation' import { useCallback, useRef } from 'react' import { diff --git a/web/app/components/workflow/block-selector/blocks.tsx b/web/app/components/workflow/block-selector/blocks.tsx index 51d08d15df..388532f7a2 100644 --- a/web/app/components/workflow/block-selector/blocks.tsx +++ b/web/app/components/workflow/block-selector/blocks.tsx @@ -1,5 +1,5 @@ import type { NodeDefault } from '../types' -import { groupBy } from 'lodash-es' +import { groupBy } from 'es-toolkit/compat' import { memo, useCallback, diff --git a/web/app/components/workflow/block-selector/market-place-plugin/list.tsx b/web/app/components/workflow/block-selector/market-place-plugin/list.tsx index 58724b4621..d6f3007b51 100644 --- a/web/app/components/workflow/block-selector/market-place-plugin/list.tsx +++ b/web/app/components/workflow/block-selector/market-place-plugin/list.tsx @@ -2,7 +2,7 @@ import type { RefObject } from 'react' import type { Plugin, PluginCategoryEnum } from '@/app/components/plugins/types' import { RiArrowRightUpLine, RiSearchLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import Link from 'next/link' import { useEffect, useImperativeHandle, useMemo, useRef } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/custom-edge.tsx b/web/app/components/workflow/custom-edge.tsx index 3b73e07536..6427520d81 100644 --- a/web/app/components/workflow/custom-edge.tsx +++ b/web/app/components/workflow/custom-edge.tsx @@ -3,7 +3,7 @@ import type { Edge, OnSelectBlock, } from './types' -import { intersection } from 'lodash-es' +import { intersection } from 'es-toolkit/compat' import { memo, useCallback, diff --git a/web/app/components/workflow/dsl-export-confirm-modal.tsx b/web/app/components/workflow/dsl-export-confirm-modal.tsx index b616ec5fb5..c5ae8e7cff 100644 --- a/web/app/components/workflow/dsl-export-confirm-modal.tsx +++ b/web/app/components/workflow/dsl-export-confirm-modal.tsx @@ -1,7 +1,7 @@ 'use client' import type { EnvironmentVariable } from '@/app/components/workflow/types' import { RiCloseLine, RiLock2Line } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/hooks-store/store.ts b/web/app/components/workflow/hooks-store/store.ts index 79cfb7dbce..3aa4ba3d91 100644 --- a/web/app/components/workflow/hooks-store/store.ts +++ b/web/app/components/workflow/hooks-store/store.ts @@ -12,7 +12,7 @@ import type { FlowType } from '@/types/common' import type { VarInInspect } from '@/types/workflow' import { noop, -} from 'lodash-es' +} from 'es-toolkit/compat' import { useContext } from 'react' import { useStore as useZustandStore, diff --git a/web/app/components/workflow/hooks/use-nodes-layout.ts b/web/app/components/workflow/hooks/use-nodes-layout.ts index 653b37008c..2ad89ff100 100644 --- a/web/app/components/workflow/hooks/use-nodes-layout.ts +++ b/web/app/components/workflow/hooks/use-nodes-layout.ts @@ -3,7 +3,7 @@ import type { Node, } from '../types' import ELK from 'elkjs/lib/elk.bundled.js' -import { cloneDeep } from 'lodash-es' +import { cloneDeep } from 'es-toolkit/compat' import { useCallback } from 'react' import { useReactFlow, diff --git a/web/app/components/workflow/hooks/use-workflow-history.ts b/web/app/components/workflow/hooks/use-workflow-history.ts index 3e6043a1fd..0171271c3b 100644 --- a/web/app/components/workflow/hooks/use-workflow-history.ts +++ b/web/app/components/workflow/hooks/use-workflow-history.ts @@ -1,5 +1,5 @@ import type { WorkflowHistoryEventMeta } from '../workflow-history-store' -import { debounce } from 'lodash-es' +import { debounce } from 'es-toolkit/compat' import { useCallback, useRef, diff --git a/web/app/components/workflow/hooks/use-workflow.ts b/web/app/components/workflow/hooks/use-workflow.ts index c958bb6b83..990c8c950d 100644 --- a/web/app/components/workflow/hooks/use-workflow.ts +++ b/web/app/components/workflow/hooks/use-workflow.ts @@ -9,7 +9,7 @@ import type { Node, ValueSelector, } from '../types' -import { uniqBy } from 'lodash-es' +import { uniqBy } from 'es-toolkit/compat' import { useCallback, } from 'react' diff --git a/web/app/components/workflow/index.tsx b/web/app/components/workflow/index.tsx index 1d0c594c23..b31c283550 100644 --- a/web/app/components/workflow/index.tsx +++ b/web/app/components/workflow/index.tsx @@ -13,8 +13,8 @@ import type { VarInInspect } from '@/types/workflow' import { useEventListener, } from 'ahooks' +import { isEqual } from 'es-toolkit/compat' import { setAutoFreeze } from 'immer' -import { isEqual } from 'lodash-es' import dynamic from 'next/dynamic' import { memo, @@ -195,9 +195,11 @@ export const Workflow: FC = memo(({ const { nodesReadOnly } = useNodesReadOnly() const { eventEmitter } = useEventEmitterContextContext() + const store = useStoreApi() eventEmitter?.useSubscription((v: any) => { if (v.type === WORKFLOW_DATA_UPDATE) { setNodes(v.payload.nodes) + store.getState().setNodes(v.payload.nodes) setEdges(v.payload.edges) if (v.payload.viewport) @@ -359,7 +361,6 @@ export const Workflow: FC = memo(({ } }, [schemaTypeDefinitions, fetchInspectVars, isLoadedVars, vars, customTools, buildInTools, workflowTools, mcpTools, dataSourceList]) - const store = useStoreApi() if (process.env.NODE_ENV === 'development') { store.getState().onError = (code, message) => { if (code === '002') diff --git a/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx b/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx index d7592b3c6f..a390ccec3c 100644 --- a/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx +++ b/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx @@ -4,7 +4,7 @@ import type { NodeOutPutVar } from '../../../types' import type { ToolVarInputs } from '../../tool/types' import type { CredentialFormSchema, CredentialFormSchemaNumberInput, CredentialFormSchemaTextInput } from '@/app/components/header/account-setting/model-provider-page/declarations' import type { PluginMeta } from '@/app/components/plugins/types' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import Link from 'next/link' import { memo } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/nodes/_base/components/editor/code-editor/index.tsx b/web/app/components/workflow/nodes/_base/components/editor/code-editor/index.tsx index fa7aef90a5..ad5410986c 100644 --- a/web/app/components/workflow/nodes/_base/components/editor/code-editor/index.tsx +++ b/web/app/components/workflow/nodes/_base/components/editor/code-editor/index.tsx @@ -1,7 +1,7 @@ 'use client' import type { FC } from 'react' import Editor, { loader } from '@monaco-editor/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useEffect, useMemo, useRef, useState } from 'react' import { diff --git a/web/app/components/workflow/nodes/_base/components/file-type-item.tsx b/web/app/components/workflow/nodes/_base/components/file-type-item.tsx index b354d35276..9498edba8f 100644 --- a/web/app/components/workflow/nodes/_base/components/file-type-item.tsx +++ b/web/app/components/workflow/nodes/_base/components/file-type-item.tsx @@ -1,6 +1,6 @@ 'use client' import type { FC } from 'react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useCallback } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/nodes/_base/components/input-support-select-var.tsx b/web/app/components/workflow/nodes/_base/components/input-support-select-var.tsx index 348bb23302..e0bb6f6df5 100644 --- a/web/app/components/workflow/nodes/_base/components/input-support-select-var.tsx +++ b/web/app/components/workflow/nodes/_base/components/input-support-select-var.tsx @@ -5,7 +5,7 @@ import type { NodeOutPutVar, } from '@/app/components/workflow/types' import { useBoolean } from 'ahooks' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useEffect } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/nodes/_base/components/next-step/index.tsx b/web/app/components/workflow/nodes/_base/components/next-step/index.tsx index 0f23161261..b9a4404dbb 100644 --- a/web/app/components/workflow/nodes/_base/components/next-step/index.tsx +++ b/web/app/components/workflow/nodes/_base/components/next-step/index.tsx @@ -1,7 +1,7 @@ import type { Node, } from '../../../../types' -import { isEqual } from 'lodash-es' +import { isEqual } from 'es-toolkit/compat' import { memo, useMemo } from 'react' import { useTranslation } from 'react-i18next' import { diff --git a/web/app/components/workflow/nodes/_base/components/next-step/operator.tsx b/web/app/components/workflow/nodes/_base/components/next-step/operator.tsx index 1b550f035d..906dad4bc9 100644 --- a/web/app/components/workflow/nodes/_base/components/next-step/operator.tsx +++ b/web/app/components/workflow/nodes/_base/components/next-step/operator.tsx @@ -3,7 +3,7 @@ import type { OnSelectBlock, } from '@/app/components/workflow/types' import { RiMoreFill } from '@remixicon/react' -import { intersection } from 'lodash-es' +import { intersection } from 'es-toolkit/compat' import { useCallback, } from 'react' diff --git a/web/app/components/workflow/nodes/_base/components/panel-operator/change-block.tsx b/web/app/components/workflow/nodes/_base/components/panel-operator/change-block.tsx index 47e1c4b22b..9236c022b9 100644 --- a/web/app/components/workflow/nodes/_base/components/panel-operator/change-block.tsx +++ b/web/app/components/workflow/nodes/_base/components/panel-operator/change-block.tsx @@ -2,7 +2,7 @@ import type { Node, OnSelectBlock, } from '@/app/components/workflow/types' -import { intersection } from 'lodash-es' +import { intersection } from 'es-toolkit/compat' import { memo, useCallback, diff --git a/web/app/components/workflow/nodes/_base/components/variable/utils.ts b/web/app/components/workflow/nodes/_base/components/variable/utils.ts index 5a5a9b826a..a7dc04e571 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/utils.ts +++ b/web/app/components/workflow/nodes/_base/components/variable/utils.ts @@ -33,8 +33,8 @@ import type { import type { PromptItem } from '@/models/debug' import type { RAGPipelineVariable } from '@/models/pipeline' import type { SchemaTypeDefinition } from '@/service/use-common' +import { isArray, uniq } from 'es-toolkit/compat' import { produce } from 'immer' -import { isArray, uniq } from 'lodash-es' import { AGENT_OUTPUT_STRUCT, FILE_STRUCT, diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx index 05e2c913ce..e92fc9a3b7 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx @@ -11,8 +11,8 @@ import { RiLoader4Line, RiMoreLine, } from '@remixicon/react' +import { noop } from 'es-toolkit/compat' import { produce } from 'immer' -import { noop } from 'lodash-es' import * as React from 'react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx index dd0dfa8682..078ba1ef4f 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx @@ -4,7 +4,7 @@ import type { StructuredOutput } from '../../../llm/types' import type { Field } from '@/app/components/workflow/nodes/llm/types' import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types' import { useHover } from 'ahooks' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/nodes/_base/components/variable/variable-label/base/variable-label.tsx b/web/app/components/workflow/nodes/_base/components/variable/variable-label/base/variable-label.tsx index 63b392482f..828f7e5ebe 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/variable-label/base/variable-label.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/variable-label/base/variable-label.tsx @@ -3,7 +3,7 @@ import { RiErrorWarningFill, RiMoreLine, } from '@remixicon/react' -import { capitalize } from 'lodash-es' +import { capitalize } from 'es-toolkit/compat' import { memo } from 'react' import Tooltip from '@/app/components/base/tooltip' import { cn } from '@/utils/classnames' 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 8e684afa87..2e25d029b4 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 @@ -6,7 +6,7 @@ import { RiCloseLine, RiPlayLargeLine, } from '@remixicon/react' -import { debounce } from 'lodash-es' +import { debounce } from 'es-toolkit/compat' import * as React from 'react' import { cloneElement, diff --git a/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts b/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts index 59774ab96a..d8fd4d2c57 100644 --- a/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts +++ b/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts @@ -1,9 +1,9 @@ import type { CommonNodeType, InputVar, TriggerNodeType, ValueSelector, Var, Variable } from '@/app/components/workflow/types' import type { FlowType } from '@/types/common' import type { NodeRunResult, NodeTracing } from '@/types/workflow' -import { produce } from 'immer' +import { noop, unionBy } from 'es-toolkit/compat' -import { noop, unionBy } from 'lodash-es' +import { produce } from 'immer' import { useCallback, useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { diff --git a/web/app/components/workflow/nodes/assigner/components/var-list/index.tsx b/web/app/components/workflow/nodes/assigner/components/var-list/index.tsx index 422cd5a486..f5ea45d60e 100644 --- a/web/app/components/workflow/nodes/assigner/components/var-list/index.tsx +++ b/web/app/components/workflow/nodes/assigner/components/var-list/index.tsx @@ -3,8 +3,8 @@ import type { FC } from 'react' import type { AssignerNodeOperation } from '../../types' import type { ValueSelector, Var } from '@/app/components/workflow/types' import { RiDeleteBinLine } from '@remixicon/react' +import { noop } from 'es-toolkit/compat' import { produce } from 'immer' -import { noop } from 'lodash-es' import * as React from 'react' import { useCallback } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/nodes/assigner/hooks.ts b/web/app/components/workflow/nodes/assigner/hooks.ts index d708222868..a3a5db8bfb 100644 --- a/web/app/components/workflow/nodes/assigner/hooks.ts +++ b/web/app/components/workflow/nodes/assigner/hooks.ts @@ -2,7 +2,7 @@ import type { Node, Var, } from '../../types' -import { uniqBy } from 'lodash-es' +import { uniqBy } from 'es-toolkit/compat' import { useCallback } from 'react' import { useNodes } from 'reactflow' import { diff --git a/web/app/components/workflow/nodes/http/components/edit-body/index.tsx b/web/app/components/workflow/nodes/http/components/edit-body/index.tsx index c475f1234a..90c230b6bb 100644 --- a/web/app/components/workflow/nodes/http/components/edit-body/index.tsx +++ b/web/app/components/workflow/nodes/http/components/edit-body/index.tsx @@ -2,8 +2,8 @@ import type { FC } from 'react' import type { Body, BodyPayload, KeyValue as KeyValueType } from '../../types' import type { ValueSelector, Var } from '@/app/components/workflow/types' +import { uniqueId } from 'es-toolkit/compat' import { produce } from 'immer' -import { uniqueId } from 'lodash-es' import * as React from 'react' import { useCallback, useMemo } from 'react' import InputWithVar from '@/app/components/workflow/nodes/_base/components/prompt/editor' diff --git a/web/app/components/workflow/nodes/http/hooks/use-key-value-list.ts b/web/app/components/workflow/nodes/http/hooks/use-key-value-list.ts index b174b7e6de..650ae47156 100644 --- a/web/app/components/workflow/nodes/http/hooks/use-key-value-list.ts +++ b/web/app/components/workflow/nodes/http/hooks/use-key-value-list.ts @@ -1,6 +1,6 @@ import type { KeyValue } from '../types' import { useBoolean } from 'ahooks' -import { uniqueId } from 'lodash-es' +import { uniqueId } from 'es-toolkit/compat' import { useCallback, useEffect, useState } from 'react' const UNIQUE_ID_PREFIX = 'key-value-' diff --git a/web/app/components/workflow/nodes/if-else/components/condition-number-input.tsx b/web/app/components/workflow/nodes/if-else/components/condition-number-input.tsx index 29419be011..9133271161 100644 --- a/web/app/components/workflow/nodes/if-else/components/condition-number-input.tsx +++ b/web/app/components/workflow/nodes/if-else/components/condition-number-input.tsx @@ -4,7 +4,7 @@ import type { } from '@/app/components/workflow/types' import { RiArrowDownSLine } from '@remixicon/react' import { useBoolean } from 'ahooks' -import { capitalize } from 'lodash-es' +import { capitalize } from 'es-toolkit/compat' import { memo, useCallback, diff --git a/web/app/components/workflow/nodes/if-else/components/condition-wrap.tsx b/web/app/components/workflow/nodes/if-else/components/condition-wrap.tsx index cdcd7561db..b829ebb040 100644 --- a/web/app/components/workflow/nodes/if-else/components/condition-wrap.tsx +++ b/web/app/components/workflow/nodes/if-else/components/condition-wrap.tsx @@ -7,7 +7,7 @@ import { RiDeleteBinLine, RiDraggable, } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/nodes/iteration/use-config.ts b/web/app/components/workflow/nodes/iteration/use-config.ts index 50cee67f81..3106577085 100644 --- a/web/app/components/workflow/nodes/iteration/use-config.ts +++ b/web/app/components/workflow/nodes/iteration/use-config.ts @@ -2,8 +2,8 @@ import type { ErrorHandleMode, ValueSelector, Var } from '../../types' import type { IterationNodeType } from './types' import type { Item } from '@/app/components/base/select' import type { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types' +import { isEqual } from 'es-toolkit/compat' import { produce } from 'immer' -import { isEqual } from 'lodash-es' import { useCallback } from 'react' import { useAllBuiltInTools, diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-value-method.tsx b/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-value-method.tsx index c930387c82..574501a27d 100644 --- a/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-value-method.tsx +++ b/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-value-method.tsx @@ -1,5 +1,5 @@ import { RiArrowDownSLine } from '@remixicon/react' -import { capitalize } from 'lodash-es' +import { capitalize } from 'es-toolkit/compat' import { useState } from 'react' import Button from '@/app/components/base/button' import { diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/metadata-filter/index.tsx b/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/metadata-filter/index.tsx index 9b541b9ea6..8a90a8bf5d 100644 --- a/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/metadata-filter/index.tsx +++ b/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/metadata-filter/index.tsx @@ -1,5 +1,5 @@ import type { MetadataShape } from '@/app/components/workflow/nodes/knowledge-retrieval/types' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useCallback, useState, diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/components/retrieval-config.tsx b/web/app/components/workflow/nodes/knowledge-retrieval/components/retrieval-config.tsx index 02ae01ba16..610aaf5d63 100644 --- a/web/app/components/workflow/nodes/knowledge-retrieval/components/retrieval-config.tsx +++ b/web/app/components/workflow/nodes/knowledge-retrieval/components/retrieval-config.tsx @@ -2,6 +2,7 @@ import type { FC } from 'react' import type { ModelConfig } from '../../../types' import type { MultipleRetrievalConfig, SingleRetrievalConfig } from '../types' +import type { ModelParameterModalProps } from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal' import type { DataSet } from '@/models/datasets' import type { DatasetConfigs } from '@/models/debug' import { RiEqualizer2Line } from '@remixicon/react' @@ -28,8 +29,8 @@ type Props = { onRetrievalModeChange: (mode: RETRIEVE_TYPE) => void onMultipleRetrievalConfigChange: (config: MultipleRetrievalConfig) => void singleRetrievalModelConfig?: ModelConfig - onSingleRetrievalModelChange?: (config: ModelConfig) => void - onSingleRetrievalModelParamsChange?: (config: ModelConfig) => void + onSingleRetrievalModelChange?: ModelParameterModalProps['setModel'] + onSingleRetrievalModelParamsChange?: ModelParameterModalProps['onCompletionParamsChange'] readonly?: boolean rerankModalOpen: boolean onRerankModelOpenChange: (open: boolean) => void diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/panel.tsx b/web/app/components/workflow/nodes/knowledge-retrieval/panel.tsx index ff5a9e2292..1471be9741 100644 --- a/web/app/components/workflow/nodes/knowledge-retrieval/panel.tsx +++ b/web/app/components/workflow/nodes/knowledge-retrieval/panel.tsx @@ -1,7 +1,7 @@ import type { FC } from 'react' import type { KnowledgeRetrievalNodeType } from './types' import type { NodePanelProps } from '@/app/components/workflow/types' -import { intersectionBy } from 'lodash-es' +import { intersectionBy } from 'es-toolkit/compat' import { memo, useMemo, @@ -104,7 +104,7 @@ const Panel: FC> = ({ onRetrievalModeChange={handleRetrievalModeChange} onMultipleRetrievalConfigChange={handleMultipleRetrievalConfigChange} singleRetrievalModelConfig={inputs.single_retrieval_config?.model} - onSingleRetrievalModelChange={handleModelChanged as any} + onSingleRetrievalModelChange={handleModelChanged} onSingleRetrievalModelParamsChange={handleCompletionParamsChange} readonly={readOnly || !selectedDatasets.length} rerankModalOpen={rerankModelOpen} diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/use-config.ts b/web/app/components/workflow/nodes/knowledge-retrieval/use-config.ts index d0846b3a34..9a63bf96de 100644 --- a/web/app/components/workflow/nodes/knowledge-retrieval/use-config.ts +++ b/web/app/components/workflow/nodes/knowledge-retrieval/use-config.ts @@ -9,8 +9,8 @@ import type { MultipleRetrievalConfig, } from './types' import type { DataSet } from '@/models/datasets' +import { isEqual } from 'es-toolkit/compat' import { produce } from 'immer' -import { isEqual } from 'lodash-es' import { useCallback, useEffect, diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/utils.ts b/web/app/components/workflow/nodes/knowledge-retrieval/utils.ts index 12cf8c053c..d6cd69b39a 100644 --- a/web/app/components/workflow/nodes/knowledge-retrieval/utils.ts +++ b/web/app/components/workflow/nodes/knowledge-retrieval/utils.ts @@ -6,7 +6,7 @@ import type { import { uniq, xorBy, -} from 'lodash-es' +} from 'es-toolkit/compat' import { DATASET_DEFAULT } from '@/config' import { DEFAULT_WEIGHTED_SCORE, diff --git a/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/context.tsx b/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/context.tsx index cfe63159d3..557cddfb61 100644 --- a/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/context.tsx +++ b/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/context.tsx @@ -1,4 +1,4 @@ -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { createContext, useContext, diff --git a/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/hooks.ts b/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/hooks.ts index 84c28b236e..1673c80f4f 100644 --- a/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/hooks.ts +++ b/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/hooks.ts @@ -1,8 +1,8 @@ import type { VisualEditorProps } from '.' import type { Field } from '../../../types' import type { EditData } from './edit-card' +import { noop } from 'es-toolkit/compat' import { produce } from 'immer' -import { noop } from 'lodash-es' import Toast from '@/app/components/base/toast' import { ArrayType, Type } from '../../../types' import { findPropertyWithPath } from '../../../utils' diff --git a/web/app/components/workflow/nodes/llm/use-single-run-form-params.ts b/web/app/components/workflow/nodes/llm/use-single-run-form-params.ts index ae500074ff..f7cb609f0e 100644 --- a/web/app/components/workflow/nodes/llm/use-single-run-form-params.ts +++ b/web/app/components/workflow/nodes/llm/use-single-run-form-params.ts @@ -2,7 +2,7 @@ import type { RefObject } from 'react' import type { LLMNodeType } from './types' import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form' import type { InputVar, PromptItem, Var, Variable } from '@/app/components/workflow/types' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useCallback } from 'react' import { useTranslation } from 'react-i18next' import { InputVarType, VarType } from '@/app/components/workflow/types' diff --git a/web/app/components/workflow/nodes/loop/components/condition-number-input.tsx b/web/app/components/workflow/nodes/loop/components/condition-number-input.tsx index 29419be011..9133271161 100644 --- a/web/app/components/workflow/nodes/loop/components/condition-number-input.tsx +++ b/web/app/components/workflow/nodes/loop/components/condition-number-input.tsx @@ -4,7 +4,7 @@ import type { } from '@/app/components/workflow/types' import { RiArrowDownSLine } from '@remixicon/react' import { useBoolean } from 'ahooks' -import { capitalize } from 'lodash-es' +import { capitalize } from 'es-toolkit/compat' import { memo, useCallback, diff --git a/web/app/components/workflow/nodes/parameter-extractor/use-single-run-form-params.ts b/web/app/components/workflow/nodes/parameter-extractor/use-single-run-form-params.ts index abf187d6e5..c53df96688 100644 --- a/web/app/components/workflow/nodes/parameter-extractor/use-single-run-form-params.ts +++ b/web/app/components/workflow/nodes/parameter-extractor/use-single-run-form-params.ts @@ -2,7 +2,7 @@ import type { RefObject } from 'react' import type { ParameterExtractorNodeType } from './types' import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form' import type { InputVar, Var, Variable } from '@/app/components/workflow/types' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useCallback } from 'react' import { useTranslation } from 'react-i18next' import { InputVarType, VarType } from '@/app/components/workflow/types' diff --git a/web/app/components/workflow/nodes/question-classifier/components/class-item.tsx b/web/app/components/workflow/nodes/question-classifier/components/class-item.tsx index 2af2f8036a..a33ba03550 100644 --- a/web/app/components/workflow/nodes/question-classifier/components/class-item.tsx +++ b/web/app/components/workflow/nodes/question-classifier/components/class-item.tsx @@ -2,7 +2,7 @@ import type { FC } from 'react' import type { Topic } from '../types' import type { ValueSelector, Var } from '@/app/components/workflow/types' -import { uniqueId } from 'lodash-es' +import { uniqueId } from 'es-toolkit/compat' import * as React from 'react' import { useCallback, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/nodes/question-classifier/components/class-list.tsx b/web/app/components/workflow/nodes/question-classifier/components/class-list.tsx index 8e61f918a5..8527ce3ad3 100644 --- a/web/app/components/workflow/nodes/question-classifier/components/class-list.tsx +++ b/web/app/components/workflow/nodes/question-classifier/components/class-list.tsx @@ -3,8 +3,8 @@ import type { FC } from 'react' import type { Topic } from '@/app/components/workflow/nodes/question-classifier/types' import type { ValueSelector, Var } from '@/app/components/workflow/types' import { RiDraggable } from '@remixicon/react' +import { noop } from 'es-toolkit/compat' import { produce } from 'immer' -import { noop } from 'lodash-es' import * as React from 'react' import { useCallback, useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/nodes/question-classifier/use-single-run-form-params.ts b/web/app/components/workflow/nodes/question-classifier/use-single-run-form-params.ts index 095809eba2..9f2ad5fa39 100644 --- a/web/app/components/workflow/nodes/question-classifier/use-single-run-form-params.ts +++ b/web/app/components/workflow/nodes/question-classifier/use-single-run-form-params.ts @@ -2,7 +2,7 @@ import type { RefObject } from 'react' import type { QuestionClassifierNodeType } from './types' import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form' import type { InputVar, Var, Variable } from '@/app/components/workflow/types' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useCallback } from 'react' import { useTranslation } from 'react-i18next' import { InputVarType, VarType } from '@/app/components/workflow/types' diff --git a/web/app/components/workflow/nodes/start/components/var-item.tsx b/web/app/components/workflow/nodes/start/components/var-item.tsx index a506c51e31..83676ed21f 100644 --- a/web/app/components/workflow/nodes/start/components/var-item.tsx +++ b/web/app/components/workflow/nodes/start/components/var-item.tsx @@ -5,7 +5,7 @@ import { RiDeleteBinLine, } from '@remixicon/react' import { useBoolean, useHover } from 'ahooks' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import * as React from 'react' import { useCallback, useRef } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/nodes/tool/components/copy-id.tsx b/web/app/components/workflow/nodes/tool/components/copy-id.tsx index 8e53970749..6a608fa0b6 100644 --- a/web/app/components/workflow/nodes/tool/components/copy-id.tsx +++ b/web/app/components/workflow/nodes/tool/components/copy-id.tsx @@ -1,7 +1,7 @@ 'use client' import { RiFileCopyLine } from '@remixicon/react' import copy from 'copy-to-clipboard' -import { debounce } from 'lodash-es' +import { debounce } from 'es-toolkit/compat' import * as React from 'react' import { useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/nodes/tool/components/input-var-list.tsx b/web/app/components/workflow/nodes/tool/components/input-var-list.tsx index 8b1bd46eeb..23f3868c59 100644 --- a/web/app/components/workflow/nodes/tool/components/input-var-list.tsx +++ b/web/app/components/workflow/nodes/tool/components/input-var-list.tsx @@ -4,8 +4,8 @@ import type { ToolVarInputs } from '../types' import type { CredentialFormSchema } from '@/app/components/header/account-setting/model-provider-page/declarations' import type { Tool } from '@/app/components/tools/types' import type { ToolWithProvider, ValueSelector, Var } from '@/app/components/workflow/types' +import { noop } from 'es-toolkit/compat' import { produce } from 'immer' -import { noop } from 'lodash-es' import * as React from 'react' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/nodes/variable-assigner/components/var-list/index.tsx b/web/app/components/workflow/nodes/variable-assigner/components/var-list/index.tsx index 19ead7ead1..85ff2def9a 100644 --- a/web/app/components/workflow/nodes/variable-assigner/components/var-list/index.tsx +++ b/web/app/components/workflow/nodes/variable-assigner/components/var-list/index.tsx @@ -1,8 +1,8 @@ 'use client' import type { FC } from 'react' import type { ValueSelector, Var } from '@/app/components/workflow/types' +import { noop } from 'es-toolkit/compat' import { produce } from 'immer' -import { noop } from 'lodash-es' import * as React from 'react' import { useCallback } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/nodes/variable-assigner/hooks.ts b/web/app/components/workflow/nodes/variable-assigner/hooks.ts index b20cee79c7..5c2fe36922 100644 --- a/web/app/components/workflow/nodes/variable-assigner/hooks.ts +++ b/web/app/components/workflow/nodes/variable-assigner/hooks.ts @@ -7,9 +7,9 @@ import type { VarGroupItem, VariableAssignerNodeType, } from './types' -import { produce } from 'immer' +import { uniqBy } from 'es-toolkit/compat' -import { uniqBy } from 'lodash-es' +import { produce } from 'immer' import { useCallback } from 'react' import { useNodes, diff --git a/web/app/components/workflow/note-node/note-editor/plugins/link-editor-plugin/component.tsx b/web/app/components/workflow/note-node/note-editor/plugins/link-editor-plugin/component.tsx index 3f5472ad56..d1b178ec4c 100644 --- a/web/app/components/workflow/note-node/note-editor/plugins/link-editor-plugin/component.tsx +++ b/web/app/components/workflow/note-node/note-editor/plugins/link-editor-plugin/component.tsx @@ -11,7 +11,7 @@ import { RiLinkUnlinkM, } from '@remixicon/react' import { useClickAway } from 'ahooks' -import { escape } from 'lodash-es' +import { escape } from 'es-toolkit/compat' import { memo, useEffect, diff --git a/web/app/components/workflow/note-node/note-editor/plugins/link-editor-plugin/hooks.ts b/web/app/components/workflow/note-node/note-editor/plugins/link-editor-plugin/hooks.ts index 2c6e014b15..fb191bc05a 100644 --- a/web/app/components/workflow/note-node/note-editor/plugins/link-editor-plugin/hooks.ts +++ b/web/app/components/workflow/note-node/note-editor/plugins/link-editor-plugin/hooks.ts @@ -5,11 +5,11 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext import { mergeRegister, } from '@lexical/utils' +import { escape } from 'es-toolkit/compat' import { CLICK_COMMAND, COMMAND_PRIORITY_LOW, } from 'lexical' -import { escape } from 'lodash-es' import { useCallback, useEffect, diff --git a/web/app/components/workflow/panel/chat-variable-panel/components/variable-item.tsx b/web/app/components/workflow/panel/chat-variable-panel/components/variable-item.tsx index a43179026e..9fec4f7d01 100644 --- a/web/app/components/workflow/panel/chat-variable-panel/components/variable-item.tsx +++ b/web/app/components/workflow/panel/chat-variable-panel/components/variable-item.tsx @@ -1,6 +1,6 @@ import type { ConversationVariable } from '@/app/components/workflow/types' import { RiDeleteBinLine, RiEditLine } from '@remixicon/react' -import { capitalize } from 'lodash-es' +import { capitalize } from 'es-toolkit/compat' import { memo, useState } from 'react' import { BubbleX } from '@/app/components/base/icons/src/vender/line/others' import { cn } from '@/utils/classnames' diff --git a/web/app/components/workflow/panel/debug-and-preview/conversation-variable-modal.tsx b/web/app/components/workflow/panel/debug-and-preview/conversation-variable-modal.tsx index 6e130180d0..4542e1fb90 100644 --- a/web/app/components/workflow/panel/debug-and-preview/conversation-variable-modal.tsx +++ b/web/app/components/workflow/panel/debug-and-preview/conversation-variable-modal.tsx @@ -5,7 +5,7 @@ import type { import { RiCloseLine } from '@remixicon/react' import { useMount } from 'ahooks' import copy from 'copy-to-clipboard' -import { capitalize, noop } from 'lodash-es' +import { capitalize, noop } from 'es-toolkit/compat' import * as React from 'react' import { useCallback } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/app/components/workflow/panel/debug-and-preview/hooks.ts b/web/app/components/workflow/panel/debug-and-preview/hooks.ts index 6eb1ea0b76..b771d97006 100644 --- a/web/app/components/workflow/panel/debug-and-preview/hooks.ts +++ b/web/app/components/workflow/panel/debug-and-preview/hooks.ts @@ -5,8 +5,8 @@ import type { Inputs, } from '@/app/components/base/chat/types' import type { FileEntity } from '@/app/components/base/file-uploader/types' +import { uniqBy } from 'es-toolkit/compat' import { produce, setAutoFreeze } from 'immer' -import { uniqBy } from 'lodash-es' import { useCallback, useEffect, diff --git a/web/app/components/workflow/panel/debug-and-preview/index.tsx b/web/app/components/workflow/panel/debug-and-preview/index.tsx index 3005b68a9c..2b63cf4751 100644 --- a/web/app/components/workflow/panel/debug-and-preview/index.tsx +++ b/web/app/components/workflow/panel/debug-and-preview/index.tsx @@ -1,7 +1,7 @@ import type { StartNodeType } from '../../nodes/start/types' import { RiCloseLine, RiEqualizer2Line } from '@remixicon/react' -import { debounce, noop } from 'lodash-es' +import { debounce, noop } from 'es-toolkit/compat' import { memo, useCallback, diff --git a/web/app/components/workflow/panel/env-panel/env-item.tsx b/web/app/components/workflow/panel/env-panel/env-item.tsx index 64d6610643..582539b85b 100644 --- a/web/app/components/workflow/panel/env-panel/env-item.tsx +++ b/web/app/components/workflow/panel/env-panel/env-item.tsx @@ -1,6 +1,6 @@ import type { EnvironmentVariable } from '@/app/components/workflow/types' import { RiDeleteBinLine, RiEditLine, RiLock2Line } from '@remixicon/react' -import { capitalize } from 'lodash-es' +import { capitalize } from 'es-toolkit/compat' import { memo, useState } from 'react' import { Env } from '@/app/components/base/icons/src/vender/line/others' import { useStore } from '@/app/components/workflow/store' diff --git a/web/app/components/workflow/panel/global-variable-panel/item.tsx b/web/app/components/workflow/panel/global-variable-panel/item.tsx index f82579dedb..458dd27692 100644 --- a/web/app/components/workflow/panel/global-variable-panel/item.tsx +++ b/web/app/components/workflow/panel/global-variable-panel/item.tsx @@ -1,5 +1,5 @@ import type { GlobalVariable } from '@/app/components/workflow/types' -import { capitalize } from 'lodash-es' +import { capitalize } from 'es-toolkit/compat' import { memo } from 'react' import { GlobalVariable as GlobalVariableIcon } from '@/app/components/base/icons/src/vender/line/others' diff --git a/web/app/components/workflow/run/utils/format-log/agent/index.ts b/web/app/components/workflow/run/utils/format-log/agent/index.ts index a4c1ea5167..f86e4b33bb 100644 --- a/web/app/components/workflow/run/utils/format-log/agent/index.ts +++ b/web/app/components/workflow/run/utils/format-log/agent/index.ts @@ -1,5 +1,5 @@ import type { AgentLogItem, AgentLogItemWithChildren, NodeTracing } from '@/types/workflow' -import { cloneDeep } from 'lodash-es' +import { cloneDeep } from 'es-toolkit/compat' import { BlockEnum } from '@/app/components/workflow/types' const supportedAgentLogNodes = [BlockEnum.Agent, BlockEnum.Tool] diff --git a/web/app/components/workflow/run/utils/format-log/index.ts b/web/app/components/workflow/run/utils/format-log/index.ts index 2c89e91571..1dbe8f1682 100644 --- a/web/app/components/workflow/run/utils/format-log/index.ts +++ b/web/app/components/workflow/run/utils/format-log/index.ts @@ -1,5 +1,5 @@ import type { NodeTracing } from '@/types/workflow' -import { cloneDeep } from 'lodash-es' +import { cloneDeep } from 'es-toolkit/compat' import { BlockEnum } from '../../../types' import formatAgentNode from './agent' import { addChildrenToIterationNode } from './iteration' diff --git a/web/app/components/workflow/run/utils/format-log/iteration/index.spec.ts b/web/app/components/workflow/run/utils/format-log/iteration/index.spec.ts index 855ac4c69d..8b4416f529 100644 --- a/web/app/components/workflow/run/utils/format-log/iteration/index.spec.ts +++ b/web/app/components/workflow/run/utils/format-log/iteration/index.spec.ts @@ -1,4 +1,4 @@ -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import format from '.' import graphToLogStruct from '../graph-to-log-struct' diff --git a/web/app/components/workflow/run/utils/format-log/loop/index.spec.ts b/web/app/components/workflow/run/utils/format-log/loop/index.spec.ts index aee2a432c3..3d31e43ba3 100644 --- a/web/app/components/workflow/run/utils/format-log/loop/index.spec.ts +++ b/web/app/components/workflow/run/utils/format-log/loop/index.spec.ts @@ -1,4 +1,4 @@ -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import format from '.' import graphToLogStruct from '../graph-to-log-struct' diff --git a/web/app/components/workflow/store/workflow/workflow-draft-slice.ts b/web/app/components/workflow/store/workflow/workflow-draft-slice.ts index 83792e84a6..68265a8eba 100644 --- a/web/app/components/workflow/store/workflow/workflow-draft-slice.ts +++ b/web/app/components/workflow/store/workflow/workflow-draft-slice.ts @@ -5,7 +5,7 @@ import type { EnvironmentVariable, Node, } from '@/app/components/workflow/types' -import { debounce } from 'lodash-es' +import { debounce } from 'es-toolkit/compat' type DebouncedFunc = { (fn: () => void): void diff --git a/web/app/components/workflow/utils/elk-layout.ts b/web/app/components/workflow/utils/elk-layout.ts index 05f81872bb..1a4bbf2d50 100644 --- a/web/app/components/workflow/utils/elk-layout.ts +++ b/web/app/components/workflow/utils/elk-layout.ts @@ -5,7 +5,7 @@ import type { Node, } from '@/app/components/workflow/types' import ELK from 'elkjs/lib/elk.bundled.js' -import { cloneDeep } from 'lodash-es' +import { cloneDeep } from 'es-toolkit/compat' import { CUSTOM_NODE, NODE_LAYOUT_HORIZONTAL_PADDING, diff --git a/web/app/components/workflow/utils/workflow-init.ts b/web/app/components/workflow/utils/workflow-init.ts index 18ba643d30..fa211934e4 100644 --- a/web/app/components/workflow/utils/workflow-init.ts +++ b/web/app/components/workflow/utils/workflow-init.ts @@ -9,7 +9,7 @@ import type { } from '../types' import { cloneDeep, -} from 'lodash-es' +} from 'es-toolkit/compat' import { getConnectedEdges, } from 'reactflow' diff --git a/web/app/components/workflow/utils/workflow.ts b/web/app/components/workflow/utils/workflow.ts index 43fbd687c1..7fabc51a45 100644 --- a/web/app/components/workflow/utils/workflow.ts +++ b/web/app/components/workflow/utils/workflow.ts @@ -4,7 +4,7 @@ import type { } from '../types' import { uniqBy, -} from 'lodash-es' +} from 'es-toolkit/compat' import { getOutgoers, } from 'reactflow' diff --git a/web/app/components/workflow/variable-inspect/index.tsx b/web/app/components/workflow/variable-inspect/index.tsx index ced7861e00..775c761eca 100644 --- a/web/app/components/workflow/variable-inspect/index.tsx +++ b/web/app/components/workflow/variable-inspect/index.tsx @@ -1,5 +1,5 @@ import type { FC } from 'react' -import { debounce } from 'lodash-es' +import { debounce } from 'es-toolkit/compat' import { useCallback, useMemo, diff --git a/web/app/components/workflow/workflow-history-store.tsx b/web/app/components/workflow/workflow-history-store.tsx index 502cb733cb..6729fe50e3 100644 --- a/web/app/components/workflow/workflow-history-store.tsx +++ b/web/app/components/workflow/workflow-history-store.tsx @@ -3,8 +3,8 @@ import type { TemporalState } from 'zundo' import type { StoreApi } from 'zustand' import type { WorkflowHistoryEventT } from './hooks' import type { Edge, Node } from './types' +import { noop } from 'es-toolkit/compat' import isDeepEqual from 'fast-deep-equal' -import { noop } from 'lodash-es' import { createContext, useContext, useMemo, useState } from 'react' import { temporal } from 'zundo' import { create } from 'zustand' diff --git a/web/app/education-apply/education-apply-page.tsx b/web/app/education-apply/education-apply-page.tsx index 5f2446352e..efd74d42d5 100644 --- a/web/app/education-apply/education-apply-page.tsx +++ b/web/app/education-apply/education-apply-page.tsx @@ -1,7 +1,7 @@ 'use client' import { RiExternalLinkLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useRouter, useSearchParams, diff --git a/web/app/reset-password/page.tsx b/web/app/reset-password/page.tsx index c7e15f8b3f..479f550ae9 100644 --- a/web/app/reset-password/page.tsx +++ b/web/app/reset-password/page.tsx @@ -1,6 +1,6 @@ 'use client' import { RiArrowLeftLine, RiLockPasswordLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import Link from 'next/link' import { useRouter, useSearchParams } from 'next/navigation' import { useState } from 'react' diff --git a/web/app/signin/components/mail-and-password-auth.tsx b/web/app/signin/components/mail-and-password-auth.tsx index 9ab2d9314c..2e95ac8663 100644 --- a/web/app/signin/components/mail-and-password-auth.tsx +++ b/web/app/signin/components/mail-and-password-auth.tsx @@ -1,5 +1,5 @@ import type { ResponseError } from '@/service/fetch' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import Link from 'next/link' import { useRouter, useSearchParams } from 'next/navigation' import { useState } from 'react' diff --git a/web/app/signin/invite-settings/page.tsx b/web/app/signin/invite-settings/page.tsx index e3bbe420bc..c4923959ab 100644 --- a/web/app/signin/invite-settings/page.tsx +++ b/web/app/signin/invite-settings/page.tsx @@ -1,7 +1,7 @@ 'use client' import type { Locale } from '@/i18n-config' import { RiAccountCircleLine } from '@remixicon/react' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import Link from 'next/link' import { useRouter, useSearchParams } from 'next/navigation' import { useCallback, useState } from 'react' diff --git a/web/app/signup/components/input-mail.tsx b/web/app/signup/components/input-mail.tsx index b001e1f8b0..26ac99d2c6 100644 --- a/web/app/signup/components/input-mail.tsx +++ b/web/app/signup/components/input-mail.tsx @@ -1,6 +1,6 @@ 'use client' import type { MailSendResponse } from '@/service/use-common' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import Link from 'next/link' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' diff --git a/web/context/app-context.tsx b/web/context/app-context.tsx index b7a47048f3..cb4cab65b7 100644 --- a/web/context/app-context.tsx +++ b/web/context/app-context.tsx @@ -3,7 +3,7 @@ import type { FC, ReactNode } from 'react' import type { ICurrentWorkspace, LangGeniusVersionResponse, UserProfileResponse } from '@/models/common' import { useQueryClient } from '@tanstack/react-query' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useCallback, useEffect, useMemo } from 'react' import { createContext, useContext, useContextSelector } from 'use-context-selector' import { setUserId, setUserProperties } from '@/app/components/base/amplitude' diff --git a/web/context/datasets-context.tsx b/web/context/datasets-context.tsx index 4ca7ad311e..f35767bc21 100644 --- a/web/context/datasets-context.tsx +++ b/web/context/datasets-context.tsx @@ -1,7 +1,7 @@ 'use client' import type { DataSet } from '@/models/datasets' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { createContext, useContext } from 'use-context-selector' export type DatasetsContextValue = { diff --git a/web/context/debug-configuration.ts b/web/context/debug-configuration.ts index 51ba4ab626..2518af6260 100644 --- a/web/context/debug-configuration.ts +++ b/web/context/debug-configuration.ts @@ -22,7 +22,7 @@ import type { TextToSpeechConfig, } from '@/models/debug' import type { VisionSettings } from '@/types/app' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { createContext, useContext } from 'use-context-selector' import { ANNOTATION_DEFAULT, DEFAULT_AGENT_SETTING, DEFAULT_CHAT_PROMPT_CONFIG, DEFAULT_COMPLETION_PROMPT_CONFIG } from '@/config' import { PromptMode } from '@/models/debug' diff --git a/web/context/explore-context.ts b/web/context/explore-context.ts index 688b9036f9..1a7b35a09b 100644 --- a/web/context/explore-context.ts +++ b/web/context/explore-context.ts @@ -1,5 +1,5 @@ import type { InstalledApp } from '@/models/explore' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { createContext } from 'use-context-selector' type IExplore = { diff --git a/web/context/i18n.ts b/web/context/i18n.ts index 773569fa21..92d66a1b2f 100644 --- a/web/context/i18n.ts +++ b/web/context/i18n.ts @@ -1,5 +1,5 @@ import type { Locale } from '@/i18n-config' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { createContext, useContext, diff --git a/web/context/mitt-context.tsx b/web/context/mitt-context.tsx index 6c6209b5a5..0fc160613a 100644 --- a/web/context/mitt-context.tsx +++ b/web/context/mitt-context.tsx @@ -1,4 +1,4 @@ -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { createContext, useContext, useContextSelector } from 'use-context-selector' import { useMitt } from '@/hooks/use-mitt' diff --git a/web/context/modal-context.tsx b/web/context/modal-context.tsx index 2afd1b7b2f..5b417a64ff 100644 --- a/web/context/modal-context.tsx +++ b/web/context/modal-context.tsx @@ -22,7 +22,7 @@ import type { ExternalDataTool, } from '@/models/common' import type { ModerationConfig, PromptVariable } from '@/models/debug' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import dynamic from 'next/dynamic' import { useSearchParams } from 'next/navigation' import { useCallback, useEffect, useState } from 'react' diff --git a/web/context/provider-context.tsx b/web/context/provider-context.tsx index eb2a034f3b..3394ea20f6 100644 --- a/web/context/provider-context.tsx +++ b/web/context/provider-context.tsx @@ -5,7 +5,7 @@ import type { Model, ModelProvider } from '@/app/components/header/account-setti import type { RETRIEVE_METHOD } from '@/types/app' import { useQueryClient } from '@tanstack/react-query' import dayjs from 'dayjs' -import { noop } from 'lodash-es' +import { noop } from 'es-toolkit/compat' import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { createContext, useContext, useContextSelector } from 'use-context-selector' diff --git a/web/i18n-config/i18next-config.ts b/web/i18n-config/i18next-config.ts index e82f5f2acb..8dce79a5e5 100644 --- a/web/i18n-config/i18next-config.ts +++ b/web/i18n-config/i18next-config.ts @@ -1,7 +1,7 @@ 'use client' import type { Locale } from '.' +import { camelCase, kebabCase } from 'es-toolkit/compat' import i18n from 'i18next' -import { camelCase, kebabCase } from 'lodash-es' import { initReactI18next } from 'react-i18next' import app from '../i18n/en-US/app' diff --git a/web/i18n-config/server.ts b/web/i18n-config/server.ts index 75a5f3943b..c92a5a6025 100644 --- a/web/i18n-config/server.ts +++ b/web/i18n-config/server.ts @@ -1,9 +1,9 @@ import type { Locale } from '.' import type { KeyPrefix, Namespace } from './i18next-config' import { match } from '@formatjs/intl-localematcher' +import { camelCase } from 'es-toolkit/compat' import { createInstance } from 'i18next' import resourcesToBackend from 'i18next-resources-to-backend' -import { camelCase } from 'lodash-es' import Negotiator from 'negotiator' import { cookies, headers } from 'next/headers' import { initReactI18next } from 'react-i18next/initReactI18next' diff --git a/web/package.json b/web/package.json index f3cc095811..a27ac234ad 100644 --- a/web/package.json +++ b/web/package.json @@ -85,6 +85,7 @@ "echarts-for-react": "^3.0.5", "elkjs": "^0.9.3", "emoji-mart": "^5.6.0", + "es-toolkit": "^1.43.0", "fast-deep-equal": "^3.1.3", "html-entities": "^2.6.0", "html-to-image": "1.11.13", @@ -100,7 +101,6 @@ "lamejs": "^1.2.1", "lexical": "^0.38.2", "line-clamp": "^1.0.0", - "lodash-es": "^4.17.21", "mermaid": "~11.11.0", "mime": "^4.1.0", "mitt": "^3.0.1", @@ -169,7 +169,6 @@ "@testing-library/user-event": "^14.6.1", "@types/js-cookie": "^3.0.6", "@types/js-yaml": "^4.0.9", - "@types/lodash-es": "^4.17.12", "@types/negotiator": "^0.6.4", "@types/node": "18.15.0", "@types/qs": "^6.14.0", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 24e710534f..51f421e90b 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -174,6 +174,9 @@ importers: emoji-mart: specifier: ^5.6.0 version: 5.6.0 + es-toolkit: + specifier: ^1.43.0 + version: 1.43.0 fast-deep-equal: specifier: ^3.1.3 version: 3.1.3 @@ -219,9 +222,6 @@ importers: line-clamp: specifier: ^1.0.0 version: 1.0.0 - lodash-es: - specifier: ^4.17.21 - version: 4.17.21 mermaid: specifier: ~11.11.0 version: 11.11.0 @@ -421,9 +421,6 @@ importers: '@types/js-yaml': specifier: ^4.0.9 version: 4.0.9 - '@types/lodash-es': - specifier: ^4.17.12 - version: 4.17.12 '@types/negotiator': specifier: ^0.6.4 version: 0.6.4 @@ -3575,12 +3572,6 @@ packages: '@types/keyv@3.1.4': resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} - '@types/lodash-es@4.17.12': - resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} - - '@types/lodash@4.17.21': - resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} - '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} @@ -5042,6 +5033,9 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-toolkit@1.43.0: + resolution: {integrity: sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA==} + esast-util-from-estree@2.0.0: resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} @@ -12077,12 +12071,6 @@ snapshots: dependencies: '@types/node': 18.15.0 - '@types/lodash-es@4.17.12': - dependencies: - '@types/lodash': 4.17.21 - - '@types/lodash@4.17.21': {} - '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 @@ -13685,6 +13673,8 @@ snapshots: es-module-lexer@1.7.0: {} + es-toolkit@1.43.0: {} + esast-util-from-estree@2.0.0: dependencies: '@types/estree-jsx': 1.0.5 diff --git a/web/service/knowledge/use-create-dataset.ts b/web/service/knowledge/use-create-dataset.ts index eb656c2994..a0d55eeb99 100644 --- a/web/service/knowledge/use-create-dataset.ts +++ b/web/service/knowledge/use-create-dataset.ts @@ -18,7 +18,7 @@ import type { ProcessRuleResponse, } from '@/models/datasets' import { useMutation } from '@tanstack/react-query' -import groupBy from 'lodash-es/groupBy' +import { groupBy } from 'es-toolkit/compat' import { post } from '../base' import { createDocument, createFirstDocument, fetchDefaultProcessRule, fetchFileIndexingEstimate } from '../datasets' diff --git a/web/service/use-flow.ts b/web/service/use-flow.ts index 30bec6dd23..74aa78ec10 100644 --- a/web/service/use-flow.ts +++ b/web/service/use-flow.ts @@ -1,5 +1,5 @@ import type { FlowType } from '@/types/common' -import { curry } from 'lodash-es' +import { curry } from 'es-toolkit/compat' import { useDeleteAllInspectorVars as useDeleteAllInspectorVarsInner, useDeleteInspectVar as useDeleteInspectVarInner, diff --git a/web/service/use-plugins.ts b/web/service/use-plugins.ts index 58454125ed..32ea4f35fd 100644 --- a/web/service/use-plugins.ts +++ b/web/service/use-plugins.ts @@ -33,7 +33,7 @@ import { useQuery, useQueryClient, } from '@tanstack/react-query' -import { cloneDeep } from 'lodash-es' +import { cloneDeep } from 'es-toolkit/compat' import { useCallback, useEffect, useState } from 'react' import useRefreshPluginList from '@/app/components/plugins/install-plugin/hooks/use-refresh-plugin-list' import { getFormattedPlugin } from '@/app/components/plugins/marketplace/utils' diff --git a/web/utils/index.ts b/web/utils/index.ts index 263d415479..ebb8b90645 100644 --- a/web/utils/index.ts +++ b/web/utils/index.ts @@ -1,4 +1,4 @@ -import { escape } from 'lodash-es' +import { escape } from 'es-toolkit/compat' export const sleep = (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms))