fix(slicer): preset visibility + lookup precedence + signed-out banner + AMS slot badges (#1712)

Four #1712 issues from the 2026-06-04 Orca Cloud integration:

  (1) Tier order put Orca Cloud above everything across SliceModal,
  auto-pick scoring, dropdown groups, the AMS slot picker, and the
  backend precedence. Bambu-Cloud-only users saw their profiles
  deprioritised behind an empty Orca tier.

  (2) Cross-tier dedup hid a same-named preset in all but the highest-
  priority tier. A user with both a local-imported and an Orca-synced
  "Bambu PLA Basic" couldn't see the Orca copy as a picker option.

  (3) CloudStatusBanner nagged signed-out users with a permanent
  "Sign in to Orca Cloud" line at the top of every slice -- even after
  explicit logout. Bambu Cloud had the symmetric problem.

  (4) ConfigureAmsSlotModal source badges were inconsistent: Orca rows
  showed only "Custom" (no source identity), Bambu Cloud built-in rows
  had no badge at all, and the orthogonal isUser-driven "Custom" badge
  collided with the source badge for cloud user presets.

  Order is local > orca_cloud > cloud > standard everywhere it lives
  (SliceModal SLICE_MODAL_TIER_ORDER + TIER_BONUS + dropdown tier list,
  ConfigureAmsSlotModal sourceOrder, and backend precedence). The order
  drives auto-pick + visual group rendering; it does NOT hide profiles.

  _dedupe_by_name replaced with _enrich_cloud_metadata: every tier
  returns its full list across all three slots (printer / process /
  filament). The function still backfills Bambu Cloud filament metadata
  from same-named local / orca_cloud / standard entries so cloud
  filaments score in pickFilamentForSlot.

  CloudStatusBanner silently no-ops on not_authenticated for both clouds;
  expired / unreachable still surface. The not_authenticated i18n keys
  stay in the locale files dormant.

  ConfigureAmsSlotModal: one source badge per row, one colour per source
  (green Local / purple Orca Cloud / bambu-blue Bambu Cloud / amber
  Built-in). The legacy isUser-driven "Custom" badge is gone; every row
  identifies its tier consistently.
This commit is contained in:
maziggy
2026-06-11 12:17:45 +02:00
parent 4ab7339fe4
commit d459b6eabb
21 changed files with 272 additions and 202 deletions
+25 -43
View File
@@ -173,11 +173,10 @@ async def _fetch_cloud_presets(
# one-by-one trips Bambu's limiter and returns 429 on every request
# for users with large preset libraries (#1150 follow-up).
#
# The dedup pass (see _dedupe_by_name) compensates: when a cloud entry
# wins over a same-named local entry, the cloud entry inherits the
# local entry's filament_type / filament_colour. So cloud presets that
# also exist locally still get metadata-aware pre-pick in the
# SliceModal; cloud-only presets fall back to plain priority order.
# The metadata-enrich pass (see _enrich_cloud_metadata) compensates:
# a Bambu Cloud entry without its own filament_type/colour inherits
# those values from a same-named local / orca_cloud / standard entry
# so it can still score for type/colour matches in pickFilamentForSlot.
_cloud_cache[cache_key] = (now, slots)
return slots, "ok"
finally:
@@ -420,7 +419,7 @@ async def _resolve_slicer_api_url(db: AsyncSession) -> str | None:
return url or None
def _dedupe_by_name(
def _enrich_cloud_metadata(
orca_cloud: dict[str, list[UnifiedPreset]],
cloud: dict[str, list[UnifiedPreset]],
local: dict[str, list[UnifiedPreset]],
@@ -431,26 +430,29 @@ def _dedupe_by_name(
dict[str, list[UnifiedPreset]],
dict[str, list[UnifiedPreset]],
]:
"""Filter so each preset name appears in exactly one tier.
"""Backfill Bambu Cloud filament metadata; do NOT dedup tiers.
Precedence: ``orca_cloud > cloud > local > standard``. Orca Cloud is
highest because a user who set up Orca sync is explicitly curating
those profiles for use here; Bambu Cloud follows for the same reason
one tier down. Order within each tier is preserved.
Every tier surfaces its full list — a name that exists in both ``local``
and ``orca_cloud`` shows up in BOTH dropdown groups so the user can pick
either source. Tier ORDER (``local > orca_cloud > cloud > standard``)
is communicated by the SliceModal's group rendering and by the
name-collision fallback in ``findPresetByName``; this function does not
enforce it.
Filament metadata merges across tiers: a Bambu Cloud entry without its
own ``filament_type`` / ``filament_colour`` (Bambu Cloud doesn't surface
Filament metadata merge: a Bambu Cloud entry without its own
``filament_type`` / ``filament_colour`` (Bambu Cloud doesn't surface
these in the list response for rate-limiting reasons — see
:func:`_fetch_cloud_presets`) inherits values from the same-named local
or standard entry. Orca Cloud already carries metadata inline, so no
backfill is needed for it.
:func:`_fetch_cloud_presets`) inherits values from a same-named entry
in ``local`` / ``orca_cloud`` / ``standard``. This is the only reason
this function exists post-#1712 — without the enrich the Bambu Cloud
tier can't score in ``pickFilamentForSlot``.
"""
# Build a name → metadata lookup from the tiers that carry it (orca_cloud,
# local, standard). Bambu cloud is intentionally skipped — it doesn't
# populate filament_type/colour in the list response. Take whichever
# non-empty entry shows up first.
# Build a name → metadata lookup from the tiers that carry it (local,
# orca_cloud, standard). Bambu cloud is intentionally skipped — it
# doesn't populate filament_type/colour in the list response. Take
# whichever non-empty entry shows up first.
metadata_by_name: dict[str, tuple[str | None, str | None]] = {}
for tier in (orca_cloud, local, standard):
for tier in (local, orca_cloud, standard):
for p in tier["filament"]:
if p.name in metadata_by_name:
continue
@@ -466,27 +468,7 @@ def _dedupe_by_name(
if p.filament_colour is None and c is not None:
p.filament_colour = c
deduped_cloud = _empty_slots()
deduped_local = _empty_slots()
deduped_standard = _empty_slots()
for slot in ("printer", "process", "filament"):
seen = {p.name for p in orca_cloud[slot]}
for p in cloud[slot]:
if p.name in seen:
continue
deduped_cloud[slot].append(p)
seen.add(p.name)
for p in local[slot]:
if p.name in seen:
continue
deduped_local[slot].append(p)
seen.add(p.name)
for p in standard[slot]:
if p.name in seen:
continue
deduped_standard[slot].append(p)
seen.add(p.name)
return orca_cloud, deduped_cloud, deduped_local, deduped_standard
return orca_cloud, cloud, local, standard
@router.get("/printer-models")
@@ -541,7 +523,7 @@ async def list_unified_presets(
local = await _fetch_local_presets(db)
standard = await _fetch_bundled_presets(db, refresh=refresh)
orca_cloud, cloud, local, standard = _dedupe_by_name(orca_cloud, cloud, local, standard)
orca_cloud, cloud, local, standard = _enrich_cloud_metadata(orca_cloud, cloud, local, standard)
return UnifiedPresetsResponse(
orca_cloud=UnifiedPresetsBySlot(**orca_cloud),
+7 -6
View File
@@ -59,13 +59,14 @@ class UnifiedPresetsBySlot(BaseModel):
class UnifiedPresetsResponse(BaseModel):
"""Each tier carries only the names that didn't appear in a higher tier.
"""Every tier carries its full preset list — no cross-tier dedup.
Priority order: ``orca_cloud > cloud > local > standard``. Orca Cloud is
highest because it's the most-recently-explicitly-curated source for
users who set up Orca sync (they did it on purpose; their Orca picks
should outrank everything else). Bambu Cloud follows as the next-most-
curated tier. Local imports beat the slicer's stock fallback.
Priority order: ``local > orca_cloud > cloud > standard``. The order
drives auto-pick (first non-empty tier wins, name-lookup walks tiers
in this order, filament scoring tiebreaks by per-tier bonus) and
determines the visual rendering order of the SliceModal's optgroups,
but a name that exists in multiple tiers appears in EACH of their
groups so the user can pick any source.
``cloud_status`` / ``orca_cloud_status`` let the frontend show a banner
explaining why a cloud tier is empty when the user expected to see it
+105 -50
View File
@@ -1,9 +1,13 @@
"""Tests for the unified slicer-presets endpoint helpers.
The endpoint stitches together three preset sources (cloud / local /
standard) with name-based dedup. These tests pin the dedup logic, the
cloud-status mapping, and the per-user / sidecar caches at the
helper level — full HTTP integration is covered by the routes test.
The endpoint stitches together four preset sources (local / orca_cloud /
cloud / standard). It does NOT dedup across tiers — every tier surfaces
its full list so the user can pick any source. Bambu Cloud filament
metadata is enriched from same-named entries in the other tiers so it
can still score in the SliceModal's auto-pick. These tests pin the
enrich behaviour, the cloud-status mapping, and the per-user / sidecar
caches at the helper level — full HTTP integration is covered by the
routes test.
"""
from __future__ import annotations
@@ -28,50 +32,31 @@ def _slot(items: list[tuple[str, str, str]]) -> dict[str, list[UnifiedPreset]]:
}
class TestDedupeByName:
"""Cloud > local > standard, by ``name``, order preserved within tier."""
class TestEnrichCloudMetadata:
"""No cross-tier dedup — every tier's full list comes back; Bambu Cloud
filament metadata is enriched from same-named entries in other tiers."""
def test_cloud_wins_over_local_and_standard(self):
def test_same_name_in_all_tiers_appears_in_every_tier(self):
"""Critical regression guard for #1712: a user who has imported a
local profile AND signed in to Orca AND has Bambu Cloud with the
same name should see it under EACH source, not just the highest-
priority tier. The order is used for auto-pick + group rendering;
it is NOT used to hide profiles."""
orca = _slot([("oid1", "Bambu PLA Basic", "orca_cloud")])
cloud = _slot([("cid1", "Bambu PLA Basic", "cloud")])
local = _slot([("lid1", "Bambu PLA Basic", "local")])
standard = _slot([("Bambu PLA Basic", "Bambu PLA Basic", "standard")])
_oc, c, l_, s = sp._dedupe_by_name(_slot([]), cloud, local, standard)
oc, c, l_, s = sp._enrich_cloud_metadata(orca, cloud, local, standard)
assert [p.source for p in l_["printer"]] == ["local"]
assert [p.source for p in oc["printer"]] == ["orca_cloud"]
assert [p.source for p in c["printer"]] == ["cloud"]
assert l_["printer"] == []
assert s["printer"] == []
def test_local_filtered_only_when_present_in_cloud(self):
cloud = _slot([("cid1", "Custom PLA", "cloud")])
local = _slot(
[
("lid1", "Custom PLA", "local"), # filtered (in cloud)
("lid2", "My Workhorse PLA", "local"), # kept
]
)
standard = _slot([])
_oc, _c, l_, _s = sp._dedupe_by_name(_slot([]), cloud, local, standard)
assert [p.name for p in l_["printer"]] == ["My Workhorse PLA"]
def test_standard_filtered_against_both_higher_tiers(self):
cloud = _slot([("c1", "A", "cloud")])
local = _slot([("l1", "B", "local")])
standard = _slot(
[
("A", "A", "standard"), # filtered (in cloud)
("B", "B", "standard"), # filtered (in local)
("C", "C", "standard"), # kept
]
)
_oc, _c, _l, s = sp._dedupe_by_name(_slot([]), cloud, local, standard)
assert [p.name for p in s["printer"]] == ["C"]
assert [p.source for p in s["printer"]] == ["standard"]
def test_preserves_order_within_tier(self):
"""A tier's input order must be preserved in its output — nothing in
the dedupe pass should sort, reverse, or otherwise reorder entries."""
"""A tier's input order must be preserved — nothing in the enrich
pass should sort, reverse, or otherwise reorder entries."""
cloud = _slot(
[
("c1", "Z-First", "cloud"),
@@ -79,25 +64,95 @@ class TestDedupeByName:
("c3", "M-Third", "cloud"),
]
)
_oc, c, _l, _s = sp._dedupe_by_name(_slot([]), cloud, _slot([]), _slot([]))
_oc, c, _l, _s = sp._enrich_cloud_metadata(_slot([]), cloud, _slot([]), _slot([]))
assert [p.name for p in c["printer"]] == ["Z-First", "A-Second", "M-Third"]
def test_dedupe_is_per_slot(self):
"""A name colliding across DIFFERENT slots must NOT cross-filter —
a "Custom" filament shouldn't hide a "Custom" printer."""
def test_bambu_cloud_filament_metadata_backfilled_from_local(self):
"""Bambu Cloud's list response omits filament_type/colour for
rate-limit reasons. A same-named local entry's metadata fills in
so the cloud entry can still score in pickFilamentForSlot."""
local = {
"printer": [],
"process": [],
"filament": [
UnifiedPreset(
id="lp1",
name="Bambu PLA Basic",
source="local",
filament_type="PLA",
filament_colour="#FF0000",
)
],
}
cloud = {
"printer": [],
"process": [],
"filament": [UnifiedPreset(id="cf1", name="Custom", source="cloud")],
"filament": [UnifiedPreset(id="cp1", name="Bambu PLA Basic", source="cloud")],
}
local = {
"printer": [UnifiedPreset(id="lp1", name="Custom", source="local")],
_oc, c, _l, _s = sp._enrich_cloud_metadata(_slot([]), cloud, local, _slot([]))
# Cloud entry now carries the local entry's metadata.
assert c["filament"][0].filament_type == "PLA"
assert c["filament"][0].filament_colour == "#FF0000"
# Local entry is untouched.
assert local["filament"][0].filament_type == "PLA"
def test_bambu_cloud_metadata_falls_back_through_orca_and_standard(self):
"""When local doesn't carry the name, orca_cloud / standard fill in."""
orca = {
"printer": [],
"process": [],
"filament": [],
"filament": [
UnifiedPreset(
id="o1",
name="Bambu PLA Basic",
source="orca_cloud",
filament_type="PLA",
filament_colour="#00FF00",
)
],
}
_oc, _c, l_, _s = sp._dedupe_by_name(_slot([]), cloud, local, _slot([]))
# The filament-tier collision must NOT remove the printer-tier "Custom".
assert [p.name for p in l_["printer"]] == ["Custom"]
cloud = {
"printer": [],
"process": [],
"filament": [UnifiedPreset(id="cp1", name="Bambu PLA Basic", source="cloud")],
}
_oc, c, _l, _s = sp._enrich_cloud_metadata(orca, cloud, _slot([]), _slot([]))
assert c["filament"][0].filament_type == "PLA"
assert c["filament"][0].filament_colour == "#00FF00"
def test_bambu_cloud_keeps_its_own_metadata_when_present(self):
"""If Bambu Cloud already has filament_type / filament_colour the
enrich pass must not overwrite them with a different same-named
entry's values."""
local = {
"printer": [],
"process": [],
"filament": [
UnifiedPreset(
id="lp1",
name="Bambu PLA Basic",
source="local",
filament_type="PETG",
filament_colour="#000000",
)
],
}
cloud = {
"printer": [],
"process": [],
"filament": [
UnifiedPreset(
id="cp1",
name="Bambu PLA Basic",
source="cloud",
filament_type="PLA",
filament_colour="#FFFFFF",
)
],
}
_oc, c, _l, _s = sp._enrich_cloud_metadata(_slot([]), cloud, local, _slot([]))
assert c["filament"][0].filament_type == "PLA"
assert c["filament"][0].filament_colour == "#FFFFFF"
def _user_with_cloud_auth(user_id: int = 1) -> MagicMock: