@@ -386,6 +386,11 @@ <h5 class="mb-0">Search Packages</h5>
386386 let filteredPackages = [ ] ;
387387 let sortColumn = - 1 ;
388388 let sortDirection = 1 ; // 1 for ascending, -1 for descending
389+ let packageSearchRows = [ ] ; // Store package search results for sorting
390+ let packageSearchSortColumn = - 1 ;
391+ let packageSearchSortDirection = 1 ;
392+ let packageSearchTotalMatches = 0 ; // Store total package matches
393+ let packageSearchQuery = '' ; // Store search query
389394 const API_BASE = '/api' ;
390395
391396 // Initialize on page load
@@ -768,64 +773,239 @@ <h5 class="mb-0">Search Packages</h5>
768773 <i class="bi bi-info-circle"></i> No packages found matching "${ escapeHtml ( data . query ) } "
769774 </div>
770775 ` ;
776+ packageSearchRows = [ ] ;
777+ packageSearchTotalMatches = 0 ;
778+ packageSearchQuery = data . query || '' ;
771779 return ;
772780 }
773781
774- let html = `
775- <div class="mb-3">
776- <strong>Found ${ data . total_matches } package(s) matching "${ escapeHtml ( data . query ) } "</strong>
777- </div>
778- ` ;
782+ // Store total matches and query
783+ packageSearchTotalMatches = data . total_matches || 0 ;
784+ packageSearchQuery = data . query || '' ;
779785
786+ // Flatten the data: create one row per package-kernel combination
787+ packageSearchRows = [ ] ;
780788 data . packages . forEach ( pkg => {
781- html += `
782- <div class="card mb-3">
783- <div class="card-header d-flex justify-content-between align-items-center">
784- <h6 class="mb-0">
785- <i class="bi bi-box-seam"></i> ${ escapeHtml ( pkg . name ) }
786- </h6>
787- <span class="badge bg-secondary">${ pkg . kernel_count } kernel(s)</span>
788- </div>
789- <div class="card-body">
790- <h6 class="mb-2">Available in the following kernels:</h6>
791- <div class="table-responsive">
792- <table class="table table-sm table-hover">
793- <thead>
794- <tr>
795- <th>Language</th>
796- <th>Kernel Name</th>
797- <th>Version</th>
798- <th>Package Version</th>
799- </tr>
800- </thead>
801- <tbody>
802- ` ;
803-
804789 if ( pkg . kernels && pkg . kernels . length > 0 ) {
805790 pkg . kernels . forEach ( kernel => {
806- html += `
791+ packageSearchRows . push ( {
792+ packageName : pkg . name ,
793+ packageVersion : kernel . package_version || 'N/A' ,
794+ kernelName : kernel . kernel_name || 'N/A' ,
795+ kernelVersion : kernel . kernel_version || 'N/A' ,
796+ language : kernel . kernel_language || kernel . language || 'N/A'
797+ } ) ;
798+ } ) ;
799+ } else {
800+ // If no kernels, still show the package
801+ packageSearchRows . push ( {
802+ packageName : pkg . name ,
803+ packageVersion : 'N/A' ,
804+ kernelName : 'N/A' ,
805+ kernelVersion : 'N/A' ,
806+ language : 'N/A'
807+ } ) ;
808+ }
809+ } ) ;
810+
811+ // Reset sort state
812+ packageSearchSortColumn = - 1 ;
813+ packageSearchSortDirection = 1 ;
814+
815+ // Render the table
816+ renderPackageSearchTable ( ) ;
817+ }
818+
819+ // Render package search results table
820+ function renderPackageSearchTable ( ) {
821+ const resultsDiv = document . getElementById ( 'packageSearchResults' ) ;
822+
823+ if ( packageSearchRows . length === 0 ) {
824+ resultsDiv . innerHTML = '<p class="text-muted text-center">No results to display</p>' ;
825+ return ;
826+ }
827+
828+ let html = `
829+ <div class="mb-3">
830+ <strong>Found ${ packageSearchTotalMatches } package(s) matching "${ escapeHtml ( packageSearchQuery ) } " (${ packageSearchRows . length } total result(s))</strong>
831+ </div>
832+ <div class="table-responsive">
833+ <table class="table table-striped table-hover" id="packageSearchTable">
834+ <thead>
807835 <tr>
808- <td><span class="badge bg-info">${ escapeHtml ( kernel . language || 'N/A' ) } </span></td>
809- <td>${ escapeHtml ( kernel . kernel_name || 'N/A' ) } </td>
810- <td><span class="badge bg-secondary">${ escapeHtml ( kernel . kernel_version || 'N/A' ) } </span></td>
811- <td>${ escapeHtml ( kernel . package_version || 'N/A' ) } </td>
836+ <th class="sortable" onclick="sortPackageSearchTable(0)">
837+ Package Name
838+ <i class="bi bi-arrow-down-up sort-icon" id="packageSortIcon0"></i>
839+ </th>
840+ <th class="sortable" onclick="sortPackageSearchTable(1)">
841+ Package Version
842+ <i class="bi bi-arrow-down-up sort-icon" id="packageSortIcon1"></i>
843+ </th>
844+ <th class="sortable" onclick="sortPackageSearchTable(2)">
845+ Kernel Name
846+ <i class="bi bi-arrow-down-up sort-icon" id="packageSortIcon2"></i>
847+ </th>
848+ <th class="sortable" onclick="sortPackageSearchTable(3)">
849+ Kernel Version
850+ <i class="bi bi-arrow-down-up sort-icon" id="packageSortIcon3"></i>
851+ </th>
852+ <th class="sortable" onclick="sortPackageSearchTable(4)">
853+ Language
854+ <i class="bi bi-arrow-down-up sort-icon" id="packageSortIcon4"></i>
855+ </th>
812856 </tr>
813- ` ;
814- } ) ;
857+ </thead>
858+ <tbody>
859+ ` ;
860+
861+ packageSearchRows . forEach ( ( row , index ) => {
862+ // Create clickable kernel name link if kernel info is available
863+ let kernelNameCell ;
864+ if ( row . kernelName !== 'N/A' && row . kernelVersion !== 'N/A' && row . language !== 'N/A' ) {
865+ kernelNameCell = `<a href="#" class="kernel-link" data-language="${ escapeHtml ( row . language ) } " data-kernel-name="${ escapeHtml ( row . kernelName ) } " data-kernel-version="${ escapeHtml ( row . kernelVersion ) } " style="color: var(--illinois-blue); text-decoration: none; font-weight: 500; cursor: pointer;">${ escapeHtml ( row . kernelName ) } </a>` ;
815866 } else {
816- html += '<tr><td colspan="4" class="text-muted text-center">No kernel information available</td></tr>' ;
867+ kernelNameCell = escapeHtml ( row . kernelName ) ;
817868 }
818869
819870 html += `
820- </tbody>
821- </table>
822- </div>
823- </div>
824- </div>
871+ <tr>
872+ <td>${ escapeHtml ( row . packageName ) } </td>
873+ <td>${ escapeHtml ( row . packageVersion ) } </td>
874+ <td>${ kernelNameCell } </td>
875+ <td>${ escapeHtml ( row . kernelVersion ) } </td>
876+ <td><span class="badge bg-info">${ escapeHtml ( row . language ) } </span></td>
877+ </tr>
825878 ` ;
826879 } ) ;
827880
881+ html += `
882+ </tbody>
883+ </table>
884+ </div>
885+ ` ;
886+
828887 resultsDiv . innerHTML = html ;
888+
889+ // Update sort icons
890+ for ( let i = 0 ; i < 5 ; i ++ ) {
891+ const icon = document . getElementById ( `packageSortIcon${ i } ` ) ;
892+ if ( icon ) {
893+ if ( packageSearchSortColumn === i ) {
894+ if ( packageSearchSortDirection === 1 ) {
895+ icon . className = 'bi bi-arrow-down sort-icon active' ;
896+ } else {
897+ icon . className = 'bi bi-arrow-up sort-icon active' ;
898+ }
899+ } else {
900+ icon . className = 'bi bi-arrow-down-up sort-icon' ;
901+ }
902+ }
903+ }
904+
905+ // Attach event listeners to kernel links
906+ resultsDiv . querySelectorAll ( '.kernel-link' ) . forEach ( link => {
907+ link . addEventListener ( 'click' , function ( e ) {
908+ e . preventDefault ( ) ;
909+ const language = this . getAttribute ( 'data-language' ) ;
910+ const kernelName = this . getAttribute ( 'data-kernel-name' ) ;
911+ const kernelVersion = this . getAttribute ( 'data-kernel-version' ) ;
912+ navigateToKernel ( language , kernelName , kernelVersion ) ;
913+ } ) ;
914+ } ) ;
915+ }
916+
917+ // Sort package search table
918+ function sortPackageSearchTable ( columnIndex ) {
919+ // Reset all sort icons
920+ for ( let i = 0 ; i < 5 ; i ++ ) {
921+ const icon = document . getElementById ( `packageSortIcon${ i } ` ) ;
922+ if ( icon ) {
923+ icon . className = 'bi bi-arrow-down-up sort-icon' ;
924+ }
925+ }
926+
927+ // If clicking same column, reverse direction
928+ if ( packageSearchSortColumn === columnIndex ) {
929+ packageSearchSortDirection *= - 1 ;
930+ } else {
931+ packageSearchSortColumn = columnIndex ;
932+ packageSearchSortDirection = 1 ;
933+ }
934+
935+ // Update sort icon
936+ const icon = document . getElementById ( `packageSortIcon${ columnIndex } ` ) ;
937+ if ( icon ) {
938+ if ( packageSearchSortDirection === 1 ) {
939+ icon . className = 'bi bi-arrow-down sort-icon active' ;
940+ } else {
941+ icon . className = 'bi bi-arrow-up sort-icon active' ;
942+ }
943+ }
944+
945+ // Sort rows
946+ packageSearchRows . sort ( ( a , b ) => {
947+ let aVal , bVal ;
948+ switch ( columnIndex ) {
949+ case 0 : // Package Name
950+ aVal = a . packageName || '' ;
951+ bVal = b . packageName || '' ;
952+ break ;
953+ case 1 : // Package Version
954+ aVal = a . packageVersion || '' ;
955+ bVal = b . packageVersion || '' ;
956+ break ;
957+ case 2 : // Kernel Name
958+ aVal = a . kernelName || '' ;
959+ bVal = b . kernelName || '' ;
960+ break ;
961+ case 3 : // Kernel Version
962+ aVal = a . kernelVersion || '' ;
963+ bVal = b . kernelVersion || '' ;
964+ break ;
965+ case 4 : // Language
966+ aVal = a . language || '' ;
967+ bVal = b . language || '' ;
968+ break ;
969+ }
970+
971+ if ( aVal < bVal ) return - 1 * packageSearchSortDirection ;
972+ if ( aVal > bVal ) return 1 * packageSearchSortDirection ;
973+ return 0 ;
974+ } ) ;
975+
976+ // Re-render the table
977+ renderPackageSearchTable ( ) ;
978+ }
979+
980+ // Function to navigate to kernel view
981+ async function navigateToKernel ( language , kernelName , version ) {
982+ // Switch to kernels view
983+ showView ( 'kernels' ) ;
984+
985+ // Set the language if needed
986+ const languageSelect = document . getElementById ( 'languageSelect' ) ;
987+ if ( languageSelect . value !== language ) {
988+ languageSelect . value = language ;
989+ currentLanguage = language ;
990+ // Load kernels for the new language
991+ await loadKernels ( language ) ;
992+ }
993+
994+ // Find the kernel item in the list to highlight it
995+ const kernelItems = document . querySelectorAll ( '.kernel-item' ) ;
996+ let kernelElement = null ;
997+
998+ kernelItems . forEach ( item => {
999+ const itemKernelName = item . getAttribute ( 'data-kernel-name' ) ;
1000+ const itemVersion = item . getAttribute ( 'data-version' ) ;
1001+
1002+ if ( itemKernelName === kernelName && itemVersion === version ) {
1003+ kernelElement = item ;
1004+ }
1005+ } ) ;
1006+
1007+ // Select the kernel (with or without element for highlighting)
1008+ await selectKernel ( language , kernelName , version , kernelElement ) ;
8291009 }
8301010 </ script >
8311011</ body >
0 commit comments