From 67dea87e016a2e24d9d5fdefc919d9e367efe628 Mon Sep 17 00:00:00 2001 From: Bill Leoutsakos Date: Thu, 24 Sep 2026 12:15:52 -0700 Subject: [PATCH 1/4] Use native buttons for terminal log rows --- .../entry-block-tile/entry-block-tile.tsx | 1 + .../components/terminal/components/index.ts | 1 + .../status-display/status-display.tsx | 10 +-- .../components/terminal-row-button.test.tsx | 74 ++++++++++++++++ .../components/terminal-row-button.tsx | 29 +++++++ .../components/terminal/terminal.tsx | 85 ++++++------------- packages/emcn/src/components/index.ts | 2 +- .../src/block-tile-view.test.tsx | 18 ++++ .../workflow-renderer/src/workflow-type.tsx | 7 +- 9 files changed, 156 insertions(+), 71 deletions(-) create mode 100644 apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/components/terminal-row-button.test.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/components/terminal-row-button.tsx diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/components/entry-block-tile/entry-block-tile.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/components/entry-block-tile/entry-block-tile.tsx index 88ada367e9a..5c718c1be07 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/components/entry-block-tile/entry-block-tile.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/components/entry-block-tile/entry-block-tile.tsx @@ -15,6 +15,7 @@ export interface EntryBlockTileProps { export const EntryBlockTile = memo(function EntryBlockTile({ blockType }: EntryBlockTileProps) { return ( - Running - - ) + return Running }) /** diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/components/terminal-row-button.test.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/components/terminal-row-button.test.tsx new file mode 100644 index 00000000000..25ddc693f00 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/components/terminal-row-button.test.tsx @@ -0,0 +1,74 @@ +/** + * @vitest-environment jsdom + */ +import { act } from 'react' +import { createRoot, type Root } from 'react-dom/client' +import { renderToStaticMarkup } from 'react-dom/server' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { ROW_STYLES } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/types' +import { StatusDisplay } from './status-display' +import { TerminalRowButton } from './terminal-row-button' + +let root: Root +let host: HTMLDivElement + +beforeEach(() => { + ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true + host = document.createElement('div') + document.body.appendChild(host) + root = createRoot(host) +}) + +afterEach(() => { + act(() => root.unmount()) + host.remove() +}) + +describe('TerminalRowButton', () => { + it('renders selected disclosure semantics and handles one native click locally', () => { + const onClick = vi.fn() + const onParentClick = vi.fn() + + act(() => { + root.render( +
+ + Workflow result + +
+ ) + }) + + const button = host.querySelector('button')! + expect(button.type).toBe('button') + expect(button.getAttribute('aria-expanded')).toBe('true') + expect(button.getAttribute('data-entry-id')).toBe('entry-1') + expect(button.className).toBe(ROW_STYLES.rowSelected) + act(() => button.focus()) + expect(document.activeElement).toBe(button) + act(() => button.click()) + expect(onClick).toHaveBeenCalledTimes(1) + expect(onParentClick).not.toHaveBeenCalled() + }) + + it('keeps the base chip row when selection and expansion are absent', () => { + act(() => { + root.render(Block output) + }) + const button = host.querySelector('button')! + expect(button.className).toBe(ROW_STYLES.row) + expect(button.hasAttribute('aria-expanded')).toBe(false) + expect(button.textContent).toBe('Block output') + }) + + it('keeps the running status inline inside a native button', () => { + const html = renderToStaticMarkup( + + + + ) + expect(html).toMatch(/^Running') + expect(html).not.toContain(' { + /** Use the selected chip surface for the active output row. */ + selected?: boolean +} + +/** Native terminal row action with the established EMCN chip surface. */ +export function TerminalRowButton({ + selected = false, + className, + onClick, + type, + ...props +}: TerminalRowButtonProps) { + return ( +