cd93533b7c
Signed-off-by: Gato <cedric@goutailler-olivier.fr>
145 lines
6.4 KiB
HTML
145 lines
6.4 KiB
HTML
<!-- suppress HtmlUnknownAttribute -->
|
||
<div class="card shadow-sm mb-3">
|
||
<div class="card-header section-header">Commentaires</div>
|
||
<div class="card-body d-flex flex-column gap-3">
|
||
|
||
@for (comment of comments(); track comment.id) {
|
||
<div class="comment-item">
|
||
<div class="comment-meta">
|
||
<span class="comment-date">{{ formatDate(comment.createdAt) }}</span>
|
||
@if (comment.updatedAt) {
|
||
<span class="comment-edited">(modifié le {{ formatDate(comment.updatedAt) }})</span>
|
||
}
|
||
<div class="comment-actions">
|
||
<button type="button" class="comment-action-btn" (click)="startEditComment(comment)">Modifier</button>
|
||
<button type="button" class="comment-action-btn comment-action-delete" (click)="deleteComment(comment.id)">Supprimer</button>
|
||
</div>
|
||
</div>
|
||
|
||
@if (editingCommentId === comment.id) {
|
||
<textarea
|
||
aria-label="Modifier le commentaire"
|
||
class="form-control form-control-sm mt-2"
|
||
rows="3"
|
||
[(ngModel)]="editingCommentText"
|
||
(keydown.escape)="cancelEditComment()"
|
||
(paste)="onPaste($event, 'edit')"
|
||
></textarea>
|
||
<div class="d-flex gap-2 mt-2">
|
||
<button type="button" class="btn btn-sm btn-primary" (click)="saveEditComment()" [disabled]="!editingCommentText.trim()">Enregistrer</button>
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" (click)="cancelEditComment()">Annuler</button>
|
||
</div>
|
||
} @else {
|
||
<div class="comment-text markdown-body mt-1" [innerHTML]="parseMarkdown(comment.text)"></div>
|
||
|
||
<!-- Issues liées -->
|
||
@if (getLinkedIssues(comment).length > 0) {
|
||
<div class="linked-issues mt-2">
|
||
@for (linked of getLinkedIssues(comment); track linked.id) {
|
||
<div class="linked-issue-chip">
|
||
<span
|
||
class="linked-issue-type-icon"
|
||
[style.background]="typeIcon(linked.type).bg"
|
||
[title]="linked.type"
|
||
>{{ typeIcon(linked.type).letter }}</span>
|
||
<a [routerLink]="['/issues', linked.id]" class="linked-issue-name">{{ linked.name }}</a>
|
||
<span
|
||
class="linked-issue-status"
|
||
[style.background]="statusLabel(linked.status).bg"
|
||
[style.color]="statusLabel(linked.status).color"
|
||
>{{ statusLabel(linked.status).label }}</span>
|
||
<button
|
||
type="button"
|
||
class="linked-issue-unlink"
|
||
title="Délier"
|
||
(click)="unlinkIssueFromComment(comment.id, linked.id)"
|
||
>×</button>
|
||
</div>
|
||
}
|
||
</div>
|
||
}
|
||
|
||
<!-- Actions : créer tâche / lier issue -->
|
||
@if (creatingTaskForCommentId === comment.id) {
|
||
<div class="comment-task-form mt-2">
|
||
<input
|
||
type="text"
|
||
class="form-control form-control-sm"
|
||
placeholder="Nom de la tâche..."
|
||
[(ngModel)]="newTaskName"
|
||
(keydown.enter)="createTaskForComment(comment.id)"
|
||
(keydown.escape)="cancelCreateTask()"
|
||
autofocus
|
||
/>
|
||
<div class="d-flex gap-2 mt-1">
|
||
<button
|
||
type="button"
|
||
class="btn btn-sm btn-primary"
|
||
(click)="createTaskForComment(comment.id)"
|
||
[disabled]="!newTaskName.trim()"
|
||
>Créer</button>
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" (click)="cancelCreateTask()">Annuler</button>
|
||
</div>
|
||
</div>
|
||
} @else if (linkingIssueForCommentId === comment.id) {
|
||
<div class="comment-link-form mt-2">
|
||
<input
|
||
type="text"
|
||
class="form-control form-control-sm"
|
||
placeholder="Rechercher une issue..."
|
||
[(ngModel)]="issueSearchText"
|
||
(keydown.escape)="cancelLinkIssue()"
|
||
autofocus
|
||
/>
|
||
<div class="link-issue-list">
|
||
@for (candidate of filteredIssuesForLink(comment.id); track candidate.id) {
|
||
<button
|
||
type="button"
|
||
class="link-issue-option"
|
||
(click)="linkIssueToComment(comment.id, candidate.id)"
|
||
>
|
||
<span
|
||
class="linked-issue-type-icon"
|
||
[style.background]="typeIcon(candidate.type).bg"
|
||
>{{ typeIcon(candidate.type).letter }}</span>
|
||
<span class="link-issue-option-name">{{ candidate.name }}</span>
|
||
<span
|
||
class="linked-issue-status"
|
||
[style.background]="statusLabel(candidate.status).bg"
|
||
[style.color]="statusLabel(candidate.status).color"
|
||
>{{ statusLabel(candidate.status).label }}</span>
|
||
</button>
|
||
}
|
||
@if (filteredIssuesForLink(comment.id).length === 0) {
|
||
<span class="link-issue-empty">Aucune issue trouvée</span>
|
||
}
|
||
</div>
|
||
<button type="button" class="btn btn-sm btn-outline-secondary mt-1" (click)="cancelLinkIssue()">Annuler</button>
|
||
</div>
|
||
} @else {
|
||
<div class="comment-link-actions mt-2">
|
||
<button type="button" class="comment-link-btn" (click)="startCreateTask(comment.id)">+ Créer une tâche</button>
|
||
<button type="button" class="comment-link-btn" (click)="startLinkIssue(comment.id)">+ Lier une issue</button>
|
||
</div>
|
||
}
|
||
}
|
||
</div>
|
||
}
|
||
|
||
<div class="comment-new">
|
||
<textarea
|
||
aria-label="Nouveau commentaire"
|
||
class="form-control form-control-sm"
|
||
rows="3"
|
||
placeholder="Ajouter un commentaire... (Markdown supporté, coller une image avec Ctrl+V)"
|
||
[(ngModel)]="newCommentText"
|
||
(paste)="onPaste($event, 'new')"
|
||
></textarea>
|
||
<div class="d-flex justify-content-end mt-2">
|
||
<button type="button" class="btn btn-sm btn-primary" (click)="addComment()" [disabled]="!newCommentText.trim()">Ajouter</button>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|