Migration Angular 20 -> 21 : fin de la migration securite (0 vulnerabilite npm)

- ng update @angular/core@21 @angular/cli@21 (corrige GHSA-jrmj-c5cx-3cw6, XSS SVG)
- Migration automatique des templates vers le control flow natif (@if/@for, 138 fichiers)
- Correction des 5 `track` invalides generes par la migration (trackBy a 1 argument
  -> track $index) + suppression des fonctions trackBy mortes
- TypeScript 5.9, zone.js 0.15 ; npm audit : 0 vulnerabilite

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 14:55:36 +02:00
parent 6acad41672
commit 23878f1c63
142 changed files with 7055 additions and 6292 deletions

View File

@@ -1,72 +1,83 @@
<div class="playthrough-page" *ngIf="playthrough">
<header class="page-header">
<button type="button" class="btn-secondary" (click)="back()">
<lucide-icon [img]="ArrowLeft" [size]="14"></lucide-icon>
Retour
</button>
<div class="header-info">
<h1>{{ playthrough.name }}</h1>
<p class="subtitle" *ngIf="playthrough.description">{{ playthrough.description }}</p>
</div>
<div class="header-actions">
<button type="button" class="btn-danger" (click)="delete()">
<lucide-icon [img]="Trash2" [size]="14"></lucide-icon>
Supprimer
@if (playthrough) {
<div class="playthrough-page">
<header class="page-header">
<button type="button" class="btn-secondary" (click)="back()">
<lucide-icon [img]="ArrowLeft" [size]="14"></lucide-icon>
Retour
</button>
</div>
</header>
<!-- Bloc action principal : démarrer ou reprendre la session -->
<section class="play-action">
<button type="button" class="btn-primary big"
*ngIf="!activeOnThis"
[disabled]="startingSession"
(click)="startSession()">
<lucide-icon [img]="Play" [size]="16"></lucide-icon>
Lancer une session
</button>
<button type="button" class="btn-primary big"
*ngIf="activeOnThis"
(click)="openSession(activeOnThis)">
<lucide-icon [img]="Play" [size]="16"></lucide-icon>
Reprendre la session en cours
</button>
<button type="button" class="btn-secondary" (click)="openFlags()">
<lucide-icon [img]="Flag" [size]="14"></lucide-icon>
Faits de la partie
</button>
</section>
<!-- PJ -->
<section class="block">
<div class="block-header">
<h2><lucide-icon [img]="Users" [size]="18"></lucide-icon> Personnages joueurs</h2>
<button type="button" class="btn-add" (click)="createCharacter()">
<lucide-icon [img]="Plus" [size]="14"></lucide-icon>
Nouveau PJ
<div class="header-info">
<h1>{{ playthrough.name }}</h1>
@if (playthrough.description) {
<p class="subtitle">{{ playthrough.description }}</p>
}
</div>
<div class="header-actions">
<button type="button" class="btn-danger" (click)="delete()">
<lucide-icon [img]="Trash2" [size]="14"></lucide-icon>
Supprimer
</button>
</div>
</header>
<!-- Bloc action principal : démarrer ou reprendre la session -->
<section class="play-action">
@if (!activeOnThis) {
<button type="button" class="btn-primary big"
[disabled]="startingSession"
(click)="startSession()">
<lucide-icon [img]="Play" [size]="16"></lucide-icon>
Lancer une session
</button>
}
@if (activeOnThis) {
<button type="button" class="btn-primary big"
(click)="openSession(activeOnThis)">
<lucide-icon [img]="Play" [size]="16"></lucide-icon>
Reprendre la session en cours
</button>
}
<button type="button" class="btn-secondary" (click)="openFlags()">
<lucide-icon [img]="Flag" [size]="14"></lucide-icon>
Faits de la partie
</button>
</div>
<p class="empty" *ngIf="characters.length === 0">Aucun PJ pour cette partie.</p>
<ul class="character-list" *ngIf="characters.length > 0">
<li *ngFor="let c of characters">
<a [routerLink]="['/campaigns', campaignId, 'playthroughs', playthroughId, 'characters', c.id]">{{ c.name }}</a>
</li>
</ul>
</section>
<!-- Sessions -->
<section class="block">
<h2>Sessions</h2>
<p class="empty" *ngIf="sessions.length === 0">Aucune session encore. Lancez la première !</p>
<ul class="session-list" *ngIf="sessions.length > 0">
<li *ngFor="let s of sessions" (click)="openSession(s)">
<span class="session-name">{{ s.name }}</span>
<span class="session-status" [class.active]="s.active">{{ s.active ? 'En cours' : 'Terminée' }}</span>
</li>
</ul>
</section>
</div>
</section>
<!-- PJ -->
<section class="block">
<div class="block-header">
<h2><lucide-icon [img]="Users" [size]="18"></lucide-icon> Personnages joueurs</h2>
<button type="button" class="btn-add" (click)="createCharacter()">
<lucide-icon [img]="Plus" [size]="14"></lucide-icon>
Nouveau PJ
</button>
</div>
@if (characters.length === 0) {
<p class="empty">Aucun PJ pour cette partie.</p>
}
@if (characters.length > 0) {
<ul class="character-list">
@for (c of characters; track c) {
<li>
<a [routerLink]="['/campaigns', campaignId, 'playthroughs', playthroughId, 'characters', c.id]">{{ c.name }}</a>
</li>
}
</ul>
}
</section>
<!-- Sessions -->
<section class="block">
<h2>Sessions</h2>
@if (sessions.length === 0) {
<p class="empty">Aucune session encore. Lancez la première !</p>
}
@if (sessions.length > 0) {
<ul class="session-list">
@for (s of sessions; track s) {
<li (click)="openSession(s)">
<span class="session-name">{{ s.name }}</span>
<span class="session-status" [class.active]="s.active">{{ s.active ? 'En cours' : 'Terminée' }}</span>
</li>
}
</ul>
}
</section>
</div>
}