78 lines
2.6 KiB
TypeScript
78 lines
2.6 KiB
TypeScript
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 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';
|
||
}
|
||
}
|