diff --git a/.claude/rules/api-evolution.md b/.claude/rules/api-evolution.md new file mode 100644 index 0000000..a9e4cb0 --- /dev/null +++ b/.claude/rules/api-evolution.md @@ -0,0 +1,40 @@ +# Règles — Évolutions API + +## Détection +Si une demande ne peut pas être implémentée avec les endpoints API existants (endpoint manquant, champ absent, comportement insuffisant), ne pas contourner le problème côté frontend. + +## Action requise +Créer un fichier dans le dossier `api-issues/` à la racine du projet, nommé en kebab-case selon le besoin : + +``` +api-issues/nom-du-besoin.md +``` + +## Contenu du fichier +Le fichier doit décrire : +1. **Contexte** — quelle fonctionnalité frontend nécessite cette évolution +2. **Problème** — ce qui manque ou bloque dans l'API actuelle +3. **Besoin** — le ou les endpoints à créer / modifier, avec le corps de requête et la réponse attendus +4. **Priorité** — bloquant / important / nice-to-have + +## Exemple de fichier +```markdown +# Filtrage des issues par milestone + +## Contexte +La page Issues doit permettre de filtrer les issues déjà assignées à un milestone. + +## Problème +L'endpoint `GET /issues` ne retourne pas le champ `milestoneId` dans la réponse. + +## Besoin +Ajouter `milestoneId: number | null` dans le corps de réponse de `GET /issues` et `GET /issues/:id`. + +## Priorité +Important +``` + +## Comportement attendu +- Implémenter tout ce qui est possible avec l'API actuelle. +- Informer clairement que le fichier a été créé et son emplacement. +- Ne pas bloquer le reste de l'implémentation : simuler la donnée manquante si cela permet d'avancer. diff --git a/.claude/rules/tests.md b/.claude/rules/tests.md new file mode 100644 index 0000000..5e391ff --- /dev/null +++ b/.claude/rules/tests.md @@ -0,0 +1,20 @@ +# Règles — Tests + +## Couverture +- Tout nouveau fichier `.ts` doit avoir un fichier `.spec.ts` correspondant. +- Maintenir les seuils de couverture définis dans `vitest.config.ts` : lignes ≥ 90 %, fonctions ≥ 90 %, branches ≥ 80 %, statements ≥ 90 %. + +## Structure des tests +- Un `describe` par classe ou fonction testée. +- Un `it` par comportement précis ; le libellé décrit le résultat attendu, pas l'implémentation. +- Utiliser `beforeEach` pour le setup commun ; ne pas dupliquer la configuration entre les `it`. + +## Mocks +- Ne pas mocker les dépendances Angular internes (Router, ActivatedRoute) sauf si indispensable. +- Mocker les services HTTP (`*ApiService`) avec des réponses fixes via `vi.fn()`. +- Pour mocker un constructeur (ex. `FileReader`), utiliser `vi.stubGlobal` avec une `class`, pas une arrow function. +- Appeler `vi.unstubAllGlobals()` dans `afterEach` après chaque `vi.stubGlobal`. + +## Commandes +- Lancer tous les tests : `npx ng test --watch=false` +- Lancer un fichier précis : `npx ng test --watch=false --include="**/mon-fichier.spec.ts"` diff --git a/src/app/milestones/milestone-detail/milestone-detail.html b/src/app/milestones/milestone-detail/milestone-detail.html index e2a6ec7..1d701a4 100644 --- a/src/app/milestones/milestone-detail/milestone-detail.html +++ b/src/app/milestones/milestone-detail/milestone-detail.html @@ -172,7 +172,22 @@ }
- @if (showAddIssue) { + @if (showCreateIssue) { +
+ + + +
+ } @else if (showAddIssue) {
} @else { - +
+ + +
}
diff --git a/src/app/milestones/milestone-detail/milestone-detail.ts b/src/app/milestones/milestone-detail/milestone-detail.ts index b507f7f..a2e32c2 100644 --- a/src/app/milestones/milestone-detail/milestone-detail.ts +++ b/src/app/milestones/milestone-detail/milestone-detail.ts @@ -27,6 +27,8 @@ export class MilestoneDetail { protected editingDescription = false; protected showAddIssue = false; + protected showCreateIssue = false; + protected newIssueName = ''; protected issueSearchQuery = ''; protected showIssueSuggestions = false; protected moreMenuOpen = false; @@ -49,6 +51,8 @@ export class MilestoneDetail { this.milestone = { ...found }; this.editingDescription = false; this.showAddIssue = false; + this.showCreateIssue = false; + this.newIssueName = ''; } }); } @@ -100,10 +104,46 @@ export class MilestoneDetail { ).slice(0, 8); } + protected openCreateIssue(): void { + this.newIssueName = ''; + this.showCreateIssue = true; + this.showAddIssue = false; + } + + protected cancelCreateIssue(): void { + this.showCreateIssue = false; + this.newIssueName = ''; + } + + protected async confirmCreateIssue(): Promise { + const name = this.newIssueName.trim(); + if (!name) return; + const created = await this.issuesStore.upsert({ + id: 0, + type: 'Story', + assignee: '', + epic: '', + name, + dueDate: '', + description: '', + estimatedTime: null, + dependsOnIds: [], + comments: [], + priority: 'MOYENNE', + status: 'draft', + progress: 0, + }); + this.milestone.issueIds = [...this.milestone.issueIds, created.id]; + await this.saveMilestone(); + this.showCreateIssue = false; + this.newIssueName = ''; + } + protected openAddIssue(): void { this.issueSearchQuery = ''; this.showIssueSuggestions = false; this.showAddIssue = true; + this.showCreateIssue = false; } protected cancelAddIssue(): void {