From 69d1ccb7a7051cfff833a97874d57fd0efffa76f Mon Sep 17 00:00:00 2001
From: yyh <92089059+lyzno1@users.noreply.github.com>
Date: Wed, 18 Mar 2026 12:14:59 +0800
Subject: [PATCH] refactor: route next/link through compat re-export (#33632)
---
web/app/(shareLayout)/webapp-reset-password/page.tsx | 4 ++--
.../webapp-signin/components/mail-and-password-auth.tsx | 2 +-
web/app/(shareLayout)/webapp-signin/normalForm.tsx | 2 +-
.../delete-account/components/check-email.tsx | 2 +-
.../delete-account/components/verify-email.tsx | 2 +-
.../app-sidebar/nav-link/__tests__/index.spec.tsx | 2 +-
web/app/components/app-sidebar/nav-link/index.tsx | 2 +-
.../configuration/dataset-config/select-dataset/index.tsx | 2 +-
web/app/components/app/log/empty-element.tsx | 2 +-
web/app/components/app/overview/settings/index.tsx | 2 +-
web/app/components/app/overview/trigger-card.tsx | 2 +-
web/app/components/app/workflow-log/index.spec.tsx | 2 +-
web/app/components/apps/footer.tsx | 2 +-
web/app/components/base/chat/chat/citation/popup.tsx | 2 +-
web/app/components/base/encrypted-bottom/index.tsx | 2 +-
.../base/linked-apps-panel/__tests__/index.spec.tsx | 2 +-
web/app/components/base/linked-apps-panel/index.tsx | 2 +-
.../base/ui/dropdown-menu/__tests__/index.spec.tsx | 4 ++--
.../components/billing/pricing/__tests__/footer.spec.tsx | 2 +-
web/app/components/billing/pricing/__tests__/index.spec.tsx | 2 +-
web/app/components/billing/pricing/footer.tsx | 2 +-
web/app/components/datasets/create-from-pipeline/header.tsx | 2 +-
web/app/components/datasets/create/__tests__/index.spec.tsx | 2 +-
.../components/datasets/create/embedding-process/index.tsx | 2 +-
.../components/__tests__/indexing-mode-section.spec.tsx | 2 +-
.../create/step-two/components/indexing-mode-section.tsx | 2 +-
.../datasets/create/top-bar/__tests__/index.spec.tsx | 2 +-
web/app/components/datasets/create/top-bar/index.tsx | 2 +-
.../documents/create-from-pipeline/__tests__/index.spec.tsx | 2 +-
.../create-from-pipeline/__tests__/left-header.spec.tsx | 2 +-
.../create-from-pipeline/actions/__tests__/index.spec.tsx | 2 +-
.../documents/create-from-pipeline/actions/index.tsx | 2 +-
.../datasets/documents/create-from-pipeline/left-header.tsx | 2 +-
.../processing/embedding-process/__tests__/index.spec.tsx | 2 +-
.../processing/embedding-process/index.tsx | 2 +-
.../components/datasets/extra-info/__tests__/index.spec.tsx | 2 +-
web/app/components/datasets/extra-info/api-access/card.tsx | 2 +-
.../extra-info/service-api/__tests__/index.spec.tsx | 2 +-
web/app/components/datasets/extra-info/service-api/card.tsx | 2 +-
.../components/datasets/list/new-dataset-card/option.tsx | 2 +-
web/app/components/explore/sidebar/index.tsx | 2 +-
web/app/components/header/__tests__/index.spec.tsx | 2 +-
web/app/components/header/account-about/index.tsx | 4 ++--
web/app/components/header/account-dropdown/index.tsx | 2 +-
.../header/account-setting/Integrations-page/index.tsx | 2 +-
.../__tests__/install-from-marketplace.spec.tsx | 2 +-
.../data-source-page-new/install-from-marketplace.tsx | 2 +-
.../__tests__/install-from-marketplace.spec.tsx | 2 +-
.../model-provider-page/install-from-marketplace.tsx | 2 +-
.../model-parameter-modal/status-indicators.tsx | 2 +-
.../components/header/account-setting/plugin-page/index.tsx | 2 +-
web/app/components/header/explore-nav/index.tsx | 2 +-
web/app/components/header/index.tsx | 2 +-
web/app/components/header/nav/index.tsx | 2 +-
web/app/components/header/plugins-nav/index.tsx | 2 +-
web/app/components/header/tools-nav/index.tsx | 2 +-
.../plugins/base/__tests__/deprecation-notice.spec.tsx | 2 +-
web/app/components/plugins/base/deprecation-notice.tsx | 2 +-
.../plugins/plugin-detail-panel/tool-selector/index.tsx | 2 +-
web/app/components/plugins/plugin-page/index.tsx | 2 +-
.../components/rag-pipeline-header/__tests__/index.spec.tsx | 2 +-
.../rag-pipeline-header/publisher/__tests__/index.spec.tsx | 2 +-
.../rag-pipeline-header/publisher/__tests__/popup.spec.tsx | 2 +-
.../components/rag-pipeline-header/publisher/popup.tsx | 2 +-
web/app/components/tools/provider/empty.tsx | 2 +-
.../components/workflow/block-selector/all-start-blocks.tsx | 2 +-
web/app/components/workflow/block-selector/all-tools.tsx | 2 +-
.../components/workflow/block-selector/featured-tools.tsx | 2 +-
.../workflow/block-selector/featured-triggers.tsx | 2 +-
.../workflow/block-selector/market-place-plugin/list.tsx | 2 +-
.../block-selector/rag-tool-recommendations/index.tsx | 2 +-
.../nodes/_base/components/agent-strategy-selector.tsx | 2 +-
.../workflow/nodes/_base/components/agent-strategy.tsx | 2 +-
.../nodes/_base/components/switch-plugin-version.tsx | 2 +-
web/app/education-apply/expire-notice-modal.tsx | 2 +-
web/app/install/installForm.tsx | 6 +++---
web/app/page.tsx | 2 +-
web/app/reset-password/page.tsx | 2 +-
web/app/signin/components/mail-and-password-auth.tsx | 2 +-
web/app/signin/invite-settings/page.tsx | 2 +-
web/app/signin/normal-form.tsx | 2 +-
web/app/signin/one-more-step.tsx | 2 +-
web/app/signup/components/input-mail.spec.tsx | 2 +-
web/app/signup/components/input-mail.tsx | 2 +-
web/eslint.config.mjs | 4 ++++
web/next/link.ts | 1 +
86 files changed, 94 insertions(+), 89 deletions(-)
create mode 100644 web/next/link.ts
diff --git a/web/app/(shareLayout)/webapp-reset-password/page.tsx b/web/app/(shareLayout)/webapp-reset-password/page.tsx
index 9b9a853cdd..05ad79b3bd 100644
--- a/web/app/(shareLayout)/webapp-reset-password/page.tsx
+++ b/web/app/(shareLayout)/webapp-reset-password/page.tsx
@@ -1,7 +1,6 @@
'use client'
import { RiArrowLeftLine, RiLockPasswordLine } from '@remixicon/react'
import { noop } from 'es-toolkit/function'
-import Link from 'next/link'
import { useRouter, useSearchParams } from 'next/navigation'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -10,9 +9,10 @@ import Input from '@/app/components/base/input'
import Toast from '@/app/components/base/toast'
import { COUNT_DOWN_KEY, COUNT_DOWN_TIME_MS } from '@/app/components/signin/countdown'
import { emailRegex } from '@/config'
-
import { useLocale } from '@/context/i18n'
+
import useDocumentTitle from '@/hooks/use-document-title'
+import Link from '@/next/link'
import { sendResetPasswordCode } from '@/service/common'
export default function CheckCode() {
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 e49559401d..f5c0e4a45c 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,6 +1,5 @@
'use client'
import { noop } from 'es-toolkit/function'
-import Link from 'next/link'
import { useRouter, useSearchParams } from 'next/navigation'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -10,6 +9,7 @@ import Toast from '@/app/components/base/toast'
import { emailRegex } from '@/config'
import { useLocale } from '@/context/i18n'
import { useWebAppStore } from '@/context/web-app-context'
+import Link from '@/next/link'
import { webAppLogin } from '@/service/common'
import { fetchAccessToken } from '@/service/share'
import { setWebAppAccessToken, setWebAppPassport } from '@/service/webapp-auth'
diff --git a/web/app/(shareLayout)/webapp-signin/normalForm.tsx b/web/app/(shareLayout)/webapp-signin/normalForm.tsx
index b15145346f..7ee08d66ae 100644
--- a/web/app/(shareLayout)/webapp-signin/normalForm.tsx
+++ b/web/app/(shareLayout)/webapp-signin/normalForm.tsx
@@ -1,12 +1,12 @@
'use client'
import { RiContractLine, RiDoorLockLine, RiErrorWarningFill } from '@remixicon/react'
-import Link from 'next/link'
import * as React from 'react'
import { useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Loading from '@/app/components/base/loading'
import { IS_CE_EDITION } from '@/config'
import { useGlobalPublicStore } from '@/context/global-public-context'
+import Link from '@/next/link'
import { LicenseStatus } from '@/types/feature'
import { cn } from '@/utils/classnames'
import MailAndCodeAuth from './components/mail-and-code-auth'
diff --git a/web/app/account/(commonLayout)/delete-account/components/check-email.tsx b/web/app/account/(commonLayout)/delete-account/components/check-email.tsx
index 65a58c936e..e0f00189b2 100644
--- a/web/app/account/(commonLayout)/delete-account/components/check-email.tsx
+++ b/web/app/account/(commonLayout)/delete-account/components/check-email.tsx
@@ -1,10 +1,10 @@
'use client'
-import Link from 'next/link'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Button from '@/app/components/base/button'
import Input from '@/app/components/base/input'
import { useAppContext } from '@/context/app-context'
+import Link from '@/next/link'
import { useSendDeleteAccountEmail } from '../state'
type DeleteAccountProps = {
diff --git a/web/app/account/(commonLayout)/delete-account/components/verify-email.tsx b/web/app/account/(commonLayout)/delete-account/components/verify-email.tsx
index d7590c27f9..5d76f13f34 100644
--- a/web/app/account/(commonLayout)/delete-account/components/verify-email.tsx
+++ b/web/app/account/(commonLayout)/delete-account/components/verify-email.tsx
@@ -1,10 +1,10 @@
'use client'
-import Link from 'next/link'
import { useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Button from '@/app/components/base/button'
import Input from '@/app/components/base/input'
import Countdown from '@/app/components/signin/countdown'
+import Link from '@/next/link'
import { useAccountDeleteStore, useConfirmDeleteAccount, useSendDeleteAccountEmail } from '../state'
const CODE_EXP = /[A-Z\d]{6}/gi
diff --git a/web/app/components/app-sidebar/nav-link/__tests__/index.spec.tsx b/web/app/components/app-sidebar/nav-link/__tests__/index.spec.tsx
index 04ca7bd0e4..faaaa43300 100644
--- a/web/app/components/app-sidebar/nav-link/__tests__/index.spec.tsx
+++ b/web/app/components/app-sidebar/nav-link/__tests__/index.spec.tsx
@@ -9,7 +9,7 @@ vi.mock('next/navigation', () => ({
}))
// Mock Next.js Link component
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: function MockLink({ children, href, className, title }: { children: React.ReactNode, href: string, className?: string, title?: string }) {
return (
diff --git a/web/app/components/app-sidebar/nav-link/index.tsx b/web/app/components/app-sidebar/nav-link/index.tsx
index d69ed8590e..a49a0b520e 100644
--- a/web/app/components/app-sidebar/nav-link/index.tsx
+++ b/web/app/components/app-sidebar/nav-link/index.tsx
@@ -1,8 +1,8 @@
'use client'
import type { RemixiconComponentType } from '@remixicon/react'
-import Link from 'next/link'
import { useSelectedLayoutSegment } from 'next/navigation'
import * as React from 'react'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
export type NavIcon = React.ComponentType<
diff --git a/web/app/components/app/configuration/dataset-config/select-dataset/index.tsx b/web/app/components/app/configuration/dataset-config/select-dataset/index.tsx
index 91e5353cc4..8c2fb77c20 100644
--- a/web/app/components/app/configuration/dataset-config/select-dataset/index.tsx
+++ b/web/app/components/app/configuration/dataset-config/select-dataset/index.tsx
@@ -2,7 +2,6 @@
import type { FC } from 'react'
import type { DataSet } from '@/models/datasets'
import { useInfiniteScroll } from 'ahooks'
-import Link from 'next/link'
import * as React from 'react'
import { useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -14,6 +13,7 @@ import Modal from '@/app/components/base/modal'
import { ModelFeatureEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import FeatureIcon from '@/app/components/header/account-setting/model-provider-page/model-selector/feature-icon'
import { useKnowledge } from '@/hooks/use-knowledge'
+import Link from '@/next/link'
import { useInfiniteDatasets } from '@/service/knowledge/use-dataset'
import { cn } from '@/utils/classnames'
diff --git a/web/app/components/app/log/empty-element.tsx b/web/app/components/app/log/empty-element.tsx
index e42a1df7d5..95b0e7f03f 100644
--- a/web/app/components/app/log/empty-element.tsx
+++ b/web/app/components/app/log/empty-element.tsx
@@ -1,9 +1,9 @@
'use client'
import type { FC, SVGProps } from 'react'
import type { App } from '@/types/app'
-import Link from 'next/link'
import * as React from 'react'
import { Trans, useTranslation } from 'react-i18next'
+import Link from '@/next/link'
import { AppModeEnum } from '@/types/app'
import { getRedirectionPath } from '@/utils/app-redirection'
import { basePath } from '@/utils/var'
diff --git a/web/app/components/app/overview/settings/index.tsx b/web/app/components/app/overview/settings/index.tsx
index f7c9e309ab..13dacde424 100644
--- a/web/app/components/app/overview/settings/index.tsx
+++ b/web/app/components/app/overview/settings/index.tsx
@@ -4,7 +4,6 @@ import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
import type { AppDetailResponse } from '@/models/app'
import type { AppIconType, AppSSO, Language } from '@/types/app'
import { RiArrowRightSLine, RiCloseLine } from '@remixicon/react'
-import Link from 'next/link'
import * as React from 'react'
import { useCallback, useEffect, useRef, useState } from 'react'
import { Trans, useTranslation } from 'react-i18next'
@@ -26,6 +25,7 @@ import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/con
import { useModalContext } from '@/context/modal-context'
import { useProviderContext } from '@/context/provider-context'
import { languages } from '@/i18n-config/language'
+import Link from '@/next/link'
import { AppModeEnum } from '@/types/app'
import { cn } from '@/utils/classnames'
diff --git a/web/app/components/app/overview/trigger-card.tsx b/web/app/components/app/overview/trigger-card.tsx
index 1f0f0dca56..09e3a08393 100644
--- a/web/app/components/app/overview/trigger-card.tsx
+++ b/web/app/components/app/overview/trigger-card.tsx
@@ -3,7 +3,6 @@ import type { AppDetailResponse } from '@/models/app'
import type { AppTrigger } from '@/service/use-tools'
import type { AppSSO } from '@/types/app'
import type { I18nKeysByPrefix } from '@/types/i18n'
-import Link from 'next/link'
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import { TriggerAll } from '@/app/components/base/icons/src/vender/workflow'
@@ -13,6 +12,7 @@ import { useTriggerStatusStore } from '@/app/components/workflow/store/trigger-s
import { BlockEnum } from '@/app/components/workflow/types'
import { useAppContext } from '@/context/app-context'
import { useDocLink } from '@/context/i18n'
+import Link from '@/next/link'
import {
useAppTriggers,
diff --git a/web/app/components/app/workflow-log/index.spec.tsx b/web/app/components/app/workflow-log/index.spec.tsx
index f8e3f16e25..e69169cde3 100644
--- a/web/app/components/app/workflow-log/index.spec.tsx
+++ b/web/app/components/app/workflow-log/index.spec.tsx
@@ -53,7 +53,7 @@ vi.mock('next/navigation', () => ({
}),
}))
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href }: { children: React.ReactNode, href: string }) => {children},
}))
diff --git a/web/app/components/apps/footer.tsx b/web/app/components/apps/footer.tsx
index 3a0e960e0d..9147ccf6a6 100644
--- a/web/app/components/apps/footer.tsx
+++ b/web/app/components/apps/footer.tsx
@@ -1,7 +1,7 @@
import { RiDiscordFill, RiDiscussLine, RiGithubFill } from '@remixicon/react'
-import Link from 'next/link'
import * as React from 'react'
import { useTranslation } from 'react-i18next'
+import Link from '@/next/link'
type CustomLinkProps = {
href: string
diff --git a/web/app/components/base/chat/chat/citation/popup.tsx b/web/app/components/base/chat/chat/citation/popup.tsx
index 7dc2baeb88..3a1d4bf251 100644
--- a/web/app/components/base/chat/chat/citation/popup.tsx
+++ b/web/app/components/base/chat/chat/citation/popup.tsx
@@ -1,6 +1,5 @@
import type { FC, MouseEvent } from 'react'
import type { Resources } from './index'
-import Link from 'next/link'
import { Fragment, useState } from 'react'
import { useTranslation } from 'react-i18next'
import FileIcon from '@/app/components/base/file-icon'
@@ -9,6 +8,7 @@ import {
PortalToFollowElemContent,
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
+import Link from '@/next/link'
import { useDocumentDownload } from '@/service/knowledge/use-document'
import { downloadUrl } from '@/utils/download'
import ProgressTooltip from './progress-tooltip'
diff --git a/web/app/components/base/encrypted-bottom/index.tsx b/web/app/components/base/encrypted-bottom/index.tsx
index 5a9bc9b488..5f35433612 100644
--- a/web/app/components/base/encrypted-bottom/index.tsx
+++ b/web/app/components/base/encrypted-bottom/index.tsx
@@ -1,7 +1,7 @@
import type { I18nKeysWithPrefix } from '@/types/i18n'
import { RiLock2Fill } from '@remixicon/react'
-import Link from 'next/link'
import { useTranslation } from 'react-i18next'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
type EncryptedKey = I18nKeysWithPrefix<'common', 'provider.encrypted.'>
diff --git a/web/app/components/base/linked-apps-panel/__tests__/index.spec.tsx b/web/app/components/base/linked-apps-panel/__tests__/index.spec.tsx
index 27408531c4..5576fb289e 100644
--- a/web/app/components/base/linked-apps-panel/__tests__/index.spec.tsx
+++ b/web/app/components/base/linked-apps-panel/__tests__/index.spec.tsx
@@ -4,7 +4,7 @@ import { vi } from 'vitest'
import { AppModeEnum } from '@/types/app'
import LinkedAppsPanel from '../index'
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href, className }: { children: React.ReactNode, href: string, className: string }) => (
{children}
diff --git a/web/app/components/base/linked-apps-panel/index.tsx b/web/app/components/base/linked-apps-panel/index.tsx
index adc8ccf729..1ce76e0647 100644
--- a/web/app/components/base/linked-apps-panel/index.tsx
+++ b/web/app/components/base/linked-apps-panel/index.tsx
@@ -2,9 +2,9 @@
import type { FC } from 'react'
import type { RelatedApp } from '@/models/datasets'
import { RiArrowRightUpLine } from '@remixicon/react'
-import Link from 'next/link'
import * as React from 'react'
import AppIcon from '@/app/components/base/app-icon'
+import Link from '@/next/link'
import { AppModeEnum } from '@/types/app'
import { cn } from '@/utils/classnames'
diff --git a/web/app/components/base/ui/dropdown-menu/__tests__/index.spec.tsx b/web/app/components/base/ui/dropdown-menu/__tests__/index.spec.tsx
index c5fb532d98..b6772e5ad0 100644
--- a/web/app/components/base/ui/dropdown-menu/__tests__/index.spec.tsx
+++ b/web/app/components/base/ui/dropdown-menu/__tests__/index.spec.tsx
@@ -1,7 +1,7 @@
import type { ComponentPropsWithoutRef, ReactNode } from 'react'
import { fireEvent, render, screen, within } from '@testing-library/react'
-import Link from 'next/link'
import { describe, expect, it, vi } from 'vitest'
+import Link from '@/next/link'
import {
DropdownMenu,
DropdownMenuContent,
@@ -14,7 +14,7 @@ import {
DropdownMenuTrigger,
} from '../index'
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({
href,
children,
diff --git a/web/app/components/billing/pricing/__tests__/footer.spec.tsx b/web/app/components/billing/pricing/__tests__/footer.spec.tsx
index 762d0ad211..9a9215c177 100644
--- a/web/app/components/billing/pricing/__tests__/footer.spec.tsx
+++ b/web/app/components/billing/pricing/__tests__/footer.spec.tsx
@@ -3,7 +3,7 @@ import * as React from 'react'
import Footer from '../footer'
import { CategoryEnum } from '../types'
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href, className, target }: { children: React.ReactNode, href: string, className?: string, target?: string }) => (
{children}
diff --git a/web/app/components/billing/pricing/__tests__/index.spec.tsx b/web/app/components/billing/pricing/__tests__/index.spec.tsx
index 1be2234cf9..36848cd463 100644
--- a/web/app/components/billing/pricing/__tests__/index.spec.tsx
+++ b/web/app/components/billing/pricing/__tests__/index.spec.tsx
@@ -19,7 +19,7 @@ vi.mock('../plans/self-hosted-plan-item/list', () => ({
),
}))
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href, className, target }: { children: React.ReactNode, href: string, className?: string, target?: string }) => (
{children}
diff --git a/web/app/components/billing/pricing/footer.tsx b/web/app/components/billing/pricing/footer.tsx
index 6a213eca00..0d3fd965b0 100644
--- a/web/app/components/billing/pricing/footer.tsx
+++ b/web/app/components/billing/pricing/footer.tsx
@@ -1,7 +1,7 @@
import type { Category } from './types'
-import Link from 'next/link'
import * as React from 'react'
import { useTranslation } from 'react-i18next'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
import { CategoryEnum } from './types'
diff --git a/web/app/components/datasets/create-from-pipeline/header.tsx b/web/app/components/datasets/create-from-pipeline/header.tsx
index 99738edb08..204b372a1d 100644
--- a/web/app/components/datasets/create-from-pipeline/header.tsx
+++ b/web/app/components/datasets/create-from-pipeline/header.tsx
@@ -1,7 +1,7 @@
import { RiArrowLeftLine } from '@remixicon/react'
-import Link from 'next/link'
import * as React from 'react'
import { useTranslation } from 'react-i18next'
+import Link from '@/next/link'
import Button from '../../base/button'
const Header = () => {
diff --git a/web/app/components/datasets/create/__tests__/index.spec.tsx b/web/app/components/datasets/create/__tests__/index.spec.tsx
index 793bc21344..59d5dd891a 100644
--- a/web/app/components/datasets/create/__tests__/index.spec.tsx
+++ b/web/app/components/datasets/create/__tests__/index.spec.tsx
@@ -24,7 +24,7 @@ const IndexingTypeValues = {
}
// Mock next/link
-vi.mock('next/link', () => {
+vi.mock('@/next/link', () => {
return function MockLink({ children, href }: { children: React.ReactNode, href: string }) {
return {children}
}
diff --git a/web/app/components/datasets/create/embedding-process/index.tsx b/web/app/components/datasets/create/embedding-process/index.tsx
index e9cea84f00..89c57b612d 100644
--- a/web/app/components/datasets/create/embedding-process/index.tsx
+++ b/web/app/components/datasets/create/embedding-process/index.tsx
@@ -6,7 +6,6 @@ import {
RiLoader2Fill,
RiTerminalBoxLine,
} from '@remixicon/react'
-import Link from 'next/link'
import { useRouter } from 'next/navigation'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
@@ -15,6 +14,7 @@ import Divider from '@/app/components/base/divider'
import { Plan } from '@/app/components/billing/type'
import { useProviderContext } from '@/context/provider-context'
import { useDatasetApiAccessUrl } from '@/hooks/use-api-access-url'
+import Link from '@/next/link'
import { useProcessRule } from '@/service/knowledge/use-dataset'
import { useInvalidDocumentList } from '@/service/knowledge/use-document'
import IndexingProgressItem from './indexing-progress-item'
diff --git a/web/app/components/datasets/create/step-two/components/__tests__/indexing-mode-section.spec.tsx b/web/app/components/datasets/create/step-two/components/__tests__/indexing-mode-section.spec.tsx
index 43a944dcd4..e46ff6d484 100644
--- a/web/app/components/datasets/create/step-two/components/__tests__/indexing-mode-section.spec.tsx
+++ b/web/app/components/datasets/create/step-two/components/__tests__/indexing-mode-section.spec.tsx
@@ -6,7 +6,7 @@ import { ChunkingMode } from '@/models/datasets'
import { IndexingType } from '../../hooks'
import { IndexingModeSection } from '../indexing-mode-section'
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href, ...props }: { children?: React.ReactNode, href?: string, className?: string }) => {children},
}))
diff --git a/web/app/components/datasets/create/step-two/components/indexing-mode-section.tsx b/web/app/components/datasets/create/step-two/components/indexing-mode-section.tsx
index da309348cc..8b49a00500 100644
--- a/web/app/components/datasets/create/step-two/components/indexing-mode-section.tsx
+++ b/web/app/components/datasets/create/step-two/components/indexing-mode-section.tsx
@@ -3,7 +3,6 @@
import type { FC } from 'react'
import type { DefaultModel, Model } from '@/app/components/header/account-setting/model-provider-page/declarations'
import type { RetrievalConfig } from '@/types/app'
-import Link from 'next/link'
import { useTranslation } from 'react-i18next'
import Badge from '@/app/components/base/badge'
import Button from '@/app/components/base/button'
@@ -16,6 +15,7 @@ import RetrievalMethodConfig from '@/app/components/datasets/common/retrieval-me
import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
import { useDocLink } from '@/context/i18n'
import { ChunkingMode } from '@/models/datasets'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
import { indexMethodIcon } from '../../icons'
import { IndexingType } from '../hooks'
diff --git a/web/app/components/datasets/create/top-bar/__tests__/index.spec.tsx b/web/app/components/datasets/create/top-bar/__tests__/index.spec.tsx
index 4fc8d1852b..c038a371d6 100644
--- a/web/app/components/datasets/create/top-bar/__tests__/index.spec.tsx
+++ b/web/app/components/datasets/create/top-bar/__tests__/index.spec.tsx
@@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react'
import { TopBar } from '../index'
// Mock next/link to capture href values
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href, replace, className }: { children: React.ReactNode, href: string, replace?: boolean, className?: string }) => (
{children}
diff --git a/web/app/components/datasets/create/top-bar/index.tsx b/web/app/components/datasets/create/top-bar/index.tsx
index 0051430511..ba4c49e300 100644
--- a/web/app/components/datasets/create/top-bar/index.tsx
+++ b/web/app/components/datasets/create/top-bar/index.tsx
@@ -1,9 +1,9 @@
import type { FC } from 'react'
import type { StepperProps } from '../stepper'
import { RiArrowLeftLine } from '@remixicon/react'
-import Link from 'next/link'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
import { Stepper } from '../stepper'
diff --git a/web/app/components/datasets/documents/create-from-pipeline/__tests__/index.spec.tsx b/web/app/components/datasets/documents/create-from-pipeline/__tests__/index.spec.tsx
index 0096dc8c29..476ac1294b 100644
--- a/web/app/components/datasets/documents/create-from-pipeline/__tests__/index.spec.tsx
+++ b/web/app/components/datasets/documents/create-from-pipeline/__tests__/index.spec.tsx
@@ -101,7 +101,7 @@ vi.mock('next/navigation', () => ({
}))
// Mock next/link
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href }: { children: React.ReactNode, href: string }) => (
{children}
),
diff --git a/web/app/components/datasets/documents/create-from-pipeline/__tests__/left-header.spec.tsx b/web/app/components/datasets/documents/create-from-pipeline/__tests__/left-header.spec.tsx
index 584c21e826..c75a36a5fc 100644
--- a/web/app/components/datasets/documents/create-from-pipeline/__tests__/left-header.spec.tsx
+++ b/web/app/components/datasets/documents/create-from-pipeline/__tests__/left-header.spec.tsx
@@ -7,7 +7,7 @@ vi.mock('next/navigation', () => ({
useParams: () => ({ datasetId: 'test-ds-id' }),
}))
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href }: { children: React.ReactNode, href: string }) => (
{children}
),
diff --git a/web/app/components/datasets/documents/create-from-pipeline/actions/__tests__/index.spec.tsx b/web/app/components/datasets/documents/create-from-pipeline/actions/__tests__/index.spec.tsx
index 45ecaa7e9b..b3cedd71af 100644
--- a/web/app/components/datasets/documents/create-from-pipeline/actions/__tests__/index.spec.tsx
+++ b/web/app/components/datasets/documents/create-from-pipeline/actions/__tests__/index.spec.tsx
@@ -9,7 +9,7 @@ vi.mock('next/navigation', () => ({
}))
// Mock next/link to capture href
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href, replace }: { children: React.ReactNode, href: string, replace?: boolean }) => (
{children}
diff --git a/web/app/components/datasets/documents/create-from-pipeline/actions/index.tsx b/web/app/components/datasets/documents/create-from-pipeline/actions/index.tsx
index de0609b4d8..c53fadf826 100644
--- a/web/app/components/datasets/documents/create-from-pipeline/actions/index.tsx
+++ b/web/app/components/datasets/documents/create-from-pipeline/actions/index.tsx
@@ -1,11 +1,11 @@
import { RiArrowRightLine } from '@remixicon/react'
-import Link from 'next/link'
import { useParams } from 'next/navigation'
import * as React from 'react'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import Button from '@/app/components/base/button'
import Checkbox from '@/app/components/base/checkbox'
+import Link from '@/next/link'
type ActionsProps = {
disabled?: boolean
diff --git a/web/app/components/datasets/documents/create-from-pipeline/left-header.tsx b/web/app/components/datasets/documents/create-from-pipeline/left-header.tsx
index 2b30c79022..375886cbc4 100644
--- a/web/app/components/datasets/documents/create-from-pipeline/left-header.tsx
+++ b/web/app/components/datasets/documents/create-from-pipeline/left-header.tsx
@@ -1,10 +1,10 @@
import type { Step } from './step-indicator'
import { RiArrowLeftLine } from '@remixicon/react'
-import Link from 'next/link'
import { useParams } from 'next/navigation'
import * as React from 'react'
import Button from '@/app/components/base/button'
import Effect from '@/app/components/base/effect'
+import Link from '@/next/link'
import StepIndicator from './step-indicator'
type LeftHeaderProps = {
diff --git a/web/app/components/datasets/documents/create-from-pipeline/processing/embedding-process/__tests__/index.spec.tsx b/web/app/components/datasets/documents/create-from-pipeline/processing/embedding-process/__tests__/index.spec.tsx
index aa107b8635..1d0518e11e 100644
--- a/web/app/components/datasets/documents/create-from-pipeline/processing/embedding-process/__tests__/index.spec.tsx
+++ b/web/app/components/datasets/documents/create-from-pipeline/processing/embedding-process/__tests__/index.spec.tsx
@@ -17,7 +17,7 @@ vi.mock('next/navigation', () => ({
}))
// Mock next/link
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: function MockLink({ children, href, ...props }: { children: React.ReactNode, href: string }) {
return {children}
},
diff --git a/web/app/components/datasets/documents/create-from-pipeline/processing/embedding-process/index.tsx b/web/app/components/datasets/documents/create-from-pipeline/processing/embedding-process/index.tsx
index a7834fc656..49c85ae433 100644
--- a/web/app/components/datasets/documents/create-from-pipeline/processing/embedding-process/index.tsx
+++ b/web/app/components/datasets/documents/create-from-pipeline/processing/embedding-process/index.tsx
@@ -10,7 +10,6 @@ import {
RiLoader2Fill,
RiTerminalBoxLine,
} from '@remixicon/react'
-import Link from 'next/link'
import { useRouter } from 'next/navigation'
import * as React from 'react'
import { useEffect, useMemo, useState } from 'react'
@@ -26,6 +25,7 @@ import DocumentFileIcon from '@/app/components/datasets/common/document-file-ico
import { useProviderContext } from '@/context/provider-context'
import { useDatasetApiAccessUrl } from '@/hooks/use-api-access-url'
import { DatasourceType } from '@/models/pipeline'
+import Link from '@/next/link'
import { useIndexingStatusBatch, useProcessRule } from '@/service/knowledge/use-dataset'
import { useInvalidDocumentList } from '@/service/knowledge/use-document'
import { cn } from '@/utils/classnames'
diff --git a/web/app/components/datasets/extra-info/__tests__/index.spec.tsx b/web/app/components/datasets/extra-info/__tests__/index.spec.tsx
index 4a8d89e9fb..c6f9066e6b 100644
--- a/web/app/components/datasets/extra-info/__tests__/index.spec.tsx
+++ b/web/app/components/datasets/extra-info/__tests__/index.spec.tsx
@@ -23,7 +23,7 @@ vi.mock('next/navigation', () => ({
}))
// Mock next/link
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href, ...props }: { children: React.ReactNode, href: string, [key: string]: unknown }) => (
{children}
),
diff --git a/web/app/components/datasets/extra-info/api-access/card.tsx b/web/app/components/datasets/extra-info/api-access/card.tsx
index 946536bf2c..eee586ff8e 100644
--- a/web/app/components/datasets/extra-info/api-access/card.tsx
+++ b/web/app/components/datasets/extra-info/api-access/card.tsx
@@ -1,5 +1,4 @@
import { RiArrowRightUpLine, RiBookOpenLine } from '@remixicon/react'
-import Link from 'next/link'
import * as React from 'react'
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
@@ -8,6 +7,7 @@ import Indicator from '@/app/components/header/indicator'
import { useSelector as useAppContextSelector } from '@/context/app-context'
import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail'
import { useDatasetApiAccessUrl } from '@/hooks/use-api-access-url'
+import Link from '@/next/link'
import { useDisableDatasetServiceApi, useEnableDatasetServiceApi } from '@/service/knowledge/use-dataset'
import { cn } from '@/utils/classnames'
diff --git a/web/app/components/datasets/extra-info/service-api/__tests__/index.spec.tsx b/web/app/components/datasets/extra-info/service-api/__tests__/index.spec.tsx
index b94508de6a..201649556f 100644
--- a/web/app/components/datasets/extra-info/service-api/__tests__/index.spec.tsx
+++ b/web/app/components/datasets/extra-info/service-api/__tests__/index.spec.tsx
@@ -19,7 +19,7 @@ vi.mock('next/navigation', () => ({
}))
// Mock next/link
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href, ...props }: { children: React.ReactNode, href: string, [key: string]: unknown }) => (
{children}
),
diff --git a/web/app/components/datasets/extra-info/service-api/card.tsx b/web/app/components/datasets/extra-info/service-api/card.tsx
index 31076d12fc..bf84204ea4 100644
--- a/web/app/components/datasets/extra-info/service-api/card.tsx
+++ b/web/app/components/datasets/extra-info/service-api/card.tsx
@@ -1,5 +1,4 @@
import { RiBookOpenLine, RiKey2Line } from '@remixicon/react'
-import Link from 'next/link'
import * as React from 'react'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -9,6 +8,7 @@ import { ApiAggregate } from '@/app/components/base/icons/src/vender/knowledge'
import SecretKeyModal from '@/app/components/develop/secret-key/secret-key-modal'
import Indicator from '@/app/components/header/indicator'
import { useDatasetApiAccessUrl } from '@/hooks/use-api-access-url'
+import Link from '@/next/link'
type CardProps = {
apiBaseUrl: string
diff --git a/web/app/components/datasets/list/new-dataset-card/option.tsx b/web/app/components/datasets/list/new-dataset-card/option.tsx
index e862b5c11e..05b14fef1a 100644
--- a/web/app/components/datasets/list/new-dataset-card/option.tsx
+++ b/web/app/components/datasets/list/new-dataset-card/option.tsx
@@ -1,5 +1,5 @@
-import Link from 'next/link'
import * as React from 'react'
+import Link from '@/next/link'
type OptionProps = {
Icon: React.ComponentType<{ className?: string }>
diff --git a/web/app/components/explore/sidebar/index.tsx b/web/app/components/explore/sidebar/index.tsx
index bafc745b01..d8d636285b 100644
--- a/web/app/components/explore/sidebar/index.tsx
+++ b/web/app/components/explore/sidebar/index.tsx
@@ -1,6 +1,5 @@
'use client'
import { useBoolean } from 'ahooks'
-import Link from 'next/link'
import { useSelectedLayoutSegments } from 'next/navigation'
import * as React from 'react'
import { useState } from 'react'
@@ -8,6 +7,7 @@ import { useTranslation } from 'react-i18next'
import Confirm from '@/app/components/base/confirm'
import Divider from '@/app/components/base/divider'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import Link from '@/next/link'
import { useGetInstalledApps, useUninstallApp, useUpdateAppPinStatus } from '@/service/use-explore'
import { cn } from '@/utils/classnames'
import Toast from '../../base/toast'
diff --git a/web/app/components/header/__tests__/index.spec.tsx b/web/app/components/header/__tests__/index.spec.tsx
index 93ab7fb535..16e0854339 100644
--- a/web/app/components/header/__tests__/index.spec.tsx
+++ b/web/app/components/header/__tests__/index.spec.tsx
@@ -52,7 +52,7 @@ vi.mock('@/context/workspace-context-provider', () => ({
WorkspaceProvider: ({ children }: { children?: React.ReactNode }) => children,
}))
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href }: { children?: React.ReactNode, href?: string }) => {children},
}))
diff --git a/web/app/components/header/account-about/index.tsx b/web/app/components/header/account-about/index.tsx
index b80cbb8f03..09ab89fc88 100644
--- a/web/app/components/header/account-about/index.tsx
+++ b/web/app/components/header/account-about/index.tsx
@@ -2,15 +2,15 @@
import type { LangGeniusVersionResponse } from '@/models/common'
import { RiCloseLine } from '@remixicon/react'
import dayjs from 'dayjs'
-import Link from 'next/link'
import { useTranslation } from 'react-i18next'
import Button from '@/app/components/base/button'
import DifyLogo from '@/app/components/base/logo/dify-logo'
import Modal from '@/app/components/base/modal'
import { IS_CE_EDITION } from '@/config'
-
import { useGlobalPublicStore } from '@/context/global-public-context'
+import Link from '@/next/link'
+
type IAccountSettingProps = {
langGeniusVersionInfo: LangGeniusVersionResponse
onCancel: () => void
diff --git a/web/app/components/header/account-dropdown/index.tsx b/web/app/components/header/account-dropdown/index.tsx
index 0a5779839e..7048ccbde0 100644
--- a/web/app/components/header/account-dropdown/index.tsx
+++ b/web/app/components/header/account-dropdown/index.tsx
@@ -1,7 +1,6 @@
'use client'
import type { MouseEventHandler, ReactNode } from 'react'
-import Link from 'next/link'
import { useRouter } from 'next/navigation'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -18,6 +17,7 @@ import { useDocLink } from '@/context/i18n'
import { useModalContext } from '@/context/modal-context'
import { useProviderContext } from '@/context/provider-context'
import { env } from '@/env'
+import Link from '@/next/link'
import { useLogout } from '@/service/use-common'
import { cn } from '@/utils/classnames'
import AccountAbout from '../account-about'
diff --git a/web/app/components/header/account-setting/Integrations-page/index.tsx b/web/app/components/header/account-setting/Integrations-page/index.tsx
index ef234b5db7..29d0d9fcd3 100644
--- a/web/app/components/header/account-setting/Integrations-page/index.tsx
+++ b/web/app/components/header/account-setting/Integrations-page/index.tsx
@@ -1,7 +1,7 @@
'use client'
-import Link from 'next/link'
import { useTranslation } from 'react-i18next'
+import Link from '@/next/link'
import { useAccountIntegrates } from '@/service/use-common'
import { cn } from '@/utils/classnames'
import s from './index.module.css'
diff --git a/web/app/components/header/account-setting/data-source-page-new/__tests__/install-from-marketplace.spec.tsx b/web/app/components/header/account-setting/data-source-page-new/__tests__/install-from-marketplace.spec.tsx
index daf9d3b988..a9d81a12e0 100644
--- a/web/app/components/header/account-setting/data-source-page-new/__tests__/install-from-marketplace.spec.tsx
+++ b/web/app/components/header/account-setting/data-source-page-new/__tests__/install-from-marketplace.spec.tsx
@@ -16,7 +16,7 @@ vi.mock('next-themes', () => ({
useTheme: vi.fn(),
}))
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href }: { children: React.ReactNode, href: string }) => (
{children}
),
diff --git a/web/app/components/header/account-setting/data-source-page-new/install-from-marketplace.tsx b/web/app/components/header/account-setting/data-source-page-new/install-from-marketplace.tsx
index f02e276f55..1a1ca19c3e 100644
--- a/web/app/components/header/account-setting/data-source-page-new/install-from-marketplace.tsx
+++ b/web/app/components/header/account-setting/data-source-page-new/install-from-marketplace.tsx
@@ -4,7 +4,6 @@ import {
RiArrowRightUpLine,
} from '@remixicon/react'
import { useTheme } from 'next-themes'
-import Link from 'next/link'
import {
memo,
useCallback,
@@ -15,6 +14,7 @@ import Divider from '@/app/components/base/divider'
import Loading from '@/app/components/base/loading'
import List from '@/app/components/plugins/marketplace/list'
import ProviderCard from '@/app/components/plugins/provider-card'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
import { getMarketplaceUrl } from '@/utils/var'
import {
diff --git a/web/app/components/header/account-setting/model-provider-page/__tests__/install-from-marketplace.spec.tsx b/web/app/components/header/account-setting/model-provider-page/__tests__/install-from-marketplace.spec.tsx
index 452068e61c..68a705e6c4 100644
--- a/web/app/components/header/account-setting/model-provider-page/__tests__/install-from-marketplace.spec.tsx
+++ b/web/app/components/header/account-setting/model-provider-page/__tests__/install-from-marketplace.spec.tsx
@@ -7,7 +7,7 @@ import { useMarketplaceAllPlugins } from '../hooks'
import InstallFromMarketplace from '../install-from-marketplace'
// Mock dependencies
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href }: { children: React.ReactNode, href: string }) => {children},
}))
diff --git a/web/app/components/header/account-setting/model-provider-page/install-from-marketplace.tsx b/web/app/components/header/account-setting/model-provider-page/install-from-marketplace.tsx
index ab712f27cc..289e8ce80e 100644
--- a/web/app/components/header/account-setting/model-provider-page/install-from-marketplace.tsx
+++ b/web/app/components/header/account-setting/model-provider-page/install-from-marketplace.tsx
@@ -3,13 +3,13 @@ import type {
} from './declarations'
import type { Plugin } from '@/app/components/plugins/types'
import { useTheme } from 'next-themes'
-import Link from 'next/link'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Divider from '@/app/components/base/divider'
import Loading from '@/app/components/base/loading'
import List from '@/app/components/plugins/marketplace/list'
import ProviderCard from '@/app/components/plugins/provider-card'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
import { getMarketplaceUrl } from '@/utils/var'
import {
diff --git a/web/app/components/header/account-setting/model-provider-page/model-parameter-modal/status-indicators.tsx b/web/app/components/header/account-setting/model-provider-page/model-parameter-modal/status-indicators.tsx
index e9780680e2..a6a93acbc2 100644
--- a/web/app/components/header/account-setting/model-provider-page/model-parameter-modal/status-indicators.tsx
+++ b/web/app/components/header/account-setting/model-provider-page/model-parameter-modal/status-indicators.tsx
@@ -1,7 +1,7 @@
import { RiErrorWarningFill } from '@remixicon/react'
-import Link from 'next/link'
import Tooltip from '@/app/components/base/tooltip'
import { SwitchPluginVersion } from '@/app/components/workflow/nodes/_base/components/switch-plugin-version'
+import Link from '@/next/link'
import { useInstalledPluginList } from '@/service/use-plugins'
type StatusIndicatorsProps = {
diff --git a/web/app/components/header/account-setting/plugin-page/index.tsx b/web/app/components/header/account-setting/plugin-page/index.tsx
index beda55f2f2..a71c3ee072 100644
--- a/web/app/components/header/account-setting/plugin-page/index.tsx
+++ b/web/app/components/header/account-setting/plugin-page/index.tsx
@@ -1,7 +1,7 @@
import type { PluginProvider } from '@/models/common'
import { LockClosedIcon } from '@heroicons/react/24/solid'
-import Link from 'next/link'
import { useTranslation } from 'react-i18next'
+import Link from '@/next/link'
import { usePluginProviders } from '@/service/use-common'
import SerpapiPlugin from './SerpapiPlugin'
diff --git a/web/app/components/header/explore-nav/index.tsx b/web/app/components/header/explore-nav/index.tsx
index 34deb61fe7..a6f9faf24e 100644
--- a/web/app/components/header/explore-nav/index.tsx
+++ b/web/app/components/header/explore-nav/index.tsx
@@ -4,9 +4,9 @@ import {
RiPlanetFill,
RiPlanetLine,
} from '@remixicon/react'
-import Link from 'next/link'
import { useSelectedLayoutSegment } from 'next/navigation'
import { useTranslation } from 'react-i18next'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
type ExploreNavProps = {
diff --git a/web/app/components/header/index.tsx b/web/app/components/header/index.tsx
index 0b86a6259b..cc4dd9bb61 100644
--- a/web/app/components/header/index.tsx
+++ b/web/app/components/header/index.tsx
@@ -1,5 +1,4 @@
'use client'
-import Link from 'next/link'
import { useCallback } from 'react'
import DifyLogo from '@/app/components/base/logo/dify-logo'
import WorkplaceSelector from '@/app/components/header/account-dropdown/workplace-selector'
@@ -10,6 +9,7 @@ import { useModalContext } from '@/context/modal-context'
import { useProviderContext } from '@/context/provider-context'
import { WorkspaceProvider } from '@/context/workspace-context-provider'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import Link from '@/next/link'
import { Plan } from '../billing/type'
import AccountDropdown from './account-dropdown'
import AppNav from './app-nav'
diff --git a/web/app/components/header/nav/index.tsx b/web/app/components/header/nav/index.tsx
index ca4498e4fb..5d86a77d04 100644
--- a/web/app/components/header/nav/index.tsx
+++ b/web/app/components/header/nav/index.tsx
@@ -1,12 +1,12 @@
'use client'
import type { INavSelectorProps } from './nav-selector'
-import Link from 'next/link'
import { useSelectedLayoutSegment } from 'next/navigation'
import * as React from 'react'
import { useState } from 'react'
import { useStore as useAppStore } from '@/app/components/app/store'
import { ArrowNarrowLeft } from '@/app/components/base/icons/src/vender/line/arrows'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
import NavSelector from './nav-selector'
diff --git a/web/app/components/header/plugins-nav/index.tsx b/web/app/components/header/plugins-nav/index.tsx
index d806416b3b..5501048915 100644
--- a/web/app/components/header/plugins-nav/index.tsx
+++ b/web/app/components/header/plugins-nav/index.tsx
@@ -1,11 +1,11 @@
'use client'
-import Link from 'next/link'
import { useSelectedLayoutSegment } from 'next/navigation'
import { useTranslation } from 'react-i18next'
import { Group } from '@/app/components/base/icons/src/vender/other'
import Indicator from '@/app/components/header/indicator'
import { usePluginTaskStatus } from '@/app/components/plugins/plugin-page/plugin-tasks/hooks'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
import DownloadingIcon from './downloading-icon'
diff --git a/web/app/components/header/tools-nav/index.tsx b/web/app/components/header/tools-nav/index.tsx
index c8f318a742..d7abaa4680 100644
--- a/web/app/components/header/tools-nav/index.tsx
+++ b/web/app/components/header/tools-nav/index.tsx
@@ -4,9 +4,9 @@ import {
RiHammerFill,
RiHammerLine,
} from '@remixicon/react'
-import Link from 'next/link'
import { useSelectedLayoutSegment } from 'next/navigation'
import { useTranslation } from 'react-i18next'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
type ToolsNavProps = {
diff --git a/web/app/components/plugins/base/__tests__/deprecation-notice.spec.tsx b/web/app/components/plugins/base/__tests__/deprecation-notice.spec.tsx
index 42616f3138..6b10e4c1f3 100644
--- a/web/app/components/plugins/base/__tests__/deprecation-notice.spec.tsx
+++ b/web/app/components/plugins/base/__tests__/deprecation-notice.spec.tsx
@@ -2,7 +2,7 @@ import { cleanup, render, screen } from '@testing-library/react'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import DeprecationNotice from '../deprecation-notice'
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href }: { children: React.ReactNode, href: string }) => (
{children}
),
diff --git a/web/app/components/plugins/base/deprecation-notice.tsx b/web/app/components/plugins/base/deprecation-notice.tsx
index 01b37bc20c..647c98c36c 100644
--- a/web/app/components/plugins/base/deprecation-notice.tsx
+++ b/web/app/components/plugins/base/deprecation-notice.tsx
@@ -2,10 +2,10 @@ import type { FC } from 'react'
import { useTranslation } from '#i18n'
import { RiAlertFill } from '@remixicon/react'
import { camelCase } from 'es-toolkit/string'
-import Link from 'next/link'
import * as React from 'react'
import { useMemo } from 'react'
import { Trans } from 'react-i18next'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
type DeprecationNoticeProps = {
diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx b/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx
index b1664eee97..633f566f79 100644
--- a/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx
@@ -7,7 +7,6 @@ import type { FC } from 'react'
import type { Node } from 'reactflow'
import type { ToolValue } from '@/app/components/workflow/block-selector/types'
import type { NodeOutPutVar } from '@/app/components/workflow/types'
-import Link from 'next/link'
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import {
@@ -16,6 +15,7 @@ import {
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import { CollectionType } from '@/app/components/tools/types'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
import {
ToolAuthorizationSection,
diff --git a/web/app/components/plugins/plugin-page/index.tsx b/web/app/components/plugins/plugin-page/index.tsx
index 6768361acf..78d590f409 100644
--- a/web/app/components/plugins/plugin-page/index.tsx
+++ b/web/app/components/plugins/plugin-page/index.tsx
@@ -9,7 +9,6 @@ import {
} from '@remixicon/react'
import { useBoolean } from 'ahooks'
import { noop } from 'es-toolkit/function'
-import Link from 'next/link'
import { useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Button from '@/app/components/base/button'
@@ -21,6 +20,7 @@ import { useGlobalPublicStore } from '@/context/global-public-context'
import { useDocLink } from '@/context/i18n'
import useDocumentTitle from '@/hooks/use-document-title'
import { usePluginInstallation } from '@/hooks/use-query-params'
+import Link from '@/next/link'
import { fetchBundleInfoFromMarketPlace, fetchManifestFromMarketPlace } from '@/service/plugins'
import { sleep } from '@/utils'
import { cn } from '@/utils/classnames'
diff --git a/web/app/components/rag-pipeline/components/rag-pipeline-header/__tests__/index.spec.tsx b/web/app/components/rag-pipeline/components/rag-pipeline-header/__tests__/index.spec.tsx
index 00c989acb0..e1e6c2f7d5 100644
--- a/web/app/components/rag-pipeline/components/rag-pipeline-header/__tests__/index.spec.tsx
+++ b/web/app/components/rag-pipeline/components/rag-pipeline-header/__tests__/index.spec.tsx
@@ -82,7 +82,7 @@ vi.mock('next/navigation', () => ({
useRouter: () => ({ push: mockPush }),
}))
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href, ...props }: PropsWithChildren<{ href: string }>) => (
{children}
),
diff --git a/web/app/components/rag-pipeline/components/rag-pipeline-header/publisher/__tests__/index.spec.tsx b/web/app/components/rag-pipeline/components/rag-pipeline-header/publisher/__tests__/index.spec.tsx
index 9cd1af2736..345f3626ec 100644
--- a/web/app/components/rag-pipeline/components/rag-pipeline-header/publisher/__tests__/index.spec.tsx
+++ b/web/app/components/rag-pipeline/components/rag-pipeline-header/publisher/__tests__/index.spec.tsx
@@ -13,7 +13,7 @@ vi.mock('next/navigation', () => ({
useRouter: () => ({ push: mockPush }),
}))
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href, ...props }: { children: React.ReactNode, href: string }) => (
{children}
),
diff --git a/web/app/components/rag-pipeline/components/rag-pipeline-header/publisher/__tests__/popup.spec.tsx b/web/app/components/rag-pipeline/components/rag-pipeline-header/publisher/__tests__/popup.spec.tsx
index 48282820d8..a0baac7785 100644
--- a/web/app/components/rag-pipeline/components/rag-pipeline-header/publisher/__tests__/popup.spec.tsx
+++ b/web/app/components/rag-pipeline/components/rag-pipeline-header/publisher/__tests__/popup.spec.tsx
@@ -24,7 +24,7 @@ vi.mock('next/navigation', () => ({
useRouter: () => ({ push: mockPush }),
}))
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href }: { children: React.ReactNode, href: string }) => (
{children}
),
diff --git a/web/app/components/rag-pipeline/components/rag-pipeline-header/publisher/popup.tsx b/web/app/components/rag-pipeline/components/rag-pipeline-header/publisher/popup.tsx
index c084a5d45d..6d292de6a0 100644
--- a/web/app/components/rag-pipeline/components/rag-pipeline-header/publisher/popup.tsx
+++ b/web/app/components/rag-pipeline/components/rag-pipeline-header/publisher/popup.tsx
@@ -10,7 +10,6 @@ import {
useBoolean,
useKeyPress,
} from 'ahooks'
-import Link from 'next/link'
import { useParams, useRouter } from 'next/navigation'
import {
memo,
@@ -40,6 +39,7 @@ import { useModalContextSelector } from '@/context/modal-context'
import { useProviderContextSelector } from '@/context/provider-context'
import { useDatasetApiAccessUrl } from '@/hooks/use-api-access-url'
import { useFormatTimeFromNow } from '@/hooks/use-format-time-from-now'
+import Link from '@/next/link'
import { useInvalidDatasetList } from '@/service/knowledge/use-dataset'
import { useInvalid } from '@/service/use-base'
import {
diff --git a/web/app/components/tools/provider/empty.tsx b/web/app/components/tools/provider/empty.tsx
index 3b9748dc27..725b171deb 100644
--- a/web/app/components/tools/provider/empty.tsx
+++ b/web/app/components/tools/provider/empty.tsx
@@ -1,8 +1,8 @@
'use client'
import { RiArrowRightUpLine } from '@remixicon/react'
-import Link from 'next/link'
import { useTranslation } from 'react-i18next'
import useTheme from '@/hooks/use-theme'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
import { NoToolPlaceholder } from '../../base/icons/src/vender/other'
import { ToolTypeEnum } from '../../workflow/block-selector/types'
diff --git a/web/app/components/workflow/block-selector/all-start-blocks.tsx b/web/app/components/workflow/block-selector/all-start-blocks.tsx
index d122faecf6..05bded8bee 100644
--- a/web/app/components/workflow/block-selector/all-start-blocks.tsx
+++ b/web/app/components/workflow/block-selector/all-start-blocks.tsx
@@ -6,7 +6,6 @@ import type { BlockEnum, OnSelectBlock } from '../types'
import type { ListRef } from './market-place-plugin/list'
import type { TriggerDefaultValue, TriggerWithProvider } from './types'
import { RiArrowRightUpLine } from '@remixicon/react'
-import Link from 'next/link'
import {
useCallback,
useEffect,
@@ -19,6 +18,7 @@ import Button from '@/app/components/base/button'
import Divider from '@/app/components/base/divider'
import { SearchMenu } from '@/app/components/base/icons/src/vender/line/general'
import { useGlobalPublicStore } from '@/context/global-public-context'
+import Link from '@/next/link'
import { useFeaturedTriggersRecommendations } from '@/service/use-plugins'
import { useAllTriggerPlugins, useInvalidateAllTriggerPlugins } from '@/service/use-triggers'
import { cn } from '@/utils/classnames'
diff --git a/web/app/components/workflow/block-selector/all-tools.tsx b/web/app/components/workflow/block-selector/all-tools.tsx
index bde5390cd7..da74305e5f 100644
--- a/web/app/components/workflow/block-selector/all-tools.tsx
+++ b/web/app/components/workflow/block-selector/all-tools.tsx
@@ -12,7 +12,6 @@ import type { ToolDefaultValue, ToolValue } from './types'
import type { ListProps, ListRef } from '@/app/components/workflow/block-selector/market-place-plugin/list'
import type { OnSelectBlock } from '@/app/components/workflow/types'
import { RiArrowRightUpLine } from '@remixicon/react'
-import Link from 'next/link'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Button from '@/app/components/base/button'
@@ -21,6 +20,7 @@ import { SearchMenu } from '@/app/components/base/icons/src/vender/line/general'
import PluginList from '@/app/components/workflow/block-selector/market-place-plugin/list'
import { useGlobalPublicStore } from '@/context/global-public-context'
import { useGetLanguage } from '@/context/i18n'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
import { getMarketplaceUrl } from '@/utils/var'
import { useMarketplacePlugins } from '../../plugins/marketplace/hooks'
diff --git a/web/app/components/workflow/block-selector/featured-tools.tsx b/web/app/components/workflow/block-selector/featured-tools.tsx
index 4e66f08222..965cf97cd0 100644
--- a/web/app/components/workflow/block-selector/featured-tools.tsx
+++ b/web/app/components/workflow/block-selector/featured-tools.tsx
@@ -4,7 +4,6 @@ import type { ToolDefaultValue, ToolValue } from './types'
import type { Plugin } from '@/app/components/plugins/types'
import type { Locale } from '@/i18n-config'
import { RiMoreLine } from '@remixicon/react'
-import Link from 'next/link'
import { useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ArrowDownDoubleLine, ArrowDownRoundFill, ArrowUpDoubleLine } from '@/app/components/base/icons/src/vender/solid/arrows'
@@ -13,6 +12,7 @@ import Tooltip from '@/app/components/base/tooltip'
import InstallFromMarketplace from '@/app/components/plugins/install-plugin/install-from-marketplace'
import Action from '@/app/components/workflow/block-selector/market-place-plugin/action'
import { useGetLanguage } from '@/context/i18n'
+import Link from '@/next/link'
import { isServer } from '@/utils/client'
import { formatNumber } from '@/utils/format'
import { getMarketplaceUrl } from '@/utils/var'
diff --git a/web/app/components/workflow/block-selector/featured-triggers.tsx b/web/app/components/workflow/block-selector/featured-triggers.tsx
index 01cb5d100f..81715c2922 100644
--- a/web/app/components/workflow/block-selector/featured-triggers.tsx
+++ b/web/app/components/workflow/block-selector/featured-triggers.tsx
@@ -3,7 +3,6 @@ import type { TriggerDefaultValue, TriggerWithProvider } from './types'
import type { Plugin } from '@/app/components/plugins/types'
import type { Locale } from '@/i18n-config'
import { RiMoreLine } from '@remixicon/react'
-import Link from 'next/link'
import { useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ArrowDownDoubleLine, ArrowDownRoundFill, ArrowUpDoubleLine } from '@/app/components/base/icons/src/vender/solid/arrows'
@@ -12,6 +11,7 @@ import Tooltip from '@/app/components/base/tooltip'
import InstallFromMarketplace from '@/app/components/plugins/install-plugin/install-from-marketplace'
import Action from '@/app/components/workflow/block-selector/market-place-plugin/action'
import { useGetLanguage } from '@/context/i18n'
+import Link from '@/next/link'
import { isServer } from '@/utils/client'
import { formatNumber } from '@/utils/format'
import { getMarketplaceUrl } from '@/utils/var'
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 29f1e77e14..b5285758fd 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
@@ -3,9 +3,9 @@ import type { RefObject } from 'react'
import type { Plugin, PluginCategoryEnum } from '@/app/components/plugins/types'
import { RiArrowRightUpLine, RiSearchLine } from '@remixicon/react'
import { noop } from 'es-toolkit/function'
-import Link from 'next/link'
import { useEffect, useImperativeHandle, useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next'
+import Link from '@/next/link'
import { cn } from '@/utils/classnames'
import { getMarketplaceUrl } from '@/utils/var'
import useStickyScroll, { ScrollPosition } from '../use-sticky-scroll'
diff --git a/web/app/components/workflow/block-selector/rag-tool-recommendations/index.tsx b/web/app/components/workflow/block-selector/rag-tool-recommendations/index.tsx
index e934f27fd1..77acd5b300 100644
--- a/web/app/components/workflow/block-selector/rag-tool-recommendations/index.tsx
+++ b/web/app/components/workflow/block-selector/rag-tool-recommendations/index.tsx
@@ -3,13 +3,13 @@ import type { Dispatch, SetStateAction } from 'react'
import type { ViewType } from '@/app/components/workflow/block-selector/view-type-select'
import type { OnSelectBlock } from '@/app/components/workflow/types'
import { RiMoreLine } from '@remixicon/react'
-import Link from 'next/link'
import * as React from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { Trans, useTranslation } from 'react-i18next'
import { ArrowDownRoundFill } from '@/app/components/base/icons/src/vender/solid/arrows'
import Loading from '@/app/components/base/loading'
import { getFormattedPlugin } from '@/app/components/plugins/marketplace/utils'
+import Link from '@/next/link'
import { useRAGRecommendedPlugins } from '@/service/use-tools'
import { isServer } from '@/utils/client'
import { getMarketplaceUrl } from '@/utils/var'
diff --git a/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx b/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx
index 4635a5575c..f872fefe19 100644
--- a/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx
+++ b/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx
@@ -4,7 +4,6 @@ import type { Strategy } from './agent-strategy'
import type { StrategyPluginDetail } from '@/app/components/plugins/types'
import type { ListProps, ListRef } from '@/app/components/workflow/block-selector/market-place-plugin/list'
import { RiArrowDownSLine, RiErrorWarningFill } from '@remixicon/react'
-import Link from 'next/link'
import { memo, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
@@ -17,6 +16,7 @@ import { PluginCategoryEnum } from '@/app/components/plugins/types'
import { CollectionType } from '@/app/components/tools/types'
import PluginList from '@/app/components/workflow/block-selector/market-place-plugin/list'
import { useGlobalPublicStore } from '@/context/global-public-context'
+import Link from '@/next/link'
import { useStrategyProviders } from '@/service/use-strategy'
import { cn } from '@/utils/classnames'
import Tools from '../../../block-selector/tools'
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 ba30053b77..70c480892b 100644
--- a/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx
+++ b/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx
@@ -5,7 +5,6 @@ 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 'es-toolkit/function'
-import Link from 'next/link'
import { memo } from 'react'
import { useTranslation } from 'react-i18next'
import { Agent } from '@/app/components/base/icons/src/vender/workflow'
@@ -26,6 +25,7 @@ import MultipleToolSelector from '@/app/components/plugins/plugin-detail-panel/m
import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector'
import { useDocLink } from '@/context/i18n'
import { useRenderI18nObject } from '@/hooks/use-i18n'
+import Link from '@/next/link'
import { AppModeEnum } from '@/types/app'
import { useWorkflowStore } from '../../../store'
import { AgentStrategySelector } from './agent-strategy-selector'
diff --git a/web/app/components/workflow/nodes/_base/components/switch-plugin-version.tsx b/web/app/components/workflow/nodes/_base/components/switch-plugin-version.tsx
index eb32c0595f..b3e398f86d 100644
--- a/web/app/components/workflow/nodes/_base/components/switch-plugin-version.tsx
+++ b/web/app/components/workflow/nodes/_base/components/switch-plugin-version.tsx
@@ -3,7 +3,6 @@
import type { FC, ReactNode } from 'react'
import { RiArrowLeftRightLine, RiExternalLinkLine } from '@remixicon/react'
import { useBoolean } from 'ahooks'
-import Link from 'next/link'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Badge from '@/app/components/base/badge'
@@ -13,6 +12,7 @@ import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-ico
import { pluginManifestToCardPluginProps } from '@/app/components/plugins/install-plugin/utils'
import PluginMutationModel from '@/app/components/plugins/plugin-mutation-model'
import PluginVersionPicker from '@/app/components/plugins/update-plugin/plugin-version-picker'
+import Link from '@/next/link'
import { useCheckInstalled, useUpdatePackageFromMarketPlace } from '@/service/use-plugins'
import { cn } from '@/utils/classnames'
import { getMarketplaceUrl } from '@/utils/var'
diff --git a/web/app/education-apply/expire-notice-modal.tsx b/web/app/education-apply/expire-notice-modal.tsx
index 2b96ecba88..c44ee0f386 100644
--- a/web/app/education-apply/expire-notice-modal.tsx
+++ b/web/app/education-apply/expire-notice-modal.tsx
@@ -1,6 +1,5 @@
'use client'
import { RiExternalLinkLine } from '@remixicon/react'
-import Link from 'next/link'
import { useRouter } from 'next/navigation'
import * as React from 'react'
import { useTranslation } from 'react-i18next'
@@ -9,6 +8,7 @@ import Modal from '@/app/components/base/modal'
import { useDocLink } from '@/context/i18n'
import { useModalContextSelector } from '@/context/modal-context'
import useTimestamp from '@/hooks/use-timestamp'
+import Link from '@/next/link'
import { useEducationVerify } from '@/service/use-education'
import { SparklesSoftAccent } from '../components/base/icons/src/public/common'
diff --git a/web/app/install/installForm.tsx b/web/app/install/installForm.tsx
index 47de6d1fb3..28c9f0e702 100644
--- a/web/app/install/installForm.tsx
+++ b/web/app/install/installForm.tsx
@@ -1,9 +1,8 @@
'use client'
import type { InitValidateStatusResponse, SetupStatusResponse } from '@/models/common'
import { useStore } from '@tanstack/react-form'
-import Link from 'next/link'
-
import { useRouter } from 'next/navigation'
+
import * as React from 'react'
import { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
@@ -13,9 +12,10 @@ import { formContext, useAppForm } from '@/app/components/base/form'
import { zodSubmitValidator } from '@/app/components/base/form/utils/zod-submit-validator'
import Input from '@/app/components/base/input'
import { validPassword } from '@/config'
-
import { LICENSE_LINK } from '@/constants/link'
+
import useDocumentTitle from '@/hooks/use-document-title'
+import Link from '@/next/link'
import { fetchInitValidateStatus, fetchSetupStatus, login, setup } from '@/service/common'
import { cn } from '@/utils/classnames'
import { encryptPassword as encodePassword } from '@/utils/encryption'
diff --git a/web/app/page.tsx b/web/app/page.tsx
index 117d6c838d..65f8827e01 100644
--- a/web/app/page.tsx
+++ b/web/app/page.tsx
@@ -1,5 +1,5 @@
-import Link from 'next/link'
import Loading from '@/app/components/base/loading'
+import Link from '@/next/link'
const Home = async () => {
return (
diff --git a/web/app/reset-password/page.tsx b/web/app/reset-password/page.tsx
index 9fdccdfd87..6fb399b8de 100644
--- a/web/app/reset-password/page.tsx
+++ b/web/app/reset-password/page.tsx
@@ -1,7 +1,6 @@
'use client'
import { RiArrowLeftLine, RiLockPasswordLine } from '@remixicon/react'
import { noop } from 'es-toolkit/function'
-import Link from 'next/link'
import { useRouter, useSearchParams } from 'next/navigation'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -11,6 +10,7 @@ import Toast from '@/app/components/base/toast'
import { emailRegex } from '@/config'
import { useLocale } from '@/context/i18n'
import useDocumentTitle from '@/hooks/use-document-title'
+import Link from '@/next/link'
import { sendResetPasswordCode } from '@/service/common'
import { COUNT_DOWN_KEY, COUNT_DOWN_TIME_MS } from '../components/signin/countdown'
diff --git a/web/app/signin/components/mail-and-password-auth.tsx b/web/app/signin/components/mail-and-password-auth.tsx
index 877720b691..0ec7cd8a29 100644
--- a/web/app/signin/components/mail-and-password-auth.tsx
+++ b/web/app/signin/components/mail-and-password-auth.tsx
@@ -1,6 +1,5 @@
import type { ResponseError } from '@/service/fetch'
import { noop } from 'es-toolkit/function'
-import Link from 'next/link'
import { useRouter, useSearchParams } from 'next/navigation'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -10,6 +9,7 @@ import Input from '@/app/components/base/input'
import Toast from '@/app/components/base/toast'
import { emailRegex } from '@/config'
import { useLocale } from '@/context/i18n'
+import Link from '@/next/link'
import { login } from '@/service/common'
import { setWebAppAccessToken } from '@/service/webapp-auth'
import { encryptPassword } from '@/utils/encryption'
diff --git a/web/app/signin/invite-settings/page.tsx b/web/app/signin/invite-settings/page.tsx
index 915e85ce57..a8d43d74c4 100644
--- a/web/app/signin/invite-settings/page.tsx
+++ b/web/app/signin/invite-settings/page.tsx
@@ -2,7 +2,6 @@
import type { Locale } from '@/i18n-config'
import { RiAccountCircleLine } from '@remixicon/react'
import { noop } from 'es-toolkit/function'
-import Link from 'next/link'
import { useRouter, useSearchParams } from 'next/navigation'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -15,6 +14,7 @@ import { LICENSE_LINK } from '@/constants/link'
import { useGlobalPublicStore } from '@/context/global-public-context'
import { setLocaleOnClient } from '@/i18n-config'
import { languages, LanguagesSupported } from '@/i18n-config/language'
+import Link from '@/next/link'
import { activateMember } from '@/service/common'
import { useInvitationCheck } from '@/service/use-common'
import { timezones } from '@/utils/timezone'
diff --git a/web/app/signin/normal-form.tsx b/web/app/signin/normal-form.tsx
index 15d86f482c..314da7616f 100644
--- a/web/app/signin/normal-form.tsx
+++ b/web/app/signin/normal-form.tsx
@@ -1,5 +1,4 @@
import { RiContractLine, RiDoorLockLine, RiErrorWarningFill } from '@remixicon/react'
-import Link from 'next/link'
import { useRouter, useSearchParams } from 'next/navigation'
import * as React from 'react'
import { useCallback, useEffect, useState } from 'react'
@@ -7,6 +6,7 @@ import { useTranslation } from 'react-i18next'
import Toast from '@/app/components/base/toast'
import { IS_CE_EDITION } from '@/config'
import { useGlobalPublicStore } from '@/context/global-public-context'
+import Link from '@/next/link'
import { invitationCheck } from '@/service/common'
import { useIsLogin } from '@/service/use-common'
import { LicenseStatus } from '@/types/feature'
diff --git a/web/app/signin/one-more-step.tsx b/web/app/signin/one-more-step.tsx
index ff28b3caaf..099f5d9c0b 100644
--- a/web/app/signin/one-more-step.tsx
+++ b/web/app/signin/one-more-step.tsx
@@ -1,6 +1,5 @@
'use client'
import type { Reducer } from 'react'
-import Link from 'next/link'
import { useRouter, useSearchParams } from 'next/navigation'
import { useReducer } from 'react'
import { useTranslation } from 'react-i18next'
@@ -10,6 +9,7 @@ import Toast from '@/app/components/base/toast'
import Tooltip from '@/app/components/base/tooltip'
import { LICENSE_LINK } from '@/constants/link'
import { languages, LanguagesSupported } from '@/i18n-config/language'
+import Link from '@/next/link'
import { useOneMoreStep } from '@/service/use-common'
import { timezones } from '@/utils/timezone'
import Input from '../components/base/input'
diff --git a/web/app/signup/components/input-mail.spec.tsx b/web/app/signup/components/input-mail.spec.tsx
index d5acc92153..e16c381585 100644
--- a/web/app/signup/components/input-mail.spec.tsx
+++ b/web/app/signup/components/input-mail.spec.tsx
@@ -24,7 +24,7 @@ const buildSystemFeatures = (overrides: SystemFeaturesOverrides = {}): SystemFea
},
})
-vi.mock('next/link', () => ({
+vi.mock('@/next/link', () => ({
default: ({ children, href, className, target, rel }: { children: React.ReactNode, href: string, className?: string, target?: string, rel?: string }) => (
{children}
diff --git a/web/app/signup/components/input-mail.tsx b/web/app/signup/components/input-mail.tsx
index 1b88007ce4..d6c4b95ce3 100644
--- a/web/app/signup/components/input-mail.tsx
+++ b/web/app/signup/components/input-mail.tsx
@@ -1,6 +1,5 @@
'use client'
import type { MailSendResponse } from '@/service/use-common'
-import Link from 'next/link'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Button from '@/app/components/base/button'
@@ -10,6 +9,7 @@ import Split from '@/app/signin/split'
import { emailRegex } from '@/config'
import { useGlobalPublicStore } from '@/context/global-public-context'
import { useLocale } from '@/context/i18n'
+import Link from '@/next/link'
import { useSendMail } from '@/service/use-common'
type Props = {
diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs
index 4599778eee..778e81866b 100644
--- a/web/eslint.config.mjs
+++ b/web/eslint.config.mjs
@@ -46,6 +46,10 @@ const NEXT_PLATFORM_RESTRICTED_IMPORT_PATTERNS = [
group: ['next/server'],
message: 'Import Next APIs from @/next/server instead of next/server.',
},
+ {
+ group: ['next/link'],
+ message: 'Import Next APIs from @/next/link instead of next/link.',
+ },
]
const OVERLAY_RESTRICTED_IMPORT_PATTERNS = [
diff --git a/web/next/link.ts b/web/next/link.ts
new file mode 100644
index 0000000000..c99bd22206
--- /dev/null
+++ b/web/next/link.ts
@@ -0,0 +1 @@
+export { default } from 'next/link'