diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/prompt-editor/prompt-editor.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/prompt-editor/prompt-editor.tsx index b2633d28841..46bd57d17ea 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/prompt-editor/prompt-editor.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/prompt-editor/prompt-editor.tsx @@ -27,6 +27,14 @@ export interface PromptEditorProps extends PromptEditorKeyPolicy { placeholder?: string /** Focuses the editor (caret at end) on mount. */ autoFocus?: boolean + /** + * Renders the editor as a non-editable display surface: the textarea becomes + * `readOnly` (so the chip overlay still paints `@`-mention / `/`-skill chips + * and the text stays selectable/copyable) and the caret-anchored resource and + * skill menus are not mounted. Use for read-only records — e.g. a finished + * scheduled task — where the prompt should render with chips but not be edited. + */ + readOnly?: boolean /** * Layout/sizing only — a height cap (`max-h-[200px]`) or fill (`flex-1`) * for the scroll container. The text chrome is owned by the editor. @@ -56,6 +64,7 @@ export function PromptEditor({ editor, placeholder, autoFocus = false, + readOnly = false, className, 'aria-label': ariaLabel, onSubmit, @@ -73,22 +82,24 @@ export function PromptEditor({ }, [value, textareaRef]) useEffect(() => { - if (autoFocus) editor.focusAtEnd() + if (autoFocus && !readOnly) editor.focusAtEnd() // eslint-disable-next-line react-hooks/exhaustive-deps -- mount-only focus }, []) /** * Clicking the editor's empty regions (padding, space below the last line) * focuses the textarea; clicks on the textarea itself keep native caret - * placement. + * placement. No-op in read-only mode: the surface is display-only, so a + * padding click should not pull focus onto the non-editable textarea. */ const handleSurfaceClick = useCallback( (e: React.MouseEvent) => { + if (readOnly) return if (e.target === textareaRef.current) return if ((e.target as HTMLElement).closest('button')) return textareaRef.current?.focus() }, - [textareaRef] + [readOnly, textareaRef] ) const overlayContent = useMemo(() => { @@ -167,38 +178,45 @@ export function PromptEditor({