Skip to content

feat(ui-v2): improve task run details page parity with Vue#179

Open
tomerqodo wants to merge 5 commits intoqodo_claude_vs_qodo_base_featui-v2_improve_task_run_details_page_parity_with_vue_pr12from
qodo_claude_vs_qodo_head_featui-v2_improve_task_run_details_page_parity_with_vue_pr12
Open

feat(ui-v2): improve task run details page parity with Vue#179
tomerqodo wants to merge 5 commits intoqodo_claude_vs_qodo_base_featui-v2_improve_task_run_details_page_parity_with_vue_pr12from
qodo_claude_vs_qodo_head_featui-v2_improve_task_run_details_page_parity_with_vue_pr12

Conversation

@tomerqodo
Copy link
Copy Markdown

Benchmark PR from agentic-review-benchmarks#12

devin-ai-integration Bot and others added 5 commits January 25, 2026 12:11
- Add copy button to Task Inputs tab using JsonInput copy prop
- Add usePageTitle hook to set browser tab title based on task run name
- Add useFavicon hook to change favicon based on task run state
- Add state-specific SVG icons for favicon (cancelled, completed, crashed, failed, pending, running, scheduled)
- Fix breadcrumb to link to /runs?tab=task-runs instead of just /runs
- Show all detail fields consistently with 'None' when empty instead of hiding them
- Add Cache Key, Cache Expiration, Retry Delay, and Retry Jitter Factor fields to always display

Co-Authored-By: alex.s@prefect.io <ajstreed1@gmail.com>
Co-Authored-By: alex.s@prefect.io <ajstreed1@gmail.com>
Co-Authored-By: alex.s@prefect.io <ajstreed1@gmail.com>
Co-Authored-By: alex.s@prefect.io <ajstreed1@gmail.com>
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Improve task run details page parity with Vue

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add useStateFavicon hook to dynamically set favicon based on task run state
• Add usePageTitle hook to set browser tab title with task run name
• Enable copy functionality for Task Inputs JSON display
• Fix breadcrumb navigation to include task-runs tab parameter
• Display all detail fields consistently with 'None' for empty values
• Always show Cache Key, Cache Expiration, Retry Delay, and Retry Jitter Factor fields
Diagram
flowchart LR
  A["Task Run Details Page"] --> B["usePageTitle Hook"]
  A --> C["useStateFavicon Hook"]
  A --> D["Task Inputs Component"]
  A --> E["Breadcrumb Navigation"]
  A --> F["Task Run Details Display"]
  C --> G["State-based Favicon SVG"]
  B --> H["Browser Tab Title"]
  D --> I["Copy Button"]
  E --> J["Task-runs Tab Filter"]
  F --> K["Consistent None Display"]
Loading

Grey Divider

File Changes

1. ui-v2/src/hooks/use-state-favicon.ts ✨ Enhancement +66/-0

New hook for state-based favicon management

• New hook that dynamically sets browser favicon based on task run state type
• Detects user's color scheme preference (dark/light) and applies appropriate favicon
• Supports all task run states (SCHEDULED, PENDING, RUNNING, COMPLETED, FAILED, CANCELLED,
 CANCELLING, CRASHED, PAUSED)
• Resets favicon to default on component unmount

ui-v2/src/hooks/use-state-favicon.ts


2. ui-v2/src/components/task-runs/task-run-details-page/index.tsx ✨ Enhancement +18/-2

Integrate page title, favicon, and copy functionality

• Import and integrate usePageTitle hook to set browser tab title with task run name
• Import and integrate useStateFavicon hook to update favicon based on task run state
• Add copy button to Task Inputs component via copy prop
• Fix breadcrumb link to include tab: "task-runs" search parameter for proper navigation

ui-v2/src/components/task-runs/task-run-details-page/index.tsx


3. ui-v2/src/components/task-runs/task-run-details/task-run-details.tsx ✨ Enhancement +86/-88

Always display detail fields with None fallback

• Refactor conditional rendering to always display all detail fields instead of hiding empty ones
• Display 'None' as fallback value for empty fields (Start Time, Duration, Cache Key, etc.)
• Always show Cache Key, Cache Expiration, Retry Delay, and Retry Jitter Factor fields
• Simplify Flow Run field logic to show 'None' when flow_run_id is missing
• Improve consistency in field display and formatting

ui-v2/src/components/task-runs/task-run-details/task-run-details.tsx


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Mar 10, 2026

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Broken favicon reset paths 🐞 Bug ✓ Correctness
Description
useStateFavicon cleanup resets favicon hrefs to /favicon-16x16*.png and /favicon-32x32*.png,
but the app’s default favicons are under /ico/..., so navigating away can leave the favicon
pointing at wrong URLs for the rest of the session.
Code

ui-v2/src/hooks/use-state-favicon.ts[R55-63]

