agent-ecosystem/src/main/ipc/notifications.ts
iliya f5efa17b1a feat: enhance notification handling and improve task comment protocols
- Added debug logging for test notification handling in the NotificationManager, improving traceability during notification operations.
- Implemented unescaping of literal newline sequences in task descriptions and comments across various components, ensuring proper formatting.
- Updated task comment handling logic to clarify awaiting replies from task responders, enhancing user awareness of task interactions.
- Refined UI components to improve user experience in settings and task management, including adjustments to the NotificationsSection and TeamDetailView.
2026-03-15 14:18:33 +02:00

206 lines
6.6 KiB
TypeScript

/**
* IPC Handlers for Notification Operations.
*
* Handlers:
* - notifications:get: Get all notifications (paginated)
* - notifications:markRead: Mark notification as read
* - notifications:markAllRead: Mark all as read
* - notifications:delete: Delete a single notification
* - notifications:clear: Clear all notifications
* - notifications:getUnreadCount: Get unread count for badge
* - notifications:testNotification: Send a test notification to verify delivery
*/
import { getErrorMessage } from '@shared/utils/errorHandling';
import { createLogger } from '@shared/utils/logger';
import { type IpcMain, type IpcMainInvokeEvent } from 'electron';
import {
type GetNotificationsOptions,
type GetNotificationsResult,
NotificationManager,
} from '../services';
import { coercePageLimit, validateNotificationId } from './guards';
const logger = createLogger('IPC:notifications');
/**
* Registers all notification-related IPC handlers.
*
* @param ipcMain - The Electron IpcMain instance
*/
export function registerNotificationHandlers(ipcMain: IpcMain): void {
ipcMain.handle('notifications:get', handleGetNotifications);
ipcMain.handle('notifications:markRead', handleMarkRead);
ipcMain.handle('notifications:markAllRead', handleMarkAllRead);
ipcMain.handle('notifications:delete', handleDelete);
ipcMain.handle('notifications:clear', handleClear);
ipcMain.handle('notifications:getUnreadCount', handleGetUnreadCount);
ipcMain.handle('notifications:testNotification', handleTestNotification);
logger.info('Notification handlers registered');
}
/**
* Removes all notification IPC handlers.
* Should be called when shutting down.
*/
export function removeNotificationHandlers(ipcMain: IpcMain): void {
ipcMain.removeHandler('notifications:get');
ipcMain.removeHandler('notifications:markRead');
ipcMain.removeHandler('notifications:markAllRead');
ipcMain.removeHandler('notifications:delete');
ipcMain.removeHandler('notifications:clear');
ipcMain.removeHandler('notifications:getUnreadCount');
ipcMain.removeHandler('notifications:testNotification');
logger.info('Notification handlers removed');
}
// =============================================================================
// Handler Implementations
// =============================================================================
/**
* Handler for 'notifications:get' IPC call.
* Gets all notifications with optional pagination and filtering.
*/
async function handleGetNotifications(
_event: IpcMainInvokeEvent,
options?: GetNotificationsOptions
): Promise<GetNotificationsResult> {
try {
const opts = options ?? {};
const safeOptions: GetNotificationsOptions = {
limit: coercePageLimit(opts.limit, 20),
offset:
typeof opts.offset === 'number' && Number.isFinite(opts.offset) && opts.offset >= 0
? Math.floor(opts.offset)
: 0,
};
const manager = NotificationManager.getInstance();
const result = await manager.getNotifications(safeOptions);
return result;
} catch (error) {
logger.error('Error in notifications:get:', getErrorMessage(error));
return {
notifications: [],
total: 0,
totalCount: 0,
unreadCount: 0,
hasMore: false,
};
}
}
/**
* Handler for 'notifications:markRead' IPC call.
* Marks a specific notification as read.
*/
async function handleMarkRead(
_event: IpcMainInvokeEvent,
notificationId: string
): Promise<boolean> {
try {
const validatedNotification = validateNotificationId(notificationId);
if (!validatedNotification.valid) {
logger.error(
`notifications:markRead rejected: ${validatedNotification.error ?? 'Invalid notificationId'}`
);
return false;
}
const manager = NotificationManager.getInstance();
const success = await manager.markRead(validatedNotification.value!);
return success;
} catch (error) {
logger.error(`Error in notifications:markRead for ${notificationId}:`, error);
return false;
}
}
/**
* Handler for 'notifications:markAllRead' IPC call.
* Marks all notifications as read.
*/
async function handleMarkAllRead(_event: IpcMainInvokeEvent): Promise<boolean> {
try {
const manager = NotificationManager.getInstance();
const success = await manager.markAllRead();
return success;
} catch (error) {
logger.error('Error in notifications:markAllRead:', error);
return false;
}
}
/**
* Handler for 'notifications:delete' IPC call.
* Deletes a single notification.
*/
async function handleDelete(_event: IpcMainInvokeEvent, notificationId: string): Promise<boolean> {
try {
const validatedNotification = validateNotificationId(notificationId);
if (!validatedNotification.valid) {
logger.error(
`notifications:delete rejected: ${validatedNotification.error ?? 'Invalid notificationId'}`
);
return false;
}
const manager = NotificationManager.getInstance();
const success = manager.deleteNotification(validatedNotification.value!);
return success;
} catch (error) {
logger.error(`Error in notifications:delete for ${notificationId}:`, error);
return false;
}
}
/**
* Handler for 'notifications:clear' IPC call.
* Clears all notifications.
*/
async function handleClear(_event: IpcMainInvokeEvent): Promise<boolean> {
try {
const manager = NotificationManager.getInstance();
const success = await manager.clearAll();
return success;
} catch (error) {
logger.error('Error in notifications:clear:', error);
return false;
}
}
/**
* Handler for 'notifications:getUnreadCount' IPC call.
* Gets the count of unread notifications for badge display.
*/
async function handleGetUnreadCount(_event: IpcMainInvokeEvent): Promise<number> {
try {
const manager = NotificationManager.getInstance();
const count = await manager.getUnreadCount();
return count;
} catch (error) {
logger.error('Error in notifications:getUnreadCount:', error);
return 0;
}
}
/**
* Handler for 'notifications:testNotification' IPC call.
* Sends a test notification to verify that native OS notifications are delivered.
*/
function handleTestNotification(_event: IpcMainInvokeEvent): { success: boolean; error?: string } {
try {
logger.debug('Handling notifications:testNotification request');
const manager = NotificationManager.getInstance();
const result = manager.sendTestNotification();
logger.debug(`notifications:testNotification result: success=${String(result.success)}`);
return result;
} catch (error) {
logger.error('Error in notifications:testNotification:', error);
return { success: false, error: getErrorMessage(error) };
}
}