Browse Source

Fix P2S showing carbon rod maintenance tasks (#640)

  P2S uses hardened steel rods, not carbon fiber. Move P2S from
  carbon rod classification to new steel_rod category with its own
  "Lubricate Steel Rods" / "Clean Steel Rods" maintenance tasks.
maziggy 2 months ago
parent
commit
d55585a73f

+ 1 - 0
CHANGELOG.md

@@ -12,6 +12,7 @@ All notable changes to Bambuddy will be documented in this file.
 - **Separate Permission for AMS Spool Assignments** ([#635](https://github.com/maziggy/bambuddy/issues/635)) — Added a new `inventory:view_assignments` permission that controls whether spool-to-AMS-slot assignment data is visible on the Printers page. Previously, viewing spool assignments on printer cards required `inventory:read`, which also exposed the full Inventory page in the sidebar. Admins can now grant `inventory:view_assignments` without `inventory:read` so users can see what's loaded in the AMS without accessing the full spool inventory. All default groups (Administrators, Operators, Viewers) include the new permission automatically. Also fixed multi-word permission labels in the group editor (e.g. "Update_Own" → "Update Own"). Reported by @Minebuddy.
 - **Separate Permission for AMS Spool Assignments** ([#635](https://github.com/maziggy/bambuddy/issues/635)) — Added a new `inventory:view_assignments` permission that controls whether spool-to-AMS-slot assignment data is visible on the Printers page. Previously, viewing spool assignments on printer cards required `inventory:read`, which also exposed the full Inventory page in the sidebar. Admins can now grant `inventory:view_assignments` without `inventory:read` so users can see what's loaded in the AMS without accessing the full spool inventory. All default groups (Administrators, Operators, Viewers) include the new permission automatically. Also fixed multi-word permission labels in the group editor (e.g. "Update_Own" → "Update Own"). Reported by @Minebuddy.
 
 
 ### Fixed
 ### Fixed
+- **P2S Shows Carbon Rod Maintenance Tasks** ([#640](https://github.com/maziggy/bambuddy/issues/640)) — The P2S was incorrectly classified as a carbon rod printer, showing "Lubricate Carbon Rods" and "Clean Carbon Rods" maintenance tasks. The P2S uses hardened steel linear shafts, not carbon fiber rods. Added a new `steel_rod` motion system category and "Lubricate Steel Rods" / "Clean Steel Rods" maintenance tasks specific to the P2S. X1/P1 series continue to show carbon rod tasks; A1/H2 series continue to show linear rail tasks. Reported by @maziggy.
 - **Dispatch Toast Stuck After Second Print** — The print dispatch progress toast ("Starting prints…") stayed visible forever after the second print dispatch in a session. The dedup guard (`lastDispatchSummaryRef`) that prevents duplicate completion toasts was never reset between batches, so every single-printer dispatch produced the same summary key (`"first-complete:1:0"`). The first print completed normally, but subsequent completions matched the stale ref and skipped creating the done toast — leaving the progress toast stuck in "Processing" state with no way to dismiss except a page reload. Now resets the dedup guard whenever the dispatch toast is dismissed (auto-dismiss timeout, cleanup events) and when a new batch starts.
 - **Dispatch Toast Stuck After Second Print** — The print dispatch progress toast ("Starting prints…") stayed visible forever after the second print dispatch in a session. The dedup guard (`lastDispatchSummaryRef`) that prevents duplicate completion toasts was never reset between batches, so every single-printer dispatch produced the same summary key (`"first-complete:1:0"`). The first print completed normally, but subsequent completions matched the stale ref and skipped creating the done toast — leaving the progress toast stuck in "Processing" state with no way to dismiss except a page reload. Now resets the dedup guard whenever the dispatch toast is dismissed (auto-dismiss timeout, cleanup events) and when a new batch starts.
 
 
 ## [0.2.2b2] - 2026-03-06
 ## [0.2.2b2] - 2026-03-06

+ 18 - 3
backend/app/api/routes/maintenance.py

@@ -34,7 +34,7 @@ router = APIRouter(prefix="/maintenance", tags=["maintenance"])
 
 
 # Default maintenance types
 # Default maintenance types
 DEFAULT_MAINTENANCE_TYPES = [
 DEFAULT_MAINTENANCE_TYPES = [
-    # Carbon rod models only (X1/P1/P2S)
+    # Carbon rod models only (X1/P1)
     {
     {
         "name": "Lubricate Carbon Rods",
         "name": "Lubricate Carbon Rods",
         "description": "Apply lubricant to carbon rods for smooth motion",
         "description": "Apply lubricant to carbon rods for smooth motion",
@@ -47,6 +47,19 @@ DEFAULT_MAINTENANCE_TYPES = [
         "default_interval_hours": 100.0,
         "default_interval_hours": 100.0,
         "icon": "Sparkles",
         "icon": "Sparkles",
     },
     },
+    # Steel rod models only (P2S)
+    {
+        "name": "Lubricate Steel Rods",
+        "description": "Apply lubricant to steel rods for smooth motion",
+        "default_interval_hours": 50.0,
+        "icon": "Droplet",
+    },
+    {
+        "name": "Clean Steel Rods",
+        "description": "Wipe steel rods with a dry cloth",
+        "default_interval_hours": 100.0,
+        "icon": "Sparkles",
+    },
     # Linear rail models only (A1/H2)
     # Linear rail models only (A1/H2)
     {
     {
         "name": "Lubricate Linear Rails",
         "name": "Lubricate Linear Rails",
@@ -88,11 +101,13 @@ DEFAULT_MAINTENANCE_TYPES = [
 ]
 ]
 
 
 # System types that only apply to printers with a specific rod/rail type.
 # System types that only apply to printers with a specific rod/rail type.
-# "carbon" = X1/P1/P2S series (carbon rods), "linear_rail" = A1/H2 series.
-# Types not listed here apply to all printers.
+# "carbon" = X1/P1 series (carbon rods), "steel_rod" = P2S (steel rods),
+# "linear_rail" = A1/H2 series. Types not listed here apply to all printers.
 _ROD_TYPE_REQUIREMENTS: dict[str, str] = {
 _ROD_TYPE_REQUIREMENTS: dict[str, str] = {
     "Lubricate Carbon Rods": "carbon",
     "Lubricate Carbon Rods": "carbon",
     "Clean Carbon Rods": "carbon",
     "Clean Carbon Rods": "carbon",
+    "Lubricate Steel Rods": "steel_rod",
+    "Clean Steel Rods": "steel_rod",
     "Lubricate Linear Rails": "linear_rail",
     "Lubricate Linear Rails": "linear_rail",
     "Clean Linear Rails": "linear_rail",
     "Clean Linear Rails": "linear_rail",
 }
 }

+ 14 - 3
backend/app/utils/printer_models.py

@@ -50,7 +50,8 @@ PRINTER_MODEL_ID_MAP = {
 
 
 
 
 # Rod/rail type classification for maintenance tasks.
 # Rod/rail type classification for maintenance tasks.
-# Carbon rods: X1, P1, P2S series (CoreXY with carbon fiber rods)
+# Carbon rods: X1, P1 series (CoreXY with carbon fiber rods)
+# Steel rods: P2S series (hardened steel linear shafts)
 # Linear rails: A1, H2 series (linear rail motion system)
 # Linear rails: A1, H2 series (linear rail motion system)
 # Values must be uppercase with spaces stripped for normalized comparison.
 # Values must be uppercase with spaces stripped for normalized comparison.
 CARBON_ROD_MODELS = frozenset(
 CARBON_ROD_MODELS = frozenset(
@@ -61,11 +62,18 @@ CARBON_ROD_MODELS = frozenset(
         "X1E",
         "X1E",
         "P1P",
         "P1P",
         "P1S",
         "P1S",
-        "P2S",
         # Internal codes
         # Internal codes
         "C11",  # X1C
         "C11",  # X1C
         "C12",  # X1
         "C12",  # X1
         "C13",  # X1E
         "C13",  # X1E
+    ]
+)
+
+STEEL_ROD_MODELS = frozenset(
+    [
+        # Display names (uppercase, no spaces)
+        "P2S",
+        # Internal codes
         "N7",  # P2S
         "N7",  # P2S
     ]
     ]
 )
 )
@@ -99,7 +107,8 @@ def get_rod_type(model: str | None) -> str | None:
     """Return the rod/rail type for a printer model.
     """Return the rod/rail type for a printer model.
 
 
     Returns:
     Returns:
-        "carbon" for X1/P1/P2S series (carbon fiber rods),
+        "carbon" for X1/P1 series (carbon fiber rods),
+        "steel_rod" for P2S series (hardened steel rods),
         "linear_rail" for A1/H2 series (linear rails),
         "linear_rail" for A1/H2 series (linear rails),
         None for unknown models.
         None for unknown models.
     """
     """
@@ -108,6 +117,8 @@ def get_rod_type(model: str | None) -> str | None:
     normalized = model.strip().upper().replace(" ", "").replace("-", "")
     normalized = model.strip().upper().replace(" ", "").replace("-", "")
     if normalized in CARBON_ROD_MODELS:
     if normalized in CARBON_ROD_MODELS:
         return "carbon"
         return "carbon"
+    if normalized in STEEL_ROD_MODELS:
+        return "steel_rod"
     if normalized in LINEAR_RAIL_MODELS:
     if normalized in LINEAR_RAIL_MODELS:
         return "linear_rail"
         return "linear_rail"
     return None
     return None

+ 56 - 0
backend/tests/unit/test_maintenance_rod_filtering.py

@@ -0,0 +1,56 @@
+"""Unit tests for maintenance rod-type filtering logic."""
+
+import pytest
+
+from backend.app.api.routes.maintenance import _should_apply_to_printer
+
+
+class TestShouldApplyToPrinter:
+    """Tests for _should_apply_to_printer() model-specific filtering."""
+
+    # Carbon rod tasks should only apply to X1/P1 models
+    @pytest.mark.parametrize("model", ["X1C", "X1", "X1E", "P1P", "P1S"])
+    def test_carbon_rod_tasks_apply_to_carbon_models(self, model: str):
+        assert _should_apply_to_printer("Lubricate Carbon Rods", model) is True
+        assert _should_apply_to_printer("Clean Carbon Rods", model) is True
+
+    def test_carbon_rod_tasks_do_not_apply_to_p2s(self):
+        """P2S has steel rods, not carbon rods (#640)."""
+        assert _should_apply_to_printer("Lubricate Carbon Rods", "P2S") is False
+        assert _should_apply_to_printer("Clean Carbon Rods", "P2S") is False
+
+    def test_carbon_rod_tasks_do_not_apply_to_a1(self):
+        assert _should_apply_to_printer("Lubricate Carbon Rods", "A1") is False
+
+    # Steel rod tasks should only apply to P2S
+    def test_steel_rod_tasks_apply_to_p2s(self):
+        assert _should_apply_to_printer("Lubricate Steel Rods", "P2S") is True
+        assert _should_apply_to_printer("Clean Steel Rods", "P2S") is True
+
+    def test_steel_rod_tasks_do_not_apply_to_x1c(self):
+        assert _should_apply_to_printer("Lubricate Steel Rods", "X1C") is False
+        assert _should_apply_to_printer("Clean Steel Rods", "X1C") is False
+
+    def test_steel_rod_tasks_do_not_apply_to_a1(self):
+        assert _should_apply_to_printer("Lubricate Steel Rods", "A1") is False
+
+    # Linear rail tasks should only apply to A1/H2 models
+    @pytest.mark.parametrize("model", ["A1", "A1 Mini", "H2D", "H2C", "H2S"])
+    def test_linear_rail_tasks_apply_to_rail_models(self, model: str):
+        assert _should_apply_to_printer("Lubricate Linear Rails", model) is True
+        assert _should_apply_to_printer("Clean Linear Rails", model) is True
+
+    def test_linear_rail_tasks_do_not_apply_to_p2s(self):
+        assert _should_apply_to_printer("Lubricate Linear Rails", "P2S") is False
+
+    # Universal tasks apply to all models
+    @pytest.mark.parametrize("model", ["X1C", "P2S", "A1", "H2D"])
+    def test_universal_tasks_apply_to_all(self, model: str):
+        assert _should_apply_to_printer("Clean Nozzle/Hotend", model) is True
+        assert _should_apply_to_printer("Check Belt Tension", model) is True
+
+    # Unknown models default to carbon (legacy behavior)
+    def test_unknown_model_defaults_to_carbon(self):
+        assert _should_apply_to_printer("Lubricate Carbon Rods", "UNKNOWN") is True
+        assert _should_apply_to_printer("Lubricate Steel Rods", "UNKNOWN") is False
+        assert _should_apply_to_printer("Lubricate Linear Rails", "UNKNOWN") is False

+ 48 - 0
backend/tests/unit/test_printer_models.py

@@ -0,0 +1,48 @@
+"""Unit tests for printer model utilities."""
+
+import pytest
+
+from backend.app.utils.printer_models import get_rod_type
+
+
+class TestGetRodType:
+    """Tests for get_rod_type() rod/rail classification."""
+
+    @pytest.mark.parametrize("model", ["X1C", "X1", "X1E", "P1P", "P1S"])
+    def test_carbon_rod_models(self, model: str):
+        assert get_rod_type(model) == "carbon"
+
+    @pytest.mark.parametrize("model", ["C11", "C12", "C13"])
+    def test_carbon_rod_internal_codes(self, model: str):
+        assert get_rod_type(model) == "carbon"
+
+    def test_p2s_is_steel_rod(self):
+        """P2S uses hardened steel rods, not carbon rods (#640)."""
+        assert get_rod_type("P2S") == "steel_rod"
+
+    def test_p2s_internal_code_is_steel_rod(self):
+        """N7 (P2S internal code) uses steel rods."""
+        assert get_rod_type("N7") == "steel_rod"
+
+    @pytest.mark.parametrize("model", ["A1", "A1 Mini", "H2D", "H2D Pro", "H2C", "H2S"])
+    def test_linear_rail_models(self, model: str):
+        assert get_rod_type(model) == "linear_rail"
+
+    @pytest.mark.parametrize("model", ["N1", "N2S", "A11", "A12", "O1D", "O1E", "O2D", "O1C", "O1C2", "O1S"])
+    def test_linear_rail_internal_codes(self, model: str):
+        assert get_rod_type(model) == "linear_rail"
+
+    def test_unknown_model_returns_none(self):
+        assert get_rod_type("UNKNOWN") is None
+
+    def test_none_returns_none(self):
+        assert get_rod_type(None) is None
+
+    def test_case_insensitive(self):
+        assert get_rod_type("p2s") == "steel_rod"
+        assert get_rod_type("x1c") == "carbon"
+        assert get_rod_type("a1") == "linear_rail"
+
+    def test_strips_whitespace_and_dashes(self):
+        assert get_rod_type(" P2S ") == "steel_rod"
+        assert get_rod_type("A1-Mini") == "linear_rail"

+ 4 - 0
frontend/src/i18n/locales/de.ts

@@ -1138,6 +1138,8 @@ export default {
       checkCooling: 'Kühlungslüfter prüfen',
       checkCooling: 'Kühlungslüfter prüfen',
       generalInspection: 'Allgemeine Inspektion',
       generalInspection: 'Allgemeine Inspektion',
       cleanCarbonRods: 'Kohlenstoffstangen reinigen',
       cleanCarbonRods: 'Kohlenstoffstangen reinigen',
+      lubricateSteelRods: 'Stahlstangen schmieren',
+      cleanSteelRods: 'Stahlstangen reinigen',
       cleanLinearRails: 'Linearschienen reinigen',
       cleanLinearRails: 'Linearschienen reinigen',
       checkPtfeTube: 'PTFE-Schlauch prüfen',
       checkPtfeTube: 'PTFE-Schlauch prüfen',
       replaceHepaFilter: 'HEPA-Filter ersetzen',
       replaceHepaFilter: 'HEPA-Filter ersetzen',
@@ -3510,6 +3512,8 @@ export default {
     checkCooling: 'Sicherstellen, dass Lüfter ordnungsgemäß funktionieren',
     checkCooling: 'Sicherstellen, dass Lüfter ordnungsgemäß funktionieren',
     generalInspection: 'Allgemeine Druckerinspektion',
     generalInspection: 'Allgemeine Druckerinspektion',
     cleanCarbonRods: 'Karbonstäbe reinigen, um Reibung zu reduzieren',
     cleanCarbonRods: 'Karbonstäbe reinigen, um Reibung zu reduzieren',
+    lubricateSteelRods: 'Schmiermittel auf Stahlstangen für sanfte Bewegung auftragen',
+    cleanSteelRods: 'Stahlstangen reinigen, um Reibung zu reduzieren',
     cleanLinearRails: 'Linearschienen abwischen, um Staub und Schmutz zu entfernen',
     cleanLinearRails: 'Linearschienen abwischen, um Staub und Schmutz zu entfernen',
     checkPtfeTube: 'PTFE-Schlauch auf Verschleiß oder Beschädigung prüfen',
     checkPtfeTube: 'PTFE-Schlauch auf Verschleiß oder Beschädigung prüfen',
     replaceHepaFilter: 'HEPA-Filter für Luftqualität ersetzen',
     replaceHepaFilter: 'HEPA-Filter für Luftqualität ersetzen',

+ 4 - 0
frontend/src/i18n/locales/en.ts

@@ -1138,6 +1138,8 @@ export default {
       checkCooling: 'Check Cooling Fans',
       checkCooling: 'Check Cooling Fans',
       generalInspection: 'General Inspection',
       generalInspection: 'General Inspection',
       cleanCarbonRods: 'Clean Carbon Rods',
       cleanCarbonRods: 'Clean Carbon Rods',
+      lubricateSteelRods: 'Lubricate Steel Rods',
+      cleanSteelRods: 'Clean Steel Rods',
       cleanLinearRails: 'Clean Linear Rails',
       cleanLinearRails: 'Clean Linear Rails',
       checkPtfeTube: 'Check PTFE Tube',
       checkPtfeTube: 'Check PTFE Tube',
       replaceHepaFilter: 'Replace HEPA Filter',
       replaceHepaFilter: 'Replace HEPA Filter',
@@ -3515,6 +3517,8 @@ export default {
     checkCooling: 'Ensure cooling fans are working properly',
     checkCooling: 'Ensure cooling fans are working properly',
     generalInspection: 'General printer inspection',
     generalInspection: 'General printer inspection',
     cleanCarbonRods: 'Clean carbon rods to reduce friction',
     cleanCarbonRods: 'Clean carbon rods to reduce friction',
+    lubricateSteelRods: 'Apply lubricant to steel rods for smooth motion',
+    cleanSteelRods: 'Clean steel rods to reduce friction',
     cleanLinearRails: 'Wipe linear rails to remove dust and debris',
     cleanLinearRails: 'Wipe linear rails to remove dust and debris',
     checkPtfeTube: 'Inspect PTFE tube for wear or damage',
     checkPtfeTube: 'Inspect PTFE tube for wear or damage',
     replaceHepaFilter: 'Replace HEPA filter for air quality',
     replaceHepaFilter: 'Replace HEPA filter for air quality',

+ 4 - 0
frontend/src/i18n/locales/fr.ts

@@ -1138,6 +1138,8 @@ export default {
       checkCooling: 'Vérifier les ventilateurs',
       checkCooling: 'Vérifier les ventilateurs',
       generalInspection: 'Inspection générale',
       generalInspection: 'Inspection générale',
       cleanCarbonRods: 'Nettoyer les tiges carbone',
       cleanCarbonRods: 'Nettoyer les tiges carbone',
+      lubricateSteelRods: 'Lubrifier les tiges en acier',
+      cleanSteelRods: 'Nettoyer les tiges en acier',
       cleanLinearRails: 'Nettoyer les rails linéaires',
       cleanLinearRails: 'Nettoyer les rails linéaires',
       checkPtfeTube: 'Vérifier le tube PTFE',
       checkPtfeTube: 'Vérifier le tube PTFE',
       replaceHepaFilter: 'Remplacer le filtre HEPA',
       replaceHepaFilter: 'Remplacer le filtre HEPA',
@@ -3502,6 +3504,8 @@ export default {
     checkCooling: 'Bon fonctionnement des ventilateurs',
     checkCooling: 'Bon fonctionnement des ventilateurs',
     generalInspection: 'Inspection générale de la machine',
     generalInspection: 'Inspection générale de la machine',
     cleanCarbonRods: 'Nettoyer les tiges carbone (friction)',
     cleanCarbonRods: 'Nettoyer les tiges carbone (friction)',
+    lubricateSteelRods: 'Appliquer du lubrifiant sur les tiges en acier pour un mouvement fluide',
+    cleanSteelRods: 'Nettoyer les tiges en acier (friction)',
     cleanLinearRails: 'Essuyer les rails linéaires (poussière/débris)',
     cleanLinearRails: 'Essuyer les rails linéaires (poussière/débris)',
     checkPtfeTube: 'Usure ou dommage du tube PTFE',
     checkPtfeTube: 'Usure ou dommage du tube PTFE',
     replaceHepaFilter: 'Filtre HEPA pour la qualité de l\'air',
     replaceHepaFilter: 'Filtre HEPA pour la qualité de l\'air',

+ 4 - 0
frontend/src/i18n/locales/it.ts

@@ -1138,6 +1138,8 @@ export default {
       checkCooling: 'Controlla ventole raffreddamento',
       checkCooling: 'Controlla ventole raffreddamento',
       generalInspection: 'Ispezione generale',
       generalInspection: 'Ispezione generale',
       cleanCarbonRods: 'Pulisci aste in carbonio',
       cleanCarbonRods: 'Pulisci aste in carbonio',
+      lubricateSteelRods: 'Lubrifica aste in acciaio',
+      cleanSteelRods: 'Pulisci aste in acciaio',
       cleanLinearRails: 'Pulisci guide lineari',
       cleanLinearRails: 'Pulisci guide lineari',
       checkPtfeTube: 'Controlla tubo PTFE',
       checkPtfeTube: 'Controlla tubo PTFE',
       replaceHepaFilter: 'Sostituisci filtro HEPA',
       replaceHepaFilter: 'Sostituisci filtro HEPA',
@@ -3501,6 +3503,8 @@ export default {
     checkCooling: 'Assicurati che le ventole di raffreddamento funzionino',
     checkCooling: 'Assicurati che le ventole di raffreddamento funzionino',
     generalInspection: 'Ispezione generale stampante',
     generalInspection: 'Ispezione generale stampante',
     cleanCarbonRods: 'Pulisci le aste in carbonio per ridurre attrito',
     cleanCarbonRods: 'Pulisci le aste in carbonio per ridurre attrito',
+    lubricateSteelRods: 'Applica lubrificante alle aste in acciaio per un movimento fluido',
+    cleanSteelRods: 'Pulisci le aste in acciaio per ridurre attrito',
     cleanLinearRails: 'Pulisci le guide lineari per rimuovere polvere e detriti',
     cleanLinearRails: 'Pulisci le guide lineari per rimuovere polvere e detriti',
     checkPtfeTube: 'Ispeziona il tubo PTFE per usura o danni',
     checkPtfeTube: 'Ispeziona il tubo PTFE per usura o danni',
     replaceHepaFilter: 'Sostituisci filtro HEPA per qualità aria',
     replaceHepaFilter: 'Sostituisci filtro HEPA per qualità aria',

+ 4 - 0
frontend/src/i18n/locales/ja.ts

@@ -1138,6 +1138,8 @@ export default {
       checkCooling: '冷却ファンの確認',
       checkCooling: '冷却ファンの確認',
       generalInspection: '総合点検',
       generalInspection: '総合点検',
       cleanCarbonRods: 'カーボンロッドの清掃',
       cleanCarbonRods: 'カーボンロッドの清掃',
+      lubricateSteelRods: 'スチールロッドの潤滑',
+      cleanSteelRods: 'スチールロッドの清掃',
       cleanLinearRails: 'リニアレールの清掃',
       cleanLinearRails: 'リニアレールの清掃',
       checkPtfeTube: 'PTFEチューブの確認',
       checkPtfeTube: 'PTFEチューブの確認',
       replaceHepaFilter: 'HEPAフィルター交換',
       replaceHepaFilter: 'HEPAフィルター交換',
@@ -3515,6 +3517,8 @@ export default {
     checkCooling: '冷却ファンの確認',
     checkCooling: '冷却ファンの確認',
     generalInspection: '総合点検',
     generalInspection: '総合点検',
     cleanCarbonRods: 'カーボンロッドの清掃',
     cleanCarbonRods: 'カーボンロッドの清掃',
+    lubricateSteelRods: 'スチールロッドに潤滑剤を塗布してスムーズな動きを確保',
+    cleanSteelRods: 'スチールロッドの清掃',
     cleanLinearRails: 'リニアレールを拭いてほこりや汚れを除去',
     cleanLinearRails: 'リニアレールを拭いてほこりや汚れを除去',
     checkPtfeTube: 'PTFEチューブの確認',
     checkPtfeTube: 'PTFEチューブの確認',
     replaceHepaFilter: 'HEPAフィルター交換',
     replaceHepaFilter: 'HEPAフィルター交換',

+ 4 - 0
frontend/src/i18n/locales/pt-BR.ts

@@ -1138,6 +1138,8 @@ export default {
       checkCooling: 'Verificar Ventiladores de Resfriamento',
       checkCooling: 'Verificar Ventiladores de Resfriamento',
       generalInspection: 'Inspeção Geral',
       generalInspection: 'Inspeção Geral',
       cleanCarbonRods: 'Limpar Barras de Carbono',
       cleanCarbonRods: 'Limpar Barras de Carbono',
+      lubricateSteelRods: 'Lubrificar Barras de Aço',
+      cleanSteelRods: 'Limpar Barras de Aço',
       cleanLinearRails: 'Limpar Trilhos Lineares',
       cleanLinearRails: 'Limpar Trilhos Lineares',
       checkPtfeTube: 'Verificar Tubo PTFE',
       checkPtfeTube: 'Verificar Tubo PTFE',
       replaceHepaFilter: 'Substituir Filtro HEPA',
       replaceHepaFilter: 'Substituir Filtro HEPA',
@@ -3501,6 +3503,8 @@ export default {
     checkCooling: 'Verifique se os ventiladores de resfriamento estão funcionando corretamente',
     checkCooling: 'Verifique se os ventiladores de resfriamento estão funcionando corretamente',
     generalInspection: 'Inspeção geral da impressora',
     generalInspection: 'Inspeção geral da impressora',
     cleanCarbonRods: 'Limpe os eixos de carbono para reduzir o atrito',
     cleanCarbonRods: 'Limpe os eixos de carbono para reduzir o atrito',
+    lubricateSteelRods: 'Aplique lubrificante nas barras de aço para um movimento suave',
+    cleanSteelRods: 'Limpe as barras de aço para reduzir o atrito',
     cleanLinearRails: 'Limpe os trilhos lineares para remover poeira e detritos',
     cleanLinearRails: 'Limpe os trilhos lineares para remover poeira e detritos',
     checkPtfeTube: 'Verifique o tubo PTFE quanto ao desgaste ou danos',
     checkPtfeTube: 'Verifique o tubo PTFE quanto ao desgaste ou danos',
     replaceHepaFilter: 'Substitua o filtro HEPA para qualidade do ar',
     replaceHepaFilter: 'Substitua o filtro HEPA para qualidade do ar',

+ 4 - 0
frontend/src/i18n/locales/zh-CN.ts

@@ -1138,6 +1138,8 @@ export default {
       checkCooling: '检查冷却风扇',
       checkCooling: '检查冷却风扇',
       generalInspection: '综合检查',
       generalInspection: '综合检查',
       cleanCarbonRods: '清洁碳纤维杆',
       cleanCarbonRods: '清洁碳纤维杆',
+      lubricateSteelRods: '润滑钢杆',
+      cleanSteelRods: '清洁钢杆',
       cleanLinearRails: '清洁线性导轨',
       cleanLinearRails: '清洁线性导轨',
       checkPtfeTube: '检查 PTFE 管',
       checkPtfeTube: '检查 PTFE 管',
       replaceHepaFilter: '更换 HEPA 过滤器',
       replaceHepaFilter: '更换 HEPA 过滤器',
@@ -3501,6 +3503,8 @@ export default {
     checkCooling: '确保冷却风扇正常工作',
     checkCooling: '确保冷却风扇正常工作',
     generalInspection: '打印机综合检查',
     generalInspection: '打印机综合检查',
     cleanCarbonRods: '清洁碳纤维杆以减少摩擦',
     cleanCarbonRods: '清洁碳纤维杆以减少摩擦',
+    lubricateSteelRods: '在钢杆上涂抹润滑剂以确保顺畅运动',
+    cleanSteelRods: '清洁钢杆以减少摩擦',
     cleanLinearRails: '擦拭线性导轨以清除灰尘和碎屑',
     cleanLinearRails: '擦拭线性导轨以清除灰尘和碎屑',
     checkPtfeTube: '检查 PTFE 管的磨损或损坏',
     checkPtfeTube: '检查 PTFE 管的磨损或损坏',
     replaceHepaFilter: '更换 HEPA 过滤器以保证空气质量',
     replaceHepaFilter: '更换 HEPA 过滤器以保证空气质量',

+ 12 - 3
frontend/src/pages/MaintenancePage.tsx

@@ -142,9 +142,18 @@ function getMaintenanceWikiUrl(typeName: string, printerModel: string | null): s
 
 
   switch (typeName) {
   switch (typeName) {
     case 'Lubricate Carbon Rods':
     case 'Lubricate Carbon Rods':
-      // X1, P1, P2S series have carbon rods
+      // X1, P1 series have carbon rods
       if (isX1) return 'https://wiki.bambulab.com/en/x1/maintenance/basic-maintenance';
       if (isX1) return 'https://wiki.bambulab.com/en/x1/maintenance/basic-maintenance';
       if (isP1) return 'https://wiki.bambulab.com/en/p1/maintenance/p1p-maintenance';
       if (isP1) return 'https://wiki.bambulab.com/en/p1/maintenance/p1p-maintenance';
+      return null;
+
+    case 'Lubricate Steel Rods':
+      // P2S has hardened steel rods
+      if (isP2S) return 'https://wiki.bambulab.com/en/p2s/maintenance/lubricate-x-y-z-axis';
+      return null;
+
+    case 'Clean Steel Rods':
+      // P2S has hardened steel rods
       if (isP2S) return 'https://wiki.bambulab.com/en/p2s/maintenance/lubricate-x-y-z-axis';
       if (isP2S) return 'https://wiki.bambulab.com/en/p2s/maintenance/lubricate-x-y-z-axis';
       return null;
       return null;
 
 
@@ -174,8 +183,8 @@ function getMaintenanceWikiUrl(typeName: string, printerModel: string | null): s
       return 'https://wiki.bambulab.com/en/x1/maintenance/belt-tension';
       return 'https://wiki.bambulab.com/en/x1/maintenance/belt-tension';
 
 
     case 'Clean Carbon Rods':
     case 'Clean Carbon Rods':
-      // X1, P1, P2S series have carbon rods
-      if (isX1 || isP1 || isP2S) return 'https://wiki.bambulab.com/en/general/carbon-rods-clearance';
+      // X1, P1 series have carbon rods
+      if (isX1 || isP1) return 'https://wiki.bambulab.com/en/general/carbon-rods-clearance';
       return null;
       return null;
 
 
     case 'Clean Linear Rails':
     case 'Clean Linear Rails':

File diff suppressed because it is too large
+ 0 - 0
static/assets/index-01PXexAN.js


+ 1 - 1
static/index.html

@@ -23,7 +23,7 @@
 
 
     <!-- Splash screens for iOS -->
     <!-- Splash screens for iOS -->
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
-    <script type="module" crossorigin src="/assets/index-BpZJje_K.js"></script>
+    <script type="module" crossorigin src="/assets/index-01PXexAN.js"></script>
     <link rel="stylesheet" crossorigin href="/assets/index-DfcIVNpM.css">
     <link rel="stylesheet" crossorigin href="/assets/index-DfcIVNpM.css">
   </head>
   </head>
   <body>
   <body>

Some files were not shown because too many files changed in this diff