diff --git a/src/app/issues/issue-detail/issue-detail.css b/src/app/issues/issue-detail/issue-detail.css
index e37f0c0..0171ee3 100644
--- a/src/app/issues/issue-detail/issue-detail.css
+++ b/src/app/issues/issue-detail/issue-detail.css
@@ -150,6 +150,78 @@
min-height: 8rem;
}
+.epic-issues-card {
+ margin-top: 1rem;
+ background-color: #ffffff;
+ border: 1px solid #e5e7eb;
+ border-radius: 0.75rem;
+ padding: 1rem;
+}
+
+.epic-issues-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 1rem;
+ margin-bottom: 1rem;
+}
+
+.epic-issues-header h2 {
+ margin: 0;
+ font-size: 1.1rem;
+}
+
+.epic-issues-header span {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 2rem;
+ padding: 0.2rem 0.5rem;
+ border-radius: 999px;
+ background: #dbeafe;
+ color: #1d4ed8;
+ font-weight: 700;
+}
+
+.epic-empty {
+ margin: 0;
+ color: #6b7280;
+}
+
+.epic-issues-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: grid;
+ gap: 0.75rem;
+}
+
+.epic-issue-item {
+ display: flex;
+ justify-content: space-between;
+ gap: 1rem;
+ padding: 0.85rem 1rem;
+ border: 1px solid #e5e7eb;
+ border-radius: 0.75rem;
+ background: #f9fafb;
+}
+
+.epic-issue-item strong,
+.epic-issue-item p {
+ display: block;
+}
+
+.epic-issue-item p {
+ margin: 0.25rem 0 0;
+ color: #6b7280;
+}
+
+.epic-issue-item span {
+ color: #374151;
+ font-weight: 600;
+ white-space: nowrap;
+}
+
.detail-card {
background-color: #ffffff;
border: 1px solid #e5e7eb;
diff --git a/src/app/issues/issue-detail/issue-detail.html b/src/app/issues/issue-detail/issue-detail.html
index 8a9ac6a..0566a1a 100644
--- a/src/app/issues/issue-detail/issue-detail.html
+++ b/src/app/issues/issue-detail/issue-detail.html
@@ -56,12 +56,19 @@
-
- | Epic |
-
-
- |
-
+ @if (!isEpicIssue) {
+
+ | Epic |
+
+
+ |
+
+ }
| Depend de |
@@ -118,4 +125,29 @@
+@if (isEpicIssue) {
+
+
+
+ @if (composedIssues.length === 0) {
+ Aucune issue ne compose encore cet Epic.
+ } @else {
+
+ @for (composedIssue of composedIssues; track composedIssue.id) {
+ -
+
+ #{{ composedIssue.id }} - {{ composedIssue.name || 'Sans nom' }}
+ {{ composedIssue.type }} · {{ composedIssue.status }}
+
+ {{ composedIssue.assignee || 'Non assigné' }}
+
+ }
+
+ }
+
+}
+
diff --git a/src/app/issues/issue-detail/issue-detail.ts b/src/app/issues/issue-detail/issue-detail.ts
index e274963..5e2faa9 100644
--- a/src/app/issues/issue-detail/issue-detail.ts
+++ b/src/app/issues/issue-detail/issue-detail.ts
@@ -27,6 +27,7 @@ export class IssueDetail {
];
protected readonly typeOptions: IssueEntity['type'][] = [
+ 'Epic',
'Bug',
'Study',
'Story',
@@ -59,6 +60,18 @@ export class IssueDetail {
this.issue.type = value;
}
+ protected get epicIssues(): IssueEntity[] {
+ return this.issues().filter((issue) => issue.type === 'Epic');
+ }
+
+ protected get composedIssues(): IssueEntity[] {
+ return this.issues().filter((issue) => issue.dependsOnIds.includes(this.issue.id));
+ }
+
+ protected get isEpicIssue(): boolean {
+ return this.issueTypeValue === 'Epic';
+ }
+
protected saveIssue(): void {
this.issuesStore.upsert(this.issue);
if (this.isNewIssueRoute) {
diff --git a/src/app/issues/issues.store.ts b/src/app/issues/issues.store.ts
index c7faf7d..0e3c32b 100644
--- a/src/app/issues/issues.store.ts
+++ b/src/app/issues/issues.store.ts
@@ -4,7 +4,7 @@ const ISSUES_STORAGE_KEY = 'bonsai.issues';
export type IssueStatus = 'draft' | 'todo' | 'done' | 'in-progress';
export type IssuePriority = 'Basse' | 'Moyenne' | 'Haute';
-export type IssueType = 'Bug' | 'Study' | 'Story' | 'Technical Story';
+export type IssueType = 'Epic' | 'Bug' | 'Study' | 'Story' | 'Technical Story';
export type IssueEntity = {
id: number;
|