# GitLab !51: Replace console.warn with LoggerService in calendar optimization Original: `nessar/vac-optimizer`; GitLab MergeRequest ID 107. Target: [#129](https://gitea.nessar.fr/nessar/vac-optimizer/pulls/129). Author: admin-backup (GitLab user 3). Created: 2025-11-17T23:30:03.000Z. Last source update: 2025-11-17T23:44:59.000Z. Source state: closed; discussion locked: False. This linked record preserves source attribution, timestamps, discussion grouping, review positions and historical diffs. Current Gitea activity is separate from the original source dates. Old CI jobs and their reports are omitted by owner decision. Source requested reviewers: admin-backup (GitLab user 3). ## Discussions and activity ### Discussion a4fb78ad4be9fe1e9c1a67166f68e1f321d22118 #### Source note 448 — admin-backup (GitLab user 3) — 2025-11-17T23:30:04Z system activity. ````text assigned to `@Copilot` ```` ### Discussion 2efc95f642a3469ee34cb562bed0ab669b8af9b9 #### Source note 449 — admin-backup (GitLab user 3) — 2025-11-17T23:30:04Z system activity. ````text assigned to `@THoguet` ```` ### Discussion ed6e35d3196950f4e8e02fb6c4f7697f615bcb94 #### Source note 452 — admin-backup (GitLab user 3) — 2025-11-17T23:30:06Z system activity. ````text mentioned in merge request !49 ```` ### Discussion 55acb92b18cd69e0bef3ed75a161fe45edbb05e5 #### Source note 450 — admin-backup (GitLab user 3) — 2025-11-17T23:42:25Z system activity. ````text changed title from **{-[WIP] WIP address feedback on loading spinner enhancement-}** to **{+Replace console.warn with LoggerService in calendar optimization+}** ```` ### Discussion 747791f2773213d3adcfdd156493fd139e69aad2 #### Source note 451 — admin-backup (GitLab user 3) — 2025-11-17T23:42:32Z system activity. ````text requested review from `@THoguet` ```` ## State event records - {"close_after_error_tracking_resolve": false, "close_auto_resolve_prometheus_alert": false, "created_at": "2025-11-17T23:44:59+00:00", "epic_id": null, "id": 224, "imported_from": 4, "issue_id": null, "merge_request_id": 107, "namespace_id": 38, "source_commit": null, "source_merge_request_id": null, "state": 2, "user_id": 3} ## Historical diff versions ### Diff version 106 — 2026-05-03T15:59:55.834478Z Base `54c2160f0dd293f8c1c78342e155a65d891041fd`; start `54c2160f0dd293f8c1c78342e155a65d891041fd`; head `95f927386dd28aee5510866a32356d0dd300ebb9`. Files: 4; stored commits: 2. #### `src/app/components/calendar-year/calendar-year.ts` → `None` Modes 100644 → 100644; new=False, deleted=False, renamed=False, binary=False, too_large=False. ````diff @@ -7,6 +7,7 @@ import { CommonModule } from '@angular/common'; import { MatProgressSpinner } from '@angular/material/progress-spinner'; import { CalendarSettingsService } from '../../services/calendar-settings-service'; import { DateCacheService } from '../../services/date-cache.service'; +import { LoggerService } from '../../services/logger.service'; @Component({ selector: 'app-calendar-year', @@ -19,6 +20,7 @@ export class CalendarYear { private userInput = inject(UserInputService); private calendarService = inject(CalendarService); private calendarSettingsService = inject(CalendarSettingsService); + private logger = inject(LoggerService); protected isLoading = signal(true); protected loadingProgress = signal(0); @@ -53,6 +55,7 @@ export class CalendarYear { (progress: number) => { this.loadingProgress.set(progress); }, + this.logger, ); // Update the remaining vacation days signal this.userInput.remainingVacationDaysSignal.set(remainingDays); ```` #### `src/app/services/calendar-service.ts` → `None` Modes 100644 → 100644; new=False, deleted=False, renamed=False, binary=False, too_large=False. ````diff @@ -6,6 +6,7 @@ import weekOfYear from 'dayjs/plugin/weekOfYear'; import isoWeek from 'dayjs/plugin/isoWeek'; import { CalendarSettingsService } from './calendar-settings-service'; import { DateCacheService } from './date-cache.service'; +import { LoggerService } from './logger.service'; dayjs.extend(weekOfYear); dayjs.extend(isoWeek); @@ -21,6 +22,7 @@ const allTypesOptions: HolidaysTypes.Options = { }) export class CalendarService { private dateCache = inject(DateCacheService); + private logger = inject(LoggerService); // Cache for holiday timestamps private holidayTimestampsCache: Set | null = null; @@ -541,6 +543,7 @@ export class SelectedDates implements SelectedDateInterface { calendarSettingsService: CalendarSettingsService, calendarService: CalendarService, progressCallback?: (progress: number) => void, + logger?: LoggerService, ): Promise { if (calendarSettingsService.get('samediMalin')()) this.samediMalin(vacationsNumber); @@ -600,8 +603,8 @@ export class SelectedDates implements SelectedDateInterface { // Inform user if not all days were placed const remainingDays = vacationsNumber.cp + vacationsNumber.rtt + vacationsNumber.other; - if (remainingDays > 0) { - console.warn( + if (remainingDays > 0 && logger) { + logger.warn( `Optimization stopped: ${remainingDays} of ${totalDays} vacation days remain unplaced. ` + `Too many days have equivalent placement quality - please place remaining days manually.`, ); ```` #### `src/app/services/logger.service.spec.ts` → `None` Modes 0 → 100644; new=True, deleted=False, renamed=False, binary=False, too_large=False. ````diff @@ -0,0 +1,52 @@ +import { TestBed } from '@angular/core/testing'; +import { LoggerService } from './logger.service'; + +describe('LoggerService', () => { + let service: LoggerService; + let consoleLogSpy: jasmine.Spy; + let consoleWarnSpy: jasmine.Spy; + let consoleErrorSpy: jasmine.Spy; + let consoleDebugSpy: jasmine.Spy; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(LoggerService); + + // Spy on console methods + consoleLogSpy = spyOn(console, 'log'); + consoleWarnSpy = spyOn(console, 'warn'); + consoleErrorSpy = spyOn(console, 'error'); + consoleDebugSpy = spyOn(console, 'debug'); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + it('should log messages', () => { + service.log('test message'); + expect(consoleLogSpy).toHaveBeenCalledWith('test message'); + }); + + it('should log warnings', () => { + service.warn('test warning'); + expect(consoleWarnSpy).toHaveBeenCalledWith('test warning'); + }); + + it('should log errors', () => { + service.error('test error'); + expect(consoleErrorSpy).toHaveBeenCalledWith('test error'); + }); + + it('should log debug messages', () => { + service.debug('test debug'); + expect(consoleDebugSpy).toHaveBeenCalledWith('test debug'); + }); + + it('should pass additional arguments to console methods', () => { + const arg1 = { key: 'value' }; + const arg2 = [1, 2, 3]; + service.log('test', arg1, arg2); + expect(consoleLogSpy).toHaveBeenCalledWith('test', arg1, arg2); + }); +}); ```` #### `src/app/services/logger.service.ts` → `None` Modes 0 → 100644; new=True, deleted=False, renamed=False, binary=False, too_large=False. ````diff @@ -0,0 +1,47 @@ +import { Injectable } from '@angular/core'; + +/** + * Logger service that wraps console methods. + * Can be configured to disable logging in production environments. + */ +@Injectable({ + providedIn: 'root', +}) +export class LoggerService { + private isProduction = false; // Can be configured based on environment + + /** + * Log an informational message + */ + log(message: string, ...args: unknown[]): void { + if (!this.isProduction) { + console.log(message, ...args); + } + } + + /** + * Log a warning message + */ + warn(message: string, ...args: unknown[]): void { + if (!this.isProduction) { + console.warn(message, ...args); + } + } + + /** + * Log an error message + */ + error(message: string, ...args: unknown[]): void { + // Always log errors, even in production + console.error(message, ...args); + } + + /** + * Log a debug message + */ + debug(message: string, ...args: unknown[]): void { + if (!this.isProduction) { + console.debug(message, ...args); + } + } +} ````