Correction affichage edition

Signed-off-by: Gato <cedric@goutailler-olivier.fr>
This commit is contained in:
2026-05-28 18:19:11 +02:00
parent e68232de21
commit 36cebe5144
4 changed files with 71 additions and 4 deletions
+17 -1
View File
@@ -138,6 +138,23 @@
}
/* Description */
.description-action-btn {
border: none;
background: none;
font-size: 0.75rem;
font-weight: 400;
text-transform: none;
letter-spacing: normal;
color: #6b7280;
cursor: pointer;
padding: 0;
}
.description-action-btn:hover {
color: #111827;
text-decoration: underline;
}
.description-textarea {
min-height: 40rem;
resize: vertical;
@@ -145,7 +162,6 @@
.description-preview {
min-height: 7rem;
white-space: pre-wrap;
font-size: 0.9rem;
color: #374151;
cursor: text;
+12 -3
View File
@@ -176,7 +176,12 @@
<!-- Description -->
<div class="card shadow-sm mb-3">
<div class="card-header section-header">Description</div>
<div class="card-header section-header d-flex align-items-center justify-content-between">
<span>Description</span>
@if (!editingDescription) {
<button type="button" class="description-action-btn" (click)="startEditDescription()">Modifier</button>
}
</div>
<div class="card-body">
@if (editingDescription) {
<textarea
@@ -184,13 +189,17 @@
class="form-control border-0 shadow-none p-0 description-textarea"
placeholder="Ajouter une description..."
[(ngModel)]="issue.description"
(blur)="editingDescription = false; saveIssue()"
(keydown.escape)="cancelEditDescription()"
(paste)="onDescriptionPaste($event)"
></textarea>
<div class="d-flex gap-2 mt-2">
<button type="button" class="btn btn-sm btn-primary" (click)="saveDescription()">Enregistrer</button>
<button type="button" class="btn btn-sm btn-outline-secondary" (click)="cancelEditDescription()">Annuler</button>
</div>
} @else {
<div
class="description-preview"
(click)="editingDescription = true"
(click)="startEditDescription()"
title="Cliquer pour éditer"
>
@if (issue.description) {
@@ -519,6 +519,32 @@ describe('IssueDetail — existing issue', () => {
});
});
describe('description edit flow', () => {
it('startEditDescription sets editingDescription to true and stores original text', () => {
(component as any).issue.description = 'original';
(component as any).startEditDescription();
expect((component as any).editingDescription).toBe(true);
expect((component as any)._descriptionBeforeEdit).toBe('original');
});
it('saveDescription exits edit mode and persists the description', async () => {
(component as any).issue.description = 'updated';
(component as any).editingDescription = true;
await (component as any).saveDescription();
expect((component as any).editingDescription).toBe(false);
expect(store.getById(1)?.description).toBe('updated');
});
it('cancelEditDescription restores the original description and exits edit mode', () => {
(component as any).issue.description = 'original';
(component as any).startEditDescription();
(component as any).issue.description = 'changed mid-edit';
(component as any).cancelEditDescription();
expect((component as any).issue.description).toBe('original');
expect((component as any).editingDescription).toBe(false);
});
});
describe('onDescriptionPaste', () => {
afterEach(() => vi.unstubAllGlobals());
@@ -58,6 +58,7 @@ export class IssueDetail {
protected showAddDependency = false;
protected selectedCandidateId: number | null = null;
protected editingDescription = false;
private _descriptionBeforeEdit = '';
protected showAddToEpic = false;
protected selectedEpicCandidateId: number | null = null;
protected showCreateInEpic = false;
@@ -237,6 +238,21 @@ export class IssueDetail {
return !!this.issue.epic;
}
protected startEditDescription(): void {
this._descriptionBeforeEdit = this.issue.description;
this.editingDescription = true;
}
protected async saveDescription(): Promise<void> {
this.editingDescription = false;
await this.saveIssue();
}
protected cancelEditDescription(): void {
this.issue.description = this._descriptionBeforeEdit;
this.editingDescription = false;
}
protected onDescriptionPaste(event: ClipboardEvent): void {
const ta = event.target as HTMLTextAreaElement;
const start = ta.selectionStart;