fix(#145): dashboard notification widget shows all recent notifications
- Add type-only filter to notification repo/service (previously only worked with type+read=false together) - Dashboard widget now fetches all recent notifications (mentions + replies, both read and unread) instead of unread mentions only - Update component heading and show type label per row Root cause: Berit's mentions were read=true, so the unread-only filter returned 0 results. The recent docs widget had no REVIEWED documents because 'marking ready' sets metadata_complete, not status=REVIEWED. Recent docs now shows all uploads without a status filter. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,9 @@ public interface NotificationRepository extends JpaRepository<Notification, UUID
|
||||
|
||||
Page<Notification> findByRecipientIdOrderByCreatedAtDesc(UUID recipientId, Pageable pageable);
|
||||
|
||||
Page<Notification> findByRecipientIdAndTypeOrderByCreatedAtDesc(
|
||||
UUID recipientId, NotificationType type, Pageable pageable);
|
||||
|
||||
Page<Notification> findByRecipientIdAndTypeAndReadFalseOrderByCreatedAtDesc(
|
||||
UUID recipientId, NotificationType type, Pageable pageable);
|
||||
|
||||
|
||||
@@ -98,6 +98,10 @@ public class NotificationService {
|
||||
return notificationRepository.findByRecipientIdAndTypeAndReadFalseOrderByCreatedAtDesc(userId, type, pageable)
|
||||
.map(this::toDTO);
|
||||
}
|
||||
if (type != null) {
|
||||
return notificationRepository.findByRecipientIdAndTypeOrderByCreatedAtDesc(userId, type, pageable)
|
||||
.map(this::toDTO);
|
||||
}
|
||||
return notificationRepository.findByRecipientIdOrderByCreatedAtDesc(userId, pageable)
|
||||
.map(this::toDTO);
|
||||
}
|
||||
|
||||
@@ -79,6 +79,24 @@ class NotificationRepositoryTest {
|
||||
assertThat(result.getTotalElements()).isEqualTo(5);
|
||||
}
|
||||
|
||||
// ─── findByRecipientIdAndType (without read filter) ──────────────────────
|
||||
|
||||
@Test
|
||||
void findByType_returnsBothReadAndUnreadMentions() {
|
||||
notificationRepository.save(mention(userA, false)); // unread
|
||||
notificationRepository.save(mention(userA, true)); // read — should also be included
|
||||
notificationRepository.save(reply(userA, false)); // REPLY — excluded
|
||||
notificationRepository.save(mention(userB, false)); // different user — excluded
|
||||
|
||||
Page<Notification> result = notificationRepository
|
||||
.findByRecipientIdAndTypeOrderByCreatedAtDesc(
|
||||
userA.getId(), NotificationType.MENTION, Pageable.ofSize(10));
|
||||
|
||||
assertThat(result.getContent()).hasSize(2);
|
||||
assertThat(result.getContent()).allMatch(n -> n.getType() == NotificationType.MENTION);
|
||||
assertThat(result.getContent()).allMatch(n -> n.getRecipient().getId().equals(userA.getId()));
|
||||
}
|
||||
|
||||
// ─── helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
private Notification mention(AppUser recipient, boolean read) {
|
||||
|
||||
@@ -386,6 +386,21 @@ class NotificationServiceTest {
|
||||
verify(notificationRepository, never()).findByRecipientIdOrderByCreatedAtDesc(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getNotifications_withTypeOnly_usesTypeFilteredRepoMethod() {
|
||||
when(notificationRepository.findByRecipientIdAndTypeOrderByCreatedAtDesc(
|
||||
eq(userA.getId()), eq(NotificationType.MENTION), any()))
|
||||
.thenReturn(Page.empty());
|
||||
|
||||
notificationService.getNotifications(userA.getId(), NotificationType.MENTION, null, Pageable.ofSize(5));
|
||||
|
||||
verify(notificationRepository).findByRecipientIdAndTypeOrderByCreatedAtDesc(
|
||||
eq(userA.getId()), eq(NotificationType.MENTION), any());
|
||||
verify(notificationRepository, never()).findByRecipientIdOrderByCreatedAtDesc(any(), any());
|
||||
verify(notificationRepository, never())
|
||||
.findByRecipientIdAndTypeAndReadFalseOrderByCreatedAtDesc(any(), any(), any());
|
||||
}
|
||||
|
||||
// ─── private helpers ──────────────────────────────────────────────────────
|
||||
|
||||
private DocumentComment commentWithAuthor(UUID id, UUID parentId, UUID authorId, String authorName) {
|
||||
|
||||
@@ -18,7 +18,7 @@ let { mentions }: Props = $props();
|
||||
{#if mentions.length > 0}
|
||||
<div data-testid="dashboard-mentions" class="rounded-sm border border-line bg-surface p-6">
|
||||
<h2 class="mb-4 font-sans text-xs font-bold tracking-widest text-gray-400 uppercase">
|
||||
Erwähnungen
|
||||
Benachrichtigungen
|
||||
</h2>
|
||||
{#each mentions as mention (mention.id)}
|
||||
<div class="flex items-center gap-3 border-b border-line py-2 last:border-0">
|
||||
@@ -28,6 +28,9 @@ let { mentions }: Props = $props();
|
||||
class="font-serif text-sm text-ink hover:text-ink-2"
|
||||
>
|
||||
{mention.actorName ?? ''}
|
||||
{#if mention.type === 'MENTION'}<span class="ml-1 font-sans text-xs text-gray-400"
|
||||
>erwähnt Sie</span
|
||||
>{:else}<span class="ml-1 font-sans text-xs text-gray-400">hat geantwortet</span>{/if}
|
||||
</a>
|
||||
{:else}
|
||||
<span class="font-serif text-sm text-ink">{mention.actorName ?? ''}</span>
|
||||
|
||||
@@ -58,13 +58,9 @@ export async function load({ url, fetch }) {
|
||||
|
||||
if (isDashboard) {
|
||||
const [mentionsResult, incompleteResult, recentResult] = await Promise.allSettled([
|
||||
api.GET('/api/notifications', {
|
||||
params: { query: { type: 'MENTION', read: false, size: 5 } }
|
||||
}),
|
||||
api.GET('/api/notifications', { params: { query: { size: 5 } } }),
|
||||
api.GET('/api/documents/incomplete', { params: { query: { size: 5 } } }),
|
||||
api.GET('/api/documents/search', {
|
||||
params: { query: { status: 'REVIEWED' } }
|
||||
})
|
||||
api.GET('/api/documents/search', { params: { query: {} } })
|
||||
]);
|
||||
|
||||
if (mentionsResult.status === 'fulfilled' && mentionsResult.value.response.ok) {
|
||||
|
||||
Reference in New Issue
Block a user