Skip to content

Prototype the run logs panel in the workflow editor - #7277

Open
andresdjasso wants to merge 47 commits into
stagingfrom
improvement/workflow-logs-panel
Open

Prototype the run logs panel in the workflow editor#7277
andresdjasso wants to merge 47 commits into
stagingfrom
improvement/workflow-logs-panel

Conversation

@andresdjasso

Copy link
Copy Markdown
Contributor

Puts a workflow's run history in the editor's right panel and wires it to the canvas. Development-only, behind ?logsPrototype=4.

Stacked on #6507. That branch is behind staging, so basing this PR on it produced an unreadable diff — it targets staging instead and therefore contains #6507's commits as well. The new work is the last commit, improvement(logs): prototype the run logs panel in the workflow editor (31 files); everything before it belongs to #6507 and is already under review there.

Try it

/workspace/<workspaceId>/w/<workflowId>?logsPrototype=4

The panel opens on the run list. Pick a run → the canvas becomes a read-only snapshot of it, focused on the block that failed. Esc or Back to current returns to the live workflow. Selecting a step syncs the canvas; Inspector opens a drawer showing what the run recorded for that step.

What to look at

Run list uses the Logs page's own controls bar (Resource.Options), so search, Filter and Sort behave identically on both surfaces. Filter offers Status, Trigger and Time Range — no Workflow or Folder, since the panel is already scoped to one workflow.

Inspector is built on the LogTraceSpan model: input and output, plus an error message where one was recorded. No block source and no console — a span holds neither. Stats above the values are the trace view's own (Duration, Tries, Model, token counts, Error type, Iteration).

Status colour comes from the Logs page's STATUS_CONFIG, which contains no green. Red is reserved for the runs that need attention; a completed run takes the muted dot the Logs table gives it.

Fixture is a fifteen-channel Slack digest with an agent, so the trace nests three levels deep (loop → iteration → tool call) and the panel is exercised at real depth. 120 runs across ~49 days.

Shared components

All additive, all defaulted to current behaviour — the Logs, Tables, Knowledge and Files pages render unchanged.

  • ResourceOptions gains size ('sm' | 'md') and SearchConfig.hideIcon, for the narrow panel.
  • ChipDropdown now honours the size its props already advertised — it extended VariantProps<typeof chipVariants> but dropped the value, so size type-checked and was silently discarded.
  • Chip gains a compact sm size.
  • WorkflowBlockView gains canConnect, so a read-only snapshot cannot start an edge.

Not included

  • RunHealth (success rate, median, failure count, spend, and the bucketed run-history strip) is built and typechecked but not mounted — it is staged for the workspace Logs page, where a cross-run summary belongs.
  • No backend. Everything reads from a fixture; swapping it for the real runs query is the port.

🤖 Generated with Claude Code

andresdjasso and others added 30 commits August 10, 2026 17:35
Connection anchors: an output now always leaves a card from the right.
The cursor swell lets a drag start on any edge, but the left side is the
input, so anchoring an outgoing edge there drew a line out of the input
port and read as a second input. `normalizeCursorSourceHandleId` resolves
every drag to the right anchor, `normalizePositionedSourceHandleId`
collapses `source-left` alongside the legacy vertical anchors (so data
from the API, an older client, or a stale save self-heals on load), and
only the right-side source anchor is mounted.

Drops in `onConnectEnd` are always source -> target. The branch that
reversed the edge for a drag starting on an input could never run: the
`target` handle is `isConnectableStart={false}` and the positioned side
anchors are `isConnectable={false}`, so React Flow never reports an input
as a drag origin. Removed it and its now-unused imports.

A newly created block is centered once its node mounts and is measured,
so a card added from a drag-release, the block menu, or the toolbar is
never left off-screen or under the editor panel.

The editor panel's block icon uses the same type accent as the card's
badge instead of the block's legacy `bgColor`, which had left the panel
on the old per-integration brand colours.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Start card intermittently collapsed after load, squashing the
action-menu tab so its icon row sat over the card.

