Skip to content

Commit 3a9630e

Browse files
BillLeoutsakosvl346Bill Leoutsakoswaleedlatif1
authored
improvement(ui): share workflow preview actions (#8065)
* improvement(ui): share workflow preview actions * improvement(ui): reuse inline and overlay workflow actions * refactor(emcn): share Code.Viewer appearances (#8238) * Add shared Code.Viewer appearances for product surfaces * Test flat virtualized Code.Viewer terminal chrome --------- Co-authored-by: Bill Leoutsakos <billleoutsakos@Bills-MacBook-Pro.local> * Share table sidebar shell and scroll body (#8249) * Share table sidebar shell and scroll body * test(tables): cover shared sidebar dialog state * test(tables): preserve sidebar scroll state --------- Co-authored-by: Bill Leoutsakos <billleoutsakos@Bills-MacBook-Pro.local> * Keep workflow preview values readable (#8256) * fix(ui): keep preview values readable and restore version tint * fix(ui): keep preview file actions inert --------- Co-authored-by: Bill Leoutsakos <billleoutsakos@Bills-MacBook-Pro.local> --------- Co-authored-by: Bill Leoutsakos <billleoutsakos@Bills-MacBook-Pro.local> Co-authored-by: Waleed <walif6@gmail.com>
1 parent 9c2953d commit 3a9630e

32 files changed

Lines changed: 468 additions & 156 deletions

File tree

‎apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/trace-view/trace-view.tsx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,8 @@ function DetailCodeSection({
495495
<Code.Viewer
496496
code={jsonString}
497497
language='json'
498-
className='max-w-full rounded-md border-0 bg-[var(--surface-4)]! [word-break:break-all] dark:bg-[var(--surface-3)]!'
498+
appearance='inspection'
499+
className='max-w-full [word-break:break-all]'
499500
wrapText
500501
searchQuery={isSearchActive ? searchQuery : undefined}
501502
currentMatchIndex={currentMatchIndex}

‎apps/sim/app/workspace/[workspaceId]/logs/components/log-details/log-details.tsx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,8 @@ export const WorkflowOutputSection = memo(
159159
<Code.Viewer
160160
code={jsonString}
161161
language='json'
162-
className='max-h-[300px] min-h-0 max-w-full rounded-md border-0 bg-[var(--surface-4)]! [word-break:break-all] dark:bg-[var(--surface-3)]!'
162+
appearance='inspection'
163+
className='max-h-[300px] min-h-0 max-w-full [word-break:break-all]'
163164
wrapText
164165
searchQuery={isSearchActive ? searchQuery : undefined}
165166
currentMatchIndex={currentMatchIndex}

‎apps/sim/app/workspace/[workspaceId]/settings/components/workflow-mcp-servers/workflow-mcp-servers.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,7 @@ function ServerDetailView({
607607
: 'json'
608608
}
609609
wrapText
610-
className='min-h-0! rounded-sm border border-[var(--border-1)]'
610+
className='min-h-0!'
611611
/>
612612
{activeConfigTab === 'cursor' && (
613613
<a

‎apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/column-config-sidebar/column-config-sidebar.tsx‎

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
Button,
66
ChipCombobox,
77
ChipInput,
8-
cn,
98
FieldDivider,
109
Label,
1110
Switch,
@@ -29,6 +28,10 @@ import {
2928
TableSidebarHeader,
3029
TableSidebarHeaderAction,
3130
} from '@/app/workspace/[workspaceId]/tables/[tableId]/components/table-sidebar-header/table-sidebar-header'
31+
import {
32+
TableSidebarScrollBody,
33+
TableSidebarShell,
34+
} from '@/app/workspace/[workspaceId]/tables/[tableId]/components/table-sidebar-layout'
3235
import { useAddTableColumn, useUpdateColumn } from '@/hooks/queries/tables'
3336
import { SelectOptionsEditor } from '../select-field'
3437
import { columnTypeOptionsForTable } from './column-types'
@@ -100,18 +103,11 @@ export function ColumnConfigSidebar(props: ColumnConfigSidebarProps) {
100103
// different column / mode remounts and re-seeds state from props.
101104
const open = props.config !== null
102105
return (
103-
<aside
104-
role='dialog'
105-
aria-label='Configure column'
106-
className={cn(
107-
'absolute top-0 right-0 bottom-0 z-[var(--z-modal)] flex w-[400px] flex-col overflow-hidden border-[var(--border)] border-l bg-[var(--bg)] transition-transform duration-200 ease-out',
108-
open ? 'translate-x-0 shadow-overlay' : 'translate-x-full'
109-
)}
110-
>
106+
<TableSidebarShell open={open} aria-label='Configure column'>
111107
{props.config && (
112108
<ColumnConfigBody key={configKey(props.config)} {...props} config={props.config} />
113109
)}
114-
</aside>
110+
</TableSidebarShell>
115111
)
116112
}
117113

@@ -274,7 +270,7 @@ function ColumnConfigBody({
274270
</TableSidebarHeaderAction>
275271
</TableSidebarHeader>
276272

277-
<div className='flex-1 overflow-y-auto overflow-x-hidden px-2 pt-3 pb-2 [overflow-anchor:none]'>
273+
<TableSidebarScrollBody>
278274
{/* `disabled` on the fieldset reaches every native control inside,
279275
including the comboboxes' trigger buttons; `contents` keeps the
280276
existing layout. Values stay readable and selectable. */}
@@ -383,7 +379,7 @@ function ColumnConfigBody({
383379
</>
384380
)}
385381
</fieldset>
386-
</div>
382+
</TableSidebarScrollBody>
387383

388384
<div className='flex items-center justify-end gap-2 border-[var(--border)] border-t px-2 py-3'>
389385
<Button variant='default' size='sm' onClick={onClose}>

‎apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/enrichments-sidebar/enrichment-config.tsx‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
TableSidebarHeader,
2626
TableSidebarHeaderAction,
2727
} from '@/app/workspace/[workspaceId]/tables/[tableId]/components/table-sidebar-header/table-sidebar-header'
28+
import { TableSidebarScrollBody } from '@/app/workspace/[workspaceId]/tables/[tableId]/components/table-sidebar-layout'
2829
import type { EnrichmentConfig as EnrichmentDef } from '@/enrichments/types'
2930
import {
3031
useAddWorkflowGroup,
@@ -252,7 +253,7 @@ export function EnrichmentConfig({
252253
</TableSidebarHeaderAction>
253254
</TableSidebarHeader>
254255

255-
<div className='flex-1 overflow-y-auto overflow-x-hidden px-2 pt-3 pb-2 [overflow-anchor:none]'>
256+
<TableSidebarScrollBody>
256257
<div className='flex flex-col gap-[9.5px]'>
257258
<Label className='flex items-baseline gap-1.5 whitespace-nowrap pl-0.5'>Inputs</Label>
258259
{enrichment.inputs.length === 0 ? (
@@ -362,7 +363,7 @@ export function EnrichmentConfig({
362363
/>
363364
</>
364365
)}
365-
</div>
366+
</TableSidebarScrollBody>
366367

367368
<div className='flex items-center justify-end gap-2 border-[var(--border)] border-t px-2 py-3'>
368369
<Button variant='default' size='sm' onClick={onClose}>

‎apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/enrichments-sidebar/enrichments-sidebar.tsx‎

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
'use client'
22

33
import { useState } from 'react'
4-
import { ChipInput, cn } from '@sim/emcn'
4+
import { ChipInput } from '@sim/emcn'
55
import { Search, X } from '@sim/emcn/icons'
66
import type { ColumnDefinition, WorkflowGroup } from '@/lib/table'
77
import {
88
TableSidebarHeader,
99
TableSidebarHeaderAction,
1010
} from '@/app/workspace/[workspaceId]/tables/[tableId]/components/table-sidebar-header/table-sidebar-header'
11+
import { TableSidebarShell } from '@/app/workspace/[workspaceId]/tables/[tableId]/components/table-sidebar-layout'
1112
import { ALL_ENRICHMENTS } from '@/enrichments'
1213
import { getEnrichment } from '@/enrichments/registry'
1314
import type { EnrichmentConfig as EnrichmentDef } from '@/enrichments/types'
@@ -31,16 +32,9 @@ interface EnrichmentsSidebarProps {
3132
*/
3233
export function EnrichmentsSidebar({ open, ...rest }: EnrichmentsSidebarProps) {
3334
return (
34-
<aside
35-
role='dialog'
36-
aria-label='Enrichments'
37-
className={cn(
38-
'absolute top-0 right-0 bottom-0 z-[var(--z-modal)] flex w-[400px] flex-col overflow-hidden border-[var(--border)] border-l bg-[var(--bg)] transition-transform duration-200 ease-out',
39-
open ? 'translate-x-0 shadow-overlay' : 'translate-x-full'
40-
)}
41-
>
35+
<TableSidebarShell open={open} aria-label='Enrichments'>
4236
{open && <EnrichmentsSidebarBody {...rest} />}
43-
</aside>
37+
</TableSidebarShell>
4438
)
4539
}
4640

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @vitest-environment jsdom
3+
*/
4+
import { act } from 'react'
5+
import { createRoot, type Root } from 'react-dom/client'
6+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
7+
import {
8+
TableSidebarScrollBody,
9+
TableSidebarShell,
10+
} from '@/app/workspace/[workspaceId]/tables/[tableId]/components/table-sidebar-layout'
11+
12+
let container: HTMLDivElement
13+
let root: Root
14+
15+
beforeEach(() => {
16+
globalThis.IS_REACT_ACT_ENVIRONMENT = true
17+
container = document.createElement('div')
18+
document.body.appendChild(container)
19+
root = createRoot(container)
20+
})
21+
22+
afterEach(() => {
23+
act(() => root.unmount())
24+
container.remove()
25+
})
26+
27+
describe('table sidebar layout', () => {
28+
it('keeps the labeled dialog and its form mounted while the sidebar slides closed', () => {
29+
function render(open: boolean) {
30+
act(() => {
31+
root.render(
32+
<TableSidebarShell open={open} aria-label='Configure workflow'>
33+
<TableSidebarScrollBody>
34+
<input aria-label='Workflow name' defaultValue='Existing workflow' />
35+
</TableSidebarScrollBody>
36+
</TableSidebarShell>
37+
)
38+
})
39+
}
40+
41+
render(true)
42+
const dialog = container.querySelector<HTMLElement>('[role="dialog"]')!
43+
const input = container.querySelector<HTMLInputElement>('input')!
44+
const scrollBody = input.parentElement!
45+
expect(dialog.getAttribute('aria-label')).toBe('Configure workflow')
46+
expect(dialog.classList.contains('translate-x-0')).toBe(true)
47+
expect(dialog.classList.contains('shadow-overlay')).toBe(true)
48+
49+
input.value = 'Edited workflow'
50+
scrollBody.scrollTop = 64
51+
render(false)
52+
expect(container.querySelector('[role="dialog"]')).toBe(dialog)
53+
expect(container.querySelector('input')).toBe(input)
54+
expect(input.value).toBe('Edited workflow')
55+
expect(input.parentElement).toBe(scrollBody)
56+
expect(scrollBody.scrollTop).toBe(64)
57+
expect(dialog.classList.contains('translate-x-full')).toBe(true)
58+
expect(dialog.classList.contains('shadow-overlay')).toBe(false)
59+
60+
render(true)
61+
expect(dialog.classList.contains('translate-x-0')).toBe(true)
62+
expect(input.value).toBe('Edited workflow')
63+
expect(scrollBody.scrollTop).toBe(64)
64+
})
65+
})
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import type { ReactNode } from 'react'
2+
import { cn } from '@sim/emcn'
3+
4+
interface TableSidebarShellProps {
5+
open: boolean
6+
'aria-label': string
7+
children: ReactNode
8+
}
9+
10+
/** The shared sliding shell for table configuration sidebars. */
11+
export function TableSidebarShell({
12+
open,
13+
children,
14+
'aria-label': ariaLabel,
15+
}: TableSidebarShellProps) {
16+
return (
17+
<aside
18+
role='dialog'
19+
aria-label={ariaLabel}
20+
className={cn(
21+
'absolute top-0 right-0 bottom-0 z-[var(--z-modal)] flex w-[400px] flex-col overflow-hidden border-[var(--border)] border-l bg-[var(--bg)] transition-transform duration-200 ease-out',
22+
open ? 'translate-x-0 shadow-overlay' : 'translate-x-full'
23+
)}
24+
>
25+
{children}
26+
</aside>
27+
)
28+
}
29+
30+
interface TableSidebarScrollBodyProps {
31+
children: ReactNode
32+
}
33+
34+
/** The scrolling form area shared by column, workflow, and enrichment settings. */
35+
export function TableSidebarScrollBody({ children }: TableSidebarScrollBodyProps) {
36+
return (
37+
<div className='flex-1 overflow-y-auto overflow-x-hidden px-2 pt-3 pb-2 [overflow-anchor:none]'>
38+
{children}
39+
</div>
40+
)
41+
}

‎apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/workflow-sidebar/workflow-sidebar.tsx‎

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,18 @@ import {
66
ChipCombobox,
77
ChipInput,
88
type ComboboxOptionGroup,
9-
cn,
109
FieldDisclosure,
1110
FieldDivider,
1211
Label,
1312
Loader,
1413
OverflowText,
1514
Switch,
16-
Tooltip,
1715
toast,
1816
} from '@sim/emcn'
1917
import { ArrowLeft, SquareArrowUpRight, X } from '@sim/emcn/icons'
2018
import { toError } from '@sim/utils/errors'
2119
import { generateId } from '@sim/utils/id'
20+
import { WorkflowPreviewAction } from '@/components/workflow/workflow-preview-action'
2221
import { findValidationIssue, isValidationError } from '@/lib/api/client/errors'
2322
import type {
2423
AddWorkflowGroupBodyInput,
@@ -50,6 +49,10 @@ import {
5049
TableSidebarHeader,
5150
TableSidebarHeaderAction,
5251
} from '@/app/workspace/[workspaceId]/tables/[tableId]/components/table-sidebar-header/table-sidebar-header'
52+
import {
53+
TableSidebarScrollBody,
54+
TableSidebarShell,
55+
} from '@/app/workspace/[workspaceId]/tables/[tableId]/components/table-sidebar-layout'
5356
import { PreviewWorkflow } from '@/app/workspace/[workspaceId]/w/components/preview'
5457
import { BlockTile } from '@/blocks/block-tile'
5558
import { useDeployedWorkflowState } from '@/hooks/queries/deployments'
@@ -150,18 +153,11 @@ interface BlockOutputGroup {
150153
export function WorkflowSidebar(props: WorkflowSidebarProps) {
151154
const open = props.config !== null
152155
return (
153-
<aside
154-
role='dialog'
155-
aria-label='Configure workflow'
156-
className={cn(
157-
'absolute top-0 right-0 bottom-0 z-[var(--z-modal)] flex w-[400px] flex-col overflow-hidden border-[var(--border)] border-l bg-[var(--bg)] transition-transform duration-200 ease-out',
158-
open ? 'translate-x-0 shadow-overlay' : 'translate-x-full'
159-
)}
160-
>
156+
<TableSidebarShell open={open} aria-label='Configure workflow'>
161157
{props.config && (
162158
<WorkflowSidebarBody key={configKey(props.config)} {...props} config={props.config} />
163159
)}
164-
</aside>
160+
</TableSidebarShell>
165161
)
166162
}
167163

@@ -654,7 +650,7 @@ export function WorkflowSidebarBody({
654650
</TableSidebarHeaderAction>
655651
</TableSidebarHeader>
656652

657-
<div className='flex-1 overflow-y-auto overflow-x-hidden px-2 pt-3 pb-2 [overflow-anchor:none]'>
653+
<TableSidebarScrollBody>
658654
{/* Single-output mode renames this column directly. */}
659655
{isEditOutputMode && (
660656
<>
@@ -711,27 +707,18 @@ export function WorkflowSidebarBody({
711707
/>
712708
</div>
713709
{!isEnrichment && (
714-
<Tooltip.Root>
715-
<Tooltip.Trigger asChild>
716-
<Button
717-
aria-label='Open workflow'
718-
type='button'
719-
variant='ghost'
720-
onClick={() =>
721-
window.open(
722-
`/workspace/${workspaceId}/w/${selectedWorkflowId}`,
723-
'_blank',
724-
'noopener,noreferrer'
725-
)
726-
}
727-
iconSize='compact-fixed'
728-
className='absolute right-[6px] bottom-1.5 z-10 cursor-pointer border border-[var(--border)] bg-[var(--surface-2)] hover-hover:bg-[var(--surface-4)]'
729-
>
730-
<SquareArrowUpRight className='size-[12px]' />
731-
</Button>
732-
</Tooltip.Trigger>
733-
<Tooltip.Content side='top'>Open workflow</Tooltip.Content>
734-
</Tooltip.Root>
710+
<WorkflowPreviewAction
711+
aria-label='Open workflow'
712+
onClick={() =>
713+
window.open(
714+
`/workspace/${workspaceId}/w/${selectedWorkflowId}`,
715+
'_blank',
716+
'noopener,noreferrer'
717+
)
718+
}
719+
>
720+
<SquareArrowUpRight className='size-[12px]' />
721+
</WorkflowPreviewAction>
735722
)}
736723
</>
737724
) : (
@@ -849,7 +836,7 @@ export function WorkflowSidebarBody({
849836
)}
850837
</>
851838
)}
852-
</div>
839+
</TableSidebarScrollBody>
853840

854841
<div className='flex items-center justify-end gap-2 border-[var(--border)] border-t px-2 py-3'>
855842
<Button variant='default' size='sm' onClick={onClose}>

‎apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/api/api.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ console.log(limits);`
493493
code={getSyncCommand()}
494494
language={LANGUAGE_SYNTAX[language]}
495495
wrapText
496-
className='min-h-0! rounded-sm border border-[var(--border-1)]'
496+
className='min-h-0!'
497497
/>
498498
</div>
499499

@@ -533,7 +533,7 @@ console.log(limits);`
533533
code={getStreamCommand()}
534534
language={LANGUAGE_SYNTAX[language]}
535535
wrapText
536-
className='min-h-0! rounded-sm border border-[var(--border-1)]'
536+
className='min-h-0!'
537537
/>
538538
</div>
539539

@@ -579,7 +579,7 @@ console.log(limits);`
579579
code={getAsyncCommand()}
580580
language={LANGUAGE_SYNTAX[language]}
581581
wrapText
582-
className='min-h-0! rounded-sm border border-[var(--border-1)]'
582+
className='min-h-0!'
583583
/>
584584
</div>
585585
)}

0 commit comments

Comments
 (0)