Skip to content

Commit b5dd9c8

Browse files
fix(tasks): include 'not_relevant' status in task completion checks (#1770)
Co-authored-by: Mariano Fuentes <marfuen98@gmail.com>
1 parent 0d5de44 commit b5dd9c8

File tree

9 files changed

+45
-15
lines changed

9 files changed

+45
-15
lines changed

apps/app/src/app/(app)/[orgId]/controls/[controlId]/components/table/ControlRequirementsTableColumns.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export const ControlRequirementsTableColumns: ColumnDef<RequirementTableData>[]
4343
const isCompleted = requirement.policy
4444
? requirement.policy?.status === 'published'
4545
: requirement.task
46-
? requirement.task?.status === 'done'
46+
? requirement.task?.status === 'done' || requirement.task?.status === 'not_relevant'
4747
: false;
4848

4949
return (

apps/app/src/app/(app)/[orgId]/controls/[controlId]/data/getOrganizationControlProgress.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export const getOrganizationControlProgress = async (controlId: string) => {
9696

9797
progress.byType[taskTypeKey].total++;
9898

99-
const isCompleted = task.status === 'done';
99+
const isCompleted = task.status === 'done' || task.status === 'not_relevant';
100100

101101
if (isCompleted) {
102102
progress.completed++;

apps/app/src/app/(app)/[orgId]/controls/lib/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export function getControlStatus(control: ControlWithRelations): StatusType {
66
const tasks = control.tasks || [];
77

88
const allPoliciesArePublished = policies.every((policy) => policy.status === 'published');
9-
const allTasksAreCompleted = tasks.every((task) => task.status === 'done');
9+
const allTasksAreCompleted = tasks.every((task) => task.status === 'done' || task.status === 'not_relevant');
1010

1111
if (!allPoliciesArePublished && !allTasksAreCompleted) {
1212
return 'not_started';

apps/app/src/app/(app)/[orgId]/frameworks/lib/compute.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export function computeFrameworkStats(
3434
for (const t of frameworkTasks) uniqueTaskMap.set(t.id, t);
3535
const uniqueTasks = Array.from(uniqueTaskMap.values());
3636
const totalTasks = uniqueTasks.length;
37-
const doneTasks = uniqueTasks.filter((t) => t.status === 'done').length;
37+
const doneTasks = uniqueTasks.filter((t) => t.status === 'done' || t.status === 'not_relevant').length;
3838
const taskRatio = totalTasks > 0 ? doneTasks / totalTasks : 1;
3939

4040
const complianceScore = Math.round(((policyRatio + taskRatio) / 2) * 100);

apps/app/src/app/(app)/[orgId]/frameworks/lib/getTasks.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ export const getDoneTasks = cache(async (organizationId: string) => {
88
},
99
});
1010

11-
const doneTasks = tasks.filter((t) => t.status === 'done');
11+
const doneTasks = tasks.filter((t) => t.status === 'done' || t.status === 'not_relevant');
1212
const incompleteTasks = tasks.filter(
13-
(t) => t.status === 'todo' || t.status === 'in_progress' || t.status === 'not_relevant',
13+
(t) => t.status === 'todo' || t.status === 'in_progress',
1414
);
1515

1616
return {

apps/app/src/app/(app)/[orgId]/frameworks/lib/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export function getControlStatus(
3434
(policy) => policy.status === 'published', // Simplified from artifact.policy.status
3535
);
3636
const allTasksDone =
37-
controlTasks.length > 0 && controlTasks.every((task) => task.status === 'done');
37+
controlTasks.length > 0 && controlTasks.every((task) => task.status === 'done' || task.status === 'not_relevant');
3838

3939
if (allPoliciesPublished && (controlTasks.length === 0 || allTasksDone)) return 'completed';
4040
if (allPoliciesDraft && allTasksTodo) return 'not_started';

apps/app/src/app/(app)/[orgId]/tasks/components/ModernTaskList.tsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,24 @@ export function ModernTaskList({ tasks, members, statusFilter }: ModernTaskListP
113113
<div className="divide-y divide-slate-100 overflow-hidden rounded-lg border border-slate-200/60 bg-white">
114114
{statusTasks.map((task, index) => {
115115
const member = assignedMember(task);
116+
const isNotRelevant = task.status === 'not_relevant';
116117
return (
117118
<div
118119
key={task.id}
119-
className="group flex items-center gap-4 p-4 transition-colors hover:bg-slate-50/50 cursor-pointer"
120+
className={`group relative flex items-center gap-4 p-4 transition-colors cursor-pointer ${
121+
isNotRelevant
122+
? 'opacity-50 bg-slate-100/50 backdrop-blur-md hover:bg-slate-100/60'
123+
: 'hover:bg-slate-50/50'
124+
}`}
120125
onClick={() => handleTaskClick(task.id)}
121126
>
127+
{isNotRelevant && (
128+
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
129+
<span className="text-sm font-bold uppercase tracking-[0.15em] text-slate-600">
130+
NOT RELEVANT
131+
</span>
132+
</div>
133+
)}
122134
<div
123135
className="flex shrink-0 items-center"
124136
onClick={(e) => e.stopPropagation()}
@@ -128,14 +140,16 @@ export function ModernTaskList({ tasks, members, statusFilter }: ModernTaskListP
128140
<div className="flex min-w-0 flex-1 items-center gap-4">
129141
<div className="min-w-0 flex-1">
130142
<div className="flex items-center gap-2">
131-
<div className="text-sm font-semibold text-slate-900">{task.title}</div>
143+
<div className={`text-sm font-semibold ${isNotRelevant ? 'text-slate-500' : 'text-slate-900'}`}>
144+
{task.title}
145+
</div>
132146
<AutomationIndicator
133147
automations={task.evidenceAutomations}
134148
variant="inline"
135149
/>
136150
</div>
137151
{task.description && (
138-
<div className="text-slate-500 mt-0.5 line-clamp-1 text-xs">
152+
<div className={`mt-0.5 line-clamp-1 text-xs ${isNotRelevant ? 'text-slate-400' : 'text-slate-500'}`}>
139153
{task.description}
140154
</div>
141155
)}

apps/app/src/app/(app)/[orgId]/tasks/components/TaskList.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export function TaskList({
8888
// Calculate overall stats from all tasks (not filtered)
8989
const overallStats = useMemo(() => {
9090
const total = initialTasks.length;
91-
const done = initialTasks.filter((t) => t.status === 'done').length;
91+
const done = initialTasks.filter((t) => t.status === 'done' || t.status === 'not_relevant').length;
9292
const inProgress = initialTasks.filter((t) => t.status === 'in_progress').length;
9393
const todo = initialTasks.filter((t) => t.status === 'todo').length;
9494
const completionRate = total > 0 ? Math.round((done / total) * 100) : 0;

apps/app/src/app/(app)/[orgId]/tasks/components/TasksByCategory.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export function TasksByCategory({ tasks, members, statusFilter }: TasksByCategor
112112
// Calculate stats for a category
113113
const getCategoryStats = (categoryTasks: Task[]) => {
114114
const total = categoryTasks.length;
115-
const done = categoryTasks.filter((t) => t.status === 'done').length;
115+
const done = categoryTasks.filter((t) => t.status === 'done' || t.status === 'not_relevant').length;
116116
const inProgress = categoryTasks.filter((t) => t.status === 'in_progress').length;
117117
const completionRate = total > 0 ? Math.round((done / total) * 100) : 0;
118118
return { total, done, inProgress, completionRate };
@@ -262,20 +262,34 @@ export function TasksByCategory({ tasks, members, statusFilter }: TasksByCategor
262262
const member = assignedMember(task);
263263
const statusStyle =
264264
statusPalette[task.status as keyof typeof statusPalette] ?? statusPalette.todo;
265+
const isNotRelevant = task.status === 'not_relevant';
265266
return (
266267
<div
267268
key={task.id}
268-
className="group relative flex cursor-pointer flex-col gap-3 rounded-sm border border-border/60 bg-card/50 p-4 transition-colors hover:bg-muted/20"
269+
className={`group relative flex cursor-pointer flex-col gap-3 rounded-sm border border-border/60 p-4 transition-colors ${
270+
isNotRelevant
271+
? 'opacity-50 bg-slate-100/50 backdrop-blur-md hover:bg-slate-100/60'
272+
: 'bg-card/50 hover:bg-muted/20'
273+
}`}
269274
onClick={() => handleTaskClick(task.id)}
270275
>
271276
<span
272277
className={`absolute left-0 top-0 h-full w-[2px] ${statusStyle.indicator}`}
273278
/>
279+
{isNotRelevant && (
280+
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
281+
<span className="text-sm font-bold uppercase tracking-[0.15em] text-slate-600">
282+
NOT RELEVANT
283+
</span>
284+
</div>
285+
)}
274286

275287
<div className="flex items-start justify-between gap-3">
276288
<div className="min-w-0 flex-1 space-y-2">
277289
<div className="flex items-start gap-2">
278-
<h4 className="flex-1 text-sm font-semibold text-foreground line-clamp-2">
290+
<h4 className={`flex-1 text-sm font-semibold line-clamp-2 ${
291+
isNotRelevant ? 'text-slate-500' : 'text-foreground'
292+
}`}>
279293
{task.title}
280294
</h4>
281295
<AutomationIndicator
@@ -284,7 +298,9 @@ export function TasksByCategory({ tasks, members, statusFilter }: TasksByCategor
284298
/>
285299
</div>
286300
{task.description && (
287-
<p className="text-xs text-muted-foreground/80 line-clamp-2 leading-relaxed">
301+
<p className={`text-xs line-clamp-2 leading-relaxed ${
302+
isNotRelevant ? 'text-slate-400' : 'text-muted-foreground/80'
303+
}`}>
288304
{task.description}
289305
</p>
290306
)}

0 commit comments

Comments
 (0)