`.workflow-drag-handle` is the host the border renderer measures, and both
it and the header row took their height from `blockHeight && blockHeight >
0`. `blockHeight` comes from the deterministic-dimensions pass and is
already floored at MIN_PAINTED_HEIGHT (48), but it is absent on the first
frames — and with no floor the host collapsed to its natural content
height (25.5px for a header-only trigger, exactly the title's line box).
The border builds its perimeter from `host.offsetHeight`, so that window
painted a sub-floor card: too little straight edge remained on the
vertical runs for the action-menu tab, which collapsed into the corner
arcs. Whether you saw it depended purely on whether the dimension publish
had landed, which is why it reproduced on one workflow and not another.

Floor all three: the host, the header row (so `items-center` centres the
title and type tag rather than pinning them to the top), and the border's
own `offsetHeight` read.

Also raise ACTION_MENU_CONTENT_READY_THRESHOLD to 0.9. At 0.8 the 24px
icon row was revealed while the swell had only reached 22.4px of its 28px
— shorter than the row it contains. Secondary to the above, but a real
overflow window on its own. The test now pins the ratio rather than the
constant.

Tag palette moves to fixed brand values (hex, not derived oklch) with two
inks — #F8F8F8 on dark fills, #1A1A1A on light. Tones are renamed to match
what they render. `green` (2.55:1) and `orange` (3.15:1) sit under WCAG AA
against their paired ink; both are deliberate brand decisions and are
documented in the component.

Deploy and Run take two new Button variants rather than className
overrides, so `tertiary` stays green everywhere else.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
andresdjasso and others added 17 commits August 11, 2026 12:26
…ow-logs-panel

# Conflicts:
#	apps/sim/app/layout.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/general/general.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/deploy-modal.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/deploy.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/credential-selector.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/dropdown/dropdown.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/index.ts
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/knowledge-base-selector/knowledge-base-selector.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/long-input/long-input.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/short-input/short-input.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tool-input/components/tools/credential-selector.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tool-input/tool-input.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/editor.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/hooks/use-editor-subblock-layout.ts
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/search-replace/workflow-search-replace.tsx
#	apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx
#	apps/sim/components/empty-state/empty-state.tsx
#	apps/sim/lib/workflows/subblocks/visibility.test.ts
#	packages/emcn/src/components/chip-input/chip-input.test.tsx
#	packages/emcn/src/components/chip-input/chip-input.tsx
#	packages/emcn/src/components/chip-modal/chip-modal.tsx
#	packages/emcn/src/components/code/code.test.tsx
#	packages/emcn/src/components/dropdown-menu/dropdown-menu.tsx
#	packages/emcn/src/components/popover/popover.tsx
Puts a workflow's run history in the editor's right panel and wires it to
the canvas, behind `?logsPrototype=4` in development.

The panel opens on the run list. Picking a run turns the canvas into a
read-only snapshot of it, focused on the block that failed; Escape or
"Back to current" returns to the live workflow. Selecting a step syncs the
canvas, and the inspector drawer shows what the run recorded for that step.

- Run list carries the Logs page's own controls bar (`Resource.Options`)
  so search, Filter and Sort behave identically on both surfaces.
- Inspector is built on the `LogTraceSpan` model: input and output, plus an
  error message where one was recorded. No block source, no console — a
  span holds neither.
- Status colour comes from the Logs page's `STATUS_CONFIG`, which has no
  green: red is reserved for runs that need attention.
- Fixture is a fifteen-channel Slack digest with an agent, so the trace
  nests three levels deep and the panel is exercised at real depth.

Shared-component changes, all additive and defaulted to current behaviour:

- `ResourceOptions` gains `size` ('sm' | 'md') and `SearchConfig.hideIcon`,
  for the narrow panel. Every existing consumer keeps the page scale.
- `ChipDropdown` now honours the `size` its props already advertised — it
  extended `VariantProps<typeof chipVariants>` but dropped the value.
- `Chip` gains a compact `sm` size; `WorkflowBlockView` gains `canConnect`
  so a read-only snapshot cannot start an edge.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Too many files changed for review (167 files, 100 file limit).

Bypass the limit by tagging @greptile-apps to review.

@vercel

vercel Bot commented Aug 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview Aug 29, 2026 5:25pm

Request Review

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found across 167 files

Confidence score: 3/5

  • packages/workflow-renderer/src/workflow-block/workflow-block-view.tsx: Preview mode still leaves the persistent default, branch, and error source handles connectable, allowing unintended workflow edits; gate every source handle’s isConnectableStart with canConnect.
  • apps/sim/app/layout.tsx: Legacy activeTab: 'copilot' state can be restored after hydration even though only the pre-hydration CSS attribute is migrated, leaving the panel in an unsupported state; migrate the persisted store value as well.
  • apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/panel-view-controls.tsx: Hidden editor actions remain keyboard-focusable while Toolbar or Logs is active, despite aria-hidden; add inert={!editorActive} to remove them from interaction.
  • apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/logs/run-health.tsx: Run-health buckets can report “All succeeded” while runs are still running or paused, and successful buckets are shown green despite the intended neutral treatment; check unfinished runs before the success fallback and remove the unconditional success color.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/logs/run-health.tsx">

<violation number="1" location="apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/logs/run-health.tsx:96">
P3: Successful buckets render green because this class applies to every nonempty bucket, contradicting the muted/no-green status treatment. Remove the success color and leave the neutral base plus the failure override.</violation>

<violation number="2" location="apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/logs/run-health.tsx:117">
P3: When a grouped bucket contains running or paused runs but no error, the tooltip says “All succeeded.” Check for unfinished runs before using the success fallback.</violation>
</file>

<file name="packages/workflow-renderer/src/workflow-block/workflow-block-view.tsx">

<violation number="1" location="packages/workflow-renderer/src/workflow-block/workflow-block-view.tsx:581">
P1: When `data.isPreview` is true, `canConnect` disables only the hover cursor handle; the persistent default, branch, and error source handles remain connectable. Gate every source handle's `isConnectableStart` with `canConnect` so read-only snapshots cannot create edges.</violation>
</file>

<file name="apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/panel-view-controls.tsx">

<violation number="1" location="apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/panel-view-controls.tsx:134">
P2: When Toolbar or Logs is active, the opacity-hidden `editorActions` subtree still exposes its ActionBar and close button to keyboard focus despite `aria-hidden`; add `inert={!editorActive}` to remove it from interaction.</violation>
</file>

<file name="apps/sim/app/layout.tsx">

<violation number="1" location="apps/sim/app/layout.tsx:171">
P2: When a user has a legacy `activeTab: 'copilot'` in `panel-state`, this migration updates only the pre-hydration CSS attribute; store rehydration restores `copilot` and removes that attribute, while the panel has no copilot content, leaving the inspector blank. Normalize the persisted value during panel-store rehydration (and persist `toolbar`) instead of migrating only the first-paint attribute.</violation>
</file>

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

}: WorkflowBlockViewProps) {
const updateNodeInternals = useUpdateNodeInternals()
const reactFlowStore = useReactFlowStoreApi()
const getConnectionNodeId = useCallback(
() => reactFlowStore.getState().connectionNodeId,
[reactFlowStore]
)
const supportsCursorHandle = type !== 'response'
const supportsCursorHandle = canConnect && type !== 'response'

@cubic-dev-ai cubic-dev-ai Bot Aug 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: When data.isPreview is true, canConnect disables only the hover cursor handle; the persistent default, branch, and error source handles remain connectable. Gate every source handle's isConnectableStart with canConnect so read-only snapshots cannot create edges.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/workflow-renderer/src/workflow-block/workflow-block-view.tsx, line 581:

<comment>When `data.isPreview` is true, `canConnect` disables only the hover cursor handle; the persistent default, branch, and error source handles remain connectable. Gate every source handle's `isConnectableStart` with `canConnect` so read-only snapshots cannot create edges.</comment>

<file context>
@@ -563,14 +570,15 @@ export function WorkflowBlockView({
     [reactFlowStore]
   )
-  const supportsCursorHandle = type !== 'response'
+  const supportsCursorHandle = canConnect && type !== 'response'
   const cursorSourceHandleRef = useRef<HTMLDivElement>(null)
   const cursorSourceHandleKeyRef = useRef<string | null>(null)
</file context>
Fix with cubic


{editorActions ? (
<div
aria-hidden={!editorActive}

@cubic-dev-ai cubic-dev-ai Bot Aug 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When Toolbar or Logs is active, the opacity-hidden editorActions subtree still exposes its ActionBar and close button to keyboard focus despite aria-hidden; add inert={!editorActive} to remove it from interaction.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/panel-view-controls.tsx, line 134:

<comment>When Toolbar or Logs is active, the opacity-hidden `editorActions` subtree still exposes its ActionBar and close button to keyboard focus despite `aria-hidden`; add `inert={!editorActive}` to remove it from interaction.</comment>

<file context>
@@ -0,0 +1,147 @@
+
+      {editorActions ? (
+        <div
+          aria-hidden={!editorActive}
+          className={cn(
+            'absolute inset-y-0 end-3.5 flex items-center transition-opacity [transition-timing-function:cubic-bezier(0.22,1,0.36,1)] motion-reduce:transition-none',
</file context>
Fix with cubic

Comment thread apps/sim/app/layout.tsx
if (activeTab === 'copilot' && !${isChatEnabled}) {
// Chat moved out of the right inspector. Migrate the legacy
// persisted tab before first paint so the inspector opens on Blocks.
if (activeTab === 'copilot') {

@cubic-dev-ai cubic-dev-ai Bot Aug 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When a user has a legacy activeTab: 'copilot' in panel-state, this migration updates only the pre-hydration CSS attribute; store rehydration restores copilot and removes that attribute, while the panel has no copilot content, leaving the inspector blank. Normalize the persisted value during panel-store rehydration (and persist toolbar) instead of migrating only the first-paint attribute.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/sim/app/layout.tsx, line 171:

<comment>When a user has a legacy `activeTab: 'copilot'` in `panel-state`, this migration updates only the pre-hydration CSS attribute; store rehydration restores `copilot` and removes that attribute, while the panel has no copilot content, leaving the inspector blank. Normalize the persisted value during panel-store rehydration (and persist `toolbar`) instead of migrating only the first-paint attribute.</comment>

<file context>
@@ -171,10 +166,9 @@ export default function RootLayout({ children }: { children: React.ReactNode })
-                    if (activeTab === 'copilot' && !${isChatEnabled}) {
+                    // Chat moved out of the right inspector. Migrate the legacy
+                    // persisted tab before first paint so the inspector opens on Blocks.
+                    if (activeTab === 'copilot') {
                       activeTab = 'toolbar';
                     }
</file context>
Fix with cubic

{bucket.runs.length} {bucket.runs.length === 1 ? 'run' : 'runs'}
</span>
<span className='block text-[var(--text-tertiary)]'>
{bucket.failedCount > 0 ? `${bucket.failedCount} failed` : 'All succeeded'}

@cubic-dev-ai cubic-dev-ai Bot Aug 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: When a grouped bucket contains running or paused runs but no error, the tooltip says “All succeeded.” Check for unfinished runs before using the success fallback.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/logs/run-health.tsx, line 117:

<comment>When a grouped bucket contains running or paused runs but no error, the tooltip says “All succeeded.” Check for unfinished runs before using the success fallback.</comment>

<file context>
@@ -0,0 +1,132 @@
+                      {bucket.runs.length} {bucket.runs.length === 1 ? 'run' : 'runs'}
+                    </span>
+                    <span className='block text-[var(--text-tertiary)]'>
+                      {bucket.failedCount > 0 ? `${bucket.failedCount} failed` : 'All succeeded'}
+                    </span>
+                  </>
</file context>
Fix with cubic

style={{ height: `${bucket.runs.length ? height : 6}%` }}
className={cn(
'w-full rounded-[2px] bg-[var(--border)] transition-opacity group-hover:opacity-70',
bucket.runs.length > 0 && 'bg-[var(--text-success)]',

@cubic-dev-ai cubic-dev-ai Bot Aug 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Successful buckets render green because this class applies to every nonempty bucket, contradicting the muted/no-green status treatment. Remove the success color and leave the neutral base plus the failure override.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/logs/run-health.tsx, line 96:

<comment>Successful buckets render green because this class applies to every nonempty bucket, contradicting the muted/no-green status treatment. Remove the success color and leave the neutral base plus the failure override.</comment>

<file context>
@@ -0,0 +1,132 @@
+                    style={{ height: `${bucket.runs.length ? height : 6}%` }}
+                    className={cn(
+                      'w-full rounded-[2px] bg-[var(--border)] transition-opacity group-hover:opacity-70',
+                      bucket.runs.length > 0 && 'bg-[var(--text-success)]',
+                      unsettled && bucket.runs.length > 0 && 'bg-[var(--text-muted)]',
+                      bucket.failedCount > 0 && 'bg-[var(--text-error)]'
</file context>
Suggested change
bucket.runs.length > 0 && 'bg-[var(--text-success)]',
bucket.runs.length > 0 && 'bg-[var(--text-muted)]',
Fix with cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant