Skip to content

feat: data preview / live tail panel#30

Merged
TerrifiedBug merged 7 commits intomainfrom
feat/live-tail
Mar 7, 2026
Merged

feat: data preview / live tail panel#30
TerrifiedBug merged 7 commits intomainfrom
feat/live-tail

Conversation

@TerrifiedBug
Copy link
Copy Markdown
Owner

Summary

  • Add LiveTailPanel component that uses the existing requestSamples/sampleResult tRPC procedures to sample live events from deployed pipeline components
  • Add tabbed layout (Config / Live Tail) to the detail panel — Live Tail tab only appears when the pipeline is deployed
  • Pass pipelineId and isDeployed props from the pipeline editor page to the detail panel
  • Update pipeline editor documentation with a new "Live Tail" section explaining usage

Test plan

  • Open a deployed pipeline in the editor, select a node, verify "Config" and "Live Tail" tabs appear
  • Open a draft pipeline, verify only the "Config" tab is visible
  • On the Live Tail tab, click "Sample 10 Events" and verify events appear after polling
  • Click an event row to expand/collapse the full JSON payload
  • Verify sampling multiple times appends events (up to 50 cap)
  • Verify error state displays correctly when sampling fails
  • Verify the Config tab still works identically to before (no regressions)

…components

Create LiveTailPanel component that uses the existing event sampling
infrastructure (requestSamples/sampleResult) to let users sample live
events flowing through any pipeline component. Integrate it into the
detail panel as a new "Live Tail" tab alongside the existing "Config"
tab, visible only when the pipeline is deployed.
Document the Live Tail feature including how to sample events from
deployed pipeline components, the detail panel tab layout, and the
agent sampling mechanics.
@github-actions github-actions bot added documentation Improvements or additions to documentation feature and removed documentation Improvements or additions to documentation labels Mar 7, 2026
- Replace useEffect setState with query select callback to avoid
  cascading renders (react-hooks/set-state-in-effect)
- Remove unused eslint-disable directive in pipeline page
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 7, 2026

Greptile Summary

This PR introduces a Live Tail panel to the pipeline detail view, allowing users to one-shot sample live events from any deployed pipeline component via the existing requestSamples/sampleResult tRPC procedures. The changes are well-scoped and all six issues flagged in the previous review threads have been addressed.

Key changes:

  • LiveTailPanel resets its own state when componentKey changes using React's recommended derived-state pattern (prevComponentKey comparison during render), covering the previously flagged stale-events bug.
  • isPending now includes resultQuery.isFetching, closing the re-entry window between mutation success and first poll response.
  • EXPIRED status sets hasExpired and clears requestId; a COMPLETED result with no matching events sets completedEmpty — both now show distinct, informative UI messages instead of the misleading "never sampled" prompt.
  • isDeployed prop uses !!isDeployed from the existing line-154 variable, keeping it consistent with the metrics/logs polling gate.
  • The blank-panel regression (Radix Tabs keeping "live-tail" as active value when the tab is removed) is resolved by keeping both tabs always rendered and letting LiveTailPanel show a guard message when !isDeployed.
  • Remaining concern (from a previous thread, not a new finding): processResults is still called inside the select callback rather than a useEffect. React may invoke select during the render phase under concurrent features/Strict Mode, making the setEvents/setRequestId calls there a latent issue. The processedRequestRef guard prevents obvious double-execution, but this pattern is worth revisiting.

Confidence Score: 3/5

  • Safe to merge with one acknowledged caveat: the select-as-side-effect pattern from the prior review thread remains in place and is a latent correctness risk under React Strict Mode / concurrent rendering.
  • All previously flagged correctness bugs have been addressed in this revision. The only outstanding concern is the processResults call inside TanStack Query's select callback, which was flagged in a prior thread and the developer has kept intentionally. This is a real antipattern in TanStack Query v5 (select runs during React's render phase), but the processedRequestRef guard limits observable damage today. Score reflects working, tested-against functionality held back by one unresolved architectural pattern.
  • src/components/flow/live-tail-panel.tsx — the select side-effect pattern at lines 77–81 is the one area warranting additional scrutiny before merge.

Important Files Changed

Filename Overview
src/components/flow/live-tail-panel.tsx New LiveTailPanel component. Previous thread issues (events reset on node switch, EXPIRED handling, completedEmpty state, isPending isFetching coverage) are all addressed. The select-as-side-effect antipattern flagged in a previous thread remains; ERROR status does not clear requestId but the logic still flows correctly because handleSample clears it before the next mutation.
src/components/flow/detail-panel.tsx Adds tabbed layout. Both tabs are always rendered (Live Tail shows a "must be deployed" guard message rather than being hidden), which resolves the previously flagged blank-panel issue. pipelineId prop comes directly from the parent rather than re-reading useParams, which is cleaner.
src/app/(dashboard)/pipelines/[id]/page.tsx Passes pipelineId and !!isDeployed to DetailPanel, reusing the existing isDeployed variable — resolves the previously flagged split-brain inconsistency. useMemouseState change for errorCheckSince is a correct equivalent simplification.
docs/public/user-guide/pipeline-editor.md Documentation-only addition. Adds a Live Tail section with step-by-step instructions, a hint about the heartbeat-based sampling model, and notes about the 50-event cap and 2-minute expiry window. Content is accurate relative to the implementation.

