- */
- private function getAuthHeaders(): array
- {
- return [
- 'Authorization' => 'Bearer ' . $this->apiToken,
- ];
- }
-}
diff --git a/templates/admin/update_manager/docker_progress.html.twig b/templates/admin/update_manager/docker_progress.html.twig
deleted file mode 100644
index e43b9afa..00000000
--- a/templates/admin/update_manager/docker_progress.html.twig
+++ /dev/null
@@ -1,235 +0,0 @@
-{% extends "main_card.html.twig" %}
-
-{% block title %}{% trans %}update_manager.docker.progress_title{% endtrans %}{% endblock %}
-
-{% block card_title %}
-
- {% trans %}update_manager.docker.progress_title{% endtrans %}
-{% endblock %}
-
-{% block card_content %}
-
-
-
- {# Progress Header #}
-
-
-
- {% trans %}update_manager.docker.updating{% endtrans %}
-
-
- {% trans %}update_manager.docker.updating_via_watchtower{% endtrans %}
-
-
-
- {# Progress Bar #}
-
-
- {# Current Step Info #}
-
- {% trans %}update_manager.docker.step_trigger{% endtrans %} :
- {% trans %}update_manager.docker.step_trigger_desc{% endtrans %}
-
-
- {# Success Message #}
-
-
- {% trans %}update_manager.docker.success_message{% endtrans %}
-
- {% trans %}update_manager.docker.previous_version{% endtrans %}:
- {{ previous_version }}
- →
- {% trans %}update_manager.docker.new_version{% endtrans %}:
- ...
-
-
- {# Timeout Message #}
-
-
- {% trans %}update_manager.docker.timeout_message{% endtrans %}
-
-
- {# Error Message #}
-
-
- {% trans %}update_manager.progress.error{% endtrans %}:
-
-
-
- {# Steps Timeline - matches git progress style #}
-
-
-
-
- {# Step 1: Trigger Watchtower #}
-
-
-
- {% trans %}update_manager.docker.step_trigger{% endtrans %}
- {% trans %}update_manager.docker.step_trigger_desc{% endtrans %}
-
-
-
-
- {# Step 2: Pull Image #}
-
-
-
- {% trans %}update_manager.docker.step_pull{% endtrans %}
- {% trans %}update_manager.docker.step_pull_desc{% endtrans %}
-
-
-
-
- {# Step 3: Stop Container #}
-
-
-
- {% trans %}update_manager.docker.step_stop{% endtrans %}
- {% trans %}update_manager.docker.step_stop_desc{% endtrans %}
-
-
-
-
- {# Step 4: Restart Container #}
-
-
-
- {% trans %}update_manager.docker.step_restart{% endtrans %}
- {% trans %}update_manager.docker.step_restart_desc{% endtrans %}
-
-
-
-
- {# Step 5: Health Check #}
-
-
-
- {% trans %}update_manager.docker.step_health{% endtrans %}
- {% trans %}update_manager.docker.step_health_desc{% endtrans %}
-
-
-
-
- {# Step 6: Verify Version #}
-
-
-
- {% trans %}update_manager.docker.step_verify{% endtrans %}
- {% trans %}update_manager.docker.step_verify_desc{% endtrans %}
-
-
-
-
-
-
-
- {# Elapsed Time #}
-
-
- {% trans %}update_manager.docker.elapsed{% endtrans %}:
- 0s
-
-
- {# Actions - shown after completion or timeout #}
-
-
- {# Warning Notice #}
-
-
- {% trans %}update_manager.docker.warning{% endtrans %}:
- {% trans %}update_manager.docker.do_not_close{% endtrans %}
-
-
-{% endblock %}
diff --git a/templates/admin/update_manager/index.html.twig b/templates/admin/update_manager/index.html.twig
index 0b4eeceb..2c6db63c 100644
--- a/templates/admin/update_manager/index.html.twig
+++ b/templates/admin/update_manager/index.html.twig
@@ -75,20 +75,6 @@
{{ status.installation.type_name }}
-
-
- {% trans %}update_manager.web_updates_allowed{% endtrans %}
- {{ helper.boolean_badge(not web_updates_disabled) }}
-
-
- {% trans %}update_manager.backup_restore_allowed{% endtrans %}
- {{ helper.boolean_badge(not backup_restore_disabled) }}
-
-
- {% trans %}update_manager.backup_download_allowed{% endtrans %}
- {{ helper.boolean_badge(not backup_download_disabled) }}
-
-
{% if status.git.is_git_install %}
{% trans %}update_manager.git_branch{% endtrans %}
@@ -113,35 +99,25 @@
{% endif %}
- {% if is_docker %}
- {# Docker: show Watchtower status #}
-
- {% trans %}update_manager.docker.watchtower_status{% endtrans %}
-
- {% if status.watchtower_configured|default(false) and status.watchtower_available|default(false) %}
-
- {% trans %}update_manager.docker.watchtower_connected{% endtrans %}
-
- {% elseif status.watchtower_configured|default(false) %}
-
- {% trans %}update_manager.docker.watchtower_unreachable_short{% endtrans %}
-
- {% else %}
-
- {% trans %}update_manager.docker.watchtower_not_configured{% endtrans %}
-
- {% endif %}
-
-
- {% else %}
- {# Git/other: show update readiness #}
-
- {% trans %}update_manager.auto_update_supported{% endtrans %}
-
- {{ helper.boolean_badge(status.can_auto_update) }}
-
-
- {% endif %}
+
+ {% trans %}update_manager.auto_update_supported{% endtrans %}
+
+ {{ helper.boolean_badge(status.can_auto_update) }}
+
+
+
+
+ {% trans %}update_manager.web_updates_allowed{% endtrans %}
+ {{ helper.boolean_badge(not web_updates_disabled) }}
+
+
+ {% trans %}update_manager.backup_restore_allowed{% endtrans %}
+ {{ helper.boolean_badge(not backup_restore_disabled) }}
+
+
+ {% trans %}update_manager.backup_download_allowed{% endtrans %}
+ {{ helper.boolean_badge(not backup_download_disabled) }}
+
@@ -182,63 +158,30 @@
{% if status.update_available and status.can_auto_update and validation.valid and not web_updates_disabled %}
- {% if is_docker %}
- {# Docker update via Watchtower #}
-
- {% else %}
- {# Git update #}
-
- {% endif %}
+
+
+
+ {% trans %}update_manager.create_backup{% endtrans %}
+
+
+
{% endif %}
{% if status.published_at %}
@@ -286,55 +229,12 @@
{# Non-auto-update installations info #}
{% if not status.can_auto_update %}
- {% if is_docker and not status.watchtower_configured|default(false) %}
- {# Docker without Watchtower - show setup instructions #}
-
-
-
-
{% trans %}update_manager.docker.setup_description{% endtrans %}
-
-
{% trans %}update_manager.docker.setup_step1{% endtrans %}
-
services:
- watchtower:
- image: containrrr/watchtower
- volumes:
- - /var/run/docker.sock:/var/run/docker.sock
- environment:
- - WATCHTOWER_HTTP_API_UPDATE=true
- - WATCHTOWER_HTTP_API_TOKEN=your-secret-token
- - WATCHTOWER_LABEL_ENABLE=true
- ports:
- - "8080:8080"
-
-
{% trans %}update_manager.docker.setup_step2{% endtrans %}
-
WATCHTOWER_API_URL=http://watchtower:8080
-WATCHTOWER_API_TOKEN=your-secret-token
-
-
-
- {% trans %}update_manager.docker.setup_network_hint{% endtrans %}
-
-
-
- {% elseif is_docker and status.watchtower_configured|default(false) and not status.watchtower_available|default(false) %}
- {# Docker with Watchtower configured but not reachable #}
-
-
- {% trans %}update_manager.docker.watchtower_unreachable_title{% endtrans %}
-
-
{% trans %}update_manager.docker.watchtower_unreachable_description{% endtrans %}
-
- {% else %}
- {# Other non-auto-update installations (ZIP, unknown) #}
-
-
- {% trans%}update_manager.cant_auto_update{% endtrans%}: {{ status.installation.type_name }}
-
-
{{ status.installation.update_instructions }}
-
- {% endif %}
+
+
+ {% trans%}update_manager.cant_auto_update{% endtrans%}: {{ status.installation.type_name }}
+
+
{{ status.installation.update_instructions }}
+
{% endif %}
@@ -377,9 +277,6 @@ WATCHTOWER_API_TOKEN=your-secret-token
{% if release.version != status.current_version and status.can_auto_update and validation.valid and not web_updates_disabled %}
- {% if is_docker %}
- {# Docker: version switching not supported, only update to latest via Watchtower #}
- {% else %}
- {% endif %}
{% endif %}
diff --git a/templates/bundles/TwigBundle/Exception/error.html.twig b/templates/bundles/TwigBundle/Exception/error.html.twig
index 936f5ca3..efdba462 100644
--- a/templates/bundles/TwigBundle/Exception/error.html.twig
+++ b/templates/bundles/TwigBundle/Exception/error.html.twig
@@ -17,7 +17,7 @@
Consider yourself lucky. You found some rare error code. You should maybe inform your administrator about it...
{% endblock %}
- {% block further_actions %}You can try to Go Back or Visit the homepage .
{% endblock %}
+ {% block further_actions %}You can try to Go Back or Visit the homepage .
{% endblock %}
{% block admin_contact %}If this error persists, please contact your
{% if error_page_admin_email is not empty %}
administrator.
diff --git a/tests/Services/System/WatchtowerClientTest.php b/tests/Services/System/WatchtowerClientTest.php
deleted file mode 100644
index 1de4bd2c..00000000
--- a/tests/Services/System/WatchtowerClientTest.php
+++ /dev/null
@@ -1,197 +0,0 @@
-.
- */
-
-declare(strict_types=1);
-
-namespace App\Tests\Services\System;
-
-use App\Services\System\WatchtowerClient;
-use PHPUnit\Framework\TestCase;
-use Psr\Log\NullLogger;
-use Symfony\Contracts\HttpClient\HttpClientInterface;
-use Symfony\Contracts\HttpClient\ResponseInterface;
-
-final class WatchtowerClientTest extends TestCase
-{
- private function createClient(string $url = 'http://watchtower:8080', string $token = 'test-token', ?HttpClientInterface $httpClient = null): WatchtowerClient
- {
- return new WatchtowerClient(
- $httpClient ?? $this->createMock(HttpClientInterface::class),
- new NullLogger(),
- $url,
- $token,
- );
- }
-
- public function testIsConfiguredReturnsTrueWhenBothSet(): void
- {
- $client = $this->createClient('http://watchtower:8080', 'my-token');
- $this->assertTrue($client->isConfigured());
- }
-
- public function testIsConfiguredReturnsFalseWhenUrlEmpty(): void
- {
- $client = $this->createClient('', 'my-token');
- $this->assertFalse($client->isConfigured());
- }
-
- public function testIsConfiguredReturnsFalseWhenTokenEmpty(): void
- {
- $client = $this->createClient('http://watchtower:8080', '');
- $this->assertFalse($client->isConfigured());
- }
-
- public function testIsConfiguredReturnsFalseWhenBothEmpty(): void
- {
- $client = $this->createClient('', '');
- $this->assertFalse($client->isConfigured());
- }
-
- public function testIsAvailableReturnsFalseWhenNotConfigured(): void
- {
- $client = $this->createClient('', '');
- $this->assertFalse($client->isAvailable());
- }
-
- public function testIsAvailableReturnsTrueOnSuccessResponse(): void
- {
- $response = $this->createMock(ResponseInterface::class);
- $response->method('getStatusCode')->willReturn(200);
-
- $httpClient = $this->createMock(HttpClientInterface::class);
- $httpClient->expects($this->once())
- ->method('request')
- ->with('GET', 'http://watchtower:8080/v1/update', $this->callback(function (array $options) {
- return $options['headers']['Authorization'] === 'Bearer test-token'
- && $options['timeout'] === 3;
- }))
- ->willReturn($response);
-
- $client = $this->createClient('http://watchtower:8080', 'test-token', $httpClient);
- $this->assertTrue($client->isAvailable());
- }
-
- public function testIsAvailableReturnsTrueOn401(): void
- {
- $response = $this->createMock(ResponseInterface::class);
- $response->method('getStatusCode')->willReturn(401);
-
- $httpClient = $this->createMock(HttpClientInterface::class);
- $httpClient->method('request')->willReturn($response);
-
- $client = $this->createClient('http://watchtower:8080', 'test-token', $httpClient);
- $this->assertTrue($client->isAvailable());
- }
-
- public function testIsAvailableReturnsFalseOn500(): void
- {
- $response = $this->createMock(ResponseInterface::class);
- $response->method('getStatusCode')->willReturn(500);
-
- $httpClient = $this->createMock(HttpClientInterface::class);
- $httpClient->method('request')->willReturn($response);
-
- $client = $this->createClient('http://watchtower:8080', 'test-token', $httpClient);
- $this->assertFalse($client->isAvailable());
- }
-
- public function testIsAvailableReturnsFalseOnException(): void
- {
- $httpClient = $this->createMock(HttpClientInterface::class);
- $httpClient->method('request')->willThrowException(new \RuntimeException('Connection refused'));
-
- $client = $this->createClient('http://watchtower:8080', 'test-token', $httpClient);
- $this->assertFalse($client->isAvailable());
- }
-
- public function testTriggerUpdateThrowsWhenNotConfigured(): void
- {
- $client = $this->createClient('', '');
- $this->expectException(\RuntimeException::class);
- $this->expectExceptionMessage('Watchtower is not configured');
- $client->triggerUpdate();
- }
-
- public function testTriggerUpdateReturnsTrueOnSuccess(): void
- {
- $response = $this->createMock(ResponseInterface::class);
- $response->method('getStatusCode')->willReturn(200);
-
- $httpClient = $this->createMock(HttpClientInterface::class);
- $httpClient->expects($this->once())
- ->method('request')
- ->with('POST', 'http://watchtower:8080/v1/update', $this->callback(function (array $options) {
- return $options['headers']['Authorization'] === 'Bearer test-token'
- && $options['timeout'] === 10;
- }))
- ->willReturn($response);
-
- $client = $this->createClient('http://watchtower:8080', 'test-token', $httpClient);
- $this->assertTrue($client->triggerUpdate());
- }
-
- public function testTriggerUpdateReturnsTrueOn202(): void
- {
- $response = $this->createMock(ResponseInterface::class);
- $response->method('getStatusCode')->willReturn(202);
-
- $httpClient = $this->createMock(HttpClientInterface::class);
- $httpClient->method('request')->willReturn($response);
-
- $client = $this->createClient('http://watchtower:8080', 'test-token', $httpClient);
- $this->assertTrue($client->triggerUpdate());
- }
-
- public function testTriggerUpdateReturnsFalseOnServerError(): void
- {
- $response = $this->createMock(ResponseInterface::class);
- $response->method('getStatusCode')->willReturn(500);
-
- $httpClient = $this->createMock(HttpClientInterface::class);
- $httpClient->method('request')->willReturn($response);
-
- $client = $this->createClient('http://watchtower:8080', 'test-token', $httpClient);
- $this->assertFalse($client->triggerUpdate());
- }
-
- public function testTriggerUpdateReturnsFalseOnException(): void
- {
- $httpClient = $this->createMock(HttpClientInterface::class);
- $httpClient->method('request')->willThrowException(new \RuntimeException('Network error'));
-
- $client = $this->createClient('http://watchtower:8080', 'test-token', $httpClient);
- $this->assertFalse($client->triggerUpdate());
- }
-
- public function testUrlTrailingSlashIsNormalized(): void
- {
- $response = $this->createMock(ResponseInterface::class);
- $response->method('getStatusCode')->willReturn(200);
-
- $httpClient = $this->createMock(HttpClientInterface::class);
- $httpClient->expects($this->once())
- ->method('request')
- ->with('GET', 'http://watchtower:8080/v1/update', $this->anything())
- ->willReturn($response);
-
- $client = $this->createClient('http://watchtower:8080/', 'test-token', $httpClient);
- $client->isAvailable();
- }
-}
diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf
index d5f5c183..1a37106f 100644
--- a/translations/messages.en.xlf
+++ b/translations/messages.en.xlf
@@ -13055,312 +13055,6 @@ Buerklin-API Authentication server:
Backup download allowed
-
-
- update_manager.docker.setup_title
- Enable One-Click Docker Updates with Watchtower
-
-
-
-
- update_manager.docker.setup_description
- Part-DB can update your Docker container automatically using Watchtower, an open-source container updater. Add Watchtower as a companion container and configure the connection below.
-
-
-
-
- update_manager.docker.setup_step1
- 1. Add Watchtower to your docker-compose.yml:
-
-
-
-
- update_manager.docker.setup_step2
- 2. Add these environment variables to your Part-DB container:
-
-
-
-
- update_manager.docker.setup_network_hint
- Make sure Part-DB and Watchtower are on the same Docker network. If you use label-based filtering in Watchtower (WATCHTOWER_LABEL_ENABLE=true), add the label "com.centurylinklabs.watchtower.enable=true" to your Part-DB container.
-
-
-
-
- update_manager.docker.watchtower_unreachable_title
- Watchtower Not Reachable
-
-
-
-
- update_manager.docker.watchtower_unreachable_description
- Watchtower is configured but cannot be reached. Please verify that the Watchtower container is running and that the API URL and token are correct.
-
-
-
-
- update_manager.docker.confirm_update
- Are you sure you want to update Part-DB via Watchtower? The container will be restarted with the new image. Unlike Git updates, Docker updates cannot be automatically rolled back.
-
-
-
-
- update_manager.docker.update_via_watchtower
- Update via Watchtower to
-
-
-
-
- update_manager.docker.no_rollback_warning
- Docker updates cannot be automatically rolled back. A database backup will be created before updating so you can restore your data if needed.
-
-
-
-
- update_manager.docker.progress_title
- Docker Update in Progress
-
-
-
-
- update_manager.docker.waiting_for_watchtower
- Waiting for Watchtower to pull the new image...
-
-
-
-
- update_manager.docker.elapsed
- Elapsed
-
-
-
-
- update_manager.docker.waiting_title
- Update Triggered
-
-
-
-
- update_manager.docker.waiting_description
- Watchtower has been notified. It will pull the latest Docker image and restart the Part-DB container.
-
-
-
-
- update_manager.docker.watchtower_working
- Watchtower is processing the update...
-
-
-
-
- update_manager.docker.watchtower_working_hint
- This may take a few minutes depending on your internet speed and image size.
-
-
-
-
- update_manager.docker.restarting_title
- Container Restarting
-
-
-
-
- update_manager.docker.restarting_description
- Watchtower has pulled the new image and is restarting the Part-DB container.
-
-
-
-
- update_manager.docker.restarting_hint
- The page will automatically detect when the server comes back online. This usually takes 10-30 seconds.
-
-
-
-
- update_manager.docker.success_title
- Update Complete!
-
-
-
-
- update_manager.docker.success_message
- Part-DB has been successfully updated via Watchtower.
-
-
-
-
- update_manager.docker.previous_version
- Previous version
-
-
-
-
- update_manager.docker.new_version
- New version
-
-
-
-
- update_manager.docker.back_to_update_manager
- Back to Update Manager
-
-
-
-
- update_manager.docker.go_to_homepage
- Go to Homepage
-
-
-
-
- update_manager.docker.timeout_title
- Update Taking Longer Than Expected
-
-
-
-
- update_manager.docker.timeout_message
- The update is taking longer than expected. Check the Watchtower container logs for details. The update may still be in progress.
-
-
-
-
- update_manager.docker.retry
- Retry
-
-
-
-
- update_manager.docker.warning
- Warning
-
-
-
-
- update_manager.docker.do_not_close
- Do not close this page. It will automatically detect when the update is complete.
-
-
-
-
- update_manager.docker.updating_via_watchtower
- Updating via Watchtower
-
-
-
-
- update_manager.docker.step_waiting
- Pulling Image
-
-
-
-
- update_manager.docker.steps
- Update Steps
-
-
-
-
- update_manager.docker.step_trigger
- Trigger Update
-
-
-
-
- update_manager.docker.step_trigger_desc
- Watchtower has been notified to check for updates
-
-
-
-
- update_manager.docker.step_pull
- Pull New Image
-
-
-
-
- update_manager.docker.step_pull_desc
- Downloading the latest Docker image from the registry
-
-
-
-
- update_manager.docker.step_restart
- Restart Container
-
-
-
-
- update_manager.docker.step_restart_desc
- Stopping old container and starting new one
-
-
-
-
- update_manager.docker.step_verify
- Verify
-
-
-
-
- update_manager.docker.step_verify_desc
- Confirming Part-DB is running on the new version
-
-
-
-
- update_manager.docker.watchtower_status
- Watchtower
-
-
-
-
- update_manager.docker.watchtower_connected
- Connected
-
-
-
-
- update_manager.docker.watchtower_unreachable_short
- Unreachable
-
-
-
-
- update_manager.docker.watchtower_not_configured
- Not configured
-
-
-
-
- update_manager.docker.step_stop
- Stop Container
-
-
-
-
- update_manager.docker.step_stop_desc
- Gracefully stopping the current container before recreation
-
-
-
-
- update_manager.docker.step_health
- Health Check
-
-
-
-
- update_manager.docker.step_health_desc
- Waiting for the new container to pass health checks
-
-
-
-
- update_manager.docker.updating
- Updating Part-DB via Docker...
-
-
part.create_from_info_provider.lot_filled_from_barcode