T hoguet/issue16 #139

Merged
admin-backup merged 7 commits from THoguet/issue16 into main 2025-11-30 03:17:57 +01:00
admin-backup commented 2025-11-29 19:11:40 +01:00 (Migrated from 172.24.0.1:8928)
admin-backup commented 2025-11-29 19:11:41 +01:00 (Migrated from 172.24.0.1:8928)

requested review from @Copilot

requested review from `@Copilot`
admin-backup commented 2025-11-29 19:15:14 +01:00 (Migrated from 172.24.0.1:8928)

The mat-select event handler is incorrect. The valueChange event emits the new value directly, not an event object. Change $event.value to just $event, or use the proper approach by updating the day object and emitting it. The current code will emit undefined.

		<mat-select (valueChange)="dayChange.emit($event)" [value]="day().type">
The mat-select event handler is incorrect. The `valueChange` event emits the new value directly, not an event object. Change `$event.value` to just `$event`, or use the proper approach by updating the day object and emitting it. The current code will emit `undefined`. ```suggestion:-0+0 <mat-select (valueChange)="dayChange.emit($event)" [value]="day().type"> ```
admin-backup commented 2025-11-29 19:15:15 +01:00 (Migrated from 172.24.0.1:8928)

Direct mutation of an input signal's value is not allowed and violates Angular's signal immutability principle. Instead, create a new object with the updated property. Replace lines 93-94 with: this.dayChange.emit({ ...this.day(), numberOfDays: value });

		this.dayChange.emit({ ...this.day(), numberOfDays: value });
Direct mutation of an input signal's value is not allowed and violates Angular's signal immutability principle. Instead, create a new object with the updated property. Replace lines 93-94 with: `this.dayChange.emit({ ...this.day(), numberOfDays: value });` ```suggestion:-0+0 this.dayChange.emit({ ...this.day(), numberOfDays: value }); ```
admin-backup commented 2025-11-29 19:15:15 +01:00 (Migrated from 172.24.0.1:8928)

Direct mutation of an input signal's value is not allowed and violates Angular's signal immutability principle. Instead, create a new object with the updated property. Replace lines 98-99 with: this.dayChange.emit({ ...this.day(), expiryDate: event.value! });

		this.dayChange.emit({ ...this.day(), expiryDate: event.value! });
	}
Direct mutation of an input signal's value is not allowed and violates Angular's signal immutability principle. Instead, create a new object with the updated property. Replace lines 98-99 with: `this.dayChange.emit({ ...this.day(), expiryDate: event.value! });` ```suggestion:-0+0 this.dayChange.emit({ ...this.day(), expiryDate: event.value! }); } ```
admin-backup commented 2025-11-29 19:15:15 +01:00 (Migrated from 172.24.0.1:8928)

Directly mutating the array returned from a signal violates signal immutability. Use the signal's update method instead: this.userInputService.vacationNumberSignal.update(days => [...days, this.userInputService.createVacationDay()]);

		this.userInputService.vacationNumberSignal.update(days => [...days, this.userInputService.createVacationDay()]);
Directly mutating the array returned from a signal violates signal immutability. Use the signal's `update` method instead: `this.userInputService.vacationNumberSignal.update(days => [...days, this.userInputService.createVacationDay()]);` ```suggestion:-0+0 this.userInputService.vacationNumberSignal.update(days => [...days, this.userInputService.createVacationDay()]); ```
admin-backup commented 2025-11-29 19:15:16 +01:00 (Migrated from 172.24.0.1:8928)

Using any type defeats TypeScript's type safety. The parameter type should match the actual data structure being used. Based on the code, this should be VacationsNumber (with properties cp, rtt, other), not the new VacDay[] type.

Using `any` type defeats TypeScript's type safety. The parameter type should match the actual data structure being used. Based on the code, this should be `VacationsNumber` (with properties cp, rtt, other), not the new `VacDay[]` type.
admin-backup commented 2025-11-29 19:15:16 +01:00 (Migrated from 172.24.0.1:8928)

Using any type defeats TypeScript's type safety. The parameter type should be VacationsNumber (with properties cp, rtt, other) to match how it's used throughout the method.

Using `any` type defeats TypeScript's type safety. The parameter type should be `VacationsNumber` (with properties cp, rtt, other) to match how it's used throughout the method.
admin-backup commented 2025-11-29 19:15:16 +01:00 (Migrated from 172.24.0.1:8928)

Directly mutating the array returned from a signal violates signal immutability. Use the signal's update method instead: this.userInputService.vacationNumberSignal.update(days => days.filter((_, i) => i !== index));

		this.userInputService.vacationNumberSignal.update(days => days.filter((_, i) => i !== index));
Directly mutating the array returned from a signal violates signal immutability. Use the signal's `update` method instead: `this.userInputService.vacationNumberSignal.update(days => days.filter((_, i) => i !== index));` ```suggestion:-0+0 this.userInputService.vacationNumberSignal.update(days => days.filter((_, i) => i !== index)); ```
admin-backup commented 2025-11-29 19:15:17 +01:00 (Migrated from 172.24.0.1:8928)

Type mismatch: vacationData is VacDay[] from the signal, but optimizeVacations expects an object with {cp: number, rtt: number, other: number} properties. The spread operator { ...vacationData } will create an object with numeric keys, not the expected structure. You need to transform the VacDay[] into the expected format before calling optimizeVacations, or update optimizeVacations to accept the new type.

Type mismatch: `vacationData` is `VacDay[]` from the signal, but `optimizeVacations` expects an object with `{cp: number, rtt: number, other: number}` properties. The spread operator `{ ...vacationData }` will create an object with numeric keys, not the expected structure. You need to transform the `VacDay[]` into the expected format before calling `optimizeVacations`, or update `optimizeVacations` to accept the new type.
admin-backup commented 2025-11-29 19:15:17 +01:00 (Migrated from 172.24.0.1:8928)

This test will fail because the component has a required input day that is not provided. You need to either provide the required input using fixture.componentRef.setInput('day', mockVacDay) before detectChanges(), or add provideAnimationsAsync() to the providers array since the component uses Material components that require animations.

This test will fail because the component has a required input `day` that is not provided. You need to either provide the required input using `fixture.componentRef.setInput('day', mockVacDay)` before `detectChanges()`, or add `provideAnimationsAsync()` to the providers array since the component uses Material components that require animations.
admin-backup commented 2025-11-29 19:15:17 +01:00 (Migrated from 172.24.0.1:8928)

Empty lifecycle hook. Since ngOnInit has no implementation, it should be removed along with the OnInit interface from the class declaration (line 35).

Empty lifecycle hook. Since `ngOnInit` has no implementation, it should be removed along with the `OnInit` interface from the class declaration (line 35).
admin-backup commented 2025-11-29 19:15:17 +01:00 (Migrated from 172.24.0.1:8928)

