@@ -34,7 +34,15 @@ <h4 class="text-sm font-bold text-black mb-2">Actions</h4>
3434 </ button >
3535 < div class ="menu-dropdown " id ="dropdown-mcps " style ="display: none; ">
3636 < div id ="mcps-list " class ="p-2 ">
37- < div class ="text-xs text-gray-500 "> Loading...</ div >
37+ {% for mcp in mcps %}
38+ < div class ="dropdown-item " onclick ="toggleDropdownItem(this, '{{ mcp.name }}', 'mcps') ">
39+ < span class ="dropdown-item-icon "> +</ span >
40+ < span > {{ mcp.name }}</ span >
41+ </ div >
42+ {% endfor %}
43+ {% if not mcps %}
44+ < div class ="text-xs text-gray-500 "> No MCPs available</ div >
45+ {% endif %}
3846 </ div >
3947 </ div >
4048 </ div >
@@ -52,7 +60,15 @@ <h4 class="text-sm font-bold text-black mb-2">Actions</h4>
5260 </ button >
5361 < div class ="menu-dropdown " id ="dropdown-rules " style ="display: none; ">
5462 < div id ="rules-list " class ="p-2 ">
55- < div class ="text-xs text-gray-500 "> Loading...</ div >
63+ {% for rule in rules %}
64+ < div class ="dropdown-item " onclick ="toggleDropdownItem(this, '{{ rule.slug or rule.name }}', 'rules') ">
65+ < span class ="dropdown-item-icon "> +</ span >
66+ < span > {{ rule.display_name or rule.name }}</ span >
67+ </ div >
68+ {% endfor %}
69+ {% if not rules %}
70+ < div class ="text-xs text-gray-500 "> No rules available</ div >
71+ {% endif %}
5672 </ div >
5773 </ div >
5874 </ div >
@@ -70,7 +86,15 @@ <h4 class="text-sm font-bold text-black mb-2">Actions</h4>
7086 </ button >
7187 < div class ="menu-dropdown " id ="dropdown-agents " style ="display: none; ">
7288 < div id ="agents-list " class ="p-2 ">
73- < div class ="text-xs text-gray-500 "> Loading...</ div >
89+ {% for agent in agents %}
90+ < div class ="dropdown-item " onclick ="toggleDropdownItem(this, '{{ agent.slug or agent.name }}', 'agents') ">
91+ < span class ="dropdown-item-icon "> +</ span >
92+ < span > {{ agent.display_name or agent.name }}</ span >
93+ </ div >
94+ {% endfor %}
95+ {% if not agents %}
96+ < div class ="text-xs text-gray-500 "> No agents available</ div >
97+ {% endif %}
7498 </ div >
7599 </ div >
76100 </ div >
@@ -301,29 +325,26 @@ <h4 class="text-sm font-bold text-black mb-2">Actions</h4>
301325</ style >
302326
303327< script >
328+ // Initialize actions data from server-side rendering
329+ const serverActions = {
330+ agents : { { agents | tojson | safe } } ,
331+ rules : { { rules | tojson | safe } } ,
332+ mcps : { { mcps | tojson | safe } }
333+ } ;
334+
304335// Track loaded data
305336let loadedData = { } ;
306337
307- // Search functionality
308- let allActions = [ ] ;
338+ // Search functionality - initialize with server data
339+ let allActions = [
340+ ...( serverActions . mcps || [ ] ) . map ( item => ( { ...item , type : 'MCP' } ) ) ,
341+ ...( serverActions . rules || [ ] ) . map ( item => ( { ...item , type : 'Rule' } ) ) ,
342+ ...( serverActions . agents || [ ] ) . map ( item => ( { ...item , type : 'Agent' } ) )
343+ ] ;
309344let searchTimeout = null ;
310345
311- // Initialize search data
312- async function initSearchData ( ) {
313- try {
314- const response = await fetch ( '/api/actions/' ) ;
315- if ( response . ok ) {
316- const data = await response . json ( ) ;
317- allActions = [
318- ...( data . mcps || [ ] ) . map ( item => ( { ...item , type : 'MCP' } ) ) ,
319- ...( data . rules || [ ] ) . map ( item => ( { ...item , type : 'Rule' } ) ) ,
320- ...( data . agents || [ ] ) . map ( item => ( { ...item , type : 'Agent' } ) )
321- ] ;
322- }
323- } catch ( error ) {
324- console . error ( 'Error loading search data:' , error ) ;
325- }
326- }
346+ // Initialize search data - no longer needed as data comes from server
347+ // The allActions array is already initialized with server data above
327348
328349// Search actions
329350function searchActions ( query ) {
@@ -437,7 +458,7 @@ <h4 class="text-sm font-bold text-black mb-2">Actions</h4>
437458
438459// Initialize on load
439460document . addEventListener ( 'DOMContentLoaded' , function ( ) {
440- initSearchData ( ) ;
461+ // No need to call initSearchData - data is already loaded from server
441462 // Wait a bit for workspace manager to initialize
442463 setTimeout ( ( ) => {
443464 restoreActionStates ( ) ;
@@ -481,19 +502,9 @@ <h4 class="text-sm font-bold text-black mb-2">Actions</h4>
481502
482503// Insert action into context
483504async function insertIntoContext ( type ) {
484- if ( type === 'agents' ) {
485- // Default agent insertion
486- const defaultAgent = 'code-searcher' ;
487- await installAgent ( defaultAgent ) ;
488- } else if ( type === 'mcps' ) {
489- // Default MCP insertion
490- const defaultMcp = 'filesystem' ;
491- await installMCP ( defaultMcp ) ;
492- } else if ( type === 'rules' ) {
493- // Default rule insertion
494- const defaultRule = 'code-quality' ;
495- await installRule ( defaultRule ) ;
496- }
505+ // No longer auto-install default items
506+ // Users should explicitly choose which items they want
507+ // This function is kept for potential future use
497508}
498509
499510// Remove action from context
@@ -527,51 +538,33 @@ <h4 class="text-sm font-bold text-black mb-2">Actions</h4>
527538 }
528539}
529540
530- // Load dropdown data
531- async function loadDropdownData ( type ) {
532- try {
533- const response = await fetch ( '/api/actions/' ) ;
534- if ( ! response . ok ) throw new Error ( 'Failed to fetch actions' ) ;
535-
536- const data = await response . json ( ) ;
537- let container , items ;
538-
539- switch ( type ) {
540- case 'mcps' :
541- container = document . getElementById ( 'mcps-list' ) ;
542- items = data . mcps || [ ] ;
543- break ;
544- case 'rules' :
545- container = document . getElementById ( 'rules-list' ) ;
546- items = data . rules || [ ] ;
547- break ;
548- case 'agents' :
549- container = document . getElementById ( 'agents-list' ) ;
550- items = data . agents || [ ] ;
551- break ;
552- }
553-
554- if ( container && items . length > 0 ) {
555- const state = window . workspaceManager ?. getState ( ) ;
556- container . innerHTML = items . map ( item => {
557- // Use slug for internal ID, display_name for display
558- const itemId = item . slug || item . name ;
559- const displayName = item . display_name || item . name ;
560- const isChecked = state ? state . isActionItemChecked ( type , itemId ) : false ;
561- return `
562- <div
563- class="dropdown-item ${ isChecked ? 'active' : '' } "
564- onclick="toggleDropdownItem(this, '${ itemId } ', '${ type } ')"
565- >
566- <span class="dropdown-item-icon">${ isChecked ? '−' : '+' } </span>
567- <span>${ displayName } </span>
568- </div>
569- ` ;
570- } ) . join ( '' ) ;
541+ // Load dropdown data - now just updates the UI state based on what's already rendered
542+ function loadDropdownData ( type ) {
543+ // The dropdown items are now rendered server-side with Jinja
544+ // This function just needs to update the UI state (active/inactive)
545+ const state = window . workspaceManager ?. getState ( ) ;
546+ if ( ! state ) return ;
547+
548+ const container = document . getElementById ( `${ type } -list` ) ;
549+ if ( ! container ) return ;
550+
551+ // Update each dropdown item's state
552+ const items = container . querySelectorAll ( '.dropdown-item' ) ;
553+ items . forEach ( item => {
554+ const itemName = item . getAttribute ( 'data-item-id' ) ||
555+ item . onclick . toString ( ) . match ( / t o g g l e D r o p d o w n I t e m \( t h i s , \s * ' ( [ ^ ' ] + ) ' / ) ?. [ 1 ] ;
556+ if ( itemName ) {
557+ const isChecked = state . isActionItemChecked ( type , itemName ) ;
558+ const icon = item . querySelector ( '.dropdown-item-icon' ) ;
559+ if ( isChecked ) {
560+ item . classList . add ( 'active' ) ;
561+ if ( icon ) icon . textContent = '−' ;
562+ } else {
563+ item . classList . remove ( 'active' ) ;
564+ if ( icon ) icon . textContent = '+' ;
565+ }
571566 }
572- } catch ( error ) {
573- console . error ( `Error loading ${ type } :` , error ) ;
574- }
567+ } ) ;
575568}
576569
577570// Toggle individual dropdown item
0 commit comments