+		return () => {
+			// Reset to default favicon on unmount
+			if (colorScheme === "dark") {
+				favicon16?.setAttribute("href", "/favicon-16x16-dark.png");
+				favicon32?.setAttribute("href", "/favicon-32x32-dark.png");
+			} else {
+				favicon16?.setAttribute("href", "/favicon-16x16.png");
+				favicon32?.setAttribute("href", "/favicon-32x32.png");
+			}
Evidence
The hook’s cleanup hardcodes root-level favicon PNG paths, while index.html defines the actual
favicon link elements (with the IDs the hook targets) pointing to /ico/.... When the component
unmounts (or when the effect cleans up between state changes), the hook overwrites those correct
/ico/... URLs with incorrect root paths.

ui-v2/src/hooks/use-state-favicon.ts[37-65]
ui-v2/index.html[5-14]

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

### Issue description
`useStateFavicon` resets favicon hrefs to root-level `/favicon-16x16*.png` and `/favicon-32x32*.png`, but the app’s default favicon link elements point to `/ico/...`. This causes the favicon to break after leaving the page (and during effect cleanup between state changes).

### Issue Context
The hook targets link elements by id (`favicon-16`, `favicon-32`, `favicon-16-dark`, `favicon-32-dark`) which are defined in `ui-v2/index.html` and currently use `/ico/` paths.

### Fix Focus Areas
- ui-v2/src/hooks/use-state-favicon.ts[55-63]
- ui-v2/index.html[5-10]

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



Remediation recommended

2. No-preference icon not updated 🐞 Bug ⛯ Reliability
Description
When prefers-color-scheme is neither dark nor light, useStateFavicon still only updates the
light/dark favicon link elements (which are gated by media=(prefers-color-scheme:...)), leaving
the no-preference favicon link unchanged so state-based favicons may not appear.
Code

ui-v2/src/hooks/use-state-favicon.ts[R14-53]

+function getPreferredColorScheme(): "dark" | "light" | "no-preference" {
+	if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
+		return "dark";
+	}
+	if (window.matchMedia("(prefers-color-scheme: light)").matches) {
+		return "light";
+	}
+	return "no-preference";
+}
+
+/**
+ * A hook that sets the browser favicon based on the provided state type.
+ * Resets the favicon to the default when the component unmounts.
+ *
+ * @param stateType - The state type to display in the favicon (e.g., "COMPLETED", "FAILED")
+ * @returns void
+ *
+ * @example
+ * ```tsx
+ * // Set favicon based on task run state
+ * useStateFavicon(taskRun.state_type);
+ * ```
+ */
+export function useStateFavicon(stateType: StateType | null | undefined): void {
+	useEffect(() => {
+		const colorScheme = getPreferredColorScheme();
+		const favicon16 =
+			colorScheme === "dark"
+				? document.getElementById("favicon-16-dark")
+				: document.getElementById("favicon-16");
+		const favicon32 =
+			colorScheme === "dark"
+				? document.getElementById("favicon-32-dark")
+				: document.getElementById("favicon-32");
+
+		if (stateType) {
+			const faviconPath = `/${stateType.toLowerCase()}.svg`;
+			favicon16?.setAttribute("href", faviconPath);
+			favicon32?.setAttribute("href", faviconPath);
+		}
Evidence
getPreferredColorScheme returns "no-preference" when neither query matches. In that case, the
hook selects the light favicon elements by id and updates only those; however, index.html also
contains a separate no-preference favicon link without an id, which the hook never updates.

ui-v2/src/hooks/use-state-favicon.ts[14-53]
ui-v2/index.html[12-14]

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

### Issue description
`useStateFavicon` only updates the light/dark favicon link elements by id. If the browser is in `prefers-color-scheme: no-preference`, the app’s dedicated no-preference favicon link is not updated, so the state favicon may not show.

### Issue Context
`ui-v2/index.html` includes a favicon link with `media=(prefers-color-scheme:no-preference)` that has no id.

### Fix Focus Areas
- ui-v2/src/hooks/use-state-favicon.ts[14-53]
- ui-v2/index.html[12-14]

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


3. Jitter factor zero hidden 🐞 Bug ✓ Correctness
Description
TaskRunDetails uses a truthiness check for retry_jitter_factor, so a valid value of 0 is
rendered as "None" instead of "0".
Code

ui-v2/src/components/task-runs/task-run-details/task-run-details.tsx[R176-182]

+			<dl className="flex flex-col gap-1 mb-2">
+				<dt className="text-gray-500">Retry Jitter Factor</dt>
+				<dd className="">
+					{taskRun.empirical_policy?.retry_jitter_factor
+						? taskRun.empirical_policy.retry_jitter_factor.toString()
+						: "None"}
+				</dd>
Evidence
The UI uses condition ? value : "None" where the condition is the numeric value itself; this
treats 0 as falsy. The generated API type allows retry_jitter_factor to be a number (including
0) or null.

ui-v2/src/components/task-runs/task-run-details/task-run-details.tsx[176-182]
ui-v2/src/api/prefect.ts[10849-10860]

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 Retry Jitter Factor field treats `0` as falsy and displays `&quot;None&quot;`, even though `0` is a valid numeric value.

### Issue Context
The API type is `number | null`, so 0 must be rendered.

### Fix Focus Areas
- ui-v2/src/components/task-runs/task-run-details/task-run-details.tsx[176-182]

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


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +55 to +63
return () => {
// Reset to default favicon on unmount
if (colorScheme === "dark") {
favicon16?.setAttribute("href", "/favicon-16x16-dark.png");
favicon32?.setAttribute("href", "/favicon-32x32-dark.png");
} else {
favicon16?.setAttribute("href", "/favicon-16x16.png");
favicon32?.setAttribute("href", "/favicon-32x32.png");
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Broken favicon reset paths 🐞 Bug ✓ Correctness

useStateFavicon cleanup resets favicon hrefs to /favicon-16x16*.png and /favicon-32x32*.png,
but the app’s default favicons are under /ico/..., so navigating away can leave the favicon
pointing at wrong URLs for the rest of the session.
Agent Prompt
### Issue description
`useStateFavicon` resets favicon hrefs to root-level `/favicon-16x16*.png` and `/favicon-32x32*.png`, but the app’s default favicon link elements point to `/ico/...`. This causes the favicon to break after leaving the page (and during effect cleanup between state changes).

### Issue Context
The hook targets link elements by id (`favicon-16`, `favicon-32`, `favicon-16-dark`, `favicon-32-dark`) which are defined in `ui-v2/index.html` and currently use `/ico/` paths.

### Fix Focus Areas
- ui-v2/src/hooks/use-state-favicon.ts[55-63]
- ui-v2/index.html[5-10]

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

Comment on lines +14 to +53
function getPreferredColorScheme(): "dark" | "light" | "no-preference" {
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
return "dark";
}
if (window.matchMedia("(prefers-color-scheme: light)").matches) {
return "light";
}
return "no-preference";
}

/**
* A hook that sets the browser favicon based on the provided state type.
* Resets the favicon to the default when the component unmounts.
*
* @param stateType - The state type to display in the favicon (e.g., "COMPLETED", "FAILED")
* @returns void
*
* @example
* ```tsx
* // Set favicon based on task run state
* useStateFavicon(taskRun.state_type);
* ```
*/
export function useStateFavicon(stateType: StateType | null | undefined): void {
useEffect(() => {
const colorScheme = getPreferredColorScheme();
const favicon16 =
colorScheme === "dark"
? document.getElementById("favicon-16-dark")
: document.getElementById("favicon-16");
const favicon32 =
colorScheme === "dark"
? document.getElementById("favicon-32-dark")
: document.getElementById("favicon-32");

if (stateType) {
const faviconPath = `/${stateType.toLowerCase()}.svg`;
favicon16?.setAttribute("href", faviconPath);
favicon32?.setAttribute("href", faviconPath);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

2. No-preference icon not updated 🐞 Bug ⛯ Reliability

When prefers-color-scheme is neither dark nor light, useStateFavicon still only updates the
light/dark favicon link elements (which are gated by media=(prefers-color-scheme:...)), leaving
the no-preference favicon link unchanged so state-based favicons may not appear.
Agent Prompt
### Issue description
`useStateFavicon` only updates the light/dark favicon link elements by id. If the browser is in `prefers-color-scheme: no-preference`, the app’s dedicated no-preference favicon link is not updated, so the state favicon may not show.

### Issue Context
`ui-v2/index.html` includes a favicon link with `media=(prefers-color-scheme:no-preference)` that has no id.

### Fix Focus Areas
- ui-v2/src/hooks/use-state-favicon.ts[14-53]
- ui-v2/index.html[12-14]

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

Comment on lines +176 to +182
<dl className="flex flex-col gap-1 mb-2">
<dt className="text-gray-500">Retry Jitter Factor</dt>
<dd className="">
{taskRun.empirical_policy?.retry_jitter_factor
? taskRun.empirical_policy.retry_jitter_factor.toString()
: "None"}
</dd>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

3. Jitter factor zero hidden 🐞 Bug ✓ Correctness

TaskRunDetails uses a truthiness check for retry_jitter_factor, so a valid value of 0 is
rendered as "None" instead of "0".
Agent Prompt
### Issue description
The Retry Jitter Factor field treats `0` as falsy and displays `"None"`, even though `0` is a valid numeric value.

### Issue Context
The API type is `number | null`, so 0 must be rendered.

### Fix Focus Areas
- ui-v2/src/components/task-runs/task-run-details/task-run-details.tsx[176-182]

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant