diff --git a/web/app/components/base/portal-to-follow-elem-plus/index.tsx b/web/app/components/base/portal-to-follow-elem-plus/index.tsx deleted file mode 100644 index 4786878524..0000000000 --- a/web/app/components/base/portal-to-follow-elem-plus/index.tsx +++ /dev/null @@ -1,16 +0,0 @@ -'use client' - -/** - * Re-exports the legacy portal / floating positioning API without using the - * restricted `@/app/components/base/portal-to-follow-elem` import path at call sites. - * Prefer migrating to `@/app/components/base/ui/*` overlays when touching UI. - */ -export { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, - usePortalToFollowElem, - usePortalToFollowElemContext, -} from '../portal-to-follow-elem' - -export type { PortalToFollowElemOptions } from '../portal-to-follow-elem' diff --git a/web/app/components/base/portal-to-follow-elem-plus/use-context-menu-floating.ts b/web/app/components/base/portal-to-follow-elem-plus/use-context-menu-floating.ts deleted file mode 100644 index 09ad490e3a..0000000000 --- a/web/app/components/base/portal-to-follow-elem-plus/use-context-menu-floating.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Re-exports context-menu floating hook without importing from the restricted - * `portal-to-follow-elem/use-context-menu-floating` path at call sites. - */ -export { - type Position, - useContextMenuFloating, - type UseContextMenuFloatingOptions, -} from '../portal-to-follow-elem/use-context-menu-floating' diff --git a/web/app/components/base/portal-to-follow-elem/use-context-menu-floating.spec.tsx b/web/app/components/base/portal-to-follow-elem/use-context-menu-floating.spec.tsx deleted file mode 100644 index af71d96b78..0000000000 --- a/web/app/components/base/portal-to-follow-elem/use-context-menu-floating.spec.tsx +++ /dev/null @@ -1,183 +0,0 @@ -import { FloatingPortal } from '@floating-ui/react' -import { cleanup, fireEvent, render, screen } from '@testing-library/react' -import * as React from 'react' -import { useContextMenuFloating } from './use-context-menu-floating' - -afterEach(cleanup) - -function TestContextMenu({ - open, - onOpenChange, - position, - placement, - offset: offsetValue, -}: { - open: boolean - onOpenChange: (open: boolean) => void - position: { x: number, y: number } - placement?: Parameters[0]['placement'] - offset?: Parameters[0]['offset'] -}) { - const { refs, floatingStyles, getFloatingProps, isPositioned } = useContextMenuFloating({ - open, - onOpenChange, - position, - placement, - offset: offsetValue, - }) - - if (!open) - return null - - return ( - -
- -
-
- ) -} - -describe('useContextMenuFloating', () => { - it('should render menu when open', () => { - render( - , - ) - - expect(screen.getByTestId('context-menu')).toBeInTheDocument() - }) - - it('should not render menu when closed', () => { - render( - , - ) - - expect(screen.queryByTestId('context-menu')).not.toBeInTheDocument() - }) - - it('should apply ARIA role="menu" to floating element', () => { - render( - , - ) - - const menu = screen.getByTestId('context-menu') - expect(menu).toHaveAttribute('role', 'menu') - }) - - it('should call onOpenChange(false) on Escape key', () => { - const handleOpenChange = vi.fn() - - render( - , - ) - - fireEvent.keyDown(document, { key: 'Escape' }) - expect(handleOpenChange).toHaveBeenCalled() - expect(handleOpenChange.mock.calls[0][0]).toBe(false) - }) - - it('should call onOpenChange(false) on outside click', () => { - const handleOpenChange = vi.fn() - - render( -
-
Outside
- -
, - ) - - fireEvent.pointerDown(screen.getByTestId('outside')) - expect(handleOpenChange).toHaveBeenCalled() - expect(handleOpenChange.mock.calls[0][0]).toBe(false) - }) - - it('should accept custom placement', () => { - render( - , - ) - - expect(screen.getByTestId('context-menu')).toBeInTheDocument() - }) - - it('should accept custom offset', () => { - render( - , - ) - - expect(screen.getByTestId('context-menu')).toBeInTheDocument() - }) - - it('should accept offset as object', () => { - render( - , - ) - - expect(screen.getByTestId('context-menu')).toBeInTheDocument() - }) - - it('should update position when coordinates change', () => { - const { rerender } = render( - , - ) - - const menu = screen.getByTestId('context-menu') - expect(menu).toBeInTheDocument() - - rerender( - , - ) - - expect(screen.getByTestId('context-menu')).toBeInTheDocument() - }) -}) diff --git a/web/app/components/base/portal-to-follow-elem/use-context-menu-floating.ts b/web/app/components/base/portal-to-follow-elem/use-context-menu-floating.ts deleted file mode 100644 index 870a59acd2..0000000000 --- a/web/app/components/base/portal-to-follow-elem/use-context-menu-floating.ts +++ /dev/null @@ -1,92 +0,0 @@ -import type { OffsetOptions, Placement } from '@floating-ui/react' -import { - flip, - offset, - shift, - useDismiss, - useFloating, - useInteractions, - useRole, -} from '@floating-ui/react' -import { useEffect, useMemo, useRef } from 'react' - -export type Position = { - x: number - y: number -} - -export type UseContextMenuFloatingOptions = { - open: boolean - onOpenChange: (open: boolean) => void - position: Position - placement?: Placement - offset?: number | OffsetOptions -} - -export function useContextMenuFloating({ - open, - onOpenChange, - position, - placement = 'bottom-start', - offset: offsetValue = 0, -}: UseContextMenuFloatingOptions) { - const onOpenChangeRef = useRef(onOpenChange) - onOpenChangeRef.current = onOpenChange - - const data = useFloating({ - placement, - open, - onOpenChange, - middleware: [ - offset(offsetValue), - flip({ - crossAxis: placement.includes('-'), - fallbackAxisSideDirection: 'start', - padding: 5, - }), - shift({ padding: 5 }), - ], - }) - - const { context, refs, floatingStyles, isPositioned } = data - - useEffect(() => { - refs.setPositionReference({ - getBoundingClientRect: () => ({ - width: 0, - height: 0, - x: position.x, - y: position.y, - top: position.y, - left: position.x, - right: position.x, - bottom: position.y, - }), - }) - }, [position.x, position.y, refs]) - - useEffect(() => { - if (!open) - return - const handler = () => onOpenChangeRef.current(false) - window.addEventListener('scroll', handler, { capture: true, passive: true }) - return () => window.removeEventListener('scroll', handler, { capture: true }) - }, [open]) - - const dismiss = useDismiss(context) - const role = useRole(context, { role: 'menu' }) - const interactions = useInteractions([dismiss, role]) - - return useMemo( - () => ({ - refs: { - setFloating: refs.setFloating, - }, - floatingStyles, - getFloatingProps: interactions.getFloatingProps, - context, - isPositioned, - }), - [context, floatingStyles, isPositioned, refs.setFloating, interactions.getFloatingProps], - ) -} diff --git a/web/app/components/sub-graph/components/config-panel.tsx b/web/app/components/sub-graph/components/config-panel.tsx index c555f124b6..e4d5771fbd 100644 --- a/web/app/components/sub-graph/components/config-panel.tsx +++ b/web/app/components/sub-graph/components/config-panel.tsx @@ -10,7 +10,7 @@ import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem-plus' +} from '@/app/components/base/portal-to-follow-elem' import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor' import Field from '@/app/components/workflow/nodes/_base/components/field' import VarReferencePicker from '@/app/components/workflow/nodes/_base/components/variable/var-reference-picker' diff --git a/web/app/components/workflow/comment/thread.tsx b/web/app/components/workflow/comment/thread.tsx index 0d100788d6..9daac87b9e 100644 --- a/web/app/components/workflow/comment/thread.tsx +++ b/web/app/components/workflow/comment/thread.tsx @@ -9,7 +9,7 @@ import { useReactFlow, useViewport } from 'reactflow' import { Avatar } from '@/app/components/base/avatar' import Divider from '@/app/components/base/divider' import InlineDeleteConfirm from '@/app/components/base/inline-delete-confirm' -import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem-plus' +import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem' import Tooltip from '@/app/components/base/tooltip-plus' import { getUserColor } from '@/app/components/workflow/collaboration/utils/user-color' diff --git a/web/app/components/workflow/header/online-users.tsx b/web/app/components/workflow/header/online-users.tsx index b183c1ba39..783b07a094 100644 --- a/web/app/components/workflow/header/online-users.tsx +++ b/web/app/components/workflow/header/online-users.tsx @@ -9,7 +9,7 @@ import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem-plus' +} from '@/app/components/base/portal-to-follow-elem' import Tooltip from '@/app/components/base/tooltip-plus' import { useAppContext } from '@/context/app-context' diff --git a/web/app/components/workflow/nodes/llm/components/config-context-item.tsx b/web/app/components/workflow/nodes/llm/components/config-context-item.tsx index eaff634017..d662712e45 100644 --- a/web/app/components/workflow/nodes/llm/components/config-context-item.tsx +++ b/web/app/components/workflow/nodes/llm/components/config-context-item.tsx @@ -9,7 +9,7 @@ import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem-plus' +} from '@/app/components/base/portal-to-follow-elem' import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars' import VariableLabelInSelect from '@/app/components/workflow/nodes/_base/components/variable/variable-label/variable-label-in-select' import { BlockEnum } from '@/app/components/workflow/types' diff --git a/web/app/components/workflow/nodes/llm/components/config-prompt.tsx b/web/app/components/workflow/nodes/llm/components/config-prompt.tsx index 218b4c087e..ea7b3a9515 100644 --- a/web/app/components/workflow/nodes/llm/components/config-prompt.tsx +++ b/web/app/components/workflow/nodes/llm/components/config-prompt.tsx @@ -13,7 +13,7 @@ import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem-plus' +} from '@/app/components/base/portal-to-follow-elem' import AddButton from '@/app/components/workflow/nodes/_base/components/add-button' import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor' import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars' diff --git a/web/app/components/workflow/nodes/tool/components/context-generate-modal/components/right-panel.tsx b/web/app/components/workflow/nodes/tool/components/context-generate-modal/components/right-panel.tsx index f29c8b6265..5d471254ea 100644 --- a/web/app/components/workflow/nodes/tool/components/context-generate-modal/components/right-panel.tsx +++ b/web/app/components/workflow/nodes/tool/components/context-generate-modal/components/right-panel.tsx @@ -9,7 +9,7 @@ import Button from '@/app/components/base/button' import { CopyFeedbackNew } from '@/app/components/base/copy-feedback' import { CodeAssistant } from '@/app/components/base/icons/src/vender/line/general' import Loading from '@/app/components/base/loading' -import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem-plus' +import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem' import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor' import { CodeLanguage } from '@/app/components/workflow/nodes/code/types' import { cn } from '@/utils/classnames' diff --git a/web/app/components/workflow/skill/editor/skill-editor/plugins/file-picker-block.tsx b/web/app/components/workflow/skill/editor/skill-editor/plugins/file-picker-block.tsx index 8e4a52accd..c8216141f1 100644 --- a/web/app/components/workflow/skill/editor/skill-editor/plugins/file-picker-block.tsx +++ b/web/app/components/workflow/skill/editor/skill-editor/plugins/file-picker-block.tsx @@ -11,7 +11,7 @@ import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem-plus' +} from '@/app/components/base/portal-to-follow-elem' import { useBasicTypeaheadTriggerMatch } from '@/app/components/base/prompt-editor/hooks' import { $splitNodeContainingQuery } from '@/app/components/base/prompt-editor/utils' import { FilePickerPanel } from './file-picker-panel' diff --git a/web/app/components/workflow/skill/editor/skill-editor/plugins/file-picker-upload-modal.tsx b/web/app/components/workflow/skill/editor/skill-editor/plugins/file-picker-upload-modal.tsx index 92aa0d9ea4..d73ca0eab9 100644 --- a/web/app/components/workflow/skill/editor/skill-editor/plugins/file-picker-upload-modal.tsx +++ b/web/app/components/workflow/skill/editor/skill-editor/plugins/file-picker-upload-modal.tsx @@ -12,7 +12,7 @@ import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem-plus' +} from '@/app/components/base/portal-to-follow-elem' import { Dialog, DialogCloseButton, DialogContent, DialogTitle } from '@/app/components/base/ui/dialog' import { toast } from '@/app/components/base/ui/toast' import OptionCard from '@/app/components/workflow/nodes/_base/components/option-card' diff --git a/web/app/components/workflow/skill/editor/skill-editor/plugins/file-reference-block/component.tsx b/web/app/components/workflow/skill/editor/skill-editor/plugins/file-reference-block/component.tsx index 82bac137f6..ad2c511982 100644 --- a/web/app/components/workflow/skill/editor/skill-editor/plugins/file-reference-block/component.tsx +++ b/web/app/components/workflow/skill/editor/skill-editor/plugins/file-reference-block/component.tsx @@ -13,7 +13,7 @@ import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem-plus' +} from '@/app/components/base/portal-to-follow-elem' import { useSelectOrDelete } from '@/app/components/base/prompt-editor/hooks' import Tooltip from '@/app/components/base/tooltip-plus' import { START_TAB_ID } from '@/app/components/workflow/skill/constants' diff --git a/web/app/components/workflow/skill/viewer/sqlite-file-preview/table-selector.tsx b/web/app/components/workflow/skill/viewer/sqlite-file-preview/table-selector.tsx index 4fd7df1c62..2202f1be05 100644 --- a/web/app/components/workflow/skill/viewer/sqlite-file-preview/table-selector.tsx +++ b/web/app/components/workflow/skill/viewer/sqlite-file-preview/table-selector.tsx @@ -7,7 +7,7 @@ import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem-plus' +} from '@/app/components/base/portal-to-follow-elem' import { cn } from '@/utils/classnames' type TableSelectorProps = { diff --git a/web/eslint-suppressions.json b/web/eslint-suppressions.json index b38a0f3f9d..d0a2c6a0b2 100644 --- a/web/eslint-suppressions.json +++ b/web/eslint-suppressions.json @@ -6160,6 +6160,11 @@ "count": 2 } }, + "app/components/sub-graph/components/config-panel.tsx": { + "no-restricted-imports": { + "count": 1 + } + }, "app/components/tools/edit-custom-collection-modal/config-credentials.tsx": { "no-restricted-imports": { "count": 1 @@ -6662,6 +6667,11 @@ "count": 2 } }, + "app/components/workflow/comment/thread.tsx": { + "no-restricted-imports": { + "count": 1 + } + }, "app/components/workflow/context.tsx": { "react-refresh/only-export-components": { "count": 1 @@ -6693,6 +6703,11 @@ "count": 1 } }, + "app/components/workflow/header/online-users.tsx": { + "no-restricted-imports": { + "count": 1 + } + }, "app/components/workflow/header/restoring-title.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 @@ -7047,11 +7062,6 @@ "count": 1 } }, - "app/components/workflow/nodes/_base/components/mcp-tool-availability.tsx": { - "react-refresh/only-export-components": { - "count": 1 - } - }, "app/components/workflow/nodes/_base/components/mcp-tool-not-support-tooltip.tsx": { "no-restricted-imports": { "count": 1 @@ -8152,6 +8162,11 @@ "count": 1 } }, + "app/components/workflow/nodes/llm/components/config-context-item.tsx": { + "no-restricted-imports": { + "count": 1 + } + }, "app/components/workflow/nodes/llm/components/config-prompt-item.tsx": { "no-restricted-imports": { "count": 1 @@ -8161,6 +8176,9 @@ } }, "app/components/workflow/nodes/llm/components/config-prompt.tsx": { + "no-restricted-imports": { + "count": 1 + }, "react/unsupported-syntax": { "count": 1 }, @@ -8575,6 +8593,11 @@ "count": 5 } }, + "app/components/workflow/nodes/tool/components/context-generate-modal/components/right-panel.tsx": { + "no-restricted-imports": { + "count": 1 + } + }, "app/components/workflow/nodes/tool/components/copy-id.tsx": { "no-restricted-imports": { "count": 1 @@ -8599,14 +8622,6 @@ "count": 1 } }, - "app/components/workflow/nodes/tool/components/mixed-variable-text-input/placeholder.tsx": { - "tailwindcss/enforce-consistent-class-order": { - "count": 2 - }, - "ts/no-explicit-any": { - "count": 1 - } - }, "app/components/workflow/nodes/tool/components/tool-form/index.tsx": { "ts/no-explicit-any": { "count": 1 @@ -9299,6 +9314,26 @@ "count": 1 } }, + "app/components/workflow/skill/editor/skill-editor/plugins/file-picker-block.tsx": { + "no-restricted-imports": { + "count": 1 + } + }, + "app/components/workflow/skill/editor/skill-editor/plugins/file-picker-upload-modal.tsx": { + "no-restricted-imports": { + "count": 1 + } + }, + "app/components/workflow/skill/editor/skill-editor/plugins/file-reference-block/component.tsx": { + "no-restricted-imports": { + "count": 1 + } + }, + "app/components/workflow/skill/viewer/sqlite-file-preview/table-selector.tsx": { + "no-restricted-imports": { + "count": 1 + } + }, "app/components/workflow/store/workflow/debug/inspect-vars-slice.ts": { "ts/no-explicit-any": { "count": 2 diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs index 5fa9a3f3a3..b1f892b323 100644 --- a/web/eslint.config.mjs +++ b/web/eslint.config.mjs @@ -170,7 +170,6 @@ export default antfu( files: [ 'app/components/base/ui/**/*.tsx', 'app/components/base/avatar/**/*.tsx', - 'app/components/base/portal-to-follow-elem-plus/**/*.tsx', ], rules: { 'react-refresh/only-export-components': 'off', diff --git a/web/eslint.constants.mjs b/web/eslint.constants.mjs index 741b430af0..9992d94f36 100644 --- a/web/eslint.constants.mjs +++ b/web/eslint.constants.mjs @@ -92,8 +92,6 @@ export const OVERLAY_RESTRICTED_IMPORT_PATTERNS = [ ] export const OVERLAY_MIGRATION_LEGACY_BASE_FILES = [ - 'app/components/base/portal-to-follow-elem-plus/index.tsx', - 'app/components/base/portal-to-follow-elem-plus/use-context-menu-floating.ts', 'app/components/base/chat/chat-with-history/header/mobile-operation-dropdown.tsx', 'app/components/base/chat/chat-with-history/header/operation.tsx', 'app/components/base/chat/chat-with-history/inputs-form/view-form-dropdown.tsx',