diff --git a/php/public/scroll-into-view.js b/php/public/scroll-into-view.js
index 2c676911..3e4b9574 100644
--- a/php/public/scroll-into-view.js
+++ b/php/public/scroll-into-view.js
@@ -4,6 +4,10 @@ const observer = new MutationObserver((records) => {
// function being present.
if (node && typeof(node.scrollIntoView) === 'function') {
node.scrollIntoView();
+ if (node.classList.contains('progress-indicator')) {
+ node.previousSibling.append('.');
+ node.remove();
+ }
}
});
observer.observe(document, {childList: true, subtree: true});
diff --git a/php/src/Controller/DockerController.php b/php/src/Controller/DockerController.php
index 1e50278a..089256b9 100644
--- a/php/src/Controller/DockerController.php
+++ b/php/src/Controller/DockerController.php
@@ -420,7 +420,7 @@ readonly class DockerController {
-
+
@@ -428,6 +428,11 @@ readonly class DockerController {
}
private function startStreamingResponse(Response $response) : Response {
+ // Ensure the script keeps running even if the client connection drops (e.g. due to a
+ // reverse proxy read timeout during a long image pull). Without this, PHP would abort
+ // on the first write after the connection is gone, leaving only some containers started.
+ ignore_user_abort(true);
+
$nonbufResp = $response
->withBody(new NonBufferedBody())
->withHeader('Content-Type', 'text/html; charset=utf-8')
@@ -448,12 +453,19 @@ readonly class DockerController {
// if it'll actually pull an image), but which should not need to know anything about the
// wanted markup or formatting.
$addToStreamingResponseBody = function (string $message, ?Container $container = null) use ($nonbufResp) : void {
- // Strip ANSI codes.
- $message = preg_replace('/\e[[][A-Za-z0-9];?[0-9]*m?/', '', $message);
- if ($container) {
- $message = "{$container->displayName}: {$message}";
+ // If the message is a single dot we treat it as a progress indicator and send a specific, empty
+ // HTML element, which gets special treatment by the Javascript code.
+ if ($message === '.') {
+ $html = "";
+ } else {
+ // Strip ANSI codes. If the operation fails, use the unchanged $message as fallback.
+ $text = preg_replace('/\e[[][A-Za-z0-9];?[0-9]*m?/', '', $message) ?? $message;
+ if ($container) {
+ $text = sprintf("%s: %s", $container->displayName, $text);
+ }
+ $html = sprintf("