+
+
+
+
+
+
+
+
+
+
+
+ @if (hasActiveFilters()) {
+
+ @if (appliedSearchText) {
+
+ "{{ appliedSearchText }}"
+
+ }
+ @for (channel of channelFilter; track channel) {
+
+ {{ getChannelDisplayName(channel) }}
+
+ }
+ @if (priorityFilter.length > 0) {
+
+ {{ getPriorityLabel(+priorityFilter[0]) }}
+
+ }
+
Clear all
+
+ }
+
+
+
+
+
+ | Title |
+ Channel |
+ Sender |
+ Priority |
+ Time |
+
+
+
+ @for (message of messages(); track message.message_id) {
+
+ |
+ {{ message.title }}
+ @if (message.content && !message.trimmed) {
+ {{ message.content | slice:0:100 }}{{ message.content.length > 100 ? '...' : '' }}
+ }
+ |
+
+ {{ message.channel_internal_name }}
+ |
+
+ {{ message.sender_name || '-' }}
+ |
+
+
+ {{ getPriorityLabel(message.priority) }}
+
+ |
+
+
+ {{ message.timestamp | relativeTime }}
+
+ |
+
+ } @empty {
+
+ |
+
+ |
+
+ }
+
+
+
+
+
diff --git a/webapp/src/app/features/messages/message-list/message-list.component.scss b/webapp/src/app/features/messages/message-list/message-list.component.scss
new file mode 100644
index 0000000..f41ad08
--- /dev/null
+++ b/webapp/src/app/features/messages/message-list/message-list.component.scss
@@ -0,0 +1,58 @@
+.page-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 16px;
+
+ h2 {
+ margin: 0;
+ }
+}
+
+.search-bar {
+ margin-bottom: 16px;
+}
+
+.active-filters {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin-bottom: 16px;
+
+ nz-tag {
+ max-width: none;
+ }
+
+ .clear-all {
+ margin-left: 8px;
+ font-size: 12px;
+ cursor: pointer;
+ }
+}
+
+.message-title {
+ font-weight: 500;
+ color: #333;
+}
+
+.message-preview {
+ font-size: 12px;
+ color: #999;
+ margin-top: 4px;
+}
+
+.pagination-controls {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 16px;
+ padding: 16px 0;
+
+ .page-indicator {
+ font-size: 14px;
+ color: #666;
+ min-width: 80px;
+ text-align: center;
+ }
+}
diff --git a/webapp/src/app/features/messages/message-list/message-list.component.ts b/webapp/src/app/features/messages/message-list/message-list.component.ts
new file mode 100644
index 0000000..d31fee2
--- /dev/null
+++ b/webapp/src/app/features/messages/message-list/message-list.component.ts
@@ -0,0 +1,211 @@
+import { Component, inject, signal, OnInit } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Router } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import { NzTableModule, NzTableFilterList } from 'ng-zorro-antd/table';
+import { NzButtonModule } from 'ng-zorro-antd/button';
+import { NzInputModule } from 'ng-zorro-antd/input';
+import { NzTagModule } from 'ng-zorro-antd/tag';
+import { NzIconModule } from 'ng-zorro-antd/icon';
+import { NzEmptyModule } from 'ng-zorro-antd/empty';
+import { NzSpinModule } from 'ng-zorro-antd/spin';
+import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
+import { NzPaginationModule } from 'ng-zorro-antd/pagination';
+import { ApiService } from '../../../core/services/api.service';
+import { AuthService } from '../../../core/services/auth.service';
+import { Message, MessageListParams } from '../../../core/models';
+import { RelativeTimePipe } from '../../../shared/pipes/relative-time.pipe';
+
+@Component({
+ selector: 'app-message-list',
+ standalone: true,
+ imports: [
+ CommonModule,
+ FormsModule,
+ NzTableModule,
+ NzButtonModule,
+ NzInputModule,
+ NzTagModule,
+ NzIconModule,
+ NzEmptyModule,
+ NzSpinModule,
+ NzToolTipModule,
+ NzPaginationModule,
+ RelativeTimePipe,
+ ],
+ templateUrl: './message-list.component.html',
+ styleUrl: './message-list.component.scss'
+})
+export class MessageListComponent implements OnInit {
+ private apiService = inject(ApiService);
+ private authService = inject(AuthService);
+ private router = inject(Router);
+
+ messages = signal