Skip to content

feat(ui): show how long each promotion step took - #6807

Merged
Marvin9 merged 2 commits into
akuity:mainfrom
utkarshcmu:feat/6806-promotion-step-durations
Aug 19, 2026
Merged

Marvin9 merged 2 commits into
akuity:mainfrom
utkarshcmu:feat/6806-promotion-step-durations

Conversation

@utkarshcmu

Copy link
Copy Markdown
Contributor

Description

Closes #6806

The promotion view shows a duration for the promotion as a whole, but individual steps show only their status. When a promotion is slow there is no way to tell which step accounted for it without inspecting the Promotion resource by hand.

This renders an elapsed time against each step:

  • Finished step — measured from startedAt to finishedAt.
  • Running step — counts up from startedAt on a one second tick, which is what distinguishes a step that is stuck from one that is merely slow.
  • Not yet started — renders nothing.

The data was already present in status.stepExecutionMetadata and already exposed on the generated StepExecutionMetadata model, so there is no API, CRD or codegen change — this is purely presentational.

Completed promotion

git-clone took 2s; the two sub-second steps read <1s.

completed promotion with per-step durations

Running promotion — before / after

Before, a running promotion showed no timing at all (note the promotion-level duration row is absent entirely until the promotion is terminal):

before

After, the running step reports how long it has been waiting:

after

Live counter

The elapsed time on a running step ticks, then settles on its final value when the step reaches a terminal state:

live counter ticking then finishing

Notes for reviewers

<1s rather than 0ms. API timestamps are RFC 3339 with second precision, so every sub-second step computes to exactly 0. Rendering that as 0ms would imply a precision the data does not have, so a zero duration renders as <1s. Non-zero sub-second values are still formatted exactly, in case finer-grained timestamps arrive later.

Clock skew. If the browser clock is behind the control plane, a running step's elapsed time would go negative; stepDurationMs returns null in that case so nothing is rendered rather than showing -3s.

Timer scope. The one second interval is owned by a small StepDuration component and only runs while a step is actually running, so finished steps do not hold a timer.

Out of scope. While testing this I noticed the promotion drawer does not refetch while it is open, so a step reaching a terminal state is only reflected after the view is reopened (the elapsed time itself ticks client-side regardless). That is pre-existing behaviour and untouched here — happy to open a separate issue for it.

Tested against a real promotion in a local kind cluster, including a step left running for 20+ minutes.

Checklist

Eligibility

  • Linked to an existing issue with no blocking labels (kind/proposal, needs discussion, needs research, maintainer only, area/security, size/large, size/x-large, size/xx-large).
  • Changes documentation only.
  • Changes ten lines or fewer.

Quality

  • Adds or updates corresponding tests.
  • Adds or updates corresponding documentation.

AI Use Disclosure

This PR was written:

  • By a human without AI assistance.
  • By a human with AI assistance. A human has reviewed every line prior to opening the PR.
  • By an AI with human supervision. A human has reviewed every line prior to opening the PR.
  • Entirely by an AI. No human has reviewed this prior to opening the PR.

Sign-Off

All commits:

  • Are signed off by their author (git commit -s) (required)
  • Are cryptographically signed (git commit -S) (encouraged)

🤖 Generated with Claude Code

The promotion view showed a duration for the promotion as a whole, but
individual steps showed only their status, so there was no way to tell which
step accounted for a slow promotion without inspecting the Promotion resource
by hand.

Render an elapsed time against each step. A finished step is measured from
startedAt to finishedAt; a running step counts up from startedAt on a one
second tick, which distinguishes a step that is stuck from one that is merely
slow. Steps that have not started show nothing.

The data was already present in status.stepExecutionMetadata and already
exposed on the generated StepExecutionMetadata model, so no API, CRD or
codegen change is required.

Durations under one second render as "<1s" rather than "0ms": API timestamps
are RFC 3339 with second precision, so every sub-second step computes to
exactly zero and "0ms" would imply a precision the data does not have.

Signed-off-by: Utkarsh Bhatnagar <utkarsh.cmu@gmail.com>
@utkarshcmu
utkarshcmu requested a review from a team as a code owner August 13, 2026 02:11
@kargo-governance-bot kargo-governance-bot Bot added needs/area Issue or PR needs to be labeled to indicate what parts of the code base are affected needs/kind Issue or PR needs to be labeled to clarify its nature needs/priority Priority has not yet been determined; a good signal that maintainers aren't fully committed labels Aug 13, 2026
@netlify

netlify Bot commented Aug 13, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for docs-kargo-io ready!

Name Link
🔨 Latest commit f47aa09
🔍 Latest deploy log https://app.netlify.com/projects/docs-kargo-io/deploys/6a83fd0c16454900080eac4a
😎 Deploy Preview https://deploy-preview-6807.docs.kargo.io
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@codecov

codecov Bot commented Aug 14, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 30.90%. Comparing base (d30e014) to head (f47aa09).
⚠️ Report is 12 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6807      +/-   ##
==========================================
+ Coverage   30.84%   30.90%   +0.05%     
==========================================
  Files         826      829       +3     
  Lines       80666    80864     +198     
==========================================
+ Hits        24885    24990     +105     
- Misses      54327    54418      +91     
- Partials     1454     1456       +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@kencochrane kencochrane added this to the v1.12.0 milestone Aug 15, 2026
@kencochrane
kencochrane requested a review from Marvin9 August 15, 2026 10:47

@Marvin9 Marvin9 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pushing some refactors and bug that makes duration counter ticks continuously even though promotion is failed

const TICK_INTERVAL_MS = 1000;

export const StepDuration = ({ meta }: { meta?: StepExecutionMetadata }) => {
const running = !!meta?.startedAt && !meta?.finishedAt;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this means that any terminated promotion will count as a running promotion

Refines the step duration display. StepDuration now takes the Promotion
and a step index rather than a pre-extracted StepExecutionMetadata, so
the component that needs a step's metadata is the one that looks it up
and Step no longer relays a prop it never uses itself.

Running and settled steps are separated: the settled case is straight
inline logic, while a running step keeps a component of its own because
mounting is what starts and stops its interval -- a hook could not be
called conditionally, so every settled step would tick forever.

A step that a Promotion cut short is never stamped with its own
finishedAt, so the Promotion's finishedAt stands in and the step still
reports how long it actually ran. Whether a step is still executing is
answered by the existing getPromotionDirectiveStepStatus rather than by
a new predicate.

Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com>
@Marvin9 Marvin9 added kind/enhancement An entirely new feature area/ui Affects the UI priority/normal This is the priority for most work and removed needs/kind Issue or PR needs to be labeled to clarify its nature needs/priority Priority has not yet been determined; a good signal that maintainers aren't fully committed needs/area Issue or PR needs to be labeled to indicate what parts of the code base are affected labels Aug 18, 2026
@Marvin9
Marvin9 added this pull request to the merge queue Aug 19, 2026
Merged via the queue into akuity:main with commit bc16c85 Aug 19, 2026
17 checks passed
@utkarshcmu
utkarshcmu deleted the feat/6806-promotion-step-durations branch August 19, 2026 18:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/ui Affects the UI kind/enhancement An entirely new feature priority/normal This is the priority for most work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UI: show how long each promotion step took

3 participants