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
co-authored by Cursor
parent b630bacdc6
commit 79c6f91cd6
138 changed files with 4286 additions and 2310 deletions
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/member-ordering */
import {
Component,
HostListener,
@@ -67,42 +66,64 @@ import {
})
export class ChatMessagesComponent {
@ViewChild(ChatMessageComposerComponent) composer?: ChatMessageComposerComponent;
@ViewChild(ChatMessageListComponent) messageList?: ChatMessageListComponent;
private readonly electronBridge = inject(ElectronBridgeService);
private readonly store = inject(Store);
private readonly webrtc = inject(RealtimeSessionFacade);
private readonly attachmentsSvc = inject(AttachmentFacade);
private readonly klipy = inject(KlipyService);
private readonly viewport = inject(ViewportService);
@ViewChild(ChatMessageListComponent) messageList?: ChatMessageListComponent;
readonly isMobile = this.viewport.isMobile;
readonly roomMessages = this.store.selectSignal(selectCurrentRoomMessages);
readonly channelMessages = this.store.selectSignal(selectActiveChannelMessages);
private readonly activeChannelId = this.store.selectSignal(selectActiveChannelId);
readonly currentRoom = this.store.selectSignal(selectCurrentRoom);
readonly loading = this.store.selectSignal(selectMessagesLoading);
readonly syncing = this.store.selectSignal(selectMessagesSyncing);
readonly loadingOlder = this.store.selectSignal(selectMessagesLoadingOlder);
readonly currentUser = this.store.selectSignal(selectCurrentUser);
readonly isAdmin = this.store.selectSignal(selectIsCurrentUserAdmin);
readonly conversationKey = computed(() => `${this.currentRoom()?.id ?? 'no-room'}:${this.activeChannelId() ?? 'general'}`);
readonly conversationExhausted = toSignal(
toObservable(this.conversationKey).pipe(switchMap((key) => this.store.select(selectConversationExhausted(key)))),
{ initialValue: false }
);
readonly klipyEnabled = computed(() => this.klipy.isEnabled(this.currentRoom()));
readonly composerBottomPadding = signal(140);
readonly klipyGifPickerAnchorRight = signal(16);
readonly replyTo = signal<Message | null>(null);
readonly showKlipyGifPicker = signal(false);
readonly lightboxState = signal<ChatLightboxState | null>(null);
readonly galleryAttachments = signal<Attachment[] | null>(null);
readonly imageContextMenu = signal<ChatMessageImageContextMenuEvent | null>(null);
private readonly electronBridge = inject(ElectronBridgeService);
private readonly store = inject(Store);
private readonly webrtc = inject(RealtimeSessionFacade);
private readonly attachmentsSvc = inject(AttachmentFacade);
private readonly klipy = inject(KlipyService);
private readonly viewport = inject(ViewportService);
private readonly activeChannelId = this.store.selectSignal(selectActiveChannelId);
constructor() {
effect(() => {
void this.klipy.refreshAvailability(this.currentRoom());
@@ -262,36 +283,6 @@ export class ChatMessagesComponent {
this.composer?.handleKlipyGifSelected(gif);
}
private syncKlipyGifPickerAnchor(): void {
const triggerRect = this.composer?.getKlipyTriggerRect();
if (!triggerRect) {
this.klipyGifPickerAnchorRight.set(16);
return;
}
const viewportWidth = window.innerWidth;
const popupWidth = this.getKlipyGifPickerWidth(viewportWidth);
const preferredRight = viewportWidth - triggerRect.right;
const minRight = 16;
const maxRight = Math.max(minRight, viewportWidth - popupWidth - 16);
this.klipyGifPickerAnchorRight.set(Math.min(Math.max(Math.round(preferredRight), minRight), maxRight));
}
private getKlipyGifPickerWidth(viewportWidth: number): number {
if (viewportWidth >= 1280)
return 52 * 16;
if (viewportWidth >= 768)
return 42 * 16;
if (viewportWidth >= 640)
return 34 * 16;
return Math.max(0, viewportWidth - 32);
}
openLightbox(event: ChatMessageImageLightboxEvent): void {
const attachments = event.attachments.filter((attachment) => attachment.available && attachment.objectUrl);
const index = attachments.findIndex((attachment) => attachment.id === event.attachment.id);
@@ -411,6 +402,36 @@ export class ChatMessagesComponent {
}
}
private syncKlipyGifPickerAnchor(): void {
const triggerRect = this.composer?.getKlipyTriggerRect();
if (!triggerRect) {
this.klipyGifPickerAnchorRight.set(16);
return;
}
const viewportWidth = window.innerWidth;
const popupWidth = this.getKlipyGifPickerWidth(viewportWidth);
const preferredRight = viewportWidth - triggerRect.right;
const minRight = 16;
const maxRight = Math.max(minRight, viewportWidth - popupWidth - 16);
this.klipyGifPickerAnchorRight.set(Math.min(Math.max(Math.round(preferredRight), minRight), maxRight));
}
private getKlipyGifPickerWidth(viewportWidth: number): number {
if (viewportWidth >= 1280)
return 52 * 16;
if (viewportWidth >= 768)
return 42 * 16;
if (viewportWidth >= 640)
return 34 * 16;
return Math.max(0, viewportWidth - 32);
}
private isOwnMessage(message: Message): boolean {
return message.senderId === this.currentUser()?.id;
}
@@ -507,4 +528,5 @@ export class ChatMessagesComponent {
this.attachmentsSvc.publishAttachments(messageId, pendingFiles, currentUserId || undefined);
}
}