Skip to content

feat(tekton): Pipeline/PipelineRun/TaskRun integration — detail views, live DAG, CI/CD fleet tab - #1627

Open
jfillman wants to merge 33 commits into
skyhook-io:mainfrom
jfillman:feature/tekton-pipeline-dag
Open

jfillman wants to merge 33 commits into
skyhook-io:mainfrom
jfillman:feature/tekton-pipeline-dag

Conversation

@jfillman

@jfillman jfillman commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

A full Tekton integration: Pipeline/PipelineRun/TaskRun detail views with an embedded, live-updating task DAG, plus a new CI/CD fleet tab for browsing PipelineRuns across the cluster.

  • Embedded DAG on the PipelineRun detail view, rendered with real topology-style nodes (not a generic graph library default look) — reflects live task status/progress as the pipeline runs, moved to a full-view layout for readability on pipelines with more than a few tasks.
  • CI/CD fleet tab: a sortable, GitOps-style table of PipelineRuns across the cluster, with row actions and bulk multi-select delete. The Pipeline column links directly to the parent Pipeline.
  • TaskRun log viewing: combined, sequential step logs (not per-step tabs) with a pod link and an explicit back-link to the parent PipelineRun.
  • DAG layout: widened ELK spacing and edge merging to fix overlapping arrows on wider pipelines; draggable nodes with a browser-local saved layout (and a Reset-layout control); a solid background wash + ring (no opacity pulse — an earlier version made the card transparent) highlights the currently-running task.
  • Fixed a real bug where the DAG could blank out (nodes hidden, edges missing) on certain live pipeline states.
  • Two small unrelated nav fixes bundled in (a peek panel wasn't closing/collapsing correctly on further drill-down), found while building this.
  • Docs updated for the full-view DAG redesign.

Test plan

  • go test ./...
  • make tsc
  • npx vitest run (k8s-ui) — 3388 tests passing
  • Live-verified DAG rendering, drag/save/reset layout, and running-task styling against real PipelineRuns

🤖 Generated with Claude Code


Note

Medium Risk
Adds cluster list/watch for Tekton CRDs and new mutate/delete/cancel paths from the CI/CD table; log and TaskRun fetch traffic scales with pipeline size and polling, but changes are scoped to Tekton UX rather than core auth or data stores.

Overview
Adds first-class Tekton Pipelines support end to end: the backend dynamic cache watches Pipeline, PipelineRun, and TaskRun (tekton.dev v1/v1beta1), and the UI gets resource-browser columns, detail drawers, status badges, icons, and navigation fixes for *Run kind names.

Pipeline / PipelineRun use compact drawers for params, workspaces, and run metadata; the task dependency graph lives only in the fullscreen expanded view (PipelineDagView + TektonPipelineFullscreen). The graph is built from runAfter and implicit $(tasks.*.results.*) deps (including finally tasks), with transitive edge reduction, ELK layout, live per-task coloring on PipelineRuns (child TaskRun fetches, matrix aggregation, skipped-task handling), draggable nodes with optional saved layout, and clicks through to TaskRuns.

TaskRuns get step status with per-step Logs (dock) and a dedicated Logs tab that merges all step containers sequentially via new LogCore showContainerName. A header chip links back to the owning PipelineRun.

A new /cicd CI/CD view lists PipelineRuns fleet-wide with stats, facets, sort, cancel/delete (including bulk delete), task-start progress bars, and row open straight to fullscreen DAG; App.tsx peek/back behavior is adjusted so CI/CD–opened full drawers close correctly on browser Back and in-drawer drill-down stays on the origin page when not on /resources.

Documentation in README and docs/integrations.md describes supported CRDs and UX.

Reviewed by Cursor Bugbot for commit e707104. Bugbot is set up for automated code reviews on this repo. Configure here.

…rogress

Tekton had zero integration despite the Helm chart already granting
tekton.dev read RBAC by default. Adds detail-drawer support for Pipeline,
PipelineRun, and TaskRun (topology-graph integration deliberately deferred
to a later PR — this is detail-view only):

- Pipeline: renders its declared task-dependency graph (parsed from
  spec.tasks[].runAfter plus implicit ordering inferred from
  $(tasks.<name>.results.*) references), reusing @xyflow/react at a small,
  static-diagram scale rather than a new hand-rolled SVG.
- PipelineRun: the same graph with live per-task coloring, sourced from
  tekton.dev/v1's status.childReferences (a PipelineRun only names its
  child TaskRuns, not their outcome, so the host wrapper fans out one
  fetch per child — same pattern as CompositeRenderer's composed-resource
  status resolution). Deliberately DAG-only, not DAG-plus-linear-list:
  unlike Argo Rollouts' single sequential promotion path, Tekton tasks
  form a genuine DAG with parallel branches that a list would misrepresent.
- TaskRun: per-step status, parameters, results.

Table columns, resource icons, and docs (README + integrations.md)
updated per the CRD Integration Guide's non-topology steps.
Feedback from live testing on the first cut: the embedded drawer DAG had
overlapping, hard-to-follow lines, tasks weren't clickable, and the graph
had no business being in the compact drawer in the first place.

- PipelineDagView now lays out with ELK.js (same engine + options as the
  main Topology view: layered/RIGHT/ORTHOGONAL/NETWORK_SIMPLEX) instead of
  a hand-rolled rank/row placement — NETWORK_SIMPLEX minimizes edge
  crossings, which is what was actually missing. Task nodes mirror
  K8sResourceNode's visual language (topology-node-card, icon + kind-label
  header, status dot) so a task reads as the same kind of thing as a real
  topology node, without extending the shared NodeKind enum or wiring
  Tekton into pkg/topology/builder.go.
- The DAG moved out of the compact drawer entirely into the resource's
  fullscreen "full view" (TektonPipelineFullscreen, wired via
  renderExpandedOverview — the same seam Argo Workflows/Jobs already use
  for their own execution views). The compact PipelineRenderer /
  PipelineRunRenderer now just point at the full view instead of trying to
  cram a graph into a few hundred pixels.
- Task nodes are clickable when they have a live TaskRun (taskRunName now
  flows through TektonTaskNode) and open that TaskRun's own page via
  onNavigateToResource — reusing the existing resource-navigation pattern
  instead of a bespoke panel.
- TaskRun's Steps section gained per-step "Logs" buttons wired to the dock's
  useOpenLogs (Tekton names each step's container `step-<name>`) — real
  streaming step logs, not just exit codes.
- Running tasks keep the spinning Loader2 + blue coloring from the first
  cut (confirmed against a live run) plus a pulse on the card itself.

Live-verified end-to-end against a throwaway 5-task Pipeline with a real
in-flight task: clean non-overlapping layout, correct running/pending/
succeeded coloring, click-through to the TaskRun page, and real log
streaming from its pod.
Clicking a task node opens its TaskRun via the app's generic "drill into a
related resource while expanded" navigation, which — by design, for every
kind, not just Tekton — points the backdrop route at the new resource's own
list rather than back at the resource you came from. So "Go back"/collapse
lands on the bare TaskRun list, not the PipelineRun you clicked from.

Rather than change that shared, heavily-used mechanism, surface an explicit
way back — the same idea as GitOps's parent-lineage breadcrumb. TaskRuns
always carry an ownerReference to their PipelineRun, so this needs no
click-time breadcrumb param and works from any entry point (direct link,
search, not just the DAG). A small "↑ Back to PipelineRun <name>" link now
sits at the top of the TaskRun view and navigates there directly.

Live-verified: click a task in a PipelineRun's full view → TaskRun page →
click the new link → back on the same PipelineRun's full view.
Two issues from live testing:

1. The TaskRun's Logs tab fell through to the generic MultiPodLogsTab (a
   pod-picker built for N-pod workloads), rendering a row of pod bubbles for
   a resource that only ever has one pod. A TaskRun's real shape is one pod
   with one container per step (Tekton names them `step-<name>`), running
   sequentially — the opposite of what that picker is for.

   Added TaskRunLogsTab: fetches every step's container in one call to the
   existing /api/pods/{ns}/{pod}/logs endpoint (already returns all
   containers when no `container` param is given), splits each into
   per-line entries client-side, and combines them into one sequential
   LogCore view in declared step order. Each line is labeled by step via a
   new `showContainerName` prop on LogCore, mirroring the existing
   `showPodName` used by the multi-pod viewer — same pattern, other axis.

