chore: enforce lint across codebase and ban "maybe" in identifiers

Remove member-ordering and complexity eslint-disable comments by reordering
class members and applying targeted fixes. Add metoyou/no-maybe-in-naming,
type-safe WebRTC e2e harness helpers, and resolve remaining lint errors so
npm run lint exits cleanly.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-11 11:08:26 +02:00
parent b630bacdc6
commit 79c6f91cd6
138 changed files with 4286 additions and 2310 deletions

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/member-ordering */
import { Injectable, inject } from '@angular/core';
import {
Actions,
@@ -38,9 +37,6 @@ export function groupMessagesByRoom(messages: Message[]): Map<string, Message[]>
@Injectable()
export class NotificationsEffects {
private readonly actions$ = inject(Actions);
private readonly store = inject(Store);
private readonly notifications = inject(NotificationsFacade);
syncRoomCatalog$ = createEffect(
() =>
@@ -136,4 +132,11 @@ export class NotificationsEffects {
),
{ dispatch: false }
);
private readonly actions$ = inject(Actions);
private readonly store = inject(Store);
private readonly notifications = inject(NotificationsFacade);
}

View File

@@ -1,14 +1,15 @@
/* eslint-disable @typescript-eslint/member-ordering */
import { Injectable, inject } from '@angular/core';
import { NotificationsService } from '../services/notifications.service';
@Injectable({ providedIn: 'root' })
export class NotificationsFacade {
private readonly service = inject(NotificationsService);
readonly settings = this.service.settings;
readonly unread = this.service.unread;
private readonly service = inject(NotificationsService);
initialize(
...args: Parameters<NotificationsService['initialize']>
): ReturnType<NotificationsService['initialize']> {
@@ -98,4 +99,5 @@ export class NotificationsFacade {
): ReturnType<NotificationsService['setChannelMuted']> {
return this.service.setChannelMuted(...args);
}
}

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/member-ordering */
import {
Injectable,
computed,
@@ -46,33 +45,54 @@ const MAX_NOTIFIED_MESSAGE_IDS = 500;
@Injectable({ providedIn: 'root' })
export class NotificationsService {
readonly settings = computed(() => this._settings());
readonly unread = computed(() => this._unread());
private readonly store = inject(Store);
private readonly db = inject(DatabaseService);
private readonly audio = inject(NotificationAudioService);
private readonly appI18n = inject(AppI18nService);
private readonly timeSync = inject(TimeSyncService);
private readonly desktopNotifications = inject(DesktopNotificationService);
private readonly storage = inject(NotificationSettingsStorageService);
private readonly currentRoom = this.store.selectSignal(selectCurrentRoom);
private readonly activeChannelId = this.store.selectSignal(selectActiveChannelId);
private readonly savedRooms = this.store.selectSignal(selectSavedRooms);
private readonly currentUser = this.store.selectSignal(selectCurrentUser);
private readonly _settings = signal<NotificationsSettings>(createDefaultNotificationSettings());
private readonly _unread = signal<NotificationsUnreadState>(createEmptyUnreadState());
private readonly _windowFocused = signal<boolean>(typeof document === 'undefined' ? true : document.hasFocus());
private readonly _documentVisible = signal<boolean>(typeof document === 'undefined' ? true : document.visibilityState === 'visible');
private readonly _windowMinimized = signal<boolean>(false);
private readonly platformKind = detectPlatform();
private readonly notifiedMessageIds = new Set<string>();
private readonly notifiedMessageOrder: string[] = [];
private attentionActive = false;
private windowStateCleanup: (() => void) | null = null;
private initialised = false;
readonly settings = computed(() => this._settings());
readonly unread = computed(() => this._unread());
private readonly _unread = signal<NotificationsUnreadState>(createEmptyUnreadState());
private readonly _windowFocused = signal<boolean>(typeof document === 'undefined' ? true : document.hasFocus());
private readonly _documentVisible = signal<boolean>(typeof document === 'undefined' ? true : document.visibilityState === 'visible');
private readonly _windowMinimized = signal<boolean>(false);
private readonly platformKind = detectPlatform();
private readonly notifiedMessageIds = new Set<string>();
private readonly notifiedMessageOrder: string[] = [];
private attentionActive = false;
private windowStateCleanup: (() => void) | null = null;
private initialised = false;
async initialize(): Promise<void> {
if (this.initialised) {
@@ -311,30 +331,6 @@ export class NotificationsService {
});
}
private registerWindowListeners(): void {
if (typeof window === 'undefined' || typeof document === 'undefined') {
return;
}
window.addEventListener('focus', this.handleWindowFocus);
window.addEventListener('blur', this.handleWindowBlur);
document.addEventListener('visibilitychange', this.handleVisibilityChange);
}
private registerWindowStateListener(): void {
this.windowStateCleanup = this.desktopNotifications.onWindowStateChanged((state) => {
this._windowFocused.set(state.isFocused);
this._windowMinimized.set(state.isMinimized);
if (state.isFocused && !state.isMinimized && this._documentVisible()) {
this.markCurrentChannelReadIfActive();
return;
}
this.syncWindowAttention();
});
}
private readonly handleWindowFocus = (): void => {
this._windowFocused.set(true);
this._windowMinimized.set(false);
@@ -359,6 +355,30 @@ export class NotificationsService {
this.syncWindowAttention();
};
private registerWindowListeners(): void {
if (typeof window === 'undefined' || typeof document === 'undefined') {
return;
}
window.addEventListener('focus', this.handleWindowFocus);
window.addEventListener('blur', this.handleWindowBlur);
document.addEventListener('visibilitychange', this.handleVisibilityChange);
}
private registerWindowStateListener(): void {
this.windowStateCleanup = this.desktopNotifications.onWindowStateChanged((state) => {
this._windowFocused.set(state.isFocused);
this._windowMinimized.set(state.isMinimized);
if (state.isFocused && !state.isMinimized && this._documentVisible()) {
this.markCurrentChannelReadIfActive();
return;
}
this.syncWindowAttention();
});
}
private buildContext(): NotificationDeliveryContext {
return {
activeChannelId: this.activeChannelId(),
@@ -625,6 +645,7 @@ export class NotificationsService {
}
}
}
}
function detectPlatform(): DesktopPlatform {

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/member-ordering */
import {
Component,
computed,
@@ -37,15 +36,20 @@ import { APP_TRANSLATE_IMPORTS } from '../../../../../core/i18n';
templateUrl: './notifications-settings.component.html'
})
export class NotificationsSettingsComponent {
private readonly store = inject(Store);
readonly notifications = inject(NotificationsFacade);
readonly rooms = this.store.selectSignal(selectSavedRooms);
readonly settings = this.notifications.settings;
readonly enabled = computed(() => this.settings().enabled);
readonly showPreview = computed(() => this.settings().showPreview);
readonly respectBusyStatus = computed(() => this.settings().respectBusyStatus);
private readonly store = inject(Store);
trackRoom = (_index: number, room: Room) => room.id;
textChannels(room: Room) {
@@ -112,4 +116,5 @@ export class NotificationsSettingsComponent {
formatUnreadCount(count: number): string {
return count > 99 ? '99+' : String(count);
}
}