Unused import. ReactiveFormsModule is no longer used after removing the form-based implementation. This import should be removed from both the import statement and the component's imports array (line 23).

Unused import. `ReactiveFormsModule` is no longer used after removing the form-based implementation. This import should be removed from both the import statement and the component's imports array (line 23).
admin-backup commented 2025-11-29 19:15:17 +01:00 (Migrated from 172.24.0.1:8928)

Unused import and variable. The destroy$ Subject (line 38) is created and completed in ngOnDestroy, but it's never actually used (no .pipe(takeUntil(this.destroy$)) calls remain after form removal). Both the import and the destroy$ property can be removed, along with the OnDestroy interface and ngOnDestroy method.

Unused import and variable. The `destroy$` Subject (line 38) is created and completed in `ngOnDestroy`, but it's never actually used (no `.pipe(takeUntil(this.destroy$))` calls remain after form removal). Both the import and the `destroy$` property can be removed, along with the `OnDestroy` interface and `ngOnDestroy` method.
admin-backup commented 2025-11-29 19:15:18 +01:00 (Migrated from 172.24.0.1:8928)

Review: Commented

Pull request overview

This PR refactors the vacation management system from a simple count-based approach to a more structured day-tracking system with expiry dates, and upgrades Angular from v20 to v21. Key changes include:

  • Migration from VacationsNumber (simple object with cp/rtt/other counts) to VacDay[] (array of vacation day objects with IDs, types, counts, and expiry dates)
  • Addition of async progress tracking for vacation optimization
  • New DayInput component for managing individual vacation day entries
  • Angular version upgrade to v21.0.1 with animations support

Reviewed changes

