From 7c6d0bedc0c6f235775744c6fa4c76d0a3a3168f Mon Sep 17 00:00:00 2001
From: yyh <92089059+lyzno1@users.noreply.github.com>
Date: Tue, 17 Mar 2026 18:56:36 +0800
Subject: [PATCH] feat(web): add base ui toast (#33569)
---
.../base/toast/__tests__/index.spec.tsx | 1 +
web/app/components/base/toast/index.tsx | 3 +-
web/app/components/base/ui/dialog/index.tsx | 2 +-
.../base/ui/toast/__tests__/index.spec.tsx | 313 ++++++++
.../base/ui/toast/index.stories.tsx | 332 ++++++++
web/app/components/base/ui/toast/index.tsx | 202 +++++
.../workflow/panel/workflow-preview.tsx | 4 +-
web/app/layout.tsx | 2 +
web/docs/overlay-migration.md | 20 +-
web/eslint-suppressions.json | 755 +++++++++++++++---
web/eslint.config.mjs | 9 +
web/i18n/en-US/common.json | 2 +
12 files changed, 1547 insertions(+), 98 deletions(-)
create mode 100644 web/app/components/base/ui/toast/__tests__/index.spec.tsx
create mode 100644 web/app/components/base/ui/toast/index.stories.tsx
create mode 100644 web/app/components/base/ui/toast/index.tsx
diff --git a/web/app/components/base/toast/__tests__/index.spec.tsx b/web/app/components/base/toast/__tests__/index.spec.tsx
index 0cf25a72e7..8e60ebf827 100644
--- a/web/app/components/base/toast/__tests__/index.spec.tsx
+++ b/web/app/components/base/toast/__tests__/index.spec.tsx
@@ -55,6 +55,7 @@ describe('Toast', () => {
)
const successToast = getToastElementByMessage('Success message')
+ expect(successToast).toHaveClass('z-[1101]')
const successIcon = within(successToast).getByTestId('toast-icon-success')
expect(successIcon).toHaveClass('text-text-success')
diff --git a/web/app/components/base/toast/index.tsx b/web/app/components/base/toast/index.tsx
index c66be8da15..897b6039ba 100644
--- a/web/app/components/base/toast/index.tsx
+++ b/web/app/components/base/toast/index.tsx
@@ -28,7 +28,8 @@ const Toast = ({
return (
{
+ beforeEach(() => {
+ vi.clearAllMocks()
+ vi.useFakeTimers({ shouldAdvanceTime: true })
+ act(() => {
+ toast.close()
+ })
+ })
+
+ afterEach(() => {
+ act(() => {
+ toast.close()
+ vi.runOnlyPendingTimers()
+ })
+ vi.useRealTimers()
+ })
+
+ // Core host and manager integration.
+ it('should render a toast when add is called', async () => {
+ render(
)
+
+ act(() => {
+ toast.add({
+ title: 'Saved',
+ description: 'Your changes are available now.',
+ type: 'success',
+ })
+ })
+
+ expect(await screen.findByText('Saved')).toBeInTheDocument()
+ expect(screen.getByText('Your changes are available now.')).toBeInTheDocument()
+ const viewport = screen.getByRole('region', { name: 'common.toast.notifications' })
+ expect(viewport).toHaveAttribute('aria-live', 'polite')
+ expect(viewport).toHaveClass('z-[1101]')
+ expect(viewport.firstElementChild).toHaveClass('top-4')
+ expect(document.body.querySelector('[aria-hidden="true"].i-ri-checkbox-circle-fill')).toBeInTheDocument()
+ expect(document.body.querySelector('button[aria-label="common.toast.close"][aria-hidden="true"]')).toBeInTheDocument()
+ })
+
+ // Collapsed stacks should keep multiple toast roots mounted for smooth stack animation.
+ it('should keep multiple toast roots mounted in a collapsed stack', async () => {
+ render(
)
+
+ act(() => {
+ toast.add({
+ title: 'First toast',
+ })
+ })
+
+ expect(await screen.findByText('First toast')).toBeInTheDocument()
+
+ act(() => {
+ toast.add({
+ title: 'Second toast',
+ })
+ toast.add({
+ title: 'Third toast',
+ })
+ })
+
+ expect(await screen.findByText('Third toast')).toBeInTheDocument()
+ expect(screen.getAllByRole('dialog')).toHaveLength(3)
+ expect(document.body.querySelectorAll('button[aria-label="common.toast.close"][aria-hidden="true"]')).toHaveLength(3)
+
+ fireEvent.mouseEnter(screen.getByRole('region', { name: 'common.toast.notifications' }))
+
+ await waitFor(() => {
+ expect(document.body.querySelector('button[aria-label="common.toast.close"][aria-hidden="true"]')).not.toBeInTheDocument()
+ })
+ })
+
+ // Base UI limit should cap the visible stack and mark overflow toasts as limited.
+ it('should mark overflow toasts as limited when the stack exceeds the configured limit', async () => {
+ render(
)
+
+ act(() => {
+ toast.add({ title: 'First toast' })
+ toast.add({ title: 'Second toast' })
+ })
+
+ expect(await screen.findByText('Second toast')).toBeInTheDocument()
+ expect(document.body.querySelector('[data-limited]')).toBeInTheDocument()
+ })
+
+ // Closing should work through the public manager API.
+ it('should close a toast when close(id) is called', async () => {
+ render(
)
+
+ let toastId = ''
+ act(() => {
+ toastId = toast.add({
+ title: 'Closable',
+ description: 'This toast can be removed.',
+ })
+ })
+
+ expect(await screen.findByText('Closable')).toBeInTheDocument()
+
+ act(() => {
+ toast.close(toastId)
+ })
+
+ await waitFor(() => {
+ expect(screen.queryByText('Closable')).not.toBeInTheDocument()
+ })
+ })
+
+ // User dismissal needs to remain accessible.
+ it('should close a toast when the dismiss button is clicked', async () => {
+ const onClose = vi.fn()
+
+ render(
)
+
+ act(() => {
+ toast.add({
+ title: 'Dismiss me',
+ description: 'Manual dismissal path.',
+ onClose,
+ })
+ })
+
+ fireEvent.mouseEnter(screen.getByRole('region', { name: 'common.toast.notifications' }))
+
+ const dismissButton = await screen.findByRole('button', { name: 'common.toast.close' })
+
+ act(() => {
+ dismissButton.click()
+ })
+
+ await waitFor(() => {
+ expect(screen.queryByText('Dismiss me')).not.toBeInTheDocument()
+ })
+ expect(onClose).toHaveBeenCalledTimes(1)
+ })
+
+ // Base UI default timeout should apply when no timeout is provided.
+ it('should auto dismiss toasts with the Base UI default timeout', async () => {
+ render(
)
+
+ act(() => {
+ toast.add({
+ title: 'Default timeout',
+ })
+ })
+
+ expect(await screen.findByText('Default timeout')).toBeInTheDocument()
+
+ act(() => {
+ vi.advanceTimersByTime(4999)
+ })
+
+ expect(screen.getByText('Default timeout')).toBeInTheDocument()
+
+ act(() => {
+ vi.advanceTimersByTime(1)
+ })
+
+ await waitFor(() => {
+ expect(screen.queryByText('Default timeout')).not.toBeInTheDocument()
+ })
+ })
+
+ // Provider timeout should apply to all toasts when configured.
+ it('should respect the host timeout configuration', async () => {
+ render(
)
+
+ act(() => {
+ toast.add({
+ title: 'Configured timeout',
+ })
+ })
+
+ expect(await screen.findByText('Configured timeout')).toBeInTheDocument()
+
+ act(() => {
+ vi.advanceTimersByTime(2999)
+ })
+
+ expect(screen.getByText('Configured timeout')).toBeInTheDocument()
+
+ act(() => {
+ vi.advanceTimersByTime(1)
+ })
+
+ await waitFor(() => {
+ expect(screen.queryByText('Configured timeout')).not.toBeInTheDocument()
+ })
+ })
+
+ // Callers must be able to override or disable timeout per toast.
+ it('should respect custom timeout values including zero', async () => {
+ render(
)
+
+ act(() => {
+ toast.add({
+ title: 'Custom timeout',
+ timeout: 1000,
+ })
+ })
+
+ expect(await screen.findByText('Custom timeout')).toBeInTheDocument()
+
+ act(() => {
+ vi.advanceTimersByTime(1000)
+ })
+
+ await waitFor(() => {
+ expect(screen.queryByText('Custom timeout')).not.toBeInTheDocument()
+ })
+
+ act(() => {
+ toast.add({
+ title: 'Persistent',
+ timeout: 0,
+ })
+ })
+
+ expect(await screen.findByText('Persistent')).toBeInTheDocument()
+
+ act(() => {
+ vi.advanceTimersByTime(10000)
+ })
+
+ expect(screen.getByText('Persistent')).toBeInTheDocument()
+ })
+
+ // Updates should flow through the same manager state.
+ it('should update an existing toast', async () => {
+ render(
)
+
+ let toastId = ''
+ act(() => {
+ toastId = toast.add({
+ title: 'Loading',
+ description: 'Preparing your data…',
+ type: 'info',
+ })
+ })
+
+ expect(await screen.findByText('Loading')).toBeInTheDocument()
+
+ act(() => {
+ toast.update(toastId, {
+ title: 'Done',
+ description: 'Your data is ready.',
+ type: 'success',
+ })
+ })
+
+ expect(screen.getByText('Done')).toBeInTheDocument()
+ expect(screen.getByText('Your data is ready.')).toBeInTheDocument()
+ expect(screen.queryByText('Loading')).not.toBeInTheDocument()
+ })
+
+ // Action props should pass through to the Base UI action button.
+ it('should render and invoke toast action props', async () => {
+ const onAction = vi.fn()
+
+ render(
)
+
+ act(() => {
+ toast.add({
+ title: 'Action toast',
+ actionProps: {
+ children: 'Undo',
+ onClick: onAction,
+ },
+ })
+ })
+
+ const actionButton = await screen.findByRole('button', { name: 'Undo' })
+
+ act(() => {
+ actionButton.click()
+ })
+
+ expect(onAction).toHaveBeenCalledTimes(1)
+ })
+
+ // Promise helpers are part of the public API and need a regression test.
+ it('should transition a promise toast from loading to success', async () => {
+ render(
)
+
+ let resolvePromise: ((value: string) => void) | undefined
+ const promise = new Promise
((resolve) => {
+ resolvePromise = resolve
+ })
+
+ void act(() => toast.promise(promise, {
+ loading: 'Saving…',
+ success: result => ({
+ title: 'Saved',
+ description: result,
+ type: 'success',
+ }),
+ error: 'Failed',
+ }))
+
+ expect(await screen.findByText('Saving…')).toBeInTheDocument()
+
+ await act(async () => {
+ resolvePromise?.('Your changes are available now.')
+ await promise
+ })
+
+ expect(await screen.findByText('Saved')).toBeInTheDocument()
+ expect(screen.getByText('Your changes are available now.')).toBeInTheDocument()
+ })
+})
diff --git a/web/app/components/base/ui/toast/index.stories.tsx b/web/app/components/base/ui/toast/index.stories.tsx
new file mode 100644
index 0000000000..045ca96823
--- /dev/null
+++ b/web/app/components/base/ui/toast/index.stories.tsx
@@ -0,0 +1,332 @@
+import type { Meta, StoryObj } from '@storybook/nextjs-vite'
+import type { ReactNode } from 'react'
+import { toast, ToastHost } from '.'
+
+const buttonClassName = 'rounded-lg border border-divider-subtle bg-components-button-secondary-bg px-3 py-2 text-sm text-text-secondary shadow-xs transition-colors hover:bg-state-base-hover'
+const cardClassName = 'flex min-h-[220px] flex-col gap-4 rounded-2xl border border-divider-subtle bg-components-panel-bg p-6 shadow-sm shadow-shadow-shadow-3'
+
+const ExampleCard = ({
+ eyebrow,
+ title,
+ description,
+ children,
+}: {
+ eyebrow: string
+ title: string
+ description: string
+ children: ReactNode
+}) => {
+ return (
+
+
+
+ {eyebrow}
+
+
+ {title}
+
+
+ {description}
+
+
+
+ {children}
+
+
+ )
+}
+
+const VariantExamples = () => {
+ const createVariantToast = (type: 'success' | 'error' | 'warning' | 'info') => {
+ const copy = {
+ success: {
+ title: 'Changes saved',
+ description: 'Your draft is available to collaborators.',
+ },
+ error: {
+ title: 'Sync failed',
+ description: 'Check your network connection and try again.',
+ },
+ warning: {
+ title: 'Storage almost full',
+ description: 'You have less than 10% of workspace quota remaining.',
+ },
+ info: {
+ title: 'Invitation sent',
+ description: 'An email has been sent to the new teammate.',
+ },
+ } as const
+
+ toast.add({
+ type,
+ ...copy[type],
+ })
+ }
+
+ return (
+
+ createVariantToast('success')}>
+ Success
+
+ createVariantToast('info')}>
+ Info
+
+ createVariantToast('warning')}>
+ Warning
+
+ createVariantToast('error')}>
+ Error
+
+
+ )
+}
+
+const StackExamples = () => {
+ const createStack = () => {
+ ;[
+ {
+ type: 'info' as const,
+ title: 'Generating preview',
+ description: 'The first toast compresses behind the newest notification.',
+ },
+ {
+ type: 'warning' as const,
+ title: 'Review required',
+ description: 'A second toast should deepen the stack without breaking spacing.',
+ },
+ {
+ type: 'success' as const,
+ title: 'Ready to publish',
+ description: 'The newest toast stays frontmost while older items tuck behind it.',
+ },
+ ].forEach(item => toast.add(item))
+ }
+
+ const createBurst = () => {
+ Array.from({ length: 5 }).forEach((_, index) => {
+ toast.add({
+ type: index % 2 === 0 ? 'info' : 'success',
+ title: `Background task ${index + 1}`,
+ description: 'Use this to inspect how the stack behaves near the host limit.',
+ })
+ })
+ }
+
+ return (
+
+
+ Create 3 stacked toasts
+
+
+ Stress the stack
+
+
+ )
+}
+
+const PromiseExamples = () => {
+ const createPromiseToast = () => {
+ const request = new Promise((resolve) => {
+ window.setTimeout(() => resolve('The deployment is now available in production.'), 1400)
+ })
+
+ void toast.promise(request, {
+ loading: {
+ type: 'info',
+ title: 'Deploying workflow',
+ description: 'Provisioning runtime and publishing the latest version.',
+ },
+ success: result => ({
+ type: 'success',
+ title: 'Deployment complete',
+ description: result,
+ }),
+ error: () => ({
+ type: 'error',
+ title: 'Deployment failed',
+ description: 'The release could not be completed.',
+ }),
+ })
+ }
+
+ const createRejectingPromiseToast = () => {
+ const request = new Promise((_, reject) => {
+ window.setTimeout(() => reject(new Error('intentional story failure')), 1200)
+ })
+
+ void toast.promise(request, {
+ loading: 'Validating model credentials…',
+ success: 'Credentials verified',
+ error: () => ({
+ type: 'error',
+ title: 'Credentials rejected',
+ description: 'The model provider returned an authentication error.',
+ }),
+ })
+ }
+
+ return (
+
+
+ Promise success
+
+
+ Promise error
+
+
+ )
+}
+
+const ActionExamples = () => {
+ const createActionToast = () => {
+ toast.add({
+ type: 'warning',
+ title: 'Project archived',
+ description: 'You can restore it from workspace settings for the next 30 days.',
+ actionProps: {
+ children: 'Undo',
+ onClick: () => {
+ toast.add({
+ type: 'success',
+ title: 'Project restored',
+ description: 'The workspace is active again.',
+ })
+ },
+ },
+ })
+ }
+
+ const createLongCopyToast = () => {
+ toast.add({
+ type: 'info',
+ title: 'Knowledge ingestion in progress',
+ description: 'This longer example helps validate line wrapping, close button alignment, and action button placement when the content spans multiple rows.',
+ actionProps: {
+ children: 'View details',
+ onClick: () => {
+ toast.add({
+ type: 'info',
+ title: 'Job details opened',
+ })
+ },
+ },
+ })
+ }
+
+ return (
+
+
+ Undo action
+
+
+ Long content
+
+
+ )
+}
+
+const UpdateExamples = () => {
+ const createUpdatableToast = () => {
+ const toastId = toast.add({
+ type: 'info',
+ title: 'Import started',
+ description: 'Preparing assets and metadata for processing.',
+ timeout: 0,
+ })
+
+ window.setTimeout(() => {
+ toast.update(toastId, {
+ type: 'success',
+ title: 'Import finished',
+ description: '128 records were imported successfully.',
+ timeout: 5000,
+ })
+ }, 1400)
+ }
+
+ const clearAll = () => {
+ toast.close()
+ }
+
+ return (
+
+
+ Add then update
+
+
+ Clear all
+
+
+ )
+}
+
+const ToastDocsDemo = () => {
+ return (
+ <>
+
+
+
+
+
+ Base UI toast docs
+
+
+ Shared stacked toast examples
+
+
+ Each example card below triggers the same shared toast viewport in the top-right corner, so you can review stacking, state transitions, actions, and tone variants the same way the official Base UI documentation demonstrates toast behavior.
+
+
+
+
+
+ >
+ )
+}
+
+const meta = {
+ title: 'Base/Feedback/UI Toast',
+ component: ToastHost,
+ parameters: {
+ layout: 'fullscreen',
+ docs: {
+ description: {
+ component: 'Dify toast host built on Base UI Toast. The story is organized as multiple example panels that all feed the same shared toast viewport, matching the way the Base UI documentation showcases toast behavior.',
+ },
+ },
+ },
+ tags: ['autodocs'],
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const DocsPattern: Story = {
+ render: () => ,
+}
diff --git a/web/app/components/base/ui/toast/index.tsx b/web/app/components/base/ui/toast/index.tsx
new file mode 100644
index 0000000000..aed0c59b16
--- /dev/null
+++ b/web/app/components/base/ui/toast/index.tsx
@@ -0,0 +1,202 @@
+'use client'
+
+import type {
+ ToastManagerAddOptions,
+ ToastManagerPromiseOptions,
+ ToastManagerUpdateOptions,
+ ToastObject,
+} from '@base-ui/react/toast'
+import { Toast as BaseToast } from '@base-ui/react/toast'
+import { useTranslation } from 'react-i18next'
+import { cn } from '@/utils/classnames'
+
+type ToastData = Record
+type ToastType = 'success' | 'error' | 'warning' | 'info'
+
+type ToastAddOptions = Omit, 'data' | 'positionerProps' | 'type'> & {
+ type?: ToastType
+}
+
+type ToastUpdateOptions = Omit, 'data' | 'positionerProps' | 'type'> & {
+ type?: ToastType
+}
+
+type ToastPromiseOptions = {
+ loading: string | ToastUpdateOptions
+ success: string | ToastUpdateOptions | ((result: Value) => string | ToastUpdateOptions)
+ error: string | ToastUpdateOptions | ((error: unknown) => string | ToastUpdateOptions)
+}
+
+export type ToastHostProps = {
+ timeout?: number
+ limit?: number
+}
+
+const toastManager = BaseToast.createToastManager()
+
+export const toast = {
+ add(options: ToastAddOptions) {
+ return toastManager.add(options)
+ },
+ close(toastId?: string) {
+ toastManager.close(toastId)
+ },
+ update(toastId: string, options: ToastUpdateOptions) {
+ toastManager.update(toastId, options)
+ },
+ promise(promiseValue: Promise, options: ToastPromiseOptions) {
+ return toastManager.promise(promiseValue, options as ToastManagerPromiseOptions)
+ },
+}
+
+function ToastIcon({ type }: { type?: string }) {
+ if (type === 'success') {
+ return
+ }
+
+ if (type === 'error') {
+ return
+ }
+
+ if (type === 'warning') {
+ return
+ }
+
+ if (type === 'info') {
+ return
+ }
+
+ return null
+}
+
+function getToneGradientClasses(type?: string) {
+ if (type === 'success')
+ return 'from-components-badge-status-light-success-halo to-background-gradient-mask-transparent'
+
+ if (type === 'error')
+ return 'from-components-badge-status-light-error-halo to-background-gradient-mask-transparent'
+
+ if (type === 'warning')
+ return 'from-components-badge-status-light-warning-halo to-background-gradient-mask-transparent'
+
+ if (type === 'info')
+ return 'from-components-badge-status-light-normal-halo to-background-gradient-mask-transparent'
+
+ return 'from-background-default-subtle to-background-gradient-mask-transparent'
+}
+
+function ToastCard({
+ toast: toastItem,
+ showHoverBridge = false,
+}: {
+ toast: ToastObject
+ showHoverBridge?: boolean
+}) {
+ const { t } = useTranslation('common')
+
+ return (
+
+
+
+
+
+
+
+
+
+ {toastItem.title != null && (
+
+ {toastItem.title}
+
+ )}
+
+ {toastItem.description != null && (
+
+ {toastItem.description}
+
+ )}
+ {toastItem.actionProps && (
+
+
+
+ )}
+
+
+
+
+
+
+
+
+ {showHoverBridge && (
+
+ )}
+
+ )
+}
+
+function ToastViewport() {
+ const { t } = useTranslation('common')
+ const { toasts } = BaseToast.useToastManager()
+
+ return (
+
+
+ {toasts.map((toastItem, index) => (
+
+ ))}
+
+
+ )
+}
+
+export function ToastHost({
+ timeout,
+ limit,
+}: ToastHostProps) {
+ return (
+
+
+
+
+
+ )
+}
diff --git a/web/app/components/workflow/panel/workflow-preview.tsx b/web/app/components/workflow/panel/workflow-preview.tsx
index 4fdc0b8376..fe43b8af94 100644
--- a/web/app/components/workflow/panel/workflow-preview.tsx
+++ b/web/app/components/workflow/panel/workflow-preview.tsx
@@ -8,9 +8,9 @@ import {
import { useTranslation } from 'react-i18next'
import Button from '@/app/components/base/button'
import Loading from '@/app/components/base/loading'
+import { toast } from '@/app/components/base/ui/toast'
import { submitHumanInputForm } from '@/service/workflow'
import { cn } from '@/utils/classnames'
-import Toast from '../../base/toast'
import {
useWorkflowInteractions,
} from '../hooks'
@@ -210,7 +210,7 @@ const WorkflowPreview = () => {
copy(content)
else
copy(JSON.stringify(content))
- Toast.notify({ type: 'success', message: t('actionMsg.copySuccessfully', { ns: 'common' }) })
+ toast.add({ type: 'success', title: t('actionMsg.copySuccessfully', { ns: 'common' }) })
}}
>
diff --git a/web/app/layout.tsx b/web/app/layout.tsx
index fd9548600c..3c8e04bc5b 100644
--- a/web/app/layout.tsx
+++ b/web/app/layout.tsx
@@ -9,6 +9,7 @@ import { TanstackQueryInitializer } from '@/context/query-client'
import { getDatasetMap } from '@/env'
import { getLocaleOnServer } from '@/i18n-config/server'
import { ToastProvider } from './components/base/toast'
+import { ToastHost } from './components/base/ui/toast'
import { TooltipProvider } from './components/base/ui/tooltip'
import BrowserInitializer from './components/browser-initializer'
import { ReactScanLoader } from './components/devtools/react-scan/loader'
@@ -70,6 +71,7 @@ const LocaleLayout = async ({
+
diff --git a/web/docs/overlay-migration.md b/web/docs/overlay-migration.md
index b3b1bd5738..23f08fd043 100644
--- a/web/docs/overlay-migration.md
+++ b/web/docs/overlay-migration.md
@@ -13,6 +13,7 @@ This document tracks the migration away from legacy overlay APIs.
- `@/app/components/base/popover`
- `@/app/components/base/dropdown`
- `@/app/components/base/dialog`
+ - `@/app/components/base/toast` (including `context`)
- Replacement primitives:
- `@/app/components/base/ui/tooltip`
- `@/app/components/base/ui/dropdown-menu`
@@ -21,6 +22,7 @@ This document tracks the migration away from legacy overlay APIs.
- `@/app/components/base/ui/dialog`
- `@/app/components/base/ui/alert-dialog`
- `@/app/components/base/ui/select`
+ - `@/app/components/base/ui/toast`
- Tracking issue: https://github.com/langgenius/dify/issues/32767
## ESLint policy
@@ -42,6 +44,13 @@ This document tracks the migration away from legacy overlay APIs.
- Remove remaining allowlist entries.
- Remove legacy overlay implementations when import count reaches zero.
+## Toast migration strategy
+
+- During migration, `@/app/components/base/toast` and `@/app/components/base/ui/toast` may coexist.
+- All new toast usage must go through `@/app/components/base/ui/toast`.
+- When a file with legacy toast usage is touched, prefer migrating that call site in the same change; full-repo toast cleanup is not required in one PR.
+- `@/app/components/base/ui/toast` is the design-system stack toast host. Legacy `ToastContext`, `ToastProvider`, anchored toast behavior, and ad-hoc mount patterns stay in `base/toast` until their call sites are migrated away.
+
## Allowlist maintenance
- After each migration batch, run:
@@ -55,7 +64,8 @@ pnpm -C web lint:fix --prune-suppressions
## z-index strategy
-All new overlay primitives in `base/ui/` share a single z-index value: **`z-[1002]`**.
+All new overlay primitives in `base/ui/` share a single z-index value:
+**`z-[1002]`**, except Toast which stays at **`z-[1101]`** during migration.
### Why z-[1002]?
@@ -69,13 +79,17 @@ portal to `document.body` with explicit z-index values:
| Legacy PortalToFollowElem callers | up to `z-[1001]` | various business components |
| **New UI primitives** | **`z-[1002]`** | `base/ui/*` (Popover, Dialog, Tooltip, etc.) |
| Legacy Modal (highPriority) | `z-[1100]` | `base/modal` (`highPriority={true}`) |
-| Toast | `z-[9999]` | `base/toast` |
+| Toast (legacy + new) | `z-[1101]` | `base/toast`, `base/ui/toast` |
`z-[1002]` sits above all common legacy overlays, so new primitives always
render on top without needing per-call-site z-index hacks. Among themselves,
new primitives share the same z-index and rely on **DOM order** for stacking
(later portal = on top).
+Toast intentionally stays one layer above the remaining legacy `highPriority`
+modal path (`z-[1100]`) so notifications keep their current visibility without
+falling back to `z-[9999]`.
+
### Rules
- **Do NOT add z-index overrides** (e.g. `className="z-[1003]"`) on new
@@ -91,7 +105,7 @@ new primitives share the same z-index and rely on **DOM order** for stacking
Once all legacy overlays are removed:
1. Reduce `z-[1002]` back to `z-50` across all `base/ui/` primitives.
-1. Reduce Toast from `z-[9999]` to `z-[99]`.
+1. Reduce Toast from `z-[1101]` to `z-[51]`.
1. Remove this section from the migration guide.
## React Refresh policy for base UI primitives
diff --git a/web/eslint-suppressions.json b/web/eslint-suppressions.json
index 3a43fb9787..29c2a48253 100644
--- a/web/eslint-suppressions.json
+++ b/web/eslint-suppressions.json
@@ -1,4 +1,9 @@
{
+ ".storybook/preview.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"__tests__/check-i18n.test.ts": {
"regexp/no-unused-capturing-group": {
"count": 1
@@ -76,6 +81,11 @@
"count": 1
}
},
+ "app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/card-view.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/chart-view.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -124,13 +134,16 @@
}
},
"app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/panel.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
},
"app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-config-modal.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
},
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -176,6 +189,9 @@
}
},
"app/(shareLayout)/webapp-reset-password/check-code/page.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 4
}
@@ -189,26 +205,46 @@
}
},
"app/(shareLayout)/webapp-reset-password/page.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 4
}
},
"app/(shareLayout)/webapp-reset-password/set-password/page.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 6
}
},
"app/(shareLayout)/webapp-signin/check-code/page.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 4
}
},
+ "app/(shareLayout)/webapp-signin/components/external-member-sso-auth.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/(shareLayout)/webapp-signin/components/mail-and-code-auth.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
},
"app/(shareLayout)/webapp-signin/components/mail-and-password-auth.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
},
@@ -216,6 +252,11 @@
"count": 2
}
},
+ "app/(shareLayout)/webapp-signin/components/sso-auth.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/(shareLayout)/webapp-signin/layout.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -233,7 +274,7 @@
},
"app/account/(commonLayout)/account-page/AvatarWithEdit.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -241,7 +282,7 @@
},
"app/account/(commonLayout)/account-page/email-change-modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 21
@@ -252,7 +293,7 @@
},
"app/account/(commonLayout)/account-page/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 14
@@ -276,7 +317,7 @@
},
"app/account/(commonLayout)/delete-account/components/feed-back.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -306,6 +347,9 @@
}
},
"app/account/oauth/authorize/page.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -318,6 +362,11 @@
"count": 4
}
},
+ "app/components/app-sidebar/app-info/use-app-info-actions.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/app-sidebar/app-sidebar-dropdown.tsx": {
"no-restricted-imports": {
"count": 1
@@ -330,7 +379,7 @@
},
"app/components/app-sidebar/dataset-info/dropdown.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
},
"ts/no-explicit-any": {
"count": 1
@@ -360,6 +409,9 @@
}
},
"app/components/app/annotation/add-annotation-modal/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -380,13 +432,16 @@
}
},
"app/components/app/annotation/batch-add-annotation-modal/csv-uploader.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
},
"app/components/app/annotation/batch-add-annotation-modal/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
@@ -424,7 +479,7 @@
},
"app/components/app/annotation/edit-annotation-modal/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -460,6 +515,9 @@
}
},
"app/components/app/annotation/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
},
@@ -510,6 +568,9 @@
}
},
"app/components/app/app-access-control/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 6
}
@@ -532,7 +593,7 @@
},
"app/components/app/app-publisher/index.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
},
"ts/no-explicit-any": {
"count": 5
@@ -550,7 +611,7 @@
},
"app/components/app/app-publisher/version-info-modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 3
@@ -568,7 +629,7 @@
},
"app/components/app/configuration/config-prompt/advanced-prompt-input.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"ts/no-explicit-any": {
"count": 2
@@ -599,7 +660,7 @@
},
"app/components/app/configuration/config-prompt/simple-prompt-input.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -610,7 +671,7 @@
},
"app/components/app/configuration/config-var/config-modal/index.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
},
"tailwindcss/enforce-consistent-class-order": {
"count": 2
@@ -634,7 +695,7 @@
},
"app/components/app/configuration/config-var/index.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
}
},
"app/components/app/configuration/config-var/input-type-icon.tsx": {
@@ -752,6 +813,9 @@
}
},
"app/components/app/configuration/config/agent/prompt-editor.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/no-unnecessary-whitespace": {
"count": 1
}
@@ -769,7 +833,7 @@
},
"app/components/app/configuration/config/automatic/get-automatic-res.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 4
@@ -807,6 +871,11 @@
"count": 1
}
},
+ "app/components/app/configuration/config/automatic/result.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/app/configuration/config/automatic/version-selector.tsx": {
"no-restricted-imports": {
"count": 1
@@ -820,7 +889,7 @@
},
"app/components/app/configuration/config/code-generator/get-code-generator-res.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 4
@@ -904,12 +973,12 @@
},
"app/components/app/configuration/dataset-config/params-config/config-content.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/app/configuration/dataset-config/params-config/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
@@ -931,6 +1000,9 @@
}
},
"app/components/app/configuration/dataset-config/settings-modal/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 2
},
@@ -1007,7 +1079,7 @@
},
"app/components/app/configuration/debug/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 2
@@ -1026,7 +1098,7 @@
},
"app/components/app/configuration/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 3
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
@@ -1064,7 +1136,7 @@
},
"app/components/app/configuration/tools/external-data-tool-modal.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
},
"tailwindcss/no-unnecessary-whitespace": {
"count": 1
@@ -1075,7 +1147,7 @@
},
"app/components/app/configuration/tools/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/app/create-app-dialog/app-card/index.spec.tsx": {
@@ -1097,6 +1169,9 @@
}
},
"app/components/app/create-app-dialog/app-list/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 5
}
@@ -1110,6 +1185,9 @@
}
},
"app/components/app/create-app-modal/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
},
@@ -1127,7 +1205,7 @@
},
"app/components/app/create-from-dsl-modal/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 2
@@ -1140,13 +1218,16 @@
}
},
"app/components/app/create-from-dsl-modal/uploader.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/no-unnecessary-whitespace": {
"count": 1
}
},
"app/components/app/duplicate-modal/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 2
@@ -1172,7 +1253,7 @@
},
"app/components/app/log/list.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 6
@@ -1259,7 +1340,7 @@
},
"app/components/app/overview/settings/index.tsx": {
"no-restricted-imports": {
- "count": 3
+ "count": 4
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 3
@@ -1278,13 +1359,16 @@
},
"app/components/app/switch-app-modal/index.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
}
},
"app/components/app/text-generate/item/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 3
},
@@ -1310,6 +1394,9 @@
}
},
"app/components/app/text-generate/saved-items/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -1371,7 +1458,7 @@
},
"app/components/apps/app-card.tsx": {
"no-restricted-imports": {
- "count": 3
+ "count": 5
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
@@ -1404,6 +1491,9 @@
}
},
"app/components/base/agent-log-modal/detail.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -1412,6 +1502,9 @@
"no-console": {
"count": 1
},
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -1457,6 +1550,9 @@
}
},
"app/components/base/audio-btn/audio.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"node/prefer-global/buffer": {
"count": 1
},
@@ -1470,6 +1566,9 @@
}
},
"app/components/base/audio-gallery/AudioPlayer.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 2
}
@@ -1569,6 +1668,9 @@
}
},
"app/components/base/chat/chat-with-history/hooks.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 4
},
@@ -1656,7 +1758,7 @@
},
"app/components/base/chat/chat/answer/operation.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
}
},
"app/components/base/chat/chat/answer/tool-detail.tsx": {
@@ -1670,11 +1772,17 @@
}
},
"app/components/base/chat/chat/chat-input-area/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 3
}
},
"app/components/base/chat/chat/check-input-forms-hooks.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -1685,6 +1793,9 @@
}
},
"app/components/base/chat/chat/hooks.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 2
},
@@ -1731,6 +1842,9 @@
}
},
"app/components/base/chat/embedded-chatbot/hooks.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 3
}
@@ -1900,12 +2014,12 @@
},
"app/components/base/features/new-feature-panel/annotation-reply/annotation-ctrl-button.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/base/features/new-feature-panel/annotation-reply/config-param-modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/base/features/new-feature-panel/annotation-reply/config-param.tsx": {
@@ -1987,7 +2101,7 @@
},
"app/components/base/features/new-feature-panel/moderation/moderation-setting-modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"ts/no-explicit-any": {
"count": 2
@@ -2042,12 +2156,25 @@
"count": 3
}
},
+ "app/components/base/file-uploader/file-uploader-in-attachment/index.stories.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/base/file-uploader/file-uploader-in-chat-input/file-image-item.tsx": {
"tailwindcss/no-unnecessary-whitespace": {
"count": 1
}
},
+ "app/components/base/file-uploader/file-uploader-in-chat-input/index.stories.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/base/file-uploader/hooks.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 3
}
@@ -2157,6 +2284,9 @@
}
},
"app/components/base/form/hooks/use-check-validated.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 2
}
@@ -2187,6 +2317,9 @@
}
},
"app/components/base/image-uploader/hooks.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 4
}
@@ -2203,7 +2336,7 @@
},
"app/components/base/image-uploader/image-preview.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"ts/no-explicit-any": {
"count": 1
@@ -2712,16 +2845,26 @@
"count": 1
}
},
- "app/components/base/tag-management/index.tsx": {
+ "app/components/base/tag-input/index.tsx": {
"no-restricted-imports": {
"count": 1
}
},
- "app/components/base/tag-management/panel.tsx": {
+ "app/components/base/tag-management/index.stories.tsx": {
"no-restricted-imports": {
"count": 1
}
},
+ "app/components/base/tag-management/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
+ "app/components/base/tag-management/panel.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/base/tag-management/selector.tsx": {
"no-restricted-imports": {
"count": 1
@@ -2729,7 +2872,7 @@
},
"app/components/base/tag-management/tag-item-editor.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
}
},
"app/components/base/tag-management/tag-remove-modal.tsx": {
@@ -2738,6 +2881,9 @@
}
},
"app/components/base/text-generation/hooks.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -2840,6 +2986,9 @@
}
},
"app/components/billing/pricing/plans/cloud-plan-item/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 6
}
@@ -2860,6 +3009,9 @@
}
},
"app/components/billing/pricing/plans/self-hosted-plan-item/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 4
},
@@ -2903,6 +3055,11 @@
"count": 1
}
},
+ "app/components/custom/custom-web-app-brand/hooks/use-web-app-brand.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/datasets/chunk.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 3
@@ -2924,6 +3081,11 @@
"count": 2
}
},
+ "app/components/datasets/common/document-status-with-action/auto-disabled-document.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/datasets/common/image-list/more.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -2938,6 +3100,9 @@
}
},
"app/components/datasets/common/image-uploader/hooks/use-upload.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 3
}
@@ -2967,7 +3132,7 @@
},
"app/components/datasets/common/retrieval-param-config/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/dsl-confirm-modal.tsx": {
@@ -2983,6 +3148,11 @@
"count": 1
}
},
+ "app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/hooks/use-dsl-import.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/index.tsx": {
"no-restricted-imports": {
"count": 1
@@ -3001,6 +3171,11 @@
"count": 1
}
},
+ "app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/uploader.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/datasets/create-from-pipeline/footer.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -3015,6 +3190,9 @@
}
},
"app/components/datasets/create-from-pipeline/list/create-card.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
@@ -3048,13 +3226,16 @@
}
},
"app/components/datasets/create-from-pipeline/list/template-card/edit-pipeline-info.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
}
},
"app/components/datasets/create-from-pipeline/list/template-card/index.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
}
},
"app/components/datasets/create-from-pipeline/list/template-card/operations.tsx": {
@@ -3077,7 +3258,7 @@
},
"app/components/datasets/create/empty-dataset-creation-modal/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/datasets/create/file-preview/index.tsx": {
@@ -3085,6 +3266,11 @@
"count": 1
}
},
+ "app/components/datasets/create/file-uploader/hooks/use-file-upload.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/datasets/create/notion-page-preview/index.tsx": {
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
@@ -3123,12 +3309,20 @@
"count": 1
}
},
+ "app/components/datasets/create/step-two/hooks/use-document-creation.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/datasets/create/step-two/hooks/use-indexing-config.ts": {
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 3
}
},
"app/components/datasets/create/step-two/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -3190,6 +3384,9 @@
"no-console": {
"count": 1
},
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
},
@@ -3211,6 +3408,9 @@
"no-console": {
"count": 1
},
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
},
@@ -3240,6 +3440,9 @@
"no-console": {
"count": 1
},
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
},
@@ -3260,6 +3463,11 @@
"count": 1
}
},
+ "app/components/datasets/documents/components/document-list/hooks/use-document-actions.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/datasets/documents/components/documents-header.tsx": {
"no-restricted-imports": {
"count": 1
@@ -3267,12 +3475,12 @@
},
"app/components/datasets/documents/components/operations.tsx": {
"no-restricted-imports": {
- "count": 3
+ "count": 4
}
},
"app/components/datasets/documents/components/rename-modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/datasets/documents/create-from-pipeline/actions/index.tsx": {
@@ -3309,6 +3517,9 @@
}
},
"app/components/datasets/documents/create-from-pipeline/data-source/online-documents/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -3385,6 +3596,9 @@
}
},
"app/components/datasets/documents/create-from-pipeline/data-source/online-drive/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 5
}
@@ -3433,6 +3647,9 @@
}
},
"app/components/datasets/documents/create-from-pipeline/data-source/website-crawl/base/options/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
},
@@ -3459,6 +3676,9 @@
}
},
"app/components/datasets/documents/create-from-pipeline/preview/online-document-preview.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 4
}
@@ -3472,6 +3692,9 @@
}
},
"app/components/datasets/documents/create-from-pipeline/process-documents/form.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 3
}
@@ -3500,6 +3723,9 @@
}
},
"app/components/datasets/documents/detail/batch-modal/csv-uploader.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/no-unnecessary-whitespace": {
"count": 1
}
@@ -3604,17 +3830,30 @@
"count": 1
}
},
+ "app/components/datasets/documents/detail/completed/hooks/use-child-segment-data.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/datasets/documents/detail/completed/hooks/use-search-filter.ts": {
"no-restricted-imports": {
"count": 1
}
},
+ "app/components/datasets/documents/detail/completed/hooks/use-segment-list-data.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/datasets/documents/detail/completed/index.tsx": {
"react-refresh/only-export-components": {
"count": 1
}
},
"app/components/datasets/documents/detail/completed/new-child-segment.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
},
@@ -3665,6 +3904,16 @@
"count": 3
}
},
+ "app/components/datasets/documents/detail/embedding/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
+ "app/components/datasets/documents/detail/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/datasets/documents/detail/metadata/components/doc-type-selector.tsx": {
"no-restricted-imports": {
"count": 1
@@ -3675,7 +3924,15 @@
"count": 1
}
},
+ "app/components/datasets/documents/detail/metadata/hooks/use-metadata-state.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/datasets/documents/detail/new-segment.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
},
@@ -3714,7 +3971,7 @@
},
"app/components/datasets/documents/status-item/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/datasets/external-api/external-api-modal/Form.tsx": {
@@ -3724,7 +3981,7 @@
},
"app/components/datasets/external-api/external-api-modal/index.tsx": {
"no-restricted-imports": {
- "count": 3
+ "count": 4
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
@@ -3746,6 +4003,11 @@
"count": 1
}
},
+ "app/components/datasets/external-knowledge-base/connector/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/datasets/external-knowledge-base/create/ExternalApiSelect.tsx": {
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
@@ -3873,6 +4135,11 @@
"count": 1
}
},
+ "app/components/datasets/hit-testing/modify-retrieval-modal.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/datasets/list/dataset-card/components/dataset-card-footer.tsx": {
"no-restricted-imports": {
"count": 1
@@ -3902,6 +4169,9 @@
}
},
"app/components/datasets/list/dataset-card/hooks/use-dataset-card-state.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
}
@@ -3946,15 +4216,26 @@
},
"app/components/datasets/metadata/edit-metadata-batch/modal.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
+ }
+ },
+ "app/components/datasets/metadata/hooks/use-batch-edit-document-metadata.ts": {
+ "no-restricted-imports": {
+ "count": 1
}
},
"app/components/datasets/metadata/hooks/use-edit-dataset-metadata.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
}
},
"app/components/datasets/metadata/hooks/use-metadata-document.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -3974,7 +4255,7 @@
},
"app/components/datasets/metadata/metadata-dataset/dataset-metadata-drawer.tsx": {
"no-restricted-imports": {
- "count": 3
+ "count": 4
},
"tailwindcss/enforce-consistent-class-order": {
"count": 5
@@ -4029,7 +4310,7 @@
},
"app/components/datasets/rename-modal/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/datasets/settings/form/components/basic-info-section.tsx": {
@@ -4047,6 +4328,11 @@
"count": 7
}
},
+ "app/components/datasets/settings/form/hooks/use-form-state.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/datasets/settings/index-method/index.tsx": {
"no-restricted-imports": {
"count": 1
@@ -4147,7 +4433,7 @@
},
"app/components/explore/create-app-modal/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 2
@@ -4174,7 +4460,7 @@
},
"app/components/explore/sidebar/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/explore/sidebar/no-apps/index.tsx": {
@@ -4259,7 +4545,15 @@
"count": 1
}
},
+ "app/components/header/account-dropdown/compliance.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/header/account-dropdown/workplace-selector/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
},
@@ -4279,7 +4573,7 @@
},
"app/components/header/account-setting/api-based-extension-page/modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/header/account-setting/api-based-extension-page/selector.tsx": {
@@ -4340,14 +4634,22 @@
"count": 2
}
},
+ "app/components/header/account-setting/data-source-page/data-source-notion/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/header/account-setting/data-source-page/data-source-notion/operate/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 4
}
},
"app/components/header/account-setting/data-source-page/data-source-website/config-firecrawl-modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -4355,7 +4657,7 @@
},
"app/components/header/account-setting/data-source-page/data-source-website/config-jina-reader-modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -4363,13 +4665,16 @@
},
"app/components/header/account-setting/data-source-page/data-source-website/config-watercrawl-modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
},
"app/components/header/account-setting/data-source-page/data-source-website/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -4399,12 +4704,12 @@
},
"app/components/header/account-setting/language-page/index.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
}
},
"app/components/header/account-setting/members-page/edit-workspace-modal/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/header/account-setting/members-page/index.tsx": {
@@ -4414,7 +4719,7 @@
},
"app/components/header/account-setting/members-page/invite-modal/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 3
@@ -4437,7 +4742,7 @@
},
"app/components/header/account-setting/members-page/operation/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 5
@@ -4450,7 +4755,7 @@
},
"app/components/header/account-setting/members-page/transfer-ownership-modal/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"ts/no-explicit-any": {
"count": 3
@@ -4541,6 +4846,9 @@
}
},
"app/components/header/account-setting/model-provider-page/model-auth/hooks/use-auth.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 6
}
@@ -4703,6 +5011,9 @@
}
},
"app/components/header/account-setting/model-provider-page/provider-added-card/credential-panel.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
},
@@ -4738,7 +5049,7 @@
},
"app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
@@ -4767,7 +5078,12 @@
},
"app/components/header/account-setting/model-provider-page/system-model-selector/index.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
+ }
+ },
+ "app/components/header/account-setting/plugin-page/SerpapiPlugin.tsx": {
+ "no-restricted-imports": {
+ "count": 1
}
},
"app/components/header/account-setting/plugin-page/utils.ts": {
@@ -4873,6 +5189,9 @@
}
},
"app/components/plugins/install-plugin/hooks.ts": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"ts/no-explicit-any": {
"count": 4
}
@@ -4900,7 +5219,7 @@
},
"app/components/plugins/install-plugin/install-from-github/index.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
},
"tailwindcss/enforce-consistent-class-order": {
"count": 2
@@ -5035,7 +5354,7 @@
},
"app/components/plugins/plugin-auth/authorize/api-key-modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"ts/no-explicit-any": {
"count": 2
@@ -5051,7 +5370,7 @@
},
"app/components/plugins/plugin-auth/authorize/oauth-client-settings.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"ts/no-explicit-any": {
"count": 2
@@ -5064,7 +5383,7 @@
},
"app/components/plugins/plugin-auth/authorized/index.tsx": {
"no-restricted-imports": {
- "count": 3
+ "count": 4
},
"tailwindcss/enforce-consistent-class-order": {
"count": 2
@@ -5085,6 +5404,9 @@
}
},
"app/components/plugins/plugin-auth/hooks/use-plugin-auth-action.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 2
}
@@ -5180,6 +5502,11 @@
"count": 1
}
},
+ "app/components/plugins/plugin-detail-panel/detail-header/hooks/use-plugin-operations.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/plugins/plugin-detail-panel/detail-header/index.tsx": {
"no-restricted-imports": {
"count": 1
@@ -5187,7 +5514,7 @@
},
"app/components/plugins/plugin-detail-panel/endpoint-card.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
},
"tailwindcss/enforce-consistent-class-order": {
"count": 5
@@ -5198,7 +5525,7 @@
},
"app/components/plugins/plugin-detail-panel/endpoint-list.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 4
@@ -5208,6 +5535,9 @@
}
},
"app/components/plugins/plugin-detail-panel/endpoint-modal.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
},
@@ -5225,7 +5555,7 @@
},
"app/components/plugins/plugin-detail-panel/model-selector/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -5292,14 +5622,24 @@
"count": 3
}
},
+ "app/components/plugins/plugin-detail-panel/subscription-list/create/hooks/use-common-modal-state.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
+ "app/components/plugins/plugin-detail-panel/subscription-list/create/hooks/use-oauth-client-state.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/plugins/plugin-detail-panel/subscription-list/create/index.tsx": {
"no-restricted-imports": {
- "count": 3
+ "count": 4
}
},
"app/components/plugins/plugin-detail-panel/subscription-list/create/oauth-client.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 3
@@ -5307,7 +5647,7 @@
},
"app/components/plugins/plugin-detail-panel/subscription-list/delete-confirm.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -5318,7 +5658,7 @@
},
"app/components/plugins/plugin-detail-panel/subscription-list/edit/apikey-edit-modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -5326,12 +5666,12 @@
},
"app/components/plugins/plugin-detail-panel/subscription-list/edit/manual-edit-modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/plugins/plugin-detail-panel/subscription-list/edit/oauth-edit-modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/plugins/plugin-detail-panel/subscription-list/index.tsx": {
@@ -5348,6 +5688,9 @@
}
},
"app/components/plugins/plugin-detail-panel/subscription-list/log-viewer.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 5
},
@@ -5400,6 +5743,11 @@
"count": 2
}
},
+ "app/components/plugins/plugin-detail-panel/tool-selector/components/tool-credentials-form.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/plugins/plugin-detail-panel/tool-selector/components/tool-item.tsx": {
"no-restricted-imports": {
"count": 2
@@ -5438,7 +5786,7 @@
},
"app/components/plugins/plugin-item/action.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
}
},
"app/components/plugins/plugin-item/index.tsx": {
@@ -5533,6 +5881,11 @@
"count": 1
}
},
+ "app/components/plugins/plugin-page/use-reference-setting.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/plugins/provider-card.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 2
@@ -5609,7 +5962,7 @@
},
"app/components/plugins/update-plugin/from-market-place.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -5635,7 +5988,7 @@
},
"app/components/rag-pipeline/components/conversion.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 2
@@ -5651,6 +6004,11 @@
"count": 2
}
},
+ "app/components/rag-pipeline/components/panel/input-field/editor/form/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/rag-pipeline/components/panel/input-field/editor/form/initial-fields.tsx": {
"ts/no-explicit-any": {
"count": 2
@@ -5679,6 +6037,11 @@
"count": 3
}
},
+ "app/components/rag-pipeline/components/panel/input-field/field-list/hooks.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/rag-pipeline/components/panel/input-field/hooks.ts": {
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
@@ -5731,6 +6094,9 @@
}
},
"app/components/rag-pipeline/components/panel/test-run/preparation/document-processing/options.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 2
}
@@ -5796,7 +6162,7 @@
},
"app/components/rag-pipeline/components/rag-pipeline-header/publisher/popup.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 8
@@ -5832,6 +6198,9 @@
}
},
"app/components/rag-pipeline/hooks/use-DSL.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -5861,6 +6230,11 @@
"count": 1
}
},
+ "app/components/rag-pipeline/hooks/use-update-dsl-modal.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/rag-pipeline/store/index.ts": {
"ts/no-explicit-any": {
"count": 2
@@ -5871,7 +6245,15 @@
"count": 1
}
},
+ "app/components/share/text-generation/hooks/use-text-generation-app-state.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/share/text-generation/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
}
@@ -5904,6 +6286,9 @@
}
},
"app/components/share/text-generation/result/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -5954,6 +6339,9 @@
}
},
"app/components/tools/edit-custom-collection-modal/get-schema.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
},
@@ -5965,6 +6353,9 @@
}
},
"app/components/tools/edit-custom-collection-modal/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 4
},
@@ -6050,6 +6441,11 @@
"count": 3
}
},
+ "app/components/tools/mcp/hooks/use-mcp-modal-form.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/tools/mcp/mcp-server-modal.tsx": {
"no-restricted-imports": {
"count": 1
@@ -6079,7 +6475,7 @@
},
"app/components/tools/mcp/modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 7
@@ -6120,13 +6516,16 @@
}
},
"app/components/tools/provider/custom-create-card.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
},
"app/components/tools/provider/detail.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 10
@@ -6143,6 +6542,9 @@
}
},
"app/components/tools/setting/build-in/config-credentials.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/no-unnecessary-whitespace": {
"count": 1
},
@@ -6160,9 +6562,14 @@
"count": 1
}
},
- "app/components/tools/workflow-tool/index.tsx": {
+ "app/components/tools/workflow-tool/hooks/use-configure-button.ts": {
"no-restricted-imports": {
"count": 1
+ }
+ },
+ "app/components/tools/workflow-tool/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 7
@@ -6184,12 +6591,20 @@
"count": 3
}
},
+ "app/components/workflow-app/components/workflow-header/features-trigger.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/workflow-app/components/workflow-main.tsx": {
"ts/no-explicit-any": {
"count": 2
}
},
"app/components/workflow-app/hooks/use-DSL.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -6210,6 +6625,9 @@
}
},
"app/components/workflow-app/hooks/use-workflow-run.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 13
}
@@ -6354,7 +6772,7 @@
},
"app/components/workflow/block-selector/tool-picker.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/workflow/block-selector/tool/action-item.tsx": {
@@ -6441,6 +6859,9 @@
}
},
"app/components/workflow/header/header-in-restoring.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/no-unnecessary-whitespace": {
"count": 1
}
@@ -6454,6 +6875,9 @@
"no-console": {
"count": 1
},
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
},
@@ -6514,6 +6938,9 @@
}
},
"app/components/workflow/hooks/use-checklist.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-empty-object-type": {
"count": 2
},
@@ -6629,6 +7056,9 @@
}
},
"app/components/workflow/nodes/_base/components/before-run-form/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 11
}
@@ -6977,6 +7407,11 @@
"count": 5
}
},
+ "app/components/workflow/nodes/_base/components/variable/output-var-list.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/nodes/_base/components/variable/utils.ts": {
"ts/no-explicit-any": {
"count": 32
@@ -6990,6 +7425,11 @@
"count": 1
}
},
+ "app/components/workflow/nodes/_base/components/variable/var-list.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx": {
"no-restricted-imports": {
"count": 2
@@ -7074,6 +7514,9 @@
}
},
"app/components/workflow/nodes/_base/components/workflow-panel/last-run/use-last-run.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
},
@@ -7090,6 +7533,9 @@
}
},
"app/components/workflow/nodes/_base/hooks/use-one-step-run.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 2
},
@@ -7337,7 +7783,7 @@
},
"app/components/workflow/nodes/http/components/curl-panel.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/components/workflow/nodes/http/components/key-value/key-value-edit/index.tsx": {
@@ -7389,7 +7835,7 @@
},
"app/components/workflow/nodes/human-input/components/delivery-method/email-configure-modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 8
@@ -7493,6 +7939,11 @@
"count": 2
}
},
+ "app/components/workflow/nodes/human-input/components/user-action.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/workflow/nodes/human-input/components/variable-in-markdown.tsx": {
"react-refresh/only-export-components": {
"count": 2
@@ -7508,7 +7959,7 @@
},
"app/components/workflow/nodes/human-input/panel.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 4
@@ -7598,6 +8049,9 @@
}
},
"app/components/workflow/nodes/iteration/node.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
}
@@ -7886,6 +8340,11 @@
"count": 3
}
},
+ "app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-config.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-generator/generated-result.tsx": {
"style/multiline-ternary": {
"count": 2
@@ -7896,7 +8355,7 @@
},
"app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-generator/index.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 2
@@ -7957,6 +8416,9 @@
}
},
"app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/hooks.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -7976,7 +8438,7 @@
},
"app/components/workflow/nodes/llm/panel.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 3
@@ -8081,6 +8543,9 @@
}
},
"app/components/workflow/nodes/loop/components/loop-variables/item.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 4
}
@@ -8112,7 +8577,7 @@
},
"app/components/workflow/nodes/parameter-extractor/components/extract-parameter/update.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
},
"ts/no-explicit-any": {
"count": 1
@@ -8182,6 +8647,11 @@
"count": 8
}
},
+ "app/components/workflow/nodes/start/components/var-list.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/workflow/nodes/start/node.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 2
@@ -8196,6 +8666,9 @@
}
},
"app/components/workflow/nodes/start/use-config.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -8294,6 +8767,9 @@
}
},
"app/components/workflow/nodes/tool/use-config.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 6
}
@@ -8379,7 +8855,12 @@
},
"app/components/workflow/nodes/trigger-webhook/panel.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
+ }
+ },
+ "app/components/workflow/nodes/trigger-webhook/use-config.ts": {
+ "no-restricted-imports": {
+ "count": 1
}
},
"app/components/workflow/nodes/trigger-webhook/utils/render-output-vars.tsx": {
@@ -8403,6 +8884,9 @@
}
},
"app/components/workflow/nodes/variable-assigner/components/var-group-item.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
},
@@ -8431,6 +8915,11 @@
"count": 1
}
},
+ "app/components/workflow/note-node/note-editor/plugins/link-editor-plugin/hooks.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/workflow/note-node/note-editor/toolbar/color-picker.tsx": {
"no-restricted-imports": {
"count": 1
@@ -8514,6 +9003,9 @@
}
},
"app/components/workflow/panel/chat-variable-panel/components/object-value-item.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-refresh/only-export-components": {
"count": 1
},
@@ -8549,6 +9041,9 @@
}
},
"app/components/workflow/panel/chat-variable-panel/components/variable-modal.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 8
},
@@ -8592,6 +9087,9 @@
}
},
"app/components/workflow/panel/debug-and-preview/hooks.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 12
}
@@ -8616,7 +9114,7 @@
},
"app/components/workflow/panel/env-panel/variable-modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 4
@@ -8711,6 +9209,9 @@
}
},
"app/components/workflow/panel/version-history-panel/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
@@ -8778,6 +9279,9 @@
}
},
"app/components/workflow/run/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 2
},
@@ -8970,7 +9474,7 @@
},
"app/components/workflow/update-dsl-modal.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
},
"tailwindcss/enforce-consistent-class-order": {
"count": 5
@@ -9156,6 +9660,9 @@
}
},
"app/education-apply/education-apply-page.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 9
}
@@ -9205,12 +9712,20 @@
"count": 5
}
},
+ "app/forgot-password/ChangePasswordForm.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/forgot-password/ForgotPasswordForm.spec.tsx": {
"ts/no-explicit-any": {
"count": 5
}
},
"app/init/InitPasswordPopup.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -9220,7 +9735,15 @@
"count": 7
}
},
+ "app/layout.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/reset-password/check-code/page.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 4
}
@@ -9234,11 +9757,17 @@
}
},
"app/reset-password/page.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 4
}
},
"app/reset-password/set-password/page.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 6
}
@@ -9248,19 +9777,35 @@
"count": 1
}
},
+ "app/signin/check-code/page.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/signin/components/mail-and-code-auth.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
},
"app/signin/components/mail-and-password-auth.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
},
+ "app/signin/components/sso-auth.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/signin/invite-settings/page.tsx": {
"no-restricted-imports": {
- "count": 1
+ "count": 2
}
},
"app/signin/layout.tsx": {
@@ -9271,9 +9816,14 @@
"count": 1
}
},
+ "app/signin/normal-form.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/signin/one-more-step.tsx": {
"no-restricted-imports": {
- "count": 2
+ "count": 3
},
"tailwindcss/enforce-consistent-class-order": {
"count": 7
@@ -9283,11 +9833,17 @@
}
},
"app/signup/check-code/page.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 4
}
},
"app/signup/components/input-mail.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 4
}
@@ -9306,6 +9862,9 @@
}
},
"app/signup/set-password/page.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 5
}
@@ -9346,6 +9905,9 @@
}
},
"context/provider-context-provider.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -9368,6 +9930,11 @@
"count": 1
}
},
+ "hooks/use-import-dsl.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"hooks/use-metadata.ts": {
"ts/no-explicit-any": {
"count": 1
@@ -9503,6 +10070,9 @@
}
},
"service/base.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 3
}
@@ -9523,6 +10093,9 @@
}
},
"service/fetch.ts": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"regexp/no-unused-capturing-group": {
"count": 1
},
diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs
index 1f27c51bf3..81e3225b3f 100644
--- a/web/eslint.config.mjs
+++ b/web/eslint.config.mjs
@@ -85,6 +85,15 @@ const OVERLAY_RESTRICTED_IMPORT_PATTERNS = [
],
message: 'Deprecated: use @/app/components/base/ui/dialog instead. See issue #32767.',
},
+ {
+ group: [
+ '**/base/toast',
+ '**/base/toast/index',
+ '**/base/toast/context',
+ '**/base/toast/context/index',
+ ],
+ message: 'Deprecated: use @/app/components/base/ui/toast instead. See issue #32811.',
+ },
]
export default antfu(
diff --git a/web/i18n/en-US/common.json b/web/i18n/en-US/common.json
index 7ee9d68424..7ac3abedc8 100644
--- a/web/i18n/en-US/common.json
+++ b/web/i18n/en-US/common.json
@@ -589,6 +589,8 @@
"theme.dark": "dark",
"theme.light": "light",
"theme.theme": "Theme",
+ "toast.close": "Dismiss notification",
+ "toast.notifications": "Notifications",
"unit.char": "chars",
"userProfile.about": "About",
"userProfile.community": "Community",