Skip to content

Commit 8d29d88

Browse files
[dev] [tofikwest] tofik/finding-improvements (#2084)
* feat(api): add revision note handling for findings update * feat(app): update onStatusChange to support async handling in FindingItem --------- Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
1 parent cddb3fd commit 8d29d88

File tree

9 files changed

+301
-57
lines changed

9 files changed

+301
-57
lines changed

apps/api/src/findings/dto/update-finding.dto.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,16 @@ export class UpdateFindingDto {
3939
@IsNotEmpty({ message: 'Content cannot be empty if provided' })
4040
@MaxLength(5000)
4141
content?: string;
42+
43+
@ApiProperty({
44+
description: 'Auditor note when requesting revision (only for needs_revision status)',
45+
example: 'Please provide clearer screenshots showing the timestamp.',
46+
maxLength: 2000,
47+
required: false,
48+
nullable: true,
49+
})
50+
@IsString()
51+
@IsOptional()
52+
@MaxLength(2000)
53+
revisionNote?: string | null;
4254
}

apps/api/src/findings/findings.service.ts

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,7 @@ export class FindingsService {
7171
],
7272
});
7373

74-
this.logger.log(
75-
`Retrieved ${findings.length} findings for task ${taskId}`,
76-
);
74+
this.logger.log(`Retrieved ${findings.length} findings for task ${taskId}`);
7775
return findings;
7876
}
7977

@@ -311,19 +309,38 @@ export class FindingsService {
311309
}
312310

313311
// ready_for_review can only be set by non-auditor admins/owners (client signals to auditor)
314-
if (updateDto.status === FindingStatus.ready_for_review && isAuditor && !isPlatformAdmin) {
312+
if (
313+
updateDto.status === FindingStatus.ready_for_review &&
314+
isAuditor &&
315+
!isPlatformAdmin
316+
) {
315317
throw new ForbiddenException(
316318
`Auditors cannot set status to 'ready_for_review'. This status is for clients to signal readiness.`,
317319
);
318320
}
319321
}
320322

323+
// Handle revisionNote logic:
324+
// - Set revisionNote when status is needs_revision and a note is provided
325+
// - Clear revisionNote when status changes to anything other than needs_revision
326+
let revisionNoteUpdate: { revisionNote?: string | null } = {};
327+
if (updateDto.status === FindingStatus.needs_revision) {
328+
// Set revision note if provided (can be null to clear)
329+
if (updateDto.revisionNote !== undefined) {
330+
revisionNoteUpdate = { revisionNote: updateDto.revisionNote || null };
331+
}
332+
} else if (updateDto.status !== undefined) {
333+
// Clear revision note when moving to a different status
334+
revisionNoteUpdate = { revisionNote: null };
335+
}
336+
321337
const updatedFinding = await db.finding.update({
322338
where: { id: findingId },
323339
data: {
324340
...(updateDto.status !== undefined && { status: updateDto.status }),
325341
...(updateDto.type !== undefined && { type: updateDto.type }),
326342
...(updateDto.content !== undefined && { content: updateDto.content }),
343+
...revisionNoteUpdate,
327344
},
328345
include: {
329346
createdBy: {
@@ -411,22 +428,34 @@ export class FindingsService {
411428

412429
switch (updateDto.status) {
413430
case FindingStatus.ready_for_review:
414-
this.logger.log(`Triggering 'ready_for_review' notification for finding ${findingId}`);
431+
this.logger.log(
432+
`Triggering 'ready_for_review' notification for finding ${findingId}`,
433+
);
415434
void this.findingNotifierService.notifyReadyForReview({
416435
...notificationParams,
417436
findingCreatorMemberId: finding.createdById,
418437
});
419438
break;
420439
case FindingStatus.needs_revision:
421-
this.logger.log(`Triggering 'needs_revision' notification for finding ${findingId}`);
422-
void this.findingNotifierService.notifyNeedsRevision(notificationParams);
440+
this.logger.log(
441+
`Triggering 'needs_revision' notification for finding ${findingId}`,
442+
);
443+
void this.findingNotifierService.notifyNeedsRevision(
444+
notificationParams,
445+
);
423446
break;
424447
case FindingStatus.closed:
425-
this.logger.log(`Triggering 'closed' notification for finding ${findingId}`);
426-
void this.findingNotifierService.notifyFindingClosed(notificationParams);
448+
this.logger.log(
449+
`Triggering 'closed' notification for finding ${findingId}`,
450+
);
451+
void this.findingNotifierService.notifyFindingClosed(
452+
notificationParams,
453+
);
427454
break;
428455
case FindingStatus.open:
429-
this.logger.log(`Status changed to 'open' for finding ${findingId}. No notification sent.`);
456+
this.logger.log(
457+
`Status changed to 'open' for finding ${findingId}. No notification sent.`,
458+
);
430459
break;
431460
default:
432461
this.logger.warn(
@@ -489,6 +518,9 @@ export class FindingsService {
489518
// Verify finding exists
490519
await this.findById(organizationId, findingId);
491520

492-
return this.findingAuditService.getFindingActivity(findingId, organizationId);
521+
return this.findingAuditService.getFindingActivity(
522+
findingId,
523+
organizationId,
524+
);
493525
}
494526
}

apps/app/src/app/(app)/[orgId]/frameworks/components/FindingsOverview.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const STATUS_COLORS: Record<FindingStatus, string> = {
1818

1919
const STATUS_LABELS: Record<FindingStatus, string> = {
2020
open: 'Open',
21-
ready_for_review: 'Review',
21+
ready_for_review: 'Auditor Review',
2222
needs_revision: 'Revision',
2323
closed: 'Closed',
2424
};
@@ -215,7 +215,7 @@ export function FindingsOverview({
215215
</div>
216216
</div>
217217
<Button asChild size="icon" variant="outline" className="shrink-0 ml-2">
218-
<Link href={`/${organizationId}/tasks/${finding.task.id}`}>
218+
<Link href={`/${organizationId}/tasks/${finding.task.id}#finding-${finding.id}`}>
219219
<ArrowRight className="h-3 w-3" />
220220
</Link>
221221
</Button>

0 commit comments

Comments
 (0)