fix: respect disabled update check setting (#367)

Backend /updates/check endpoint now returns early without calling
GitHub API when check_updates is disabled. Settings page no longer
auto-fetches update status when the setting is off. Printer card
firmware badge falls back to showing the current version from MQTT
instead of disappearing when firmware update checks are disabled.
This commit is contained in:
maziggy
2026-02-15 10:09:22 +01:00
parent e1b3329b68
commit 259c7eaa43
8 changed files with 411 additions and 392 deletions
+1
View File
@@ -16,6 +16,7 @@ All notable changes to Bambuddy will be documented in this file.
- **K-Profiles View — Accurate Filament Name Resolution** — K-profile filament names are now resolved from builtin filament tables and user cloud presets (via new `/cloud/filament-id-map` endpoint) instead of showing raw IDs like "GFU99" or "P4d64437". Falls back to extracting names from the profile name field.
### Fixed
- **Update Check Runs When Disabled** ([#367](https://github.com/maziggy/bambuddy/issues/367)) — The Settings page triggered an update check on every visit even when "Check for updates" was disabled, causing error popups on air-gapped systems with no internet. The backend `/updates/check` endpoint also ignored the setting entirely. Now the backend returns early without making GitHub API calls when the setting is disabled, the Settings page respects the `check_updates` flag before auto-fetching, and the printer card firmware badge shows a neutral version-only display instead of disappearing when firmware update checks are off.
- **Stale Inventory Assignments Persist After Switching to Spoolman Mode** — When switching from built-in inventory to Spoolman mode, existing spool-to-AMS-slot assignments were not cleaned up. The printer card hover cards continued showing "Assign Spool" buttons that opened the internal inventory modal, and any prior assignments remained visible. Now bulk-deletes all `SpoolAssignment` records when enabling Spoolman, invalidates the frontend cache so printer cards update immediately, and hides the inventory assign/unassign UI on printer cards while in Spoolman mode.
- **Bulk Archive Delete Leaves Orphaned Database Records** — When bulk-deleting archives, the files were removed from disk before the database commit. If concurrent SQLite writes caused a lock timeout, the commit failed and rolled back — leaving database records pointing to deleted files (broken thumbnails, 404 errors). Fixed by deleting the database record first and only removing files after a successful commit.
- **Model-Specific Maintenance Tasks for Carbon Rods vs Linear Rails** ([#351](https://github.com/maziggy/bambuddy/issues/351)) — Maintenance tasks "Clean Carbon Rods" and "Lubricate Linear Rails" were shown for all printers regardless of motion system. H2 and A1 series use linear rails (not carbon rods), and X1/P1/P2S series use carbon rods (not linear rails). Maintenance types are now classified by rod/rail type: "Lubricate Carbon Rods" and "Clean Carbon Rods" for X1/P1/P2S, "Lubricate Linear Rails" and "Clean Linear Rails" for A1/H2. Stale and duplicate system types are automatically cleaned up on startup. Includes model-specific wiki links and i18n keys for all 4 locales.
+13
View File
@@ -9,12 +9,14 @@ import sys
import httpx
from fastapi import APIRouter, BackgroundTasks, Depends
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from backend.app.core.auth import RequirePermissionIfAuthEnabled
from backend.app.core.config import APP_VERSION, GITHUB_REPO, settings
from backend.app.core.database import get_db
from backend.app.core.permissions import Permission
from backend.app.models.settings import Settings
from backend.app.models.user import User
logger = logging.getLogger(__name__)
@@ -176,6 +178,17 @@ async def check_for_updates(
"""Check GitHub for available updates."""
global _update_status
# Respect the check_updates setting
result = await db.execute(select(Settings).where(Settings.key == "check_updates"))
setting = result.scalar_one_or_none()
if setting and setting.value.lower() == "false":
return {
"update_available": False,
"current_version": APP_VERSION,
"latest_version": None,
"message": "Update checks are disabled",
}
_update_status = {
"status": "checking",
"progress": 0,
+1
View File
@@ -249,6 +249,7 @@ export interface PrinterStatus {
big_fan1_speed: number | null; // Auxiliary fan
big_fan2_speed: number | null; // Chamber/exhaust fan
heatbreak_fan_speed: number | null; // Hotend heatbreak fan
firmware_version: string | null; // Firmware version from MQTT
}
export interface PrinterCreate {
+6 -2
View File
@@ -2283,7 +2283,7 @@ function PrinterCard({
</button>
)}
{/* Firmware Version Badge */}
{firmwareInfo?.current_version && firmwareInfo?.latest_version && (
{checkPrinterFirmware && firmwareInfo?.current_version && firmwareInfo?.latest_version ? (
<button
onClick={() => setShowFirmwareModal(true)}
className={`flex items-center gap-1 px-2 py-1 rounded-full text-xs hover:opacity-80 transition-opacity ${
@@ -2300,7 +2300,11 @@ function PrinterCard({
{firmwareInfo.update_available ? <Download className="w-3 h-3" /> : <CheckCircle className="w-3 h-3" />}
{firmwareInfo.current_version}
</button>
)}
) : status?.firmware_version ? (
<span className="flex items-center gap-1 px-2 py-1 rounded-full text-xs bg-bambu-dark-tertiary/50 text-bambu-gray">
{status.firmware_version}
</span>
) : null}
</div>
)}
</div>
+1
View File
@@ -285,6 +285,7 @@ export function SettingsPage() {
const { data: updateCheck, refetch: refetchUpdateCheck, isRefetching: isCheckingUpdate } = useQuery({
queryKey: ['updateCheck'],
queryFn: api.checkForUpdates,
enabled: settings?.check_updates !== false,
staleTime: 5 * 60 * 1000,
});
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -23,8 +23,8 @@
<!-- Splash screens for iOS -->
<link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
<script type="module" crossorigin src="/assets/index-CwWjVtap.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-C0Wzgyzo.css">
<script type="module" crossorigin src="/assets/index-C9JxyacH.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-OqmBOPoC.css">
</head>
<body>
<div id="root"></div>