Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 24 additions & 28 deletions apps/frontend/src/renderer/components/TaskCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -268,15 +268,24 @@ export const TaskCard = memo(function TaskCard({ task, onClick }: TaskCardProps)
onClick={onClick}
>
<CardContent className="p-4">
{/* Header - improved visual hierarchy */}
<div className="flex items-start justify-between gap-3">
<h3
className="font-semibold text-sm text-foreground line-clamp-2 leading-snug flex-1 min-w-0"
title={task.title}
>
{task.title}
</h3>
<div className="flex items-center gap-1.5 shrink-0 flex-wrap justify-end max-w-[180px]">
{/* Title - full width, no wrapper */}
<h3
className="font-semibold text-sm text-foreground line-clamp-2 leading-snug"
title={task.title}
>
{task.title}
</h3>

{/* Description - sanitized to handle markdown content (memoized) */}
{sanitizedDescription && (
<p className="mt-2 text-xs text-muted-foreground line-clamp-2">
{sanitizedDescription}
</p>
)}

{/* Metadata badges */}
{(task.metadata || isStuck || isIncomplete || hasActiveExecution || reviewReasonInfo) && (
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The condition to render the badge container is a bit too broad. If task.metadata is an object with properties that don't result in a badge (e.g., { sourceType: 'manual' }), and no status badges are active, this will render an empty <div> with a top margin, causing a minor layout issue. You should make the condition more specific to only render the container if there's at least one badge to display.

Copy link

Choose a reason for hiding this comment

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

Status badge hidden for tasks without metadata

The condition (task.metadata || isStuck || isIncomplete || hasActiveExecution || reviewReasonInfo) controls the entire badges section, including the status badge. Since task.metadata is optional in the Task type, a task in backlog status without metadata will have all conditions evaluate to falsy, causing no badges to render. In the original code, status badges were in the header (always rendered), so the "Pending" status badge would always display. This change causes a visibility regression for tasks lacking metadata.

Fix in Cursor Fix in Web

<div className="mt-2.5 flex flex-wrap gap-1.5">
{/* Stuck indicator - highest priority */}
{isStuck && (
<Badge
Expand Down Expand Up @@ -338,21 +347,8 @@ export const TaskCard = memo(function TaskCard({ task, onClick }: TaskCardProps)
{reviewReasonInfo.label}
</Badge>
)}
</div>
</div>

{/* Description - sanitized to handle markdown content (memoized) */}
{sanitizedDescription && (
<p className="mt-2 text-xs text-muted-foreground line-clamp-2">
{sanitizedDescription}
</p>
)}

{/* Metadata badges */}
{task.metadata && (
<div className="mt-2.5 flex flex-wrap gap-1.5">
{/* Category badge with icon */}
{task.metadata.category && (
{task.metadata?.category && (
<Badge
variant="outline"
className={cn('text-[10px] px-1.5 py-0', TASK_CATEGORY_COLORS[task.metadata.category])}
Expand All @@ -367,7 +363,7 @@ export const TaskCard = memo(function TaskCard({ task, onClick }: TaskCardProps)
</Badge>
)}
{/* Impact badge - high visibility for important tasks */}
{task.metadata.impact && (task.metadata.impact === 'high' || task.metadata.impact === 'critical') && (
{task.metadata?.impact && (task.metadata.impact === 'high' || task.metadata.impact === 'critical') && (
<Badge
variant="outline"
className={cn('text-[10px] px-1.5 py-0', TASK_IMPACT_COLORS[task.metadata.impact])}
Expand All @@ -376,7 +372,7 @@ export const TaskCard = memo(function TaskCard({ task, onClick }: TaskCardProps)
</Badge>
)}
{/* Complexity badge */}
{task.metadata.complexity && (
{task.metadata?.complexity && (
<Badge
variant="outline"
className={cn('text-[10px] px-1.5 py-0', TASK_COMPLEXITY_COLORS[task.metadata.complexity])}
Expand All @@ -385,7 +381,7 @@ export const TaskCard = memo(function TaskCard({ task, onClick }: TaskCardProps)
</Badge>
)}
{/* Priority badge - only show urgent/high */}
{task.metadata.priority && (task.metadata.priority === 'urgent' || task.metadata.priority === 'high') && (
{task.metadata?.priority && (task.metadata.priority === 'urgent' || task.metadata.priority === 'high') && (
<Badge
variant="outline"
className={cn('text-[10px] px-1.5 py-0', TASK_PRIORITY_COLORS[task.metadata.priority])}
Expand All @@ -394,12 +390,12 @@ export const TaskCard = memo(function TaskCard({ task, onClick }: TaskCardProps)
</Badge>
)}
{/* Security severity - always show */}
{task.metadata.securitySeverity && (
{task.metadata?.securitySeverity && (
<Badge
variant="outline"
className={cn('text-[10px] px-1.5 py-0', TASK_IMPACT_COLORS[task.metadata.securitySeverity])}

Choose a reason for hiding this comment

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

🟠 HIGH - Hardcoded user-facing text not internationalized
Agent: react

Category: style

Description:
The security severity badge displays a hardcoded string ' severity' that is not wrapped in i18n translation. According to CLAUDE.md, all user-facing text must use react-i18next.

Suggestion:
Replace the hardcoded ' severity' text with a translation key. Example: {t('labels.securitySeverity', { level: task.metadata.securitySeverity })}

Confidence: 95%
Rule: ts_internationalize_user_facing_text_with_n
Review ID: cd6efcdf-d065-4788-b8c8-a492d4f14b15
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

>
{task.metadata.securitySeverity} severity
{task.metadata.securitySeverity} {t('metadata.severity')}
</Badge>
)}
Comment on lines +393 to 400
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Good i18n fix for severity label.

The translation key t('metadata.severity') addresses the previously flagged hardcoded string.

Consider fully localizing the severity level value as well (e.g., t('severity.high') instead of raw task.metadata.securitySeverity) for complete i18n support, but the current fix resolves the immediate issue. Based on learnings, all user-facing text should use translation keys.

🤖 Prompt for AI Agents
In apps/frontend/src/renderer/components/TaskCard.tsx around lines 393 to 400,
the severity label text uses the raw value task.metadata.securitySeverity while
only the "severity" label was translated; change this to fully localize the
severity value by replacing the raw string with a translation lookup (for
example t(`severity.${task.metadata.securitySeverity.toLowerCase()}`) or a safe
mapping from severity values to keys) and provide a sensible fallback to the
original value if the translation key is missing; ensure you normalize the
severity string (lowercase/trim) before building the key and add/update
corresponding i18n keys for each severity level.

</div>
Expand Down
3 changes: 3 additions & 0 deletions apps/frontend/src/shared/i18n/locales/en/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,8 @@
"retry": "Retry",
"selectFile": "Select a file to view its contents",
"openInIDE": "Open in IDE"
},
"metadata": {
"severity": "severity"
}
}
3 changes: 3 additions & 0 deletions apps/frontend/src/shared/i18n/locales/fr/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,8 @@
"retry": "Réessayer",
"selectFile": "Sélectionnez un fichier pour voir son contenu",
"openInIDE": "Ouvrir dans l'IDE"
},
"metadata": {
"severity": "sévérité"
}
}
26 changes: 16 additions & 10 deletions implementation_plan.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
{
"spec_id": "011-fix-scale-adjustment-and-view-reload-issues",
"spec_id": "025-improving-task-card-title-readability",
"subtasks": [
{
"id": "1",
"title": "Fix slider to defer view reload until drag ends and add zoom button functionality",
"title": "Restructure TaskCard header: Remove flex wrapper around title, make title standalone with full width",
"status": "completed"
},
{
"id": "2",
"title": "Relocate status badges from header to metadata section",
"status": "completed"
},
{
"id": "3",
"title": "Add localization for security severity badge label",
"status": "completed"
}
],
"qa_signoff": {
"status": "fixes_applied",
"timestamp": "2025-12-27T02:20:00Z",
"fix_session": 0,
"timestamp": "2026-01-01T11:58:40Z",
"fix_session": 1,
"issues_fixed": [
{
"title": "Remove preview hint textbox",
"fix_commit": "2653019"
},
{
"title": "Remove unused preview translation keys",
"fix_commit": "e17536c"
"title": "Missing localization for hardcoded 'severity' string in TaskCard",
"fix_commit": "de0c8e4"
}
],
"ready_for_qa_revalidation": true
Expand Down
Loading