diff --git a/web/app/components/base/prompt-editor/__tests__/sandbox-placeholder.spec.tsx b/web/app/components/base/prompt-editor/__tests__/sandbox-placeholder.spec.tsx new file mode 100644 index 0000000000..22d69cdd11 --- /dev/null +++ b/web/app/components/base/prompt-editor/__tests__/sandbox-placeholder.spec.tsx @@ -0,0 +1,59 @@ +import type { ReactElement } from 'react' +import { render, screen } from '@testing-library/react' +import SandboxPlaceholder from '../sandbox-placeholder' + +vi.mock('react-i18next', () => ({ + Trans: ({ i18nKey, components = [] }: { + i18nKey: string + components?: ReactElement[] + }) => ( +
+ {components} +
+ ), +})) + +describe('SandboxPlaceholder', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + // Rendering branches for sandbox availability and tool-block support. + describe('Rendering', () => { + it('should render nothing when sandbox is not supported', () => { + const { container } = render() + + expect(container).toBeEmptyDOMElement() + expect(screen.queryByTestId('sandbox-placeholder-trans')).not.toBeInTheDocument() + }) + + it('should render slash and insert tokens when tool blocks are disabled', () => { + const { container } = render( + , + ) + + expect(screen.getByTestId('sandbox-placeholder-trans')).toHaveAttribute('data-i18n-key', 'promptEditor.placeholderSandboxNoTools') + + const spans = container.querySelectorAll('span') + expect(spans).toHaveLength(2) + expect(spans[0]).toHaveClass('inline-flex', 'bg-components-kbd-bg-gray', 'system-kbd') + expect(spans[1]).toHaveClass('border-b', 'border-dotted', 'border-current') + }) + + it('should render slash insert at and tools tokens when tool blocks are enabled', () => { + const { container } = render() + + expect(screen.getByTestId('sandbox-placeholder-trans')).toHaveAttribute('data-i18n-key', 'promptEditor.placeholderSandbox') + + const spans = container.querySelectorAll('span') + expect(spans).toHaveLength(4) + expect(spans[0]).toHaveClass('inline-flex', 'bg-components-kbd-bg-gray', 'system-kbd') + expect(spans[1]).toHaveClass('border-b', 'border-dotted', 'border-current') + expect(spans[2]).toHaveClass('inline-flex', 'bg-components-kbd-bg-gray', 'system-kbd') + expect(spans[3]).toHaveClass('border-b', 'border-dotted', 'border-current') + }) + }) +}) diff --git a/web/app/components/base/prompt-editor/index.tsx b/web/app/components/base/prompt-editor/index.tsx index 9f202a3d62..141b960249 100644 --- a/web/app/components/base/prompt-editor/index.tsx +++ b/web/app/components/base/prompt-editor/index.tsx @@ -39,7 +39,6 @@ import { } from 'lexical' import * as React from 'react' import { useEffect, useState } from 'react' -import { Trans } from 'react-i18next' import { WorkflowContext } from '@/app/components/workflow/context' import { HooksStoreContext } from '@/app/components/workflow/hooks-store/provider' import { FileReferenceNode } from '@/app/components/workflow/skill/editor/skill-editor/plugins/file-reference-block/node' @@ -118,6 +117,7 @@ import { WorkflowVariableBlockNode, WorkflowVariableBlockReplacementBlock, } from './plugins/workflow-variable-block' +import SandboxPlaceholder from './sandbox-placeholder' import { textToEditorState } from './utils' const ValueSyncPlugin: FC<{ value?: string }> = ({ value }) => { @@ -342,50 +342,6 @@ const PromptEditorContent: FC = ({ enabled: Boolean(isSupportSandbox), }), [isSupportSandbox]) - const sandboxPlaceHolder = React.useMemo(() => { - if (!isSupportSandbox) - return null - const i18nKey = disableToolBlocks - ? 'promptEditor.placeholderSandboxNoTools' - : 'promptEditor.placeholderSandbox' - const components = disableToolBlocks - ? [ - , - , - ] - : [ - , - , - , - , - ] - return ( - - ) - }, [disableToolBlocks, isSupportSandbox]) - const [floatingAnchorElem, setFloatingAnchorElem] = useState(null) const onRef = (floatingAnchorElement: HTMLDivElement | null) => { @@ -415,7 +371,12 @@ const PromptEditorContent: FC = ({ )} placeholder={( + )} className={cn('truncate', placeholderClassName)} compact={compact} /> diff --git a/web/app/components/base/prompt-editor/sandbox-placeholder.tsx b/web/app/components/base/prompt-editor/sandbox-placeholder.tsx new file mode 100644 index 0000000000..5fb348bee0 --- /dev/null +++ b/web/app/components/base/prompt-editor/sandbox-placeholder.tsx @@ -0,0 +1,57 @@ +import type { FC, PropsWithChildren, ReactElement } from 'react' +import { Trans } from 'react-i18next' + +type SandboxPlaceholderTokenProps = PropsWithChildren<{ + variant: 'kbd' | 'action' +}> + +const SandboxPlaceholderToken: FC = ({ variant, children }) => { + if (variant === 'kbd') { + return ( + + {children} + + ) + } + + return ( + + {children} + + ) +} + +type SandboxPlaceholderProps = { + disableToolBlocks?: boolean + isSupportSandbox?: boolean +} + +const SandboxPlaceholder: FC = ({ + disableToolBlocks, + isSupportSandbox, +}) => { + if (!isSupportSandbox) + return null + + const components: ReactElement[] = [ + , + , + ] + + if (!disableToolBlocks) { + components.push( + , + , + ) + } + + return ( + + ) +} + +export default SandboxPlaceholder