Uh oh!
There was an error while loading. Please reload this page.
Migration/angular 21 - #19
Conversation
There was a problem hiding this comment.
Pull request overview
Migrates the project to Angular 21, updating the build/SSR pipeline and modernizing templates/styles to align with the latest Angular + Angular Material (M3) patterns.
Changes:
- Upgrade Angular dependencies/tooling (switch to
@angular/build, update TypeScript, adjust project configs). - Replace legacy Angular Universal Express engine with the new
@angular/ssrCommonEngineSSR setup. - Rework theming/styles toward Material 3 + CSS variables and update templates to the new control-flow syntax (
@if,@for).
Reviewed changes
Copilot reviewed 80 out of 84 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.server.json | Removed legacy server tsconfig. |
| tsconfig.json | Updated TS compiler options (ES2022, bundler resolution, interop). |
| tsconfig.app.json | Updated app tsconfig (added node types; includes SSR entrypoints). |
| src/theme-colors.scss | Added M3 palette definitions for brand colors. |
| src/test.ts | Simplified Angular test bootstrap file. |
| src/styles.scss | Replaced legacy theming with M3 theme config + CSS vars + MDC overrides. |
| src/main.ts | Updated bootstrap call/options for Angular 21. |
| src/main.server.ts | Updated server entry exports for new SSR bootstrap expectations. |
| src/litopia-base.scss | Refactored base styles to rely on CSS variables. |
| src/environments/environment.ts | Adjusted dev environment config defaults. |
| src/app/utils/themes-chooser.service.ts | Updated theme switching service imports/injection. |
| src/app/utils/picture-content-delivery/picture-content-delivery.component.ts | Formatting + Angular 21 metadata updates. |
| src/app/utils/picture-content-delivery/picture-content-delivery.component.html | Migrated structural directives to @for. |
| src/app/utils/appear.directive.ts | Formatting + Angular 21 metadata updates. |
| src/app/runtime-config.service.ts | Formatting adjustments (runtime config loading unchanged). |
| src/app/pages/reglement/reglement.component.ts | Formatting + Angular 21 metadata updates. |
| src/app/pages/profil/profil.component.ts | Adjusted markdown parsing flow and formatting. |
| src/app/pages/profil/profil.component.html | Migrated *ngIf to @if. |
| src/app/pages/nous-rejoindre/nous-rejoindre.component.ts | Formatting + Angular 21 metadata updates. |
| src/app/pages/nous-rejoindre/nous-rejoindre.component.html | Template formatting cleanup. |
| src/app/pages/nous-rejoindre-form/nous-rejoindre-form/nous-rejoindre-form.theme.component.scss | Moved theme styling to CSS variables. |
| src/app/pages/nous-rejoindre-form/nous-rejoindre-form/nous-rejoindre-form.component.ts | Added theme stylesheet + formatting/refactors. |
| src/app/pages/nous-rejoindre-form/nous-rejoindre-form/nous-rejoindre-form.component.scss | Updated MDC checkbox deep selectors + formatting. |
| src/app/pages/nous-rejoindre-form/nous-rejoindre-form/nous-rejoindre-form.component.html | Migrated to @if control flow. |
| src/app/pages/nous-rejoindre-form/nous-rejoindre-form.component.theme.scss | Moved theme styling to CSS variables. |
| src/app/pages/nous-rejoindre-form/nous-rejoindre-form-counsel/nous-rejoindre-form-counsel.component.ts | Formatting + Angular 21 metadata updates. |
| src/app/pages/nous-rejoindre-form/nous-rejoindre-form-counsel/nous-rejoindre-form-counsel.component.html | Template formatting cleanup. |
| src/app/pages/nous-rejoindre-form/nous-rejoindre-form-adhesion/nous-rejoindre-form-adhesion.component.ts | Added shared theme stylesheet + metadata updates. |
| src/app/pages/not-found/not-found.component.ts | Formatting + Angular 21 metadata updates. |
| src/app/pages/membres/profil-card/profil-card.theme.component.scss | Moved theme styling to CSS variables. |
| src/app/pages/membres/profil-card/profil-card.component.ts | Formatting + stylesheet array cleanup. |
| src/app/pages/membres/profil-card/profil-card.component.scss | Minor typography tweak. |
| src/app/pages/membres/membres.component.ts | Formatting + minor layout/state handling cleanup. |
| src/app/pages/membres/membres.component.scss | Layout tuning + added section title styles. |
| src/app/pages/membres/membres.component.html | Migrated loops to @for and adjusted header markup. |
| src/app/pages/archives/archives.component.ts | Added/updated archives data + formatting + metadata updates. |
| src/app/pages/archives/archives.component.theme.scss | Moved theme styling to CSS variables. |
| src/app/pages/archives/archives.component.scss | Updated MDC chips selectors + formatting. |
| src/app/pages/archives/archives.component.html | Migrated loops/conditionals to @for/@if. |
| src/app/pages/acceuil/timeline/timeline.theme.component.scss | Moved theme styling to CSS variables. |
| src/app/pages/acceuil/timeline/timeline.component.ts | Formatting + metadata updates. |
| src/app/pages/acceuil/timeline/timeline.component.scss | Typography/layout tweaks. |
| src/app/pages/acceuil/timeline/timeline.component.html | Migrated loop to @for. |
| src/app/pages/acceuil/timeline/timeline-item/timeline-item.component.ts | Formatting + metadata updates. |
| src/app/pages/acceuil/timeline/timeline-item/timeline-item.component.theme.scss | Moved theme styling to CSS variables. |
| src/app/pages/acceuil/timeline/timeline-item/timeline-item.component.html | Typography class updates + formatting. |
| src/app/pages/acceuil/season-presentations/season-presentations.component.ts | Formatting + metadata updates. |
| src/app/pages/acceuil/season-presentations/season-presentations.component.scss | Minor typography/layout tweaks. |
| src/app/pages/acceuil/season-presentations/season-presentations.component.html | Formatting + minor markup updates. |
| src/app/pages/acceuil/fullscreen-img-text/fullscreen-img-text.theme.component.scss | Moved theme styling to CSS variables. |
| src/app/pages/acceuil/fullscreen-img-text/fullscreen-img-text.component.ts | Added theme stylesheet + metadata updates. |
| src/app/pages/acceuil/fullscreen-img-text/fullscreen-img-text.component.html | Markup formatting updates. |
| src/app/pages/acceuil/acceuil.component.ts | Formatting + metadata updates. |
| src/app/pages/acceuil/a-propos/a-propos.component.ts | Formatting + metadata updates. |
| src/app/layout/page-header/page-header.component.ts | Formatting + metadata updates. |
| src/app/layout/page-header/page-header.component.html | Migrated conditional image rendering to @if. |
| src/app/layout/navbar/theme-chooser/theme-chooser.component.ts | Formatting + metadata updates. |
| src/app/layout/navbar/navbar.theme.component.scss | Moved theme styling to CSS variables. |
| src/app/layout/navbar/navbar.component.ts | Formatting + stylesheet array cleanup. |
| src/app/layout/navbar/navbar.component.html | Migrated conditionals to @if. |
| src/app/layout/footer/footers.component.theme.scss | Moved theme styling to CSS variables. |
| src/app/layout/footer/footer.component.ts | Formatting + metadata updates. |
| src/app/layout/footer/footer.component.scss | Responsive footer layout updates. |
| src/app/layout/footer/footer.component.html | Simplified layout markup and added responsive GitHub link variants. |
| src/app/auth/services/authentication.service.ts | SSR-safe initialization tweaks + formatting. |
| src/app/auth/auth-popup/auth-popup.component.ts | Formatting + metadata updates. |
| src/app/auth/auth-popup/auth-popup.component.scss | Added dialog checkbox spacing. |
| src/app/auth/auth-popup/auth-popup.component.html | Markup formatting cleanup. |
| src/app/app.server.module.ts | Removed FlexLayout server module. |
| src/app/app.module.ts | Switch to provideHttpClient(...), adjust SSR/app-id providers, remove FlexLayout module. |
| src/app/app.component.ts | Formatting + metadata updates. |
| src/app/apis/minecraft-api/minecraft-api.service.ts | Minor import formatting. |
| src/app/apis/litopia-api/api/users.service.ts | Import formatting change in generated client. |
| src/app/apis/litopia-api/api/minecraftUsers.service.ts | Import formatting change in generated client. |
| src/app/apis/litopia-api/api/default.service.ts | Import formatting change in generated client. |
| src/app/apis/litopia-api/api/candidatureProcess.service.ts | Import formatting change in generated client. |
| src/app/apis/litopia-api/api/auth.service.ts | Import formatting change in generated client. |
| server.ts | Migrated SSR server to @angular/ssrCommonEngine and ESM-style paths. |
| proxy.conf.json | Added /api proxy target. |
| package.json | Updated Angular dependencies + SSR scripts. |
| karma.conf.js | Updated Karma config (plugin/framework references changed). |
| angular.json | Migrated build/test/serve builders to @angular/build and configured SSR entry. |
| .browserslistrc | Removed browserslist config file. |
Comments suppressed due to low confidence (1)
server.ts:61
- The server is started unconditionally via
run();. This makes the module unsafe to import (e.g., serverless/SSR bundling/tests) and removes the previous "only run when main" guard. Consider restoring an ESM-safe entrypoint guard soapp()can be imported without side effects.
function run(): void {
const port = process.env['PORT'] || 4000;
// Start up the Node server
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
run();
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import {Inject, Injectable, PLATFORM_ID, Renderer2, RendererFactory2, DOCUMENT} from '@angular/core'; | ||
| import {BehaviorSubject} from "rxjs"; | ||
| import {OverlayContainer} from "@angular/cdk/overlay"; | ||
| import {DOCUMENT, isPlatformBrowser} from "@angular/common"; | ||
| import {isPlatformBrowser} from "@angular/common"; |
There was a problem hiding this comment.
DOCUMENT is imported from @angular/core, but the DOCUMENT injection token is provided by @angular/common. This will fail to compile and/or inject the wrong token. Import DOCUMENT from @angular/common (or switch the injection to @Inject('DOCUMENT') to match the string-token provider in AppModule).
| isAppear(title: string) { | ||
| this.appearSet.add(title) | ||
| this.appearSet.add(title); | ||
| } | ||
| appear(title: string) { | ||
| return this.appearSet.has(title) | ||
| return this.appearSet.has(title); | ||
| } |
There was a problem hiding this comment.
isAppear() and appear() are reversed: isAppear() should return whether the key has appeared (boolean), and appear() should record the key. As written, isAppear() returns void, which will break the [@...] animation bindings and the (appear) handler logic.
| '**', | ||
| express.static(browserDistFolder, { | ||
| maxAge: '1y', | ||
| index: 'index.html', |
There was a problem hiding this comment.
express.static(..., { index: 'index.html' }) on the catch-all route will serve index.html for /, which prevents SSR from running for most routes. For SSR, set index: false (and typically only serve *.* assets) so non-asset routes fall through to CommonEngine.render(...).
| '**', | |
| express.static(browserDistFolder,{ | |
| maxAge: '1y', | |
| index: 'index.html', | |
| '*.*', | |
| express.static(browserDistFolder,{ | |
| maxAge: '1y', | |
| index: false, |
| map((base64: string) => { | ||
| return { | ||
| backgroundImage: 'url(data:image/png;;base64,' + base64 + ')', | ||
| }; | ||
| }), |
There was a problem hiding this comment.
The generated data URL has an extra semicolon (data:image/png;;base64,). This is not a valid data URL in all browsers and can prevent the preview avatar from rendering. Use data:image/png;base64,.
| async onSubmit(){ | ||
| const user = this.authService.currentUserValue; | ||
| if (!user.logged){ | ||
| this.snackBar.open('Vous devez être connecté pour pouvoir candidater', 'Ok', {duration: 5000, panelClass: 'snackbar-error'}); | ||
| if (!user.logged) { | ||
| this.snackBar.open( | ||
| 'Vous devez être connecté pour pouvoir candidater', | ||
| 'Ok', | ||
| { duration: 5000, panelClass: 'snackbar-error' }, | ||
| ); | ||
| } | ||
| try { | ||
| await lastValueFrom( | ||
| this.candidatureProcess.candidatureProcessControllerPostCandidature({candidature: this.candidatureForm.value.candidature, minecraftUUID:this.uuid}) | ||
| this.candidatureProcess.candidatureProcessControllerPostCandidature({ | ||
| candidature: this.candidatureForm.value.candidature, | ||
| minecraftUUID: this.uuid, | ||
| }), |
There was a problem hiding this comment.
After showing the "Vous devez être connecté" snackbar, onSubmit() continues and still attempts to POST the candidature. This can generate unnecessary API calls and confusing errors; return early when the user is not logged in.
| <span>AGPL-3.0</span></a | ||
| > |
There was a problem hiding this comment.
There is malformed HTML around the license link: </a is followed by a stray > on the next line. This will render an extra > character and can break layout/DOM parsing. Remove the stray > and ensure the <a> tag is properly closed.
| <span>AGPL-3.0</span></a | |
| > | |
| <span>AGPL-3.0</span> | |
| </a> |
| > | ||
| <mat-icon svgIcon="github"></mat-icon> | ||
| <span> Github</span> | ||
| </a> |
There was a problem hiding this comment.
Display text should use the correct brand capitalization: change "Github" to "GitHub".
| <mat-checkbox [(ngModel)]="notDisplayAnymore">Ne plus afficher</mat-checkbox> | ||
| <p> | ||
| Lorsque vous vous connectez ou vous inscrivez à Litopia via discord,<br /> | ||
| le Litobot vous ferra automatiquement rejoindre notre serveur discord. |
There was a problem hiding this comment.
Typo in user-facing text: "vous ferra" should be "vous fera".
| le Litobot vous ferra automatiquement rejoindre notre serveur discord. | |
| le Litobot vous fera automatiquement rejoindre notre serveur discord. |
| >Ne plus afficher</mat-checkbox | ||
| > |
There was a problem hiding this comment.
There is a stray > after the closing </mat-checkbox> (it appears on its own line). This produces invalid HTML and may render an extra character. Remove the extra > and keep the checkbox element properly formatted.
| >Ne plus afficher</mat-checkbox | |
| > | |
| >Ne plus afficher</mat-checkbox> |
| basePath: '', | ||
| frameworks: ['jasmine', '@angular-devkit/build-angular'], | ||
| plugins: [ | ||
| require('karma-jasmine'), | ||
| require('karma-chrome-launcher'), | ||
| require('karma-jasmine-html-reporter'), | ||
| require('karma-coverage'), | ||
| require('@angular-devkit/build-angular/plugins/karma') | ||
| ], |
There was a problem hiding this comment.
Karma config still references @angular-devkit/build-angular in frameworks, but @angular-devkit/build-angular was removed from devDependencies and the project switched to @angular/build:karma. Update frameworks/plugins to the Angular 21 equivalents (and include the appropriate Angular Karma plugin) so npm test works.
mrsolarius
commented
Apr 7, 2026
@copilot apply changes based on the comments in this thread |
mrsolarius
commented
Apr 7, 2026
@copilot fix the pipeline to be compatible with angular 21 |
…ma config Agent-Logs-Url: https://github.com/LitopiaCommunity/LitopiaFront/sessions/2de4060f-872a-4970-9196-8b9bfacb17e1 Co-authored-by: mrsolarius <45536184+mrsolarius@users.noreply.github.com>
Applied all changes from the review in commit
|
- Deleted various compressed image files (AVIF, JPEG, WEBP) for 'litopia-s4-ville-asia', 'litopia-s5-coronacave', and 'litopia-s5-netherreactor' across multiple resolutions. - Updated index.html to change font links and added crossorigin attribute for preconnect. - Refactored styles.scss to remove font imports and streamline styles. - Added new tools for analyzing bundle stats and generating image variants using sharp.
…ponents - Updated the HTML structure in `a-propos.component.html` for better readability and maintainability. - Simplified button links in `fullscreen-img-text.component.html`, `season-presentations.component.html`, and `archives.component.html` by removing redundant href attributes. - Enhanced styling in `season-presentations.component.scss` for better responsiveness. - Adjusted layout in `archives.component.scss` to ensure full-width display of grid items. - Improved form structure and validation messages in `nous-rejoindre-form-adhesion.component.html` and `nous-rejoindre-form.component.html`. - Streamlined image generation script in `generate-images.mjs` to check for existing files before regeneration. - Updated `appear.directive.ts` to optimize visibility checks and improve performance. - Adjusted base styles in `litopia-base.scss` for consistent image alignment and sizing.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 82 out of 413 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private async renderCandidature(candidature: string) { | ||
| try { | ||
| const { marked } = await import('marked'); | ||
| this.descriptionField = await marked.parse(candidature); | ||
| } catch (_error) { | ||
| this.descriptionField = candidature; | ||
| } | ||
| } |
There was a problem hiding this comment.
marked.parse() returns HTML. If descriptionField is rendered via [innerHTML] (common for markdown), this introduces an XSS risk because user-provided candidature can inject arbitrary HTML/JS. Recommended fix: sanitize the generated HTML before binding (e.g., via DOMPurify), and/or configure the markdown pipeline to disable raw HTML rendering; avoid using bypassSecurityTrustHtml on untrusted content.
| @if (mcAccount.value.length == 0) { | ||
| <mat-hint align="end" | ||
| >Saisissez au moins 3 caractères</mat-hint | ||
| > | ||
| } | ||
| @if (mcAccount.value.length > 0 && mcAccount.value.length < 3) { | ||
| <mat-hint align="end" | ||
| >Plus que {{ 3 - mcAccount.value.length }}...</mat-hint | ||
| > | ||
| } | ||
| @if ( | ||
| mcAccount.value.length >= 3 && mcAccount.value.length <= 16 | ||
| ) { | ||
| <mat-hint align="end" | ||
| >{{ 16 - mcAccount.value.length }} caractères | ||
| restants</mat-hint | ||
| > | ||
| } | ||
| @if (mcAccount.value.length > 16) { | ||
| <mat-hint align="end" | ||
| >Trop long de | ||
| {{ mcAccount.value.length - 16 }} caractères</mat-hint |
There was a problem hiding this comment.
mcAccount.value can be null depending on the control state, which would throw at runtime when accessing .length. Make these checks null-safe (e.g., derive a mcLen = (mcAccount.value?.length ?? 0) and use that for all conditions/expressions).
| @if (mcAccount.value.length == 0) { | |
| <mat-hintalign="end" | |
| >Saisissez au moins 3 caractères</mat-hint | |
| > | |
| } | |
| @if (mcAccount.value.length > 0 && mcAccount.value.length <3){ | |
| <mat-hintalign="end" | |
| >Plus que {{ 3 - mcAccount.value.length }}...</mat-hint | |
| > | |
| } | |
| @if ( | |
| mcAccount.value.length >= 3 && mcAccount.value.length <= 16 | |
| ) { | |
| <mat-hintalign="end" | |
| >{{ 16 - mcAccount.value.length }} caractères | |
| restants</mat-hint | |
| > | |
| } | |
| @if (mcAccount.value.length > 16) { | |
| <mat-hintalign="end" | |
| >Trop long de | |
| {{ mcAccount.value.length - 16 }} caractères</mat-hint | |
| @if ((mcAccount.value?.length ?? 0) == 0) { | |
| <mat-hintalign="end" | |
| >Saisissez au moins 3 caractères</mat-hint | |
| > | |
| } | |
| @if ( | |
| (mcAccount.value?.length ?? 0) > 0 && | |
| (mcAccount.value?.length ?? 0) <3 | |
| ) { | |
| <mat-hintalign="end" | |
| >Plus que {{ 3 - (mcAccount.value?.length ?? 0) }}...</mat-hint | |
| > | |
| } | |
| @if ( | |
| (mcAccount.value?.length ?? 0) >= 3 && | |
| (mcAccount.value?.length ?? 0) <= 16 | |
| ) { | |
| <mat-hintalign="end" | |
| >{{ 16 - (mcAccount.value?.length ?? 0) }} caractères | |
| restants</mat-hint | |
| > | |
| } | |
| @if ((mcAccount.value?.length ?? 0) > 16) { | |
| <mat-hintalign="end" | |
| >Trop long de | |
| {{ (mcAccount.value?.length ?? 0) - 16 }} caractères</mat-hint |
| ); | ||
| return { takenUsername: true }; | ||
| } catch (e) { | ||
| console.log(e); |
There was a problem hiding this comment.
Logging raw errors to console.log inside a validator will spam the console in normal user flows (and may leak details in production). Prefer removing this log or using a structured logger gated by environment/debug mode.
| console.log(e); |
| const y = window.top!.outerHeight / 2 + window.top!.screenY - h / 2; | ||
| const x = window.top!.outerWidth / 2 + window.top!.screenX - w / 2; | ||
| return window.open( | ||
| url, | ||
| '', | ||
| `toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=${w}, height=${h}, top=${y}, left=${x}`, |
There was a problem hiding this comment.
This method uses the global window even though the service already injects a WINDOWS token (this.windows) for platform abstraction/mocking. Use this.windows here as well (and avoid non-null assertions on top) to keep the SSR/testability model consistent and prevent hard failures if window.top is unavailable (e.g., sandboxed iframes).
| consty=window.top!.outerHeight/2+window.top!.screenY-h/2; | |
| constx=window.top!.outerWidth/2+window.top!.screenX-w/2; | |
| returnwindow.open( | |
| url, | |
| '', | |
| `toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=${w}, height=${h}, top=${y}, left=${x}`, | |
| constparentWindow=this.windows?.top??this.windows; | |
| constouterHeight=parentWindow?.outerHeight??0; | |
| constouterWidth=parentWindow?.outerWidth??0; | |
| constscreenY=parentWindow?.screenY??0; | |
| constscreenX=parentWindow?.screenX??0; | |
| consty=outerHeight/2+screenY-h/2; | |
| constx=outerWidth/2+screenX-w/2; | |
| return( | |
| this.windows?.open( | |
| url, | |
| '', | |
| `toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=${w}, height=${h}, top=${y}, left=${x}`, | |
| )??null |
| </a> | ||
| </div> | ||
| } @else { | ||
| <h2>Tu as déjà rédigé ta canidature</h2> |
There was a problem hiding this comment.
Typo: 'canidature' should be 'candidature'.
| <h2>Tu as déjà rédigé ta canidature</h2> | |
| <h2>Tu as déjà rédigé ta candidature</h2> |
mrsolarius
commented
Apr 10, 2026
@copilot apply changes based on the comments in this thread |
Agent-Logs-Url: https://github.com/LitopiaCommunity/LitopiaFront/sessions/2a35a8bb-5bd0-49ab-be7f-392336f21494 Co-authored-by: mrsolarius <45536184+mrsolarius@users.noreply.github.com>
Fixed in commit
Applied all changes from that review thread in commit
|
Uh oh!
There was an error while loading. Please reload this page.
No description provided.