Improve app page with sorting, recommendations and more (#520)

This commit is contained in:
Jeffrey
2026-03-15 22:58:06 +01:00
committed by GitHub
parent d187679cd0
commit c37bdcf5f2
25 changed files with 1573 additions and 970 deletions

View File

@@ -0,0 +1,55 @@
# Runs a scriptblock in a background PowerShell runspace while keeping the UI responsive.
# In GUI mode, the work executes on a separate thread and the UI thread pumps messages (~60fps).
# In CLI mode, the scriptblock runs directly in the current session.
function Invoke-NonBlocking {
param(
[scriptblock]$ScriptBlock,
[object[]]$ArgumentList = @(),
[int]$TimeoutSeconds = 0
)
# CLI mode without timeout: run directly in-process
if (-not $script:GuiWindow -and $TimeoutSeconds -eq 0) {
return (& $ScriptBlock @ArgumentList)
}
$ps = [powershell]::Create()
try {
$null = $ps.AddScript($ScriptBlock.ToString())
foreach ($arg in $ArgumentList) {
$null = $ps.AddArgument($arg)
}
$handle = $ps.BeginInvoke()
if ($script:GuiWindow) {
# GUI mode: pump UI messages while waiting
$stopwatch = if ($TimeoutSeconds -gt 0) { [System.Diagnostics.Stopwatch]::StartNew() } else { $null }
while (-not $handle.IsCompleted) {
if ($stopwatch -and $stopwatch.Elapsed.TotalSeconds -ge $TimeoutSeconds) {
$ps.Stop()
throw "Operation timed out after $TimeoutSeconds seconds"
}
DoEvents
Start-Sleep -Milliseconds 16
}
}
else {
# CLI mode with timeout: block until completion or timeout
if (-not $handle.AsyncWaitHandle.WaitOne($TimeoutSeconds * 1000)) {
$ps.Stop()
throw "Operation timed out after $TimeoutSeconds seconds"
}
}
$result = $ps.EndInvoke($handle)
if ($result.Count -eq 0) { return $null }
if ($result.Count -eq 1) { return $result[0] }
return @($result)
}
finally {
$ps.Dispose()
}
}