diff --git a/src/app/app.component.html b/src/app/app.component.html index ec21e8698..c4e54aeb2 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -413,6 +413,10 @@

No Message Selected

+
+ + {{ messageListEmptyNotice }} +
0) { + if (this.canvastable.rows) { const options = new Map(); options.set('unreadOnly', this.unreadMessagesOnlyCheckbox); options.set('searchText', this.searchText); this.canvastable.rows.filterBy(options); + this.updateMessageListEmptyNotice(); this.canvastable.hasChanges = true; } } + private updateMessageListEmptyNotice() { + this.messageListEmptyNotice = getEmptyMessageListNotice({ + hasVisibleRows: this.canvastable.rows.rowCount() > 0, + ignoredUnreadFolders: this.messagelistservice.ignoreUnreadInFolders, + searchText: this.searchText, + selectedFolder: this.selectedFolder, + showingSearchResults: this.showingSearchResults, + showingWebSocketSearchResults: this.showingWebSocketSearchResults, + unreadOnly: this.unreadMessagesOnlyCheckbox, + }); + } + public clearSelection() { if (this.canvastable.rows) { this.canvastable.rows.clearSelection(); diff --git a/src/app/message-list-empty-notice.spec.ts b/src/app/message-list-empty-notice.spec.ts new file mode 100644 index 000000000..44c1de5ff --- /dev/null +++ b/src/app/message-list-empty-notice.spec.ts @@ -0,0 +1,43 @@ +// --------- BEGIN RUNBOX LICENSE --------- +// Copyright (C) 2016-2026 Runbox Solutions AS (runbox.com). +// +// This file is part of Runbox 7. +// +// Runbox 7 is free software: You can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation, either version 3 of the License, or (at your +// option) any later version. +// +// Runbox 7 is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Runbox 7. If not, see . +// ---------- END RUNBOX LICENSE ---------- + +import { getEmptyMessageListNotice } from './message-list-empty-notice'; + +describe('getEmptyMessageListNotice', () => { + it('shows a clear notice when Unread only hides all messages in a folder', () => { + const notice = getEmptyMessageListNotice({ + hasVisibleRows: false, + ignoredUnreadFolders: ['Sent'], + selectedFolder: 'Inbox', + unreadOnly: true, + }); + + expect(notice).toBe('No unread messages in Inbox.'); + }); + + it('does not show an empty-state notice while rows are visible', () => { + const notice = getEmptyMessageListNotice({ + hasVisibleRows: true, + selectedFolder: 'Inbox', + unreadOnly: true, + }); + + expect(notice).toBeNull(); + }); +}); diff --git a/src/app/message-list-empty-notice.ts b/src/app/message-list-empty-notice.ts new file mode 100644 index 000000000..08c4fb0ec --- /dev/null +++ b/src/app/message-list-empty-notice.ts @@ -0,0 +1,48 @@ +// --------- BEGIN RUNBOX LICENSE --------- +// Copyright (C) 2016-2026 Runbox Solutions AS (runbox.com). +// +// This file is part of Runbox 7. +// +// Runbox 7 is free software: You can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation, either version 3 of the License, or (at your +// option) any later version. +// +// Runbox 7 is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Runbox 7. If not, see . +// ---------- END RUNBOX LICENSE ---------- + +export interface EmptyMessageListNoticeContext { + hasVisibleRows: boolean; + ignoredUnreadFolders?: string[]; + searchText?: string; + selectedFolder?: string; + showingSearchResults?: boolean; + showingWebSocketSearchResults?: boolean; + unreadOnly?: boolean; +} + +export function getEmptyMessageListNotice(context: EmptyMessageListNoticeContext): string { + if (context.hasVisibleRows) { + return null; + } + + const selectedFolder = context.selectedFolder || 'this folder'; + const ignoresUnreadOnly = (context.ignoredUnreadFolders || []).includes(selectedFolder); + if (context.unreadOnly && !ignoresUnreadOnly) { + return `No unread messages in ${selectedFolder}.`; + } + + const searchIsActive = (context.searchText || '').length >= 3 + || context.showingWebSocketSearchResults; + if (searchIsActive) { + return 'No messages match this search.'; + } + + return `No messages in ${selectedFolder}.`; +}