Sequence Diagram

sequenceDiagram
    participant U as User
    participant LP as LiveTailPanel
    participant TQ as TanStack Query
    participant tRPC as tRPC (server)
    participant A as Vector Agent

    U->>LP: Click "Sample 10 Events"
    LP->>LP: handleSample()<br/>reset processedRequestRef, requestId, flags
    LP->>tRPC: requestSamples mutation<br/>{pipelineId, componentKeys, limit}
    tRPC->>A: Schedule sample capture
    tRPC-->>LP: onSuccess → setRequestId(result.requestId)
    LP->>TQ: Enable sampleResult query<br/>(enabled: !!requestId)

    loop Poll every 1 second while PENDING
        TQ->>tRPC: sampleResult({ requestId })
        tRPC-->>TQ: { status: "PENDING" }
    end

    A->>tRPC: Heartbeat delivers captured events
    TQ->>tRPC: sampleResult({ requestId })
    tRPC-->>TQ: { status: "COMPLETED", samples: [...] }
    TQ->>LP: select() → processResults(data)
    LP->>LP: filter samples by componentKey<br/>setEvents / setCompletedEmpty<br/>setRequestId(null) — stops polling

    alt status: EXPIRED
        tRPC-->>TQ: { status: "EXPIRED" }
        TQ->>LP: select() → processResults(data)
        LP->>LP: setHasExpired(true)<br/>setRequestId(null)
    end

    alt status: ERROR
        tRPC-->>TQ: { status: "ERROR" }
        TQ->>LP: refetchInterval → false (stop polling)
        LP->>U: Show error banner<br/>button re-enabled
    end

    U->>LP: Click event row
    LP->>LP: toggleExpand(index)
    LP->>U: Render full JSON payload
Loading

Last reviewed commit: 6cd9fba

React Compiler flags Date.now() in useMemo as impure. useState initializer
is the idiomatic pattern for compute-once-on-mount values.
- Fix isPending to include isFetching, preventing double-click between
  mutation success and first poll response
- Reset events and requestId when componentKey changes so stale events
  from a previous node are not shown
- Always render the Live Tail tab and TabsContent regardless of deploy
  status; LiveTailPanel itself shows "Pipeline must be deployed" when
  isDeployed is false, preventing a blank tab panel.
- Track completedEmpty state so that a COMPLETED session with 0 matching
  events shows "No matching events found" instead of the generic initial
  prompt, avoiding user confusion.
@TerrifiedBug TerrifiedBug merged commit ea0ae98 into main Mar 7, 2026
12 checks passed
@TerrifiedBug TerrifiedBug deleted the feat/live-tail branch March 7, 2026 14:43
TerrifiedBug added a commit that referenced this pull request Mar 7, 2026
The merge of custom dashboards (#36) and live tail (#30) created a
conflict where LiveTailPanel references `componentKey` which was never
destructured as a local variable. The correct reference is `storeKey`,
derived from selectedNode.data.componentKey at the top of the component.
TerrifiedBug added a commit that referenced this pull request Mar 7, 2026
* fix: use storeKey instead of undefined componentKey in LiveTailPanel

The merge of custom dashboards (#36) and live tail (#30) created a
conflict where LiveTailPanel references `componentKey` which was never
destructured as a local variable. The correct reference is `storeKey`,
derived from selectedNode.data.componentKey at the top of the component.

* docs: update OIDC group sync documentation

Rewrite the OIDC role/team mapping section to reflect the new group
sync toggle, separate scope/claim fields, and stepper-based setup
guide. Removes references to legacy Admin/Editor Groups fields.
TerrifiedBug added a commit that referenced this pull request Mar 7, 2026
…42)

The merge of custom dashboards (#36) and live tail (#30) created a
conflict where LiveTailPanel references `componentKey` which was never
destructured as a local variable. The correct reference is `storeKey`,
derived from selectedNode.data.componentKey at the top of the component.
TerrifiedBug added a commit that referenced this pull request Mar 7, 2026
…42)

The merge of custom dashboards (#36) and live tail (#30) created a
conflict where LiveTailPanel references `componentKey` which was never
destructured as a local variable. The correct reference is `storeKey`,
derived from selectedNode.data.componentKey at the top of the component.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant