feat: feedback visuel immédiat après drag-and-drop + correction résolution IDs labels
- /api/move retourne maintenant les labels mis à jour - Le frontend met à jour les labels de la carte sans recharger la page - Flash vert sur la carte pour confirmer le succès du déplacement - Correction: résolution noms→IDs des labels via l'API Gitea (update_issue_labels attend des ints) - Mise à jour de data-column sur la carte déplacée
This commit is contained in:
+12
-4
@@ -139,6 +139,7 @@ async def move_card(
|
|||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
|
labels = []
|
||||||
if mapping:
|
if mapping:
|
||||||
try:
|
try:
|
||||||
if mapping["close_issue"]:
|
if mapping["close_issue"]:
|
||||||
@@ -147,13 +148,20 @@ async def move_card(
|
|||||||
issue = await gitea.get_issue(owner, repo, issue_id)
|
issue = await gitea.get_issue(owner, repo, issue_id)
|
||||||
current_labels = [lbl["name"] for lbl in issue.get("labels", [])]
|
current_labels = [lbl["name"] for lbl in issue.get("labels", [])]
|
||||||
status_labels = await _get_status_labels(owner, repo, board_id)
|
status_labels = await _get_status_labels(owner, repo, board_id)
|
||||||
filtered = [l for l in current_labels if l not in status_labels]
|
filtered_names = [l for l in current_labels if l not in status_labels]
|
||||||
filtered.append(mapping["gitea_label"])
|
filtered_names.append(mapping["gitea_label"])
|
||||||
await gitea.update_issue_labels(owner, repo, issue_id, filtered)
|
|
||||||
|
# Resolve label names to IDs
|
||||||
|
all_labels = await gitea.get_labels(owner, repo)
|
||||||
|
name_to_id = {lbl["name"]: lbl["id"] for lbl in all_labels}
|
||||||
|
label_ids = [name_to_id[n] for n in filtered_names if n in name_to_id]
|
||||||
|
|
||||||
|
result = await gitea.update_issue_labels(owner, repo, issue_id, label_ids)
|
||||||
|
labels = [{"name": lbl["name"], "color": lbl.get("color", "666")} for lbl in result]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("Gitea sync failed: %s", e)
|
logger.warning("Gitea sync failed: %s", e)
|
||||||
|
|
||||||
return {"status": "ok", "issue_id": issue_id, "column": column}
|
return {"status": "ok", "issue_id": issue_id, "column": column, "labels": labels}
|
||||||
|
|
||||||
|
|
||||||
async def _get_status_labels(owner: str, repo: str, board_id: int) -> list[str]:
|
async def _get_status_labels(owner: str, repo: str, board_id: int) -> list[str]:
|
||||||
|
|||||||
@@ -237,6 +237,25 @@
|
|||||||
method: 'POST', headers: {'X-CSRF-Token': getCSRFToken()}
|
method: 'POST', headers: {'X-CSRF-Token': getCSRFToken()}
|
||||||
});
|
});
|
||||||
if (!resp.ok) throw new Error('Move failed');
|
if (!resp.ok) throw new Error('Move failed');
|
||||||
|
const data = await resp.json();
|
||||||
|
|
||||||
|
// Update card's data-column
|
||||||
|
card.dataset.column = newCol;
|
||||||
|
|
||||||
|
// Update labels on the moved card
|
||||||
|
const labelsDiv = card.querySelector('.card-labels');
|
||||||
|
if (labelsDiv && data.labels) {
|
||||||
|
labelsDiv.innerHTML = data.labels.map(l =>
|
||||||
|
`<span class="card-label" style="background:#${l.color||'666'}33;color:#${l.color||'ccc'}">${escHtml(l.name)}</span>`
|
||||||
|
).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flash feedback
|
||||||
|
card.style.transition = 'box-shadow 0.3s';
|
||||||
|
card.style.boxShadow = '0 0 0 2px var(--green)';
|
||||||
|
setTimeout(() => { card.style.boxShadow = ''; }, 800);
|
||||||
|
|
||||||
|
// Update column counts
|
||||||
document.querySelectorAll('.board-column').forEach(col => {
|
document.querySelectorAll('.board-column').forEach(col => {
|
||||||
const c = col.querySelectorAll('.card').length;
|
const c = col.querySelectorAll('.card').length;
|
||||||
const b = col.querySelector('.column-count');
|
const b = col.querySelector('.column-count');
|
||||||
|
|||||||
Reference in New Issue
Block a user