Skip to content
Merged
197 changes: 52 additions & 145 deletions dashboard/src/v2/TasksPage.tsx

Large diffs are not rendered by default.

94 changes: 37 additions & 57 deletions dashboard/src/v2/components/tasks/DependencyStatusIndicators.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,15 @@ import { getDependencyPresentation, type DependencyIndicator } from "../../lib/t
import { useInteractionTokens } from "../../lib/motion/tokens.js";

function getDependencyStatusCopy(dep: DependencyIndicator): string {
if (dep.stateLabel) {
return dep.stateLabel;
}

if (dep.isKnown === false || dep.title.startsWith("Unknown Task")) {
return "Unknown";
}
return getDependencyPresentation(dep.status, isDependencyKnown(dep)).stateLabel ?? "Unknown";
}

switch (dep.status) {
case "completed":
return "Resolved";
case "coding_completed":
return "Ready for QA";
case "in_progress":
return "In progress";
case "QA_REVIEW_FAILED":
return "QA failed";
case "pending":
default:
return "Blocked";
}
function isDependencyKnown(dep: DependencyIndicator): boolean {
return dep.isKnown !== false && !dep.title.startsWith("Unknown Task");
}

function getDependencyState(dep: DependencyIndicator): "unknown" | "resolved" | "qa_failed" | "in_progress" | "blocked" {
if (dep.isKnown === false || dep.title.startsWith("Unknown Task")) {
if (!isDependencyKnown(dep)) {
return "unknown";
}

Expand All @@ -52,7 +36,7 @@ function isDependencyBlocking(dep: DependencyIndicator): boolean {
}

function getDependencyToneClass(dep: DependencyIndicator): string {
if (dep.isKnown === false || dep.title.startsWith("Unknown Task")) {
if (!isDependencyKnown(dep)) {
return "bg-slate-400/[0.08] border-slate-400/30 text-slate-600 dark:text-slate-300 border-dashed";
}

Expand Down Expand Up @@ -86,10 +70,9 @@ export const DependencyStatusIndicators: FunctionComponent<{
: `${summary}.`;

return (
<div
className="relative z-10 mt-3 flex flex-wrap items-center gap-1.5"
role="list"
aria-label={`${summary}. Task dependencies`}
<section
className="relative z-10 mt-3"
aria-label="Task dependencies"
aria-live="polite"
aria-atomic="false"
style={{
Expand All @@ -103,44 +86,41 @@ export const DependencyStatusIndicators: FunctionComponent<{
>
<span className="sr-only" role="status" aria-live="polite" aria-atomic="true">{announcement}</span>
<div
role="listitem"
className={`flex min-h-7 max-w-full items-center gap-1.5 rounded-lg border px-2 py-1 text-[9px] font-bold uppercase tracking-[0.12em] transition-colors motion-reduce:transition-none ${
className={`inline-flex min-h-6 max-w-full items-center rounded-md border px-2 py-0.5 text-[9px] font-bold uppercase tracking-[0.12em] transition-colors motion-reduce:transition-none ${
blockerCount === 0
? "border-status-green/20 bg-status-green/[0.08] text-status-green"
: "border-status-amber/25 bg-status-amber/[0.08] text-status-amber"
}`}
aria-label={summary}
>
{summary}
</div>
{indicators.map((dep) => {
const statusText = dep.status.replace(/_/g, ' ');
const statusCopy = getDependencyStatusCopy(dep);
const dependencyState = getDependencyState(dep);
const blockingCopy = isDependencyBlocking(dep) ? "Blocking dependency" : "Resolved dependency";
const blockingBadge = isDependencyBlocking(dep) ? "Blocking" : "Clear";
const stateDescription = dep.stateDescription ?? getDependencyPresentation(dep.status, dep.isKnown !== false && !dep.title.startsWith("Unknown Task")).stateDescription;
const containerClass = getDependencyToneClass(dep);
<div className="mt-1.5 flex flex-wrap items-center gap-1.5" role="list" aria-label={`${summary}. Task dependencies`}>
{indicators.map((dep) => {
const statusText = dep.status.replace(/_/g, " ");
const statusCopy = getDependencyStatusCopy(dep);
const dependencyState = getDependencyState(dep);
const blockingCopy = isDependencyBlocking(dep) ? "Blocking dependency" : "Resolved dependency";
const stateDescription = dep.stateDescription ?? getDependencyPresentation(dep.status, isDependencyKnown(dep)).stateDescription;
const containerClass = getDependencyToneClass(dep);

return (
<div
key={dep.recordId}
role="listitem"
className={`flex min-h-7 max-w-full items-center gap-1.5 rounded-lg border px-2 py-1 text-[9px] font-bold uppercase tracking-[0.12em] transition-colors motion-reduce:transition-none ${containerClass}`}
data-dependency-state={dependencyState}
data-blocking={isDependencyBlocking(dep) ? "true" : "false"}
title={`Depends on ${dep.title} (${statusCopy}; ${statusText})`}
aria-label={`Depends on task ${dep.id}, ${statusCopy.toLowerCase()}. ${blockingCopy}. ${stateDescription}. Status: ${statusText}. Title: ${dep.title}`}
>
<span className="sr-only">Depends on task {dep.id}, {statusCopy.toLowerCase()}. {blockingCopy}. {stateDescription}. Status: {statusText}. Title: {dep.title}</span>
<ArrowRight className="w-2.5 h-2.5" strokeWidth={2.5} aria-hidden="true" />
<span aria-hidden="true" className="shrink-0">{dep.id}</span>
<span aria-hidden="true" className="rounded-full bg-current/10 px-1.5 py-0.5 text-[8px] opacity-90">{statusCopy}</span>
<span aria-hidden="true" className="rounded-full border border-current/15 bg-current/5 px-1.5 py-0.5 text-[8px] opacity-90">{blockingBadge}</span>
<span aria-hidden="true" className="min-w-0 max-w-[9rem] truncate text-[8px] normal-case opacity-80">{dep.title}</span>
</div>
);
})}
</div>
return (
<div
key={dep.recordId}
role="listitem"
className={`flex min-h-7 max-w-full items-center gap-1.5 rounded-lg border px-2 py-1 text-[9px] font-bold uppercase tracking-[0.12em] transition-colors motion-reduce:transition-none ${containerClass}`}
data-dependency-state={dependencyState}
data-blocking={isDependencyBlocking(dep) ? "true" : "false"}
title={`Depends on ${dep.title} (${statusCopy}; ${statusText})`}
aria-label={`Depends on task ${dep.id}, ${statusCopy.toLowerCase()}. ${blockingCopy}. ${stateDescription}. Status: ${statusText}. Title: ${dep.title}`}
>
<span className="sr-only">Depends on task {dep.id}, {statusCopy.toLowerCase()}. {blockingCopy}. {stateDescription}. Status: {statusText}. Title: {dep.title}</span>
<ArrowRight className="h-2.5 w-2.5 shrink-0" strokeWidth={2.5} aria-hidden="true" />
<span aria-hidden="true" className="min-w-0 break-all font-mono">{dep.id}</span>
<span aria-hidden="true" className="shrink-0 rounded-full bg-current/10 px-1.5 py-0.5 text-[8px] opacity-90">{statusCopy}</span>
</div>
);
})}
</div>
</section>
);
});
Loading
Loading