Copilot reviewed 16 out of 17 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
src/main.server.ts Adds zone change detection configuration for server-side rendering
src/app/services/user-input-service.ts Refactors service to use VacDay[] structure instead of VacationsNumber
src/app/services/calendar-service.ts Updates types, adds async optimization with progress tracking, and implements heuristic limit
src/app/components/userInput/day-input/* New component for managing individual vacation day inputs
src/app/components/user-input/* Refactored to use signal-based state with new VacDay structure
src/app/components/calendar-year/* Updated to handle async optimization and remaining days tracking
package.json Upgrades Angular from v20 to v21 and adds animations package
Comments suppressed due to low confidence (1)

src/app/components/user-input/user-input.spec.ts:40

  • These tests reference component.userInputForm which no longer exists after the refactoring. The component now uses daysOff signal instead of a form. These tests should be updated to test the new implementation: verify daysOff is defined, test addDay() and removeFromList() methods.
	it('should initialize form with values from service', () => {
		expect(component.userInputForm).toBeDefined();
		expect(component.userInputForm.get('CP')).toBeDefined();
		expect(component.userInputForm.get('RTT')).toBeDefined();
		expect(component.userInputForm.get('Others')).toBeDefined();
	});

	it('should have valid form controls', () => {
		const cpControl = component.userInputForm.get('CP');
		const rttControl = component.userInputForm.get('RTT');
		const othersControl = component.userInputForm.get('Others');

		expect(cpControl).toBeTruthy();
		expect(rttControl).toBeTruthy();
		expect(othersControl).toBeTruthy();
	});
**Review:** Commented ## Pull request overview This PR refactors the vacation management system from a simple count-based approach to a more structured day-tracking system with expiry dates, and upgrades Angular from v20 to v21. Key changes include: - Migration from `VacationsNumber` (simple object with cp/rtt/other counts) to `VacDay[]` (array of vacation day objects with IDs, types, counts, and expiry dates) - Addition of async progress tracking for vacation optimization - New `DayInput` component for managing individual vacation day entries - Angular version upgrade to v21.0.1 with animations support ### Reviewed changes Copilot reviewed 16 out of 17 changed files in this pull request and generated 12 comments. <details> <summary>Show a summary per file</summary> | File | Description | | ---- | ----------- | | src/main.server.ts | Adds zone change detection configuration for server-side rendering | | src/app/services/user-input-service.ts | Refactors service to use VacDay[] structure instead of VacationsNumber | | src/app/services/calendar-service.ts | Updates types, adds async optimization with progress tracking, and implements heuristic limit | | src/app/components/userInput/day-input/* | New component for managing individual vacation day inputs | | src/app/components/user-input/* | Refactored to use signal-based state with new VacDay structure | | src/app/components/calendar-year/* | Updated to handle async optimization and remaining days tracking | | package.json | Upgrades Angular from v20 to v21 and adds animations package | </details> <details> <summary>Comments suppressed due to low confidence (1)</summary> **src/app/components/user-input/user-input.spec.ts:40** * These tests reference `component.userInputForm` which no longer exists after the refactoring. The component now uses `daysOff` signal instead of a form. These tests should be updated to test the new implementation: verify `daysOff` is defined, test `addDay()` and `removeFromList()` methods. ``` it('should initialize form with values from service', () => { expect(component.userInputForm).toBeDefined(); expect(component.userInputForm.get('CP')).toBeDefined(); expect(component.userInputForm.get('RTT')).toBeDefined(); expect(component.userInputForm.get('Others')).toBeDefined(); }); it('should have valid form controls', () => { const cpControl = component.userInputForm.get('CP'); const rttControl = component.userInputForm.get('RTT'); const othersControl = component.userInputForm.get('Others'); expect(cpControl).toBeTruthy(); expect(rttControl).toBeTruthy(); expect(othersControl).toBeTruthy(); }); ``` </details>
admin-backup commented 2025-11-29 21:09:52 +01:00 (Migrated from 172.24.0.1:8928)

requested review from @Copilot

requested review from `@Copilot`
admin-backup commented 2025-11-29 21:15:39 +01:00 (Migrated from 172.24.0.1:8928)

@copilot open a new pull request to apply changes based on the comments in this thread

`@copilot` open a new pull request to apply changes based on the comments in [this thread](https://gitlab.nessar.fr/Nessar/vac-optimizer/-/merge_requests/61#pullrequestreview-3520781340)
admin-backup commented 2025-11-29 21:15:46 +01:00 (Migrated from 172.24.0.1:8928)

mentioned in merge request !62

mentioned in merge request [!62](https://gitea.nessar.fr/nessar/vac-optimizer/pulls/140)
admin-backup commented 2025-11-29 21:15:47 +01:00 (Migrated from 172.24.0.1:8928)

@THoguet I've opened a new pull request, #62, to work on those changes. Once the pull request is ready, I'll request review from you.

`@THoguet` I've opened a new pull request, #62, to work on those changes. Once the pull request is ready, I'll request review from you.
admin-backup commented 2025-11-29 21:16:33 +01:00 (Migrated from 172.24.0.1:8928)

Input type should be "text" or "date", not "datetime". The "datetime" type is not a valid HTML input type. For date-only pickers (which this appears to be), use:

<input matInput [matDatepicker]="picker" [value]="day().expiryDate" (dateChange)="addEvent($event)" />
			type="text"
Input type should be "text" or "date", not "datetime". The "datetime" type is not a valid HTML input type. For date-only pickers (which this appears to be), use: ```html <input matInput [matDatepicker]="picker" [value]="day().expiryDate" (dateChange)="addEvent($event)" /> ``` ```suggestion:-0+0 type="text" ```
admin-backup commented 2025-11-29 21:16:34 +01:00 (Migrated from 172.24.0.1:8928)

Missing dayChange output binding from app-day-input. The DayInput component emits changes through the dayChange output, but this parent component doesn't listen to it. Without handling this event, changes made in the child component won't be properly synchronized. Add the binding:

<app-day-input 
  [day]="day" 
  (dayChange)="day = $event" 
  (deleteEntry)="removeFromList($index)">
</app-day-input>

However, note that with the current direct mutation pattern in the component, you may not need this if you address the signal mutation issues identified in other comments.

				<app-day-input [day]="day" (dayChange)="daysOff[$index] = $event" (deleteEntry)="removeFromList($index)"></app-day-input>
Missing `dayChange` output binding from `app-day-input`. The `DayInput` component emits changes through the `dayChange` output, but this parent component doesn't listen to it. Without handling this event, changes made in the child component won't be properly synchronized. Add the binding: ```html <app-day-input [day]="day" (dayChange)="day = $event" (deleteEntry)="removeFromList($index)"> </app-day-input> ``` However, note that with the current direct mutation pattern in the component, you may not need this if you address the signal mutation issues identified in other comments. ```suggestion:-0+0 <app-day-input [day]="day" (dayChange)="daysOff[$index] = $event" (deleteEntry)="removeFromList($index)"></app-day-input> ```
admin-backup commented 2025-11-29 21:16:34 +01:00 (Migrated from 172.24.0.1:8928)

Direct mutation of input signal object. Input signals return readonly values and should not be mutated directly. Instead, emit a new object with the updated value through dayChange output.

Consider this approach:

onInput(event: Event) {
  const value = Number((event.target as HTMLInputElement).value);
  this.dayChange.emit({ ...this.day(), numberOfDays: value });
}
		this.dayChange.emit({ ...this.day(), numberOfDays: value });
	}

	addEvent(event: MatDatepickerInputEvent<Date>) {
		this.dayChange.emit({ ...this.day(), expiryDate: event.value! });
Direct mutation of input signal object. Input signals return readonly values and should not be mutated directly. Instead, emit a new object with the updated value through `dayChange` output. Consider this approach: ```typescript onInput(event: Event) { const value = Number((event.target as HTMLInputElement).value); this.dayChange.emit({ ...this.day(), numberOfDays: value }); } ``` ```suggestion:-0+0 this.dayChange.emit({ ...this.day(), numberOfDays: value }); } addEvent(event: MatDatepickerInputEvent<Date>) { this.dayChange.emit({ ...this.day(), expiryDate: event.value! }); ```
admin-backup commented 2025-11-29 21:16:34 +01:00 (Migrated from 172.24.0.1:8928)

[nitpick] Commented-out code should be removed. If the mat-list-item wrapper was removed intentionally, the closing comment should be deleted as well.


[nitpick] Commented-out code should be removed. If the `mat-list-item` wrapper was removed intentionally, the closing comment should be deleted as well. ```suggestion:-0+0 ```
admin-backup commented 2025-11-29 21:16:34 +01:00 (Migrated from 172.24.0.1:8928)

Empty mat-option without value serves no clear purpose. If this is meant to be a "clear selection" option, it should have a descriptive label. If not needed, remove it:

<mat-select (valueChange)="..." [value]="day().type">
  @for (dayType of selectableDayTypes; track $index) {
    <mat-option [value]="dayType">{{ tooltipTypeMapping[dayType] }}</mat-option>
  }
</mat-select>

Empty `mat-option` without value serves no clear purpose. If this is meant to be a "clear selection" option, it should have a descriptive label. If not needed, remove it: ```html <mat-select (valueChange)="..." [value]="day().type"> @for (dayType of selectableDayTypes; track $index) { <mat-option [value]="dayType">{{ tooltipTypeMapping[dayType] }}</mat-option> } </mat-select> ``` ```suggestion:-0+0 ```
admin-backup commented 2025-11-29 21:16:35 +01:00 (Migrated from 172.24.0.1:8928)

Direct mutation of signal array. The code mutates this.daysOff which is the result of calling a signal (this.userInputService.vacationNumberSignal()), but this doesn't trigger signal updates. The mutation affects the underlying array but Angular's change detection won't be notified.

This issue is partially acknowledged in triggerComputation() (line 80), but the pattern of mutating and then manually triggering updates is error-prone. Consider using update() instead:

public addDay() {
  this.userInputService.vacationNumberSignal.update(days => [...days, this.userInputService.createVacationDay()]);
}
Direct mutation of signal array. The code mutates `this.daysOff` which is the result of calling a signal (`this.userInputService.vacationNumberSignal()`), but this doesn't trigger signal updates. The mutation affects the underlying array but Angular's change detection won't be notified. This issue is partially acknowledged in `triggerComputation()` (line 80), but the pattern of mutating and then manually triggering updates is error-prone. Consider using `update()` instead: ```typescript public addDay() { this.userInputService.vacationNumberSignal.update(days => [...days, this.userInputService.createVacationDay()]); } ```
admin-backup commented 2025-11-29 21:16:35 +01:00 (Migrated from 172.24.0.1:8928)

Empty ngOnInit() method serves no purpose and should be removed. If the OnInit lifecycle hook isn't needed, also remove OnInit from the implements clause and the import.

Empty `ngOnInit()` method serves no purpose and should be removed. If the `OnInit` lifecycle hook isn't needed, also remove `OnInit` from the implements clause and the import.
admin-backup commented 2025-11-29 21:16:35 +01:00 (Migrated from 172.24.0.1:8928)

[nitpick] Commented-out code should be removed. If the mat-list-item wrapper was removed intentionally, the comment should be deleted as well.

[nitpick] Commented-out code should be removed. If the `mat-list-item` wrapper was removed intentionally, the comment should be deleted as well.
admin-backup commented 2025-11-29 21:16:35 +01:00 (Migrated from 172.24.0.1:8928)

Type casting day.type as unknown as DayType indicates a design issue. Since SelectableDayType is a subset of DayType (with values CP, RTT, OTHER), the type system should handle this naturally. Consider redesigning the types to avoid unsafe casting, or if the relationship is valid, use a direct cast: day.type as DayType.

				const typeName = tooltipTypeMapping[day.type as DayType];
Type casting `day.type as unknown as DayType` indicates a design issue. Since `SelectableDayType` is a subset of `DayType` (with values CP, RTT, OTHER), the type system should handle this naturally. Consider redesigning the types to avoid unsafe casting, or if the relationship is valid, use a direct cast: `day.type as DayType`. ```suggestion:-0+0 const typeName = tooltipTypeMapping[day.type as DayType]; ```
admin-backup commented 2025-11-29 21:16:36 +01:00 (Migrated from 172.24.0.1:8928)

The destroy$ Subject is defined but never used since ngOnInit() no longer subscribes to observables. If not needed for cleanup, remove both destroy$ and the OnDestroy implementation.

The `destroy$` Subject is defined but never used since `ngOnInit()` no longer subscribes to observables. If not needed for cleanup, remove both `destroy$` and the `OnDestroy` implementation.
admin-backup commented 2025-11-29 21:16:36 +01:00 (Migrated from 172.24.0.1:8928)

Select dropdown for day type is missing an accessible label. Screen readers won't be able to describe this field to users. Add a <mat-label>:

<mat-form-field class="dayTypeInput">
  <mat-label>Type of leave</mat-label>
  <mat-select ...>
Select dropdown for day type is missing an accessible label. Screen readers won't be able to describe this field to users. Add a `<mat-label>`: ```html <mat-form-field class="dayTypeInput"> <mat-label>Type of leave</mat-label> <mat-select ...> ```
admin-backup commented 2025-11-29 21:16:36 +01:00 (Migrated from 172.24.0.1:8928)

::ng-deep is deprecated and should be avoided. It pierces component encapsulation and can cause unexpected styling issues. Consider using Angular's host context or moving this style to a global stylesheet if it needs to affect Material components. Alternatively, use ViewEncapsulation.None if you need to style child components, though this is also not recommended.

`::ng-deep` is deprecated and should be avoided. It pierces component encapsulation and can cause unexpected styling issues. Consider using Angular's host context or moving this style to a global stylesheet if it needs to affect Material components. Alternatively, use ViewEncapsulation.None if you need to style child components, though this is also not recommended.
admin-backup commented 2025-11-29 21:16:36 +01:00 (Migrated from 172.24.0.1:8928)

Unused import in component's imports array. ReactiveFormsModule should be removed from the imports array since reactive forms are no longer used in this component.


Unused import in component's imports array. `ReactiveFormsModule` should be removed from the imports array since reactive forms are no longer used in this component. ```suggestion:-0+0 ```
admin-backup commented 2025-11-29 21:16:36 +01:00 (Migrated from 172.24.0.1:8928)

Direct mutation of input signal object and non-null assertion without validation. Input signals should not be mutated directly, and event.value may be null for invalid dates.

Consider this approach:

addEvent(event: MatDatepickerInputEvent<Date>) {
  if (event.value) {
    this.dayChange.emit({ ...this.day(), expiryDate: event.value });
  }
}
		if (event.value) {
			this.dayChange.emit({ ...this.day(), expiryDate: event.value });
		}
Direct mutation of input signal object and non-null assertion without validation. Input signals should not be mutated directly, and `event.value` may be null for invalid dates. Consider this approach: ```typescript addEvent(event: MatDatepickerInputEvent<Date>) { if (event.value) { this.dayChange.emit({ ...this.day(), expiryDate: event.value }); } } ``` ```suggestion:-0+0 if (event.value) { this.dayChange.emit({ ...this.day(), expiryDate: event.value }); } ```
admin-backup commented 2025-11-29 21:16:37 +01:00 (Migrated from 172.24.0.1:8928)

Direct mutation of signal array. Similar to addDay(), this mutates the signal's underlying array without triggering updates. Use update() instead:

public removeFromList(index: number) {
  this.userInputService.vacationNumberSignal.update(days => days.filter((_, i) => i !== index));
}
		this.userInputService.vacationNumberSignal.update(days => days.filter((_, i) => i !== index));
Direct mutation of signal array. Similar to `addDay()`, this mutates the signal's underlying array without triggering updates. Use `update()` instead: ```typescript public removeFromList(index: number) { this.userInputService.vacationNumberSignal.update(days => days.filter((_, i) => i !== index)); } ``` ```suggestion:-0+0 this.userInputService.vacationNumberSignal.update(days => days.filter((_, i) => i !== index)); ```
admin-backup commented 2025-11-29 21:16:37 +01:00 (Migrated from 172.24.0.1:8928)

The test will fail because DayInput has a required input day that is not provided. The component requires a VacDay object to be passed as input.

Add the required input:

beforeEach(async () => {
  await TestBed.configureTestingModule({
    imports: [DayInput],
  }).compileComponents();

  fixture = TestBed.createComponent(DayInput);
  fixture.componentRef.setInput('day', {
    id: 'test-id',
    type: SelectableDayType.CP,
    numberOfDays: 5,
    expiryDate: new Date()
  });
  component = fixture.componentInstance;
  fixture.detectChanges();
});
The test will fail because `DayInput` has a required input `day` that is not provided. The component requires a `VacDay` object to be passed as input. Add the required input: ```typescript beforeEach(async () => { await TestBed.configureTestingModule({ imports: [DayInput], }).compileComponents(); fixture = TestBed.createComponent(DayInput); fixture.componentRef.setInput('day', { id: 'test-id', type: SelectableDayType.CP, numberOfDays: 5, expiryDate: new Date() }); component = fixture.componentInstance; fixture.detectChanges(); }); ```
admin-backup commented 2025-11-29 21:16:37 +01:00 (Migrated from 172.24.0.1:8928)

Missing test provider for animations. The DayInput component uses Material components that depend on animations. Add provideAnimationsAsync() to the test configuration to avoid console warnings and potential test failures:

import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';

await TestBed.configureTestingModule({
  imports: [DayInput],
  providers: [provideAnimationsAsync()],
}).compileComponents();
Missing test provider for animations. The `DayInput` component uses Material components that depend on animations. Add `provideAnimationsAsync()` to the test configuration to avoid console warnings and potential test failures: ```typescript import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; await TestBed.configureTestingModule({ imports: [DayInput], providers: [provideAnimationsAsync()], }).compileComponents(); ```
admin-backup commented 2025-11-29 21:16:37 +01:00 (Migrated from 172.24.0.1:8928)

Shallow copy doesn't deep copy the expiryDate Date objects. Since optimizeVacations() modifies numberOfDays on the vacation days objects, and those objects contain mutable Date objects, a shallow spread may not be sufficient if dates are mutated. While the current code appears to only mutate numberOfDays, the comment claims "deep copy" but provides shallow copy.

Consider using a proper deep copy or clarify the comment:

const vacationDaysCopy = vacationData.map((vd) => ({ 
  ...vd, 
  expiryDate: new Date(vd.expiryDate) 
}));
						const vacationDaysCopy = vacationData.map((vd) => ({
							...vd,
							expiryDate: vd.expiryDate ? new Date(vd.expiryDate) : vd.expiryDate,
						}));
Shallow copy doesn't deep copy the `expiryDate` Date objects. Since `optimizeVacations()` modifies `numberOfDays` on the vacation days objects, and those objects contain mutable `Date` objects, a shallow spread may not be sufficient if dates are mutated. While the current code appears to only mutate `numberOfDays`, the comment claims "deep copy" but provides shallow copy. Consider using a proper deep copy or clarify the comment: ```typescript const vacationDaysCopy = vacationData.map((vd) => ({ ...vd, expiryDate: new Date(vd.expiryDate) })); ``` ```suggestion:-0+0 const vacationDaysCopy = vacationData.map((vd) => ({ ...vd, expiryDate: vd.expiryDate ? new Date(vd.expiryDate) : vd.expiryDate, })); ```
admin-backup commented 2025-11-29 21:16:38 +01:00 (Migrated from 172.24.0.1:8928)

Missing tests for the component's key behaviors. The test suite only verifies component creation but doesn't test the onInput() and addEvent() methods, or the output events (dayChange, deleteEntry). Given the repository has comprehensive test coverage for other components and services, consider adding tests for:

  • Input changes emitting dayChange event
  • Date changes emitting dayChange event
  • Delete button emitting deleteEntry event
Missing tests for the component's key behaviors. The test suite only verifies component creation but doesn't test the `onInput()` and `addEvent()` methods, or the output events (`dayChange`, `deleteEntry`). Given the repository has comprehensive test coverage for other components and services, consider adding tests for: - Input changes emitting `dayChange` event - Date changes emitting `dayChange` event - Delete button emitting `deleteEntry` event
admin-backup commented 2025-11-29 21:16:38 +01:00 (Migrated from 172.24.0.1:8928)

The valueChange event emits only the selected value, not an object with a value property. Accessing $event.value will result in undefined. Also, emitting just the type value instead of updating the entire VacDay object doesn't align with how other changes are handled.

Use:

<mat-select (valueChange)="day().type = $event; dayChange.emit(day())" [value]="day().type">

Or better, follow the pattern of not mutating inputs:

<mat-select (valueChange)="dayChange.emit({ ...day(), type: $event })" [value]="day().type">
		<mat-select (valueChange)="dayChange.emit({ ...day(), type: $event })" [value]="day().type">
The `valueChange` event emits only the selected value, not an object with a `value` property. Accessing `$event.value` will result in `undefined`. Also, emitting just the type value instead of updating the entire `VacDay` object doesn't align with how other changes are handled. Use: ```html <mat-select (valueChange)="day().type = $event; dayChange.emit(day())" [value]="day().type"> ``` Or better, follow the pattern of not mutating inputs: ```html <mat-select (valueChange)="dayChange.emit({ ...day(), type: $event })" [value]="day().type"> ``` ```suggestion:-0+0 <mat-select (valueChange)="dayChange.emit({ ...day(), type: $event })" [value]="day().type"> ```
admin-backup commented 2025-11-29 21:16:38 +01:00 (Migrated from 172.24.0.1:8928)

No validation for negative or invalid number inputs. The HTML has min="0", but the Number() conversion can still produce negative values or NaN if the user enters invalid text. Consider adding validation:

onInput(event: Event) {
  const value = Number((event.target as HTMLInputElement).value);
  if (isNaN(value) || value < 0) return;
  this.dayChange.emit({ ...this.day(), numberOfDays: value });
}
		const value = Number((event.target as HTMLInputElement).value);
		if (isNaN(value) || value < 0) return;
No validation for negative or invalid number inputs. The HTML has `min="0"`, but the `Number()` conversion can still produce negative values or `NaN` if the user enters invalid text. Consider adding validation: ```typescript onInput(event: Event) { const value = Number((event.target as HTMLInputElement).value); if (isNaN(value) || value < 0) return; this.dayChange.emit({ ...this.day(), numberOfDays: value }); } ``` ```suggestion:-0+0 const value = Number((event.target as HTMLInputElement).value); if (isNaN(value) || value < 0) return; ```
admin-backup commented 2025-11-29 21:16:38 +01:00 (Migrated from 172.24.0.1:8928)

Type casting vacDay.type as unknown as DayType indicates a design issue. Since SelectableDayType enum values are defined as equal to DayType values (lines 207-211), a direct cast should work: vacDay.type as DayType. The double cast through unknown suggests the types aren't properly aligned.

		const vacType = vacDay.type as DayType;
Type casting `vacDay.type as unknown as DayType` indicates a design issue. Since `SelectableDayType` enum values are defined as equal to `DayType` values (lines 207-211), a direct cast should work: `vacDay.type as DayType`. The double cast through `unknown` suggests the types aren't properly aligned. ```suggestion:-0+0 const vacType = vacDay.type as DayType; ```
admin-backup commented 2025-11-29 21:16:39 +01:00 (Migrated from 172.24.0.1:8928)

Review: Commented

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated 22 comments.

**Review:** Commented ## Pull request overview Copilot reviewed 13 out of 14 changed files in this pull request and generated 22 comments.
admin-backup commented 2025-11-30 02:47:17 +01:00 (Migrated from 172.24.0.1:8928)

@copilot fix pipeline

`@copilot` fix pipeline
admin-backup commented 2025-11-30 02:47:25 +01:00 (Migrated from 172.24.0.1:8928)

mentioned in merge request !63

mentioned in merge request [!63](https://gitea.nessar.fr/nessar/vac-optimizer/pulls/141)
admin-backup commented 2025-11-30 02:47:27 +01:00 (Migrated from 172.24.0.1:8928)

@THoguet I've opened a new pull request, #63, to work on those changes. Once the pull request is ready, I'll request review from you.

`@THoguet` I've opened a new pull request, #63, to work on those changes. Once the pull request is ready, I'll request review from you.
admin-backup commented 2025-11-30 02:59:05 +01:00 (Migrated from 172.24.0.1:8928)

requested review from @Copilot

requested review from `@Copilot`
admin-backup commented 2025-11-30 03:06:25 +01:00 (Migrated from 172.24.0.1:8928)

@copilot fix unit test and linter

`@copilot` fix unit test and linter
admin-backup commented 2025-11-30 03:06:34 +01:00 (Migrated from 172.24.0.1:8928)

mentioned in merge request !64

mentioned in merge request [!64](https://gitea.nessar.fr/nessar/vac-optimizer/pulls/142)
admin-backup commented 2025-11-30 03:06:35 +01:00 (Migrated from 172.24.0.1:8928)

@THoguet I've opened a new pull request, #64, to work on those changes. Once the pull request is ready, I'll request review from you.

`@THoguet` I've opened a new pull request, #64, to work on those changes. Once the pull request is ready, I'll request review from you.
admin-backup commented 2025-11-30 03:07:11 +01:00 (Migrated from 172.24.0.1:8928)

The daysOff getter directly returns a signal instead of its value. This is inconsistent with Angular best practices for signals. Consider either making this a computed signal or calling the signal to return its value, e.g., return this.userInputService.vacationNumberSignal();

The `daysOff` getter directly returns a signal instead of its value. This is inconsistent with Angular best practices for signals. Consider either making this a computed signal or calling the signal to return its value, e.g., `return this.userInputService.vacationNumberSignal();`
admin-backup commented 2025-11-30 03:07:12 +01:00 (Migrated from 172.24.0.1:8928)

The clickable card uses (click)="addDay()" on a mat-card element instead of the button inside it. This creates a redundant click handler since the button inside already has keyboard accessibility. The card itself isn't keyboard-accessible unless additional attributes like tabindex="0" and (keydown.enter) or (keydown.space) are added. Consider moving the click handler to just the button, or add proper keyboard event handlers to the card.

The clickable card uses `(click)="addDay()"` on a `mat-card` element instead of the button inside it. This creates a redundant click handler since the button inside already has keyboard accessibility. The card itself isn't keyboard-accessible unless additional attributes like `tabindex="0"` and `(keydown.enter)` or `(keydown.space)` are added. Consider moving the click handler to just the button, or add proper keyboard event handlers to the card.
admin-backup commented 2025-11-30 03:07:12 +01:00 (Migrated from 172.24.0.1:8928)

The number input field lacks a label, making it inaccessible to screen reader users. Consider adding a mat-label inside the mat-form-field to describe what this input represents (e.g., "Number of days").

The number input field lacks a label, making it inaccessible to screen reader users. Consider adding a `mat-label` inside the `mat-form-field` to describe what this input represents (e.g., "Number of days").
admin-backup commented 2025-11-30 03:07:12 +01:00 (Migrated from 172.24.0.1:8928)

The non-null assertion operator ! is used on event.value, but there's no guarantee that event.value is non-null. If the user clears the date field, event.value could be null, causing a runtime error. Consider handling the null case explicitly, e.g., by not emitting if the value is null, or using a default date.

		if (event.value !== null) {
			this.dayChange.emit({ ...this.day(), expiryDate: event.value });
		}
The non-null assertion operator `!` is used on `event.value`, but there's no guarantee that `event.value` is non-null. If the user clears the date field, `event.value` could be `null`, causing a runtime error. Consider handling the null case explicitly, e.g., by not emitting if the value is null, or using a default date. ```suggestion:-0+0 if (event.value !== null) { this.dayChange.emit({ ...this.day(), expiryDate: event.value }); } ```
admin-backup commented 2025-11-30 03:07:12 +01:00 (Migrated from 172.24.0.1:8928)

[nitpick] The explicit type annotation : UserInputService is redundant when using inject(), as TypeScript can infer the type. Consider simplifying to: private userInputService = inject(UserInputService);

	private userInputService = inject(UserInputService);
[nitpick] The explicit type annotation `: UserInputService` is redundant when using `inject()`, as TypeScript can infer the type. Consider simplifying to: `private userInputService = inject(UserInputService);` ```suggestion:-0+0 private userInputService = inject(UserInputService); ```
admin-backup commented 2025-11-30 03:07:13 +01:00 (Migrated from 172.24.0.1:8928)

This line has the same date calculation issue. The duplicated logic appears 4 times in this file (lines 19, 25, 31, and 41). Extract this into a helper method like private getExpiryDateOneYearFromNow(): Date to eliminate duplication.

This line has the same date calculation issue. The duplicated logic appears 4 times in this file (lines 19, 25, 31, and 41). Extract this into a helper method like `private getExpiryDateOneYearFromNow(): Date` to eliminate duplication.
admin-backup commented 2025-11-30 03:07:13 +01:00 (Migrated from 172.24.0.1:8928)

Commented-out code should be removed rather than left in the codebase. If this mat-list-item wrapper is no longer needed, delete it. If it might be needed in the future, rely on version control to retrieve it.

Commented-out code should be removed rather than left in the codebase. If this `mat-list-item` wrapper is no longer needed, delete it. If it might be needed in the future, rely on version control to retrieve it.
admin-backup commented 2025-11-30 03:07:13 +01:00 (Migrated from 172.24.0.1:8928)

Commented-out code should be removed. See comment on line 1.

Commented-out code should be removed. See comment on line 1.
admin-backup commented 2025-11-30 03:07:13 +01:00 (Migrated from 172.24.0.1:8928)

The type cast day.type as unknown as DayType is a code smell. Since SelectableDayType values are derived from DayType, this cast should be unnecessary. Consider refactoring the type relationship or using a type-safe mapping function.

				const typeName = isDayType(day.type)
					? tooltipTypeMapping[day.type]
					: 'Unknown';
The type cast `day.type as unknown as DayType` is a code smell. Since `SelectableDayType` values are derived from `DayType`, this cast should be unnecessary. Consider refactoring the type relationship or using a type-safe mapping function. ```suggestion:-0+0 const typeName = isDayType(day.type) ? tooltipTypeMapping[day.type] : 'Unknown'; ```
admin-backup commented 2025-11-30 03:07:14 +01:00 (Migrated from 172.24.0.1:8928)

The component has been significantly refactored with new methods (addDay, removeFromList, updateDay, triggerComputation) and computed signals, but the test file only adds provideAnimationsAsync(). Consider adding tests to verify the new functionality works correctly.

The component has been significantly refactored with new methods (`addDay`, `removeFromList`, `updateDay`, `triggerComputation`) and computed signals, but the test file only adds `provideAnimationsAsync()`. Consider adding tests to verify the new functionality works correctly.
admin-backup commented 2025-11-30 03:07:14 +01:00 (Migrated from 172.24.0.1:8928)

Using ::ng-deep is deprecated and discouraged in Angular. It's a workaround that pierces view encapsulation and can cause global style pollution. Consider using Angular Material's theming system or custom form field appearance options instead to hide the subscript wrapper.

/* To hide the subscript wrapper, add a custom class to your mat-form-field in the template, e.g. <mat-form-field class="no-subscript"> */
/* Then use the following selector: */
.no-subscript .mat-mdc-form-field-subscript-wrapper {
Using `::ng-deep` is deprecated and discouraged in Angular. It's a workaround that pierces view encapsulation and can cause global style pollution. Consider using Angular Material's theming system or custom form field appearance options instead to hide the subscript wrapper. ```suggestion:-0+0 /* To hide the subscript wrapper, add a custom class to your mat-form-field in the template, e.g. <mat-form-field class="no-subscript"> */ /* Then use the following selector: */ .no-subscript .mat-mdc-form-field-subscript-wrapper { ```
admin-backup commented 2025-11-30 03:07:14 +01:00 (Migrated from 172.24.0.1:8928)

The date calculation creates multiple new Date() objects unnecessarily. The expression new Date(new Date().setFullYear(...)) first creates a Date, mutates it with setFullYear (which returns a timestamp), then creates a new Date from that timestamp. This is convoluted. Use a clearer approach: const date = new Date(); date.setFullYear(date.getFullYear() + 1); return date; or simply new Date(Date.now() + 365 * 24 * 60 * 60 * 1000)

The date calculation creates multiple `new Date()` objects unnecessarily. The expression `new Date(new Date().setFullYear(...))` first creates a Date, mutates it with `setFullYear` (which returns a timestamp), then creates a new Date from that timestamp. This is convoluted. Use a clearer approach: `const date = new Date(); date.setFullYear(date.getFullYear() + 1); return date;` or simply `new Date(Date.now() + 365 * 24 * 60 * 60 * 1000)`
admin-backup commented 2025-11-30 03:07:15 +01:00 (Migrated from 172.24.0.1:8928)

This line has the same date calculation issue as the previous occurrences. See comments on lines 19, 25, and 31.

This line has the same date calculation issue as the previous occurrences. See comments on lines 19, 25, and 31.
admin-backup commented 2025-11-30 03:07:15 +01:00 (Migrated from 172.24.0.1:8928)

The test suite only includes a basic creation test. The component has several behavioral methods (onInput, onTypeChange, addEvent) that lack test coverage. Consider adding tests to verify:

  • onInput emits dayChange with updated numberOfDays
  • onTypeChange emits dayChange with updated type
  • addEvent emits dayChange with updated expiryDate
  • deleteEntry output works correctly
The test suite only includes a basic creation test. The component has several behavioral methods (`onInput`, `onTypeChange`, `addEvent`) that lack test coverage. Consider adding tests to verify: - `onInput` emits `dayChange` with updated `numberOfDays` - `onTypeChange` emits `dayChange` with updated `type` - `addEvent` emits `dayChange` with updated `expiryDate` - `deleteEntry` output works correctly
admin-backup commented 2025-11-30 03:07:15 +01:00 (Migrated from 172.24.0.1:8928)

On each iteration of the while loop, the code creates a copy of vacationDays, filters it, and sorts it. This is inefficient for large arrays. Consider moving the filtering and sorting outside the loop, or using a more efficient data structure like a priority queue to avoid repeated sorting.

On each iteration of the while loop, the code creates a copy of `vacationDays`, filters it, and sorts it. This is inefficient for large arrays. Consider moving the filtering and sorting outside the loop, or using a more efficient data structure like a priority queue to avoid repeated sorting.
admin-backup commented 2025-11-30 03:07:15 +01:00 (Migrated from 172.24.0.1:8928)

This line has the same date calculation issue as line 19. Consider extracting this logic into a helper method to avoid duplication and improve maintainability.

This line has the same date calculation issue as line 19. Consider extracting this logic into a helper method to avoid duplication and improve maintainability.
admin-backup commented 2025-11-30 03:07:16 +01:00 (Migrated from 172.24.0.1:8928)

Adding --legacy-peer-deps flag suggests there are peer dependency conflicts with Angular 21. While this may work, it bypasses npm's peer dependency validation which could hide compatibility issues. Consider documenting why this flag is necessary, or investigate resolving the underlying peer dependency conflicts.

Adding `--legacy-peer-deps` flag suggests there are peer dependency conflicts with Angular 21. While this may work, it bypasses npm's peer dependency validation which could hide compatibility issues. Consider documenting why this flag is necessary, or investigate resolving the underlying peer dependency conflicts.
admin-backup commented 2025-11-30 03:07:16 +01:00 (Migrated from 172.24.0.1:8928)

Review: Commented

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated 19 comments.

Comments suppressed due to low confidence (1)

src/app/services/calendar-service.ts:925

  • The lookForVacation method has been modified to filter candidate days based on the expiry date of the VacDay object. This new behavior lacks test coverage to ensure days after the expiry date are correctly excluded from consideration.
	lookForVacation(
		vacDay: VacDay,
		calendarService: CalendarService,
	): { apply: () => void; heuristic: number } {
		const daysOfYear = calendarService.monthsInAYearFromNow();
		const now = new Date();
		now.setHours(0, 0, 0, 0);
		const nowTime = now.getTime();
		const expiryTime = vacDay.expiryDate.getTime();

		// Preprocess: filter out past days, already selected days, and days after expiry date
		const candidateDays: Date[] = [];
		for (const month of daysOfYear) {
			for (const week of month) {
				for (const day of week) {
					if (day) {
						day.setHours(0, 0, 0, 0);
						const dayTime = day.getTime();
						if (dayTime >= nowTime && dayTime <= expiryTime && !this.isSelected(day)) {
							candidateDays.push(day);
						}
					}
				}
			}
		}

		// Early exit if no candidates
		if (candidateDays.length === 0) {
			return { apply: () => {}, heuristic: SelectedDates.NO_VALID_STRATEGY_HEURISTIC };
		}

		const vacType = vacDay.type as unknown as DayType;
		const tempDatesBackup = [...this._datesSelected];
		let bestStrategy: { apply: () => void; heuristic: number; value: Date } | null = null;
		let bestHeuristic = -Infinity;
		let daysWithBestHeuristic = 0;

		// Evaluate each candidate day
		for (const day of candidateDays) {
			// Reset to backup state
			this._datesSelected = [...tempDatesBackup];
			this.datesSelected = this._datesSelected.slice();
			this.grouping();

			// Mark this day as vacation (reuse the day object since it's already normalized)
			this.datesSelected.push(new SelectedDate(vacType, new DateRange<Date>(day, day)));

			const heuristic = this.computeHeuristics();

			// Track only if better than current best
			if (heuristic > bestHeuristic) {
				bestHeuristic = heuristic;
				daysWithBestHeuristic = 1;
				const capturedDay = day;
				bestStrategy = {
					apply: () => {
						this._datesSelected = [...tempDatesBackup];
						this.push(
							new SelectedDate(
								vacType,
								new DateRange<Date>(capturedDay, capturedDay),
							),
						);
					},
					heuristic: heuristic,
					value: capturedDay,
				};
			} else if (heuristic === bestHeuristic) {
				daysWithBestHeuristic++;
			}
		}

		// Check if too many days have the same best heuristic after evaluating all days
		if (daysWithBestHeuristic > SelectedDates.MAX_DAYS_WITH_SAME_HEURISTIC) {
			// Restore backup before stopping
			this._datesSelected = [...tempDatesBackup];
			this.datesSelected = this._datesSelected.slice();
			this.grouping();

			// Stop optimization - let user decide manually
			return {
				apply: () => {},
				heuristic: SelectedDates.NO_VALID_STRATEGY_HEURISTIC,
			};
		}

		// Restore backup before returning
		this._datesSelected = [...tempDatesBackup];
		this.datesSelected = this._datesSelected.slice();
		this.grouping();

		// Apply best strategy if found
		if (bestStrategy) {
			bestStrategy.apply();
			return bestStrategy;
		}

		return { apply: () => {}, heuristic: SelectedDates.NO_VALID_STRATEGY_HEURISTIC };
	}
**Review:** Commented ## Pull request overview Copilot reviewed 14 out of 15 changed files in this pull request and generated 19 comments. <details> <summary>Comments suppressed due to low confidence (1)</summary> **src/app/services/calendar-service.ts:925** * The `lookForVacation` method has been modified to filter candidate days based on the expiry date of the `VacDay` object. This new behavior lacks test coverage to ensure days after the expiry date are correctly excluded from consideration. ``` lookForVacation( vacDay: VacDay, calendarService: CalendarService, ): { apply: () => void; heuristic: number } { const daysOfYear = calendarService.monthsInAYearFromNow(); const now = new Date(); now.setHours(0, 0, 0, 0); const nowTime = now.getTime(); const expiryTime = vacDay.expiryDate.getTime(); // Preprocess: filter out past days, already selected days, and days after expiry date const candidateDays: Date[] = []; for (const month of daysOfYear) { for (const week of month) { for (const day of week) { if (day) { day.setHours(0, 0, 0, 0); const dayTime = day.getTime(); if (dayTime >= nowTime && dayTime <= expiryTime && !this.isSelected(day)) { candidateDays.push(day); } } } } } // Early exit if no candidates if (candidateDays.length === 0) { return { apply: () => {}, heuristic: SelectedDates.NO_VALID_STRATEGY_HEURISTIC }; } const vacType = vacDay.type as unknown as DayType; const tempDatesBackup = [...this._datesSelected]; let bestStrategy: { apply: () => void; heuristic: number; value: Date } | null = null; let bestHeuristic = -Infinity; let daysWithBestHeuristic = 0; // Evaluate each candidate day for (const day of candidateDays) { // Reset to backup state this._datesSelected = [...tempDatesBackup]; this.datesSelected = this._datesSelected.slice(); this.grouping(); // Mark this day as vacation (reuse the day object since it's already normalized) this.datesSelected.push(new SelectedDate(vacType, new DateRange<Date>(day, day))); const heuristic = this.computeHeuristics(); // Track only if better than current best if (heuristic > bestHeuristic) { bestHeuristic = heuristic; daysWithBestHeuristic = 1; const capturedDay = day; bestStrategy = { apply: () => { this._datesSelected = [...tempDatesBackup]; this.push( new SelectedDate( vacType, new DateRange<Date>(capturedDay, capturedDay), ), ); }, heuristic: heuristic, value: capturedDay, }; } else if (heuristic === bestHeuristic) { daysWithBestHeuristic++; } } // Check if too many days have the same best heuristic after evaluating all days if (daysWithBestHeuristic > SelectedDates.MAX_DAYS_WITH_SAME_HEURISTIC) { // Restore backup before stopping this._datesSelected = [...tempDatesBackup]; this.datesSelected = this._datesSelected.slice(); this.grouping(); // Stop optimization - let user decide manually return { apply: () => {}, heuristic: SelectedDates.NO_VALID_STRATEGY_HEURISTIC, }; } // Restore backup before returning this._datesSelected = [...tempDatesBackup]; this.datesSelected = this._datesSelected.slice(); this.grouping(); // Apply best strategy if found if (bestStrategy) { bestStrategy.apply(); return bestStrategy; } return { apply: () => {}, heuristic: SelectedDates.NO_VALID_STRATEGY_HEURISTIC }; } ``` </details>
admin-backup commented 2025-11-30 03:17:57 +01:00 (Migrated from 172.24.0.1:8928)

Merged by: THoguet at 2025-11-30 02:17:57 UTC

*Merged by: THoguet at 2025-11-30 02:17:57 UTC*
admin-backup (Migrated from 172.24.0.1:8928) closed this pull request 2025-11-30 03:17:57 +01:00
admin-backup (Migrated from 172.24.0.1:8928) merged commit into main 2025-11-30 03:17:57 +01:00

Preserved source assignment/reviewer metadata. Historical accounts stay inactive.

Source requested reviewers: admin-backup (GitLab user 3).

The linked history record retains original IDs and source dates. No historical identity was merged into nessar or granted new authentication permissions.

<!-- gitlab-to-gitea-assignment:35:MergeRequest:61 --> Preserved source assignment/reviewer metadata. Historical accounts stay inactive. Source requested reviewers: admin-backup (GitLab user 3). The linked history record retains original IDs and source dates. No historical identity was merged into nessar or granted new authentication permissions.

Preserved GitLab !61 history: source attribution, exact timestamps, discussion grouping and review positions. Historical diff snapshots: 1; visible source notes: 67.

gitlab-35-mergerequest-61.md (SHA-256 0ff43ee494c7c3e8fcc0b8dc244691ef9a8601103ead1aef0fa7b0098e04929d)

gitlab-35-mergerequest-61.json (SHA-256 8863c25530d8af4f0e797b36868d94d2eb73be01dd7e6c4e50437ed99ae346e4)

Old CI job execution and reports are omitted. Original source files and rollback backups remain protected.

<!-- gitlab-to-gitea-history:35:MergeRequest:61 --> Preserved GitLab !61 history: source attribution, exact timestamps, discussion grouping and review positions. Historical diff snapshots: 1; visible source notes: 67. [gitlab-35-mergerequest-61.md](https://gitea.nessar.fr/attachments/4c8f7a01-48cf-43e7-aad1-27ee73607237) (SHA-256 `0ff43ee494c7c3e8fcc0b8dc244691ef9a8601103ead1aef0fa7b0098e04929d`) [gitlab-35-mergerequest-61.json](https://gitea.nessar.fr/attachments/ba0f3b24-ea95-474a-9102-9e76c4c87fbc) (SHA-256 `8863c25530d8af4f0e797b36868d94d2eb73be01dd7e6c4e50437ed99ae346e4`) Old CI job execution and reports are omitted. Original source files and rollback backups remain protected.
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: nessar/vac-optimizer#139