@@ -323,6 +323,100 @@ function updateViewSwitcherLinks() {
323323 }
324324}
325325
326+ /**
327+ * Delete a specific repository from cache
328+ */
329+ function deleteRepoFromCache ( repo ) {
330+ const cacheKeysToDelete = [ ] ;
331+
332+ // Find all cache keys for this repo
333+ Object . keys ( localStorage ) . forEach ( key => {
334+ if ( key . startsWith ( `${ CACHE_KEY_PREFIX } ${ repo } _` ) ) {
335+ cacheKeysToDelete . push ( key ) ;
336+ }
337+ } ) ;
338+
339+ if ( cacheKeysToDelete . length === 0 ) {
340+ showError ( `No cache found for ${ repo } ` ) ;
341+ return ;
342+ }
343+
344+ // Delete the cache entries
345+ cacheKeysToDelete . forEach ( key => localStorage . removeItem ( key ) ) ;
346+
347+ // Also remove from the repos textarea
348+ const reposInput = document . getElementById ( 'repos' ) ;
349+ if ( reposInput ) {
350+ const currentRepos = reposInput . value . split ( '\n' )
351+ . map ( line => line . trim ( ) )
352+ . filter ( line => line && line . includes ( '/' ) ) ;
353+
354+ const filteredRepos = currentRepos . filter ( r => r !== repo ) ;
355+ reposInput . value = filteredRepos . join ( '\n' ) ;
356+
357+ // Trigger input event to show change notice
358+ reposInput . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
359+ }
360+
361+ // Show confirmation message briefly
362+ const cacheStatus = document . getElementById ( 'cacheStatus' ) ;
363+ if ( cacheStatus ) {
364+ cacheStatus . innerHTML = `🗑️ Deleted cache for ${ repo } ` ;
365+ }
366+
367+ // Update cache status display immediately to remove the item
368+ setTimeout ( ( ) => {
369+ updateCacheStatus ( ) ;
370+ } , 500 ) ;
371+ }
372+
373+ /**
374+ * Add a repository to the repos list if it's not already there
375+ */
376+ function addRepoToList ( repo ) {
377+ const reposInput = document . getElementById ( 'repos' ) ;
378+ if ( ! reposInput ) return ;
379+
380+ const currentRepos = reposInput . value . split ( '\n' )
381+ . map ( line => line . trim ( ) )
382+ . filter ( line => line && line . includes ( '/' ) ) ;
383+
384+ // Toggle: remove if exists, add if not
385+ const repoIndex = currentRepos . indexOf ( repo ) ;
386+ let message ;
387+
388+ if ( repoIndex !== - 1 ) {
389+ // Remove the repo
390+ currentRepos . splice ( repoIndex , 1 ) ;
391+ message = `➖ Removed ${ repo } from list` ;
392+ } else {
393+ // Add the repo
394+ currentRepos . push ( repo ) ;
395+ message = `✅ Added ${ repo } to list` ;
396+ }
397+
398+ reposInput . value = currentRepos . join ( '\n' ) ;
399+
400+ // Trigger input event to show change notice
401+ reposInput . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
402+
403+ // Expand the config section if collapsed
404+ const reposSection = document . getElementById ( 'reposSection' ) ;
405+ if ( reposSection && reposSection . classList . contains ( 'collapsed' ) ) {
406+ reposSection . classList . remove ( 'collapsed' ) ;
407+ }
408+
409+ // Show toggle message
410+ const cacheStatus = document . getElementById ( 'cacheStatus' ) ;
411+ if ( cacheStatus ) {
412+ const originalText = cacheStatus . innerHTML ;
413+ cacheStatus . innerHTML = message ;
414+ setTimeout ( ( ) => {
415+ cacheStatus . innerHTML = originalText ;
416+ } , 2000 ) ;
417+ }
418+ }
419+
326420/**
327421 * Setup common UI handlers (repos toggle, token permissions toggle)
328422 */
@@ -449,15 +543,41 @@ export function updateCacheStatus() {
449543
450544 // Populate details panel
451545 if ( cacheDetails ) {
452- cacheDetails . innerHTML = cacheInfo . map ( info => `
546+ cacheDetails . innerHTML = `
547+ <div style="font-size: 11px; color: #8b949e; margin-bottom: 8px; padding: 6px; background: #161b22; border-radius: 4px; border-left: 2px solid #58a6ff;">
548+ 💡 <strong>Tip:</strong> Left-click to toggle repo in list • Right-click to delete from cache
549+ </div>
550+ ` + cacheInfo . map ( info => `
453551 <div class="cache-detail-item">
454- <span style="font-family: monospace; color: #58a6ff;">${ escapeHtml ( info . repo ) } </span>
552+ <span style="font-family: monospace; color: #58a6ff; cursor: pointer; text-decoration: underline;"
553+ class="cache-repo-name"
554+ data-repo="${ escapeHtml ( info . repo ) } "
555+ title="Left-click to toggle in list • Right-click to delete from cache">
556+ ${ escapeHtml ( info . repo ) }
557+ </span>
455558 <span class="cache-detail-time">
456559 ${ info . timeAgo } •
457560 expires in ${ info . remainingMinutes } m
458561 </span>
459562 </div>
460563 ` ) . join ( '' ) ;
564+
565+ // Add click handlers for repo names
566+ cacheDetails . querySelectorAll ( '.cache-repo-name' ) . forEach ( el => {
567+ el . addEventListener ( 'click' , ( e ) => {
568+ e . stopPropagation ( ) ;
569+ const repo = el . dataset . repo ;
570+ addRepoToList ( repo ) ;
571+ } ) ;
572+
573+ // Add right-click handler to delete from cache
574+ el . addEventListener ( 'contextmenu' , ( e ) => {
575+ e . preventDefault ( ) ;
576+ e . stopPropagation ( ) ;
577+ const repo = el . dataset . repo ;
578+ deleteRepoFromCache ( repo ) ;
579+ } ) ;
580+ } ) ;
461581 }
462582 } else {
463583 cacheStatus . textContent = 'No cached data' ;
@@ -542,13 +662,35 @@ export function setupLoadButton(onLoad) {
542662 const tokenInput = document . getElementById ( 'token' ) ;
543663 const reposInput = document . getElementById ( 'repos' ) ;
544664 const forceRefresh = document . getElementById ( 'forceRefresh' ) ;
665+
666+ let configChanged = false ;
545667
546668 // Load saved token from localStorage
547669 const savedToken = localStorage . getItem ( 'githubToken' ) ;
548670 if ( savedToken ) {
549671 tokenInput . value = savedToken ;
550672 setGitHubToken ( savedToken ) ;
551673 }
674+
675+ // Track changes to repos textarea
676+ const showChangeNotice = ( ) => {
677+ if ( ! configChanged ) {
678+ configChanged = true ;
679+ loadBtn . style . background = '#da3633' ;
680+ loadBtn . style . animation = 'pulse 2s infinite' ;
681+ loadBtn . textContent = '⚠️ Load Issues & PRs (Config Changed)' ;
682+ }
683+ } ;
684+
685+ const hideChangeNotice = ( ) => {
686+ configChanged = false ;
687+ loadBtn . style . background = '' ;
688+ loadBtn . style . animation = '' ;
689+ loadBtn . textContent = 'Load Issues & PRs' ;
690+ } ;
691+
692+ // Watch for changes in repos textarea
693+ reposInput . addEventListener ( 'input' , showChangeNotice ) ;
552694
553695 loadBtn . addEventListener ( 'click' , async ( ) => {
554696 const token = tokenInput . value . trim ( ) ;
@@ -558,6 +700,9 @@ export function setupLoadButton(onLoad) {
558700 // Save to localStorage
559701 localStorage . setItem ( 'githubToken' , token ) ;
560702 localStorage . setItem ( 'githubRepos' , reposText ) ;
703+
704+ // Clear change notice
705+ hideChangeNotice ( ) ;
561706
562707 if ( ! reposText ) {
563708 showError ( 'Please enter at least one repository' ) ;
0 commit comments