Prototype the run logs panel in the workflow editor - #7277
Conversation
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>
…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 `搜索Config.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>
|
Too many files changed for review (167 files, 100 file limit). Bypass the limit by tagging |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
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’sisConnectableStartwithcanConnect.apps/sim/app/layout.tsx: LegacyactiveTab: '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, despitearia-hidden; addinert={!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 `editor操作` 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' |
There was a problem hiding this comment.
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>
|
|
||
| {editor操作 ? ( | ||
| <div | ||
| aria-hidden={!editorActive} |
There was a problem hiding this comment.
P2: When Toolbar or Logs is active, the opacity-hidden editor操作 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 `editor操作` 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 @@
+
+ {editor操作 ? (
+ <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>
| 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') { |
There was a problem hiding this comment.
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>
| {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'} |
There was a problem hiding this comment.
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>
| 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)]', |
There was a problem hiding this comment.
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>
| bucket.runs.length > 0 && 'bg-[var(--text-success)]', | |
| bucket.runs.length > 0 && 'bg-[var(--text-muted)]', |
Puts a workflow's run history in the editor's right panel and wires it to the canvas. Development-only, behind
?logsPrototype=4.Try it
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.
Escor 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
LogTraceSpanmodel: 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.
ResourceOptionsgainssize('sm' | 'md') and搜索Config.hideIcon, for the narrow panel.ChipDropdownnow honours thesizeits props already advertised — it extendedVariantProps<typeof chipVariants>but dropped the value, sosizetype-checked and was silently discarded.Chipgains a compactsmsize.WorkflowBlockViewgainscanConnect, 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.🤖 Generated with Claude Code