ソースを参照

fix(frontend/hms): surface uncataloged HMS faults that carry firmware actions (#1840)

    filterKnownHMSErrors and the modal-local copy gated visibility on
    ERROR_DESCRIPTIONS membership. H2C 0500_809C carries IGNORE_RESUME /
    PROBLEM_SOLVED_RESUME but is missing from the bundled 853-entry catalog,
    so the entire error — pip, count, panel, action buttons — never rendered
    even though backend captured + dispatched it correctly.

    The gate isn't dead code: PrintersPageBucketing pins the post-cancel
    0C00_001B junk-echo regression to it. Widen the predicate to keep
    (cataloged) OR (actions.length > 0) so noise is still filtered out
    while user-actionable faults always surface.

    Replace the modal's inline filter with the shared helper so badge
    counts and modal contents agree by construction. Fall back to
    hmsErrors.unknownCode ("Unknown HMS code — see the Bambu Lab wiki
    for details.") when the catalog has no entry. New key translated in
    all 11 locales.

    New bucketing test pins PAUSE + uncataloged-with-actions = error;
    existing FAILED + uncataloged-without-actions = finished stays green.
maziggy 2 ヶ月 前
コミット
7f661be941

+ 0 - 73
BACKERS.md

@@ -1,73 +0,0 @@
-# Bambuddy Backers & Sponsors
-
-Bambuddy is sustainable thanks to people who put their money where their use is. This page lists everyone who supports the project on [GitHub Sponsors](https://github.com/sponsors/maziggy) or [Ko-fi](https://ko-fi.com/maziggy).
-
-If you'd like to support Bambuddy:
-
-- **GitHub Sponsors** (recurring, 5 tiers from $5/mo to $300/mo) — https://github.com/sponsors/maziggy
-- **Ko-fi** (one-time or recurring) — https://ko-fi.com/maziggy
-
-If you sponsor and your name isn't here within 48h, please write an email to martin@bambuddy.cool or open an Issue on the main repo.
-
----
-
-## Corporate Sponsors ($300/mo+)
-
-- [@northpole3dprinting](https://github.com/northpole3dprinting)
-
-## Sustaining Sponsors ($150/mo+)
-
-*None yet.*
-
-## Patrons ($35/mo+)
-
-- [@VREmma](https://github.com/VREmma)
-- [@pwostran](https://github.com/pwostran)
-- [@Praxeis](https://github.com/Praxeis)
-- [@jmclaren7](https://github.com/jmclaren7)
-- [@RoBoT24-web](https://github.com/RoBoT24-web)
-- [@Rayvenhaus](https://github.com/Rayvenhaus)
-
-## Supporters ($15/mo+)
-
-- [@rewart01](https://github.com/rewart01)
-- [@rstocks](https://github.com/rstocks)
-- [@sixfootseven](https://github.com/sixfootseven)
-- [@MethodicalMartian](https://github.com/MethodicalMartian)
-- [@brianharwell](https://github.com/brianharwell)
-
-## Backers ($5/mo+)
-
-- [@aneopsy](https://github.com/aneopsy)
-- [@flom89](https://github.com/flom89)
-- [@grizz0blaw](https://github.com/grizz0blaw)
-- [@NoahTingey](https://github.com/NoahTingey)
-- [@sentinel-center](https://github.com/sentinel-center)
-- [@brianehlert](https://github.com/brianehlert)
-- [@siiruup](https://github.com/siiruup)
-- [@agntcoopersea](https://github.com/agntcoopersea)
-- [@PJMCL1618033](https://github.com/PJMCL1618033
-- [@mgf99](https://github.com/mgf99)
-- [@Geoff-S](https://github.com/Geoff-S)
-- [@andyspinball](https://github.com/andyspinball
-- [@avandeputte](https://github.com/avandeputte)
-- [@joeferrante](https://github.com/joeferrante)
-- [@GPop61](https://github.com)
-- [@CooleyMcCoolson](https://github.com/CooleyMcCoolson)
-- [@mikeloveridge](https://github.com/mikeloveridge)
-- [@boernie](https://github.com/boernie)
-- [@qoatzelcoat](https://github.com/qoatzelcoat)
-- [@Sanaki](https://github.com/Sanaki)
-- [@jlofshult](https://github.com/jlofshult)
-- [@TriadX1](https://github.com/TriadX1)
-- [@hazzardr](https://github.com/hazzardr)
-
----
-
-## One-time and historical supporters
-
-A general thank-you to everyone who's contributed via Ko-fi over the past months. Specific names get added on request — if you'd like to be listed, ping `maziggy`.
-
----
-
-Thanks. — Martin

ファイルの差分が大きいため隠しています
+ 0 - 0
CHANGELOG.md


+ 17 - 2
frontend/src/__tests__/pages/PrintersPageBucketing.test.ts

@@ -20,7 +20,7 @@ import { describe, it, expect } from 'vitest';
 type Status = {
 type Status = {
   connected: boolean;
   connected: boolean;
   state: string | null;
   state: string | null;
-  hms_errors?: { code: string; attr: number; severity: number }[];
+  hms_errors?: { code: string; attr: number; severity: number; actions?: string[] }[];
 };
 };
 
 
 type Bucket = 'printing' | 'paused' | 'finished' | 'idle' | 'offline' | 'error';
 type Bucket = 'printing' | 'paused' | 'finished' | 'idle' | 'offline' | 'error';
@@ -32,7 +32,8 @@ function filterKnownHMSErrors(errors: Status['hms_errors']): NonNullable<Status[
     const codeNum = parseInt(e.code.replace('0x', ''), 16) || 0;
     const codeNum = parseInt(e.code.replace('0x', ''), 16) || 0;
     const module = ((e.attr >> 16) & 0xFFFF).toString(16).padStart(4, '0').toUpperCase();
     const module = ((e.attr >> 16) & 0xFFFF).toString(16).padStart(4, '0').toUpperCase();
     const code = (codeNum & 0xFFFF).toString(16).padStart(4, '0').toUpperCase();
     const code = (codeNum & 0xFFFF).toString(16).padStart(4, '0').toUpperCase();
-    return KNOWN_HMS_CODES.has(`${module}_${code}`);
+    if (KNOWN_HMS_CODES.has(`${module}_${code}`)) return true;
+    return (e.actions?.length ?? 0) > 0;
   });
   });
 }
 }
 
 
@@ -77,6 +78,20 @@ describe('FAILED-without-HMS bucketing', () => {
     expect(classifyPrinterStatus(cancelEcho)).toBe('finished');
     expect(classifyPrinterStatus(cancelEcho)).toBe('finished');
   });
   });
 
 
+  it('classifies PAUSE + uncataloged HMS WITH actions as "error" (#1840: H2C 0500_809C carries actions but isnt in the bundled catalog)', () => {
+    const h2cActionableFault: Status = {
+      connected: true,
+      state: 'PAUSE',
+      hms_errors: [{
+        code: '0x809c',
+        attr: 0x0500_809C,
+        severity: 3,
+        actions: ['IGNORE_RESUME', 'PROBLEM_SOLVED_RESUME'],
+      }],
+    };
+    expect(classifyPrinterStatus(h2cActionableFault)).toBe('error');
+  });
+
   it('classifies FINISH as "finished" (unchanged baseline)', () => {
   it('classifies FINISH as "finished" (unchanged baseline)', () => {
     const completedPrinter: Status = { connected: true, state: 'FINISH' };
     const completedPrinter: Status = { connected: true, state: 'FINISH' };
     expect(classifyPrinterStatus(completedPrinter)).toBe('finished');
     expect(classifyPrinterStatus(completedPrinter)).toBe('finished');

+ 14 - 9
frontend/src/components/HMSErrorModal.tsx

@@ -896,12 +896,20 @@ function getShortCode(attr: number, code: number): string {
   return `${module.toString(16).padStart(4, '0').toUpperCase()}_${codeNum.toString(16).padStart(4, '0').toUpperCase()}`;
   return `${module.toString(16).padStart(4, '0').toUpperCase()}_${codeNum.toString(16).padStart(4, '0').toUpperCase()}`;
 }
 }
 
 
-// Helper to filter only known HMS errors (exported for use in badge counts)
+// Helper to filter HMS errors the UI should surface (exported for use in badge counts).
+// Keeps an error if EITHER:
+//   - it's in the bundled ERROR_DESCRIPTIONS catalog (known, has a description), OR
+//   - it carries firmware actions (uncataloged but user-actionable — e.g. H2C 0500_809C
+//     with IGNORE_RESUME/PROBLEM_SOLVED_RESUME — must surface so the button can render).
+// Drops uncataloged errors WITHOUT actions: those are transient junk like the post-cancel
+// 0C00_001B echo that re-introduces the FAILED-after-cancel "1 problem forever"
+// regression — see PrintersPageBucketing.test.ts.
 export function filterKnownHMSErrors(errors: HMSError[]): HMSError[] {
 export function filterKnownHMSErrors(errors: HMSError[]): HMSError[] {
   return errors.filter((error) => {
   return errors.filter((error) => {
     const codeNum = parseInt(error.code.replace('0x', ''), 16) || 0;
     const codeNum = parseInt(error.code.replace('0x', ''), 16) || 0;
     const shortCode = getShortCode(error.attr, codeNum);
     const shortCode = getShortCode(error.attr, codeNum);
-    return ERROR_DESCRIPTIONS[shortCode] !== undefined;
+    if (ERROR_DESCRIPTIONS[shortCode] !== undefined) return true;
+    return (error.actions?.length ?? 0) > 0;
   });
   });
 }
 }
 
 
@@ -925,12 +933,9 @@ export function HMSErrorModal({ printerName, errors, onClose, printerId, hasPerm
     },
     },
   });
   });
 
 
-  // Filter to only show errors we have descriptions for (skip unknown codes)
-  const knownErrors = errors.filter((error) => {
-    const codeNum = parseInt(error.code.replace('0x', ''), 16) || 0;
-    const shortCode = getShortCode(error.attr, codeNum);
-    return ERROR_DESCRIPTIONS[shortCode] !== undefined;
-  });
+  // Surface cataloged errors and uncataloged-but-actionable errors. Mirrors
+  // filterKnownHMSErrors so the modal and the badge counts agree.
+  const knownErrors = filterKnownHMSErrors(errors);
 
 
   // Close on Escape key
   // Close on Escape key
   useEffect(() => {
   useEffect(() => {
@@ -998,7 +1003,7 @@ export function HMSErrorModal({ printerName, errors, onClose, printerId, hasPerm
                 const { label, color, bgColor, buttonHoverColor, Icon } = getSeverityInfo(error.severity);
                 const { label, color, bgColor, buttonHoverColor, Icon } = getSeverityInfo(error.severity);
                 const codeNum = parseInt(error.code.replace('0x', ''), 16) || 0;
                 const codeNum = parseInt(error.code.replace('0x', ''), 16) || 0;
                 const shortCode = getShortCode(error.attr, codeNum);
                 const shortCode = getShortCode(error.attr, codeNum);
-                const description = ERROR_DESCRIPTIONS[shortCode];
+                const description = ERROR_DESCRIPTIONS[shortCode] ?? t('hmsErrors.unknownCode');
                 const hmsHomeUrl = getHMSHomeUrl();
                 const hmsHomeUrl = getHMSHomeUrl();
                 const displayCode = shortCode.replace('_', '-');
                 const displayCode = shortCode.replace('_', '-');
 
 

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

@@ -2755,6 +2755,7 @@ export default {
     title: 'Fehler - {{name}}',
     title: 'Fehler - {{name}}',
     noErrors: 'Keine Fehler',
     noErrors: 'Keine Fehler',
     viewOnWiki: 'Im Bambu Lab Wiki ansehen',
     viewOnWiki: 'Im Bambu Lab Wiki ansehen',
+    unknownCode: 'Unbekannter HMS-Code — Details siehe Bambu Lab Wiki.',
     clearInstructions: 'Löschen Sie die Fehler am Drucker, um sie hier zu entfernen.',
     clearInstructions: 'Löschen Sie die Fehler am Drucker, um sie hier zu entfernen.',
     clearErrors: 'Fehler löschen',
     clearErrors: 'Fehler löschen',
     clearSuccess: 'HMS-Fehler gelöscht',
     clearSuccess: 'HMS-Fehler gelöscht',

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

@@ -2784,6 +2784,7 @@ export default {
     title: 'Errors - {{name}}',
     title: 'Errors - {{name}}',
     noErrors: 'No errors',
     noErrors: 'No errors',
     viewOnWiki: 'View on Bambu Lab Wiki',
     viewOnWiki: 'View on Bambu Lab Wiki',
+    unknownCode: 'Unknown HMS code — see the Bambu Lab wiki for details.',
     clearInstructions: 'Clear errors on the printer to dismiss them here.',
     clearInstructions: 'Clear errors on the printer to dismiss them here.',
     clearErrors: 'Clear Errors',
     clearErrors: 'Clear Errors',
     clearSuccess: 'HMS errors cleared',
     clearSuccess: 'HMS errors cleared',

+ 1 - 0
frontend/src/i18n/locales/es.ts

@@ -2758,6 +2758,7 @@ export default {
     title: 'Errores - {{name}}',
     title: 'Errores - {{name}}',
     noErrors: 'No hay errores',
     noErrors: 'No hay errores',
     viewOnWiki: 'Ver en la wiki de Bambu Lab',
     viewOnWiki: 'Ver en la wiki de Bambu Lab',
+    unknownCode: 'Código HMS desconocido — consulta la wiki de Bambu Lab para más detalles.',
     clearInstructions: 'Borre los errores en la impresora para descartarlos aquí.',
     clearInstructions: 'Borre los errores en la impresora para descartarlos aquí.',
     clearErrors: 'Borrar errores',
     clearErrors: 'Borrar errores',
     clearSuccess: 'Errores HMS borrados',
     clearSuccess: 'Errores HMS borrados',

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

@@ -2744,6 +2744,7 @@ export default {
     title: 'Erreurs - {{name}}',
     title: 'Erreurs - {{name}}',
     noErrors: 'Aucune erreur',
     noErrors: 'Aucune erreur',
     viewOnWiki: 'Voir sur le Wiki Bambu Lab',
     viewOnWiki: 'Voir sur le Wiki Bambu Lab',
+    unknownCode: 'Code HMS inconnu — consultez le wiki Bambu Lab pour plus de détails.',
     clearInstructions: 'Effacez les erreurs sur l\'imprimante pour les retirer ici.',
     clearInstructions: 'Effacez les erreurs sur l\'imprimante pour les retirer ici.',
     clearErrors: 'Effacer les erreurs',
     clearErrors: 'Effacer les erreurs',
     clearSuccess: 'Erreurs HMS effacées',
     clearSuccess: 'Erreurs HMS effacées',

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

@@ -2743,6 +2743,7 @@ export default {
     title: 'Errori - {{name}}',
     title: 'Errori - {{name}}',
     noErrors: 'Nessun errore',
     noErrors: 'Nessun errore',
     viewOnWiki: 'Vedi su Bambu Lab Wiki',
     viewOnWiki: 'Vedi su Bambu Lab Wiki',
+    unknownCode: 'Codice HMS sconosciuto — consulta la wiki di Bambu Lab per i dettagli.',
     clearInstructions: 'Cancella gli errori sulla stampante per rimuoverli qui.',
     clearInstructions: 'Cancella gli errori sulla stampante per rimuoverli qui.',
     clearErrors: 'Cancella errori',
     clearErrors: 'Cancella errori',
     clearSuccess: 'Errori HMS cancellati',
     clearSuccess: 'Errori HMS cancellati',

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

@@ -2755,6 +2755,7 @@ export default {
     title: 'エラー - {{name}}',
     title: 'エラー - {{name}}',
     noErrors: 'エラーなし',
     noErrors: 'エラーなし',
     viewOnWiki: 'Bambu Lab Wikiで表示',
     viewOnWiki: 'Bambu Lab Wikiで表示',
+    unknownCode: '不明なHMSコード — 詳細はBambu Lab Wikiを参照してください。',
     clearInstructions: 'プリンターでエラーをクリアするとここからも消えます。',
     clearInstructions: 'プリンターでエラーをクリアするとここからも消えます。',
     clearErrors: 'エラーをクリア',
     clearErrors: 'エラーをクリア',
     clearSuccess: 'HMSエラーをクリアしました',
     clearSuccess: 'HMSエラーをクリアしました',

+ 1 - 0
frontend/src/i18n/locales/ko.ts

@@ -2605,6 +2605,7 @@ export default {
     title: '오류 - {{name}}',
     title: '오류 - {{name}}',
     noErrors: '오류 없음',
     noErrors: '오류 없음',
     viewOnWiki: 'Bambu Lab 위키에서 보기',
     viewOnWiki: 'Bambu Lab 위키에서 보기',
+    unknownCode: '알 수 없는 HMS 코드 — 자세한 내용은 Bambu Lab 위키를 참조하세요.',
     clearInstructions: '오류를 해제하려면 프린터에서 오류를 지우세요.',
     clearInstructions: '오류를 해제하려면 프린터에서 오류를 지우세요.',
     clearErrors: '오류 지우기',
     clearErrors: '오류 지우기',
     clearSuccess: 'HMS 오류가 지워졌습니다',
     clearSuccess: 'HMS 오류가 지워졌습니다',

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

@@ -2743,6 +2743,7 @@ export default {
     title: 'Erros - {{name}}',
     title: 'Erros - {{name}}',
     noErrors: 'Nenhum erro',
     noErrors: 'Nenhum erro',
     viewOnWiki: 'Ver no Bambu Lab Wiki',
     viewOnWiki: 'Ver no Bambu Lab Wiki',
+    unknownCode: 'Código HMS desconhecido — consulte o wiki da Bambu Lab para mais detalhes.',
     clearInstructions: 'Limpe os erros na impressora para descartá-los aqui.',
     clearInstructions: 'Limpe os erros na impressora para descartá-los aqui.',
     clearErrors: 'Limpar Erros',
     clearErrors: 'Limpar Erros',
     clearSuccess: 'Erros HMS limpos',
     clearSuccess: 'Erros HMS limpos',

+ 1 - 0
frontend/src/i18n/locales/tr.ts

@@ -2759,6 +2759,7 @@ export default {
     title: 'Hatalar - {{name}}',
     title: 'Hatalar - {{name}}',
     noErrors: 'Hata yok',
     noErrors: 'Hata yok',
     viewOnWiki: 'Bambu Lab Wiki\'de görüntüle',
     viewOnWiki: 'Bambu Lab Wiki\'de görüntüle',
+    unknownCode: 'Bilinmeyen HMS kodu — ayrıntılar için Bambu Lab wiki sayfasına bakın.',
     clearInstructions: 'Buradan kapatmak için yazıcıdaki hataları temizleyin.',
     clearInstructions: 'Buradan kapatmak için yazıcıdaki hataları temizleyin.',
     clearErrors: 'Hataları Temizle',
     clearErrors: 'Hataları Temizle',
     clearSuccess: 'HMS hataları temizlendi',
     clearSuccess: 'HMS hataları temizlendi',

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

@@ -2743,6 +2743,7 @@ export default {
     title: '错误 - {{name}}',
     title: '错误 - {{name}}',
     noErrors: '无错误',
     noErrors: '无错误',
     viewOnWiki: '在拓竹 Wiki 上查看',
     viewOnWiki: '在拓竹 Wiki 上查看',
+    unknownCode: '未知 HMS 代码 — 详情请参阅拓竹 Wiki。',
     clearInstructions: '在打印机上清除错误以在此处消除它们。',
     clearInstructions: '在打印机上清除错误以在此处消除它们。',
     clearErrors: '清除错误',
     clearErrors: '清除错误',
     clearSuccess: 'HMS 错误已清除',
     clearSuccess: 'HMS 错误已清除',

+ 1 - 0
frontend/src/i18n/locales/zh-TW.ts

@@ -2743,6 +2743,7 @@ export default {
     title: '錯誤 - {{name}}',
     title: '錯誤 - {{name}}',
     noErrors: '無錯誤',
     noErrors: '無錯誤',
     viewOnWiki: '在拓竹 Wiki 上檢視',
     viewOnWiki: '在拓竹 Wiki 上檢視',
+    unknownCode: '未知 HMS 代碼 — 詳情請參閱拓竹 Wiki。',
     clearInstructions: '在印表機上清除錯誤以在此處消除它們。',
     clearInstructions: '在印表機上清除錯誤以在此處消除它們。',
     clearErrors: '清除錯誤',
     clearErrors: '清除錯誤',
     clearSuccess: 'HMS 錯誤已清除',
     clearSuccess: 'HMS 錯誤已清除',

ファイルの差分が大きいため隠しています
+ 0 - 0
static/assets/index-CKTYjVC_.js


+ 1 - 1
static/index.html

@@ -26,7 +26,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-ChnivgH9.js"></script>
+    <script type="module" crossorigin src="/assets/index-CKTYjVC_.js"></script>
     <link rel="stylesheet" crossorigin href="/assets/index-BYzbe9TT.css">
     <link rel="stylesheet" crossorigin href="/assets/index-BYzbe9TT.css">
   </head>
   </head>
   <body>
   <body>

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません