feat(live-update): interactive deploy console teaches upload → channel → rollout - #1015
feat(live-update): interactive deploy console teaches upload → channel → rollout#1015riderx wants to merge 1 commit into
Conversation
Replace the static console screenshot with a steppable upload → channel → rollout demo on the Live Update guidance panel. Includes aria-live status, keyboard-reachable steps, reduced-motion support, and interruptible auto-advance. Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
|
Warning Review limit reached
On-demand reviews are free for the next 12 days. After that, they cost $0.25 per reviewed file. Or wait 1 minute for your next included review. View limit detailsLimit details: You’ve used all 3 included reviews currently available. Your 44 included PR review attempts over the past 7 days set your current allowance at 3 reviews per hour. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Essentials Run ID: 📒 Files selected for processing (6)
Comment |
|
|
@coderabbitai full review Please review current HEAD |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
requested_sha="0a6e971852b0e5d890a1ffeaa4ce23cf3bfb482e"
actual_sha="$(git rev-parse HEAD)"
printf 'HEAD=%s\nREQUESTED=%s\n' "$actual_sha" "$requested_sha"
if [ "$actual_sha" != "$requested_sha" ]; then
echo "ERROR: checked-out HEAD does not match requested commit" >&2
fi
echo '--- changed files ---'
git diff --name-status "${requested_sha}^" "${requested_sha}"
echo '--- diff ---'
git diff --find-renames --find-copies --unified=80 "${requested_sha}^" "${requested_sha}"
echo '--- package scripts ---'
if [ -f package.json ]; then
jq '{scripts: .scripts, packageManager: .packageManager}' package.json
fi
echo '--- changed-file outlines ---'
for f in \
apps/web/src/components/live-update/LiveUpdateDeployConsole.astro \
apps/web/src/components/live-update/live-update-deploy-console.client.ts \
apps/web/src/pages/live-update.astro \
apps/web/src/styles/lu-product.css \
apps/shared/copy/messages.ts
do
if [ -f "$f" ]; then
echo "### $f"
case "$f" in
*.ts) ast-grep outline "$f" --items all || true ;;
*) nl -ba "$f" | sed -n '1,80p' ;;
esac
fi
doneLength of output: 1808 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '--- available history ---'
git log --oneline -5 || true
git show --format=fuller --stat --summary HEAD
echo '--- PR files and patches from GitHub ---'
gh api 'repos/Cap-go/website/pulls/1015/files?per_page=100' \
--jq '.[] | "FILE: \(.filename)\nSTATUS: \(.status)\nPATCH:\n\(.patch // "[no textual patch]")\n---"'
echo '--- component markup ---'
nl -ba apps/web/src/components/live-update/LiveUpdateDeployConsole.astro
echo '--- client module ---'
nl -ba apps/web/src/components/live-update/live-update-deploy-console.client.ts
echo '--- page integration occurrences ---'
rg -n -C 12 'LiveUpdateDeployConsole|live-update-console-demo' apps/web/src/pages/live-update.astro
echo '--- console CSS selectors ---'
rg -n -C 8 'lu-deploy|deploy-console|console-' apps/web/src/styles/lu-product.css
echo '--- console messages ---'
rg -n -C 5 'liveUpdate.*(Deploy|Console)|deploy.*(Console|Upload|Channel|Rollout)|publishBundle|watchRollout' apps/shared/copy/messages.ts || true
echo '--- references to console IDs/classes/data attributes ---'
rg -n -C 2 'lu-deploy-console|lu-deploy-|data-lu' apps/web/src apps/shared/copyLength of output: 163794 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '--- exact target ---'
git rev-parse HEAD
echo '--- PR changed paths ---'
gh api 'repos/Cap-go/website/pulls/1015/files?per_page=100' --jq '.[] | [.filename, .status, .additions, .deletions] | `@tsv`'
echo '--- deploy console component ---'
sed -n '1,240p' apps/web/src/components/live-update/LiveUpdateDeployConsole.astro
echo '--- deploy console client ---'
sed -n '1,340p' apps/web/src/components/live-update/live-update-deploy-console.client.ts
echo '--- live update integration ---'
sed -n '1,35p' apps/web/src/pages/live-update.astro
sed -n '385,430p' apps/web/src/pages/live-update.astro
echo '--- changed CSS block ---'
sed -n '700,1100p' apps/web/src/styles/lu-product.css
echo '--- package scripts and workspace configuration ---'
jq '{scripts, packageManager, workspaces}' package.json
find apps -maxdepth 2 -name package.json -print -exec sh -c 'echo "--- $1"; jq "{scripts, packageManager}" "$1"' _ {} \;
echo '--- message module API and locale validation references ---'
rg -n -C 3 'export.*(MessageValues|default)|function.*messages|missing translation|messageContexts|messages\.ts' apps/shared apps/web scripts -g '*.ts' -g '*.js' -g '*.mjs' | head -500 || true
echo '--- static review: untracked timeouts and console behavior references ---'
rg -n -C 3 'setTimeout|clearTimeout|runRolloutSequence|scheduleAutoAdvance|setupLiveUpdateDeployConsole' apps/web/src/components/live-update apps/web/test -g '*.ts' -g '*.astro' -g '*.js' || trueLength of output: 55426
I found one blocking issue. I cannot approve this SHA.
Store and cancel every rollout timer, or use one cancellable sequence token, before resetting or restarting the flow. I did not run build or browser checks. The sandbox does not permit execution of repository code. You are interacting with an AI system. |
There was a problem hiding this comment.
9 issues found across 6 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/web/src/styles/lu-product.css">
<violation number="1" location="apps/web/src/styles/lu-product.css:907">
P3: The field labels (dt) are 10px text in #64748b on the #f4f7fb console background, which computes to ~4.43:1 contrast — just under the 4.5:1 AA requirement for normal-size text. Darken to #475569 (slate-600), which yields ~7:1, so the small labels stay readable.</violation>
</file>
<file name="apps/web/src/components/live-update/LiveUpdateDeployConsole.astro">
<violation number="1" location="apps/web/src/components/live-update/LiveUpdateDeployConsole.astro:37">
P3: `rolloutLabel` is dead copy: it is computed and shipped but never rendered or consumed. Remove the unused value or render it as the staged-rollout label.</violation>
<violation number="2" location="apps/web/src/components/live-update/LiveUpdateDeployConsole.astro:61">
P2: Keyboard users cannot reach the inactive step tabs because the roving `tabindex` has no arrow-key navigation. Implement the standard tablist arrow-key/focus behavior, or make the inactive tabs keyboard reachable.</violation>
<violation number="3" location="apps/web/src/components/live-update/LiveUpdateDeployConsole.astro:121">
P2: When a visitor selects staging, the status region and rollout still announce production. Make the status copy channel-aware before exposing staging, or remove the staging control until that flow is supported.</violation>
</file>
<file name="apps/web/src/components/live-update/live-update-deploy-console.client.ts">
<violation number="1" location="apps/web/src/components/live-update/live-update-deploy-console.client.ts:156">
P2: When a user navigates back during the rollout animation, the intermediate callbacks keep mutating the reset rollout and can leave the next visit stuck at 10% or 55%. Store both intermediate timeout handles and cancel the complete rollout sequence when navigating or restarting.</violation>
<violation number="2" location="apps/web/src/components/live-update/live-update-deploy-console.client.ts:174">
P2: Returning from a partially watched Rollout leaves the flow stuck because the nonzero progress prevents the sequence from restarting. Restart or resume the rollout whenever an incomplete Rollout step is entered.</violation>
<violation number="3" location="apps/web/src/components/live-update/live-update-deploy-console.client.ts:183">
P2: The upload and channel completion statuses are overwritten immediately when `goToStep()` refreshes the next panel, so the `aria-live` region does not reliably announce completion. Preserve the completion status when advancing, then switch to the next idle status on a later interaction.</violation>
<violation number="4" location="apps/web/src/components/live-update/live-update-deploy-console.client.ts:200">
P1: When auto-advance reaches Rollout, `scheduleAutoAdvance()` clears the completion timer immediately after `runRolloutSequence()` creates it, so the demo stops at 55% and never completes. Separate auto-timer cleanup from rollout cleanup and retain all rollout timer handles.</violation>
</file>
<file name="apps/shared/copy/messages.ts">
<violation number="1" location="apps/shared/copy/messages.ts:2151">
P2: The new console copy is missing from the generated `translationContextByText.ts` artifact, so the edge translation worker cannot resolve context for these strings. Run `bun run generate:message-contexts` and commit the regenerated artifact with the message changes.
(Based on your team's feedback about regenerating translation contexts).</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| function scheduleAutoAdvance() { | ||
| if (userInterrupted || reducedMotion || rolloutComplete) return | ||
| clearTimers() | ||
| if (step === 2) return |
There was a problem hiding this comment.
P1: When auto-advance reaches Rollout, scheduleAutoAdvance() clears the completion timer immediately after runRolloutSequence() creates it, so the demo stops at 55% and never completes. Separate auto-timer cleanup from rollout cleanup and retain all rollout timer handles.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/src/components/live-update/live-update-deploy-console.client.ts, line 200:
<comment>When auto-advance reaches Rollout, `scheduleAutoAdvance()` clears the completion timer immediately after `runRolloutSequence()` creates it, so the demo stops at 55% and never completes. Separate auto-timer cleanup from rollout cleanup and retain all rollout timer handles.</comment>
<file context>
@@ -0,0 +1,258 @@
+ function scheduleAutoAdvance() {
+ if (userInterrupted || reducedMotion || rolloutComplete) return
+ clearTimers()
+ if (step === 2) return
+
+ autoTimer = setTimeout(() => {
</file context>
| <button type="button" class="lu-console-channel is-selected" data-channel="production" aria-pressed="true"> | ||
| {consoleCopy.channelProduction} | ||
| </button> | ||
| <button type="button" class="lu-console-channel" data-channel="staging" aria-pressed="false"> |
There was a problem hiding this comment.
P2: When a visitor selects staging, the status region and rollout still announce production. Make the status copy channel-aware before exposing staging, or remove the staging control until that flow is supported.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/src/components/live-update/LiveUpdateDeployConsole.astro, line 121:
<comment>When a visitor selects staging, the status region and rollout still announce production. Make the status copy channel-aware before exposing staging, or remove the staging control until that flow is supported.</comment>
<file context>
@@ -0,0 +1,183 @@
+ <button type="button" class="lu-console-channel is-selected" data-channel="production" aria-pressed="true">
+ {consoleCopy.channelProduction}
+ </button>
+ <button type="button" class="lu-console-channel" data-channel="staging" aria-pressed="false">
+ {consoleCopy.channelStaging}
+ </button>
</file context>
| aria-selected={index === 0 ? 'true' : 'false'} | ||
| aria-controls={`lu-console-panel-${index}`} | ||
| id={`lu-console-tab-${index}`} | ||
| tabindex={index === 0 ? 0 : -1} |
There was a problem hiding this comment.
P2: Keyboard users cannot reach the inactive step tabs because the roving tabindex has no arrow-key navigation. Implement the standard tablist arrow-key/focus behavior, or make the inactive tabs keyboard reachable.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/src/components/live-update/LiveUpdateDeployConsole.astro, line 61:
<comment>Keyboard users cannot reach the inactive step tabs because the roving `tabindex` has no arrow-key navigation. Implement the standard tablist arrow-key/focus behavior, or make the inactive tabs keyboard reachable.</comment>
<file context>
@@ -0,0 +1,183 @@
+ aria-selected={index === 0 ? 'true' : 'false'}
+ aria-controls={`lu-console-panel-${index}`}
+ id={`lu-console-tab-${index}`}
+ tabindex={index === 0 ? 0 : -1}
+ >
+ <span class="lu-console-step-num" aria-hidden="true">
</file context>
| setTimeout(() => { | ||
| setRollout(10, true) | ||
| setStatus(copy.status.rolloutHealth) | ||
| }, 900) |
There was a problem hiding this comment.
P2: When a user navigates back during the rollout animation, the intermediate callbacks keep mutating the reset rollout and can leave the next visit stuck at 10% or 55%. Store both intermediate timeout handles and cancel the complete rollout sequence when navigating or restarting.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/src/components/live-update/live-update-deploy-console.client.ts, line 156:
<comment>When a user navigates back during the rollout animation, the intermediate callbacks keep mutating the reset rollout and can leave the next visit stuck at 10% or 55%. Store both intermediate timeout handles and cancel the complete rollout sequence when navigating or restarting.</comment>
<file context>
@@ -0,0 +1,258 @@
+ setTimeout(() => {
+ setRollout(10, true)
+ setStatus(copy.status.rolloutHealth)
+ }, 900)
+
+ setTimeout(() => {
</file context>
| live_update_guidance_panel_footer: 'Choose the safe path before rollout: ship OTA, gate by native version, trigger a native build, or roll back.', | ||
| live_update_guidance_panel_title: 'Release decision', | ||
| live_update_guidance_title: 'Catch breaking updates before they ship', | ||
| live_update_console_action_channel: 'Assign to channel', |
There was a problem hiding this comment.
P2: The new console copy is missing from the generated translationContextByText.ts artifact, so the edge translation worker cannot resolve context for these strings. Run bun run generate:message-contexts and commit the regenerated artifact with the message changes.
(Based on your team's feedback about regenerating translation contexts).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/shared/copy/messages.ts, line 2151:
<comment>The new console copy is missing from the generated `translationContextByText.ts` artifact, so the edge translation worker cannot resolve context for these strings. Run `bun run generate:message-contexts` and commit the regenerated artifact with the message changes.
(Based on your team's feedback about regenerating translation contexts). </comment>
<file context>
@@ -2148,6 +2148,36 @@ const messages = {
live_update_guidance_panel_footer: 'Choose the safe path before rollout: ship OTA, gate by native version, trigger a native build, or roll back.',
live_update_guidance_panel_title: 'Release decision',
live_update_guidance_title: 'Catch breaking updates before they ship',
+ live_update_console_action_channel: 'Assign to channel',
+ live_update_console_action_rollout: 'Watch rollout',
+ live_update_console_action_upload: 'Publish bundle',
</file context>
| function advance() { | ||
| interruptAuto() | ||
| if (step === 0) { | ||
| setStatus(copy.status.uploadDone) |
There was a problem hiding this comment.
P2: The upload and channel completion statuses are overwritten immediately when goToStep() refreshes the next panel, so the aria-live region does not reliably announce completion. Preserve the completion status when advancing, then switch to the next idle status on a later interaction.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/src/components/live-update/live-update-deploy-console.client.ts, line 183:
<comment>The upload and channel completion statuses are overwritten immediately when `goToStep()` refreshes the next panel, so the `aria-live` region does not reliably announce completion. Preserve the completion status when advancing, then switch to the next idle status on a later interaction.</comment>
<file context>
@@ -0,0 +1,258 @@
+ function advance() {
+ interruptAuto()
+ if (step === 0) {
+ setStatus(copy.status.uploadDone)
+ goToStep(1)
+ return
</file context>
| function goToStep(next: Step) { | ||
| step = next | ||
| updateStepUi() | ||
| if (step === 2 && !rolloutComplete && rolloutProgress === 0) { |
There was a problem hiding this comment.
P2: Returning from a partially watched Rollout leaves the flow stuck because the nonzero progress prevents the sequence from restarting. Restart or resume the rollout whenever an incomplete Rollout step is entered.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/src/components/live-update/live-update-deploy-console.client.ts, line 174:
<comment>Returning from a partially watched Rollout leaves the flow stuck because the nonzero progress prevents the sequence from restarting. Restart or resume the rollout whenever an incomplete Rollout step is entered.</comment>
<file context>
@@ -0,0 +1,258 @@
+ function goToStep(next: Step) {
+ step = next
+ updateStepUi()
+ if (step === 2 && !rolloutComplete && rolloutProgress === 0) {
+ runRolloutSequence()
+ }
</file context>
| .lu .lu-console-field dt { | ||
| font-size: 10px; | ||
| font-weight: 700; | ||
| color: #64748b; |
There was a problem hiding this comment.
P3: The field labels (dt) are 10px text in #64748b on the #f4f7fb console background, which computes to ~4.43:1 contrast — just under the 4.5:1 AA requirement for normal-size text. Darken to #475569 (slate-600), which yields ~7:1, so the small labels stay readable.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/src/styles/lu-product.css, line 907:
<comment>The field labels (dt) are 10px text in #64748b on the #f4f7fb console background, which computes to ~4.43:1 contrast — just under the 4.5:1 AA requirement for normal-size text. Darken to #475569 (slate-600), which yields ~7:1, so the small labels stay readable.</comment>
<file context>
@@ -729,6 +729,338 @@ body:has(.lu) footer > div > div:first-child {
+.lu .lu-console-field dt {
+ font-size: 10px;
+ font-weight: 700;
+ color: #64748b;
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
</file context>
| color: #64748b; | |
| color: #475569; |
| fieldChecksum: copy('live_update_console_field_checksum'), | ||
| fieldChannel: copy('live_update_console_field_channel'), | ||
| fieldRollout: copy('live_update_console_field_rollout'), | ||
| rolloutLabel: copy('live_update_console_rollout_label'), |
There was a problem hiding this comment.
P3: rolloutLabel is dead copy: it is computed and shipped but never rendered or consumed. Remove the unused value or render it as the staged-rollout label.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/src/components/live-update/LiveUpdateDeployConsole.astro, line 37:
<comment>`rolloutLabel` is dead copy: it is computed and shipped but never rendered or consumed. Remove the unused value or render it as the staged-rollout label.</comment>
<file context>
@@ -0,0 +1,183 @@
+ fieldChecksum: copy('live_update_console_field_checksum'),
+ fieldChannel: copy('live_update_console_field_channel'),
+ fieldRollout: copy('live_update_console_field_rollout'),
+ rolloutLabel: copy('live_update_console_rollout_label'),
+ healthOk: copy('live_update_console_health_ok'),
+ orgName: copy('live_update_console_org_name'),
</file context>
|
Superseding this PR. The Live Update teaching console here looks like a sparse toy mockup (fake chrome, thin UI, confusing CLI noise) — Martin rejected it. Rebuilding one end-to-end PR for every product page at real-console craft quality. Do not merge this. |
|
Closed as superseded — toy console rejected; consolidating into one end-to-end product-page teaching PR. |



Summary
Replaces the static
/landing-demos/live-update-console-demo.webpimage in the Live Update guidance panel with an interactive, console-style teaching demo.Three teaching beats
1.0.0, size, and CRC32 checksum, then publish.productionorstagingand assign the bundle.Interaction & accessibility
aria-live="polite"status updates, keyboard-reachable step tabs, no replay button.prefers-reduced-motion: skips rollout animation and lands on the complete state.text-overflow, compact layout).Demo
Before
Static console screenshot — no interaction.
After — step 1: Upload
After — step 2: Channel
After — step 3: Rollout complete
Recording
live-update-console-demo.webm
Files
apps/web/src/components/live-update/LiveUpdateDeployConsole.astro— markup + copy wiringapps/web/src/components/live-update/live-update-deploy-console.client.ts— step state, rollout sequence, auto-advanceapps/web/src/pages/live-update.astro— swaps static image for componentapps/web/src/styles/lu-product.css— console demo stylesapps/shared/copy/messages.ts— i18n strings for console UIOut of scope
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.