Skip to content

Commit e2ed724

Browse files
committed
Update Cards
1 parent 43e9a12 commit e2ed724

File tree

3 files changed

+211
-20
lines changed

3 files changed

+211
-20
lines changed

src/github-api.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,83 @@ async function reopenGitHubIssue(issueNumber) {
240240
}
241241
}
242242

243+
// Update GitHub issue priority or category label
244+
async function updateGitHubIssueMetadata(issueNumber, type, newValue) {
245+
if (!window.GitHubAuth.githubAuth.isAuthenticated || !window.GitHubAuth.githubAuth.accessToken) {
246+
console.log('❌ Not authenticated with GitHub - cannot update issue metadata');
247+
return false;
248+
}
249+
250+
try {
251+
// First, get current issue to preserve existing labels
252+
const getResponse = await fetch(`${window.GitHubAuth.GITHUB_CONFIG.apiBaseUrl}/repos/${window.GitHubAuth.GITHUB_CONFIG.owner}/${window.GitHubAuth.GITHUB_CONFIG.repo}/issues/${issueNumber}?_t=${Date.now()}`, {
253+
headers: {
254+
'Accept': 'application/vnd.github.v3+json',
255+
'Authorization': `token ${window.GitHubAuth.githubAuth.accessToken}`
256+
}
257+
});
258+
259+
if (!getResponse.ok) {
260+
throw new Error(`Failed to fetch issue: ${getResponse.status}`);
261+
}
262+
263+
const issue = await getResponse.json();
264+
const currentLabels = issue.labels.map(label => label.name);
265+
266+
// Define label categories
267+
const priorityLabels = ['critical', 'high', 'medium', 'low'];
268+
const categoryLabels = ['frontend', 'backend', 'design', 'testing', 'database', 'setup', 'bug', 'enhancement', 'feature'];
269+
270+
let updatedLabels = [...currentLabels];
271+
272+
if (type === 'priority') {
273+
// Remove existing priority labels
274+
updatedLabels = updatedLabels.filter(label => !priorityLabels.includes(label.toLowerCase()));
275+
276+
// Add new priority label if not empty
277+
if (newValue && newValue.trim() !== '') {
278+
updatedLabels.push(newValue.toLowerCase());
279+
}
280+
} else if (type === 'category') {
281+
// Remove existing category labels
282+
updatedLabels = updatedLabels.filter(label => !categoryLabels.includes(label.toLowerCase()));
283+
284+
// Add new category label if not empty
285+
if (newValue && newValue.trim() !== '') {
286+
updatedLabels.push(newValue.toLowerCase());
287+
}
288+
}
289+
290+
// Update labels via API
291+
const updateResponse = await fetch(`${window.GitHubAuth.GITHUB_CONFIG.apiBaseUrl}/repos/${window.GitHubAuth.GITHUB_CONFIG.owner}/${window.GitHubAuth.GITHUB_CONFIG.repo}/issues/${issueNumber}/labels`, {
292+
method: 'PUT',
293+
headers: {
294+
'Accept': 'application/vnd.github.v3+json',
295+
'Authorization': `token ${window.GitHubAuth.githubAuth.accessToken}`,
296+
'Content-Type': 'application/json'
297+
},
298+
body: JSON.stringify({
299+
labels: updatedLabels
300+
})
301+
});
302+
303+
if (!updateResponse.ok) {
304+
const errorData = await updateResponse.json();
305+
throw new Error(`GitHub API error: ${updateResponse.status} - ${errorData.message || 'Unknown error'}`);
306+
}
307+
308+
console.log(`✅ Successfully updated GitHub issue #${issueNumber} ${type} to: "${newValue}"`);
309+
return true;
310+
311+
} catch (error) {
312+
console.error(`❌ Failed to update GitHub issue ${type}:`, error);
313+
314+
// Show user-friendly error message
315+
alert(`Failed to update GitHub issue ${type}: ${error.message}\n\nThe ${type} was updated on the board but not on GitHub.`);
316+
return false;
317+
}
318+
}
319+
243320
// Create GitHub issue via API
244321
async function createGitHubIssue(title, description, labels = []) {
245322
if (!window.GitHubAuth.githubAuth.isAuthenticated || !window.GitHubAuth.githubAuth.accessToken) {
@@ -421,6 +498,7 @@ window.GitHubAPI = {
421498
archiveGitHubIssue,
422499
updateGitHubIssueLabels,
423500
updateGitHubIssueTitle,
501+
updateGitHubIssueMetadata,
424502
closeGitHubIssue,
425503
reopenGitHubIssue,
426504
initializeGitHubIssues

src/issue-modal.js

Lines changed: 129 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ function setupIssueModalEventHandlers() {
217217
// Also update the title in the kanban card if it exists
218218
const taskElement = document.querySelector(`[data-issue-number="${issueNumber}"]`);
219219
if (taskElement) {
220-
const titleElement = taskElement.querySelector('.task-title');
220+
const titleElement = taskElement.querySelector('h4');
221221
if (titleElement) {
222222
titleElement.textContent = newTitle;
223223
}
@@ -264,21 +264,42 @@ function setupIssueModalEventHandlers() {
264264
}
265265

266266
if (saveDescBtn) {
267-
saveDescBtn.addEventListener('click', function() {
267+
saveDescBtn.addEventListener('click', async function() {
268268
const newDesc = document.getElementById('issue-description-edit').value;
269+
270+
// Get issue number from the modal
271+
const issueNumberElement = document.getElementById('issue-modal-number');
272+
const issueNumber = issueNumberElement.textContent.replace('#', '');
273+
269274
// Render markdown if available
275+
let renderedDesc;
270276
if (window.GitHubUI && window.GitHubUI.renderMarkdown) {
271-
document.getElementById('issue-description-display').innerHTML = window.GitHubUI.renderMarkdown(newDesc);
277+
renderedDesc = window.GitHubUI.renderMarkdown(newDesc);
278+
document.getElementById('issue-description-display').innerHTML = renderedDesc;
272279
} else {
280+
renderedDesc = newDesc;
273281
document.getElementById('issue-description-display').textContent = newDesc;
274282
}
275283

284+
// Also update the description in the kanban card if it exists
285+
const taskElement = document.querySelector(`[data-issue-number="${issueNumber}"]`);
286+
if (taskElement) {
287+
const descElement = taskElement.querySelector('.markdown-content');
288+
if (descElement) {
289+
descElement.innerHTML = renderedDesc;
290+
}
291+
}
292+
276293
document.getElementById('issue-description-display').classList.remove('hidden');
277294
document.getElementById('issue-description-edit').classList.add('hidden');
278295
document.getElementById('description-edit-actions').classList.add('hidden');
279296

280-
// TODO: Save to GitHub API
281-
console.log('Save description to GitHub API:', newDesc);
297+
// Update GitHub API
298+
if (window.GitHubAPI && window.GitHubAPI.updateGitHubIssueDescription) {
299+
await window.GitHubAPI.updateGitHubIssueDescription(issueNumber, newDesc);
300+
} else {
301+
console.log('GitHub API not available, description updated locally only');
302+
}
282303
});
283304
}
284305

@@ -298,41 +319,98 @@ function setupIssueModalEventHandlers() {
298319
prioritySelect.addEventListener('change', async function() {
299320
const newPriority = this.value;
300321
const issueNumberElement = document.getElementById('issue-modal-number');
322+
if (!issueNumberElement) return;
323+
301324
const issueNumber = issueNumberElement.textContent.replace('#', '');
302325

303326
// Update the kanban card priority if it exists
304327
const taskElement = document.querySelector(`[data-issue-number="${issueNumber}"]`);
305328
if (taskElement) {
306-
const priorityElement = taskElement.querySelector('.task-priority');
307-
if (priorityElement) {
308-
priorityElement.textContent = newPriority;
309-
priorityElement.style.display = newPriority ? 'inline' : 'none';
329+
// Find the current priority badge
330+
const labelContainer = taskElement.querySelector('.flex.items-center.space-x-2');
331+
if (labelContainer) {
332+
// Remove existing priority badge (look for known priority texts)
333+
const existingPriorityBadge = Array.from(labelContainer.querySelectorAll('span')).find(span => {
334+
const text = span.textContent.toLowerCase();
335+
return ['critical', 'high', 'medium', 'low'].includes(text);
336+
});
337+
338+
if (existingPriorityBadge) {
339+
existingPriorityBadge.remove();
340+
}
341+
342+
// Add new priority badge if priority is selected
343+
if (newPriority && window.getPriorityColor) {
344+
const priorityBadge = document.createElement('span');
345+
priorityBadge.className = `inline-flex items-center px-2 py-1 rounded-full text-xs font-medium ${window.getPriorityColor(newPriority)}`;
346+
priorityBadge.textContent = newPriority;
347+
348+
// Insert at the beginning of the label container
349+
labelContainer.insertBefore(priorityBadge, labelContainer.firstChild);
350+
}
310351
}
311352
}
312353

313-
// TODO: Save to GitHub API
314-
console.log('Update priority to GitHub API:', newPriority);
354+
// Update GitHub issue labels
355+
if (window.GitHubAPI && window.GitHubAPI.updateGitHubIssueMetadata) {
356+
await window.GitHubAPI.updateGitHubIssueMetadata(issueNumber, 'priority', newPriority);
357+
} else {
358+
console.log('GitHub API not available, priority updated locally only');
359+
}
315360
});
316361
}
317362

318363
if (categorySelect) {
319364
categorySelect.addEventListener('change', async function() {
320365
const newCategory = this.value;
321366
const issueNumberElement = document.getElementById('issue-modal-number');
367+
if (!issueNumberElement) return;
368+
322369
const issueNumber = issueNumberElement.textContent.replace('#', '');
323370

324371
// Update the kanban card category if it exists
325372
const taskElement = document.querySelector(`[data-issue-number="${issueNumber}"]`);
326373
if (taskElement) {
327-
const categoryElement = taskElement.querySelector('.task-category');
328-
if (categoryElement) {
329-
categoryElement.textContent = newCategory;
330-
categoryElement.style.display = newCategory ? 'inline' : 'none';
374+
// Find the current category badge
375+
const labelContainer = taskElement.querySelector('.flex.items-center.space-x-2');
376+
if (labelContainer) {
377+
// Remove existing category badge (look for known category texts)
378+
const existingCategoryBadge = Array.from(labelContainer.querySelectorAll('span')).find(span => {
379+
const text = span.textContent.toLowerCase();
380+
return ['frontend', 'backend', 'design', 'testing', 'database', 'setup', 'bug', 'enhancement', 'feature'].includes(text);
381+
});
382+
383+
if (existingCategoryBadge) {
384+
existingCategoryBadge.remove();
385+
}
386+
387+
// Add new category badge if category is selected
388+
if (newCategory && window.getCategoryColor) {
389+
const categoryBadge = document.createElement('span');
390+
categoryBadge.className = `inline-flex items-center px-2 py-1 rounded-full text-xs font-medium ${window.getCategoryColor(newCategory)}`;
391+
categoryBadge.textContent = newCategory;
392+
393+
// Insert after priority badge or at beginning if no priority
394+
const priorityBadge = Array.from(labelContainer.querySelectorAll('span')).find(span => {
395+
const text = span.textContent.toLowerCase();
396+
return ['critical', 'high', 'medium', 'low'].includes(text);
397+
});
398+
399+
if (priorityBadge) {
400+
labelContainer.insertBefore(categoryBadge, priorityBadge.nextSibling);
401+
} else {
402+
labelContainer.insertBefore(categoryBadge, labelContainer.firstChild);
403+
}
404+
}
331405
}
332406
}
333407

334-
// TODO: Save to GitHub API
335-
console.log('Update category to GitHub API:', newCategory);
408+
// Update GitHub issue labels
409+
if (window.GitHubAPI && window.GitHubAPI.updateGitHubIssueMetadata) {
410+
await window.GitHubAPI.updateGitHubIssueMetadata(issueNumber, 'category', newCategory);
411+
} else {
412+
console.log('GitHub API not available, category updated locally only');
413+
}
336414
});
337415
}
338416

@@ -364,7 +442,16 @@ function setupIssueModalEventHandlers() {
364442
const doneColumn = document.getElementById('done');
365443
if (doneColumn) {
366444
doneColumn.appendChild(taskElement);
367-
window.updateColumnCounts();
445+
446+
// Update column counts using the global function
447+
if (window.KanbanBoard && window.KanbanBoard.updateColumnCounts) {
448+
window.KanbanBoard.updateColumnCounts();
449+
}
450+
451+
// Add completed section to the card
452+
if (window.GitHubUI && window.GitHubUI.addCompletedSection) {
453+
window.GitHubUI.addCompletedSection(taskElement);
454+
}
368455
}
369456
}
370457

@@ -394,13 +481,22 @@ function setupIssueModalEventHandlers() {
394481
reopenIssueBtn.classList.add('hidden');
395482
if (closeIssueBtn) closeIssueBtn.classList.remove('hidden');
396483

397-
// Also move the task back to backlog column in the kanban board (default for reopened issues)
484+
// Also move the task back to backlog column in the kanban board
398485
const taskElement = document.querySelector(`[data-issue-number="${issueNumber}"]`);
399486
if (taskElement) {
400487
const backlogColumn = document.getElementById('backlog');
401488
if (backlogColumn) {
402489
backlogColumn.appendChild(taskElement);
403-
window.updateColumnCounts();
490+
491+
// Update column counts using the global function
492+
if (window.KanbanBoard && window.KanbanBoard.updateColumnCounts) {
493+
window.KanbanBoard.updateColumnCounts();
494+
}
495+
496+
// Remove completed section from the card
497+
if (window.GitHubUI && window.GitHubUI.removeCompletedSection) {
498+
window.GitHubUI.removeCompletedSection(taskElement);
499+
}
404500
}
405501
}
406502

@@ -429,6 +525,19 @@ function setupIssueModalEventHandlers() {
429525
}
430526
}
431527

528+
// Helper functions for styling priority and category badges
529+
function getPriorityClasses(priority) {
530+
const baseClasses = 'task-priority inline-flex items-center px-2 py-1 rounded-full text-xs font-medium';
531+
if (!priority || !window.getPriorityColor) return baseClasses;
532+
return `${baseClasses} ${window.getPriorityColor(priority)}`;
533+
}
534+
535+
function getCategoryClasses(category) {
536+
const baseClasses = 'task-category inline-flex items-center px-2 py-1 rounded-full text-xs font-medium';
537+
if (!category || !window.getCategoryColor) return baseClasses;
538+
return `${baseClasses} ${window.getCategoryColor(category)}`;
539+
}
540+
432541
// Export functions to global scope
433542
window.IssueModal = {
434543
openIssueModal,

src/kanban.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,10 @@ document.addEventListener('DOMContentLoaded', function() {
330330
});
331331
}
332332

333+
// Expose updateColumnCounts globally for modal use
334+
window.KanbanBoard = window.KanbanBoard || {};
335+
window.KanbanBoard.updateColumnCounts = updateColumnCounts;
336+
333337
// Load collapse states from localStorage
334338
function loadCollapseStates() {
335339
const saved = localStorage.getItem('columnCollapseStates');

0 commit comments

Comments
 (0)