diff --git a/openwisp_firmware_upgrader/admin.py b/openwisp_firmware_upgrader/admin.py
index c8acbf4..cb12306 100644
--- a/openwisp_firmware_upgrader/admin.py
+++ b/openwisp_firmware_upgrader/admin.py
@@ -20,7 +20,7 @@
from django.utils.translation import gettext_lazy as _
from reversion.admin import VersionAdmin
-from openwisp_controller.config.admin import DeviceAdmin
+from openwisp_controller.config.admin import DeactivatedDeviceReadOnlyMixin, DeviceAdmin
from openwisp_users.multitenancy import MultitenantAdminMixin, MultitenantOrgFilter
from openwisp_utils.admin import ReadOnlyAdmin, TimeReadonlyAdminMixin
@@ -402,7 +402,9 @@ def get_form_kwargs(self, index):
return kwargs
-class DeviceFirmwareInline(MultitenantAdminMixin, admin.StackedInline):
+class DeviceFirmwareInline(
+ MultitenantAdminMixin, DeactivatedDeviceReadOnlyMixin, admin.StackedInline
+):
model = DeviceFirmware
formset = DeviceFormSet
form = DeviceFirmwareForm
diff --git a/openwisp_firmware_upgrader/tests/test_admin.py b/openwisp_firmware_upgrader/tests/test_admin.py
index 174b6d9..a13c1e1 100644
--- a/openwisp_firmware_upgrader/tests/test_admin.py
+++ b/openwisp_firmware_upgrader/tests/test_admin.py
@@ -343,6 +343,35 @@ def test_device_firmware_upgrade_without_device_connection(
mocked_func.assert_not_called()
self.assertEqual(response.status_code, 200)
+ def test_deactivated_firmware_image_inline(self):
+ self._login()
+ device = self._create_config(organization=self._get_org()).device
+ device.deactivate()
+ response = self.client.get(
+ reverse('admin:config_device_change', args=[device.id])
+ )
+ # Check that it is not possible to add a DeviceFirmwareImage to a
+ # deactivated device in the admin interface.
+ self.assertContains(
+ response,
+ '',
+ )
+ self._create_device_firmware(device=device)
+ response = self.client.get(
+ reverse('admin:config_device_change', args=[device.id])
+ )
+ # Ensure that a deactivated device's existing DeviceFirmwareImage
+ # is displayed as readonly in the admin interface.
+ self.assertContains(
+ response,
+ 'div class="readonly">Test Category v0.1: TP-Link WDR4300 v1 (OpenWRT 19.07 and later)',
+ )
+ self.assertNotContains(
+ response,
+ '