Skip to content

Commit 852562c

Browse files
authored
feat(logs-context-menu): consolidated logs utils and types, added logs record context menu (#2659)
1 parent 4da128d commit 852562c

File tree

20 files changed

+375
-135
lines changed

20 files changed

+375
-135
lines changed

.cursor/rules/sim-imports.mdc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@ import { Dashboard, Sidebar } from '@/app/workspace/[workspaceId]/logs/component
3030
import { Dashboard } from '@/app/workspace/[workspaceId]/logs/components/dashboard/dashboard'
3131
```
3232

33+
## No Re-exports
34+
35+
Do not re-export from non-barrel files. Import directly from the source.
36+
37+
```typescript
38+
// ✓ Good - import from where it's declared
39+
import { CORE_TRIGGER_TYPES } from '@/stores/logs/filters/types'
40+
41+
// ✗ Bad - re-exporting in utils.ts then importing from there
42+
import { CORE_TRIGGER_TYPES } from '@/app/workspace/.../utils'
43+
```
44+
3345
## Import Order
3446

3547
1. React/core libraries

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import { useWorkflowStore } from '@/stores/workflows/store'
5252
import { useWorkflowStore } from '../../../stores/workflows/store'
5353
```
5454

55-
Use barrel exports (`index.ts`) when a folder has 3+ exports.
55+
Use barrel exports (`index.ts`) when a folder has 3+ exports. Do not re-export from non-barrel files; import directly from the source.
5656

5757
### Import Order
5858
1. React/core libraries

apps/sim/app/api/workflows/[id]/execute/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { markExecutionCancelled } from '@/lib/execution/cancellation'
1212
import { processInputFileFields } from '@/lib/execution/files'
1313
import { preprocessExecution } from '@/lib/execution/preprocessing'
1414
import { LoggingSession } from '@/lib/logs/execution/logging-session'
15-
import { ALL_TRIGGER_TYPES } from '@/lib/logs/types'
1615
import { executeWorkflowCore } from '@/lib/workflows/executor/execution-core'
1716
import { type ExecutionEvent, encodeSSEEvent } from '@/lib/workflows/executor/execution-events'
1817
import { PauseResumeManager } from '@/lib/workflows/executor/human-in-the-loop-manager'
@@ -27,13 +26,14 @@ import { normalizeName } from '@/executor/constants'
2726
import { type ExecutionMetadata, ExecutionSnapshot } from '@/executor/execution/snapshot'
2827
import type { StreamingExecution } from '@/executor/types'
2928
import { Serializer } from '@/serializer'
29+
import { CORE_TRIGGER_TYPES } from '@/stores/logs/filters/types'
3030
import type { SubflowType } from '@/stores/workflows/workflow/types'
3131

3232
const logger = createLogger('WorkflowExecuteAPI')
3333

3434
const ExecuteWorkflowSchema = z.object({
3535
selectedOutputs: z.array(z.string()).optional().default([]),
36-
triggerType: z.enum(ALL_TRIGGER_TYPES).optional(),
36+
triggerType: z.enum(CORE_TRIGGER_TYPES).optional(),
3737
stream: z.boolean().optional(),
3838
useDraftState: z.boolean().optional(),
3939
input: z.any().optional(),

apps/sim/app/api/workspaces/[id]/notifications/[notificationId]/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ import { type NextRequest, NextResponse } from 'next/server'
66
import { z } from 'zod'
77
import { getSession } from '@/lib/auth'
88
import { encryptSecret } from '@/lib/core/security/encryption'
9-
import { ALL_TRIGGER_TYPES } from '@/lib/logs/types'
109
import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils'
10+
import { CORE_TRIGGER_TYPES } from '@/stores/logs/filters/types'
1111
import { MAX_EMAIL_RECIPIENTS, MAX_WORKFLOW_IDS } from '../constants'
1212

1313
const logger = createLogger('WorkspaceNotificationAPI')
1414

1515
const levelFilterSchema = z.array(z.enum(['info', 'error']))
16-
const triggerFilterSchema = z.array(z.enum(ALL_TRIGGER_TYPES))
16+
const triggerFilterSchema = z.array(z.enum(CORE_TRIGGER_TYPES))
1717

1818
const alertRuleSchema = z.enum([
1919
'consecutive_failures',

apps/sim/app/api/workspaces/[id]/notifications/route.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ import { v4 as uuidv4 } from 'uuid'
77
import { z } from 'zod'
88
import { getSession } from '@/lib/auth'
99
import { encryptSecret } from '@/lib/core/security/encryption'
10-
import { ALL_TRIGGER_TYPES } from '@/lib/logs/types'
1110
import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils'
11+
import { CORE_TRIGGER_TYPES } from '@/stores/logs/filters/types'
1212
import { MAX_EMAIL_RECIPIENTS, MAX_NOTIFICATIONS_PER_TYPE, MAX_WORKFLOW_IDS } from './constants'
1313

1414
const logger = createLogger('WorkspaceNotificationsAPI')
1515

1616
const notificationTypeSchema = z.enum(['webhook', 'email', 'slack'])
1717
const levelFilterSchema = z.array(z.enum(['info', 'error']))
18-
const triggerFilterSchema = z.array(z.enum(ALL_TRIGGER_TYPES))
18+
const triggerFilterSchema = z.array(z.enum(CORE_TRIGGER_TYPES))
1919

2020
const alertRuleSchema = z.enum([
2121
'consecutive_failures',
@@ -81,7 +81,7 @@ const createNotificationSchema = z
8181
workflowIds: z.array(z.string()).max(MAX_WORKFLOW_IDS).default([]),
8282
allWorkflows: z.boolean().default(false),
8383
levelFilter: levelFilterSchema.default(['info', 'error']),
84-
triggerFilter: triggerFilterSchema.default([...ALL_TRIGGER_TYPES]),
84+
triggerFilter: triggerFilterSchema.default([...CORE_TRIGGER_TYPES]),
8585
includeFinalOutput: z.boolean().default(false),
8686
includeTraceSpans: z.boolean().default(false),
8787
includeRateLimits: z.boolean().default(false),

apps/sim/app/workspace/[workspaceId]/logs/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ export { LogDetails } from './log-details'
33
export { FileCards } from './log-details/components/file-download'
44
export { FrozenCanvas } from './log-details/components/frozen-canvas'
55
export { TraceSpans } from './log-details/components/trace-spans'
6+
export { LogRowContextMenu } from './log-row-context-menu'
67
export { LogsList } from './logs-list'
78
export { AutocompleteSearch, LogsToolbar, NotificationSettings } from './logs-toolbar'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { LogRowContextMenu } from './log-row-context-menu'
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
'use client'
2+
3+
import type { RefObject } from 'react'
4+
import { Popover, PopoverAnchor, PopoverContent, PopoverItem } from '@/components/emcn'
5+
import type { WorkflowLog } from '@/stores/logs/filters/types'
6+
7+
interface LogRowContextMenuProps {
8+
isOpen: boolean
9+
position: { x: number; y: number }
10+
menuRef: RefObject<HTMLDivElement | null>
11+
onClose: () => void
12+
log: WorkflowLog | null
13+
onCopyExecutionId: () => void
14+
onOpenWorkflow: () => void
15+
onToggleWorkflowFilter: () => void
16+
onClearAllFilters: () => void
17+
isFilteredByThisWorkflow: boolean
18+
hasActiveFilters: boolean
19+
}
20+
21+
/**
22+
* Context menu for log rows.
23+
* Provides quick actions for copying data, navigation, and filtering.
24+
*/
25+
export function LogRowContextMenu({
26+
isOpen,
27+
position,
28+
menuRef,
29+
onClose,
30+
log,
31+
onCopyExecutionId,
32+
onOpenWorkflow,
33+
onToggleWorkflowFilter,
34+
onClearAllFilters,
35+
isFilteredByThisWorkflow,
36+
hasActiveFilters,
37+
}: LogRowContextMenuProps) {
38+
const hasExecutionId = Boolean(log?.executionId)
39+
const hasWorkflow = Boolean(log?.workflow?.id || log?.workflowId)
40+
41+
return (
42+
<Popover open={isOpen} onOpenChange={onClose} variant='secondary' size='sm'>
43+
<PopoverAnchor
44+
style={{
45+
position: 'fixed',
46+
left: `${position.x}px`,
47+
top: `${position.y}px`,
48+
width: '1px',
49+
height: '1px',
50+
}}
51+
/>
52+
<PopoverContent ref={menuRef} align='start' side='bottom' sideOffset={4}>
53+
{/* Copy Execution ID */}
54+
<PopoverItem
55+
disabled={!hasExecutionId}
56+
onClick={() => {
57+
onCopyExecutionId()
58+
onClose()
59+
}}
60+
>
61+
Copy Execution ID
62+
</PopoverItem>
63+
64+
{/* Open Workflow */}
65+
<PopoverItem
66+
disabled={!hasWorkflow}
67+
onClick={() => {
68+
onOpenWorkflow()
69+
onClose()
70+
}}
71+
>
72+
Open Workflow
73+
</PopoverItem>
74+
75+
{/* Filter by Workflow - only show when not already filtered by this workflow */}
76+
{!isFilteredByThisWorkflow && (
77+
<PopoverItem
78+
disabled={!hasWorkflow}
79+
onClick={() => {
80+
onToggleWorkflowFilter()
81+
onClose()
82+
}}
83+
>
84+
Filter by Workflow
85+
</PopoverItem>
86+
)}
87+
88+
{/* Clear All Filters - show when any filters are active */}
89+
{hasActiveFilters && (
90+
<PopoverItem
91+
onClick={() => {
92+
onClearAllFilters()
93+
onClose()
94+
}}
95+
>
96+
Clear Filters
97+
</PopoverItem>
98+
)}
99+
</PopoverContent>
100+
</Popover>
101+
)
102+
}

0 commit comments

Comments
 (0)