feat(branch): créer la branche depuis la carte (issue #3)

slugify + branch_name_for (issue-<n>-<slug>, reconnu par #1/#2);
client create_branch; POST /api/issues/{o}/{r}/{n}/branch (nom
libre validé, idempotent si existante); la carte passe en En
cours, journalisée source branch, étiquette synchronisée;
formulaire dans la section Code lié du panneau détail.
This commit is contained in:
Spark
2026-10-11 14:49:38 -04:00
parent 5b41c5ea74
commit 1932d11457
6 changed files with 316 additions and 9 deletions
+13
View File
@@ -1151,3 +1151,16 @@ footer {
.code-line { padding: 3px 0; font-size: 0.9rem; color: var(--text-2, #b6c2d2); }
.code-line a { color: var(--accent, #58a6ff); text-decoration: none; }
.code-line code { background: var(--surface-3, #1d2942); border-radius: 4px; padding: 0 5px; }
/* ── Branche depuis la carte (0.14.0, #3) ── */
.branch-input {
background: var(--surface-3, #1d2942); color: var(--text-1);
border: 1px solid var(--border, #22304a); border-radius: 6px;
padding: 3px 8px; font-family: monospace; font-size: 0.85rem;
}
/* ── Santé du flux (0.14.0, #9) ── */
.health-table { width: 100%; border-collapse: collapse; margin: 10px 0; }
.health-table th, .health-table td { text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border, #22304a); }
.health-slowest td { color: var(--warn, #e8a33d); font-weight: 600; }
.zombie-actions { display: flex; gap: 6px; flex-shrink: 0; }
+31 -3
View File
@@ -397,9 +397,37 @@ document.addEventListener('DOMContentLoaded', () => {
for (const c of (data.commits || []).slice(0, 8)) {
parts.push(`⑂ <a href="${c.html_url}" target="_blank" rel="noopener"><code>${c.sha}</code></a> ${c.message}${c.date ? ' · ' + c.date : ''}`);
}
box.innerHTML = parts.length
? '<h3 class="detail-comments-title">🧬 Code lié</h3>' + parts.map(p => `<div class="code-line">${p}</div>`).join('')
: '';
const hasBranch = (data.branches || []).length > 0;
if (!hasBranch && data.suggested_branch) {
parts.push(`🌿 <input id="branch-name" class="branch-input" value="${data.suggested_branch}" size="36" spellcheck="false"> <button type="button" class="btn-sm" id="branch-create">Créer la branche</button>`);
}
box.innerHTML = '<h3 class="detail-comments-title">🧬 Code lié</h3>' + (
parts.length
? parts.map(p => `<div class="code-line">${p}</div>`).join('')
: '<div class="code-line">Aucun élément lié pour l\'instant.</div>'
);
const createBtn = document.getElementById('branch-create');
if (createBtn) {
createBtn.addEventListener('click', async () => {
const name = (document.getElementById('branch-name') || {}).value || '';
const form = new FormData();
form.append('name', name);
form.append('csrf_token', csrfToken);
createBtn.disabled = true;
try {
const r2 = await fetch(`/api/issues/${owner}/${repo}/${number}/branch`, { method: 'POST', body: form });
const body = await r2.json().catch(() => ({}));
if (!r2.ok || !body.ok) throw new Error(body.error || ('HTTP ' + r2.status));
showToast(body.exists
? `🌿 La branche ${body.branch} existait déjà`
: `🌿 Branche ${body.branch} créée depuis ${body.from} — carte en « En cours »`);
loadCodeLinks(repoFull, number);
} catch (err) {
createBtn.disabled = false;
showToast('❌ Branche non créée : ' + err.message, true);
}
});
}
} catch (err) { /* le code est un bonus, jamais bloquant */ }
}