Skip to content

Commit e672467

Browse files
committed
feat(terminal): added terminal context menu (#2692)
1 parent afef3e1 commit e672467

File tree

9 files changed

+486
-47
lines changed

9 files changed

+486
-47
lines changed

apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/components/chunk-context-menu/chunk-context-menu.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
'use client'
22

3-
import { Popover, PopoverAnchor, PopoverContent, PopoverItem } from '@/components/emcn'
3+
import {
4+
Popover,
5+
PopoverAnchor,
6+
PopoverContent,
7+
PopoverDivider,
8+
PopoverItem,
9+
} from '@/components/emcn'
410

511
interface ChunkContextMenuProps {
612
isOpen: boolean
@@ -102,6 +108,7 @@ export function ChunkContextMenu({
102108
<PopoverContent ref={menuRef} align='start' side='bottom' sideOffset={4}>
103109
{hasChunk ? (
104110
<>
111+
{/* Navigation */}
105112
{!isMultiSelect && onOpenInNewTab && (
106113
<PopoverItem
107114
onClick={() => {
@@ -112,6 +119,9 @@ export function ChunkContextMenu({
112119
Open in new tab
113120
</PopoverItem>
114121
)}
122+
{!isMultiSelect && onOpenInNewTab && <PopoverDivider />}
123+
124+
{/* Edit and copy actions */}
115125
{!isMultiSelect && onEdit && (
116126
<PopoverItem
117127
onClick={() => {
@@ -132,6 +142,9 @@ export function ChunkContextMenu({
132142
Copy content
133143
</PopoverItem>
134144
)}
145+
{!isMultiSelect && (onEdit || onCopyContent) && <PopoverDivider />}
146+
147+
{/* State toggle */}
135148
{onToggleEnabled && (
136149
<PopoverItem
137150
disabled={disableToggleEnabled}
@@ -143,6 +156,9 @@ export function ChunkContextMenu({
143156
{getToggleLabel()}
144157
</PopoverItem>
145158
)}
159+
160+
{/* Destructive action */}
161+
{onToggleEnabled && onDelete && <PopoverDivider />}
146162
{onDelete && (
147163
<PopoverItem
148164
disabled={disableDelete}

apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/document-context-menu/document-context-menu.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
'use client'
22

3-
import { Popover, PopoverAnchor, PopoverContent, PopoverItem } from '@/components/emcn'
3+
import {
4+
Popover,
5+
PopoverAnchor,
6+
PopoverContent,
7+
PopoverDivider,
8+
PopoverItem,
9+
} from '@/components/emcn'
410

511
interface DocumentContextMenuProps {
612
isOpen: boolean
@@ -107,6 +113,7 @@ export function DocumentContextMenu({
107113
<PopoverContent ref={menuRef} align='start' side='bottom' sideOffset={4}>
108114
{hasDocument ? (
109115
<>
116+
{/* Navigation */}
110117
{!isMultiSelect && onOpenInNewTab && (
111118
<PopoverItem
112119
onClick={() => {
@@ -117,6 +124,9 @@ export function DocumentContextMenu({
117124
Open in new tab
118125
</PopoverItem>
119126
)}
127+
{!isMultiSelect && onOpenInNewTab && <PopoverDivider />}
128+
129+
{/* Edit and view actions */}
120130
{!isMultiSelect && onRename && (
121131
<PopoverItem
122132
onClick={() => {
@@ -137,6 +147,9 @@ export function DocumentContextMenu({
137147
View tags
138148
</PopoverItem>
139149
)}
150+
{!isMultiSelect && (onRename || (hasTags && onViewTags)) && <PopoverDivider />}
151+
152+
{/* State toggle */}
140153
{onToggleEnabled && (
141154
<PopoverItem
142155
disabled={disableToggleEnabled}
@@ -148,6 +161,9 @@ export function DocumentContextMenu({
148161
{getToggleLabel()}
149162
</PopoverItem>
150163
)}
164+
165+
{/* Destructive action */}
166+
{onToggleEnabled && onDelete && <PopoverDivider />}
151167
{onDelete && (
152168
<PopoverItem
153169
disabled={disableDelete}

apps/sim/app/workspace/[workspaceId]/knowledge/components/knowledge-base-context-menu/knowledge-base-context-menu.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
'use client'
22

3-
import { Popover, PopoverAnchor, PopoverContent, PopoverItem } from '@/components/emcn'
3+
import {
4+
Popover,
5+
PopoverAnchor,
6+
PopoverContent,
7+
PopoverDivider,
8+
PopoverItem,
9+
} from '@/components/emcn'
410

511
interface KnowledgeBaseContextMenuProps {
612
/**
@@ -104,6 +110,7 @@ export function KnowledgeBaseContextMenu({
104110
}}
105111
/>
106112
<PopoverContent ref={menuRef} align='start' side='bottom' sideOffset={4}>
113+
{/* Navigation */}
107114
{showOpenInNewTab && onOpenInNewTab && (
108115
<PopoverItem
109116
onClick={() => {
@@ -114,6 +121,9 @@ export function KnowledgeBaseContextMenu({
114121
Open in new tab
115122
</PopoverItem>
116123
)}
124+
{showOpenInNewTab && onOpenInNewTab && <PopoverDivider />}
125+
126+
{/* View and copy actions */}
117127
{showViewTags && onViewTags && (
118128
<PopoverItem
119129
onClick={() => {
@@ -134,6 +144,9 @@ export function KnowledgeBaseContextMenu({
134144
Copy ID
135145
</PopoverItem>
136146
)}
147+
{((showViewTags && onViewTags) || onCopyId) && <PopoverDivider />}
148+
149+
{/* Edit action */}
137150
{showEdit && onEdit && (
138151
<PopoverItem
139152
disabled={disableEdit}
@@ -145,6 +158,9 @@ export function KnowledgeBaseContextMenu({
145158
Edit
146159
</PopoverItem>
147160
)}
161+
162+
{/* Destructive action */}
163+
{showEdit && onEdit && showDelete && onDelete && <PopoverDivider />}
148164
{showDelete && onDelete && (
149165
<PopoverItem
150166
disabled={disableDelete}

apps/sim/app/workspace/[workspaceId]/logs/components/log-row-context-menu/log-row-context-menu.tsx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
'use client'
22

33
import type { RefObject } from 'react'
4-
import { Popover, PopoverAnchor, PopoverContent, PopoverItem } from '@/components/emcn'
4+
import {
5+
Popover,
6+
PopoverAnchor,
7+
PopoverContent,
8+
PopoverDivider,
9+
PopoverItem,
10+
} from '@/components/emcn'
511
import type { WorkflowLog } from '@/stores/logs/filters/types'
612

713
interface LogRowContextMenuProps {
@@ -50,7 +56,7 @@ export function LogRowContextMenu({
5056
}}
5157
/>
5258
<PopoverContent ref={menuRef} align='start' side='bottom' sideOffset={4}>
53-
{/* Copy Execution ID */}
59+
{/* Copy action */}
5460
<PopoverItem
5561
disabled={!hasExecutionId}
5662
onClick={() => {
@@ -61,7 +67,8 @@ export function LogRowContextMenu({
6167
Copy Execution ID
6268
</PopoverItem>
6369

64-
{/* Open Workflow */}
70+
{/* Navigation */}
71+
<PopoverDivider />
6572
<PopoverItem
6673
disabled={!hasWorkflow}
6774
onClick={() => {
@@ -72,7 +79,8 @@ export function LogRowContextMenu({
7279
Open Workflow
7380
</PopoverItem>
7481

75-
{/* Filter by Workflow - only show when not already filtered by this workflow */}
82+
{/* Filter actions */}
83+
<PopoverDivider />
7684
{!isFilteredByThisWorkflow && (
7785
<PopoverItem
7886
disabled={!hasWorkflow}
@@ -84,8 +92,6 @@ export function LogRowContextMenu({
8492
Filter by Workflow
8593
</PopoverItem>
8694
)}
87-
88-
{/* Clear All Filters - show when any filters are active */}
8995
{hasActiveFilters && (
9096
<PopoverItem
9197
onClick={() => {
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
export { LogRowContextMenu } from './log-row-context-menu'
2+
export { OutputContextMenu } from './output-context-menu'
13
export { PrettierOutput } from './prettier-output'
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
'use client'
2+
3+
import type { RefObject } from 'react'
4+
import {
5+
Popover,
6+
PopoverAnchor,
7+
PopoverContent,
8+
PopoverDivider,
9+
PopoverItem,
10+
} from '@/components/emcn'
11+
import type { ConsoleEntry } from '@/stores/terminal'
12+
13+
interface ContextMenuPosition {
14+
x: number
15+
y: number
16+
}
17+
18+
interface TerminalFilters {
19+
blockIds: Set<string>
20+
statuses: Set<'error' | 'info'>
21+
runIds: Set<string>
22+
}
23+
24+
interface LogRowContextMenuProps {
25+
isOpen: boolean
26+
position: ContextMenuPosition
27+
menuRef: RefObject<HTMLDivElement | null>
28+
onClose: () => void
29+
entry: ConsoleEntry | null
30+
filters: TerminalFilters
31+
onFilterByBlock: (blockId: string) => void
32+
onFilterByStatus: (status: 'error' | 'info') => void
33+
onFilterByRunId: (runId: string) => void
34+
onClearFilters: () => void
35+
onClearConsole: () => void
36+
hasActiveFilters: boolean
37+
}
38+
39+
/**
40+
* Context menu for terminal log rows (left side).
41+
* Displays filtering options based on the selected row's properties.
42+
*/
43+
export function LogRowContextMenu({
44+
isOpen,
45+
position,
46+
menuRef,
47+
onClose,
48+
entry,
49+
filters,
50+
onFilterByBlock,
51+
onFilterByStatus,
52+
onFilterByRunId,
53+
onClearFilters,
54+
onClearConsole,
55+
hasActiveFilters,
56+
}: LogRowContextMenuProps) {
57+
const hasRunId = entry?.executionId != null
58+
59+
const isBlockFiltered = entry ? filters.blockIds.has(entry.blockId) : false
60+
const entryStatus = entry?.success ? 'info' : 'error'
61+
const isStatusFiltered = entry ? filters.statuses.has(entryStatus) : false
62+
const isRunIdFiltered = entry?.executionId ? filters.runIds.has(entry.executionId) : false
63+
64+
return (
65+
<Popover
66+
open={isOpen}
67+
onOpenChange={onClose}
68+
variant='secondary'
69+
size='sm'
70+
colorScheme='inverted'
71+
>
72+
<PopoverAnchor
73+
style={{
74+
position: 'fixed',
75+
left: `${position.x}px`,
76+
top: `${position.y}px`,
77+
width: '1px',
78+
height: '1px',
79+
}}
80+
/>
81+
<PopoverContent ref={menuRef} align='start' side='bottom' sideOffset={4}>
82+
{/* Clear filters at top when active */}
83+
{hasActiveFilters && (
84+
<>
85+
<PopoverItem
86+
onClick={() => {
87+
onClearFilters()
88+
onClose()
89+
}}
90+
>
91+
Clear All Filters
92+
</PopoverItem>
93+
{entry && <PopoverDivider />}
94+
</>
95+
)}
96+
97+
{/* Filter actions */}
98+
{entry && (
99+
<>
100+
<PopoverItem
101+
showCheck={isBlockFiltered}
102+
onClick={() => {
103+
onFilterByBlock(entry.blockId)
104+
onClose()
105+
}}
106+
>
107+
Filter by Block
108+
</PopoverItem>
109+
<PopoverItem
110+
showCheck={isStatusFiltered}
111+
onClick={() => {
112+
onFilterByStatus(entryStatus)
113+
onClose()
114+
}}
115+
>
116+
Filter by Status
117+
</PopoverItem>
118+
{hasRunId && (
119+
<PopoverItem
120+
showCheck={isRunIdFiltered}
121+
onClick={() => {
122+
onFilterByRunId(entry.executionId!)
123+
onClose()
124+
}}
125+
>
126+
Filter by Run ID
127+
</PopoverItem>
128+
)}
129+
</>
130+
)}
131+
132+
{/* Destructive action */}
133+
{(entry || hasActiveFilters) && <PopoverDivider />}
134+
<PopoverItem
135+
onClick={() => {
136+
onClearConsole()
137+
onClose()
138+
}}
139+
>
140+
Clear Console
141+
</PopoverItem>
142+
</PopoverContent>
143+
</Popover>
144+
)
145+
}

0 commit comments

Comments
 (0)