Refacto issue detail
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
@@ -16,14 +17,33 @@ export class IssueDetail {
|
||||
private readonly router = inject(Router);
|
||||
private readonly issuesStore = inject(IssuesStore);
|
||||
private readonly sanitizer = inject(DomSanitizer);
|
||||
private readonly isNewIssueRoute = this.route.snapshot.routeConfig?.path === 'issues/new';
|
||||
protected readonly isNewIssueRoute = this.route.snapshot.routeConfig?.path === 'issues/new';
|
||||
|
||||
protected issue: IssueEntity = this.buildIssue();
|
||||
protected readonly issues = this.issuesStore.issues;
|
||||
protected moreMenuOpen = false;
|
||||
|
||||
constructor() {
|
||||
this.route.paramMap.pipe(takeUntilDestroyed()).subscribe((params) => {
|
||||
const id = Number(params.get('id'));
|
||||
if (!id || isNaN(id)) return;
|
||||
const existingIssue = this.issuesStore.getById(id);
|
||||
if (existingIssue) {
|
||||
this.issue = { ...existingIssue };
|
||||
this.editingDescription = false;
|
||||
this.showAddDependency = false;
|
||||
this.showAddToEpic = false;
|
||||
this.showCreateInEpic = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
protected showAddDependency = false;
|
||||
protected selectedCandidateId: number | null = null;
|
||||
protected editingDescription = false;
|
||||
protected showAddToEpic = false;
|
||||
protected selectedEpicCandidateId: number | null = null;
|
||||
protected showCreateInEpic = false;
|
||||
protected newIssueName = '';
|
||||
|
||||
protected readonly statusOptions: IssueEntity['status'][] = [
|
||||
'draft',
|
||||
@@ -107,6 +127,66 @@ export class IssueDetail {
|
||||
);
|
||||
}
|
||||
|
||||
protected get epicCandidates(): IssueEntity[] {
|
||||
const composedIds = new Set(this.composedIssues.map((i) => i.id));
|
||||
return this.issues().filter(
|
||||
(issue) => issue.id !== this.issue.id && !composedIds.has(issue.id),
|
||||
);
|
||||
}
|
||||
|
||||
protected openCreateInEpic(): void {
|
||||
this.newIssueName = '';
|
||||
this.showCreateInEpic = true;
|
||||
this.showAddToEpic = false;
|
||||
}
|
||||
|
||||
protected cancelCreateInEpic(): void {
|
||||
this.showCreateInEpic = false;
|
||||
this.newIssueName = '';
|
||||
}
|
||||
|
||||
protected confirmCreateInEpic(): void {
|
||||
const name = this.newIssueName.trim();
|
||||
if (!name) return;
|
||||
this.issuesStore.upsert({
|
||||
id: this.issuesStore.getNextId(),
|
||||
type: 'Story',
|
||||
assignee: '',
|
||||
epic: this.issue.name,
|
||||
name,
|
||||
dueDate: '',
|
||||
description: '',
|
||||
estimatedTime: null,
|
||||
dependsOnIds: [],
|
||||
priority: 'Moyenne',
|
||||
status: 'draft',
|
||||
progress: 0,
|
||||
});
|
||||
this.showCreateInEpic = false;
|
||||
this.newIssueName = '';
|
||||
}
|
||||
|
||||
protected openAddToEpic(): void {
|
||||
this.selectedEpicCandidateId = null;
|
||||
this.showAddToEpic = true;
|
||||
}
|
||||
|
||||
protected cancelAddToEpic(): void {
|
||||
this.showAddToEpic = false;
|
||||
this.selectedEpicCandidateId = null;
|
||||
}
|
||||
|
||||
protected confirmAddToEpic(): void {
|
||||
if (this.selectedEpicCandidateId !== null) {
|
||||
const target = this.issues().find((i) => i.id === this.selectedEpicCandidateId);
|
||||
if (target) {
|
||||
this.issuesStore.upsert({ ...target, epic: this.issue.name });
|
||||
}
|
||||
}
|
||||
this.showAddToEpic = false;
|
||||
this.selectedEpicCandidateId = null;
|
||||
}
|
||||
|
||||
protected get isEpicIssue(): boolean {
|
||||
return this.issueTypeValue === 'Epic';
|
||||
}
|
||||
@@ -117,6 +197,10 @@ export class IssueDetail {
|
||||
}
|
||||
|
||||
protected get typeBadgeClass(): string {
|
||||
return this.getBadgeClass(this.issueTypeValue);
|
||||
}
|
||||
|
||||
protected getBadgeClass(type: IssueEntity['type']): string {
|
||||
const map: Record<IssueEntity['type'], string> = {
|
||||
Bug: 'text-bg-danger',
|
||||
Study: 'text-bg-secondary',
|
||||
@@ -125,16 +209,37 @@ export class IssueDetail {
|
||||
'Technical Story': 'text-bg-warning',
|
||||
Epic: 'text-bg-info',
|
||||
};
|
||||
return map[this.issueTypeValue] ?? 'text-bg-secondary';
|
||||
return map[type] ?? 'text-bg-secondary';
|
||||
}
|
||||
|
||||
protected saveIssue(): void {
|
||||
protected openComposedIssue(id: number): void {
|
||||
this.router.navigate(['/issues', id]);
|
||||
}
|
||||
|
||||
protected get epicIssueId(): number | null {
|
||||
const epic = this.epicIssues.find((e) => e.name === this.issue.epic);
|
||||
return epic?.id ?? null;
|
||||
}
|
||||
|
||||
protected navigateToEpic(): void {
|
||||
if (this.epicIssueId !== null) {
|
||||
this.router.navigate(['/issues', this.epicIssueId]);
|
||||
}
|
||||
}
|
||||
|
||||
protected saveIssue(explicit = false): void {
|
||||
if (this.isNewIssueRoute && !explicit) return;
|
||||
if (!this.issue.name.trim()) return;
|
||||
this.issuesStore.upsert(this.issue);
|
||||
if (this.isNewIssueRoute) {
|
||||
this.router.navigate(['/issues', this.issue.id]);
|
||||
}
|
||||
}
|
||||
|
||||
protected cancelCreation(): void {
|
||||
this.router.navigate(['/issues']);
|
||||
}
|
||||
|
||||
protected deleteIssue(): void {
|
||||
this.issuesStore.deleteById(this.issue.id);
|
||||
this.router.navigate(['/issues']);
|
||||
|
||||
Reference in New Issue
Block a user