2. Run Info's "Pod" field was plain text. It's now a ResourceLink (the same
   component GitOps/RBAC use for cross-resource links) into the pod itself.

Live-verified against a real 3-step TaskRun: Logs tab shows all three
steps' output concatenated in order with real timestamps, no pod-picker;
Pod field navigates to the Pod's own page.
The link lived inside the TaskRun's Overview body — easy to miss below the
badges and "Managed by" chip. Moved it into the same header chip row as
ManagedByChip/OpenInGitOpsChip (in both the compact drawer and full view
headers), styled the same way (a small skyhook-colored pill), instead of a
plain text link buried in the content.

The derivation itself is unchanged (TaskRun's ownerReferences), just
relocated from TaskRunRenderer's body to WorkloadView's shared header —
consistent with how GitOps ownership already gets a header chip there
rather than living in each renderer.
Step names were truncating at 140px — too tight for real pipelines whose
step names run 20+ characters (e.g. "step-start-build-stage-span").
A dedicated top-level view (new left-rail entry, /cicd) for operating on
Tekton PipelineRuns as a fleet, rather than only reachable one at a time
through the generic Resources browser:

- Header stat tiles (Total/Running/Succeeded/Failed/Success Rate, plus a
  Tasks Running count from TaskRuns) — each status tile doubles as a
  one-click filter, same pattern as GitOps's fleet header.
- Status and Pipeline facets in a filter rail, plus a search box, all
  computed client-side from the already-cached PipelineRun list (no new
  backend endpoints).
- Rich table rows: status badge, referenced Pipeline, a progress bar keyed
  off status.childReferences vs declared task count (colored by outcome,
  pulsing while running), duration, and age. The bar's denominator uses
  whichever of {declared, started} is larger so a `matrix`-strategy task
  (one declared task expanding into several childReferences) never renders
  as a backwards fraction like "12/7".
- Clicking a row opens the PipelineRun directly in the expanded full view
  (skipping the collapsed drawer, since the DAG only renders there) via the
  same navigateToResource-records-the-peek-owner mechanism GitOps and
  Applications already use — so the header's "Go back"/collapse control
  returns to the CI/CD tab instead of the generic PipelineRuns list.

Live-verified end-to-end: stat tiles and facets against 5 real PipelineRuns,
row click opening a running PipelineRun straight into its live DAG, and
back-navigation returning to /cicd.
panOnScroll + zoomOnScroll were both enabled with no translateExtent
bound, so an ordinary wheel/trackpad scroll over the panel (which has
no page scroll of its own) silently panned the graph's nodes off-
screen — reported as "the diagram appears, then blanks out". Drop
panOnScroll to match the other two ReactFlow views in this codebase
(TopologyGraph, GitOpsTreeGraph), which rely on the zoom-on-scroll
default with no pan-on-scroll, and bound min/max zoom like
GitOpsTreeGraph. Also adds the Controls (zoom in/out/fit-to-screen).
- Column headers are now clickable and sort the PipelineRun table
  (name, status, pipeline, progress, duration, started).
- Header restyled to match GitOps: PageHeader (left-aligned title +
  description, right-aligned FreshnessControl + stat tiles) instead
  of a hand-rolled title row.
- Filter sidebar gets a "Filters" header with a Clear link, matching
  GitOpsFilterSidebar.
- Root layout gets flex-1 min-w-0, fixing a right-edge gap where the
  view stopped short of the window width instead of filling it.
navigateToResource opens a peek outside /resources (CICD, GitOps,
Applications) purely via React state, with no URL backing — that's
what lets "Go back" return to the origin page. But drilling one hop
further (e.g. PipelineRun -> TaskRun via the DAG, or TaskRun -> back
to its PipelineRun) went through the other onNavigateToResource
handler, which unconditionally navigates to /resources/<kind>. That
silently relocated the backdrop into the Resources page, so a later
"Go back" landed on the generic resource list instead of back on the
CICD tab (or wherever the peek started).

Branch on the current pathname: only navigate to /resources/<kind>
when already there (the existing "list follows the drill" behavior
for genuine Resources-page drilling); otherwise update state only,
same as navigateToResource, so the backdrop never moves.
A peek opened directly to fullscreen (CICD table rows skip the small
drawer entirely) had nothing for "Go back"/collapse to fall back to,
so it collapsed into a small drawer the user never saw — confusing,
since there was no smaller state to "return" to. Track whether the
current peek ever visited the small state (peekOpenedFullRef, reset
on every normal navigateToResource open, set by the CICD opener right
after); onCollapse now closes outright for peeks that skipped it.
Each PipelineRun row gets a trailing actions menu (reusing the shared
RowActionMenu):
- Cancel run — patches spec.status to "Cancelled", enabled only while
  the run is actually running.
- Delete PipelineRun — the existing generic delete endpoint, behind a
  confirmation dialog.

Rows switch from <button> to a keyboard-accessible div (role="button",
Enter/Space handled) since a real <button> can't host the menu's own
nested button without producing invalid HTML.
…ve pipelines

Root-caused via a real platform-cicd pipeline with 11 tasks/28 edges,
comparing DOM state (node visibility, edge count, ReactFlow viewport
transform) between a healthy render and a blanked one — the data layer
(task statuses, ELK layout, taskKey) was identical in both; only the
DOM differed.

@xyflow/system's adoptUserNodes rebuilds a node's internal record from
scratch whenever the incoming node object isn't the exact same
reference as last render — true on every poll here, since the task
array was rebuilt fresh each time (useQueries returns a new array every
render; the outer tasks/onTaskClick were unstabilized on top of that).
The rebuild resets `measured` to undefined and clears cached handle
bounds, so the node goes visibility:hidden and its edges drop out until
a ResizeObserver fires to remeasure it — which never happens once the
card's on-screen size stops changing, since there's nothing new to
report. Denser real pipelines hit this far more (more polling, more
edges converging on shared "hub" tasks like tracing spans) than the
sparse synthetic pipelines used earlier, which is why it didn't
reproduce there.

Two changes close it:
- PipelineDagView: give every node explicit `measured` (width/height)
  and `handles` (position/x/y for its target+source connection points)
  up front, so both node visibility and edge connection points are
  answered from data instead of a live DOM measurement, independent of
  object identity. Also wraps the ReactFlow render in an error boundary
  so a future bad state renders a message instead of a silent blank.
- TektonPipelineFullscreen: stabilize the tasks array by a content
  signature (only produces a new reference when a task's status/reason/
  taskRunName actually changed) and memoize the task-click handler —
  removes the poll-driven churn that was the recurring trigger.
Matches the "Select multiple resources" pattern from the main
Resources table: a toggle button enters select mode (checkboxes per
row + a select-all header checkbox, row clicks toggle selection
instead of opening the drawer, the per-row actions menu hides), a
selection bar shows the count with Delete/Cancel, and Delete goes
through the existing useBulkDeleteResources mutation (parallel,
partial-failure-safe) behind a confirmation dialog listing the
targets.
Resolves the PipelineRun's pipelineRef to a real, navigable Pipeline
resource and opens it in the drawer on click — a direct name ref
lives in the run's own namespace, a cluster resolver ref carries its
own namespace param (platform-cicd's catalog pipelines live in a
shared namespace, not the run's, confirmed live). Other resolvers
(git/http/bundle) fetch the spec from outside the cluster, so there's
no live Pipeline object to open — those stay plain text. Opens as a
normal small drawer (not straight-to-fullscreen like a PipelineRun
row) since a Pipeline is a static template, not something actively
progressing.
…arrows

Pipeline task graphs fan out/in much more densely than the topology view's
own ownership hierarchy (several governance-check tasks depending on one
upstream task, converging on one downstream task) - the default spacing
(carried over from Topology's own numbers, and even tighter in edge/edge and
edge/node spacing, which wasn't set at all) let parallel edges visually run
together. Widens node/edge spacing, adds edge-edge/edge-node spacing that
wasn't set before, turns on mergeEdges so edges sharing an endpoint bundle
into one trunk instead of fanning out the whole way, and raises crossing-
minimization thoroughness (cheap at this task-graph size).
nodesDraggable was hardcoded off with no persistence path. Now nodes are
draggable, and dropping one persists every node's current position to
localStorage keyed by the task set's own shape (names + dependency edges) -
so a saved layout is naturally shared across every PipelineRun of the same
underlying Pipeline, not tied to one specific run. A "Reset layout" panel
button (shown only once a manual layout exists) clears the override and
restores ELK's auto-computed positions.

Structural re-layout (ELK) still only runs when the task set/dependency
shape changes; live status polling updates node data in place without
touching positions, whether auto-laid-out or hand-placed - unchanged from
before, just applied to a mutable node-position state (useNodesState)
instead of a derived-every-render array.
The pulsing opacity + spinning icon alone were easy to miss at a glance
across a busy pipeline DAG. Adds a sky-hued background wash and ring,
matching the icon's existing sky-500 running color, so a running task is
readable without having to spot the animation.
animate-pulse animates the whole card element's opacity, not just its
color - combined with the alpha-blended sky background from the previous
change, the card became translucent at the pulse's low point and let the
DAG's edge lines show straight through it (user-reported live testing).
Switched to a solid (non-alpha) background wash and removed animate-pulse
from the card entirely; the icon's own animate-spin still carries the
"in progress" motion cue.
Rebasing onto current upstream/main conflicted on the pinned counts this
branch's foundational commit set (upstream's own curated-column table grew
independently in the meantime). Resolved to upstream's current baseline
plus this branch's own +3 (Pipeline/PipelineRun/TaskRun), then verified
against a real test run rather than computed by hand.
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add Tekton pipeline views, live DAG, and CI/CD fleet

✨ Enhancement 🐞 Bug fix 📝 Documentation 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Adds Tekton resource discovery, statuses, tables, detail views, and navigation.
• Visualizes live PipelineRun dependencies in a draggable, persistent fullscreen DAG.
• Introduces CI/CD fleet actions, bulk deletion, and combined TaskRun step logs.
Diagram

graph TD
  A["CI/CD Fleet"] --> B["Resource API"] --> C["Tekton CRDs"]
  A --> D["PipelineRun View"] --> E["TaskRun Queries"] --> B
  D --> F["Live Task DAG"] --> G["TaskRun View"] --> H["Combined Logs"]
  H --> B
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Backend TaskRun status aggregation
  • ➕ Replaces per-child polling with one request.
  • ➕ Provides a consistent status snapshot for the entire DAG.
  • ➕ Scales better for large or matrix-expanded pipelines.
  • ➖ Requires a new backend contract and cache behavior.
  • ➖ Adds server-side Tekton-specific logic to a generic resource API.
2. List namespace TaskRuns once
  • ➕ Uses the existing generic list endpoint.
  • ➕ Reduces request count when pipelines contain many tasks.
  • ➖ May over-fetch unrelated historical TaskRuns.
  • ➖ Requires reliable client-side matching and potentially larger payloads.
  • ➖ Can perform worse in namespaces with extensive run history.

Recommendation: The current child-reference fan-out is appropriate for an initial integration because it reuses established resource queries, independently caches each TaskRun, and avoids broad namespace scans. Retain it now, but consider backend batch aggregation if telemetry shows large DAGs causing excessive five-second polling traffic.

Files changed (24) +2038 / -10

Enhancement (17) +1427 / -3
LogCore.tsxSupport container labels in combined log views +15/-0

Support container labels in combined log views

• Adds an optional container-name column to log lines, enabling readable multi-container logs from one pod.

packages/k8s-ui/src/components/logs/LogCore.tsx

ResourcesView.tsxAdd curated Tekton resource tables +82/-0

Add curated Tekton resource tables

• Defines Tekton columns and cells for task counts, statuses, references, and durations. Associates the tables with the tekton.dev API group.

packages/k8s-ui/src/components/resources/ResourcesView.tsx

index.tsExport Tekton resource utilities +1/-0

Export Tekton resource utilities

• Exposes Tekton status, reference, and DAG helpers through the resources package entry point.

packages/k8s-ui/src/components/resources/index.ts

PipelineRenderer.tsxAdd Pipeline compact detail renderer +57/-0

Add Pipeline compact detail renderer

• Displays declared task count, parameters, workspaces, and description while directing graph usage to the fullscreen view.

packages/k8s-ui/src/components/resources/renderers/PipelineRenderer.tsx

PipelineRunRenderer.tsxAdd PipelineRun compact detail renderer +59/-0

Add PipelineRun compact detail renderer

• Shows pipeline reference, timing, duration, failure information, and a fullscreen task-graph hint.

packages/k8s-ui/src/components/resources/renderers/PipelineRunRenderer.tsx

TaskRunRenderer.tsxAdd TaskRun status and step details +137/-0

Add TaskRun status and step details

• Renders step states, exit information, log actions, pod navigation, timing, parameters, results, and failures.

packages/k8s-ui/src/components/resources/renderers/TaskRunRenderer.tsx

index.tsExport Tekton renderers and DAG view +4/-0

Export Tekton renderers and DAG view

• Publishes the Pipeline, PipelineRun, TaskRun, and DAG components from the renderer barrel.

packages/k8s-ui/src/components/resources/renderers/index.ts

resource-utils-tekton.tsAdd Tekton status and DAG utilities +170/-0

Add Tekton status and DAG utilities

• Normalizes run conditions and resolver references, derives explicit and result-based task dependencies, resolves child TaskRuns, and merges live task statuses.

packages/k8s-ui/src/components/resources/resource-utils-tekton.ts

ResourceRendererDispatch.tsxDispatch Tekton statuses and detail renderers +19/-0

Dispatch Tekton statuses and detail renderers

• Recognizes all three Tekton kinds, routes them to dedicated renderers, and supports a host-provided TaskRun renderer override.

packages/k8s-ui/src/components/shared/ResourceRendererDispatch.tsx

WorkloadView.tsxLink TaskRuns back to parent PipelineRuns +40/-1

Link TaskRuns back to parent PipelineRuns

• Reads PipelineRun ownership from TaskRun metadata and adds explicit parent-navigation chips in compact and expanded headers.

packages/k8s-ui/src/components/workload/WorkloadView.tsx

resource-icons.tsAssign icons to Tekton resource kinds +6/-0

Assign icons to Tekton resource kinds

• Maps Pipelines and PipelineRuns to workflow icons and TaskRuns to a play icon.

packages/k8s-ui/src/utils/resource-icons.ts

CicdView.tsxAdd cluster-wide PipelineRun fleet view +676/-0

Add cluster-wide PipelineRun fleet view

• Implements live metrics, status and pipeline facets, search, sorting, progress, pipeline links, cancellation, deletion, and bulk selection. PipelineRun rows open directly into fullscreen details.

web/src/components/cicd/CicdView.tsx

TaskRunLogsTab.tsxCombine sequential TaskRun step logs +103/-0

Combine sequential TaskRun step logs

• Fetches the TaskRun pod's containers and combines logs in declared step order with source labels, refresh, clearing, errors, and downloads.

web/src/components/logs/TaskRunLogsTab.tsx

PrimaryNavRail.tsxAdd CI/CD to primary navigation +4/-1

Add CI/CD to primary navigation

• Adds the CI/CD view and workflow icon to the application navigation rail.

web/src/components/nav/PrimaryNavRail.tsx

TaskRunRenderer.tsxConnect TaskRun steps to docked logs +32/-0

Connect TaskRun steps to docked logs

• Wraps the shared TaskRun renderer and opens the selected step container in the floating multi-container log dock.

web/src/components/resources/renderers/TaskRunRenderer.tsx

command-items.tsRegister CI/CD as a command view +2/-1

Register CI/CD as a command view

• Extends the main-view type so command navigation can represent the CI/CD page.

web/src/components/ui/command-items.ts

WorkloadView.tsxIntegrate Tekton fullscreen views and logs +20/-0

Integrate Tekton fullscreen views and logs

• Wires Pipeline and PipelineRun fullscreen DAGs, the host TaskRun renderer, and the dedicated combined TaskRun logs tab into workload details.

web/src/components/workload/WorkloadView.tsx

Tests (1) +3 / -3
curated-column-ownership.test.tsUpdate curated-column ownership expectations +3/-3

Update curated-column ownership expectations

• Adjusts extraction and ownership counts for the three new Tekton resource table definitions.

packages/k8s-ui/src/components/resources/curated-column-ownership.test.ts

Documentation (2) +27 / -0
README.mdList Tekton Pipelines as a supported integration +1/-0

List Tekton Pipelines as a supported integration

• Adds Pipeline, PipelineRun, and TaskRun to the user-facing integration matrix.

README.md

integrations.mdDocument Tekton resource and DAG support +26/-0

Document Tekton resource and DAG support

• Explains Tekton detail views, fullscreen task graphs, inferred dependencies, live statuses, logs, browser columns, and supported CRDs.

docs/integrations.md

Other (4) +581 / -4
dynamic_cache.goDiscover Tekton CRDs through dynamic cache fallbacks +3/-0

Discover Tekton CRDs through dynamic cache fallbacks

• Registers namespaced Pipeline, PipelineRun, and TaskRun resources for tekton.dev/v1 with v1beta1 fallback.

internal/k8s/dynamic_cache.go

PipelineDagView.tsxImplement persistent live Tekton task DAG +408/-0

Implement persistent live Tekton task DAG

• Introduces an ELK-laid React Flow DAG with topology-style status cards, draggable nodes, local layout persistence, reset controls, and error isolation. Explicit node dimensions and handles prevent live updates from blanking nodes and edges.

packages/k8s-ui/src/components/resources/renderers/PipelineDagView.tsx

App.tsxRoute CI/CD fleet and preserve peek navigation +54/-4

Route CI/CD fleet and preserve peek navigation

• Registers the CI/CD route, title, shortcut, and view while wiring PipelineRun and Pipeline opens. Fixes fullscreen peek collapse and multi-hop drill-down behavior outside resource-list routes.

web/src/App.tsx

TektonPipelineFullscreen.tsxBuild fullscreen Pipeline and PipelineRun DAG data +116/-0

Build fullscreen Pipeline and PipelineRun DAG data

• Constructs static Pipeline graphs and polls child TaskRuns to color PipelineRun nodes live. Stabilizes task data references and routes clickable nodes to TaskRun details.

web/src/components/execution/TektonPipelineFullscreen.tsx

@qodo-code-review

qodo-code-review Bot commented Sep 3, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📜 Skill insights (0)

Grey Divider


Action required

1. Skipped tasks stay pending ✓ Resolved 🐞 Bug ≡ Correctness
Description
Tasks without a TaskRun child are unconditionally labeled pending, even though Tekton records
tasks skipped by when expressions in PipelineRun.status.skippedTasks without creating a child
reference. Completed PipelineRuns therefore show skipped nodes as permanently pending instead of
skipped.
Code

packages/k8s-ui/src/components/resources/resource-utils-tekton.ts[R164-168]

+  return tasks.map((task) => {
+    const live = statusByTaskName.get(task.name)
+    return live
+      ? { ...task, status: live.status, reason: live.reason, taskRunName: live.taskRunName }
+      : { ...task, status: 'pending' }
Relevance

●●● Strong

The pending fallback ignores Tekton's explicit skipped-task status, producing a concrete incorrect
completed-run display.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The status merger has only a live-child branch and a pending fallback, while Tekton documents
status.skippedTasks as the source of skip reasons and shows skipped tasks absent from
childReferences.

packages/k8s-ui/src/components/resources/resource-utils-tekton.ts[157-169]
web/src/components/execution/TektonPipelineFullscreen.tsx[51-63]
🌐 Tekton records tasks skipped by when expressions in the PipelineRun's Skipped Tasks status section while child references list created runs.

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The DAG treats every declared task lacking a child reference as pending and ignores `status.skippedTasks`.

## Issue Context
Merge `PipelineRun.status.skippedTasks` by task name before applying the pending fallback, preserving each skip reason. This must also cover skipped final tasks.

## Fix Focus Areas
- packages/k8s-ui/src/components/resources/resource-utils-tekton.ts[157-169]
- web/src/components/execution/TektonPipelineFullscreen.tsx[51-63]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Stale TaskRun logs persist ✓ Resolved 🐞 Bug ☼ Reliability
Description
load neither clears the buffer nor guards against an older request completing after the TaskRun
changes, and it replaces entries only on success. A failed refresh or a late response from the
previous pod can therefore leave that pod's logs displayed in the current TaskRun view.
Code

web/src/components/logs/TaskRunLogsTab.tsx[R31-45]

+  const load = useCallback(async () => {
+    if (!podName) return
+    setIsLoading(true)
+    setFetchError(null)
+    try {
+      const data = await fetchJSON<{ logs: Record<string, string> }>(`/pods/${namespace}/${podName}/logs`)
+      const combined = stepNames.flatMap((container) => {
+        const raw = data.logs?.[container]
+        if (!raw) return []
+        return raw.split('\n').filter(Boolean).map((line) => {
+          const { timestamp, content } = parseLogLine(line)
+          return { timestamp, content, container }
+        })
+      })
+      set(combined)
Relevance

●●● Strong

Accepted log lifecycle precedents address stale buffers and late responses when changing log
sources.

PR-#870

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The newly added loader clears only the error state and writes the buffer only after a successful
response; it has no cancellation or request-generation check. This is the same stale-buffer
lifecycle pattern previously accepted for log viewers when changing their source.

web/src/components/logs/TaskRunLogsTab.tsx[25-53]
PR-#870

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The TaskRun log buffer can retain or be overwritten by entries belonging to a prior pod when loads fail or resolve out of order.

## Issue Context
A TaskRun change recomputes `load` and invokes it through the effect, but in-flight requests are not cancelled or identified. Clear stale entries at load start and ignore completions whose request identity is no longer current.

## Fix Focus Areas
- web/src/components/logs/TaskRunLogsTab.tsx[31-53]
- packages/k8s-ui/src/components/logs/useLogBuffer.ts[123-135]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Matrix statuses get overwritten ✓ Resolved 🐞 Bug ≡ Correctness
Description
buildChildTaskRunRefs keys children solely by pipelineTaskName, so each matrix expansion
overwrites the preceding TaskRun for that logical task. The DAG consequently polls, displays, and
links only the last retained matrix child rather than the aggregate state, potentially showing
success when another expansion failed and exposing an arbitrary child for navigation.
Code

packages/k8s-ui/src/components/resources/resource-utils-tekton.ts[R134-138]

+export function buildChildTaskRunRefs(pipelineRunStatus: any): Map<string, { taskRunName: string }> {
+  const refs = new Map<string, { taskRunName: string }>()
+  for (const child of pipelineRunStatus?.childReferences ?? []) {
+    if (child?.kind === 'TaskRun' && child?.pipelineTaskName && child?.name) {
+      refs.set(child.pipelineTaskName, { taskRunName: child.name })
Relevance

●●● Strong

Duplicate matrix children are discarded by a deterministic map-key bug, causing incorrect status and
navigation.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The map repeatedly calls set with the same pipelineTaskName, causing each reference to replace
the preceding value, while both the repository's CI/CD implementation and Tekton's matrix
documentation establish that matrix tasks can produce multiple child TaskRuns sharing that name. The
fullscreen query fan-out fetches only the retained map values after the duplicate keys have already
been discarded, so its displayed status and click navigation depend on child-reference ordering.

packages/k8s-ui/src/components/resources/resource-utils-tekton.ts[134-141]
web/src/components/execution/TektonPipelineFullscreen.tsx[34-61]
web/src/components/cicd/CicdView.tsx[111-119]
web/src/components/execution/TektonPipelineFullscreen.tsx[40-63]
🌐 Tekton documents that a PipelineTask with a Matrix creates multiple uniquely suffixed child TaskRuns.
🌐 Tekton documents that a matrix creates multiple TaskRuns with the same pipelineTaskName and lists each in status.childReferences.

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Matrix-expanded TaskRuns share a `pipelineTaskName`, but `buildChildTaskRunRefs` retains only the final child reference, causing the fullscreen DAG to omit sibling executions.

## Issue Context
Preserve every child reference because the fullscreen view fetches and renders exactly the references returned by this map. Either render individual matrix executions or aggregate their statuses deterministically, with failure taking precedence over running, pending, and success; status and navigation must not depend on child-reference ordering or silently select an arbitrary child.

## Fix Focus Areas
- packages/k8s-ui/src/components/resources/resource-utils-tekton.ts[128-141]
- web/src/components/execution/TektonPipelineFullscreen.tsx[34-63]
- packages/k8s-ui/src/components/resources/renderers/PipelineDagView.tsx[165-175]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View high (2)
4. Finally tasks omitted ✓ Resolved 🐞 Bug ≡ Correctness
Description
buildPipelineTaskGraph reads only pipelineSpec.tasks, so every spec.finally task is absent
from Pipeline and PipelineRun DAGs, compact task counts, live statuses, and navigation. This hides
final-task execution and failures even though Tekton runs these tasks after all regular tasks and
includes their outcomes in the PipelineRun result.
Code

packages/k8s-ui/src/components/resources/resource-utils-tekton.ts[R112-115]

+export function buildPipelineTaskGraph(pipelineSpec: any): TektonTaskNode[] {
+  const tasks: any[] = pipelineSpec?.tasks ?? []
+  return tasks.map((task) => {
+    const deps = new Set<string>(task.runAfter ?? [])
Relevance

●●● Strong

This is a concrete completeness bug hiding Tekton finally-task execution from DAGs and counts.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The graph builder maps only pipelineSpec.tasks, while both the fullscreen DAG rendering and
compact task counts consume that builder. Tekton documents finally as a list of Pipeline tasks
that run after all regular PipelineTasks and contribute to PipelineRun status, demonstrating that
omitting them hides tasks that participate in execution and affect the final result.

packages/k8s-ui/src/components/resources/resource-utils-tekton.ts[112-121]
web/src/components/execution/TektonPipelineFullscreen.tsx[30-32]
packages/k8s-ui/src/components/resources/renderers/PipelineRunRenderer.tsx[21-22]
packages/k8s-ui/src/components/resources/resource-utils-tekton.ts[112-120]
web/src/components/execution/TektonPipelineFullscreen.tsx[29-32]
🌐 Tekton documents that finally tasks execute after all regular PipelineTasks and participate in the PipelineRun's final status.

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Tekton `spec.finally` tasks are excluded from the task graph because `buildPipelineTaskGraph` reads only `pipelineSpec.tasks`, hiding their execution and terminal status from Pipeline and PipelineRun views.

## Issue Context
Finally tasks execute after all regular PipelineTasks and contribute to the final PipelineRun result. Include them as graph nodes with live TaskRun status, and model dependency edges that represent the barrier after the ordinary task phase settles so their failures and outcomes appear in DAGs, task counts, statuses, and navigation.

## Fix Focus Areas
- packages/k8s-ui/src/components/resources/resource-utils-tekton.ts[112-121]
- packages/k8s-ui/src/components/resources/renderers/PipelineRunRenderer.tsx[21-22]
- web/src/components/execution/TektonPipelineFullscreen.tsx[29-63]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Container names are synthesized ✓ Resolved 🐞 Bug ≡ Correctness
Description
Both TaskRun log paths construct step-${step.name} instead of using the authoritative
status.steps[].container value. If Tekton's generated container name differs, combined logs
silently omit that step and the per-step Logs button requests a nonexistent container.
Code

web/src/components/logs/TaskRunLogsTab.tsx[R21-23]

+  const stepNames = useMemo(
+    () => ((resource?.status?.steps ?? []) as Array<{ name: string }>).map((s) => `step-${s.name}`),
+    [resource],
Relevance

●●● Strong

Authoritative container names should come from Tekton status; synthesized names can silently target
nonexistent containers.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The combined tab and both renderer layers derive names from step.name. Tekton added the
TaskRun.Status.Steps.Container field specifically so integrations would not infer internal
container names, after that inference had broken consumers.

web/src/components/logs/TaskRunLogsTab.tsx[19-24]
web/src/components/resources/renderers/TaskRunRenderer.tsx[17-27]
packages/k8s-ui/src/components/resources/renderers/TaskRunRenderer.tsx[17-20]
🌐 Tekton added TaskRun.Status.Steps.Container because integrations deriving pod container names from step names had broken.

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
TaskRun log consumers derive internal pod container names from step names instead of reading the container field reported by Tekton.

## Issue Context
Use `status.steps[].container` as the primary container name, with the synthesized form only as a compatibility fallback for old objects that omit the field. Apply this consistently to combined logs and dock log actions.

## Fix Focus Areas
- web/src/components/logs/TaskRunLogsTab.tsx[19-24]
- web/src/components/resources/renderers/TaskRunRenderer.tsx[14-27]
- packages/k8s-ui/src/components/resources/renderers/TaskRunRenderer.tsx[17-20]
- packages/k8s-ui/src/components/resources/renderers/TaskRunRenderer.tsx[48-57]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

6. Dependency edits remain stale ✓ Resolved 🐞 Bug ≡ Correctness
Description
The fullscreen task stabilization signature omits dependsOn, so Pipeline updates that change
runAfter or implicit result-reference dependencies without renaming tasks leave tasksRef
pointing to the old graph. Consequently, PipelineDagView continues displaying stale edges and
topology even after the updated Pipeline resource is received.
Code

web/src/components/execution/TektonPipelineFullscreen.tsx[R79-84]

+  const tasksSigRef = useRef('')
+  const tasksRef = useRef(rawTasks)
+  const sig = rawTasks.map((t) => `${t.name}:${t.status ?? ''}:${t.reason ?? ''}:${t.taskRunName ?? ''}`).join('|')
+  if (sig !== tasksSigRef.current) {
+    tasksSigRef.current = sig
+    tasksRef.current = rawTasks
Relevance

●●● Strong

Dependency-only graph changes are omitted from the stabilization signature, causing deterministic
stale DAG topology.

PR-#982

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The graph builder places dependency names in each task node's dependsOn, and PipelineDagView
uses those dependencies to key its structural layout. However, the stabilization signature compares
only task name, status, reason, and TaskRun name, so dependency-only changes are not detected and
the old task array remains in tasksRef, preventing PipelineDagView from observing the updated
graph structure.

packages/k8s-ui/src/components/resources/resource-utils-tekton.ts[112-121]
web/src/components/execution/TektonPipelineFullscreen.tsx[71-86]
packages/k8s-ui/src/components/resources/renderers/PipelineDagView.tsx[298-320]
web/src/components/execution/TektonPipelineFullscreen.tsx[79-86]
packages/k8s-ui/src/components/resources/resource-utils-tekton.ts[112-120]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The DAG task array is intentionally stabilized using visible status fields, but its content signature omits the `dependsOn` dependency shape used by `PipelineDagView`. As a result, dependency-only Pipeline updates do not replace the stabilized task array or trigger a topology update.

## Issue Context
Include a deterministic representation of dependencies in the stabilization signature, including task ordering where relevant, so changes to `runAfter` or implicit result-reference dependencies reach `PipelineDagView`. Preserve stabilization for status-only no-op renders while ensuring the child can update the structural layout keyed from `dependsOn`.

## Fix Focus Areas
- web/src/components/execution/TektonPipelineFullscreen.tsx[71-86]
- packages/k8s-ui/src/components/resources/resource-utils-tekton.ts[112-121]
- packages/k8s-ui/src/components/resources/renderers/PipelineDagView.tsx[298-320]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. PipelineDagView comments record history ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
Added comments describe prior behavior using before, previously, and Now. This embeds change
history in code comments instead of documenting only the current rationale.
Code

packages/k8s-ui/src/components/resources/renderers/PipelineDagView.tsx[80]

+  // Not set at all before - default edge-edge/edge-node spacing is tight
Relevance

●●● Strong

Same-day precedent accepted rewriting comments that describe prior implementations instead of
current rationale.

PR-#1614

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 3036538 prohibits explicit change-history phrases in code comments. The cited comments use
before, previously, and Now to contrast prior and current implementations.

Rule 3036538: Disallow references to tickets or PR history in code comments
packages/k8s-ui/src/components/resources/renderers/PipelineDagView.tsx[80-95]
packages/k8s-ui/src/components/resources/renderers/PipelineDagView.tsx[182-189]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Comments in `PipelineDagView` describe how the implementation behaved before this change, violating the prohibition on PR or change-history commentary.

## Issue Context
Preserve useful ELK-layout and running-state rationale, but state it entirely in terms of current constraints and behavior.

## Fix Focus Areas
- packages/k8s-ui/src/components/resources/renderers/PipelineDagView.tsx[80-95]
- packages/k8s-ui/src/components/resources/renderers/PipelineDagView.tsx[182-189]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Parent PipelineRun link never appears ✓ Resolved 🐞 Bug ≡ Correctness
Description
The shared workload view tests for singular TaskRun, but the web wrapper passes the plural API
resource name taskruns. As a result, tektonParentPipelineRun is always null and TaskRun pages
never show the new parent PipelineRun chip.
Code

packages/k8s-ui/src/components/workload/WorkloadView.tsx[R628-633]

+  const tektonParentPipelineRun = useMemo(() => {
+    // `kind` (URL-derived, not resource.kind — list items often arrive with
+    // TypeMeta stripped) is the reliable signal here.
+    if (kind !== 'TaskRun') return null
+    const owner = (resource?.metadata?.ownerReferences ?? []).find((o: any) => o?.kind === 'PipelineRun')
+    return owner?.name ? { name: owner.name as string, namespace: resource?.metadata?.namespace ?? '' } : null
Relevance

●●● Strong

Singular/plural kind mismatch makes the newly intended parent link unreachable for actual TaskRun
pages.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The web view derives apiKind with kindToPluralWithGroup and passes it as kind to the shared
view. The new check requires the singular spelling, making the subsequent owner-reference logic
unreachable for actual TaskRuns.

packages/k8s-ui/src/components/workload/WorkloadView.tsx[628-634]
web/src/components/workload/WorkloadView.tsx[495-505]
web/src/components/workload/WorkloadView.tsx[1126-1132]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
TaskRun parent detection compares against a singular kind even though this shared component receives an API resource plural.

## Issue Context
Use the normalized plural kind consistently, or normalize it with `pluralToKind` before performing the comparison.

## Fix Focus Areas
- packages/k8s-ui/src/components/workload/WorkloadView.tsx[628-634]
- web/src/components/workload/WorkloadView.tsx[495-505]
- web/src/components/workload/WorkloadView.tsx[1126-1132]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View medium (5)
9. Status badges bypass Badge ✗ Dismissed 📘 Rule violation ⚙ Maintainability
Description
PipelineRun and TaskRun statuses are rendered as styled <span> elements using badge and color
classes rather than the shared <Badge> component. This bypasses the required semantic severity
or kind appearance API.
Code

packages/k8s-ui/src/components/resources/ResourcesView.tsx[R8631-8632]

+      const status = getTektonPipelineRunStatus(resource)
+      return <span className={clsx('badge', status.color)}>{status.text}</span>
Relevance

●●● Strong

Team accepted replacing badge-like spans with shared Badge components in a recent renderer
precedent.

PR-#1018

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 3036677 requires badge-like status labels to use <Badge> with semantic appearance props. The
cited additions render Tekton statuses through <span className={clsx('badge', status.color)}>
instead.

Rule 3036677: Use Badge components instead of hard-coded badge color strings
packages/k8s-ui/src/components/resources/ResourcesView.tsx[8628-8650]
web/src/components/cicd/CicdView.tsx[584-585]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New Tekton status labels are implemented as manually styled badge spans instead of the shared `Badge` component.

## Issue Context
Map the normalized Tekton health level to the supported semantic `severity` or `kind` prop and retain the existing status text.

## Fix Focus Areas
- packages/k8s-ui/src/components/resources/ResourcesView.tsx[8628-8650]
- web/src/components/cicd/CicdView.tsx[584-585]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


10. Query failures appear empty ✓ Resolved 🐞 Bug ◔ Observability
Description
When the PipelineRun query fails, runs falls back to an empty array and the view displays “No
PipelineRuns found” because no error branch is rendered. Missing RBAC, API failures, or discovery
failures are therefore misreported as a healthy empty fleet.
Code

web/src/components/cicd/CicdView.tsx[R505-510]

+            {runsQuery.isLoading ? (
+              <div className="p-4 text-sm text-theme-text-tertiary">Loading PipelineRuns…</div>
+            ) : filteredRuns.length === 0 ? (
+              <div className="flex h-full items-center justify-center text-sm text-theme-text-tertiary">
+                {runs.length === 0 ? 'No PipelineRuns found.' : 'No PipelineRuns match the current filters.'}
+              </div>
Relevance

●●● Strong

Missing query-error rendering misreports API failures as empty data; this is a straightforward
observability fix.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The query can reject through fetchJSON, but data is converted to [] and rendering distinguishes
only loading and empty states; runsQuery.isError and runsQuery.error are never inspected.

web/src/components/cicd/CicdView.tsx[249-258]
web/src/components/cicd/CicdView.tsx[275-283]
web/src/components/cicd/CicdView.tsx[504-510]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The CI/CD fleet treats failed PipelineRun requests as successful empty responses.

## Issue Context
Render an explicit error state from `runsQuery.error` with retry/refresh support. Also surface the TaskRun statistics query failure rather than displaying a misleading zero.

## Fix Focus Areas
- web/src/components/cicd/CicdView.tsx[249-273]
- web/src/components/cicd/CicdView.tsx[275-283]
- web/src/components/cicd/CicdView.tsx[504-510]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


11. Running logs never update ✓ Resolved 🐞 Bug ≡ Correctness
Description
TaskRunLogsTab fetches one snapshot on mount and explicitly disables streaming, with no polling or
other live refresh. Logs emitted after the tab opens remain invisible until the user manually
refreshes, including output from a currently running step.
Code

web/src/components/logs/TaskRunLogsTab.tsx[R92-95]

+      isLoading={isLoading}
+      isStreaming={false}
+      onStopStream={() => {}}
+      onRefresh={load}
Relevance

●●● Strong

Recent precedent explicitly accepted missing live log updates and enabled streaming by default for
running workloads.

PR-#870

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The only automatic invocation of load is the mount effect, and LogCore is configured with
isStreaming={false} and no start-stream callback. Running steps nevertheless expose the same
logging UI.

web/src/components/logs/TaskRunLogsTab.tsx[31-53]
web/src/components/logs/TaskRunLogsTab.tsx[89-100]
packages/k8s-ui/src/components/resources/renderers/TaskRunRenderer.tsx[23-35]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The TaskRun Logs tab presents a one-time snapshot even while the TaskRun is active.

## Issue Context
Add streaming or bounded polling while the TaskRun is non-terminal, merging all step containers without duplicating lines. Stop live activity when the run reaches a terminal condition or the component unmounts, then perform a final snapshot refresh.

## Fix Focus Areas
- web/src/components/logs/TaskRunLogsTab.tsx[31-53]
- web/src/components/logs/TaskRunLogsTab.tsx[89-100]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


12. Browser Back reopens drawer ✓ Resolved 🐞 Bug ≡ Correctness
Description
Opening a PipelineRun from CI/CD selects the resource and then pushes ?full=1; browser Back only
removes that flag while leaving the resource selected. The supposedly fullscreen-only peek
consequently reappears as a compact drawer over CI/CD instead of closing.
Code

web/src/App.tsx[R2319-2322]

+              navigateToResource({ kind: 'pipelineruns', namespace, name, group: 'tekton.dev' })
+              // Opened straight to fullscreen — there's no small-drawer state
+              // to collapse back to, so "Go back" should close outright.
+              peekOpenedFullRef.current = true
Relevance

●●● Strong

Recent App drawer precedents accepted fixes preventing stale fullscreen state and incorrect
back/collapse behavior.

PR-#1050

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The opener creates state selection before pushing the fullscreen query parameter, while
peekOpenedFullRef is consulted only by the explicit collapse callback. Removing the query
parameter through browser history therefore leaves selection intact and allows compact rendering.

web/src/App.tsx[608-614]
web/src/App.tsx[2315-2325]
web/src/App.tsx[2427-2430]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Browser Back from a CI/CD PipelineRun fullscreen peek removes `full=1` but does not clear its state-only selected resource.

## Issue Context
Track fullscreen-only peek ownership in URL-pop reconciliation and close the resource when its fullscreen history entry is popped. Preserve normal expanded drawers that genuinely have a compact state to collapse into.

## Fix Focus Areas
- web/src/App.tsx[608-614]
- web/src/App.tsx[2315-2325]
- web/src/App.tsx[2427-2430]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


13. Renderer sections start collapsed ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The new renderer sections contain real content but either omit defaultExpanded={true} or
explicitly set it to false without being marked low-priority. This violates the required default
expansion behavior for renderer content.
Code

packages/k8s-ui/src/components/resources/renderers/TaskRunRenderer.tsx[117]

+        <Section title="Parameters" defaultExpanded={false}>
Relevance

●● Moderate

The rule is explicit, but available history lacks a close renderer-section precedent establishing
team behavior.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 3036709 requires every populated, normal-priority renderer section to explicitly set
defaultExpanded={true}. The new Parameters and Results sections set the value to false, while
the other cited populated Tekton sections omit it entirely.

Rule 3036709: Renderer sections with content must explicitly set defaultExpanded to true
packages/k8s-ui/src/components/resources/renderers/PipelineRenderer.tsx[20-53]
packages/k8s-ui/src/components/resources/renderers/PipelineRunRenderer.tsx[41-55]
packages/k8s-ui/src/components/resources/renderers/TaskRunRenderer.tsx[91-133]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Populated Tekton renderer sections are not explicitly expanded by default, and the Parameters and Results sections are explicitly collapsed.

## Issue Context
Add `defaultExpanded={true}` to every non-empty, normal-priority `Section`. If a section is genuinely low-priority, mark it with the component's supported low-priority mechanism before allowing it to remain collapsed.

## Fix Focus Areas
- packages/k8s-ui/src/components/resources/renderers/PipelineRenderer.tsx[20-53]
- packages/k8s-ui/src/components/resources/renderers/PipelineRunRenderer.tsx[41-55]
- packages/k8s-ui/src/components/resources/renderers/TaskRunRenderer.tsx[91-133]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

14. Status backgrounds bypass theme tokens 📘 Rule violation ⚙ Maintainability
Description
New components use hardcoded bg-sky-*, bg-emerald-*, bg-red-*, bg-amber-*, and
bg-skyhook-* utilities. These backgrounds will not consistently follow the configured application
theme.
Code

web/src/components/cicd/CicdView.tsx[R127-130]

+    running: 'bg-sky-500',
+    succeeded: 'bg-emerald-500',
+    failed: 'bg-red-500',
+    cancelled: 'bg-amber-500',
Relevance

● Weak

A same-day precedent rejected palette-specific color replacement with theme tokens, closely matching
this maintainability rule.

PR-#1614

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 3036653 restricts frontend background utilities to the approved theme tokens. The cited
additions directly introduce multiple palette-specific background classes without a documented
design-spec exception.

Rule 3036653: Use theme background tokens instead of hardcoded utility color classes
web/src/components/cicd/CicdView.tsx[127-131]
web/src/components/cicd/CicdView.tsx[449-468]
packages/k8s-ui/src/components/resources/renderers/PipelineDagView.tsx[190-191]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new Tekton UI uses background colors outside the approved theme background tokens.

## Issue Context
Rule 3036653 permits `bg-theme-base`, `bg-theme-surface`, `bg-theme-elevated`, and `bg-theme-hover`. Refactor status, selection, and action backgrounds to approved theme or design-system components without losing state communication.

## Fix Focus Areas
- packages/k8s-ui/src/components/resources/renderers/PipelineDagView.tsx[190-191]
- web/src/components/cicd/CicdView.tsx[127-131]
- web/src/components/cicd/CicdView.tsx[449-468]
- web/src/components/cicd/CicdView.tsx[565-566]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 41 rules
✅ Web pages:
  +15 more
Review mode: 🧠 Deep: This is a broad, behavior-heavy Tekton integration spanning API/resource handling, live DAG state, logs, navigation, deletion actions, and a new fleet UI, creating many independent paths where a redundant review can catch subtle defects.

Grey Divider

Tip of the day
💡 Did you know, you can show, collapse, or hide each part of a finding: code, evidence, and all

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread packages/k8s-ui/src/components/resources/renderers/PipelineDagView.tsx Outdated
Comment thread packages/k8s-ui/src/components/resources/ResourcesView.tsx
Comment thread packages/k8s-ui/src/components/resources/renderers/TaskRunRenderer.tsx Outdated
Comment thread packages/k8s-ui/src/components/resources/resource-utils-tekton.ts
Comment thread packages/k8s-ui/src/components/resources/resource-utils-tekton.ts Outdated
Comment thread web/src/components/execution/TektonPipelineFullscreen.tsx
Comment thread web/src/components/cicd/CicdView.tsx
Comment thread web/src/App.tsx
Comment thread packages/k8s-ui/src/components/workload/WorkloadView.tsx
Comment thread web/src/components/logs/TaskRunLogsTab.tsx
Comment thread packages/k8s-ui/src/components/resources/resource-utils-tekton.ts
Comment thread packages/k8s-ui/src/components/resources/resource-utils-tekton.ts
jfillman and others added 2 commits September 3, 2026 22:24
buildPipelineTaskGraph correctly infers a task dependency from a
$(tasks.X.results.Y) param reference in addition to explicit runAfter
— but real pipelines commonly pipe a value (a trace ID, a shared
config blob) from an early task into nearly every later task's
params. Each of those is a genuine Tekton ordering constraint, but
when it's already implied by a longer runAfter chain, drawing it as a
direct edge too puts a fan of redundant arrows into one node instead
of the single "runs right after X" edge a reader expects.

Found live on the real "build" Pipeline (platform-catalog namespace):
build-source's only runAfter is start-build-stage-span, but it also
references start-flow's and validate-config's results for tracing/
config — both already ancestors of start-build-stage-span — producing
3 arrows into build-source instead of 1.

Added a standard transitive-reduction pass: drop a dependency only
when it's also reachable through one of the task's other direct
dependencies, so genuinely independent deps (a real fan-in) are left
untouched. New tests pin both the real-pipeline scenario and a
diamond fan-out/fan-in case that must survive unreduced.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
buildPipelineTaskGraph only read pipelineSpec.tasks, so a Pipeline's
finally tasks — cleanup/notify steps Tekton always runs after every
regular task settles, success or failure — were invisible in Pipeline
and PipelineRun DAGs, and undercounted in every "N tasks" readout
(PipelineRenderer, the Resources table's Pipeline column, the CI/CD
fleet's progress fraction).

finally tasks don't support runAfter (Tekton rejects the field there),
and the real ordering constraint is absolute — every finally task
waits for the WHOLE regular task graph to settle, not just the tasks
it happens to read a result from. Modeled that as a dependency on
every regular task with nothing else depending on it (the graph's own
terminal/leaf tasks), plus each finally task's own explicit
$(tasks.X.results.Y) refs; the existing transitive-reduction pass then
drops any of those that are already implied by a barrier edge.

Verified against the real "build" Pipeline (platform-catalog
namespace, 5 finally tasks including end-flow, notify, and
send-cdevent) — every finally task now correctly depends on the 3 true
terminal regular tasks (pipelinerun-started, image-scan,
generate-sbom), matching Tekton's actual scheduling.

Found independently by both the qodo-code-review and cursor[bot]
automated PR reviews ("Finally tasks omitted").

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Comment thread packages/k8s-ui/src/components/resources/resource-utils-tekton.ts
jfillman and others added 7 commits September 3, 2026 22:55
… last one

buildChildTaskRunRefs keyed its map by pipelineTaskName alone, so a
matrix-strategy task's several childReferences (one per parameter
combination, all sharing that name) overwrote each other — only the
last-listed sibling's status ever reached the DAG, and a click could
land on an arbitrary matrix child instead of an actionable one.

Return every childReference per task name instead of one, fan out a
query per actual TaskRun (not per declared task), and collapse the
results with worst-status-wins ranking (failed > running > unknown/
pending > skipped > succeeded) — a single failure among nine
successes now surfaces as failed, and the DAG node's navigation
target is the failed sibling, not whichever happened to be listed
last.

Also fixed a second, related staleness bug in the same component: the
fullscreen DAG's array-stabilization signature covered name/status/
reason/taskRunName but not dependsOn, so a Pipeline edit that changed
runAfter or a result-ref dependency without renaming any task left the
DAG showing the old topology until something else (a status change)
happened to bust the cache.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A task Tekton decides not to run (a false when guard, or a parent
that failed/was itself skipped) never gets a childReference — the
same absence-from-the-map signal applyTaskRunStatuses used for "not
reached yet." A completed PipelineRun with a skipped task therefore
showed it as permanently pending, with no way to tell "hasn't started"
from "was never going to run."

Tekton already records the distinction in status.skippedTasks[], with
the reason it decided to skip each one. Read that and mark a matching
task 'skipped' (surfacing the real reason) before falling back to
'pending' — PipelineDagView already has skipped styling, it just never
got exercised for this case.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
qodo/cursor flagged the TaskRun-to-parent-PipelineRun chip as always
null, blaming a plural/singular mismatch — that specific claim doesn't
hold: WorkloadView's kind prop is a plural ("taskruns"), but the
component already derives a singular `kind = pluralToKind(kindProp)`
before the comparison, and once API discovery has populated the
dynamic map (effectively always, by the time a user can navigate to a
TaskRun), pluralToKind('taskruns') correctly resolves to 'TaskRun'.

There's a real, narrower gap behind the same finding though:
BUILTIN_PLURAL_TO_KIND (the fallback used before discovery completes)
never had Tekton's kinds, even though it already seeds Argo Workflow's
for exactly this reason. Tekton's "Run" suffix doesn't naively
de-pluralize to the right casing either — the heuristic fallback would
produce "Taskrun", not "TaskRun" — so a very early render, or a
restricted-RBAC cluster where Tekton CRD discovery is delayed, could
still show the chip as missing. Seeded pipelines/pipelineruns/taskruns
the same way workflows already are.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…y list

runsQuery.data falling back to `?? []` on a failed fetch meant an RBAC
denial, a backend error, or a discovery failure all rendered as "No
PipelineRuns found" — a healthy-looking empty fleet indistinguishable
from an actual problem. Added an explicit error branch (special-cased
for 403) with a Retry button. The Tasks Running tile now also treats
its own query error the same as still-loading — a 0 there was a false
zero, not a real count, same reasoning the component's own loading
prop already documents.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…x a log race

Three related TaskRun log bugs, found by qodo-code-review:

- Container names were synthesized as step-<name> in three places
  instead of reading status.steps[].container, the field Tekton
  actually reports. Every live example checked matches the synthesized
  form today, but Tekton doesn't guarantee it once a step name gets
  sanitized or truncated to fit Kubernetes' container-name limit — the
  authoritative field is one field access away and was sitting unused
  (one comment even claimed it wasn't reported back, which isn't true).
  Kept the synthesized form only as a fallback for an older/stripped
  status shape.

- TaskRunLogsTab fetched one snapshot on mount and never again unless
  the user manually refreshed — output from a currently running step
  stayed invisible. Added polling every 5s while the TaskRun's
  Succeeded condition hasn't settled, stopping as soon as it does (or
  the component unmounts).

- The same fetch had no guard against out-of-order responses: if
  podName changed (a different TaskRun) while a previous fetch was
  still in flight, a late-arriving stale response could overwrite the
  fresh one. Added a request-generation guard, and clear the buffer
  when the pod actually changes (not on a plain manual refresh of the
  same pod, which intentionally leaves it alone so the view doesn't
  flash empty).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…e it

Opening a PipelineRun from the CI/CD table selects the resource and
pushes ?full=1 straight to fullscreen — there's no small-drawer state
underneath it (peekOpenedFullRef already exists to mark exactly this
case, consulted by the collapse button's onCollapse handler). Browser
Back naturally pops that history entry, dropping ?full=1 while leaving
selectedResource set — correct behavior for a peek that WAS expanded
from an already-open small drawer (it correctly collapses back to
one), but for the never-small CI/CD case it left a compact drawer
reappearing over the CI/CD table instead of actually closing.

Added a Pop-only effect that closes the peek outright in that specific
case, mirroring what the collapse button already does via the same
peekOpenedFullRef flag — no URL writes, so it can't interact with the
file's existing Pop/URL-write-suppression machinery.

This file has no automated routing tests and I don't have browser
tooling in this session to click through the actual back-button flow
— worth a manual spot-check (open a PipelineRun from CI/CD, hit Back)
before relying on it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…Results

Two comments in PipelineDagView described prior behavior ("not set at
all before", "previously relied on... now a solid...") instead of just
the current rationale — rewritten to state only why the code is what
it is, per this repo's own comment rule.

TaskRun's Parameters and Results sections explicitly defaulted to
collapsed; every other populated section on the same page (Steps, Run
Info) relies on the shared Section component's own default (expanded)
per this repo's stated convention (defaultExpanded unless empty/low-
priority). Parameters/Results are the same plain PropertyList shape as
Run Info, not verbose or low-priority — often the single most useful
thing on a TaskRun page (what it was given, what it produced) —
dropped the override so they expand by default too.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit db1d377. Configure here.

Comment thread web/src/App.tsx
Comment thread web/src/components/execution/TektonPipelineFullscreen.tsx
jfillman and others added 3 commits September 3, 2026 23:40
…r outranks known statuses

Two real bugs cursor found in the fixes from the last round, both
confirmed against the actual code:

- peekOpenedFullRef was reset only at the top of navigateToResource (a
  fresh peek open) — every other setSelectedResource(null) call site in
  this file (list-kind change, route mismatch, Escape, several others)
  left it untouched. After one CI/CD fullscreen visit, if the peek
  later closed through any of those other paths, the ref stayed stale
  true — misclassifying a LATER, legitimately small-drawer-backed peek
  as never-small the next time either the new Back-close effect or the
  existing collapse button consulted it, closing it outright instead
  of collapsing. Added a catch-all effect that clears the ref the
  instant there's no peek left, regardless of which path closed it.

- STATUS_SEVERITY ranked 'unknown' above pending/skipped/succeeded, so
  aggregateMatrixStatuses could let one matrix sibling's in-flight or
  permanently-404ing fetch (a garbage-collected TaskRun/pod — a normal
  race, not an error) mask that the other nine siblings were already
  known to have succeeded. unknown now ranks last: every other status
  is something Tekton actually reported, so any of them is more
  informative than "we don't know" and should win the aggregate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
getTektonPipelineStatus only counted spec.tasks, while the DAG, table,
and drawer already count finally tasks too via buildPipelineTaskGraph
— a Pipeline with cleanup/notify finally tasks showed a smaller total
in its header badge than in its own Tasks section.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
logsTabVisible required allPods.length > 0, and pod discovery for
these two kinds only ever succeeds through relationships/timeline
attribution — there's no topology-graph awareness of Tekton kinds at
all, and the timeline path depends on Radar's own Pod-lifecycle event
for that specific pod still being in the fixed-size event ring buffer
(ExtractOwner resolves ownerReferences for a Pod's own tracked event,
but K8s Event objects attribute to their involvedObject, i.e. the Pod
itself, not up the owner chain). On a busy cluster, or for a run from
a while ago, that event rotates out and allPods comes up empty — the
tab disappears instead of falling back.

Added taskruns/pipelineruns to LOGS_TAB_WITHOUT_PODS_KINDS, the same
set Jobs/CronJobs/Workflows already use for the identical problem.
Each kind's own logs view already handles "no pod found" gracefully
(TaskRunLogsTab's "may have been garbage-collected" message, or
MultiPodLogsTab's "No pods available" state for PipelineRun) — the
tab itself just needs to stay reachable.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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