Просмотр исходного кода

chore(settings): drop the Slicer Bundles notice and rebalance the columns

Bundle import was withdrawn in 0.2.5 and the panel was kept behind as a
static notice pointing at the alternatives. It has been on screen for
several releases, it was shown to everyone running the slicer sidecar
whether or not they had ever imported a bundle, and it was a card in
Settings -> Queue & Dispatch that could not be acted on. Component,
render site and all thirteen locales' strings are gone; no slicing
behaviour is touched.

Four docstrings still described the removed feature as a live fallback:
SliceModal was said to fall back to "the user's uploaded Slicer Bundles"
when a preset carries no compatible_printers. There is no bundle model
and no bundle endpoint left -- the actual fallback is the @BBL <code>
printer-model registry, which is what SliceModal has been doing since

Removing the card left the left column of that tab noticeably longer, so
G-code Injection moves to the foot of the right column. The card is
unchanged and keeps its card-gcode anchor, so settings search still
jumps to it.
maziggy 3 недель назад
Родитель
Сommit
e93f1b43c3

+ 1 - 0
CHANGELOG.md

@@ -24,6 +24,7 @@ All notable changes to Bambuddy will be documented in this file.
 - **The slice dialog's process and filament lists now leave out presets that belong to another printer** — They were already sorted by compatibility, but a preset for a different Bambu model still appeared, demoted to an "Other printers" group at the bottom of the dropdown. With a large cloud filament library that group is most of the list, so the filtering was doing little for the thing it was meant to help: finding the profile you actually want. Those presets are now held back, with the label reporting how many ("3 hidden") next to a **Show all** link that brings them back for that one dropdown. Two things are never hidden. A preset with no detectable printer — a custom or renamed profile — stays in the list, because absence of evidence is not evidence of incompatibility and hiding those would make people's own imported profiles vanish. And whatever is currently selected stays visible even when the list is collapsed, so a deliberate cross-printer pick, or one restored from a pipeline, is never silently discarded by being dropped from the options. Re-slicing for another printer remains fully supported, so this is a default view rather than a restriction. Fixing this also corrected a screen-reader bug in those dropdowns: the controls sat inside the label wrapping the select, which handed them the entire label as their spoken name. A separate defect surfaced alongside it — the filter did nothing at all when the selected printer was a preset you had edited, because BambuStudio names those copies with a leading "# " and the matcher did not know to look past it. On such a printer every preset read as "compatibility unknown", and profiles listing their compatible printers by name could be ruled out against the very printer they were cloned from.
 - **The MQTT debug log now records the commands sent to a printer, not only what it reports back** — **Printer → Debug → MQTT** captured one side of the conversation. Bambuddy listens on both of a printer's topics, but the one carrying commands returned before anything was written to the log, so a capture could show every status push the printer made and nothing it was ever told — including the commands Bambu Studio sends over the local network, which is the only place they can be observed at all. Those now appear alongside Bambuddy's own, grouped under the outgoing filter. It is what lets a question like "which value does Studio put in this field?" be answered from a user's capture instead of guessed at, and it is why #2774 could not be taken further. Commands Bambuddy sends appear twice, once as it publishes and once as the broker echoes it back, and the pair is itself evidence the command reached the broker. Logging is off until switched on, as before. Covered by backend tests.
 - **The L and XL printer cards now scale their text and icons, not just their width (#1848, reporter @misterff1)** — Switching a card from M to XL made it wider, enlarged the printer name and the thumbnail, and left everything else exactly as it was: the AMS slot labels, temperatures, filament names, status text and every small button stayed pinned between 8 and 11 pixels, well under the smallest size used anywhere else in Bambuddy. The result was a full-width card carrying the same tiny text as the compact one, which is precisely the opposite of what someone reaching for a bigger card is asking for. Browser zoom is not an answer to this, since it enlarges the entire page and so preserves the very disparity being complained about. The card body now scales along with the card: L draws it 20% larger and XL 40% larger, icons included, so the controls grow with the text rather than staying fiddly to hit. The AMS-HT card needed two adjustments of its own, since its temperature and humidity readings sit beside the slot rather than under it. Its single slot was the only thing on that row able to grow, so it swallowed every spare pixel and pushed the readings hard against the card's edge — it is now capped at roughly two ordinary slots, which keeps them clear at any card width. The card itself also gained a ceiling of one full AMS card's width, so a unit that wraps onto a line of its own no longer stretches that single slot across the whole card. S and M are deliberately untouched — S is the dense fleet view where density is the point, and M is the default, so an existing install looks identical until you reach for a size that is already asking for more room. Wiki updated. Covered by frontend tests.
+- **The "Slicer Bundles (removed)" card is gone from Settings** — Bundle import was withdrawn in 0.2.5, and the panel it lived in was kept behind as a static notice explaining where the feature went and what to use instead. That notice has done its job: it has been visible for several releases, it was shown to everyone running the slicer sidecar whether or not they had ever imported a bundle, and it occupied a card in **Settings → Workflow** that could not be acted on. The card and its translations are removed. Nothing about slicing changes — single-preset import, Bambu Cloud and Orca Cloud sync all work as before, and the slice-time lookup order is still Imported, then Orca Cloud, then Bambu Cloud, then the sidecar's standard presets. In the same pass **G-code Injection** moved to the foot of the right-hand column, which evens out two columns that the removal had left lopsided; the card itself is unchanged, and the settings search still jumps straight to it. Wiki updated.
 - **Error and warning toasts now stay up twice as long** — Every pop-up notification disappeared after three seconds regardless of what it said. That is about right for "Settings saved", which confirms something you just did and is skimmed rather than read, but errors and warnings are a different kind of message: they carry a reason, often one relayed from the printer or the backend, and they run to a couple of lines. Three seconds was not long enough to finish reading one, and a missed error message is gone for good — there is no notification history to go back to. Errors and warnings now hold for six seconds. Success and informational toasts keep the three-second default, so the common case of clicking something and seeing it confirmed is unchanged, and the close button and the manual dismiss work exactly as before on all of them. The background print-dispatch toast is unaffected: it stays up while it has work in progress and clears itself shortly after the last job settles. Covered by frontend tests.
 
 ### Fixed

+ 5 - 5
backend/app/api/routes/slicer_presets.py

@@ -302,7 +302,7 @@ async def _fetch_local_presets(db: AsyncSession) -> dict[str, list[UnifiedPreset
             # Precise compatibility link — the slicer's own compatible_printers
             # list, captured at import time. Lets the SliceModal filter the
             # process / filament dropdowns by the selected printer without
-            # falling back to the uploaded-bundle index.
+            # falling back to the @BBL name matcher.
             preset.compatible_printers = _parse_compatible_printers(p.compatible_printers)
         slots[slot].append(preset)
     return slots
@@ -330,7 +330,7 @@ def _content_compatible_printers(content: dict) -> list[str] | None:
 def _parse_compatible_printers(raw: str | None) -> list[str] | None:
     """``LocalPreset.compatible_printers`` stores a JSON array of printer-preset
     names. Return the parsed list, or ``None`` on missing / malformed data so
-    the SliceModal falls back to the uploaded-bundle index for that preset."""
+    the SliceModal falls back to the name-based matcher for that preset."""
     if not raw:
         return None
     try:
@@ -533,9 +533,9 @@ def list_printer_models() -> dict[str, str]:
     "Bambu Lab <model>" form that appears in 3MF metadata and in slicer
     printer-preset names, values are the normalized short codes used in
     BambuStudio's `@BBL <code>` cloud-preset filenames. The frontend uses this
-    mapping to classify cloud / standard presets against the selected printer
-    when no slicer bundle has been uploaded that covers the preset (#1325
-    follow-up) - avoiding a second, manually-maintained model table on the
+    mapping to classify cloud / standard presets against the selected printer,
+    which carry no ``compatible_printers`` of their own (#1325 follow-up) -
+    avoiding a second, manually-maintained model table on the
     frontend. No auth gate: this is a static reference dictionary, not
     user data.
     """

+ 2 - 2
backend/app/schemas/slicer_presets.py

@@ -38,8 +38,8 @@ class UnifiedPreset(BaseModel):
     detail is fetched — rate limits) and standard (the sidecar's bundled
     listing doesn't expose it). The SliceModal uses it to filter the
     process / filament dropdowns by the selected printer (#1325); when it is
-    ``None`` the modal falls back to the user's uploaded Slicer Bundles, which
-    map each printer to the presets it ships.
+    ``None`` the modal falls back to matching the preset name against the
+    ``@BBL <code>`` printer-model registry.
     """
 
     id: str

+ 0 - 46
frontend/src/components/SlicerBundlesPanel.tsx

@@ -1,46 +0,0 @@
-import { useTranslation } from 'react-i18next';
-import { Package } from 'lucide-react';
-import { Card, CardContent, CardHeader } from './Card';
-
-// Static notice replacing the former Printer Preset Bundle import UI.
-// Removed in #1712: BambuStudio's bundle export only includes user-
-// customised presets, so users who exported a bundle ended up with no
-// process presets to slice with (BS doesn't export system processes).
-// Users with custom presets now route through Single Preset Import or
-// cloud sync; the standard tier on the sidecar already provides every
-// stock preset for slicing.
-export function SlicerBundlesPanel() {
-  const { t } = useTranslation();
-  return (
-    <Card>
-      <CardHeader>
-        <h3 className="text-base font-semibold text-white flex items-center gap-2">
-          <Package className="w-4 h-4 text-bambu-gray" />
-          {t('settings.slicerBundlesRemoved.title', {
-            defaultValue: 'Slicer Bundles (removed)',
-          })}
-        </h3>
-      </CardHeader>
-      <CardContent className="space-y-2">
-        <p className="text-sm text-bambu-gray">
-          {t('settings.slicerBundlesRemoved.description', {
-            defaultValue:
-              'Printer Preset Bundle (.bbscfg) import was removed. BambuStudio\'s bundle export only includes user-customised presets, so the import never delivered standard processes / filaments and slicing fell back to embedded settings.',
-          })}
-        </p>
-        <p className="text-sm text-bambu-gray">
-          {t('settings.slicerBundlesRemoved.alternatives', {
-            defaultValue:
-              'Use Single Preset Import for individual customs, or sync via Bambu Cloud / Orca Cloud. Stock presets come from the slicer sidecar automatically.',
-          })}
-        </p>
-        <p className="text-sm text-bambu-gray">
-          {t('settings.slicerBundlesRemoved.lookupOrder', {
-            defaultValue:
-              'Slice-time preset lookup order: 1) Imported (local), 2) Orca Cloud, 3) Bambu Cloud, 4) Standard (sidecar fallback).',
-          })}
-        </p>
-      </CardContent>
-    </Card>
-  );
-}

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

@@ -2393,12 +2393,6 @@ export default {
     slicerStallTimeout: 'Zeitlimit bei Slicer-Stillstand (Minuten)',
     slicerStallTimeoutDescription: 'Bricht einen Slice-Vorgang ab, wenn der Sidecar so lange keinen Fortschritt meldet. Aufwendige Modelle, die weiter Fortschritt melden, werden nie abgebrochen, egal wie lange sie brauchen. Sidecars ohne Fortschrittsmeldung nutzen diesen Wert stattdessen als Gesamtzeitlimit.',
     slicerApiUrlDescription: 'URL des Slicer-API-Sidecar-Containers. Leer lassen, um die SLICER_API_URL- bzw. BAMBU_STUDIO_API_URL-Umgebungsvariablen zu nutzen.',
-    slicerBundlesRemoved: {
-      title: 'Slicer-Bundles (entfernt)',
-      description: 'Der Import von Drucker-Voreinstellungs-Bundles (.bbscfg) wurde entfernt. Der Bundle-Export von BambuStudio enthält nur benutzerdefinierte Voreinstellungen, daher lieferte der Import nie die Standard-Prozesse / -Filamente, und das Slicen fiel auf eingebettete Einstellungen zurück.',
-      alternatives: 'Verwende Einzel-Voreinstellungs-Import für individuelle Anpassungen oder synchronisiere via Bambu Cloud / Orca Cloud. Standard-Voreinstellungen kommen automatisch vom Slicer-Sidecar.',
-      lookupOrder: 'Reihenfolge der Voreinstellungssuche beim Slicen: 1) Importiert (lokal), 2) Orca Cloud, 3) Bambu Cloud, 4) Standard (Sidecar-Fallback).',
-    },
     externalCameras: 'Externe Kameras',
     costTracking: 'Kostenverfolgung',
     billingEnabled: 'Abrechnung aktivieren',

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

@@ -2412,12 +2412,6 @@ export default {
     slicerStallTimeout: 'Slicer stall timeout (minutes)',
     slicerStallTimeoutDescription: 'Give up on a slice after this long with no progress from the sidecar. Heavy models that keep reporting progress are never cut off, however long they take. Sidecars that do not report progress use this as a total time limit instead.',
     slicerApiUrlDescription: 'URL of the slicer-API sidecar container. Leave blank to use the SLICER_API_URL / BAMBU_STUDIO_API_URL env var defaults.',
-    slicerBundlesRemoved: {
-      title: 'Slicer Bundles (removed)',
-      description: 'Printer Preset Bundle (.bbscfg) import was removed. BambuStudio\'s bundle export only includes user-customised presets, so the import never delivered standard processes / filaments and slicing fell back to embedded settings.',
-      alternatives: 'Use Single Preset Import for individual customs, or sync via Bambu Cloud / Orca Cloud. Stock presets come from the slicer sidecar automatically.',
-      lookupOrder: 'Slice-time preset lookup order: 1) Imported (local), 2) Orca Cloud, 3) Bambu Cloud, 4) Standard (sidecar fallback).',
-    },
     externalCameras: 'External Cameras',
     costTracking: 'Cost Tracking',
     billingEnabled: 'Enable Billing',

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

@@ -2396,12 +2396,6 @@ export default {
     slicerStallTimeout: 'Tiempo de espera por inactividad del laminador (minutos)',
     slicerStallTimeoutDescription: 'Abandona un laminado tras este tiempo sin progreso del sidecar. Los modelos pesados que siguen informando progreso nunca se interrumpen, por mucho que tarden. Los sidecars que no informan progreso usan este valor como limite de tiempo total.',
     slicerApiUrlDescription: 'URL del contenedor auxiliar de la API del laminador. Déjelo en blanco para usar los valores predeterminados de las variables de entorno SLICER_API_URL / BAMBU_STUDIO_API_URL.',
-    slicerBundlesRemoved: {
-      title: 'Paquetes del laminador (eliminado)',
-      description: 'Se eliminó la importación de paquetes de preajustes de impresora (.bbscfg). La exportación de paquetes de BambuStudio solo incluye preajustes personalizados, por lo que la importación nunca entregaba procesos / filamentos estándar y el laminado recurría a la configuración incrustada.',
-      alternatives: 'Usa Importación de preajuste individual para personalizaciones, o sincroniza vía Bambu Cloud / Orca Cloud. Los preajustes estándar vienen del sidecar del laminador automáticamente.',
-      lookupOrder: 'Orden de búsqueda de preajustes al laminar: 1) Importado (local), 2) Orca Cloud, 3) Bambu Cloud, 4) Estándar (sidecar de respaldo).',
-    },
     externalCameras: 'Cámaras externas',
     costTracking: 'Seguimiento de costes',
     billingEnabled: 'Activar facturación',

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

@@ -2349,12 +2349,6 @@ export default {
     slicerStallTimeout: "Delai d'inactivite du trancheur (minutes)",
     slicerStallTimeoutDescription: 'Abandonne un decoupage apres cette duree sans progression du sidecar. Les modeles lourds qui continuent a signaler leur progression ne sont jamais interrompus, quel que soit le temps necessaire. Les sidecars qui ne signalent pas de progression utilisent cette valeur comme limite de duree totale.',
     slicerApiUrlDescription: 'URL du conteneur sidecar slicer-API. Laisser vide pour utiliser les variables d\'environnement SLICER_API_URL / BAMBU_STUDIO_API_URL.',
-    slicerBundlesRemoved: {
-      title: 'Bundles de slicer (supprimé)',
-      description: 'L\'import de Printer Preset Bundles (.bbscfg) a été supprimé. L\'export de bundle de BambuStudio ne comprend que les préréglages personnalisés, donc l\'import ne livrait jamais les processus / filaments standard et le découpage retombait sur les paramètres intégrés.',
-      alternatives: 'Utilisez l\'Import de préréglage unique pour les personnalisations, ou synchronisez via Bambu Cloud / Orca Cloud. Les préréglages standard viennent automatiquement du sidecar du trancheur.',
-      lookupOrder: 'Ordre de recherche des préréglages au découpage : 1) Importé (local), 2) Orca Cloud, 3) Bambu Cloud, 4) Standard (repli sidecar).',
-    },
     externalCameras: 'Caméras externes',
     costTracking: 'Suivi des coûts',
     printsOnly: 'Impressions uniquement',

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

@@ -2349,12 +2349,6 @@ export default {
     slicerStallTimeout: 'Timeout di inattivita dello slicer (minuti)',
     slicerStallTimeoutDescription: 'Interrompe uno slice dopo questo tempo senza progressi dal sidecar. I modelli pesanti che continuano a segnalare progressi non vengono mai interrotti, per quanto tempo richiedano. I sidecar che non segnalano progressi usano questo valore come limite di tempo totale.',
     slicerApiUrlDescription: 'URL del container sidecar slicer-API. Lascia vuoto per usare le variabili d\'ambiente SLICER_API_URL / BAMBU_STUDIO_API_URL.',
-    slicerBundlesRemoved: {
-      title: 'Bundle slicer (rimosso)',
-      description: 'L\'importazione di Printer Preset Bundle (.bbscfg) è stata rimossa. L\'esportazione di bundle di BambuStudio include solo preset personalizzati, quindi l\'importazione non forniva mai i processi / filamenti standard e lo slicing ricorreva alle impostazioni incorporate.',
-      alternatives: 'Usa Importazione preset singolo per personalizzazioni, o sincronizza tramite Bambu Cloud / Orca Cloud. I preset standard arrivano automaticamente dal sidecar dello slicer.',
-      lookupOrder: 'Ordine di ricerca dei preset al momento dello slicing: 1) Importato (locale), 2) Orca Cloud, 3) Bambu Cloud, 4) Standard (fallback sidecar).',
-    },
     externalCameras: 'Camere esterne',
     costTracking: 'Tracciamento costi',
     printsOnly: 'Solo stampe',

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

@@ -2392,12 +2392,6 @@ export default {
     slicerStallTimeout: 'スライサー停止タイムアウト(分)',
     slicerStallTimeoutDescription: 'サイドカーからの進捗がこの時間なければスライスを中止します。進捗を報告し続ける重いモデルは、どれだけ時間がかかっても中断されません。進捗を報告しないサイドカーでは、この値が合計時間の上限になります。',
     slicerApiUrlDescription: 'slicer-APIサイドカーコンテナのURL。空のままにすると SLICER_API_URL / BAMBU_STUDIO_API_URL 環境変数のデフォルト値が使用されます。',
-    slicerBundlesRemoved: {
-      title: 'スライサーバンドル(削除済み)',
-      description: 'プリンタープリセットバンドル(.bbscfg)のインポートは削除されました。BambuStudioのバンドルエクスポートはユーザーがカスタマイズしたプリセットのみを含むため、インポートでは標準プロセス/フィラメントが提供されず、スライスは埋め込み設定にフォールバックしていました。',
-      alternatives: '個別カスタマイズには単一プリセットインポートを使うか、Bambu Cloud / Orca Cloudで同期してください。標準プリセットはスライサーサイドカーから自動的に提供されます。',
-      lookupOrder: 'スライス時のプリセット検索順: 1) インポート済み(ローカル)、2) Orca Cloud、3) Bambu Cloud、4) 標準(サイドカーのフォールバック)。',
-    },
     externalCameras: '外部カメラ',
     costTracking: 'コスト追跡',
     printsOnly: '印刷のみ',

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

@@ -2265,12 +2265,6 @@ export default {
     slicerStallTimeout: '슬라이서 정지 시간 제한(분)',
     slicerStallTimeoutDescription: '사이드카에서 이 시간 동안 진행 상황이 없으면 슬라이싱을 중단합니다. 진행 상황을 계속 보고하는 무거운 모델은 아무리 오래 걸려도 중단되지 않습니다. 진행 상황을 보고하지 않는 사이드카에서는 이 값이 전체 시간 제한으로 사용됩니다.',
     slicerApiUrlDescription: '슬라이서 API 사이드카 컨테이너의 URL. SLICER_API_URL / BAMBU_STUDIO_API_URL 환경 변수 기본값을 사용하려면 비워두세요.',
-    slicerBundlesRemoved: {
-      title: '슬라이서 번들 (제거됨)',
-      description: '프린터 프리셋 번들 (.bbscfg) 가져오기가 제거되었습니다. BambuStudio의 번들 내보내기에는 사용자 정의 프리셋만 포함되므로, 가져오기로는 표준 프로세스 / 필라멘트가 제공되지 않았고 슬라이싱은 임베디드 설정으로 되돌아갔습니다.',
-      alternatives: '개별 사용자 정의는 단일 프리셋 가져오기를, 또는 Bambu Cloud / Orca Cloud를 통해 동기화하세요. 표준 프리셋은 슬라이서 사이드카에서 자동으로 제공됩니다.',
-      lookupOrder: '슬라이스 시점의 프리셋 조회 순서: 1) 가져옴 (로컬), 2) Orca Cloud, 3) Bambu Cloud, 4) 표준 (사이드카 폴백).',
-    },
     externalCameras: '외부 카메라',
     costTracking: '비용 추적',
     billingEnabled: '결제 기능 사용',

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

@@ -2349,12 +2349,6 @@ export default {
     slicerStallTimeout: 'Tempo limite de inatividade do fatiador (minutos)',
     slicerStallTimeoutDescription: 'Desiste de um fatiamento apos esse tempo sem progresso do sidecar. Modelos pesados que continuam relatando progresso nunca sao interrompidos, por mais que demorem. Sidecars que nao relatam progresso usam este valor como limite de tempo total.',
     slicerApiUrlDescription: 'URL do contêiner sidecar slicer-API. Deixe em branco para usar SLICER_API_URL / BAMBU_STUDIO_API_URL.',
-    slicerBundlesRemoved: {
-      title: 'Bundles do fatiador (removido)',
-      description: 'A importação de Printer Preset Bundles (.bbscfg) foi removida. A exportação de bundle do BambuStudio inclui apenas predefinições personalizadas, portanto a importação nunca entregava processos / filamentos padrão e o fatiamento recorria às configurações incorporadas.',
-      alternatives: 'Use a Importação de predefinição individual para personalizações, ou sincronize via Bambu Cloud / Orca Cloud. As predefinições padrão vêm do sidecar do fatiador automaticamente.',
-      lookupOrder: 'Ordem de busca de predefinições no fatiamento: 1) Importada (local), 2) Orca Cloud, 3) Bambu Cloud, 4) Padrão (fallback do sidecar).',
-    },
     externalCameras: 'Câmeras Externas',
     costTracking: 'Rastreamento de Custos',
     printsOnly: 'Apenas Impressões',

+ 0 - 6
frontend/src/i18n/locales/ru.ts

@@ -2266,12 +2266,6 @@ export default {
     slicerStallTimeout: 'Тайм-аут простоя слайсера (минуты)',
     slicerStallTimeoutDescription: 'Прервать нарезку, если sidecar не сообщает о прогрессе в течение этого времени. Тяжёлые модели, которые продолжают сообщать о прогрессе, не прерываются, сколько бы времени ни потребовалось. Для sidecar без отчёта о прогрессе это значение используется как общий лимит времени.',
     slicerApiUrlDescription: "URL контейнера API-службы слайсера. Оставьте пустым, чтобы использовать значения переменных окружения SLICER_API_URL или BAMBU_STUDIO_API_URL.",
-    slicerBundlesRemoved: {
-      title: "Пакеты профилей слайсера (удалено)",
-      description: "Импорт пакетов профилей принтера .bbscfg удалён. Экспорт пакета из BambuStudio содержит только пользовательские профили, поэтому стандартные процессы и филаменты не импортировались, а нарезка использовала встроенные настройки.",
-      alternatives: "Для отдельных пользовательских профилей используйте импорт одного профиля либо синхронизацию через Bambu Cloud или Orca Cloud. Стандартные профили автоматически предоставляет служба слайсера.",
-      lookupOrder: "Порядок поиска профиля при нарезке: 1) импортированный локально, 2) Orca Cloud, 3) Bambu Cloud, 4) стандартный профиль службы слайсера.",
-    },
     externalCameras: "Внешние камеры",
     costTracking: "Учёт затрат",
     billingEnabled: "Включить расчёты",

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

@@ -2397,12 +2397,6 @@ export default {
     slicerStallTimeout: 'Dilimleyici duraklama zaman asimi (dakika)',
     slicerStallTimeoutDescription: 'Sidecar bu sure boyunca ilerleme bildirmezse dilimleme iptal edilir. Ilerleme bildirmeye devam eden agir modeller ne kadar surerse sursun kesilmez. Ilerleme bildirmeyen sidecar surumleri bu degeri toplam sure siniri olarak kullanir.',
     slicerApiUrlDescription: 'Dilimleyici-API yardımcı bileşen konteynerinin URL\'si. SLICER_API_URL / BAMBU_STUDIO_API_URL ortam değişkeni varsayılanlarını kullanmak için boş bırakın.',
-    slicerBundlesRemoved: {
-      title: 'Dilimleyici Paketleri (kaldırıldı)',
-      description: 'Yazıcı Ön Ayar Paketi (.bbscfg) içe aktarma kaldırıldı. BambuStudio\'nun paket dışa aktarması yalnızca kullanıcı tarafından özelleştirilmiş ön ayarları içerir, bu nedenle içe aktarma hiçbir zaman standart süreçleri / filamentleri sağlamadı ve dilimleme gömülü ayarlara geri döndü.',
-      alternatives: 'Bireysel özelleştirmeler için Tekli Ön Ayar İçe Aktarma\'yı kullanın veya Bambu Cloud / Orca Cloud üzerinden senkronize edin. Standart ön ayarlar otomatik olarak dilimleyici sidecar\'ından gelir.',
-      lookupOrder: 'Dilimleme sırasında ön ayar arama sırası: 1) İçe aktarılmış (yerel), 2) Orca Cloud, 3) Bambu Cloud, 4) Standart (sidecar yedeği).',
-    },
     externalCameras: 'Harici Kameralar',
     costTracking: 'Maliyet Takibi',
     billingEnabled: 'Faturalandırmayı etkinleştir',

+ 0 - 6
frontend/src/i18n/locales/uk.ts

@@ -2412,12 +2412,6 @@ export default {
     slicerStallTimeout: 'Тайм-аут простою слайсера (хвилини)',
     slicerStallTimeoutDescription: 'Перервати нарізку, якщо sidecar не повідомляє про прогрес протягом цього часу. Важкі моделі, які продовжують повідомляти про прогрес, ніколи не перериваються, скільки б часу не знадобилося. Для sidecar без звіту про прогрес це значення використовується як загальний ліміт часу.',
     slicerApiUrlDescription: "URL контейнера допоміжного сервісу slicer-API. Залиште поле порожнім, щоб використовувати типові значення зі змінних середовища SLICER_API_URL / BAMBU_STUDIO_API_URL.",
-    slicerBundlesRemoved: {
-      title: "Пакети профілів слайсера (вилучено)",
-      description: "Імпорт пакетів профілів принтера (.bbscfg) вилучено. Експорт пакетів Bambu Studio містить лише змінені користувачем профілі, тому імпорт не надавав стандартних профілів процесу й філаменту, а під час нарізання використовувалися вбудовані налаштування.",
-      alternatives: "Використовуйте імпорт окремого профілю для власних профілів або синхронізацію через Bambu Cloud / Orca Cloud. Стандартні профілі автоматично надходять із допоміжного сервісу слайсера.",
-      lookupOrder: "Порядок пошуку профілів під час нарізання: 1) імпортовані локально, 2) Orca Cloud, 3) Bambu Cloud, 4) стандартні профілі слайсера.",
-    },
     externalCameras: "Зовнішні камери",
     costTracking: "Відстеження витрат",
     billingEnabled: "Увімкнути розрахунки",

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

@@ -2394,12 +2394,6 @@ export default {
     slicerStallTimeout: '切片器停滞超时(分钟)',
     slicerStallTimeoutDescription: '若 sidecar 在此时长内没有任何进度,则放弃本次切片。持续报告进度的复杂模型无论耗时多久都不会被中断。不报告进度的 sidecar 则将此值作为总时长上限。',
     slicerApiUrlDescription: 'slicer-API sidecar 容器的 URL。留空以使用 SLICER_API_URL / BAMBU_STUDIO_API_URL 环境变量默认值。',
-    slicerBundlesRemoved: {
-      title: '切片器捆绑包(已移除)',
-      description: '打印机预设包 (.bbscfg) 导入已移除。BambuStudio 的包导出仅包含用户自定义的预设,因此导入从未提供标准工艺 / 耗材,切片会回退到嵌入设置。',
-      alternatives: '对于单独的自定义,请使用单个预设导入,或通过 Bambu Cloud / Orca Cloud 同步。标准预设自动来自切片器侧车。',
-      lookupOrder: '切片时的预设查找顺序:1) 已导入(本地),2) Orca Cloud,3) Bambu Cloud,4) 标准(侧车回退)。',
-    },
     externalCameras: '外部摄像头',
     costTracking: '成本追踪',
     printsOnly: '仅打印',

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

@@ -2394,12 +2394,6 @@ export default {
     slicerStallTimeout: '切片器停滯逾時(分鐘)',
     slicerStallTimeoutDescription: '若 sidecar 在此時長內沒有任何進度,則放棄本次切片。持續回報進度的複雜模型無論耗時多久都不會被中斷。不回報進度的 sidecar 則將此值作為總時長上限。',
     slicerApiUrlDescription: 'slicer-API sidecar 容器的 URL。留空以使用 SLICER_API_URL / BAMBU_STUDIO_API_URL 環境變數預設值。',
-    slicerBundlesRemoved: {
-      title: '切片器捆綁包(已移除)',
-      description: '印表機預設套件 (.bbscfg) 匯入已移除。BambuStudio 的套件匯出僅包含使用者自訂的預設,因此匯入從未提供標準製程 / 耗材,切片會回退到嵌入設定。',
-      alternatives: '對於單獨的自訂,請使用單一預設匯入,或透過 Bambu Cloud / Orca Cloud 同步。標準預設自動來自切片器側車。',
-      lookupOrder: '切片時的預設查找順序:1) 已匯入(本機),2) Orca Cloud,3) Bambu Cloud,4) 標準(側車回退)。',
-    },
     externalCameras: '外部攝影機',
     costTracking: '成本追蹤',
     printsOnly: '僅列印',

+ 107 - 114
frontend/src/pages/SettingsPage.tsx

@@ -13,7 +13,6 @@ import { CALIBRATION_MODES, CALIBRATION_MODE_ACTIVE, CALIBRATION_MODE_INACTIVE }
 import { PreheatFilamentTargetsEditor } from '../components/PreheatFilamentTargetsEditor';
 import type { APIKey, AppSettings, AppSettingsUpdate, PrinterHASensor, SmartPlug, SmartPlugStatus, NotificationProvider, NotificationTemplate, UpdateStatus, GitHubBackupStatus, CloudAuthStatus, UserCreate, UserUpdate, UserResponse, StorageUsageResponse, CalibrationMode } from '../api/client';
 import { Card, CardContent, CardDensityProvider, CardHeader } from '../components/Card';
-import { SlicerBundlesPanel } from '../components/SlicerBundlesPanel';
 import { SlicerPipelinesPanel } from '../components/SlicerPipelinesPanel';
 import { CameraTokensSection } from './CameraTokensPage';
 import { StreamOverlayBuilder } from '../components/StreamOverlayBuilder';
@@ -5025,113 +5024,6 @@ export function SettingsPage() {
             </CardContent>
           </Card>
 
-          {/* G-code Injection (#422) */}
-          <Card id="card-gcode">
-            <CardHeader>
-              <h3 className="text-base font-semibold text-white flex items-center gap-2">
-                <Code className="w-4 h-4 text-bambu-green" />
-                {t('settings.gcodeInjection', 'G-code Injection')}
-              </h3>
-            </CardHeader>
-            <CardContent className="space-y-3">
-              <p className="text-xs text-bambu-gray">
-                {t('settings.gcodeInjectionDescription', 'Configure custom G-code to inject at the start and/or end of prints for auto-print systems like Farmloop, SwapMod, AutoClear, and Printflow 3D. Snippets are configured per printer model and applied when "Inject G-code" is enabled on a queue item.')}
-              </p>
-              {(() => {
-                const gcodeSnippets: Record<string, { start_gcode: string; end_gcode: string }> = (() => {
-                  try {
-                    return localSettings.gcode_snippets ? JSON.parse(localSettings.gcode_snippets) : {};
-                  } catch {
-                    return {};
-                  }
-                })();
-                const printerModels = [...new Set((printers || []).filter((p) => p.model).map((p) => p.model as string))].sort();
-
-                const updateSnippet = (model: string, field: 'start_gcode' | 'end_gcode', value: string) => {
-                  const updated = { ...gcodeSnippets };
-                  if (!updated[model]) {
-                    updated[model] = { start_gcode: '', end_gcode: '' };
-                  }
-                  updated[model][field] = value;
-                  // Remove model entry if both fields are empty
-                  if (!updated[model].start_gcode && !updated[model].end_gcode) {
-                    delete updated[model];
-                  }
-                  const newValue = Object.keys(updated).length > 0 ? JSON.stringify(updated) : '';
-                  // Update local state for immediate UI feedback, save on blur
-                  setLocalSettings(prev => prev ? { ...prev, gcode_snippets: newValue } : null);
-                  pendingGcodeSnippetsRef.current = newValue;
-                };
-
-                const saveGcodeSnippets = () => {
-                  if (pendingGcodeSnippetsRef.current !== null) {
-                    updateMutation.mutate({ gcode_snippets: pendingGcodeSnippetsRef.current });
-                    pendingGcodeSnippetsRef.current = null;
-                  }
-                };
-
-                if (printerModels.length === 0) {
-                  return (
-                    <p className="text-sm text-bambu-gray italic">
-                      {t('settings.gcodeInjectionNoPrinters', 'No printers found. Add printers to configure G-code snippets.')}
-                    </p>
-                  );
-                }
-
-                return printerModels.map((model) => {
-                  const snippet = gcodeSnippets[model] || { start_gcode: '', end_gcode: '' };
-                  const hasContent = !!(snippet.start_gcode || snippet.end_gcode);
-                  return (
-                    <Collapsible
-                      key={model}
-                      defaultOpen={hasContent}
-                      className="border border-bambu-dark-tertiary rounded-lg px-3 py-2"
-                      summary={
-                        <div className="flex items-center gap-2">
-                          <h4 className="text-sm font-medium text-white">{model}</h4>
-                          {hasContent && (
-                            <span className="text-xs px-1.5 py-0.5 rounded bg-bambu-green/20 text-bambu-green">
-                              {t('settings.gcodeConfigured', 'Configured')}
-                            </span>
-                          )}
-                        </div>
-                      }
-                    >
-                      <div className="space-y-2">
-                        <div>
-                          <label className="block text-xs text-bambu-gray mb-1">
-                            {t('settings.gcodeStartLabel', 'Start G-code')}
-                          </label>
-                          <textarea
-                            value={snippet.start_gcode}
-                            onChange={(e) => updateSnippet(model, 'start_gcode', e.target.value)}
-                            onBlur={saveGcodeSnippets}
-                            placeholder={t('settings.gcodeStartPlaceholder', 'G-code prepended before the print starts...')}
-                            rows={3}
-                            className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-xs font-mono focus:outline-none focus:border-bambu-green resize-y"
-                          />
-                        </div>
-                        <div>
-                          <label className="block text-xs text-bambu-gray mb-1">
-                            {t('settings.gcodeEndLabel', 'End G-code')}
-                          </label>
-                          <textarea
-                            value={snippet.end_gcode}
-                            onChange={(e) => updateSnippet(model, 'end_gcode', e.target.value)}
-                            onBlur={saveGcodeSnippets}
-                            placeholder={t('settings.gcodeEndPlaceholder', 'G-code appended after the print ends...')}
-                            rows={3}
-                            className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-xs font-mono focus:outline-none focus:border-bambu-green resize-y"
-                          />
-                        </div>
-                      </div>
-                    </Collapsible>
-                  );
-                });
-              })()}
-            </CardContent>
-          </Card>
-
           </div>
           {/* Right Column */}
           <div className="lg:w-1/2 space-y-3">
@@ -5363,12 +5255,6 @@ export function SettingsPage() {
             </CardContent>
           </Card>
 
-          {/* Slicer Preset Bundles — only meaningful when the sidecar is in use,
-              since uploads / lists round-trip through it. Hide it entirely when
-              use_slicer_api is off so the Settings page doesn't show a panel that
-              can't do anything. */}
-          {(localSettings.use_slicer_api ?? false) && <SlicerBundlesPanel />}
-
           {/* Auto-Drying */}
           <Card>
             <CardHeader>
@@ -5649,6 +5535,113 @@ export function SettingsPage() {
               </div>
             </CardContent>
           </Card>
+
+          {/* G-code Injection (#422) */}
+          <Card id="card-gcode">
+            <CardHeader>
+              <h3 className="text-base font-semibold text-white flex items-center gap-2">
+                <Code className="w-4 h-4 text-bambu-green" />
+                {t('settings.gcodeInjection', 'G-code Injection')}
+              </h3>
+            </CardHeader>
+            <CardContent className="space-y-3">
+              <p className="text-xs text-bambu-gray">
+                {t('settings.gcodeInjectionDescription', 'Configure custom G-code to inject at the start and/or end of prints for auto-print systems like Farmloop, SwapMod, AutoClear, and Printflow 3D. Snippets are configured per printer model and applied when "Inject G-code" is enabled on a queue item.')}
+              </p>
+              {(() => {
+                const gcodeSnippets: Record<string, { start_gcode: string; end_gcode: string }> = (() => {
+                  try {
+                    return localSettings.gcode_snippets ? JSON.parse(localSettings.gcode_snippets) : {};
+                  } catch {
+                    return {};
+                  }
+                })();
+                const printerModels = [...new Set((printers || []).filter((p) => p.model).map((p) => p.model as string))].sort();
+
+                const updateSnippet = (model: string, field: 'start_gcode' | 'end_gcode', value: string) => {
+                  const updated = { ...gcodeSnippets };
+                  if (!updated[model]) {
+                    updated[model] = { start_gcode: '', end_gcode: '' };
+                  }
+                  updated[model][field] = value;
+                  // Remove model entry if both fields are empty
+                  if (!updated[model].start_gcode && !updated[model].end_gcode) {
+                    delete updated[model];
+                  }
+                  const newValue = Object.keys(updated).length > 0 ? JSON.stringify(updated) : '';
+                  // Update local state for immediate UI feedback, save on blur
+                  setLocalSettings(prev => prev ? { ...prev, gcode_snippets: newValue } : null);
+                  pendingGcodeSnippetsRef.current = newValue;
+                };
+
+                const saveGcodeSnippets = () => {
+                  if (pendingGcodeSnippetsRef.current !== null) {
+                    updateMutation.mutate({ gcode_snippets: pendingGcodeSnippetsRef.current });
+                    pendingGcodeSnippetsRef.current = null;
+                  }
+                };
+
+                if (printerModels.length === 0) {
+                  return (
+                    <p className="text-sm text-bambu-gray italic">
+                      {t('settings.gcodeInjectionNoPrinters', 'No printers found. Add printers to configure G-code snippets.')}
+                    </p>
+                  );
+                }
+
+                return printerModels.map((model) => {
+                  const snippet = gcodeSnippets[model] || { start_gcode: '', end_gcode: '' };
+                  const hasContent = !!(snippet.start_gcode || snippet.end_gcode);
+                  return (
+                    <Collapsible
+                      key={model}
+                      defaultOpen={hasContent}
+                      className="border border-bambu-dark-tertiary rounded-lg px-3 py-2"
+                      summary={
+                        <div className="flex items-center gap-2">
+                          <h4 className="text-sm font-medium text-white">{model}</h4>
+                          {hasContent && (
+                            <span className="text-xs px-1.5 py-0.5 rounded bg-bambu-green/20 text-bambu-green">
+                              {t('settings.gcodeConfigured', 'Configured')}
+                            </span>
+                          )}
+                        </div>
+                      }
+                    >
+                      <div className="space-y-2">
+                        <div>
+                          <label className="block text-xs text-bambu-gray mb-1">
+                            {t('settings.gcodeStartLabel', 'Start G-code')}
+                          </label>
+                          <textarea
+                            value={snippet.start_gcode}
+                            onChange={(e) => updateSnippet(model, 'start_gcode', e.target.value)}
+                            onBlur={saveGcodeSnippets}
+                            placeholder={t('settings.gcodeStartPlaceholder', 'G-code prepended before the print starts...')}
+                            rows={3}
+                            className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-xs font-mono focus:outline-none focus:border-bambu-green resize-y"
+                          />
+                        </div>
+                        <div>
+                          <label className="block text-xs text-bambu-gray mb-1">
+                            {t('settings.gcodeEndLabel', 'End G-code')}
+                          </label>
+                          <textarea
+                            value={snippet.end_gcode}
+                            onChange={(e) => updateSnippet(model, 'end_gcode', e.target.value)}
+                            onBlur={saveGcodeSnippets}
+                            placeholder={t('settings.gcodeEndPlaceholder', 'G-code appended after the print ends...')}
+                            rows={3}
+                            className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white text-xs font-mono focus:outline-none focus:border-bambu-green resize-y"
+                          />
+                        </div>
+                      </div>
+                    </Collapsible>
+                  );
+                });
+              })()}
+            </CardContent>
+          </Card>
           </div>
         </div>
           )}

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
static/assets/index-moQVuKgX.js


+ 1 - 1
static/index.html

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

Некоторые файлы не были показаны из-за большого количества измененных файлов