Skip to content
Open
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
16 changes: 6 additions & 10 deletions apps/frontend/src/renderer/components/CreateSpecView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ import { cn } from '../lib/utils';
import type { PatternSuggestion } from '../../shared/types';
export type { PatternSuggestion };

/**
* Import skeleton component for loading state
*/
import { PatternSuggestionsSkeleton } from './skeletons/PatternSuggestionsSkeleton';

/**
* Pattern action state
*/
Expand Down Expand Up @@ -440,16 +445,7 @@ export function CreateSpecView({
</div>

{/* Loading State */}
{isLoading && (
<Card>
<CardContent className="p-6">
<div className="flex items-center justify-center gap-3 text-muted-foreground">
<div className="h-5 w-5 animate-spin rounded-full border-2 border-primary border-t-transparent" />
<span>Finding relevant patterns...</span>
</div>
</CardContent>
</Card>
)}
{isLoading && <PatternSuggestionsSkeleton count={3} showHeader={false} />}

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.

⚠️ Potential issue | 🟠 Major

Loading skeleton needs an accessible, localized status message.

Line 448 renders only visual placeholders, so users on assistive tech may not get loading feedback.

Suggested fix
+import { useTranslation } from 'react-i18next';
...
 export function CreateSpecView({
@@
 }: CreateSpecViewProps) {
+  const { t } = useTranslation();
...
-      {isLoading && <PatternSuggestionsSkeleton count={3} showHeader={false} />}
+      {isLoading && (
+        <div role="status" aria-live="polite" aria-busy="true">
+          <span className="sr-only">{t('tasks:createSpec.patternSuggestionsLoading')}</span>
+          <PatternSuggestionsSkeleton count={3} showHeader={false} />
+        </div>
+      )}

Please also add tasks:createSpec.patternSuggestionsLoading to English and French locale files.

As per coding guidelines: "All user-facing text must use i18n translation keys from react-i18next with format namespace:section.key. Never use hardcoded strings in JSX/TSX. Update all language files (minimum: English and French) when adding new text."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{isLoading && <PatternSuggestionsSkeleton count={3} showHeader={false} />}
{isLoading && (
<div role="status" aria-live="polite" aria-busy="true">
<span className="sr-only">{t('tasks:createSpec.patternSuggestionsLoading')}</span>
<PatternSuggestionsSkeleton count={3} showHeader={false} />
</div>
)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/renderer/components/CreateSpecView.tsx` at line 448, The
PatternSuggestionsSkeleton rendering when isLoading in CreateSpecView.tsx
currently provides only visual placeholders; update the JSX around
PatternSuggestionsSkeleton to expose an accessible, localized loading status
using react-i18next (call t('tasks:createSpec.patternSuggestionsLoading') where
the status is announced) — e.g., add a non-visual element or wrapper with
role="status" or aria-live="polite" that contains
t('tasks:createSpec.patternSuggestionsLoading') so assistive tech receives
loading feedback; then add the new translation key
tasks:createSpec.patternSuggestionsLoading to both English and French locale
files with appropriate localized strings.


{/* Error State */}
{error && (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { Card, CardContent, CardHeader } from '../ui/card';

interface PatternSuggestionsSkeletonProps {
/** Number of pattern cards to render */
count?: number;
/** Whether to show header section */
showHeader?: boolean;
}

/**
* Skeleton loader for PatternSuggestions in CreateSpecView
* Matches the structure: header with badges, pattern cards with category badges,
* confidence levels, pattern text, action buttons, and expandable details
*/
export function PatternSuggestionsSkeleton({
count = 3,
showHeader = true
}: PatternSuggestionsSkeletonProps) {

Check warning on line 18 in apps/frontend/src/renderer/components/skeletons/PatternSuggestionsSkeleton.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Mark the props of the component as read-only.

See more on https://sonarcloud.io/project/issues?id=OBenner_Auto-Coding&issues=AZ0KaJCpahTOYVkemWb8&open=AZ0KaJCpahTOYVkemWb8&pullRequest=139
return (
<div className="space-y-4 animate-pulse">
{/* Header Section */}
{showHeader && (
<div className="flex items-start justify-between">
<div className="flex-1 space-y-2">
{/* Title with icon */}
<div className="flex items-center gap-2">
<div className="h-5 w-5 bg-muted rounded" />
<div className="h-6 w-48 bg-muted rounded" />
</div>
{/* Subtitle */}
<div className="h-4 w-80 bg-muted rounded" />
</div>
{/* Summary badges */}
<div className="flex items-center gap-2">
<div className="h-6 w-24 bg-muted rounded-md" />
<div className="h-6 w-20 bg-muted rounded-md" />
<div className="h-6 w-22 bg-muted rounded-md" />
</div>
</div>
)}

{/* Pattern Cards */}
<div className="space-y-3">
{Array.from({ length: count }).map((_, index) => (
<Card key={index} className="border">

Check warning on line 45 in apps/frontend/src/renderer/components/skeletons/PatternSuggestionsSkeleton.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not use Array index in keys

See more on https://sonarcloud.io/project/issues?id=OBenner_Auto-Coding&issues=AZ0KaJCpahTOYVkemWb9&open=AZ0KaJCpahTOYVkemWb9&pullRequest=139
<CardHeader className="pb-3">
<div className="flex items-start justify-between gap-3">
{/* Main content area */}
<div className="flex-1 space-y-2">
{/* Category Badge and Confidence Level */}
<div className="flex items-center gap-2">
<div className="h-5 w-32 bg-muted rounded-md" />
<div className="h-4 w-20 bg-muted rounded" />
</div>

{/* Pattern Text Lines */}
<div className="space-y-1.5">
<div className="h-4 w-full bg-muted rounded" />
<div className="h-4 w-5/6 bg-muted rounded" />
{index % 2 === 0 && (
<div className="h-4 w-4/6 bg-muted rounded" />
)}
</div>
</div>

{/* Action Buttons */}
<div className="flex items-center gap-1">
<div className="h-8 w-8 bg-muted rounded-md" />
<div className="h-8 w-8 bg-muted rounded-md" />
<div className="h-8 w-8 bg-muted rounded-md" />
</div>
</div>
</CardHeader>

<CardContent className="pt-0">
{/* Expandable Details Section */}
<div className="mt-3 space-y-2">
{/* "Show details" button placeholder */}
<div className="h-4 w-24 bg-muted rounded" />

{/* Details content (simulate expanded state ~50% of the time) */}
{index % 2 === 0 && (
<div className="mt-3 space-y-2 text-xs">
{/* Reasoning line */}
<div className="flex items-start gap-2">
<div className="h-3 w-16 bg-muted rounded" />
<div className="h-3 w-full bg-muted rounded" />
</div>

{/* Metadata row */}
<div className="flex items-center gap-4">
<div className="flex items-center gap-2">
<div className="h-3 w-14 bg-muted rounded" />
<div className="h-3 w-8 bg-muted rounded" />
</div>
<div className="flex items-center gap-2">
<div className="h-3 w-10 bg-muted rounded" />
<div className="h-3 w-16 bg-muted rounded" />
</div>
</div>
</div>
)}
</div>
</CardContent>
</Card>
))}
</div>
</div>
);
}
108 changes: 108 additions & 0 deletions apps/frontend/src/renderer/components/skeletons/SpecDetailSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { Card } from '../ui/card';

interface SpecDetailSkeletonProps {
/** Number of phase skeletons to render */
phaseCount?: number;
/** Whether to show description placeholder */
showDescription?: boolean;
}

/**
* Skeleton loader for SpecDetail/TaskOverview implementation plan
* Matches the structure: section header, phases, subtasks, metadata
*/
export function SpecDetailSkeleton({ phaseCount = 3, showDescription = true }: SpecDetailSkeletonProps) {

Check warning on line 14 in apps/frontend/src/renderer/components/skeletons/SpecDetailSkeleton.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Mark the props of the component as read-only.

See more on https://sonarcloud.io/project/issues?id=OBenner_Auto-Coding&issues=AZ0KaJGJahTOYVkemWb-&open=AZ0KaJGJahTOYVkemWb-&pullRequest=139
return (
<div className="p-5 space-y-5 animate-pulse">
{/* Section Header */}
<div className="mb-4">
<div className="flex items-center gap-2">
<div className="h-3 w-3 bg-muted rounded" />
<div className="h-5 w-48 bg-muted rounded" />
</div>
</div>

{/* Optional Description */}
{showDescription && (
<div className="mb-4">
<div className="h-4 w-full bg-muted rounded" />
<div className="h-4 w-2/3 bg-muted rounded mt-2" />
</div>
)}

{/* Phases */}
<div className="space-y-2">
{Array.from({ length: phaseCount }).map((_, phaseIndex) => (
<Card
key={phaseIndex}

Check warning on line 37 in apps/frontend/src/renderer/components/skeletons/SpecDetailSkeleton.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not use Array index in keys

See more on https://sonarcloud.io/project/issues?id=OBenner_Auto-Coding&issues=AZ0KaJGJahTOYVkemWb_&open=AZ0KaJGJahTOYVkemWb_&pullRequest=139
className="border border-border rounded-lg"
>
{/* Phase Header */}
<div className="px-4 py-3 flex items-center gap-3">
{/* Chevron placeholder */}
<div className="h-4 w-4 bg-muted rounded shrink-0" />

{/* Status icon placeholder */}
<div className="h-4 w-4 bg-muted rounded-full shrink-0" />

{/* Phase title and badge */}
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 flex-wrap mb-1">
<div className="h-4 w-40 bg-muted rounded" />
<div className="h-5 w-20 bg-muted rounded-md" />
</div>

{/* Progress text */}
<div className="h-3 w-24 bg-muted rounded" />
</div>
</div>

{/* Subtasks (simulate expanded phase) */}
<div className="px-4 pb-3 space-y-2">
{/* Separator */}
<div className="h-px w-full bg-border" />

{/* Subtask items */}
{Array.from({ length: 3 + (phaseIndex % 2) }).map((_, subtaskIndex) => (
<div
key={subtaskIndex}

Check warning on line 68 in apps/frontend/src/renderer/components/skeletons/SpecDetailSkeleton.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not use Array index in keys

See more on https://sonarcloud.io/project/issues?id=OBenner_Auto-Coding&issues=AZ0KaJGJahTOYVkemWcA&open=AZ0KaJGJahTOYVkemWcA&pullRequest=139
className="flex items-start gap-3 p-2"
>
{/* Status badge placeholder */}
<div className="h-5 w-16 bg-muted rounded-md shrink-0 mt-0.5" />

{/* Subtask content */}
<div className="flex-1 min-w-0 space-y-1">
{/* Subtask description */}
<div className="h-4 w-full bg-muted rounded" />
{/* Verification text (optional) */}
{subtaskIndex % 2 === 0 && (
<div className="h-3 w-32 bg-muted rounded" />
)}
</div>
</div>
))}
</div>
</Card>
))}
</div>

{/* QA Report Section (skeleton) */}
<div className="space-y-3 pt-4">
{/* QA Report header */}
<div className="flex items-center gap-2">
<div className="h-3 w-3 bg-muted rounded" />
<div className="h-5 w-24 bg-muted rounded" />
</div>

{/* QA content lines */}
<div className="space-y-2 pl-5">
<div className="h-4 w-full bg-muted rounded" />
<div className="h-4 w-5/6 bg-muted rounded" />
<div className="h-4 w-4/6 bg-muted rounded" />
<div className="h-4 w-3/4 bg-muted rounded" />
</div>
</div>
</div>
);
}
7 changes: 7 additions & 0 deletions apps/frontend/src/renderer/components/skeletons/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export { ChangelogSkeleton } from './ChangelogSkeleton';
export { IssueListSkeleton } from './IssueListSkeleton';
export { PRListSkeleton } from './PRListSkeleton';
export { ProjectListSkeleton } from './ProjectListSkeleton';
export { TaskCardSkeleton } from './TaskCardSkeleton';
export { SpecDetailSkeleton } from './SpecDetailSkeleton';
export { PatternSuggestionsSkeleton } from './PatternSuggestionsSkeleton';
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import { Badge } from '../ui/badge';
import { Separator } from '../ui/separator';
import { ScrollArea } from '../ui/scroll-area';
import { SpecDetailSkeleton } from '../skeletons/SpecDetailSkeleton';
import { cn } from '../../lib/utils';
import type { Task, ImplementationPlan, Phase, SubtaskStatus, QAEscalation } from '../../../shared/types';

Expand Down Expand Up @@ -124,11 +125,7 @@ export function TaskOverview({ task }: TaskOverviewProps) {
};

if (isLoading) {
return (
<div className="flex items-center justify-center py-12">
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
</div>
);
return <SpecDetailSkeleton />;
}
Comment on lines 127 to 129

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.

⚠️ Potential issue | 🟠 Major

Add an accessible loading announcement for the skeleton state.

Line 128 now renders only visual placeholders, so assistive tech loses explicit loading feedback.

Suggested fix
  if (isLoading) {
-    return <SpecDetailSkeleton />;
+    return (
+      <div role="status" aria-live="polite" aria-busy="true">
+        <span className="sr-only">{t('tasks:overview.loading')}</span>
+        <SpecDetailSkeleton />
+      </div>
+    );
  }

Also add tasks:overview.loading to English and French locale files.

As per coding guidelines: "All user-facing text must use i18n translation keys from react-i18next with format namespace:section.key. Never use hardcoded strings in JSX/TSX. Update all language files (minimum: English and French) when adding new text."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (isLoading) {
return (
<div className="flex items-center justify-center py-12">
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
</div>
);
return <SpecDetailSkeleton />;
}
if (isLoading) {
return (
<div role="status" aria-live="polite" aria-busy="true">
<span className="sr-only">{t('tasks:overview.loading')}</span>
<SpecDetailSkeleton />
</div>
);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/renderer/components/task-detail/TaskOverview.tsx` around
lines 127 - 129, The skeleton render in TaskOverview currently returns only
visual placeholders when isLoading is true; add an accessible loading
announcement by rendering an element (e.g., a visually-hidden div or aria-live
region) alongside SpecDetailSkeleton that uses the i18n key
"tasks:overview.loading" via react-i18next (use the useTranslation hook or t
function already in the component) and ensure it has appropriate
aria-live="polite" (or "assertive" if needed) and role="status" so screen
readers announce the loading state; then add the new translation key
"tasks:overview.loading" to both English and French locale files with the
appropriate strings.


if (error) {
Expand Down
Loading