Files
Bonsai-webapp/src/app/issues/issues.ts
T

100 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Component, inject } from '@angular/core';
import { Router } from '@angular/router';
import { IssueEntity, IssuesStore } from './issues.store';
@Component({
selector: 'app-issues',
imports: [],
templateUrl: './issues.html',
styleUrl: './issues.css',
})
export class Issues {
private readonly router = inject(Router);
private readonly issuesStore = inject(IssuesStore);
constructor() {
this.issuesStore.load();
}
protected readonly issues = this.issuesStore.issues;
protected selectedType: IssueEntity['type'] | null = null;
protected readonly typeOptions: IssueEntity['type'][] = [
'Epic', 'Bug', 'Study', 'Story', 'Task', 'Technical Story',
];
protected get filteredIssues(): IssueEntity[] {
if (this.selectedType === null) return this.issues();
return this.issues().filter((i) => i.type === this.selectedType);
}
protected selectType(type: IssueEntity['type'] | null): void {
this.selectedType = this.selectedType === type ? null : type;
}
protected createIssue(): void {
this.router.navigate(['/issues/new']);
}
protected openIssue(issueId: number): void {
this.router.navigate(['/issues', issueId]);
}
protected getProgress(issue: IssueEntity): number {
if (issue.type !== 'Epic') {
return issue.progress;
}
const children = this.issues().filter(
(i) => i.id !== issue.id && (i.epic === issue.name || i.dependsOnIds.includes(issue.id)),
);
if (children.length === 0) return 0;
const done = children.filter((i) => i.status === 'done').length;
return Math.round((done / children.length) * 100);
}
protected priorityDisplay(priority: IssueEntity['priority']): { symbol: string; color: string; label: string } {
const map: Record<IssueEntity['priority'], { symbol: string; color: string; label: string }> = {
'TRES_HAUTE': { symbol: '↑↑', color: '#dc3545', label: 'Très haute' },
'HAUTE': { symbol: '↑', color: '#fd7e14', label: 'Haute' },
'MOYENNE': { symbol: '', color: '#ffc107', label: 'Moyenne' },
'BASSE': { symbol: '↓', color: '#0d6efd', label: 'Basse' },
'TRES_FAIBLE':{ symbol: '↓↓', color: '#6c757d', label: 'Très faible'},
};
return map[priority] ?? { symbol: '?', color: '#6c757d', label: priority };
}
protected typeIcon(type: IssueEntity['type']): { letter: string; bg: string } {
const map: Record<IssueEntity['type'], { letter: string; bg: string }> = {
Epic: { letter: 'E', bg: '#7c3aed' },
Bug: { letter: 'B', bg: '#dc2626' },
Story: { letter: 'S', bg: '#16a34a' },
Task: { letter: 'T', bg: '#2563eb' },
Study: { letter: 'St', bg: '#6b7280' },
'Technical Story':{ letter: 'TS', bg: '#d97706' },
};
return map[type] ?? { letter: '?', bg: '#6b7280' };
}
protected typeBadgeClass(type: IssueEntity['type']): string {
const map: Record<IssueEntity['type'], string> = {
Bug: 'text-bg-danger',
Study: 'text-bg-secondary',
Story: 'text-bg-success',
Task: 'text-bg-primary',
'Technical Story': 'text-bg-warning',
Epic: 'text-bg-info',
};
return map[type] ?? 'text-bg-secondary';
}
protected statusBadge(status: IssueEntity['status']): { label: string; bg: string; color: string } {
const map: Record<IssueEntity['status'], { label: string; bg: string; color: string }> = {
draft: { label: 'BROUILLON', bg: '#e2e8f0', color: '#475569' },
todo: { label: 'À FAIRE', bg: '#dbeafe', color: '#1d4ed8' },
'in-progress': { label: 'EN COURS', bg: '#ffedd5', color: '#9a3412' },
done: { label: 'TERMINÉ', bg: '#dcfce7', color: '#166534' },
};
return map[status] ?? { label: status, bg: '#e2e8f0', color: '#475569' };
}
}