()
| 307 | |
| 308 | // UI helpers |
| 309 | function renderTableRows() { |
| 310 | const filterText = (filterInput.value || '').toLowerCase(); |
| 311 | libsTbody.innerHTML = ''; |
| 312 | for (const name of state.libraryNames) { |
| 313 | const deps = state.dependencyGraph[name]?.all_dependencies || []; |
| 314 | const brief = state.libraryBriefByName[name] || ''; |
| 315 | if (filterText) { |
| 316 | const hay = `${name} ${brief} ${deps.join(' ')}`.toLowerCase(); |
| 317 | if (!hay.includes(filterText)) continue; |
| 318 | } |
| 319 | const tr = document.createElement('tr'); |
| 320 | const tdName = document.createElement('td'); |
| 321 | const docUrl = `https://pagghiu.github.io/SaneCppLibraries/library_${name.replace(/[A-Z]/g, (m, i) => (i? '_' : '') + m.toLowerCase()).replace(/^_/, '').replace(/__+/g, '_')}.html`; |
| 322 | tdName.innerHTML = `<strong><a href="${docUrl}" target="_blank" rel="noopener noreferrer">${name}</a></strong>`; |
| 323 | const tdDesc = document.createElement('td'); |
| 324 | tdDesc.textContent = brief; |
| 325 | // Dependencies moved below action button in action cell |
| 326 | const tdAction = document.createElement('td'); |
| 327 | tdAction.className = 'fit'; |
| 328 | const actions = document.createElement('div'); |
| 329 | actions.className = 'row-actions'; |
| 330 | const btn = document.createElement('button'); |
| 331 | btn.className = 'ghost'; |
| 332 | btn.textContent = 'Generate / Download'; |
| 333 | btn.addEventListener('click', async () => { |
| 334 | btn.disabled = true; |
| 335 | // Inline progress UI |
| 336 | const inline = document.createElement('div'); |
| 337 | inline.className = 'inline-progress'; |
| 338 | const row = document.createElement('div'); row.className = 'row'; |
| 339 | const label = document.createElement('div'); label.className = 'label'; label.textContent = 'Preparing…'; |
| 340 | const cancel = document.createElement('button'); cancel.className = 'cancel'; cancel.textContent = 'Cancel'; |
| 341 | const prog = document.createElement('div'); prog.className = 'progress'; |
| 342 | const bar = document.createElement('div'); bar.className = 'progress-bar'; prog.appendChild(bar); |
| 343 | row.appendChild(label); row.appendChild(cancel); |
| 344 | inline.appendChild(row); inline.appendChild(prog); |
| 345 | tdAction.appendChild(inline); |
| 346 | const controller = new AbortController(); |
| 347 | const signal = controller.signal; |
| 348 | cancel.addEventListener('click', () => controller.abort()); |
| 349 | try { |
| 350 | label.textContent = 'Fetching tree…'; |
| 351 | bar.style.width = '8%'; |
| 352 | const tree = await getRepoTree(state.currentRef); |
| 353 | if (signal.aborted) throw new Error('Cancelled'); |
| 354 | label.textContent = 'Amalgamating…'; |
| 355 | bar.style.width = '60%'; |
| 356 | const content = await buildSingleLibraryHeader(name, state.currentRef, tree); |
| 357 | if (signal.aborted) throw new Error('Cancelled'); |
| 358 | label.textContent = 'Saving…'; |
| 359 | bar.style.width = '90%'; |
| 360 | triggerDownload(`SaneCpp${name}.h`, content); |
| 361 | bar.style.width = '100%'; |
| 362 | label.textContent = 'Done'; |
| 363 | setTimeout(() => inline.remove(), 700); |
| 364 | } catch (e) { |
| 365 | console.error(e); |
| 366 | alert(`Failed to build ${name}: ${e.message}`); |
no test coverage detected