@@ -186,7 +186,7 @@ function renderPRTable(prs) {
186186 return dt ;
187187 }
188188
189- // Fallback: sort by Created date (col 7) ascending, then wire up pure-JS column filters .
189+ // Fallback: sort by Created date (col 7) ascending, then add paging + per- column filtering .
190190 const allRows = Array . from ( tbody . querySelectorAll ( 'tr' ) ) ;
191191 allRows . sort ( ( a , b ) => {
192192 const aVal = a . querySelectorAll ( 'td' ) [ 7 ] ?. textContent || '' ;
@@ -195,14 +195,88 @@ function renderPRTable(prs) {
195195 } ) ;
196196 allRows . forEach ( row => tbody . appendChild ( row ) ) ;
197197
198- function applyFilters ( ) {
198+ let pageSize = 25 ;
199+ let currentPage = 0 ;
200+
201+ const lengthSel = document . createElement ( 'select' ) ;
202+ lengthSel . className = 'form-select form-select-sm d-inline-block w-auto' ;
203+ [ 10 , 25 , 50 , 100 ] . forEach ( n => {
204+ const opt = document . createElement ( 'option' ) ;
205+ opt . value = String ( n ) ;
206+ opt . textContent = String ( n ) ;
207+ if ( n === 25 ) opt . selected = true ;
208+ lengthSel . appendChild ( opt ) ;
209+ } ) ;
210+ const lengthLabel = document . createElement ( 'label' ) ;
211+ lengthLabel . className = 'text-muted small me-auto' ;
212+ lengthLabel . append ( 'Show ' , lengthSel , ' entries' ) ;
213+
214+ const infoEl = document . createElement ( 'small' ) ;
215+ infoEl . className = 'text-muted' ;
216+
217+ const pagUl = document . createElement ( 'ul' ) ;
218+ pagUl . className = 'pagination pagination-sm mb-0' ;
219+
220+ const topBar = document . createElement ( 'div' ) ;
221+ topBar . className = 'd-flex align-items-center mb-2' ;
222+ topBar . appendChild ( lengthLabel ) ;
223+
224+ const bottomBar = document . createElement ( 'div' ) ;
225+ bottomBar . className = 'd-flex justify-content-between align-items-center mt-2 flex-wrap gap-2' ;
226+ bottomBar . append ( infoEl , pagUl ) ;
227+
228+ const table = container . querySelector ( 'table' ) ;
229+ container . insertBefore ( topBar , table ) ;
230+ container . appendChild ( bottomBar ) ;
231+
232+ function getFiltered ( ) {
199233 const filters = filterInputs . map ( inp => inp . value . toLowerCase ( ) ) ;
200- allRows . forEach ( row => {
234+ return allRows . filter ( row => {
201235 const cells = Array . from ( row . querySelectorAll ( 'td' ) ) ;
202- row . style . display = filters . every ( ( f , i ) => ! f || ( cells [ i ] ?. textContent || '' ) . toLowerCase ( ) . includes ( f ) ) ? '' : 'none' ;
236+ return filters . every ( ( f , i ) => ! f || ( cells [ i ] ?. textContent || '' ) . toLowerCase ( ) . includes ( f ) ) ;
203237 } ) ;
204238 }
205- filterInputs . forEach ( inp => inp . addEventListener ( 'input' , applyFilters ) ) ;
239+
240+ function renderPage ( ) {
241+ const filtered = getFiltered ( ) ;
242+ const totalPages = Math . max ( 1 , Math . ceil ( filtered . length / pageSize ) ) ;
243+ currentPage = Math . min ( currentPage , totalPages - 1 ) ;
244+ const start = currentPage * pageSize ;
245+
246+ allRows . forEach ( r => { r . style . display = 'none' ; } ) ;
247+ filtered . slice ( start , start + pageSize ) . forEach ( r => { r . style . display = '' ; } ) ;
248+
249+ const from = filtered . length === 0 ? 0 : start + 1 ;
250+ const to = Math . min ( start + pageSize , filtered . length ) ;
251+ infoEl . textContent = `Showing ${ from } to ${ to } of ${ filtered . length } entries` ;
252+
253+ pagUl . innerHTML = '' ;
254+ const addBtn = ( label , page , disabled , active ) => {
255+ const li = document . createElement ( 'li' ) ;
256+ li . className = `page-item${ disabled ? ' disabled' : '' } ${ active ? ' active' : '' } ` ;
257+ const btn = document . createElement ( 'button' ) ;
258+ btn . className = 'page-link' ;
259+ btn . textContent = label ;
260+ btn . disabled = disabled ;
261+ if ( ! disabled ) btn . addEventListener ( 'click' , ( ) => { currentPage = page ; renderPage ( ) ; } ) ;
262+ li . appendChild ( btn ) ;
263+ pagUl . appendChild ( li ) ;
264+ } ;
265+ addBtn ( 'Previous' , currentPage - 1 , currentPage === 0 , false ) ;
266+ const startP = Math . max ( 0 , Math . min ( currentPage - 2 , totalPages - 5 ) ) ;
267+ for ( let p = startP ; p < Math . min ( totalPages , startP + 5 ) ; p ++ ) {
268+ addBtn ( String ( p + 1 ) , p , false , p === currentPage ) ;
269+ }
270+ addBtn ( 'Next' , currentPage + 1 , currentPage >= totalPages - 1 , false ) ;
271+ }
272+
273+ lengthSel . addEventListener ( 'change' , ( ) => {
274+ pageSize = parseInt ( lengthSel . value , 10 ) ;
275+ currentPage = 0 ;
276+ renderPage ( ) ;
277+ } ) ;
278+ filterInputs . forEach ( inp => inp . addEventListener ( 'input' , ( ) => { currentPage = 0 ; renderPage ( ) ; } ) ) ;
279+ renderPage ( ) ;
206280}
207281
208282// License treemap
0 commit comments